LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - address.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 153 156 98.1 %
Date: 2026-08-03 02:19:58 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <base/address.h>
       6             : 
       7             : #include <map>
       8             : #include <boost/assign/list_of.hpp>
       9             : 
      10             : using namespace std;
      11             : 
      12           0 : Address::Address() {
      13           0 : }
      14             : 
      15             : static const std::map<string, Address::Family>
      16             :     fromString = boost::assign::map_list_of
      17             :         ("unspecified", Address::UNSPEC)
      18             :         ("inet", Address::INET)
      19             :         ("inet-labeled", Address::INETMPLS)
      20             :         ("inet6", Address::INET6)
      21             :         ("inet-vpn", Address::INETVPN)
      22             :         ("inet6-vpn", Address::INET6VPN)
      23             :         ("route-target", Address::RTARGET)
      24             :         ("e-vpn", Address::EVPN)
      25             :         ("inet-mvpn", Address::MVPN)
      26             :         ("erm-vpn", Address::ERMVPN);
      27             : 
      28             : static const std::map<Address::Family, string>
      29             :     toString = boost::assign::map_list_of
      30             :         (Address::UNSPEC, "unspecified")
      31             :         (Address::INET, "inet")
      32             :         (Address::INETMPLS, "inet-labeled")
      33             :         (Address::INET6, "inet6")
      34             :         (Address::INETVPN, "inet-vpn")
      35             :         (Address::INET6VPN, "inet6-vpn")
      36             :         (Address::RTARGET, "route-target")
      37             :         (Address::EVPN, "e-vpn")
      38             :         (Address::MVPN, "inet-mvpn")
      39             :         (Address::ERMVPN, "erm-vpn");
      40             : 
      41             : static const std::map<Address::Family, string>
      42             :     toTableName = boost::assign::map_list_of
      43             :         (Address::UNSPEC, "unspecified")
      44             :         (Address::INET, "inet")
      45             :         (Address::INETMPLS, "inet")
      46             :         (Address::INET6, "inet6")
      47             :         (Address::INETVPN, "l3vpn")
      48             :         (Address::INET6VPN, "l3vpn-inet6")
      49             :         (Address::RTARGET, "rtarget")
      50             :         (Address::EVPN, "evpn")
      51             :         (Address::MVPN, "mvpn")
      52             :         (Address::ERMVPN, "ermvpn");
      53             : 
      54       34935 : Address::Family Address::FamilyFromString(const std::string &family) {
      55             :     std::map<string, Address::Family>::const_iterator loc =
      56       34935 :             fromString.find(family);
      57       34935 :     if (loc != fromString.end()) {
      58       34935 :         return loc->second;
      59             :     }
      60           0 :     return Address::UNSPEC;
      61             : }
      62             : 
      63     3508500 : std::string Address::FamilyToString(Address::Family family) {
      64     7016909 :     return toString.find(family)->second;
      65             : }
      66             : 
      67      257438 : std::string Address::FamilyToTableString(Address::Family family) {
      68      514802 :     return toTableName.find(family)->second;
      69             : }
      70             : 
      71        5554 : Address::Family Address::VpnFamilyFromFamily(Address::Family family) {
      72        5554 :     switch (family) {
      73        5257 :     case Address::INET:
      74             :     case Address::INETVPN:
      75        5257 :         return Address::INETVPN;
      76          95 :     case Address::INET6:
      77             :     case Address::INET6VPN:
      78          95 :         return Address::INET6VPN;
      79          97 :     case Address::EVPN:
      80          97 :         return Address::EVPN;
      81           8 :     case Address::MVPN:
      82           8 :         return Address::MVPN;
      83          17 :     case Address::ERMVPN:
      84          17 :         return Address::ERMVPN;
      85          80 :     default:
      86          80 :         return Address::UNSPEC;
      87             :     }
      88             :     return Address::UNSPEC;
      89             : }
      90             : 
      91      157917 : static int CountDots(const string &str) {
      92      157917 :     int count = 0;
      93      157917 :     size_t pos = 0;
      94      619076 :     while (pos < str.size()) {
      95      619066 :         pos = str.find('.', pos);
      96      619075 :         if (pos == string::npos) {
      97      157916 :             break;
      98             :         }
      99      461159 :         count++;
     100      461159 :         pos++;
     101             :     }
     102      157920 :     return count;
     103             : }
     104             : 
     105             : // Return the IP address part as it is i.e. 1.2.3.4/24 will return 1.2.3.4 and
     106             : // 24.
     107      178552 : boost::system::error_code Ip4PrefixParse(const string &str, Ip4Address *addr,
     108             :                                          int *plen) {
     109      178552 :     size_t pos = str.find('/');
     110      178552 :     if (pos == string::npos) {
     111          35 :         return make_error_code(boost::system::errc::invalid_argument);
     112             :     }
     113      178517 :     *plen = atoi(str.c_str() + pos + 1);
     114      178517 :     if ((*plen < 0) || (*plen > Address::kMaxV4PrefixLen)) {
     115       20600 :         return make_error_code(boost::system::errc::invalid_argument);
     116             :     }
     117             : 
     118      157917 :     string addrstr = str.substr(0, pos);
     119      157916 :     int dots = CountDots(addrstr);
     120      170518 :     while (dots < 3) {
     121       12599 :         addrstr.append(".0");
     122       12599 :         dots++;
     123             :     }
     124             : 
     125      157919 :     boost::system::error_code err;
     126      157919 :     *addr = Ip4Address::from_string(addrstr, err);
     127      157917 :     return err;
     128      157917 : }
     129             : 
     130             : // Return the bitwise and of IP and mask.
     131      174656 : boost::system::error_code Ip4SubnetParse(const string &str, Ip4Address *addr,
     132             :                                          int *plen) {
     133      174656 :     Ip4Address address;
     134      174656 :     boost::system::error_code err;
     135      174656 :     err = Ip4PrefixParse(str, &address, plen);
     136      174659 :     if (!err) {
     137      152539 :         *addr = Address::GetIp4SubnetAddress(address, *plen);
     138             :     }
     139      174658 :     return err;
     140             : }
     141             : 
     142             : // Return the IP address part as it is i.e. 2001:db8:85a3:aaaa::b:c:d/64 will
     143             : // return 2001:db8:85a3:aaaa::b:c:d and 64.
     144       75562 : boost::system::error_code Inet6PrefixParse(const string &str, Ip6Address *addr,
     145             :                                            int *plen) {
     146       75562 :     size_t pos = str.find('/');
     147       75562 :     if (pos == string::npos) {
     148          24 :         return make_error_code(boost::system::errc::invalid_argument);
     149             :     }
     150       75538 :     *plen = atoi(str.c_str() + pos + 1);
     151       75538 :     if ((*plen < 0) || (*plen > Address::kMaxV6PrefixLen)) {
     152           5 :         return make_error_code(boost::system::errc::invalid_argument);
     153             :     }
     154             : 
     155       75533 :     string addrstr = str.substr(0, pos);
     156       75533 :     boost::system::error_code err;
     157       75533 :     *addr = Ip6Address::from_string(addrstr, err);
     158       75533 :     return err;
     159       75533 : }
     160             : 
     161             : // Return the bitwise and of IP and mask.
     162       75126 : boost::system::error_code Inet6SubnetParse(const string &str, Ip6Address *addr,
     163             :                                            int *plen) {
     164       75126 :     Ip6Address address;
     165       75126 :     boost::system::error_code err;
     166       75126 :     err = Inet6PrefixParse(str, &address, plen);
     167       75126 :     if (!err) {
     168       75094 :         *addr = Address::GetIp6SubnetAddress(address, *plen);
     169             :     }
     170       75126 :     return err;
     171             : }
     172             : 
     173             : /* Returns IPv4 subnet address for a given IPv4 address and prefix length. The
     174             :  * IPv4 address and prefix lengths are converted to u32 numbers and then bitwise
     175             :  * AND operation is performed between those 2 numbers and the resulting u32
     176             :  * number is converted to IPv4Address object and returned. If prefix length is 0
     177             :  * then 0 is converted to IPv4Address object and returned.
     178             :  */
     179      819872 : Ip4Address Address::GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen) {
     180      819872 :     if (plen == 0) {
     181       21156 :         return boost::asio::ip::address_v4(0);
     182             :     }
     183             : 
     184      798716 :     Ip4Address subnet(prefix.to_ulong() & (0xFFFFFFFF << (32 - plen)));
     185      798718 :     return subnet;
     186             : }
     187             : 
     188             : /* Returns IPv6 subnet address for a given IPv6 address and prefix length. The
     189             :  * input IPv6 address is first converted into an array of 8 two byte integers.
     190             :  * Based on prefix length we first figure out the array index position from
     191             :  * where the masking of bits needs to start. Once the array index is found we
     192             :  * have 16 possible bit positions from where masking has to start. For each of
     193             :  * the 16 positions we have a unique 16 byte constant that we use to mask the
     194             :  * two byte integer. Once the array position is appropriately masked we mask
     195             :  * the rest of two byte integers till the array ends. The resulting array is
     196             :  * converted to IPv6 object and returned. If the prefix length is 0 then we
     197             :  * return an IPv6 object constructed using its default constructors which
     198             :  * assumes all bits as 0s.
     199             :  */
     200     1421119 : Ip6Address Address::GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen) {
     201     1421119 :     if (plen == 0) {
     202        9615 :         return boost::asio::ip::address_v6();
     203             :     }
     204             : 
     205     1411504 :     if (plen == 128) {
     206      174036 :         return prefix;
     207             :     }
     208             : 
     209             :     uint16_t ip6[8], in_ip6[8];
     210             :     unsigned char bytes[16];
     211             : 
     212     1237468 :     inet_pton(AF_INET6, prefix.to_string().c_str(), ip6);
     213             : 
     214    11137212 :     for (int i = 0; i < 8; ++i) {
     215     9899744 :         in_ip6[i] = ntohs(ip6[i]);
     216             :     }
     217             : 
     218     1237468 :     int index = (int) (plen / 16);
     219     1237468 :     int remain_mask = plen % 16;
     220             : 
     221     1237468 :     switch (remain_mask) {
     222       79897 :         case 0:
     223       79897 :             in_ip6[index++] = 0;
     224       79897 :             break;
     225       74415 :         case 1:
     226       74415 :             in_ip6[index++] &= 0x8000;
     227       74415 :             break;
     228       74415 :         case 2:
     229       74415 :             in_ip6[index++] &= 0xc000;
     230       74415 :             break;
     231       74415 :         case 3:
     232       74415 :             in_ip6[index++] &= 0xe000;
     233       74415 :             break;
     234       74430 :         case 4:
     235       74430 :             in_ip6[index++] &= 0xf000;
     236       74430 :             break;
     237       74415 :         case 5:
     238       74415 :             in_ip6[index++] &= 0xf800;
     239       74415 :             break;
     240       74416 :         case 6:
     241       74416 :             in_ip6[index++] &= 0xfc00;
     242       74416 :             break;
     243       74418 :         case 7:
     244       74418 :             in_ip6[index++] &= 0xfe00;
     245       74418 :             break;
     246      107129 :         case 8:
     247      107129 :             in_ip6[index++] &= 0xff00;
     248      107129 :             break;
     249       74449 :         case  9:
     250       74449 :             in_ip6[index++] &= 0xff80;
     251       74449 :             break;
     252       74450 :         case 10:
     253       74450 :             in_ip6[index++] &= 0xffc0;
     254       74450 :             break;
     255       74661 :         case 11:
     256       74661 :             in_ip6[index++] &= 0xffe0;
     257       74661 :             break;
     258       74469 :         case 12:
     259       74469 :             in_ip6[index++] &= 0xfff0;
     260       74469 :             break;
     261       74449 :         case 13:
     262       74449 :             in_ip6[index++] &= 0xfff8;
     263       74449 :             break;
     264       74585 :         case 14:
     265       74585 :             in_ip6[index++] &= 0xfffc;
     266       74585 :             break;
     267       82455 :         case 15:
     268       82455 :             in_ip6[index++] &= 0xfffe;
     269       82455 :             break;
     270             :     }
     271             : 
     272     5402414 :     for (int i = index; i < 8; ++i) {
     273     4164946 :         in_ip6[i] = 0;
     274             :     }
     275             : 
     276    11137212 :     for (int i = 0; i < 8; ++i) {
     277     9899744 :         ip6[i] = htons(in_ip6[i]);
     278             :     }
     279     1237468 :     memcpy(bytes, ip6, sizeof(ip6));
     280             :     Ip6Address::bytes_type to_bytes;
     281    21036956 :     for (int i = 0; i < 16; ++i) {
     282    19799488 :         to_bytes.at(i) = bytes[i];
     283             :     }
     284     1237468 :     return boost::asio::ip::address_v6(to_bytes);
     285             : }
     286             : 
     287             : // Ip6Address.to_v4() has exceptions. Plus, we dont have a to_v4() version
     288             : // without exceptions that takes an boost::error_code.
     289             : // If the v6-address is v4_mapped, return the ipv4 equivalent address. Else
     290             : // return a 'zero' ipv4 address.
     291       31501 : Ip4Address Address::V4FromV4MappedV6(const Ip6Address &v6_address) {
     292       31501 :     Ip4Address v4_address;
     293       31501 :     if (v6_address.is_v4_mapped()) {
     294       31501 :         Ip6Address::bytes_type v6_bt = v6_address.to_bytes();
     295             :         Ip4Address::bytes_type v4_bt =
     296       31501 :             { { v6_bt[12], v6_bt[13], v6_bt[14], v6_bt[15] } };
     297       31501 :         v4_address = Ip4Address(v4_bt);
     298             :     }
     299       31501 :     return v4_address;
     300             : }

Generated by: LCOV version 1.14