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-09-07 02:14:47 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       34643 : Address::Family Address::FamilyFromString(const std::string &family) {
      55             :     std::map<string, Address::Family>::const_iterator loc =
      56       34643 :             fromString.find(family);
      57       34643 :     if (loc != fromString.end()) {
      58       34643 :         return loc->second;
      59             :     }
      60           0 :     return Address::UNSPEC;
      61             : }
      62             : 
      63     3501305 : std::string Address::FamilyToString(Address::Family family) {
      64     7002497 :     return toString.find(family)->second;
      65             : }
      66             : 
      67      257393 : std::string Address::FamilyToTableString(Address::Family family) {
      68      514659 :     return toTableName.find(family)->second;
      69             : }
      70             : 
      71        5555 : Address::Family Address::VpnFamilyFromFamily(Address::Family family) {
      72        5555 :     switch (family) {
      73        5267 :     case Address::INET:
      74             :     case Address::INETVPN:
      75        5267 :         return Address::INETVPN;
      76          87 :     case Address::INET6:
      77             :     case Address::INET6VPN:
      78          87 :         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          79 :     default:
      86          79 :         return Address::UNSPEC;
      87             :     }
      88             :     return Address::UNSPEC;
      89             : }
      90             : 
      91      157594 : static int CountDots(const string &str) {
      92      157594 :     int count = 0;
      93      157594 :     size_t pos = 0;
      94      617776 :     while (pos < str.size()) {
      95      617780 :         pos = str.find('.', pos);
      96      617774 :         if (pos == string::npos) {
      97      157592 :             break;
      98             :         }
      99      460182 :         count++;
     100      460182 :         pos++;
     101             :     }
     102      157594 :     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      178231 : boost::system::error_code Ip4PrefixParse(const string &str, Ip4Address *addr,
     108             :                                          int *plen) {
     109      178231 :     size_t pos = str.find('/');
     110      178231 :     if (pos == string::npos) {
     111          35 :         return make_error_code(boost::system::errc::invalid_argument);
     112             :     }
     113      178196 :     *plen = atoi(str.c_str() + pos + 1);
     114      178196 :     if ((*plen < 0) || (*plen > Address::kMaxV4PrefixLen)) {
     115       20602 :         return make_error_code(boost::system::errc::invalid_argument);
     116             :     }
     117             : 
     118      157594 :     string addrstr = str.substr(0, pos);
     119      157594 :     int dots = CountDots(addrstr);
     120      170193 :     while (dots < 3) {
     121       12599 :         addrstr.append(".0");
     122       12599 :         dots++;
     123             :     }
     124             : 
     125      157594 :     boost::system::error_code err;
     126      157594 :     *addr = Ip4Address::from_string(addrstr, err);
     127      157594 :     return err;
     128      157594 : }
     129             : 
     130             : // Return the bitwise and of IP and mask.
     131      174334 : boost::system::error_code Ip4SubnetParse(const string &str, Ip4Address *addr,
     132             :                                          int *plen) {
     133      174334 :     Ip4Address address;
     134      174334 :     boost::system::error_code err;
     135      174334 :     err = Ip4PrefixParse(str, &address, plen);
     136      174336 :     if (!err) {
     137      152216 :         *addr = Address::GetIp4SubnetAddress(address, *plen);
     138             :     }
     139      174336 :     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       75509 : boost::system::error_code Inet6PrefixParse(const string &str, Ip6Address *addr,
     145             :                                            int *plen) {
     146       75509 :     size_t pos = str.find('/');
     147       75509 :     if (pos == string::npos) {
     148          24 :         return make_error_code(boost::system::errc::invalid_argument);
     149             :     }
     150       75485 :     *plen = atoi(str.c_str() + pos + 1);
     151       75485 :     if ((*plen < 0) || (*plen > Address::kMaxV6PrefixLen)) {
     152           5 :         return make_error_code(boost::system::errc::invalid_argument);
     153             :     }
     154             : 
     155       75480 :     string addrstr = str.substr(0, pos);
     156       75481 :     boost::system::error_code err;
     157       75481 :     *addr = Ip6Address::from_string(addrstr, err);
     158       75481 :     return err;
     159       75481 : }
     160             : 
     161             : // Return the bitwise and of IP and mask.
     162       75071 : boost::system::error_code Inet6SubnetParse(const string &str, Ip6Address *addr,
     163             :                                            int *plen) {
     164       75071 :     Ip6Address address;
     165       75073 :     boost::system::error_code err;
     166       75073 :     err = Inet6PrefixParse(str, &address, plen);
     167       75074 :     if (!err) {
     168       75042 :         *addr = Address::GetIp6SubnetAddress(address, *plen);
     169             :     }
     170       75074 :     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      930903 : Ip4Address Address::GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen) {
     180      930903 :     if (plen == 0) {
     181       23839 :         return boost::asio::ip::address_v4(0);
     182             :     }
     183             : 
     184      907064 :     Ip4Address subnet(prefix.to_ulong() & (0xFFFFFFFF << (32 - plen)));
     185      907064 :     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     1431280 : Ip6Address Address::GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen) {
     201     1431280 :     if (plen == 0) {
     202        9690 :         return boost::asio::ip::address_v6();
     203             :     }
     204             : 
     205     1421590 :     if (plen == 128) {
     206      173982 :         return prefix;
     207             :     }
     208             : 
     209             :     uint16_t ip6[8], in_ip6[8];
     210             :     unsigned char bytes[16];
     211             : 
     212     1247608 :     inet_pton(AF_INET6, prefix.to_string().c_str(), ip6);
     213             : 
     214    11228472 :     for (int i = 0; i < 8; ++i) {
     215     9980864 :         in_ip6[i] = ntohs(ip6[i]);
     216             :     }
     217             : 
     218     1247608 :     int index = (int) (plen / 16);
     219     1247608 :     int remain_mask = plen % 16;
     220             : 
     221     1247608 :     switch (remain_mask) {
     222       80484 :         case 0:
     223       80484 :             in_ip6[index++] = 0;
     224       80484 :             break;
     225       75026 :         case 1:
     226       75026 :             in_ip6[index++] &= 0x8000;
     227       75026 :             break;
     228       75022 :         case 2:
     229       75022 :             in_ip6[index++] &= 0xc000;
     230       75022 :             break;
     231       75022 :         case 3:
     232       75022 :             in_ip6[index++] &= 0xe000;
     233       75022 :             break;
     234       75037 :         case 4:
     235       75037 :             in_ip6[index++] &= 0xf000;
     236       75037 :             break;
     237       75022 :         case 5:
     238       75022 :             in_ip6[index++] &= 0xf800;
     239       75022 :             break;
     240       75023 :         case 6:
     241       75023 :             in_ip6[index++] &= 0xfc00;
     242       75023 :             break;
     243       75025 :         case 7:
     244       75025 :             in_ip6[index++] &= 0xfe00;
     245       75025 :             break;
     246      108104 :         case 8:
     247      108104 :             in_ip6[index++] &= 0xff00;
     248      108104 :             break;
     249       75057 :         case  9:
     250       75057 :             in_ip6[index++] &= 0xff80;
     251       75057 :             break;
     252       75058 :         case 10:
     253       75058 :             in_ip6[index++] &= 0xffc0;
     254       75058 :             break;
     255       75269 :         case 11:
     256       75269 :             in_ip6[index++] &= 0xffe0;
     257       75269 :             break;
     258       75141 :         case 12:
     259       75141 :             in_ip6[index++] &= 0xfff0;
     260       75141 :             break;
     261       75057 :         case 13:
     262       75057 :             in_ip6[index++] &= 0xfff8;
     263       75057 :             break;
     264       75193 :         case 14:
     265       75193 :             in_ip6[index++] &= 0xfffc;
     266       75193 :             break;
     267       83068 :         case 15:
     268       83068 :             in_ip6[index++] &= 0xfffe;
     269       83068 :             break;
     270             :     }
     271             : 
     272     5448876 :     for (int i = index; i < 8; ++i) {
     273     4201268 :         in_ip6[i] = 0;
     274             :     }
     275             : 
     276    11228472 :     for (int i = 0; i < 8; ++i) {
     277     9980864 :         ip6[i] = htons(in_ip6[i]);
     278             :     }
     279     1247608 :     memcpy(bytes, ip6, sizeof(ip6));
     280             :     Ip6Address::bytes_type to_bytes;
     281    21209336 :     for (int i = 0; i < 16; ++i) {
     282    19961728 :         to_bytes.at(i) = bytes[i];
     283             :     }
     284     1247608 :     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       31428 : Ip4Address Address::V4FromV4MappedV6(const Ip6Address &v6_address) {
     292       31428 :     Ip4Address v4_address;
     293       31428 :     if (v6_address.is_v4_mapped()) {
     294       31428 :         Ip6Address::bytes_type v6_bt = v6_address.to_bytes();
     295             :         Ip4Address::bytes_type v4_bt =
     296       31428 :             { { v6_bt[12], v6_bt[13], v6_bt[14], v6_bt[15] } };
     297       31428 :         v4_address = Ip4Address(v4_bt);
     298             :     }
     299       31428 :     return v4_address;
     300             : }

Generated by: LCOV version 1.14