LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/topo/topo_addr_info/src - npu_nic_affinity.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.5 % 304 263
Test Date: 2026-07-28 12:11:00 Functions: 100.0 % 20 20

            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 "npu_nic_affinity.h"
      12              : #include "xml_parser.h"
      13              : 
      14              : #include <arpa/inet.h>
      15              : #include <dirent.h>
      16              : #include <ifaddrs.h>
      17              : #include <stdlib.h>
      18              : #include <string.h>
      19              : #include <stdbool.h>
      20              : #include <sys/socket.h>
      21              : 
      22              : #include "hal.h"
      23              : #include "securec.h"
      24              : #include "topo_addr_info_log.h"
      25              : #include "topo_addr_info_perf.h"
      26              : 
      27              : /* ───────── 常量 ───────── */
      28              : #ifndef XML_PATH
      29              : #define XML_PATH "/var/run/ascend-topologyd/virtualTopology.xml"
      30              : #endif
      31              : #ifndef HCA_NET_PATH_TEMPLATE
      32              : #define HCA_NET_PATH_TEMPLATE "/sys/class/infiniband/%s/device/net"
      33              : #endif
      34              : #define MAX_PATH_LEN 512
      35              : #define MAX_GROUP_CNT 16
      36              : #define MAX_HCA_COUNT 64
      37              : #define MAX_NAME_LEN 64
      38              : #define MAX_IP_STR_LEN 48
      39              : 
      40              : /* ───────── 业务结构 ───────── */
      41              : typedef struct {
      42              :     int npuIds[MAX_NPU_COUNT];
      43              :     unsigned int npuCnt;
      44              :     unsigned int nicIdx[MAX_HCA_COUNT];
      45              :     unsigned int nicCnt;
      46              : } AffinityGroup;
      47              : 
      48              : typedef struct {
      49              :     char nicNames[MAX_HCA_COUNT][MAX_NAME_LEN];
      50              :     unsigned int nicCount;
      51              :     AffinityGroup groups[MAX_GROUP_CNT];
      52              :     unsigned int groupCount;
      53              :     bool affined[MAX_NPU_COUNT][MAX_HCA_COUNT]; /* groups 展开后的 NPU×NIC 亲和矩阵 */
      54              : } XmlInfo;
      55              : 
      56        12728 : static bool TagIs(const TagEntry *e, const char *name)
      57              : {
      58        12728 :     return strcmp(e->tagName, name) == 0;
      59              : }
      60              : 
      61              : /* ─── 硬件枚举 ─── */
      62              : 
      63          384 : static void BuildNpuBdfTable(char bdfs[MAX_NPU_COUNT][MAX_NAME_LEN])
      64              : {
      65          384 :     int npuCnt = hal_get_npu_count();
      66          384 :     if (npuCnt <= 0 || npuCnt > (int)MAX_NPU_COUNT) {
      67            0 :         TOPO_ERR("BuildNpuBdfTable: invalid npuCnt=%d", npuCnt);
      68            0 :         return;
      69              :     }
      70         3245 :     for (int phyId = 0; phyId < npuCnt; phyId++) {
      71              :         struct dcmi_pcie_info_all pcieInfo;
      72         2861 :         if (hal_get_device_pcie_info(phyId, &pcieInfo) == 0) {
      73         1018 :             (void)sprintf_s(bdfs[phyId], MAX_NAME_LEN, "%04x:%02x:%02x.%x", pcieInfo.domain, pcieInfo.bdf_busid,
      74              :                 pcieInfo.bdf_deviceid, pcieInfo.bdf_funcid);
      75              :         } else {
      76         1843 :             bdfs[phyId][0] = '\0';
      77              :         }
      78              :     }
      79              : }
      80              : 
      81              : /* ─── 亲和分组构建 ─── */
      82              : 
      83         1256 : static void TryAddNpuByBdf(
      84              :     const TagEntry *e, unsigned int curGroupIdx, const char npuBdfs[MAX_NPU_COUNT][MAX_NAME_LEN], XmlInfo *info)
      85              : {
      86         1256 :     const char *busId = TagFindAttr(e, "busid");
      87         1256 :     if (busId == NULL || busId[0] == '\0') {
      88            2 :         return;
      89              :     }
      90         1254 :     if (curGroupIdx >= MAX_GROUP_CNT) {
      91            0 :         return;
      92              :     }
      93              : 
      94              :     /* 遍历所有 NPU 的 BDF 表,找与 busId 匹配的那个 NPU */
      95         1254 :     int npuCount = hal_get_npu_count();
      96         1254 :     unsigned int tableSize = (npuCount <= 0) ? 0 : (unsigned int)npuCount;
      97         1254 :     if (tableSize > MAX_NPU_COUNT) {
      98            0 :         tableSize = MAX_NPU_COUNT;
      99              :     }
     100         6489 :     for (unsigned int npuIdx = 0; npuIdx < tableSize; npuIdx++) {
     101         6253 :         if (npuBdfs[npuIdx][0] == '\0') {
     102         1058 :             continue;
     103              :         }
     104         5195 :         if (strcmp(busId, npuBdfs[npuIdx]) != 0) {
     105         4177 :             continue;
     106              :         }
     107              : 
     108              :         /* busId 匹配 → 将 NPU[npuIdx] 加入亲和组 */
     109         1018 :         AffinityGroup *group = &info->groups[curGroupIdx];
     110         1018 :         unsigned int groupCnt = group->npuCnt;
     111         1018 :         if (groupCnt > MAX_NPU_COUNT) {
     112            0 :             groupCnt = MAX_NPU_COUNT;
     113              :         }
     114              : 
     115              :         /* 检查该 NPU 是否已在组内,避免重复占用槽位 */
     116         1018 :         bool alreadyInGroup = false;
     117         3594 :         for (unsigned int existIdx = 0; existIdx < groupCnt; existIdx++) {
     118         2577 :             if (group->npuIds[existIdx] == (int)npuIdx) {
     119            1 :                 alreadyInGroup = true;
     120            1 :                 break;
     121              :             }
     122              :         }
     123         1018 :         if (!alreadyInGroup && groupCnt < MAX_NPU_COUNT) {
     124         1017 :             group->npuIds[groupCnt] = (int)npuIdx;
     125         1017 :             group->npuCnt = groupCnt + 1;
     126              :         }
     127         1018 :         break;
     128              :     }
     129              : }
     130              : 
     131              : /* ─── 分组上下文,降低标签处理器的参数传递 ─── */
     132              : typedef struct {
     133              :     const char (*npuBdfs)[MAX_NAME_LEN];
     134              :     XmlInfo *info;
     135              :     unsigned int *curGroupIdx;
     136              :     unsigned int *groupCount;
     137              :     unsigned int *nicCount;
     138              :     bool *inGroup;
     139              :     int *containerDepth;
     140              : } GroupCtx;
     141              : 
     142          670 : static void GroupEnterOrSkip(GroupCtx *ctx, int depth)
     143              : {
     144          670 :     if (*ctx->inGroup && depth <= *ctx->containerDepth) {
     145           85 :         *ctx->inGroup = false;
     146              :     }
     147          670 :     if (!*ctx->inGroup && *ctx->groupCount < MAX_GROUP_CNT) {
     148          469 :         *ctx->curGroupIdx = *ctx->groupCount;
     149          469 :         (*ctx->groupCount)++;
     150          469 :         *ctx->containerDepth = depth;
     151          469 :         *ctx->inGroup = true;
     152              :     }
     153          670 : }
     154              : 
     155         1256 : static void HandlePciTag(const TagEntry *e, GroupCtx *ctx)
     156              : {
     157         1256 :     if (!e->isSelfClose) {
     158          239 :         GroupEnterOrSkip(ctx, e->depth);
     159          239 :         if (*ctx->inGroup) {
     160          239 :             TryAddNpuByBdf(e, *ctx->curGroupIdx, ctx->npuBdfs, ctx->info);
     161              :         }
     162          239 :         return;
     163              :     }
     164         1017 :     if (*ctx->inGroup) {
     165         1017 :         TryAddNpuByBdf(e, *ctx->curGroupIdx, ctx->npuBdfs, ctx->info);
     166              :     }
     167              : }
     168              : 
     169          431 : static void HandleUbTag(const TagEntry *e, GroupCtx *ctx)
     170              : {
     171          431 :     if (!e->isSelfClose) {
     172          431 :         GroupEnterOrSkip(ctx, e->depth);
     173              :     }
     174          431 : }
     175              : 
     176          986 : static void HandleNpuTag(const TagEntry *e, GroupCtx *ctx)
     177              : {
     178          986 :     if (!*ctx->inGroup) {
     179           11 :         return;
     180              :     }
     181          986 :     const char *chipId = TagFindAttr(e, "chipphyid");
     182          986 :     if (chipId == NULL) {
     183            0 :         return;
     184              :     }
     185          986 :     int phyId = atoi(chipId);
     186          986 :     if (phyId < 0 || phyId >= (int)MAX_NPU_COUNT) {
     187            0 :         return;
     188              :     }
     189              :     /* 跳过当前进程不可见的设备 */
     190          986 :     int userDevId = -1;
     191          986 :     if (hal_get_userdevid_by_phyid(phyId, &userDevId) != 0) {
     192           10 :         return;
     193              :     }
     194          976 :     XmlInfo *info = ctx->info;
     195          976 :     if (info == NULL) {
     196            0 :         return;
     197              :     }
     198              : 
     199          976 :     unsigned int gIdx = *ctx->curGroupIdx;
     200          976 :     if (gIdx >= MAX_GROUP_CNT) {
     201            0 :         TOPO_ERR("HandleNpuTag: group index overflow, gIdx=%u >= MAX_GROUP_CNT=%d", gIdx, MAX_GROUP_CNT);
     202            0 :         return;
     203              :     }
     204              : 
     205              :     /* 去重:同组已有该 phyId 则跳过,防止重复占用 npuIds 槽位 */
     206          976 :     AffinityGroup *group = &info->groups[gIdx];
     207          976 :     unsigned int groupNpuCnt = group->npuCnt;
     208          976 :     if (groupNpuCnt > MAX_NPU_COUNT) {
     209            0 :         groupNpuCnt = MAX_NPU_COUNT;
     210              :     }
     211         3478 :     for (unsigned int existIdx = 0; existIdx < groupNpuCnt; existIdx++) {
     212         2503 :         if (group->npuIds[existIdx] == phyId) {
     213            1 :             return;
     214              :         }
     215              :     }
     216          975 :     if (groupNpuCnt < MAX_NPU_COUNT) {
     217          975 :         group->npuIds[groupNpuCnt] = phyId;
     218          975 :         group->npuCnt = groupNpuCnt + 1;
     219              :     }
     220              : }
     221              : 
     222              : /* 将 NIC 名去重加入 info,返回 TOPO_SUCCESS 并通过 nicIdx 输出索引 */
     223          563 : static TopoAddrResult DedupNetNic(XmlInfo *info, const char *name,
     224              :                                    unsigned int *nicCount, unsigned int *nicIdx)
     225              : {
     226          563 :     unsigned int curCnt = *nicCount;
     227          563 :     if (curCnt > MAX_HCA_COUNT) {
     228            0 :         curCnt = MAX_HCA_COUNT;
     229              :     }
     230          563 :     unsigned int idx = 0;
     231         1148 :     for (; idx < curCnt; idx++) {
     232          665 :         if (strcmp(info->nicNames[idx], name) == 0) {
     233           80 :             *nicIdx = idx;
     234           80 :             return TOPO_SUCCESS;
     235              :         }
     236              :     }
     237          483 :     if (idx >= MAX_HCA_COUNT) {
     238            0 :         TOPO_ERR("DedupNetNic: NIC count overflow, name=%s", name);
     239            0 :         return TOPO_ERR_INTERNAL;
     240              :     }
     241          483 :     if (strcpy_s(info->nicNames[idx], sizeof(info->nicNames[0]), name) != 0) {
     242            0 :         return TOPO_ERR_INTERNAL;
     243              :     }
     244          483 :     (*nicCount)++;
     245          483 :     *nicIdx = idx;
     246          483 :     return TOPO_SUCCESS;
     247              : }
     248              : 
     249          563 : static void HandleNetTag(const TagEntry *e, GroupCtx *ctx)
     250              : {
     251          563 :     if (!*ctx->inGroup) {
     252            0 :         return;
     253              :     }
     254          563 :     const char *name = TagFindAttr(e, "name");
     255          563 :     if (name == NULL) {
     256            0 :         return;
     257              :     }
     258          563 :     XmlInfo *info = ctx->info;
     259          563 :     if (info == NULL) {
     260            0 :         return;
     261              :     }
     262              : 
     263              :     unsigned int nicIdx;
     264          563 :     if (DedupNetNic(info, name, ctx->nicCount, &nicIdx) != TOPO_SUCCESS) {
     265            0 :         return;
     266              :     }
     267              : 
     268          563 :     unsigned int gIdx = *ctx->curGroupIdx;
     269          563 :     if (gIdx >= MAX_GROUP_CNT) {
     270            0 :         TOPO_ERR("HandleNetTag: group index overflow, gIdx=%u >= MAX_GROUP_CNT=%d", gIdx, MAX_GROUP_CNT);
     271            0 :         return;
     272              :     }
     273          563 :     AffinityGroup *group = &info->groups[gIdx];
     274              :     /* 组内去重:同名 NIC 只加入一次,避免重复占用 nicIdx 槽位 */
     275          563 :     unsigned int groupNicCnt = group->nicCnt;
     276          563 :     if (groupNicCnt > MAX_HCA_COUNT) {
     277            0 :         groupNicCnt = MAX_HCA_COUNT;
     278              :     }
     279          660 :     for (unsigned int existIdx = 0; existIdx < groupNicCnt; existIdx++) {
     280           97 :         if (group->nicIdx[existIdx] == nicIdx) {
     281            0 :             return;
     282              :         }
     283              :     }
     284          563 :     if (groupNicCnt < MAX_HCA_COUNT) {
     285          563 :         group->nicIdx[groupNicCnt] = nicIdx;
     286          563 :         group->nicCnt = groupNicCnt + 1;
     287              :     }
     288              : }
     289              : 
     290              : /* 将 AffinityGroup 展开为 affined 二维矩阵,供 O(1) 亲和查询 */
     291          384 : static void BuildAffinityMatrix(XmlInfo *info)
     292              : {
     293          384 :     TOPO_PERF_BEGIN(BuildAffinityMatrix);
     294          384 :     unsigned int groupCnt = info->groupCount;
     295          384 :     if (groupCnt > MAX_GROUP_CNT) {
     296            0 :         groupCnt = MAX_GROUP_CNT;
     297              :     }
     298              : 
     299          853 :     for (unsigned int g = 0; g < groupCnt; g++) {
     300          469 :         unsigned int npuCnt = info->groups[g].npuCnt;
     301          469 :         if (npuCnt > MAX_NPU_COUNT) {
     302            0 :             npuCnt = MAX_NPU_COUNT;
     303              :         }
     304          469 :         unsigned int nicCnt = info->groups[g].nicCnt;
     305          469 :         if (nicCnt > MAX_HCA_COUNT) {
     306            0 :             nicCnt = MAX_HCA_COUNT;
     307              :         }
     308         2461 :         for (unsigned int ni = 0; ni < npuCnt; ni++) {
     309         1992 :             int npuId = info->groups[g].npuIds[ni];
     310         1992 :             if (npuId < 0 || npuId >= (int)MAX_NPU_COUNT) {
     311            0 :                 continue;
     312              :             }
     313         4110 :             for (unsigned int nci = 0; nci < nicCnt; nci++) {
     314         2118 :                 unsigned int nicIdx = info->groups[g].nicIdx[nci];
     315         2118 :                 if (nicIdx < MAX_HCA_COUNT) {
     316         2118 :                     info->affined[(unsigned int)npuId][nicIdx] = true;
     317              :                 }
     318              :             }
     319              :         }
     320              :     }
     321          384 :     TOPO_PERF_END(BuildAffinityMatrix);
     322          384 : }
     323              : 
     324          384 : static TopoAddrResult BuildAffinityGroups(const TagEntry *tags, unsigned int tagCount, XmlInfo *info)
     325              : {
     326          384 :     char npuBdfs[MAX_NPU_COUNT][MAX_NAME_LEN] = {{0}};
     327          384 :     BuildNpuBdfTable(npuBdfs);
     328          384 :     (void)memset_s(info, sizeof(*info), 0, sizeof(*info));
     329              : 
     330          384 :     unsigned int curGroupIdx = 0;
     331          384 :     unsigned int groupCount = 0;
     332          384 :     unsigned int nicCount = 0;
     333          384 :     bool inGroup = false;
     334          384 :     int containerDepth = -1;
     335              : 
     336          384 :     GroupCtx ctx = {
     337              :         .npuBdfs = (const char (*)[MAX_NAME_LEN])npuBdfs,
     338              :         .info = info,
     339              :         .curGroupIdx = &curGroupIdx,
     340              :         .groupCount = &groupCount,
     341              :         .nicCount = &nicCount,
     342              :         .inGroup = &inGroup,
     343              :         .containerDepth = &containerDepth,
     344              :     };
     345              : 
     346         4970 :     for (unsigned int i = 0; i < tagCount; i++) {
     347         4586 :         const TagEntry *e = &tags[i];
     348              : 
     349         4586 :         if (TagIs(e, "pci")) {
     350         1256 :             HandlePciTag(e, &ctx);
     351         1256 :             continue;
     352              :         }
     353         3330 :         if (TagIs(e, "ub")) {
     354          431 :             HandleUbTag(e, &ctx);
     355          431 :             continue;
     356              :         }
     357         2899 :         if (TagIs(e, "npu")) {
     358          986 :             HandleNpuTag(e, &ctx);
     359          986 :             continue;
     360              :         }
     361         1913 :         if (TagIs(e, "net")) {
     362          563 :             HandleNetTag(e, &ctx);
     363          563 :             continue;
     364              :         }
     365              :     }
     366              : 
     367          384 :     info->groupCount = groupCount;
     368          384 :     info->nicCount = nicCount;
     369              : 
     370          384 :     BuildAffinityMatrix(info);
     371              : 
     372          384 :     if (nicCount == 0) {
     373            3 :         TOPO_ERR("no NICs found in XML, cannot build affinity groups");
     374            3 :         return TOPO_ERR_NOT_FOUND;
     375              :     }
     376          381 :     return TOPO_SUCCESS;
     377              : }
     378              : 
     379              : /* ─── 合成:ParseXml = ParseXmlTags + BuildAffinityGroups ─── */
     380              : 
     381          396 : static TopoAddrResult ParseXml(XmlInfo *info)
     382              : {
     383              :     TagEntry tags[MAX_TAG_ENTRIES];
     384          396 :     unsigned int tagCount = 0;
     385          396 :     TopoAddrResult ret = ParseXmlTags(XML_PATH, tags, &tagCount, MAX_TAG_ENTRIES);
     386          396 :     if (ret != TOPO_SUCCESS) {
     387           12 :         return ret;
     388              :     }
     389          384 :     return BuildAffinityGroups(tags, tagCount, info);
     390              : }
     391              : 
     392              : /* ─── 打印 NPU → 网卡名 → IP 分配结果 ─── */
     393          381 : static void LogAssignResult(const XmlInfo *info, int npuCount, const bool nicValid[MAX_HCA_COUNT],
     394              :     const char nicIps[][MAX_IP_STR_LEN], const char assignment[][MAX_IP_STR_LEN])
     395              : {
     396         3238 :     for (int ni = 0; ni < npuCount; ni++) {
     397         2857 :         if (assignment[ni][0] == '\0') {
     398          876 :             continue;
     399              :         }
     400              :         /* 反向查找该 IP 对应的 NIC 名 */
     401         1981 :         const char *nicName = NULL;
     402         2334 :         for (unsigned int j = 0; j < info->nicCount; j++) {
     403         2334 :             if (nicValid[j] && strcmp(assignment[ni], nicIps[j]) == 0) {
     404         1981 :                 nicName = info->nicNames[j];
     405         1981 :                 break;
     406              :             }
     407              :         }
     408         1981 :         TOPO_INFO("NPU %d → %s (%s)", ni, assignment[ni], nicName ? nicName : "?");
     409              :     }
     410          381 : }
     411              : 
     412              : /* ─── 轮询分发全量 NPU 的 RoCE IP ─── */
     413              : 
     414          381 : static TopoAddrResult DispatchIpsRoundRobin(int phyId, const XmlInfo *info, const bool nicValid[MAX_HCA_COUNT],
     415              :     const char nicIps[][MAX_IP_STR_LEN], char *outIp, size_t outLen)
     416              : {
     417          381 :     if (phyId < 0 || phyId >= (int)MAX_NPU_COUNT) {
     418            0 :         TOPO_ERR("DispatchIpsRoundRobin: invalid phyId=%d", phyId);
     419            0 :         return TOPO_ERR_PARA;
     420              :     }
     421          381 :     int npuCount = hal_get_npu_count();
     422          381 :     if (npuCount <= 0 || npuCount > (int)MAX_NPU_COUNT) {
     423            0 :         TOPO_ERR("DispatchIpsRoundRobin: invalid npuCount=%d", npuCount);
     424            0 :         return TOPO_ERR_INTERNAL;
     425              :     }
     426          381 :     unsigned int nicCount = info->nicCount;
     427          381 :     if (nicCount == 0 || nicCount > MAX_HCA_COUNT) {
     428            0 :         TOPO_ERR("DispatchIpsRoundRobin: invalid nicCount=%u", nicCount);
     429            0 :         return TOPO_ERR_INTERNAL;
     430              :     }
     431              : 
     432              :     char assignment[MAX_NPU_COUNT][MAX_IP_STR_LEN];
     433          381 :     (void)memset_s(assignment, sizeof(assignment), 0, sizeof(assignment));
     434              : 
     435          381 :     unsigned int cur = 0;
     436         3238 :     for (int npuId = 0; npuId < npuCount; npuId++) {
     437         3802 :         for (unsigned int j = cur; j < cur + nicCount; j++) {
     438         2926 :             unsigned int nicIdx = j % nicCount;
     439         2926 :             if (!nicValid[nicIdx] || !info->affined[npuId][nicIdx]) {
     440          945 :                 continue;
     441              :             }
     442         1981 :             if (strcpy_s(assignment[npuId], sizeof(assignment[0]), nicIps[nicIdx]) != 0) {
     443            0 :                 continue;
     444              :             }
     445         1981 :             cur = (j + 1) % nicCount;
     446         1981 :             break;
     447              :         }
     448              :     }
     449              : 
     450          381 :     LogAssignResult(info, npuCount, nicValid, nicIps, assignment);
     451              : 
     452          381 :     if (assignment[phyId][0] != '\0') {
     453          265 :         return strcpy_s(outIp, outLen, assignment[phyId]);
     454              :     }
     455          116 :     TOPO_ERR("no IP assigned for phyId=%d", phyId);
     456          116 :     return TOPO_ERR_NOT_FOUND;
     457              : }
     458              : 
     459              : /* ─── 名称 → IP 转换 ─── */
     460              : 
     461              : /* 直接以 eth 名查 IP */
     462          845 : static TopoAddrResult EthToIp(const char *eth, char *ip, size_t ipLen)
     463              : {
     464          845 :     struct ifaddrs *ifaddr = NULL;
     465          845 :     if (getifaddrs(&ifaddr) == -1) {
     466            0 :         return TOPO_ERR_SYSCALL;
     467              :     }
     468              : 
     469         1557 :     for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
     470         1188 :         if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL) {
     471            1 :             continue;
     472              :         }
     473         1187 :         if (strcmp(ifa->ifa_name, eth) != 0) {
     474          710 :             continue;
     475              :         }
     476          477 :         if (ifa->ifa_addr->sa_family != AF_INET) {
     477            1 :             continue;
     478              :         }
     479          476 :         struct sockaddr_in *sin = (struct sockaddr_in *)ifa->ifa_addr;
     480          476 :         if (inet_ntop(AF_INET, &sin->sin_addr, ip, (socklen_t)ipLen) != NULL) {
     481          476 :             freeifaddrs(ifaddr);
     482          476 :             return TOPO_SUCCESS;
     483              :         }
     484              :     }
     485          369 :     freeifaddrs(ifaddr);
     486          369 :     return TOPO_ERR_NOT_FOUND;
     487              : }
     488              : 
     489              : /* 以 HCA 名查 IP:/sys/class/infiniband/<hca>/device/net/<eth> */
     490          368 : static TopoAddrResult HcaToIp(const char *hca, char *ip, size_t ipLen)
     491              : {
     492              :     char netPath[MAX_PATH_LEN];
     493          368 :     if (sprintf_s(netPath, sizeof(netPath), HCA_NET_PATH_TEMPLATE, hca) < 0) {
     494            0 :         return TOPO_ERR_INTERNAL;
     495              :     }
     496              : 
     497          368 :     DIR *dir = opendir(netPath);
     498          368 :     if (dir == NULL) {
     499            5 :         return TOPO_ERR_NOT_FOUND;
     500              :     }
     501              : 
     502          363 :     char eth[MAX_NAME_LEN] = {0};
     503          363 :     struct dirent *entry = NULL;
     504          365 :     while ((entry = readdir(dir)) != NULL) {
     505          364 :         if (entry->d_name[0] == '.') {
     506            2 :             continue;
     507              :         }
     508          362 :         (void)strncpy_s(eth, sizeof(eth), entry->d_name, sizeof(eth) - 1);
     509          362 :         break;
     510              :     }
     511          363 :     closedir(dir);
     512              : 
     513          363 :     if (eth[0] == '\0') {
     514            1 :         return TOPO_ERR_NOT_FOUND;
     515              :     }
     516              : 
     517          362 :     return EthToIp(eth, ip, ipLen);
     518              : }
     519              : 
     520              : /* name 可能是 eth 名或 HCA 名:先尝试 eth,再尝试 HCA */
     521          483 : static TopoAddrResult NameToIp(const char *name, char *ip, size_t ipLen)
     522              : {
     523          483 :     if (EthToIp(name, ip, ipLen) == TOPO_SUCCESS) {
     524          115 :         return TOPO_SUCCESS;
     525              :     }
     526          368 :     TopoAddrResult ret = HcaToIp(name, ip, ipLen);
     527          368 :     if (ret != TOPO_SUCCESS) {
     528            7 :         TOPO_ERR("NameToIp: cannot resolve IP for %s (eth+HCA)", name);
     529              :     }
     530          368 :     return ret;
     531              : }
     532              : 
     533              : /* ─── 打印 NPU-NIC 亲和关系(NIC 名 + IP) ─── */
     534              : 
     535          381 : static void LogAffinityInfo(const XmlInfo *info, const char nicIps[][MAX_IP_STR_LEN])
     536              : {
     537          381 :     unsigned int nicCnt = info->nicCount;
     538          381 :     if (nicCnt > MAX_HCA_COUNT) {
     539            0 :         nicCnt = MAX_HCA_COUNT;
     540              :     }
     541          381 :     int npuCount = hal_get_npu_count();
     542          381 :     if (npuCount <= 0 || npuCount > (int)MAX_NPU_COUNT) {
     543            0 :         return;
     544              :     }
     545         3238 :     for (int npuId = 0; npuId < npuCount; npuId++) {
     546         6539 :         for (unsigned int nicIdx = 0; nicIdx < nicCnt; nicIdx++) {
     547         3682 :             if (info->affined[npuId][nicIdx]) {
     548         2118 :                 TOPO_INFO("[affinity] NPU%d <- %s(%s)", npuId, info->nicNames[nicIdx],
     549              :                     (nicIps[nicIdx][0] != '\0') ? nicIps[nicIdx] : "?");
     550              :             }
     551              :         }
     552              :     }
     553              : }
     554              : 
     555              : /* ─── 预解析全部 NIC 的 IP → 调用轮询分发 → 直接出 IP ─── */
     556              : 
     557          381 : static TopoAddrResult SelectNpuRoceIp(int npuId, const XmlInfo *info, char *ip, size_t ipLen)
     558              : {
     559          381 :     unsigned int nicCnt = info->nicCount;
     560          381 :     if (nicCnt > MAX_HCA_COUNT) {
     561            0 :         nicCnt = MAX_HCA_COUNT;
     562              :     }
     563              : 
     564          381 :     char nicIps[MAX_HCA_COUNT][MAX_IP_STR_LEN] = {{0}};
     565          381 :     bool nicValid[MAX_HCA_COUNT] = {false};
     566          864 :     for (unsigned int i = 0; i < nicCnt; i++) {
     567          483 :         if (NameToIp(info->nicNames[i], nicIps[i], sizeof(nicIps[i])) == TOPO_SUCCESS) {
     568          476 :             nicValid[i] = true;
     569              :         }
     570              :     }
     571          381 :     LogAffinityInfo(info, nicIps);
     572          381 :     return DispatchIpsRoundRobin(npuId, info, nicValid, nicIps, ip, ipLen);
     573              : }
     574              : 
     575              : /* ─── 对外接口 ─── */
     576              : 
     577          398 : TopoAddrResult GetRoceIpFromXml(int npuId, char *ip, size_t ipLen)
     578              : {
     579          398 :     if (ip == NULL || ipLen == 0 || npuId < 0) {
     580            2 :         TOPO_ERR("GetRoceIpFromXml: invalid params (ip=%p, ipLen=%zu, npuId=%d)", ip, ipLen, npuId);
     581            2 :         return TOPO_ERR_PARA;
     582              :     }
     583              : 
     584              :     /* 解析 XML,构建 NPU-NIC 亲和分组 */
     585              :     XmlInfo info;
     586          396 :     (void)memset_s(&info, sizeof(info), 0, sizeof(info));
     587          396 :     TopoAddrResult ret = ParseXml(&info);
     588          396 :     if (ret != TOPO_SUCCESS) {
     589           15 :         return ret;
     590              :     }
     591              : 
     592              :     /* XML 中无 NIC 定义 */
     593          381 :     if (info.nicCount == 0) {
     594            0 :         TOPO_ERR("GetRoceIpFromXml: no NICs in XML for npuId=%d", npuId);
     595            0 :         return TOPO_ERR_NOT_FOUND;
     596              :     }
     597              : 
     598              :     /* 从所有 NIC 中轮询选出当前 NPU 的 RoCE IP */
     599          381 :     return SelectNpuRoceIp(npuId, &info, ip, ipLen);
     600              : }
        

Generated by: LCOV version 2.0-1