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

Generated by: LCOV version 1.14