LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/topo/topo_addr_info/src - product_server.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.0 % 155 138
Test Date: 2026-08-04 10:52:23 Functions: 91.7 % 12 11

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2026 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : #include "product_server.h"
      11              : #include <string.h>
      12              : #include <stdlib.h>
      13              : #include <syslog.h>
      14              : #include "rank_info_types.h"
      15              : #include "hal.h"
      16              : #include "topo.h"
      17              : #include "eid_util.h"
      18              : #include "securec.h"
      19              : 
      20              : #define MAX_SERVER_ROOTINFO_LEN (2048)
      21              : #define PRODUCT_MESH_LEVEL (0)
      22              : #define PRODUCT_CLOS_LEVEL (1)
      23              : #define IP_ADDR_LEN (32)
      24              : 
      25              : /* 用于识别FE*/
      26              : #define MAX_UE_ID_IN_LEVEL (4)
      27              : #define MAX_LEVEL_NUM (4)
      28              : #define SERVER_NPU_NUM (8)
      29              : #define CLOS_LEVEL3 \
      30              :     { .level = 3, .netType = NET_TYPE_CLOS, .ueNum = 0, .instanceIdFunc = GetNetInstanceIdForCluster }
      31              : 
      32              : enum UbEntityType {
      33              :     UE_TYPE_MESH = 0,
      34              :     UE_TYPE_CLOS = 1,
      35              :     UE_TYPE_UBOE = 2,
      36              :     UE_TYPE_UBG = 3,
      37              :     UE_TYPE_CLOS_PORTS = 4,
      38              : };
      39              : 
      40              : typedef struct stUEInfo {
      41              :     int dieId;
      42              :     int feId;
      43              :     enum UbEntityType type;
      44              :     char ports[256];
      45              : } UEInfo;
      46              : 
      47              : typedef int (*GetNetInstanceIdFunc)(
      48              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen);
      49              : 
      50              : typedef struct stLevelInfo {
      51              :     int level;
      52              :     int ueNum;
      53              :     UEInfo ueList[MAX_UE_ID_IN_LEVEL];
      54              :     char netType[16];
      55              :     GetNetInstanceIdFunc instanceIdFunc;
      56              : } LevelInfo;
      57              : 
      58              : typedef struct _stUBRule {
      59              :     unsigned int mainBoardId;
      60              :     unsigned int spodType;
      61              :     int levelNum;
      62              :     LevelInfo levelInfos[MAX_LEVEL_NUM];
      63              : } NetInfo;
      64              : 
      65              : /**
      66              :  *  获取OS级net instance id, 用于不组超节点形态
      67              :  */
      68              : int GetNetInstanceIdForOS(int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen);
      69              : 
      70              : /**
      71              :  *  获取超节点中单个服务器的net instance id
      72              :  */
      73              : int GetNetInstanceIdForPod(
      74              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen);
      75              : 
      76              : /**
      77              :  *  获取超节点的net instance id
      78              :  */
      79              : int GetNetInstanceIdForSuperPod(
      80              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen);
      81              : 
      82              : int GetNetInstanceIdForCluster(
      83              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen);
      84              : 
      85              : #define MAX_UE_ID (99) // 定义一个MAX_UE_ID, mesh必须使用最大的UE
      86              : static const NetInfo g_netInfoList[] = {
      87              :     {
      88              :         .mainBoardId = MAIN_BOARD_ID_SERVER_UBX,
      89              :         .spodType = TOPO_TYPE_IGNORE,
      90              :         .levelNum = 2, 
      91              :         {
      92              :             {
      93              :                 .level = 0,
      94              :                 .netType = NET_TYPE_TOPO_FILE_DESC,
      95              :                 .ueNum = 3,
      96              :                 .instanceIdFunc = GetNetInstanceIdForOS,
      97              :                 .ueList = {
      98              :                     {.dieId = UDIE_1, .feId = 3, .type =UE_TYPE_MESH}, 
      99              :                     {.dieId = UDIE_1, .feId = 2, .type =UE_TYPE_CLOS_PORTS},
     100              :                     {.dieId = UDIE_1, .feId = 2, .type =UE_TYPE_CLOS}
     101              :                 }
     102              :             },
     103              :             CLOS_LEVEL3,
     104              :         },
     105              :    },
     106              :    {
     107              :         .mainBoardId = MAIN_BOARD_ID_SERVER_8PMESH,
     108              :         .spodType = TOPO_TYPE_IGNORE,
     109              :         .levelNum = 3, 
     110              :         {
     111              :             {  // level 0 为OS内通信
     112              :                 .level = 0,
     113              :                 .netType = NET_TYPE_TOPO_FILE_DESC,
     114              :                 .ueNum = 1,
     115              :                 .instanceIdFunc = GetNetInstanceIdForPod,
     116              :                 .ueList = {
     117              :                     {.dieId = UDIE_1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH},
     118              :                 }
     119              :             },
     120              :             { // level 1 为超平面
     121              :                 .level = 1,
     122              :                 .netType = NET_TYPE_CLOS,
     123              :                 .ueNum = 1,
     124              :                 .instanceIdFunc = GetNetInstanceIdForSuperPod,
     125              :                 .ueList = { // 8口scaleup
     126              :                     {.dieId = UDIE_0, .feId = 3, .type = UE_TYPE_CLOS},
     127              :                 },
     128              :             },
     129              :             CLOS_LEVEL3,
     130              :         },
     131              :    },
     132              :    {
     133              :         .mainBoardId = MAIN_BOARD_ID_SERVER_8PMESH_UBOE,
     134              :         .spodType = TOPO_TYPE_IGNORE,
     135              :         .levelNum = 4, 
     136              :         {
     137              :             {
     138              :                 .level = 0, .netType = NET_TYPE_TOPO_FILE_DESC, .ueNum = 1,
     139              :                 .instanceIdFunc = GetNetInstanceIdForPod,
     140              :                 .ueList = { {.dieId = UDIE_1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH}, }
     141              :             },
     142              :             {
     143              :                 .level = 1, .netType = NET_TYPE_CLOS, .ueNum = 1,
     144              :                 .instanceIdFunc = GetNetInstanceIdForSuperPod,
     145              :                 .ueList = { {.dieId = UDIE_0, .feId = 3, .type =UE_TYPE_CLOS} },
     146              :             },
     147              :             { 
     148              :                 .level = 2, .netType = NET_TYPE_CLOS, .ueNum = 1, .instanceIdFunc = GetNetInstanceIdForCluster,
     149              :                 .ueList = { {.dieId = UDIE_0, .feId = 0, .type =UE_TYPE_UBOE, .ports = "1/8"} } 
     150              :             },
     151              :             CLOS_LEVEL3,
     152              :         },
     153              :    },
     154              :    {// 由两个8 NPU服务器组成一个16NPU的小超节点,共16个NPU组成fullmesh组网
     155              :         .mainBoardId = MAIN_BOARD_ID_SERVER_8PMESH_UBOE,
     156              :         .spodType = TOPO_TYPE_SERVER_16FM,  // 两个服务器组16p fullmesh
     157              :         .levelNum = 3, 
     158              :         {
     159              :             {
     160              :                 .level = 0, .netType = NET_TYPE_TOPO_FILE_DESC, .ueNum = 2,
     161              :                 .instanceIdFunc = GetNetInstanceIdForPod,
     162              :                 .ueList = { 
     163              :                     {.dieId = UDIE_0, .feId = MAX_UE_ID, .type = UE_TYPE_MESH}, 
     164              :                     {.dieId = UDIE_1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH}
     165              :                 }
     166              :             },
     167              :             { // 支持UBOE出口
     168              :                 .level = 2, .netType = NET_TYPE_CLOS, .ueNum = 1, .instanceIdFunc = GetNetInstanceIdForCluster,
     169              :                 .ueList = { {.dieId = UDIE_0, .feId = 0, .type =UE_TYPE_UBOE, .ports = "1/8"} },
     170              :             },
     171              :             CLOS_LEVEL3,
     172              :         },
     173              :    },
     174              :    {
     175              :         .mainBoardId = MAIN_BOARD_ID_SERVER_8PMESH_NOSP_UBOE, // 这种形态无超平面,但是有UBOE
     176              :         .spodType = TOPO_TYPE_IGNORE,
     177              :         .levelNum = 3, 
     178              :         {
     179              :             {
     180              :                 .level = 0,
     181              :                 .netType = NET_TYPE_TOPO_FILE_DESC,
     182              :                 .ueNum = 1,
     183              :                 .instanceIdFunc = GetNetInstanceIdForOS,
     184              :                 .ueList = {
     185              :                     {.dieId = UDIE_1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH},
     186              :                 }
     187              :             },
     188              :             { 
     189              :                 .level = 2, .netType = NET_TYPE_CLOS, .ueNum = 1, .instanceIdFunc = GetNetInstanceIdForCluster,
     190              :                 .ueList = { {.dieId = UDIE_0, .feId = 0, .type =UE_TYPE_UBOE, .ports = "1/8"} } 
     191              :             },
     192              :             CLOS_LEVEL3,
     193              :         },
     194              :    },
     195              :    {
     196              :         .mainBoardId = MAIN_BOARD_ID_SERVER_8PMESH_NOSP, // 无超平面,无UBOE
     197              :         .spodType = TOPO_TYPE_IGNORE,
     198              :         .levelNum = 2,
     199              :         {
     200              :             {
     201              :                 .level = 0, .netType = NET_TYPE_TOPO_FILE_DESC, .ueNum = 1,
     202              :                 .instanceIdFunc = GetNetInstanceIdForOS,
     203              :                 .ueList = { {.dieId = UDIE_1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH} }
     204              :             },
     205              :             CLOS_LEVEL3,
     206              :         },
     207              :    },
     208              :    {
     209              :         .mainBoardId = MAIN_BOARD_ID_SERVER_TYPE1,
     210              :         .spodType = TOPO_TYPE_IGNORE,
     211              :         .levelNum = 3, 
     212              :         {
     213              :             {
     214              :                 .level = 0,
     215              :                 .ueNum = 1,
     216              :                 .ueList = {
     217              :                     {.dieId = 1, .feId = MAX_UE_ID, .type = UE_TYPE_MESH},
     218              :                 }
     219              :             },
     220              :             {
     221              :                 .level = 1,
     222              :                 .ueNum = 2,
     223              :                 .ueList = {
     224              :                     {.dieId = 0, .feId = 3, .type =UE_TYPE_CLOS },
     225              :                     {.dieId = 1, .feId = 2, .type =UE_TYPE_CLOS },
     226              :                 }
     227              :             },
     228              :             CLOS_LEVEL3,
     229              :         },
     230              :    },
     231              : };
     232              : 
     233            0 : int ServerGetRootinfoLen(size_t *len)
     234              : {
     235            0 :     *len = MAX_SERVER_ROOTINFO_LEN;
     236            0 :     return 0;
     237              : }
     238              : 
     239           98 : int GetNetInstanceIdForOS(int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen)
     240              : {
     241           98 :     return get_server_id(netInstanceId, netInstanceIdLen);
     242              : }
     243              : 
     244           68 : int GetNetInstanceIdForPod(int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen)
     245              : {
     246           68 :     return sprintf_s(netInstanceId, netInstanceIdLen, "sp_%ld_srv_%ld", spodInfo->super_pod_id, spodInfo->server_index);
     247              : }
     248              : 
     249           67 : int GetNetInstanceIdForSuperPod(
     250              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen)
     251              : {
     252           67 :     return sprintf_s(netInstanceId, netInstanceIdLen, "sp_%ld", spodInfo->super_pod_id);
     253              : }
     254              : 
     255           67 : int GetNetInstanceIdForCluster(
     256              :     int npu_id, const struct dcmi_spod_info *spodInfo, char *netInstanceId, int netInstanceIdLen)
     257              : {
     258           67 :     return sprintf_s(netInstanceId, netInstanceIdLen, "cluster");
     259              : }
     260              : 
     261          166 : const NetInfo *GetNetInfo(unsigned int mainBoardId, unsigned int spodType)
     262              : {
     263              :     // 优先匹配满足mainboard id和 super pod type的情况
     264         1324 :     for (size_t i = 0; i < sizeof(g_netInfoList) / sizeof(g_netInfoList[0]); ++i) {
     265         1159 :         if (g_netInfoList[i].mainBoardId == mainBoardId && g_netInfoList[i].spodType == spodType) {
     266            1 :             return &g_netInfoList[i];
     267              :         }
     268              :     }
     269              :     //  忽略spod type,只匹配mainboard id
     270          554 :     for (size_t i = 0; i < sizeof(g_netInfoList) / sizeof(g_netInfoList[0]); ++i) {
     271          554 :         if (g_netInfoList[i].mainBoardId == mainBoardId) {
     272          165 :             return &g_netInfoList[i];
     273              :         }
     274              :     }
     275            0 :     return NULL;
     276              : }
     277              : 
     278              : /*
     279              :  * @brief 处理mesh entity的地址, 将UBEntity中的地址加到layer中
     280              :  * 将UB entity中的所有地址按每个端口填入
     281              :  * @param layer: 网络层
     282              :  * @param ue: ue entity
     283              :  * @param spod_info: spod信息
     284              :  * @return int: 0 成功
     285              :  */
     286            9 : static int LayerAddMesh(const UBEntity *ue, NetLayer *layer, int type)
     287              : {
     288           68 :     for (unsigned int j = 0; j < ue->eidNum; ++j) {
     289           59 :         if (UrmaEidIsPortGroup(&ue->eidList[j].eid)) {
     290            9 :             continue;
     291              :         }
     292              :         Addr addr;
     293           50 :         memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
     294           50 :         AddrSetEID(&addr, &ue->eidList[j].eid);
     295           50 :         char port[MAX_PORT_LEN] = {0};
     296           50 :         char planeId[MAX_PLANE_ID_LEN] = {0};
     297           50 :         int portId = UrmaEidGetPortId(&ue->eidList[j].eid);
     298           50 :         int dieId = UrmaEidGetDieId(&ue->eidList[j].eid);
     299              :         // topo中端口从0开始编,CNA中需要规避全0,从1开始
     300           50 :         sprintf_s(port, MAX_PORT_LEN, "%d/%d", dieId, portId);
     301           50 :         if (type == UE_TYPE_MESH) {
     302           42 :             sprintf_s(planeId, sizeof(planeId), "plane_%d", dieId);
     303            8 :         } else if (type == UE_TYPE_CLOS_PORTS) {
     304            8 :             sprintf_s(planeId, sizeof(planeId), "plane_clos_%d_%d", dieId, portId);
     305              :         }
     306           50 :         AddrAddPort(&addr, port);
     307           50 :         AddrSetPlaneId(&addr, planeId);
     308           50 :         NetLayerAddAddr(layer, &addr);
     309              :     }
     310            9 :     return 0;
     311              : }
     312              : 
     313            5 : static int LayerAddClos(const UBEntity *ue, NetLayer *layer)
     314              : {
     315            5 :     int portGroupIdx = UBEntityGetPortGroupIdx(ue);
     316            5 :     if (portGroupIdx < 0) {
     317            0 :         return -1;
     318              :     }
     319            5 :     int dieId = UrmaEidGetDieId(&ue->eidList[portGroupIdx].eid);
     320              :     Addr addr;
     321            5 :     memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
     322            5 :     AddrSetEID(&addr, &ue->eidList[portGroupIdx].eid);
     323           42 :     for (unsigned int i = 0; i < ue->eidNum; ++i) {
     324           37 :         if (UrmaEidIsPortGroup(&ue->eidList[i].eid)) {
     325            5 :             continue;
     326              :         }
     327           32 :         char port[MAX_PORT_LEN] = {0};
     328           32 :         sprintf_s(port, MAX_PORT_LEN, "%d/%d", dieId, UrmaEidGetPortId(&ue->eidList[i].eid));
     329           32 :         AddrAddPort(&addr, port);
     330              :     }
     331              : 
     332            5 :     char planeId[MAX_PLANE_ID_LEN] = {0};
     333            5 :     sprintf_s(planeId, sizeof(planeId), "plane_clos_%d", dieId);
     334            5 :     AddrSetPlaneId(&addr, planeId);
     335            5 :     NetLayerAddAddr(layer, &addr);
     336            5 :     return 0;
     337              : }
     338              : 
     339            2 : static int LayerAddUBOE(const UBEntity *ue, const UEInfo *ueInfo, NetLayer *layer)
     340              : {
     341              : #define INVLID_IP_PREFIX "254" // 该IP是有协议栈无DHCP等场景自动生成的本地私有地址前缀
     342              :     Addr addr;
     343            2 :     memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
     344            2 :     int result = -1;
     345            6 :     for (unsigned int i = 0; i < ue->eidNum; ++i) {
     346            4 :         char cna[IP_ADDR_LEN] = {0};
     347            4 :         UrmaEid2CNA(&ue->eidList[i].eid, cna, sizeof(cna));
     348            4 :         if (strncmp(cna, INVLID_IP_PREFIX, strlen(INVLID_IP_PREFIX)) == 0) {
     349            2 :             continue;
     350              :         }
     351            2 :         AddrSetIP(&addr, cna);
     352            2 :         char port[MAX_PORT_LEN] = {0};
     353            2 :         int ret = sprintf_s(port, MAX_PORT_LEN, "%s", ueInfo->ports);
     354            2 :         if (ret < 0) {
     355            0 :             break;
     356              :         }
     357            2 :         AddrAddPort(&addr, port);
     358            2 :         result = 0;
     359              :     }
     360            2 :     char planeId[MAX_PLANE_ID_LEN] = {0};
     361            2 :     int ret = sprintf_s(planeId, sizeof(planeId), "plane_uboe");
     362            2 :     if (ret < 0) {
     363            0 :         return -1;
     364              :     }
     365            2 :     AddrSetPlaneId(&addr, planeId);
     366            2 :     NetLayerAddAddr(layer, &addr);
     367            2 :     return result;
     368              : }
     369              : 
     370              : /**
     371              :  * @brief 根据dieId和feId从UEList中获取UBEntity
     372              :  * @param ueList: ue entity列表
     373              :  * @param dieId: die id
     374              :  * @param ueId: ue id
     375              :  * @param type: UB类型
     376              :  * @return UBEntity*: ue entity
     377              :  */
     378          369 : static const UBEntity *GetUBEntityByFilter(const UEList *ueList, int dieId, int ueId, int type)
     379              : {
     380          369 :     if (type == UE_TYPE_UBOE) {
     381           79 :         for (unsigned int i = 0; i < ueList->ueNum; i++) {
     382           14 :             if (UrmaEidIsUBOE(&ueList->ueList[i].eidList[0].eid)) {
     383            2 :                 return &ueList->ueList[i];
     384              :             }
     385              :         }
     386           65 :         return NULL;
     387              :     }
     388          302 :     if (type == UE_TYPE_UBG) {
     389            0 :         for (unsigned int i = 0; i < ueList->ueNum; i++) {
     390            0 :             if (UrmaEidIsUBG(&ueList->ueList[i].eidList[0].eid)) {
     391            0 :                 return &ueList->ueList[i];
     392              :             }
     393              :         }
     394            0 :         return NULL;
     395              :     }
     396          302 :     int maxFe = 0;
     397          302 :     const UBEntity *ubEntity = NULL;
     398          331 :     for (unsigned int i = 0; i < ueList->ueNum; i++) {
     399           38 :         if (UrmaEidIsUBOE(&ueList->ueList[i].eidList[0].eid)) {
     400            4 :             continue;
     401              :         }
     402           34 :         int die = UrmaEidGetDieId(&ueList->ueList[i].eidList[0].eid);
     403           34 :         int fe = UBEntityGetId(&ueList->ueList[i]);
     404           34 :         if (die == dieId && fe == ueId) { // MAX_UE_ID足够大,这里不会匹配到
     405            9 :             return &ueList->ueList[i];
     406              :         }
     407              :         //  获取本iodie上UBEntity ID最大的UB Entity
     408           25 :         if (die == dieId && fe > maxFe) {
     409           15 :             maxFe = fe;
     410           15 :             ubEntity = &ueList->ueList[i];
     411              :         }
     412              :     }
     413          293 :     if (ueId == MAX_UE_ID) {
     414          133 :         return ubEntity;
     415              :     }
     416          160 :     return NULL;
     417              : }
     418              : 
     419              : /**
     420              :  * @brief 根据配置从ueList中过滤出ub entity, 并处理其中的地址添加到netlayer中
     421              :  * @param layer: 网络层信息
     422              :  * @param ueList: 全量的ue entity数组
     423              :  * @param levelInfo:  当前处理的层级信息
     424              :  * @param spodInfo: spod信息
     425              :  * @return int: 0 成功
     426              :  */
     427          466 : static int ProcessLayer(
     428              :     int npuId, NetLayer *layer, UEList *ueList, const LevelInfo *levelInfo, const struct dcmi_spod_info *spodInfo)
     429              : {
     430              :     /* RoCE 层(level 3)走独立路径,不查 UEList */
     431          466 :     if (levelInfo->level == 3) {
     432          166 :         return ProcessLayerRoce(npuId, layer);
     433              :     }
     434              : 
     435          300 :     char net_instance_id[MAX_INSTANCE_ID_LEN] = {0};
     436          300 :     levelInfo->instanceIdFunc(npuId, spodInfo, net_instance_id, sizeof(net_instance_id));
     437          300 :     NetLayerInit(layer, levelInfo->level, net_instance_id);
     438          300 :     NetLayerSetNetType(layer, levelInfo->netType);
     439              : 
     440          300 :     int ret = -1;
     441          669 :     for (int i = 0; i < levelInfo->ueNum; ++i) {
     442          369 :         int fe = levelInfo->ueList[i].feId;
     443          369 :         int die = levelInfo->ueList[i].dieId;
     444          369 :         int type = levelInfo->ueList[i].type;
     445          369 :         const UBEntity *ue = GetUBEntityByFilter(ueList, die, fe, type);
     446          369 :         if (ue == NULL) {
     447          353 :             continue;
     448              :         }
     449           16 :         if (type == UE_TYPE_MESH || type == UE_TYPE_CLOS_PORTS) {
     450            9 :             ret = LayerAddMesh(ue, layer, type);
     451            7 :         } else if (type == UE_TYPE_CLOS) {
     452            5 :             ret = LayerAddClos(ue, layer);
     453            2 :         } else if (type == UE_TYPE_UBOE) {
     454            2 :             ret = LayerAddUBOE(ue, &levelInfo->ueList[i], layer);
     455              :         }
     456              :     }
     457          300 :     return ret;
     458              : }
     459              : 
     460          166 : int ServerGetRootinfo(int npu_id, unsigned mainboard_id, void *buf, size_t *len)
     461              : {
     462          166 :     if (buf == NULL || len == NULL) {
     463            0 :         return RET_NOK;
     464              :     }
     465              :     struct dcmi_spod_info spod_info;
     466              :     UEList ueList;
     467          166 :     HalGetUBEntityList(npu_id, &ueList);
     468          166 :     hal_get_spod_info(npu_id, &spod_info);
     469              : 
     470              :     RootInfo rootinfo;
     471              :     Rank rank;
     472          166 :     RootInfoInit(&rootinfo);
     473          166 :     int localId = npu_id;
     474          166 :     if (spod_info.super_pod_type == TOPO_TYPE_SERVER_16FM) {
     475            1 :         localId = npu_id + (spod_info.server_index * SERVER_NPU_NUM);
     476              :     }
     477          166 :     RankInit(&rank, npu_id, localId);
     478          166 :     TopoGetFilePath(mainboard_id, spod_info.super_pod_type, rootinfo.topo_file_path, MAX_TOPO_PATH_LEN);
     479              :     
     480              : 
     481          166 :     const NetInfo *netInfo = GetNetInfo(mainboard_id, spod_info.super_pod_type);
     482          166 :     if (netInfo == NULL) {
     483            0 :         return -1;
     484              :     }
     485              : 
     486          632 :     for (int i = 0; i < netInfo->levelNum; ++i) {
     487              :         NetLayer layer;
     488          466 :         if (ProcessLayer(npu_id, &layer, &ueList, &netInfo->levelInfos[i], &spod_info) == 0) {
     489          121 :             RankAddNetLayer(&rank, &layer);
     490              :         }
     491              :     }
     492              : 
     493          166 :     RootInfoAddRank(&rootinfo, &rank);
     494          166 :     char *rootinfo_buf = RootInfoToString(&rootinfo);
     495          166 :     if (rootinfo_buf == NULL) {
     496            0 :         return -1;
     497              :     }
     498          166 :     if ((*len) < strlen(rootinfo_buf)) {
     499            0 :         (*len) = strlen(rootinfo_buf);
     500            0 :         free(rootinfo_buf);
     501            0 :         return -1;
     502              :     }
     503          166 :     errno_t ret = strcpy_s(buf, *len, rootinfo_buf);
     504          166 :     (*len) = strlen(buf);
     505          166 :     free(rootinfo_buf);
     506          166 :     return ret;
     507              : }
        

Generated by: LCOV version 2.0-1