LCOV - code coverage report
Current view: top level - legacy/ascend950/common - ip_address.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.8 % 216 194
Test Date: 2026-08-18 17:47:01 Functions: 90.3 % 31 28

            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
        

Generated by: LCOV version 2.0-1