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