Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package server
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math"
"os"
"sort"
"strconv"
"strings"
"sync"
"Ascend-device-plugin/pkg/common"
"ascend-common/api"
"ascend-common/common-utils/hwlog"
"ascend-common/common-utils/utils"
apiCommon "ascend-common/devmanager/common"
)
var hcclTopoFilePathMap = map[int32]string{
common.ProductTypeServer: common.Server8PTopoPath,
common.ProductType1D: common.Pod1DTopoPath,
common.ProductType2D: common.Pod2DTopoPath,
common.ProductType16PServer: common.Server16PTopoPath,
common.ProductType32PServer: common.Server32PTopoPath,
common.ProductType1PCard: common.Card1PTopoPath,
common.ProductType4PCard: common.Card4PTopoPath,
}
var rankLevelInfoKeyArrMap = map[string][]string{
common.A5300ICardName: {
api.LevelInfoTypeIgnore, api.LevelInfoTypeIgnore, api.LevelInfoTypeIgnore, api.LevelInfoTypeRoCE,
},
common.A54P300ICardName: {
api.LevelInfoTypeUB, api.LevelInfoTypeIgnore, api.LevelInfoTypeIgnore, api.LevelInfoTypeRoCE,
},
}
const (
size50M = 50 * 1024 * 1024
addrTypeEID = "EID"
addrTypeIPV4 = "IPV4"
addrTypeIPV6 = "IPV6"
decimal = 10
hexadecimal = 16
addrNumsLength = 2
dieIdMaskNum = 0x04
portIdMaskNum = 0x7F
rightShiftLen = 3
podPlanePortCount = 6
)
var (
ServerLevel1Ports = []int{1, 2, 3, 4, 5, 6, 7, 8}
PodLevel1LowerHalfPortsDie0 = []int{1, 2}
PodLevel1LowerHalfPortsDie1 = []int{0, 1, 2, 3, 5, 6}
PodLevel1UpperHalfPortsDie1 = []int{1, 2}
PodLevel1UpperHalfPortsDie0 = []int{0, 1, 2, 3, 4, 5}
PodNpuGroupCount = 2
)
var npuBase *NpuBase
func init() {
npuBase = NewNpuBase()
}
type netTypeAndFeIdList struct {
netType string
feIdList []uint
}
type ProductBase struct {
superPodSize uint32
superPodID uint32
serverIndex uint32
chassisID uint32
superPodType uint32
nodeInternalIP string
topoFilePath string
cardType string
mainBoardId int
maxNpuCount int
topoInfo *TopoInfo
}
func (p *ProductBase) getID(level int) string {
if p == nil {
hwlog.RunLog.Errorf("product info is empty")
return ""
}
switch level {
case api.RankLevel0:
if p.cardType == common.A5300ICardName || p.cardType == common.A54P300ICardName {
return p.nodeInternalIP
}
if !p.isServer() {
return fmt.Sprintf("%s_%s", strconv.Itoa(int(p.superPodID)), strconv.Itoa(int(p.serverIndex)))
}
if p.isSuperServer() {
return fmt.Sprintf("%s_%s", strconv.Itoa(int(p.superPodID)), strconv.Itoa(int(p.serverIndex)))
}
return p.nodeInternalIP
case api.RankLevel1:
if p.isServer() && !p.isSuperServer() {
return ""
}
return strconv.Itoa(int(p.superPodID))
case api.RankLevel2:
return api.DefaultClusterName
case api.RankLevel3:
return api.DefaultClusterName
default:
return ""
}
}
func (p *ProductBase) isPodScene() bool {
if p == nil {
hwlog.RunLog.Errorf("product info is empty")
return false
}
superPodType := p.superPodType
return superPodType == common.ProductType1D || superPodType == common.ProductType2D
}
func (p *ProductBase) isSuperServer() bool {
if p == nil {
hwlog.RunLog.Errorf("product info is empty")
return false
}
if !p.isServer() {
return false
}
if p.superPodType == common.ProductType16PServer || p.superPodType == common.ProductType32PServer {
return false
}
superPodID := p.superPodID
superPodSize := p.superPodSize
return int(superPodSize) != common.InvalidSuperPodSize && int(superPodID) != common.InvalidSuperPodID
}
func (p *ProductBase) isServer() bool {
if p == nil {
hwlog.RunLog.Error("product info is empty")
return false
}
return !p.isPodScene()
}
func (p *ProductBase) isStandCard() bool {
if p == nil {
hwlog.RunLog.Error("product info is empty")
return false
}
return p.cardType == common.A5300ICardName || p.cardType == common.A54P300ICardName
}
func (p *ProductBase) getTopoFileInfo() (*TopoInfo, error) {
if p.topoInfo != nil {
hwlog.RunLog.Debugf("topo info is already loaded from file %s", p.topoFilePath)
return p.topoInfo, nil
}
path, err := p.getTopoPath()
if err != nil {
return nil, fmt.Errorf("get topo path failed, err:<%v>", err)
}
if _, err := os.Stat(path); err != nil {
return nil, fmt.Errorf("check topo file exist failed, path:<%v>; err:<%v>", path, err)
}
topoData, err := utils.ReadLimitBytes(path, size50M)
if err != nil {
return nil, fmt.Errorf("read topo file failed, path:<%v>; err:<%v>", path, err)
}
if !json.Valid(topoData) {
return nil, fmt.Errorf("topo file is not json, path:<%v>", path)
}
var topoInfo TopoInfo
if err := json.Unmarshal(topoData, &topoInfo); err != nil {
return nil, fmt.Errorf("topo info json unmarshal failed, err:<%v>", err)
}
p.topoFilePath = path
p.topoInfo = &topoInfo
return &topoInfo, nil
}
func (p *ProductBase) getTopoPath() (string, error) {
if p.cardType == common.A5300ICardName {
return hcclTopoFilePathMap[common.ProductType1PCard], nil
}
if p.cardType == common.A54P300ICardName {
return hcclTopoFilePathMap[common.ProductType4PCard], nil
}
path, exist := hcclTopoFilePathMap[int32(p.superPodType)]
if !exist {
return "", fmt.Errorf("super pod type:<%d> topo path not exist", p.superPodType)
}
return path, nil
}
type NpuBase struct {
productInfo *ProductBase
eidPortMap map[string][]string
portMapMutex sync.RWMutex
urmaDevInfoMap map[int32][]apiCommon.UrmaDeviceInfo
}
func NewNpuBase() *NpuBase {
return &NpuBase{
eidPortMap: make(map[string][]string),
portMapMutex: sync.RWMutex{},
urmaDevInfoMap: make(map[int32][]apiCommon.UrmaDeviceInfo),
}
}
func (n *NpuBase) SetUrmaDeviceInfoByHdm(hdm *HwDevManager, dev *common.NpuDevice) error {
if dev == nil {
return errors.New("input parameter dev is nil")
}
if _, exist := n.urmaDevInfoMap[dev.PhyID]; exist {
hwlog.RunLog.Infof("LogicID(%d) phyID(%d) urma devie info already exist",
dev.LogicID, dev.PhyID)
return nil
}
if hdm == nil {
return errors.New("input parameter hdm is nil")
}
if hdm.manager == nil {
return errors.New("input parameter hdm.manager is nil")
}
dmgr := hdm.manager.GetDmgr()
if dmgr == nil {
return errors.New("input parameter dmgr is nil")
}
urmaDevInfoAll, err := dmgr.GetUrmaDevEidListAll(dev.LogicID)
if err != nil {
hwlog.RunLog.Errorf("get urma device info failed, err: %v", err)
return err
}
n.urmaDevInfoMap[dev.PhyID] = urmaDevInfoAll
return nil
}
func (n *NpuBase) getID(level int) string {
if n.productInfo == nil {
hwlog.RunLog.Error("product info is empty")
return ""
}
return n.productInfo.getID(level)
}
func (n *NpuBase) getRankLevelInfoKeyArr() []string {
if n.productInfo == nil {
hwlog.RunLog.Error("product info is empty")
return []string{}
}
if arr, ok := rankLevelInfoKeyArrMap[n.productInfo.cardType]; ok {
return arr
}
if n.productInfo.isPodScene() {
return []string{
api.LevelInfoTypeUB, api.LevelInfoTypeUB, api.LevelInfoTypeUBG, api.LevelInfoTypeRoCE,
}
}
if n.productInfo.isSuperServer() {
return []string{
api.LevelInfoTypeUB, api.LevelInfoTypeUB, api.LevelInfoTypeUBoE, api.LevelInfoTypeRoCE,
}
}
if n.productInfo.isServer() {
return []string{
api.LevelInfoTypeUB, api.LevelInfoTypeIgnore, api.LevelInfoTypeUBoE, api.LevelInfoTypeRoCE,
}
}
return []string{}
}
func (n *NpuBase) getNetTypeForLevel(level int) string {
if level == api.RankLevel0 {
return api.NetTypeTopo
}
return api.NetTypeCLOS
}
func (n *NpuBase) getNetTypeAndFeIDListByRankLevel(rankLevel int) (string, []uint) {
if n.productInfo == nil {
hwlog.RunLog.Warn("product info is nil")
return "", []uint{}
}
if rankLevel < 0 || rankLevel >= api.RankLevelCnt {
hwlog.RunLog.Errorf("rank level is %d, should be in range [0, %d)", rankLevel, api.RankLevelCnt)
return "", []uint{}
}
switch rankLevel {
case api.RankLevel0:
if n.productInfo.isStandCard() {
return api.LevelInfoTypeUB, []uint{common.UrmaFeId0}
}
return api.LevelInfoTypeUB, []uint{common.UrmaFeId1}
case api.RankLevel1:
return api.LevelInfoTypeUB, []uint{common.UrmaFeId0}
case api.RankLevel2:
if !n.productInfo.isPodScene() {
return api.LevelInfoTypeUBoE, []uint{common.UrmaFeId8, common.UrmaFeId9}
}
return api.LevelInfoTypeUBG, []uint{common.UrmaFeId3}
case api.RankLevel3:
return api.LevelInfoTypeRoCE, []uint{}
default:
return "", nil
}
}
func (n *NpuBase) getRandAddrByFuncEntityID(phyID int32, feID uint, netType string, rankLevel int) []api.RankAddrItem {
urmaDevInfoAll, exist := n.urmaDevInfoMap[phyID]
if !exist {
hwlog.RunLog.Errorf("get urma device info failed, phyID(%d) not exist in cache map", phyID)
return nil
}
rankAddrList := make([]api.RankAddrItem, 0)
for _, devInfo := range urmaDevInfoAll {
eidList := n.getEidListByFeIDAndRankLevel(feID, &devInfo, rankLevel)
for i := 0; i < len(eidList); i++ {
eid := eidList[i].Eid
eidStr := hex.EncodeToString(eid.Raw[:])
portList, err := n.GetPortListByEid(phyID, eidStr, rankLevel)
if err != nil {
hwlog.RunLog.Warnf("get port list by eid for phyID=%d feID=%d netType=%s rankLevel=%d eid=%s "+
"failed, err: %v", phyID, feID, netType, rankLevel, eidStr, err)
continue
}
item := n.createRankAddrItem(netType, eid, portList)
rankAddrList = append(rankAddrList, item)
}
}
return rankAddrList
}
func (n *NpuBase) GetPortListByEid(phyId int32, eid string, rLevel int) ([]string, error) {
n.portMapMutex.Lock()
defer n.portMapMutex.Unlock()
if common.ParamOption.RealCardType != api.Ascend910A5 {
return nil, fmt.Errorf("get port list by eid error, device type is not %s", api.HuaweiNPU)
}
eidPortMapKey := getEidPortMapKey(phyId, eid)
if ports, exist := n.eidPortMap[eidPortMapKey]; exist {
hwlog.RunLog.Infof("get port list success, hit cache key:<%s>", eidPortMapKey)
return ports, nil
}
return n.getPortsList(phyId, eid, rLevel)
}
func (n *NpuBase) getEidListByFeIDAndRankLevel(feID uint, urmaDevInfo *apiCommon.UrmaDeviceInfo,
rankLevel int) []apiCommon.UrmaEidInfo {
if urmaDevInfo == nil {
return []apiCommon.UrmaEidInfo{}
}
eidList := make([]apiCommon.UrmaEidInfo, 0)
for i := 0; i < int(urmaDevInfo.EidCount); i++ {
if n.getFeIDByEid(&urmaDevInfo.EidInfos[i].Eid) != feID {
continue
}
if rankLevel == api.RankLevel0 && !n.checkEidIsUsedForD2D(&urmaDevInfo.EidInfos[i].Eid) {
continue
}
if rankLevel == api.RankLevel0 && n.productInfo.isStandCard() {
eidStr := hex.EncodeToString(urmaDevInfo.EidInfos[i].Eid.Raw[:])
portId, err := getPortIdBydEid(eidStr)
if err != nil || portId > common.PortIdLimit {
continue
}
}
eidList = append(eidList, urmaDevInfo.EidInfos[i])
}
return eidList
}
func (n *NpuBase) getFeIDByEid(eid *apiCommon.Eid) uint {
if eid == nil {
return math.MaxUint
}
return uint(binary.BigEndian.Uint64(eid.Raw[0:common.FeIdIndexByte]) >> common.FeIdIndexBit & common.FeIdMask)
}
func (n *NpuBase) checkEidIsUsedForD2D(eid *apiCommon.Eid) bool {
if eid == nil {
return false
}
const twoBytes = 2
const usageBitIndex = 11
const usageBitVal = 0
const usageBitMask = 0x01
return (binary.BigEndian.Uint16(eid.Raw[len(eid.Raw)-twoBytes:]) >> usageBitIndex & usageBitMask) == usageBitVal
}
func (n *NpuBase) createRankAddrItem(netType string, eid apiCommon.Eid, ports []string) api.RankAddrItem {
planeId := api.DefaultRandAddrPlaneID
if netType == api.LevelInfoTypeUB {
val := int(eid.Raw[len(eid.Raw)-1])
dieId := 0
if val <= common.PhyLimit {
dieId = ((val - 1) / common.PhyPortNumPerDie) % common.DieNumPerDev
} else if common.LogicLowerLimit <= val && val <= common.LogicUpperLimit {
dieId = ((val - common.LogicLowerLimit) / common.LogicPortNumPerDie) % common.DieNumPerDev
}
planeId = strconv.Itoa(dieId)
}
if netType == api.LevelInfoTypeUBG || netType == api.LevelInfoTypeUB {
return api.RankAddrItem{
AddrType: addrTypeEID,
Addr: hex.EncodeToString(eid.Raw[:]),
Ports: ports,
PlaneId: planeId,
}
}
if netType == api.LevelInfoTypeUBoE {
ipv4Bytes := eid.Raw[len(eid.Raw)-apiCommon.MaxUBCNAByteLen : len(eid.Raw)]
ipv4Str := fmt.Sprintf("%d.%d.%d.%d", ipv4Bytes[0], ipv4Bytes[1], ipv4Bytes[2], ipv4Bytes[3])
return api.RankAddrItem{
AddrType: addrTypeIPV4,
Addr: ipv4Str,
Ports: ports,
PlaneId: planeId,
}
}
return api.RankAddrItem{}
}
func getEidPortMapKey(phyId int32, eid string) string {
return fmt.Sprintf("%d_%s", phyId, eid)
}
func (n *NpuBase) getPortsList(phyId int32, eid string, rLevel int) ([]string, error) {
ports := make([]string, 0)
portsMap := make(map[string]struct{})
eidPortMapKey := getEidPortMapKey(phyId, eid)
if rLevel == api.RankLevel2 {
topoInfo, err := n.productInfo.getTopoFileInfo()
if err != nil {
return ports, fmt.Errorf("get port list by eid failed: get topo file info err:<%v>", err)
}
for _, edge := range topoInfo.EdgeList {
if edge.NetLayer == rLevel && edge.LocalA == int(phyId) {
ports = savePortsResult(edge, ports, portsMap)
}
}
if len(ports) == 0 {
hwlog.RunLog.Warnf("eid<%s> ports info is not found in topo file, edge list count %d",
eid, len(topoInfo.EdgeList))
}
n.eidPortMap[eidPortMapKey] = ports
return ports, nil
}
dieId, portId, err := getDieIdAndPortId(eid)
if err != nil {
return ports, err
}
if n.productInfo.isStandCard() && rLevel == api.RankLevel0 {
if portId > common.PortIdLimit {
return ports, nil
}
ports = append(ports, fmt.Sprintf("%d/%d", dieId, portId))
}
topoInfo, err := n.productInfo.getTopoFileInfo()
if err != nil {
return ports, fmt.Errorf("get topoInfo failed: err:<%v>", err)
}
for _, edge := range topoInfo.EdgeList {
if edge.NetLayer == rLevel && edge.LocalA == int(phyId) && edge.LinkType == common.Peer2Net {
ports = savePortsResultByDieId(edge, dieId, ports, portsMap)
}
}
hwlog.RunLog.Infof("get port list success, save cache key:<%s>, value:%v, rLevel:<%d>",
eidPortMapKey, ports, rLevel)
n.eidPortMap[eidPortMapKey] = ports
return ports, nil
}
type ServerLevel1Config struct {
Die int
Fe int
Ports []int
}
func (n *NpuBase) getServerLevel1Config() []ServerLevel1Config {
mainBoardId := n.productInfo.mainBoardId
if mainBoardId == api.Atlas850MainBoardID2 || mainBoardId == api.Atlas850MainBoardID3 {
return []ServerLevel1Config{
{Die: common.DieID0, Fe: common.UrmaFeId3, Ports: ServerLevel1Ports},
}
}
return nil
}
type PodLevel1Config struct {
Die int
Fe int
Ports []int
}
func (n *NpuBase) getPodLevel1Config(phyID int) []PodLevel1Config {
mainBoardId := n.productInfo.mainBoardId
maxNpuCountPerNode := n.productInfo.maxNpuCount
PodLevel1HalfGroupBoundary := maxNpuCountPerNode / PodNpuGroupCount
if (mainBoardId == api.Atlas9501DMainBoardID || mainBoardId == api.Atlas950MainBoardID) &&
(phyID%maxNpuCountPerNode) < PodLevel1HalfGroupBoundary {
return []PodLevel1Config{
{Die: common.DieID0, Fe: common.UrmaFeId2, Ports: PodLevel1LowerHalfPortsDie0},
{Die: common.DieID1, Fe: common.UrmaFeId2, Ports: PodLevel1LowerHalfPortsDie1},
}
}
if (mainBoardId == api.Atlas9501DMainBoardID || mainBoardId == api.Atlas950MainBoardID) &&
(phyID%maxNpuCountPerNode) >= PodLevel1HalfGroupBoundary {
return []PodLevel1Config{
{Die: common.DieID1, Fe: common.UrmaFeId2, Ports: PodLevel1UpperHalfPortsDie1},
{Die: common.DieID0, Fe: common.UrmaFeId2, Ports: PodLevel1UpperHalfPortsDie0},
}
}
return nil
}
func selectMeshDev(parsed []*ParsedUrma, keep func(p *ParsedUrma) bool) *ParsedUrma {
var meshDev *ParsedUrma
maxFe := common.InvalidFeValue
for _, p := range parsed {
if p == nil || p.IsUboe {
continue
}
if !keep(p) {
continue
}
if p.Fe > maxFe {
maxFe = p.Fe
meshDev = p
}
}
return meshDev
}
func buildRankListFromMesh(meshDev *ParsedUrma) []api.RankAddrItem {
rankList := make([]api.RankAddrItem, 0)
if meshDev == nil {
return rankList
}
for _, e := range meshDev.Eids {
if e.IsPg {
continue
}
if e.Die < common.DieID0 || e.Port < common.PortId0 {
continue
}
rankList = append(rankList, api.RankAddrItem{
AddrType: addrTypeEID,
Addr: e.Eid,
Ports: []string{fmt.Sprintf("%d/%d", e.Die, e.Port)},
PlaneId: fmt.Sprintf("%d", e.Die),
})
}
return rankList
}
func buildLevel1ParsedGeneric(parsed []*ParsedUrma, getPorts func(die, fe int) []int, skipUboe bool,
planeIdFunc func(p *ParsedUrma, ports []int) string,
) []api.RankAddrItem {
rankList := make([]api.RankAddrItem, 0)
for _, p := range parsed {
if p == nil || p.PgEid == "" {
continue
}
if skipUboe && p.IsUboe {
continue
}
ports := getPorts(p.Die, p.Fe)
if len(ports) == 0 {
continue
}
portList := make([]string, 0, len(ports))
for _, port := range ports {
portList = append(portList, fmt.Sprintf("%d/%d", p.Die, port))
}
rankList = append(rankList, api.RankAddrItem{
AddrType: addrTypeEID,
Addr: p.PgEid,
Ports: portList,
PlaneId: planeIdFunc(p, ports),
})
}
sort.Slice(rankList, func(i, j int) bool {
return len(rankList[i].Ports) > len(rankList[j].Ports)
})
return rankList
}
func (n *NpuBase) buildServerRankAddrListParsed(level int, parsed []*ParsedUrma) []api.RankAddrItem {
switch level {
case api.RankLevel0:
return n.buildServerLevel0Parsed(parsed)
case api.RankLevel1:
return n.buildServerLevel1Parsed(parsed)
case api.RankLevel2:
return n.buildServerLevel2Parsed(parsed)
default:
return nil
}
}
func (n *NpuBase) buildServerLevel0Parsed(parsed []*ParsedUrma) []api.RankAddrItem {
keep := func(p *ParsedUrma) bool {
return p.Die != common.DieID0
}
meshDev := selectMeshDev(parsed, keep)
return buildRankListFromMesh(meshDev)
}
func (n *NpuBase) buildServerLevel1Parsed(parsed []*ParsedUrma) []api.RankAddrItem {
cfgs := n.getServerLevel1Config()
getPorts := func(die, fe int) []int {
for _, c := range cfgs {
if c.Die == die && c.Fe == fe {
return c.Ports
}
}
return nil
}
planeIdFunc := func(p *ParsedUrma, ports []int) string {
return fmt.Sprintf("%d", p.Die)
}
return buildLevel1ParsedGeneric(parsed, getPorts, true, planeIdFunc)
}
func (n *NpuBase) buildServerLevel2Parsed(parsed []*ParsedUrma) []api.RankAddrItem {
for _, p := range parsed {
if p == nil || !p.IsUboe || p.IPv4 == "" {
continue
}
return []api.RankAddrItem{
{
AddrType: addrTypeIPV4,
Addr: p.IPv4,
Ports: []string{common.A5ServerLevel2UboePort},
PlaneId: api.DefaultRandAddrPlaneID,
},
}
}
return nil
}
func (n *NpuBase) buildPodRankAddrListParsed(level int, dev *common.NpuDevice, parsed []*ParsedUrma) []api.RankAddrItem {
switch level {
case api.RankLevel0:
return n.buildPodLevel0Parsed(dev, parsed)
case api.RankLevel1:
return n.buildPodLevel1Parsed(dev, parsed)
default:
return nil
}
}
func (n *NpuBase) buildPodLevel0Parsed(dev *common.NpuDevice, parsed []*ParsedUrma) []api.RankAddrItem {
keep := func(p *ParsedUrma) bool {
die := p.Die
maxNpuCountPerNode := n.productInfo.maxNpuCount
PodLevel1HalfGroupBoundary := maxNpuCountPerNode / PodNpuGroupCount
phyMod := int(dev.PhyID) % maxNpuCountPerNode
if phyMod < PodLevel1HalfGroupBoundary && die == common.DieID1 {
return false
}
if phyMod >= PodLevel1HalfGroupBoundary && die == common.DieID0 {
return false
}
return true
}
meshDev := selectMeshDev(parsed, keep)
return buildRankListFromMesh(meshDev)
}
func (n *NpuBase) buildPodLevel1Parsed(dev *common.NpuDevice, parsed []*ParsedUrma) []api.RankAddrItem {
cfgs := n.getPodLevel1Config(int(dev.PhyID))
getPorts := func(die, fe int) []int {
for _, c := range cfgs {
if c.Die == die && c.Fe == fe {
return c.Ports
}
}
return nil
}
planeIdFunc := func(p *ParsedUrma, ports []int) string {
if len(ports) == podPlanePortCount {
return "0"
}
return "1"
}
return buildLevel1ParsedGeneric(parsed, getPorts, false, planeIdFunc)
}
func getDieIdByEid(eid string) (byte, error) {
var dieId byte
dieIdStr := eid[len(eid)-common.DieIDOffset : len(eid)-common.PortIDSuffixLen]
dieIdInt, err := strconv.ParseInt(dieIdStr, hexadecimal, 0)
if err != nil {
return 0, fmt.Errorf("dieId:<%v> is invalid, parse to int failed, err: %v", dieIdInt, err)
}
if (dieIdInt & dieIdMaskNum) != 0 {
dieId = 1
} else {
dieId = 0
}
return dieId, nil
}
func getPortIdBydEid(eid string) (byte, error) {
var portId byte
portIdStr := eid[len(eid)-common.PortIDSuffixLen:]
portInt, err := strconv.ParseInt(portIdStr, hexadecimal, 0)
if err != nil {
return 0, fmt.Errorf("portId:<%v> is invalid, parse to int failed, err: %v", portInt, err)
}
portId = byte((portInt & portIdMaskNum) >> rightShiftLen)
return portId, nil
}
func getDieIdAndPortId(eid string) (byte, byte, error) {
if len(eid) < common.DieIDOffset {
return 0, 0, fmt.Errorf("eid:<%v> len is invalid, which should be greater equal than %d",
eid, common.DieIDOffset)
}
dieId, err := getDieIdByEid(eid)
if err != nil {
return 0, 0, err
}
portId, err := getPortIdBydEid(eid)
if err != nil {
return 0, 0, err
}
return dieId, portId, nil
}
func savePortsResult(edge Edge, ports []string, portsMap map[string]struct{}) []string {
if portsMap == nil {
portsMap = make(map[string]struct{})
}
for _, addr := range edge.LocalAPorts {
if _, ok := portsMap[addr]; ok {
continue
}
ports = append(ports, addr)
portsMap[addr] = struct{}{}
}
hwlog.RunLog.Infof("savePortsResult finished, total ports count=%d", len(ports))
return ports
}
func savePortsResultByDieId(edge Edge, dieId byte, ports []string, portsMap map[string]struct{}) []string {
if portsMap == nil {
portsMap = make(map[string]struct{})
}
for _, addr := range edge.LocalAPorts {
if _, ok := portsMap[addr]; ok {
continue
}
addrNums := strings.Split(addr, "/")
if len(addrNums) == addrNumsLength && addrNums[0] == strconv.Itoa(int(dieId)) {
ports = append(ports, addr)
portsMap[addr] = struct{}{}
}
}
return ports
}