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 : #ifndef HCCLV2_IP_ADDRESS_H
12 : #define HCCLV2_IP_ADDRESS_H
13 :
14 : #include <arpa/inet.h>
15 : #include <string>
16 : #include <vector>
17 : #include <regex>
18 : #include <cstring>
19 :
20 : #include "hccl/base.h"
21 : #include "string_util.h"
22 : #include "not_support_exception.h"
23 : #include "exception_util.h"
24 : #include "invalid_params_exception.h"
25 : #include "hash_utils.h"
26 : #include "binary_stream.h"
27 : #include "internal_exception.h"
28 :
29 : namespace Hccl {
30 : using namespace std;
31 :
32 : constexpr uint32_t URMA_EID_LEN = 16;
33 : constexpr uint32_t URMA_EID_NUM_TWO = 2;
34 : constexpr uint32_t MAX_IPV4_LEN = 15; // 最大IPv4地址长度
35 : constexpr uint32_t MIN_IPV4_LEN = 7; // 最小IPv4地址长度
36 : constexpr uint32_t BASE = 10; // 进制基数
37 : constexpr uint32_t MAX_DOT_COUNT = 3; // IPv4地址.分割符的最大个数
38 : constexpr uint32_t MAX_IPV4_SEGMENT_VALUE = 255; // 每个段的最大值
39 : constexpr uint32_t URMA_EID_IPV4_PREFIX = 0x0;
40 : constexpr uint32_t EID_WORD_SHIFT_0 = 48; // EID 64位值中第0个16位字的右移位数
41 : constexpr uint32_t EID_WORD_SHIFT_1 = 32; // EID 64位值中第1个16位字的右移位数
42 : constexpr uint32_t EID_WORD_SHIFT_2 = 16; // EID 64位值中第2个16位字的右移位数
43 :
44 : union Eid {
45 : uint8_t raw[URMA_EID_LEN]{0};
46 : struct {
47 : uint64_t reserved;
48 : uint32_t prefix;
49 : uint32_t addr;
50 : } in4;
51 : struct {
52 : uint64_t subnetPrefix;
53 : uint64_t interfaceId;
54 : } in6;
55 :
56 10744 : string Describe() const
57 : {
58 10744 : uint64_t subnet = be64toh(in6.subnetPrefix);
59 10744 : uint64_t ifId = be64toh(in6.interfaceId);
60 : return StringFormat("%04llx:%04llx:%04llx:%04llx:%04llx:%04llx:%04llx:%04llx",
61 10744 : static_cast<unsigned long long>((subnet >> EID_WORD_SHIFT_0) & 0xFFFF),
62 10744 : static_cast<unsigned long long>((subnet >> EID_WORD_SHIFT_1) & 0xFFFF),
63 10744 : static_cast<unsigned long long>((subnet >> EID_WORD_SHIFT_2) & 0xFFFF),
64 : static_cast<unsigned long long>(subnet & 0xFFFF),
65 10744 : static_cast<unsigned long long>((ifId >> EID_WORD_SHIFT_0) & 0xFFFF),
66 10744 : static_cast<unsigned long long>((ifId >> EID_WORD_SHIFT_1) & 0xFFFF),
67 10744 : static_cast<unsigned long long>((ifId >> EID_WORD_SHIFT_2) & 0xFFFF),
68 10744 : static_cast<unsigned long long>(ifId & 0xFFFF));
69 : }
70 :
71 0 : bool operator==(const Eid &that) const
72 : {
73 0 : return memcmp(&raw, &that.raw, sizeof(raw)) == 0;
74 : }
75 :
76 : bool operator<(const Eid &that) const
77 : {
78 : return memcmp(&raw, &that.raw, sizeof(raw)) < 0;
79 : }
80 : };
81 :
82 : union BinaryAddr {
83 : struct in_addr addr;
84 : struct in6_addr addr6;
85 : };
86 : class IpAddress {
87 : public:
88 21081 : IpAddress()
89 21081 : {
90 21081 : scopeID_ = 0;
91 21081 : family_ = AF_INET;
92 21081 : binaryAddr_.addr.s_addr = 0;
93 21081 : }
94 :
95 2117 : explicit IpAddress(const string &ip, s32 family = AF_INET) : family_(family)
96 : {
97 2117 : InitBinaryAddr(ip);
98 2115 : }
99 :
100 : explicit IpAddress(const union BinaryAddr &ip, s32 family, const uint8_t* eid)
101 : : family_(family)
102 : {
103 : binaryAddr_ = ip;
104 : if (eid != nullptr) {
105 : // 安全复制原始EID
106 : s32 sRet = memcpy_s(eid_.raw, sizeof(eid_.raw), eid, URMA_EID_LEN);
107 : if (sRet != 0) {
108 : THROW<InternalException>("[IpAddress]memcpy_s failed when setting original EID");
109 : }
110 : }
111 : }
112 :
113 7817 : explicit IpAddress(const union BinaryAddr &ip, s32 family, s32 scopeID = 0) : family_(family), scopeID_(scopeID)
114 : {
115 7817 : binaryAddr_ = ip;
116 : // 区分ipv4和ipv6转eid
117 7817 : if (family_ == AF_INET6) {
118 6375 : s32 sRet = memcpy_s(eid_.raw, sizeof(eid_.raw), binaryAddr_.addr6.s6_addr, sizeof(binaryAddr_.addr6.s6_addr));
119 6375 : if (sRet != 0) {
120 0 : THROW<InternalException>("[IpAddress]memcpy_s failed");
121 : }
122 : } else {
123 1442 : ipv4AddrToEid(binaryAddr_.addr.s_addr);
124 : }
125 7817 : }
126 :
127 954 : explicit IpAddress(u32 address)
128 954 : {
129 : struct in_addr addr {
130 : address
131 954 : };
132 954 : family_ = AF_INET;
133 954 : binaryAddr_.addr = addr;
134 954 : ipv4AddrToEid(address);
135 954 : }
136 :
137 14 : explicit IpAddress(std::vector<char> &uniqueId) // 基于序列化数据得到IpAddress
138 14 : {
139 14 : char dst[INET6_ADDRSTRLEN]{0};
140 14 : BinaryStream binaryStream(uniqueId);
141 14 : binaryStream >> family_;
142 14 : binaryStream >> scopeID_;
143 14 : binaryStream >> dst;
144 :
145 14 : std::string ip = dst;
146 14 : InitBinaryAddr(ip);
147 14 : binaryStream >> eid_.raw; // 恢复eid.raw,覆盖eid
148 14 : }
149 92 : explicit IpAddress(const Eid &eidInput)
150 92 : {
151 1564 : for (uint32_t i = 0; i < URMA_EID_LEN; i++) {
152 1472 : eid_.raw[i] = eidInput.raw[i];
153 : }
154 112 : HCCL_INFO("[IpAddress] %s", eid_.Describe().c_str());
155 : // IPoURMA适配后,使用EID初始化时转为ipv6建链
156 92 : family_ = AF_INET6;
157 92 : (void)memcpy_s(binaryAddr_.addr6.s6_addr, sizeof(eid_.raw), eid_.raw, sizeof(eid_.raw));
158 92 : }
159 :
160 18 : std::vector<char> GetUniqueId() const // 获取序列化数据
161 : {
162 18 : std::string ipStr = GetIpStr();
163 18 : char dst[INET6_ADDRSTRLEN]{0};
164 18 : int sret = strcpy_s(dst, sizeof(dst), ipStr.data());
165 18 : if (sret != 0) {
166 : auto msg = StringFormat("[Get][UniqueId]errNo[0x%016llx] memory copy failed. ret[%d]",
167 0 : HCOM_ERROR_CODE(HcclResult::HCCL_E_MEMORY), sret);
168 0 : THROW<InternalException>(msg);
169 0 : }
170 18 : BinaryStream binaryStream;
171 18 : binaryStream << family_;
172 18 : binaryStream << scopeID_;
173 18 : binaryStream << dst;
174 18 : binaryStream << eid_.raw; // 保存eid.raw
175 18 : std::vector<char> result;
176 18 : binaryStream.Dump(result);
177 18 : return result;
178 18 : }
179 :
180 : void SetScopeID(s32 scope)
181 : {
182 : this->scopeID_ = scope;
183 : }
184 :
185 6807 : s32 GetScopeID() const
186 : {
187 6807 : return scopeID_;
188 : }
189 :
190 7133 : s32 GetFamily() const
191 : {
192 7133 : return family_;
193 : }
194 :
195 7484 : union BinaryAddr GetBinaryAddress() const
196 : {
197 7484 : return binaryAddr_;
198 : }
199 :
200 : bool IsIPv6() const
201 : {
202 : return (family_ == AF_INET6);
203 : }
204 :
205 : /*The following IPV6 formats can be verified:
206 : dotted quad at the end, multiple zeroes collapsed: fe80::204:61ff:254.157.241.86
207 : collapse multiple zeroes to :: in the IPv6 address: fe80::204:61ff:fe9d:f156
208 : full form of IPv6: fe80:0000:0000:0000:0204:61ff:fe9d:f156
209 : drop leading zeroes, IPv4 dotted quad at the end: fe80:0:0:0:0204:61ff:254.157.241.86
210 : drop leading zeroes: fe80:0:0:0:204:61ff:fe9d:f156
211 : IPv4 dotted quad at the end: fe80:0000:0000:0000:0204:61ff:254.157.241.86
212 : global unicast prefix: 2001::
213 : link-local prefix: fe80::
214 : localhost: ::1
215 : */
216 9 : static bool IsIPv6(const string& str)
217 : {
218 9 : regex ipv6Pattern(R"(^([\da-fA-F]{1,4}:){6}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^::([\da-fA-F]{1,4}:){0,4}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^([\da-fA-F]{1,4}:):([\da-fA-F]{1,4}:){0,3}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^([\da-fA-F]{1,4}:){2}:([\da-fA-F]{1,4}:){0,2}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^([\da-fA-F]{1,4}:){3}:([\da-fA-F]{1,4}:){0,1}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^([\da-fA-F]{1,4}:){4}:((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$|^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$|^:((:[\da-fA-F]{1,4}){1,6}|:)$|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)$|^([\da-fA-F]{1,4}:){2}((:[\da-fA-F]{1,4}){1,4}|:)$|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)$|^([\da-fA-F]{1,4}:){4}((:[\da-fA-F]{1,4}){1,2}|:)$|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?$|^([\da-fA-F]{1,4}:){6}:$)");
219 18 : return regex_match(str, ipv6Pattern);
220 9 : }
221 : /*All the five types of IPV4 addresses,ABCDE,can be identified.
222 : A: 1.0.0.1 - 126.255.255.254
223 : B: 128.0.0.1 - 191.255.255.254
224 : C: 192.0.0.1 - 223.255.255.254
225 : D: 224.0.0.1 - 239.255.255.254
226 : E: 240.0.0.1 - 255.255.255.254
227 : 127.x.x.x is reserved address for loopback test.
228 : 0.0.0.0 can only be used as the source address.
229 : 255.255.255.255 is broadcast address.
230 : */
231 557 : static bool IsIPv4(const std::string& str) {
232 : // 快速长度检查
233 557 : size_t len = str.length();
234 557 : if (len < MIN_IPV4_LEN || len > MAX_IPV4_LEN) {
235 1 : return false;
236 : }
237 556 : uint32_t num = 0;
238 556 : uint32_t dotCount = 0;
239 556 : bool hasDigit = false;
240 8529 : for (size_t i = 0; i < len; ++i) {
241 7976 : char c = str[i];
242 7976 : if (c >= '0' && c <= '9') {
243 : // 检查前导零
244 6319 : if (!hasDigit && c == '0' && i + 1 < len && str[i + 1] != '.') {
245 1 : return false;
246 : }
247 6318 : num = num * BASE + (c - '0');
248 6318 : hasDigit = true;
249 6318 : if (num > MAX_IPV4_SEGMENT_VALUE) {
250 1 : return false;
251 : }
252 1657 : } else if (c == '.') {
253 : // 检查点号位置和数字有效性
254 1656 : if (!hasDigit || dotCount >= MAX_DOT_COUNT || i == 0 || i == len - 1) {
255 0 : return false;
256 : }
257 1656 : dotCount++;
258 1656 : num = 0;
259 1656 : hasDigit = false;
260 : } else {
261 1 : return false;
262 : }
263 : }
264 553 : return dotCount == MAX_DOT_COUNT && hasDigit;
265 : }
266 :
267 126 : static bool IsEID(const string& str)
268 : {
269 126 : if (str.length() == URMA_EID_LEN * URMA_EID_NUM_TWO) {
270 7 : std::regex hexCharsRegex("[0-9a-fA-F]+");
271 7 : return std::regex_match(str, hexCharsRegex);
272 7 : }
273 119 : return false;
274 : }
275 :
276 6 : static Eid StrToEID(const string& str)
277 : {
278 6 : Eid tmpeEid{};
279 6 : const int Base = 16;
280 102 : for (size_t i = 0; i < URMA_EID_LEN; ++i) {
281 96 : std::string byteString = str.substr(i * 2, 2);
282 96 : tmpeEid.raw[i] = static_cast<uint8_t>(std::stoi(byteString, nullptr, Base));
283 96 : }
284 6 : return tmpeEid;
285 : }
286 :
287 11148 : string GetIpStr() const
288 : {
289 11148 : const void *src = nullptr;
290 11148 : if (family_ == AF_INET) {
291 8783 : src = &binaryAddr_.addr;
292 2365 : } else if (family_ == AF_INET6) {
293 2365 : src = &binaryAddr_.addr6;
294 : } else {
295 0 : THROW<NotSupportException>(StringFormat("Unsupported Address Family: %d", family_));
296 : }
297 : char dst[INET6_ADDRSTRLEN];
298 11148 : const char *res = inet_ntop(family_, src, dst, INET6_ADDRSTRLEN);
299 11148 : if (res == nullptr) {
300 0 : THROW<InvalidParamsException>("Invalid Binary Network Address");
301 : }
302 22296 : return dst;
303 : }
304 :
305 14109 : Eid GetEid() const
306 : {
307 14109 : return eid_;
308 : }
309 :
310 : void SetEid(Eid eid)
311 : {
312 : eid_ = eid;
313 : }
314 :
315 584 : Eid GetReverseEid() const
316 : {
317 584 : Eid eidOut;
318 9928 : for (uint32_t i = 0; i < URMA_EID_LEN; i++) {
319 9344 : eidOut.raw[i] = eid_.raw[URMA_EID_LEN - i - 1];
320 : }
321 584 : return eidOut;
322 : }
323 :
324 10443 : string Describe() const
325 : {
326 10443 : string desc = StringFormat("IpAddress[%s, ", eid_.Describe().c_str());
327 :
328 10443 : if (family_ == AF_INET) {
329 8083 : desc += StringFormat("AF=IPv4, addr=%s]", GetIpStr().c_str());
330 : } else {
331 2360 : desc += StringFormat("AF=IPv6, addr=%s, scopeId=0x%x]", GetIpStr().c_str(), scopeID_);
332 : }
333 10443 : return desc;
334 0 : }
335 :
336 4774 : bool operator==(const IpAddress &that) const
337 : {
338 4774 : if (this->family_ != that.family_) {
339 0 : return false;
340 : }
341 4774 : if (memcmp(&this->eid_.raw, &that.eid_.raw, sizeof(this->eid_.raw)) != 0) {
342 927 : return false;
343 : }
344 3847 : return true;
345 : }
346 :
347 229 : bool operator<(const IpAddress &that) const
348 : {
349 229 : if (this->family_ < that.family_) {
350 0 : return true;
351 : }
352 229 : if (that.family_ < this->family_) {
353 0 : return false;
354 : }
355 229 : if (memcmp(&this->eid_.raw, &that.eid_.raw, sizeof(this->eid_.raw)) < 0) {
356 139 : return true;
357 : }
358 90 : return false;
359 : }
360 :
361 26 : explicit IpAddress(BinaryStream &binaryStream) // 基于序列化数据得到IpAddress
362 26 : {
363 26 : binaryStream >> family_ >> scopeID_;
364 : // 打印family_、scopeID_
365 78 : HCCL_INFO("[IpAddress::%s] family_[%d], scopeID_[%d]",
366 : __func__, family_, scopeID_);
367 26 : char dst[INET6_ADDRSTRLEN]{0};
368 26 : binaryStream >> dst;
369 26 : std::string ip = dst;
370 : // 打印ip
371 78 : HCCL_INFO("[IpAddress::%s] ip_[%s]", __func__, ip.c_str());
372 26 : InitBinaryAddr(ip);
373 26 : binaryStream >> eid_.raw; // 恢复eid.raw,覆盖eid
374 26 : }
375 :
376 151 : void GetBinStream(BinaryStream &binaryStream) const {
377 151 : std::string ipStr = GetIpStr();
378 151 : char dst[INET6_ADDRSTRLEN]{0};
379 151 : int sret = strcpy_s(dst, sizeof(dst), ipStr.data());
380 151 : if (sret != 0) {
381 : auto msg = StringFormat("[Get][UniqueId]errNo[0x%016llx] memory copy failed. ret[%d]",
382 0 : HCOM_ERROR_CODE(HcclResult::HCCL_E_MEMORY), sret);
383 0 : THROW<InternalException>(msg);
384 0 : }
385 151 : binaryStream << family_ << scopeID_ << dst;
386 151 : binaryStream << eid_.raw; // 保存eid.raw
387 151 : }
388 :
389 11 : bool IsInvalid() const
390 : {
391 11 : return ((family_ == AF_INET) && (binaryAddr_.addr.s_addr == 0));
392 : }
393 :
394 : private:
395 : union BinaryAddr binaryAddr_{}; // 二进制IP地址
396 : s32 family_{AF_INET};
397 : s32 scopeID_{0};
398 : Eid eid_{};
399 2142 : void InitBinaryAddr(const string &ip)
400 : {
401 : void *dst;
402 2142 : int cnt = std::count(ip.begin(), ip.end(), ':');
403 2142 : if (cnt >= 2) { // ipv6地址中至少有2个":"
404 12 : family_ = AF_INET6;
405 12 : dst = &binaryAddr_.addr6;
406 : } else {
407 2130 : family_ = AF_INET;
408 2130 : dst = &binaryAddr_.addr;
409 : }
410 2142 : int res = inet_pton(family_, ip.c_str(), dst);
411 2142 : if (res == -1) {
412 0 : THROW<NotSupportException>(StringFormat("Unsupported Address Family: %d", family_));
413 2142 : } else if (res == 0) {
414 2 : THROW<InvalidParamsException>(StringFormat("Invalid Network Address: %s", ip.c_str()));
415 : }
416 :
417 2140 : if (family_ == AF_INET6) {
418 12 : s32 sRet = memcpy_s(eid_.raw, sizeof(eid_.raw), binaryAddr_.addr6.s6_addr, sizeof(binaryAddr_.addr6.s6_addr));
419 12 : if (sRet != 0) {
420 0 : THROW<InternalException>("[InitBinaryAddr]memcpy_s failed");
421 : }
422 : } else {
423 2128 : ipv4AddrToEid(binaryAddr_.addr.s_addr);
424 : }
425 2140 : }
426 :
427 4524 : void ipv4AddrToEid(const uint32_t &inAddr)
428 : {
429 4524 : eid_.in4.reserved = 0;
430 4524 : eid_.in4.prefix = URMA_EID_IPV4_PREFIX;
431 4524 : eid_.in4.addr = inAddr;
432 4524 : }
433 : };
434 : } // namespace Hccl
435 :
436 : namespace std {
437 :
438 : template <> class equal_to<Hccl::Eid> {
439 : public:
440 0 : bool operator()(const Hccl::Eid &p1, const Hccl::Eid &p2) const
441 : {
442 0 : return p1 == p2;
443 : }
444 : };
445 :
446 : template <> class hash<Hccl::Eid> {
447 : public:
448 0 : size_t operator()(const Hccl::Eid &eid) const
449 : {
450 0 : auto subnetPrefixHash = hash<uint64_t>{}(be64toh(eid.in6.subnetPrefix));
451 0 : auto interfaceIdHash = hash<uint64_t>{}(be64toh(eid.in6.interfaceId));
452 0 : return Hccl::HashCombine({subnetPrefixHash, interfaceIdHash});
453 : }
454 : };
455 :
456 : template <> class equal_to<Hccl::IpAddress> {
457 : public:
458 2089 : bool operator()(const Hccl::IpAddress &p1, const Hccl::IpAddress &p2) const
459 : {
460 2089 : return p1 == p2;
461 : }
462 : };
463 :
464 : template <> class hash<Hccl::IpAddress> {
465 : public:
466 6802 : size_t operator()(const Hccl::IpAddress &ip) const
467 : {
468 6802 : auto scopeIDHash = hash<s32>{}(ip.GetScopeID());
469 6802 : auto familyHash = hash<s32>{}(ip.GetFamily());
470 6802 : auto addrHash = hash<size_t>{}(ip.GetBinaryAddress().addr.s_addr); //Ipv4地址hash
471 6802 : auto eidSubnetPrefix = hash<uint64_t>{}(ip.GetEid().in6.subnetPrefix);
472 6802 : auto eidInterfaceId = hash<uint64_t>{}(ip.GetEid().in6.interfaceId);
473 :
474 6802 : return Hccl::HashCombine({scopeIDHash, familyHash, addrHash, eidSubnetPrefix, eidInterfaceId});
475 : }
476 : };
477 : } // namespace std
478 :
479 : #endif // HCCLV2_IP_ADDRESS_H
|