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