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_server.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_SERVER_ROOTINFO_LEN (2048)
22 : #define PRODUCT_MESH_LEVEL (0)
23 : #define PRODUCT_CLOS_LEVEL (1)
24 : #define IP_ADDR_LEN (32)
25 :
26 : /* 用于识别FE*/
27 : #define MAX_UE_ID_IN_LEVEL (4)
28 : #define MAX_LEVEL_NUM (4)
29 : #define SERVER_NPU_NUM (8)
30 : #define CLOS_LEVEL3 {.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_UB_RTP = 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 : (void)npu_id;
242 : (void)spodInfo;
243 98 : return get_server_id(netInstanceId, netInstanceIdLen);
244 : }
245 :
246 68 : int GetNetInstanceIdForPod(int npu_id, const struct dcmi_spod_info* spodInfo, char* netInstanceId, int netInstanceIdLen)
247 : {
248 : (void)npu_id;
249 68 : return sprintf_s(netInstanceId, netInstanceIdLen, "sp_%ld_srv_%ld", spodInfo->super_pod_id, spodInfo->server_index);
250 : }
251 :
252 67 : int GetNetInstanceIdForSuperPod(
253 : int npu_id, const struct dcmi_spod_info* spodInfo, char* netInstanceId, int netInstanceIdLen)
254 : {
255 : (void)npu_id;
256 67 : return sprintf_s(netInstanceId, netInstanceIdLen, "sp_%ld", spodInfo->super_pod_id);
257 : }
258 :
259 67 : int GetNetInstanceIdForCluster(
260 : int npu_id, const struct dcmi_spod_info* spodInfo, char* netInstanceId, int netInstanceIdLen)
261 : {
262 : (void)npu_id;
263 : (void)spodInfo;
264 67 : return sprintf_s(netInstanceId, netInstanceIdLen, "cluster");
265 : }
266 :
267 166 : const NetInfo* GetNetInfo(unsigned int mainBoardId, unsigned int spodType)
268 : {
269 : // 优先匹配满足mainboard id和 super pod type的情况
270 1324 : for (size_t i = 0; i < sizeof(g_netInfoList) / sizeof(g_netInfoList[0]); ++i) {
271 1159 : if (g_netInfoList[i].mainBoardId == mainBoardId && g_netInfoList[i].spodType == spodType) {
272 1 : return &g_netInfoList[i];
273 : }
274 : }
275 : // 忽略spod type,只匹配mainboard id
276 554 : for (size_t i = 0; i < sizeof(g_netInfoList) / sizeof(g_netInfoList[0]); ++i) {
277 554 : if (g_netInfoList[i].mainBoardId == mainBoardId) {
278 165 : return &g_netInfoList[i];
279 : }
280 : }
281 0 : return NULL;
282 : }
283 :
284 : /*
285 : * @brief 处理mesh entity的地址, 将UBEntity中的地址加到layer中
286 : * 将UB entity中的所有地址按每个端口填入
287 : * @param layer: 网络层
288 : * @param ue: ue entity
289 : * @param spod_info: spod信息
290 : * @return int: 0 成功
291 : */
292 9 : static int LayerAddMesh(const UBEntity* ue, NetLayer* layer, int type)
293 : {
294 68 : for (unsigned int j = 0; j < ue->eidNum; ++j) {
295 59 : if (UrmaEidIsPortGroup(&ue->eidList[j].eid)) {
296 9 : continue;
297 : }
298 : Addr addr;
299 50 : memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
300 50 : AddrSetEID(&addr, &ue->eidList[j].eid);
301 50 : char port[MAX_PORT_LEN] = {0};
302 50 : char planeId[MAX_PLANE_ID_LEN] = {0};
303 50 : int portId = UrmaEidGetPortId(&ue->eidList[j].eid);
304 50 : int dieId = UrmaEidGetDieId(&ue->eidList[j].eid);
305 : // topo中端口从0开始编,CNA中需要规避全0,从1开始
306 50 : sprintf_s(port, MAX_PORT_LEN, "%d/%d", dieId, portId);
307 50 : if (type == UE_TYPE_MESH) {
308 42 : sprintf_s(planeId, sizeof(planeId), "plane_%d", dieId);
309 8 : } else if (type == UE_TYPE_CLOS_PORTS) {
310 8 : sprintf_s(planeId, sizeof(planeId), "plane_clos_%d_%d", dieId, portId);
311 : }
312 50 : AddrAddPort(&addr, port);
313 50 : AddrSetPlaneId(&addr, planeId);
314 50 : NetLayerAddAddr(layer, &addr);
315 : }
316 9 : return 0;
317 : }
318 :
319 5 : static int LayerAddClos(const UBEntity* ue, NetLayer* layer)
320 : {
321 5 : int portGroupIdx = UBEntityGetPortGroupIdx(ue);
322 5 : if (portGroupIdx < 0) {
323 0 : return -1;
324 : }
325 5 : int dieId = UrmaEidGetDieId(&ue->eidList[portGroupIdx].eid);
326 : Addr addr;
327 5 : memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
328 5 : AddrSetEID(&addr, &ue->eidList[portGroupIdx].eid);
329 42 : for (unsigned int i = 0; i < ue->eidNum; ++i) {
330 37 : if (UrmaEidIsPortGroup(&ue->eidList[i].eid)) {
331 5 : continue;
332 : }
333 32 : char port[MAX_PORT_LEN] = {0};
334 32 : sprintf_s(port, MAX_PORT_LEN, "%d/%d", dieId, UrmaEidGetPortId(&ue->eidList[i].eid));
335 32 : AddrAddPort(&addr, port);
336 : }
337 :
338 5 : char planeId[MAX_PLANE_ID_LEN] = {0};
339 5 : sprintf_s(planeId, sizeof(planeId), "plane_clos_%d", dieId);
340 5 : AddrSetPlaneId(&addr, planeId);
341 5 : NetLayerAddAddr(layer, &addr);
342 5 : return 0;
343 : }
344 :
345 2 : static int LayerAddUBOE(const UBEntity* ue, const UEInfo* ueInfo, NetLayer* layer)
346 : {
347 : #define INVLID_IP_PREFIX "254" // 该IP是有协议栈无DHCP等场景自动生成的本地私有地址前缀
348 : Addr addr;
349 2 : memset_s(&addr, sizeof(Addr), 0x00, sizeof(Addr));
350 2 : int result = -1;
351 6 : for (unsigned int i = 0; i < ue->eidNum; ++i) {
352 4 : char cna[IP_ADDR_LEN] = {0};
353 4 : UrmaEid2CNA(&ue->eidList[i].eid, cna, sizeof(cna));
354 4 : if (strncmp(cna, INVLID_IP_PREFIX, strlen(INVLID_IP_PREFIX)) == 0) {
355 2 : continue;
356 : }
357 2 : AddrSetIP(&addr, cna);
358 2 : char port[MAX_PORT_LEN] = {0};
359 2 : int ret = sprintf_s(port, MAX_PORT_LEN, "%s", ueInfo->ports);
360 2 : if (ret < 0) {
361 0 : break;
362 : }
363 2 : AddrAddPort(&addr, port);
364 2 : result = 0;
365 : }
366 2 : char planeId[MAX_PLANE_ID_LEN] = {0};
367 2 : int ret = sprintf_s(planeId, sizeof(planeId), "plane_uboe");
368 2 : if (ret < 0) {
369 0 : return -1;
370 : }
371 2 : AddrSetPlaneId(&addr, planeId);
372 2 : NetLayerAddAddr(layer, &addr);
373 2 : return result;
374 : }
375 :
376 : /**
377 : * @brief 根据dieId和feId从UEList中获取UBEntity
378 : * @param ueList: ue entity列表
379 : * @param dieId: die id
380 : * @param ueId: ue id
381 : * @param type: UB类型
382 : * @return UBEntity*: ue entity
383 : */
384 369 : static const UBEntity* GetUBEntityByFilter(const UEList* ueList, int dieId, int ueId, int type)
385 : {
386 369 : if (type == UE_TYPE_UBOE) {
387 79 : for (unsigned int i = 0; i < ueList->ueNum; i++) {
388 14 : if (UrmaEidIsUBOE(&ueList->ueList[i].eidList[0].eid)) {
389 2 : return &ueList->ueList[i];
390 : }
391 : }
392 65 : return NULL;
393 : }
394 302 : if (type == UE_TYPE_UB_RTP) {
395 0 : for (unsigned int i = 0; i < ueList->ueNum; i++) {
396 0 : if (UrmaEidIsUbRtp(&ueList->ueList[i].eidList[0].eid)) {
397 0 : return &ueList->ueList[i];
398 : }
399 : }
400 0 : return NULL;
401 : }
402 302 : int maxFe = 0;
403 302 : const UBEntity* ubEntity = NULL;
404 331 : for (unsigned int i = 0; i < ueList->ueNum; i++) {
405 38 : if (UrmaEidIsUBOE(&ueList->ueList[i].eidList[0].eid)) {
406 4 : continue;
407 : }
408 34 : int die = UrmaEidGetDieId(&ueList->ueList[i].eidList[0].eid);
409 34 : int fe = UBEntityGetId(&ueList->ueList[i]);
410 34 : if (die == dieId && fe == ueId) { // MAX_UE_ID足够大,这里不会匹配到
411 9 : return &ueList->ueList[i];
412 : }
413 : // 获取本iodie上UBEntity ID最大的UB Entity
414 25 : if (die == dieId && fe > maxFe) {
415 15 : maxFe = fe;
416 15 : ubEntity = &ueList->ueList[i];
417 : }
418 : }
419 293 : if (ueId == MAX_UE_ID) {
420 133 : return ubEntity;
421 : }
422 160 : return NULL;
423 : }
424 :
425 : /**
426 : * @brief 根据配置从ueList中过滤出ub entity, 并处理其中的地址添加到netlayer中
427 : * @param layer: 网络层信息
428 : * @param ueList: 全量的ue entity数组
429 : * @param levelInfo: 当前处理的层级信息
430 : * @param spodInfo: spod信息
431 : * @return int: 0 成功
432 : */
433 466 : static int ProcessLayer(
434 : int npuId, NetLayer* layer, UEList* ueList, const LevelInfo* levelInfo, const struct dcmi_spod_info* spodInfo)
435 : {
436 : /* RoCE 层(level 3)走独立路径,不查 UEList */
437 466 : if (levelInfo->level == 3) {
438 166 : return ProcessLayerRoce(npuId, layer);
439 : }
440 :
441 300 : char net_instance_id[MAX_INSTANCE_ID_LEN] = {0};
442 300 : levelInfo->instanceIdFunc(npuId, spodInfo, net_instance_id, sizeof(net_instance_id));
443 300 : NetLayerInit(layer, levelInfo->level, net_instance_id);
444 300 : NetLayerSetNetType(layer, levelInfo->netType);
445 :
446 300 : int ret = -1;
447 669 : for (int i = 0; i < levelInfo->ueNum; ++i) {
448 369 : int fe = levelInfo->ueList[i].feId;
449 369 : int die = levelInfo->ueList[i].dieId;
450 369 : int type = levelInfo->ueList[i].type;
451 369 : const UBEntity* ue = GetUBEntityByFilter(ueList, die, fe, type);
452 369 : if (ue == NULL) {
453 353 : continue;
454 : }
455 16 : if (type == UE_TYPE_MESH || type == UE_TYPE_CLOS_PORTS) {
456 9 : ret = LayerAddMesh(ue, layer, type);
457 7 : } else if (type == UE_TYPE_CLOS) {
458 5 : ret = LayerAddClos(ue, layer);
459 2 : } else if (type == UE_TYPE_UBOE) {
460 2 : ret = LayerAddUBOE(ue, &levelInfo->ueList[i], layer);
461 : }
462 : }
463 300 : return ret;
464 : }
465 :
466 166 : int ServerGetRootinfo(int npu_id, unsigned mainboard_id, void* buf, size_t* len)
467 : {
468 166 : if (buf == NULL || len == NULL) {
469 0 : return RET_NOK;
470 : }
471 : struct dcmi_spod_info spod_info;
472 : UEList ueList;
473 166 : HalGetUBEntityList(npu_id, &ueList);
474 166 : hal_get_spod_info(npu_id, &spod_info);
475 :
476 : RootInfo rootinfo;
477 : Rank rank;
478 166 : RootInfoInit(&rootinfo);
479 166 : int localId = npu_id;
480 166 : if (spod_info.super_pod_type == TOPO_TYPE_SERVER_16FM) {
481 1 : localId = npu_id + (spod_info.server_index * SERVER_NPU_NUM);
482 : }
483 166 : RankInit(&rank, npu_id, localId);
484 166 : TopoGetFilePath(mainboard_id, spod_info.super_pod_type, rootinfo.topo_file_path, MAX_TOPO_PATH_LEN);
485 :
486 166 : const NetInfo* netInfo = GetNetInfo(mainboard_id, spod_info.super_pod_type);
487 166 : if (netInfo == NULL) {
488 0 : return -1;
489 : }
490 :
491 632 : for (int i = 0; i < netInfo->levelNum; ++i) {
492 : NetLayer layer;
493 466 : if (ProcessLayer(npu_id, &layer, &ueList, &netInfo->levelInfos[i], &spod_info) == 0) {
494 121 : RankAddNetLayer(&rank, &layer);
495 : }
496 : }
497 :
498 166 : RootInfoAddRank(&rootinfo, &rank);
499 166 : char* rootinfo_buf = RootInfoToString(&rootinfo);
500 166 : if (rootinfo_buf == NULL) {
501 0 : return -1;
502 : }
503 166 : if ((*len) < strlen(rootinfo_buf)) {
504 0 : (*len) = strlen(rootinfo_buf);
505 0 : free(rootinfo_buf);
506 0 : return -1;
507 : }
508 166 : errno_t ret = strcpy_s(buf, *len, rootinfo_buf);
509 166 : (*len) = strlen(buf);
510 166 : free(rootinfo_buf);
511 166 : return ret;
512 : }
|