LCOV - code coverage report
Current view: top level - bgp/ermvpn - ermvpn_route.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 198 208 95.2 %
Date: 2026-06-04 02:06:09 Functions: 23 23 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/ermvpn/ermvpn_route.h"
       6             : 
       7             : #include <algorithm>
       8             : #include <string>
       9             : #include <vector>
      10             : 
      11             : #include "base/string_util.h"
      12             : #include "bgp/ermvpn/ermvpn_table.h"
      13             : 
      14             : using std::copy;
      15             : using std::string;
      16             : using std::vector;
      17             : 
      18             : // BgpProtoPrefix format for erm-vpn prefix.
      19             : //
      20             : // +------------------------------------+
      21             : // |      RD   (8 octets)               |
      22             : // +------------------------------------+
      23             : // |  Router-Id (4 octets)              |
      24             : // +------------------------------------+
      25             : // |  Multicast Source length (1 octet) |
      26             : // +------------------------------------+
      27             : // |  Multicast Source (4)              |
      28             : // +------------------------------------+
      29             : // |  Multicast Group length (1 octet)  |
      30             : // +------------------------------------+
      31             : // |  Multicast Group (4)               |
      32             : // +------------------------------------+
      33             : 
      34       80336 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
      35       80336 : }
      36             : 
      37        2510 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
      38        2510 :     const Ip4Address &group, const Ip4Address &source)
      39        2510 :     : type_(type), rd_(rd), group_(group), source_(source) {
      40        2510 : }
      41             : 
      42        2240 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
      43             :     const Ip4Address &router_id,
      44        2240 :     const Ip4Address &group, const Ip4Address &source)
      45        2240 :     : type_(type), rd_(rd), router_id_(router_id),
      46        2240 :       group_(group), source_(source) {
      47        2240 : }
      48             : 
      49        4774 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
      50             :     ErmVpnPrefix *prefix) {
      51        4774 :     size_t rd_size = RouteDistinguisher::kSize;
      52        4774 :     size_t rtid_size = Address::kMaxV4Bytes;
      53        4774 :     size_t nlri_size = proto_prefix.prefix.size();
      54        4774 :     size_t expected_nlri_size =
      55        4774 :         rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
      56             : 
      57        4774 :     if (!IsValidForBgp(proto_prefix.type))
      58           3 :         return -1;
      59        4771 :     if (nlri_size != expected_nlri_size)
      60           3 :         return -1;
      61             : 
      62        4768 :     prefix->type_ = proto_prefix.type;
      63        4768 :     size_t rd_offset = 0;
      64        4768 :     prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
      65        4768 :     size_t rtid_offset = rd_offset + rd_size;
      66             :     prefix->router_id_ =
      67        4768 :         Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
      68             : 
      69        4768 :     size_t source_offset = rtid_offset + rtid_size + 1;
      70        4768 :     if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
      71           4 :         return -1;
      72        4764 :     prefix->source_ = Ip4Address(
      73        9528 :         get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
      74             : 
      75        4764 :     size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
      76        4764 :     if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
      77           4 :         return -1;
      78        4760 :     prefix->group_ = Ip4Address(
      79        9520 :         get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
      80             : 
      81        4760 :     return 0;
      82             : }
      83             : 
      84        4758 : int ErmVpnPrefix::FromProtoPrefix(BgpServer *server,
      85             :                                   const BgpProtoPrefix &proto_prefix,
      86             :                                   const BgpAttr *attr,
      87             :                                   const Address::Family family,
      88             :                                   ErmVpnPrefix *prefix,
      89             :                                   BgpAttrPtr *new_attr, uint32_t *label,
      90             :                                   uint32_t *l3_label) {
      91        4758 :     return FromProtoPrefix(proto_prefix, prefix);
      92             : }
      93             : 
      94        4199 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
      95        4199 :     assert(IsValidForBgp(type_));
      96             : 
      97        4199 :     size_t rd_size = RouteDistinguisher::kSize;
      98        4199 :     size_t rtid_size = Address::kMaxV4Bytes;
      99             : 
     100        4199 :     proto_prefix->type = type_;
     101        4199 :     proto_prefix->prefix.clear();
     102        4199 :     proto_prefix->prefixlen =
     103        4199 :         (rd_size + rtid_size +  2 * (1 + Address::kMaxV4Bytes)) * 8;
     104        4199 :     proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
     105             : 
     106        4199 :     size_t rd_offset = 0;
     107        4199 :     copy(rd_.GetData(), rd_.GetData() + rd_size,
     108        4199 :         proto_prefix->prefix.begin() + rd_offset);
     109             : 
     110        4199 :     size_t rtid_offset = rd_offset + rd_size;
     111        4199 :     const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
     112        4199 :     copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
     113        4199 :         proto_prefix->prefix.begin() + rtid_offset);
     114             : 
     115        4199 :     size_t source_offset = rtid_offset + rtid_size + 1;
     116        4199 :     proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
     117        4199 :     const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
     118        4199 :     copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
     119        4199 :         proto_prefix->prefix.begin() + source_offset);
     120             : 
     121        4199 :     size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
     122        4199 :     proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
     123        4199 :     const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
     124        4199 :     copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
     125        4199 :         proto_prefix->prefix.begin() + group_offset);
     126        4199 : }
     127             : 
     128       37783 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
     129             :     boost::system::error_code *errorp) {
     130       37783 :     ErmVpnPrefix prefix, null_prefix;
     131       37783 :     string temp_str;
     132             : 
     133             :     // Look for Type.
     134       37783 :     size_t pos1 = str.find('-');
     135       37783 :     if (pos1 == string::npos) {
     136           1 :         if (errorp != NULL) {
     137           1 :             *errorp = make_error_code(boost::system::errc::invalid_argument);
     138             :         }
     139           1 :         return null_prefix;
     140             :     }
     141       37782 :     temp_str = str.substr(0, pos1);
     142       37782 :     stringToInteger(temp_str, prefix.type_);
     143       37782 :     if (!IsValid(prefix.type_)) {
     144           1 :         if (errorp != NULL) {
     145           1 :             *errorp = make_error_code(boost::system::errc::invalid_argument);
     146             :         }
     147           1 :         return null_prefix;
     148             :     }
     149             : 
     150             :     // Look for RD.
     151       37781 :     size_t pos2 = str.find('-', pos1 + 1);
     152       37781 :     if (pos2 == string::npos) {
     153           1 :         if (errorp != NULL) {
     154           1 :             *errorp = make_error_code(boost::system::errc::invalid_argument);
     155             :         }
     156           1 :         return null_prefix;
     157             :     }
     158       37780 :     temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
     159       37780 :     boost::system::error_code rd_err;
     160       37780 :     prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
     161       37780 :     if (rd_err.failed()) {
     162           1 :         if (errorp != NULL) {
     163           1 :             *errorp = rd_err;
     164             :         }
     165           1 :         return null_prefix;
     166             :     }
     167             : 
     168             :     // Look for router-id.
     169       37779 :     size_t pos3 = str.find(',', pos2 + 1);
     170       37779 :     if (pos3 == string::npos) {
     171           1 :         if (errorp != NULL) {
     172           1 :             *errorp = make_error_code(boost::system::errc::invalid_argument);
     173             :         }
     174           1 :         return null_prefix;
     175             :     }
     176       37778 :     temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
     177       37778 :     boost::system::error_code rtid_err;
     178       37778 :     prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
     179       37778 :     if (rtid_err.failed()) {
     180           1 :         if (errorp != NULL) {
     181           1 :             *errorp = rtid_err;
     182             :         }
     183           1 :         return null_prefix;
     184             :     }
     185             : 
     186             :     // Look for group.
     187       37777 :     size_t pos4 = str.find(',', pos3 + 1);
     188       37777 :     if (pos4 == string::npos) {
     189           1 :         if (errorp != NULL) {
     190           1 :             *errorp = make_error_code(boost::system::errc::invalid_argument);
     191             :         }
     192           1 :         return null_prefix;
     193             :     }
     194       37776 :     temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
     195       37776 :     boost::system::error_code group_err;
     196       37776 :     prefix.group_ = Ip4Address::from_string(temp_str, group_err);
     197       37776 :     if (group_err.failed()) {
     198           1 :         if (errorp != NULL) {
     199           1 :             *errorp = group_err;
     200             :         }
     201           1 :         return null_prefix;
     202             :     }
     203             : 
     204             :     // Rest is source.
     205       37775 :     temp_str = str.substr(pos4 + 1, string::npos);
     206       37775 :     boost::system::error_code source_err;
     207       37775 :     prefix.source_ = Ip4Address::from_string(temp_str, source_err);
     208       37775 :     if (source_err.failed()) {
     209           1 :         if (errorp != NULL) {
     210           1 :             *errorp = source_err;
     211             :         }
     212           1 :         return null_prefix;
     213             :     }
     214             : 
     215       37774 :     return prefix;
     216       37783 : }
     217             : 
     218       46028 : string ErmVpnPrefix::ToString() const {
     219       46028 :     string repr = integerToString(type_);
     220       46028 :     repr += "-" + rd_.ToString();
     221       46028 :     repr += "-" + router_id_.to_string();
     222       46028 :     repr += "," + group_.to_string();
     223       46028 :     repr += "," + source_.to_string();
     224       46028 :     return repr;
     225           0 : }
     226             : 
     227         583 : string ErmVpnPrefix::ToXmppIdString() const {
     228         583 :     assert(type_ == 0);
     229         583 :     string repr = rd_.ToString();
     230         583 :     repr += ":" + group_.to_string();
     231         583 :     repr += "," + source_.to_string();
     232         583 :     return repr;
     233           0 : }
     234             : 
     235       46109 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
     236       46109 :     return (type == LocalTreeRoute || type == GlobalTreeRoute);
     237             : }
     238             : 
     239       37788 : bool ErmVpnPrefix::IsValid(uint8_t type) {
     240       37788 :     return (type == NativeRoute || IsValidForBgp(type));
     241             : }
     242             : 
     243          14 : bool ErmVpnPrefix::operator==(const ErmVpnPrefix &rhs) const {
     244             :     return (
     245          28 :         type_ == rhs.type_ &&
     246          28 :         rd_ == rhs.rd_ &&
     247          28 :         router_id_ == rhs.router_id_ &&
     248          42 :         group_ == rhs.group_ &&
     249          28 :         source_ == rhs.source_);
     250             : }
     251             : 
     252       68881 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
     253       68867 : }
     254             : 
     255      244265 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
     256      244265 :     const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
     257      244265 :     KEY_COMPARE(prefix_.source(), other.prefix_.source());
     258      242454 :     KEY_COMPARE(prefix_.group(), other.prefix_.group());
     259      136071 :     KEY_COMPARE(prefix_.type(), other.prefix_.type());
     260      107094 :     KEY_COMPARE(
     261             :         prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
     262       80024 :     KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
     263       65805 :     return 0;
     264             : }
     265             : 
     266       46016 : string ErmVpnRoute::ToString() const {
     267       46016 :     return prefix_.ToString();
     268             : }
     269             : 
     270        2895 : string ErmVpnRoute::ToXmppIdString() const {
     271        2895 :     if (xmpp_id_str_.empty())
     272         581 :         xmpp_id_str_ = prefix_.ToXmppIdString();
     273        2895 :     return xmpp_id_str_;
     274             : }
     275             : 
     276       21932 : bool ErmVpnRoute::IsValid() const {
     277       21932 :     if (!BgpRoute::IsValid())
     278        5164 :         return false;
     279             : 
     280       16768 :     const BgpAttr *attr = BestPath()->GetAttr();
     281       16768 :     switch (prefix_.type()) {
     282        5266 :     case ErmVpnPrefix::NativeRoute:
     283        5266 :         return attr->label_block().get() != NULL;
     284        5132 :     case ErmVpnPrefix::LocalTreeRoute:
     285        5132 :         return attr->edge_discovery() != NULL;
     286        6370 :     case ErmVpnPrefix::GlobalTreeRoute:
     287        6370 :         return attr->edge_forwarding() != NULL;
     288           0 :     case ErmVpnPrefix::Invalid:
     289           0 :         break;
     290             :     }
     291             : 
     292           0 :     return false;
     293             : }
     294             : 
     295           3 : void ErmVpnRoute::SetKey(const DBRequestKey *reqkey) {
     296           3 :     const ErmVpnTable::RequestKey *key =
     297             :         static_cast<const ErmVpnTable::RequestKey *>(reqkey);
     298           3 :     prefix_ = key->prefix;
     299           3 : }
     300             : 
     301        4199 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
     302             :     const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
     303        4199 :     prefix_.BuildProtoPrefix(prefix);
     304        4199 : }
     305             : 
     306        2839 : void ErmVpnRoute::BuildBgpProtoNextHop(
     307             :     vector<uint8_t> &nh, IpAddress nexthop) const {
     308        2839 :     nh.resize(4);
     309        2839 :     const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
     310        2839 :     copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
     311        2839 : }
     312             : 
     313         826 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
     314             :     ErmVpnTable::RequestKey *key;
     315         826 :     key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
     316         826 :     return KeyPtr(key);
     317             : }
     318             : 
     319        9110 : const std::string ErmVpnPrefix::GetType() const {
     320        9110 :     switch (type_) {
     321         392 :     case NativeRoute:
     322         392 :         return "NativeRoute";
     323           0 :     case LocalTreeRoute:
     324           0 :         return "LocalTreeRoute";
     325        8718 :     case GlobalTreeRoute:
     326        8718 :         return "GlobalTreeRoute";
     327           0 :     case Invalid:
     328           0 :         return "Invalid";
     329             :     }
     330           0 :     return "";
     331             : }
     332             : 
     333        9110 : const std::string ErmVpnRoute::GetType() const {
     334        9110 :     return GetPrefix().GetType();
     335             : }

Generated by: LCOV version 1.14