LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/topo/topo_addr_info/src - product_pod.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.2 % 103 96
Test Date: 2026-08-04 10:52:23 Functions: 100.0 % 5 5

            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_pod.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_POD_ROOTINFO_LEN (2048)
      21              : #define PRODUCT_MESH_LEVEL (0)
      22              : #define PRODUCT_CLOS_LEVEL (1)
      23              : #define MAX_MESH_PORT_ID (9)
      24              : #define NPU_NUM (8)
      25              : 
      26            1 : int PodGetRootinfoLen(size_t *len)
      27              : {
      28            1 :     *len = MAX_POD_ROOTINFO_LEN;
      29            1 :     return 0;
      30              : }
      31              : 
      32              : typedef struct rule {
      33              :     unsigned int mainboardId;
      34              :     int level; // 网络层级  0 mesh, 1 scaleup, 2 UBOE/UBG, 3 ROCE
      35              :     int dieId; // io die id NPU有两个iodie, 0和1
      36              :     int ueId;  // UBEntity ID, 用于定义UB实体的功能
      37              :     int ports[MAX_PORT_NUM];
      38              :     int portNum;
      39              :     int npus[MAX_PORT_NUM];
      40              :     int npuNum;
      41              :     char planeId[MAX_PLANE_ID_LEN];
      42              : } UBEntityRule;
      43              : 
      44              : /**
      45              :  * @brief PoD形态的通信规划
      46              :  * 每个NPU出8个口上scaleup网络,一个iodie出6口到平面0, 另一个iodie出2口到平面1
      47              :  * 其中前4个NPU:  iodie 0出6口, iodie 1出2口
      48              :  * 其中后4个NPU:  iodie 0出2口, iodie 1出6口
      49              :  * 这个结构体用于定义这些规则
      50              :  */
      51              : static const UBEntityRule g_ubrules[] = {
      52              :     // NPU 0-3 的1die使用6个端口,连平面0,平面0只和平面0通信
      53              :     {MAIN_BOARD_ID_POD, PRODUCT_CLOS_LEVEL, 1, 2, {0, 1, 2, 3, 5, 6}, 6, {0, 1, 2, 3}, 4, "plane_pg_0"},
      54              :     // NPU 0-3 的0die使用2个端口,连平面1,平面1只和平面1通信
      55              :     {MAIN_BOARD_ID_POD, PRODUCT_CLOS_LEVEL, 0, 2, {1, 2}, 2, {0, 1, 2, 3}, 4, "plane_pg_1"},
      56              :     // NPU 4-7 的0 die使用6个端口
      57              :     {MAIN_BOARD_ID_POD, PRODUCT_CLOS_LEVEL, 0, 2, {0, 1, 2, 3, 4, 5}, 6, {4, 5, 6, 7}, 4, "plane_pg_0"},
      58              :     // NPU 4-7 的1 die使用2个端口
      59              :     {MAIN_BOARD_ID_POD, PRODUCT_CLOS_LEVEL, 1, 2, {1, 2}, 2, {4, 5, 6, 7}, 4, "plane_pg_1"},
      60              :     // NPU 0-3 的1die使用6个端口
      61              :     {MAIN_BOARD_ID_POD_2D, PRODUCT_CLOS_LEVEL, 1, 2, {0, 1, 2, 3, 5, 6}, 6, {0, 1, 2, 3}, 4, "plane_pg_0"},
      62              :     // NPU 0-3 的0die使用2个端口
      63              :     {MAIN_BOARD_ID_POD_2D, PRODUCT_CLOS_LEVEL, 0, 2, {1, 2}, 2, {0, 1, 2, 3}, 4, "plane_pg_1"},
      64              :     // NPU 4-7 的0 die使用6个端口
      65              :     {MAIN_BOARD_ID_POD_2D, PRODUCT_CLOS_LEVEL, 0, 2, {0, 1, 2, 3, 4, 5}, 6, {4, 5, 6, 7}, 4, "plane_pg_0"},
      66              :     // NPU 4-7 的1 die使用2个端口
      67              :     {MAIN_BOARD_ID_POD_2D, PRODUCT_CLOS_LEVEL, 1, 2, {1, 2}, 2, {4, 5, 6, 7}, 4, "plane_pg_1"},
      68              : };
      69              : 
      70           65 : static int ProcessLayerMesh(int npu_id, NetLayer *layer, UEList *ueList, struct dcmi_spod_info *spod_info)
      71              : {
      72           65 :     char net_instance_id[MAX_INSTANCE_ID_LEN] = {0};
      73           65 :     sprintf_s(
      74              :         net_instance_id, sizeof(net_instance_id), "sp%ld_srv%ld", spod_info->super_pod_id, spod_info->server_index);
      75           65 :     NetLayerInit(layer, PRODUCT_MESH_LEVEL, net_instance_id);
      76           65 :     NetLayerSetNetType(layer, NET_TYPE_MESH);
      77              : 
      78           65 :     const int meshDieId = npu_id % 8 < 4 ? 0 : 1;
      79           65 :     int meshEntityId = UBGetMaxEntityId(ueList, meshDieId);
      80           69 :     for (unsigned int i = 0; i < ueList->ueNum; i++) {
      81            4 :         int fe = UBEntityGetId(&ueList->ueList[i]);
      82            4 :         int dieId = UBEntityGetDieId(&ueList->ueList[i]);
      83            4 :         if (fe != meshEntityId || dieId != meshDieId) {
      84            3 :             continue;
      85              :         }
      86            9 :         for (unsigned int j = 0; j < ueList->ueList[i].eidNum; ++j) {
      87            8 :             int phyPortId = UrmaEidGetPortId(&ueList->ueList[i].eidList[j].eid);
      88            8 :             if (phyPortId > MAX_MESH_PORT_ID) {
      89            1 :                 continue;
      90              :             }
      91              :             Addr addr;
      92            7 :             memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
      93            7 :             AddrSetEID(&addr, &ueList->ueList[i].eidList[j].eid);
      94            7 :             int portId = UrmaEidGetPortId(&ueList->ueList[i].eidList[j].eid);
      95            7 :             char port[MAX_PORT_LEN] = {0};
      96            7 :             sprintf_s(port, MAX_PORT_LEN, "%d/%d", dieId, portId);
      97            7 :             AddrAddPort(&addr, port);
      98            7 :             AddrSetPlaneId(&addr, "plane_0");
      99            7 :             NetLayerAddAddr(layer, &addr);
     100              :         }
     101              :     }
     102           65 :     return 0;
     103              : }
     104              : 
     105              : /**
     106              :  * @brief 根据NPU ID, 网络层级, 主板ID, iodie ID, UE ID获取对应的UB实体规则
     107              :  * @param npu_id NPU ID
     108              :  * @param level 网络层级
     109              :  * @param mainBoardId 主板ID
     110              :  * @param die iodie ID
     111              :  * @param feId UE ID
     112              :  * @return const UBEntityRule* 对应的UB实体规则
     113              :  */
     114            4 : static const UBEntityRule *GetUBRule(int npu_id, int level, unsigned int mainBoardId, int die, int feId)
     115              : {
     116           21 :     for (size_t i = 0; i < sizeof(g_ubrules) / sizeof(UBEntityRule); ++i) {
     117           19 :         if (g_ubrules[i].level != level) {
     118            0 :             continue;
     119              :         }
     120           19 :         int isNpuInRule = 0;
     121           51 :         for (int j = 0; j < g_ubrules[i].npuNum; ++j) {
     122           43 :             if (g_ubrules[i].npus[j] == npu_id) {
     123           11 :                 isNpuInRule = 1;
     124           11 :                 break;
     125              :             }
     126              :         }
     127           19 :         if (isNpuInRule == 0) {
     128            8 :             continue;
     129              :         }
     130           11 :         if (g_ubrules[i].level != level) {
     131            0 :             continue;
     132              :         }
     133           11 :         if (mainBoardId == g_ubrules[i].mainboardId && die == g_ubrules[i].dieId && feId == g_ubrules[i].ueId) {
     134            2 :             return &g_ubrules[i];
     135              :         }
     136              :     }
     137            2 :     return NULL;
     138              : }
     139              : 
     140           65 : static int ProcessLayerClos(
     141              :     int npu_id, unsigned int mainBoardId, NetLayer *layer, UEList *ueList, struct dcmi_spod_info *spod_info)
     142              : {
     143           65 :     char net_instance_id[MAX_INSTANCE_ID_LEN] = {0};
     144           65 :     sprintf_s(net_instance_id, sizeof(net_instance_id), "superpod_%ld", spod_info->super_pod_id);
     145           65 :     NetLayerInit(layer, PRODUCT_CLOS_LEVEL, net_instance_id);
     146           65 :     NetLayerSetNetType(layer, NET_TYPE_CLOS);
     147              : 
     148           69 :     for (unsigned int i = 0; i < ueList->ueNum; ++i) {
     149            4 :         int fe = UBEntityGetId(&ueList->ueList[i]);
     150            4 :         int portGroupIdx = UBEntityGetPortGroupIdx(&ueList->ueList[i]);
     151            4 :         if (portGroupIdx < 0) {
     152            2 :             continue;
     153              :         }
     154            4 :         int die = UrmaEidGetDieId(&ueList->ueList[i].eidList[portGroupIdx].eid);
     155            4 :         const UBEntityRule *rule =  GetUBRule((npu_id % NPU_NUM), PRODUCT_CLOS_LEVEL, mainBoardId, die, fe);
     156            4 :         if (rule == NULL) {
     157            2 :             continue;
     158              :         }
     159              :         Addr addr;
     160            2 :         memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
     161            2 :         AddrSetEID(&addr, &ueList->ueList[i].eidList[portGroupIdx].eid);
     162              : 
     163            2 :         int portNum = 0;
     164           12 :         for (unsigned int j = 0; j < ueList->ueList[i].eidNum; ++j) {
     165           10 :             if (UrmaEidIsPortGroup(&ueList->ueList[i].eidList[j].eid)) {
     166            2 :                 continue;
     167              :             }
     168            8 :             int portId = UrmaEidGetPortId(&ueList->ueList[i].eidList[j].eid);
     169            8 :             char port[MAX_PORT_LEN] = {0};
     170            8 :             sprintf_s(port, MAX_PORT_LEN, "%d/%d", die, portId);
     171            8 :             AddrAddPort(&addr, port);
     172            8 :             portNum++;
     173              :         }
     174              : 
     175              :         // CCU需使用相同的6口建联,需要把6口的portgroup排在前面
     176            2 :         const int primaryPortNum = 6;
     177            2 :         if (portNum >= primaryPortNum) {
     178            1 :             AddrSetPlaneId(&addr, "plane_0");
     179            1 :             NetLayerSetAddrAt(layer, &addr, 0);
     180              :         } else {
     181            1 :             AddrSetPlaneId(&addr, "plane_1");
     182            1 :             NetLayerSetAddrAt(layer, &addr, 1);
     183              :         }
     184              :     }
     185           65 :     return 0;
     186              : }
     187              : 
     188           65 : int PodGetRootinfo(int npu_id, unsigned mainboard_id, void *buf, size_t *len)
     189              : {
     190           65 :     if (buf == NULL || len == NULL) {
     191            0 :         return RET_NOK;
     192              :     }
     193              :     RootInfo rootinfo;
     194              :     Rank rank;
     195              :     NetLayer layerMesh;
     196              :     NetLayer layerClos;
     197              :     NetLayer layerRoce;
     198           65 :     RootInfoInit(&rootinfo);
     199              :     
     200           65 :     TopoGetFilePath(mainboard_id, TOPO_TYPE_IGNORE, rootinfo.topo_file_path, MAX_TOPO_PATH_LEN);
     201              :     struct dcmi_spod_info spod_info;
     202              :     UEList ueList;
     203           65 :     HalGetUBEntityList(npu_id, &ueList);
     204           65 :     hal_get_spod_info(npu_id, &spod_info);
     205              :     // local id在PoD框内取值从0-63, 本OS只能看到device_id, 需要加上server_index * 8构成完整的0-63
     206           65 :     int localId = (npu_id % NPU_NUM) + ((spod_info.server_index % NPU_NUM) * NPU_NUM);
     207           65 :     RankInit(&rank, npu_id, localId);
     208              : 
     209           65 :     if (ProcessLayerMesh(npu_id, &layerMesh, &ueList, &spod_info) == 0) {
     210           65 :         RankAddNetLayer(&rank, &layerMesh);
     211              :     }
     212           65 :     if (ProcessLayerClos(npu_id, mainboard_id, &layerClos, &ueList, &spod_info) == 0) {
     213           65 :         RankAddNetLayer(&rank, &layerClos);
     214              :     }
     215              : 
     216              :     /* L3 RoCE 层:当 XML 提供 IP 时追加 */
     217           65 :     if (ProcessLayerRoce(npu_id, &layerRoce) == 0) {
     218           44 :         RankAddNetLayer(&rank, &layerRoce);
     219              :     }
     220              : 
     221           65 :     RootInfoAddRank(&rootinfo, &rank);
     222           65 :     char *rootinfo_buf = RootInfoToString(&rootinfo);
     223           65 :     if (rootinfo_buf == NULL) {
     224            0 :         return -1;
     225              :     }
     226           65 :     if ((*len) < strlen(rootinfo_buf)) {
     227            0 :         (*len) = strlen(rootinfo_buf);
     228            0 :         free(rootinfo_buf);
     229            0 :         return -1;
     230              :     }
     231           65 :     errno_t ret = strcpy_s(buf, *len, rootinfo_buf);
     232           65 :     (*len) = strlen(buf);
     233           65 :     free(rootinfo_buf);
     234           65 :     return ret;
     235              : }
        

Generated by: LCOV version 2.0-1