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

Generated by: LCOV version 2.0-1