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