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