LCOV - code coverage report
Current view: top level - legacy/ascend950/common - ip_address.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.3 % 217 196
Test Date: 2026-08-25 19:18:03 Functions: 90.6 % 32 29

            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
        

Generated by: LCOV version 2.0-1