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 : }
|