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