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