Line data Source code
1 : /**
2 : * Copyright (c) 2025 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 "bootstrap_ip.h"
12 : #include <mutex>
13 : #include <algorithm>
14 : #include "whitelist.h"
15 : #include "env_config/env_config_v2.h"
16 : #include "exception_util.h"
17 : #include "adapter_error_manager_pub.h"
18 :
19 : namespace Hccl {
20 :
21 : static UniversalConcurrentMap<u32, IpAddress> bootstrapIps; // <devPhyId, ip>
22 :
23 0 : std::vector<IpAddress> GetHostSocketWhitelist()
24 : {
25 0 : std::vector<IpAddress> hostSocketWhitelist{};
26 :
27 : // 文件路径在g_externalInput.hcclWhiteList已经做过合法性判断, 无需再次校验
28 0 : std::string fileName = EnvConfig::GetInstance().GetHostNicConfig().GetWhiteListFile();
29 0 : CHK_PRT_THROW(
30 : fileName.empty(),
31 : HCCL_ERROR(
32 : "[%s] HCCL_WHITELIST_DISABLE variable is [0],but "
33 : "HCCL_WHITELIST_FILE is not set",
34 : __func__),
35 : InternalException, "whiteList file name empty");
36 :
37 0 : Whitelist::GetInstance().LoadConfigFile(fileName);
38 0 : Whitelist::GetInstance().GetHostWhiteList(hostSocketWhitelist);
39 0 : CHK_PRT_THROW(
40 : hostSocketWhitelist.empty(),
41 : HCCL_ERROR("[%s] whitelist file[%s] have no valid host ip.", __func__, fileName.c_str()), InternalException,
42 : "whiteList invalid");
43 :
44 0 : HCCL_INFO(
45 : "[%s] get host socket whitelist success. there are %zu host ip in the whitelist.", __func__,
46 : hostSocketWhitelist.size());
47 0 : return hostSocketWhitelist;
48 0 : }
49 :
50 8 : void GetAllValidHostIfInfos(
51 : const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos,
52 : vector<std::pair<std::string, IpAddress>>& ifInfos)
53 : {
54 8 : if (!EnvConfig::GetInstance().GetHostNicConfig().GetWhitelistDisable()) {
55 5 : auto whitelist = GetHostSocketWhitelist();
56 10 : for (auto& ifInfo : hostIfInfos) {
57 5 : auto iter = find(whitelist.begin(), whitelist.end(), ifInfo.second);
58 5 : if (iter != whitelist.end()) {
59 4 : ifInfos.push_back({ifInfo.first, ifInfo.second});
60 : }
61 : }
62 5 : } else {
63 3 : ifInfos = hostIfInfos;
64 : }
65 8 : }
66 :
67 1 : bool FindHostIpbyControlIfIp(const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, IpAddress& ipAddress)
68 : {
69 : // 匹配指定IP的网卡信息
70 1 : auto it = std::find_if(hostIfInfos.begin(), hostIfInfos.end(), [&ipAddress](const auto& hostIfInfo) {
71 1 : return hostIfInfo.second == ipAddress;
72 : });
73 1 : if (it != hostIfInfos.end()) {
74 1 : HCCL_INFO(
75 : "[%s] find hostIp success, name[%s] ip[%s]", __func__, it->first.c_str(), ipAddress.GetIpStr().c_str());
76 1 : return true;
77 : }
78 0 : RPT_INPUT_ERR(
79 : true, "EI0001", std::vector<std::string>({"value", "env", "expect"}),
80 : std::vector<std::string>(
81 : {ipAddress.GetIpStr(), "HCCL_IF_IP", "a valid IP from the available network interfaces"}));
82 0 : HCCL_ERROR(
83 : "[%s] Env config \"HCCL_IF_IP\" is [%s] which is not found in the nic list.", __func__,
84 : ipAddress.GetIpStr().c_str());
85 0 : return false;
86 0 : }
87 :
88 3 : bool FindHostIpByIfName(
89 : const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, s32 family, IpAddress& ipAddress)
90 : {
91 3 : HCCL_INFO("[%s] find host ip start. family[%d]", __func__, family);
92 :
93 : // 使用Host网卡名和环境变量HCCL_SOCKET_IFNAME配置的网卡名进行比较
94 3 : auto socketIfName = EnvConfig::GetInstance().GetHostNicConfig().GetSocketIfName();
95 5 : for (auto& hostIfInfo : hostIfInfos) {
96 3 : if (hostIfInfo.second.GetFamily() != family) {
97 1 : continue;
98 : }
99 2 : u32 matchLen = hostIfInfo.first.size();
100 2 : bool configIfNamesFlag = false;
101 4 : for (u32 i = 0; i < socketIfName.configIfNames.size(); i++) {
102 2 : matchLen = socketIfName.searchExact ? hostIfInfo.first.size() : socketIfName.configIfNames[i].size();
103 2 : if (hostIfInfo.first.compare(0, matchLen, socketIfName.configIfNames[i], 0, matchLen) == 0) {
104 1 : configIfNamesFlag = true;
105 : }
106 : }
107 2 : if (configIfNamesFlag != socketIfName.searchNot) {
108 1 : configIfNamesFlag = false;
109 1 : ipAddress = hostIfInfo.second;
110 1 : HCCL_INFO(
111 : "[%s] find hostIp success by ifName. name[%s] ip[%s]", __func__, hostIfInfo.first.c_str(),
112 : hostIfInfo.second.GetIpStr().c_str());
113 1 : return true;
114 : }
115 : }
116 :
117 2 : HCCL_WARNING("[%s] find host ip fail by family[%d] ifName.", __func__, family);
118 2 : return false;
119 3 : }
120 :
121 2 : bool FindHostIpByIfName(const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, IpAddress& ipAddress)
122 : {
123 2 : s32 socketFamily = EnvConfig::GetInstance().GetSocketConfig().GetSocketFamily();
124 2 : socketFamily = (socketFamily == -1) ? AF_INET : socketFamily;
125 2 : bool ret = FindHostIpByIfName(hostIfInfos, socketFamily, ipAddress);
126 2 : if (!ret) {
127 1 : socketFamily = (socketFamily == AF_INET) ? AF_INET6 : AF_INET;
128 1 : ret = FindHostIpByIfName(hostIfInfos, socketFamily, ipAddress);
129 : }
130 2 : return ret;
131 : }
132 :
133 9 : bool FindHostIpFromOneNicClass(
134 : const std::map<std::string, std::map<std::string, IpAddress>>& nicClassifyInfo, const std::string& nicClass,
135 : IpAddress& ip)
136 : {
137 9 : auto iterClass = nicClassifyInfo.find(nicClass);
138 9 : if (iterClass != nicClassifyInfo.end()) {
139 4 : if (iterClass->second.empty()) {
140 0 : HCCL_WARNING("[%s] nic class[%s]: no valid ip.", __func__, nicClass.c_str());
141 0 : return false;
142 : }
143 4 : ip = iterClass->second.begin()->second;
144 4 : HCCL_INFO(
145 : "[%s] find host ip success by nic class[%s]. host ifName[%s] ip[%s]", __func__, nicClass.c_str(),
146 : iterClass->second.begin()->first.c_str(), ip.GetIpStr().c_str());
147 4 : return true;
148 : }
149 5 : return false;
150 : }
151 :
152 4 : bool FindHostIPByNicClass(
153 : const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, s32 family, IpAddress& ipAddress)
154 : {
155 4 : std::map<std::string, std::map<std::string, IpAddress>> nicClassify;
156 8 : for (auto& hostIfInfo : hostIfInfos) {
157 4 : if (hostIfInfo.second.GetFamily() != family) {
158 0 : continue;
159 : }
160 4 : if (hostIfInfo.first.find("lo") == 0) {
161 4 : nicClassify["lo"].insert({hostIfInfo.first, hostIfInfo.second});
162 2 : } else if (hostIfInfo.first.find("docker") == 0) {
163 2 : nicClassify["docker"].insert({hostIfInfo.first, hostIfInfo.second});
164 : } else {
165 2 : nicClassify["normal"].insert({hostIfInfo.first, hostIfInfo.second});
166 : }
167 4 : HCCL_DEBUG(
168 : "[%s] ifName[%s] addr[%s]", __func__, hostIfInfo.first.c_str(), hostIfInfo.second.GetIpStr().c_str());
169 : }
170 :
171 8 : if (FindHostIpFromOneNicClass(nicClassify, "normal", ipAddress)) {
172 1 : HCCL_INFO("[%s] find host ip success by nic class[normal]. ip[%s].", __func__, ipAddress.GetIpStr().c_str());
173 1 : return true;
174 6 : } else if (FindHostIpFromOneNicClass(nicClassify, "docker", ipAddress)) {
175 1 : HCCL_INFO("[%s] find host ip success by nic class[docker]. ip[%s].", __func__, ipAddress.GetIpStr().c_str());
176 1 : return true;
177 4 : } else if (FindHostIpFromOneNicClass(nicClassify, "lo", ipAddress)) {
178 2 : HCCL_INFO("[%s] find host ip success by nic class[lo]. ip[%s].", __func__, ipAddress.GetIpStr().c_str());
179 2 : return true;
180 : }
181 :
182 0 : HCCL_WARNING("[%s] find hostIp by nic class[normal_docket_lo] fail.", __func__);
183 0 : return false;
184 4 : }
185 :
186 4 : bool FindHostIPByNicClass(const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, IpAddress& ipAddress)
187 : {
188 4 : s32 socketFamily = EnvConfig::GetInstance().GetSocketConfig().GetSocketFamily();
189 4 : socketFamily = (socketFamily == -1) ? AF_INET : socketFamily;
190 4 : bool ret = FindHostIPByNicClass(hostIfInfos, socketFamily, ipAddress);
191 4 : if (!ret) {
192 0 : socketFamily = (socketFamily == AF_INET) ? AF_INET6 : AF_INET;
193 0 : ret = FindHostIPByNicClass(hostIfInfos, socketFamily, ipAddress);
194 : }
195 4 : return ret;
196 : }
197 :
198 7 : bool FindLocalHostIp(const std::vector<std::pair<std::string, IpAddress>>& hostIfInfos, IpAddress& ipAddress)
199 : {
200 : // 根据HCCL_IF_IP查询ips中匹配的LocalHostIP
201 7 : ipAddress = EnvConfig::GetInstance().GetHostNicConfig().GetControlIfIp();
202 7 : if (!ipAddress.IsInvalid()) {
203 1 : return FindHostIpbyControlIfIp(hostIfInfos, ipAddress);
204 : }
205 :
206 : // 根据HCCL_SOCKET_IFNAME查询ips中匹配的LocalHostIP
207 6 : auto ifnames = EnvConfig::GetInstance().GetHostNicConfig().GetSocketIfName();
208 6 : if (!ifnames.configIfNames.empty()) {
209 2 : bool ret = FindHostIpByIfName(hostIfInfos, ipAddress);
210 2 : if (!ret) {
211 14 : RPT_INPUT_ERR(
212 : true, "EI0001", std::vector<std::string>({"value", "env", "expect"}),
213 : std::vector<std::string>(
214 : {ifnames.configIfNameStr, "HCCL_SOCKET_IFNAME",
215 : "a valid network interface name from the available interfaces"}));
216 1 : HCCL_ERROR(
217 : "[Init][EnvVarParam][%s] Env config \"HCCL_SOCKET_IFNAME\" is [%s] which is not found in the nic list",
218 : __func__, ifnames.configIfNameStr.c_str());
219 2 : for (auto& ifInfo : hostIfInfos) {
220 1 : HCCL_ERROR(
221 : "[%s] get host ip fail by socket Ifname. nic name[%s] ip[%s]", __func__, ifInfo.first.c_str(),
222 : ifInfo.second.Describe().c_str());
223 : }
224 : }
225 2 : return ret;
226 : }
227 :
228 : // 不匹配的话以此类推选择normal/docker/lo类型的
229 4 : return FindHostIPByNicClass(hostIfInfos, ipAddress);
230 8 : }
231 :
232 12 : const IpAddress& GetBootstrapIp(u32 devPhyId)
233 : {
234 : // 如果已获取过则直接使用ip
235 12 : auto it = bootstrapIps.Find(devPhyId);
236 12 : if (it.second) {
237 2 : CHK_PRT_RET(
238 : !it.first->second.IsInvalid(),
239 : HCCL_INFO("[%s] hostIp[%s] already exists.", __func__, it.first->second.GetIpStr().c_str()),
240 : it.first->second);
241 : }
242 :
243 : // 获取网卡ip
244 10 : auto hostIfInfos = HrtGetHostIf(devPhyId);
245 14 : CHK_PRT_THROW(
246 : hostIfInfos.empty(), HCCL_ERROR("[%s] there is no host if.", __func__), InternalException, "get host ip error");
247 :
248 : // 若白名单使能则过滤
249 8 : vector<std::pair<std::string, IpAddress>> ifInfos;
250 8 : GetAllValidHostIfInfos(hostIfInfos, ifInfos);
251 10 : CHK_PRT_THROW(
252 : ifInfos.empty(), HCCL_ERROR("[%s] there is no valid host if in whitelist.", __func__), InternalException,
253 : "get host ip error");
254 :
255 : // 获得有效的bootstrapIp
256 7 : IpAddress ipAddress{};
257 7 : bool ret = FindLocalHostIp(ifInfos, ipAddress);
258 9 : CHK_PRT_THROW(!ret, HCCL_ERROR("[%s] there is no valid host ip.", __func__), InternalException, "no valid host ip");
259 :
260 : // 保存有效的bootstrapIp且返回
261 6 : bootstrapIps[devPhyId] = ipAddress;
262 :
263 6 : HCCL_INFO("[%s] get hostIp success. ipAddress[%s]", __func__, ipAddress.GetIpStr().c_str());
264 6 : return bootstrapIps[devPhyId];
265 12 : }
266 :
267 : } // namespace Hccl
|