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-08 02:02:55 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       81038 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
      35       81038 : }
      36             : 
      37        2513 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
      38        2513 :     const Ip4Address &group, const Ip4Address &source)
      39        2513 :     : type_(type), rd_(rd), group_(group), source_(source) {
      40        2512 : }
      41             : 
      42        2243 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
      43             :     const Ip4Address &router_id,
      44        2243 :     const Ip4Address &group, const Ip4Address &source)
      45        2243 :     : type_(type), rd_(rd), router_id_(router_id),
      46        2243 :       group_(group), source_(source) {
      47        2243 : }
      48             : 
      49        4844 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
      50             :     ErmVpnPrefix *prefix) {
      51        4844 :     size_t rd_size = RouteDistinguisher::kSize;
      52        4844 :     size_t rtid_size = Address::kMaxV4Bytes;
      53        4844 :     size_t nlri_size = proto_prefix.prefix.size();
      54        4844 :     size_t expected_nlri_size =
      55        4844 :         rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
      56             : 
      57        4844 :     if (!IsValidForBgp(proto_prefix.type))
      58           3 :         return -1;
      59        4841 :     if (nlri_size != expected_nlri_size)
      60           3 :         return -1;
      61             : 
      62        4838 :     prefix->type_ = proto_prefix.type;
      63        4838 :     size_t rd_offset = 0;
      64        4838 :     prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
      65        4838 :     size_t rtid_offset = rd_offset + rd_size;
      66             :     prefix->router_id_ =
      67        4838 :         Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
      68             : 
      69        4838 :     size_t source_offset = rtid_offset + rtid_size + 1;
      70        4838 :     if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
      71           4 :         return -1;
      72        4834 :     prefix->source_ = Ip4Address(
      73        9668 :         get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
      74             : 
      75        4834 :     size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
      76        4834 :     if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
      77           4 :         return -1;
      78        4830 :     prefix->group_ = Ip4Address(
      79        9660 :         get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
      80             : 
      81        4830 :     return 0;
      82             : }
      83             : 
      84        4828 : 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        4828 :     return FromProtoPrefix(proto_prefix, prefix);
      92             : }
      93             : 
      94        4250 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
      95        4250 :     assert(IsValidForBgp(type_));
      96             : 
      97        4250 :     size_t rd_size = RouteDistinguisher::kSize;
      98        4250 :     size_t rtid_size = Address::kMaxV4Bytes;
      99             : 
     100        4250 :     proto_prefix->type = type_;
     101        4250 :     proto_prefix->prefix.clear();
     102        4250 :     proto_prefix->prefixlen =
     103        4250 :         (rd_size + rtid_size +  2 * (1 + Address::kMaxV4Bytes)) * 8;
     104        4250 :     proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
     105             : 
     106        4250 :     size_t rd_offset = 0;
     107        4250 :     copy(rd_.GetData(), rd_.GetData() + rd_size,
     108        4250 :         proto_prefix->prefix.begin() + rd_offset);
     109             : 
     110        4250 :     size_t rtid_offset = rd_offset + rd_size;
     111        4250 :     const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
     112        4250 :     copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
     113        4250 :         proto_prefix->prefix.begin() + rtid_offset);
     114             : 
     115        4250 :     size_t source_offset = rtid_offset + rtid_size + 1;
     116        4250 :     proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
     117        4250 :     const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
     118        4250 :     copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
     119        4250 :         proto_prefix->prefix.begin() + source_offset);
     120             : 
     121        4250 :     size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
     122        4250 :     proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
     123        4250 :     const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
     124        4250 :     copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
     125        4250 :         proto_prefix->prefix.begin() + group_offset);
     126        4250 : }
     127             : 
     128       38099 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
     129             :     boost::system::error_code *errorp) {
     130       38099 :     ErmVpnPrefix prefix, null_prefix;
     131       38099 :     string temp_str;
     132             : 
     133             :     // Look for Type.
     134       38099 :     size_t pos1 = str.find('-');
     135       38099 :     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       38098 :     temp_str = str.substr(0, pos1);
     142       38098 :     stringToInteger(temp_str, prefix.type_);
     143       38098 :     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       38097 :     size_t pos2 = str.find('-', pos1 + 1);
     152       38097 :     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       38096 :     temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
     159       38096 :     boost::system::error_code rd_err;
     160       38096 :     prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
     161       38096 :     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       38095 :     size_t pos3 = str.find(',', pos2 + 1);
     170       38095 :     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       38094 :     temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
     177       38094 :     boost::system::error_code rtid_err;
     178       38094 :     prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
     179       38094 :     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       38093 :     size_t pos4 = str.find(',', pos3 + 1);
     188       38093 :     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       38092 :     temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
     195       38092 :     boost::system::error_code group_err;
     196       38092 :     prefix.group_ = Ip4Address::from_string(temp_str, group_err);
     197       38092 :     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       38091 :     temp_str = str.substr(pos4 + 1, string::npos);
     206       38091 :     boost::system::error_code source_err;
     207       38091 :     prefix.source_ = Ip4Address::from_string(temp_str, source_err);
     208       38091 :     if (source_err.failed()) {
     209           1 :         if (errorp != NULL) {
     210           1 :             *errorp = source_err;
     211             :         }
     212           1 :         return null_prefix;
     213             :     }
     214             : 
     215       38090 :     return prefix;
     216       38099 : }
     217             : 
     218       45980 : string ErmVpnPrefix::ToString() const {
     219       45980 :     string repr = integerToString(type_);
     220       45980 :     repr += "-" + rd_.ToString();
     221       45980 :     repr += "-" + router_id_.to_string();
     222       45980 :     repr += "," + group_.to_string();
     223       45980 :     repr += "," + source_.to_string();
     224       45980 :     return repr;
     225           0 : }
     226             : 
     227         586 : string ErmVpnPrefix::ToXmppIdString() const {
     228         586 :     assert(type_ == 0);
     229         586 :     string repr = rd_.ToString();
     230         586 :     repr += ":" + group_.to_string();
     231         586 :     repr += "," + source_.to_string();
     232         586 :     return repr;
     233           0 : }
     234             : 
     235       46546 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
     236       46546 :     return (type == LocalTreeRoute || type == GlobalTreeRoute);
     237             : }
     238             : 
     239       38104 : bool ErmVpnPrefix::IsValid(uint8_t type) {
     240       38104 :     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       69290 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
     253       69289 : }
     254             : 
     255      245703 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
     256      245703 :     const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
     257      245703 :     KEY_COMPARE(prefix_.source(), other.prefix_.source());
     258      243807 :     KEY_COMPARE(prefix_.group(), other.prefix_.group());
     259      136806 :     KEY_COMPARE(prefix_.type(), other.prefix_.type());
     260      107497 :     KEY_COMPARE(
     261             :         prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
     262       80236 :     KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
     263       65936 :     return 0;
     264             : }
     265             : 
     266       45968 : string ErmVpnRoute::ToString() const {
     267       45968 :     return prefix_.ToString();
     268             : }
     269             : 
     270        2887 : string ErmVpnRoute::ToXmppIdString() const {
     271        2887 :     if (xmpp_id_str_.empty())
     272         584 :         xmpp_id_str_ = prefix_.ToXmppIdString();
     273        2887 :     return xmpp_id_str_;
     274             : }
     275             : 
     276       21829 : bool ErmVpnRoute::IsValid() const {
     277       21829 :     if (!BgpRoute::IsValid())
     278        5163 :         return false;
     279             : 
     280       16666 :     const BgpAttr *attr = BestPath()->GetAttr();
     281       16666 :     switch (prefix_.type()) {
     282        5133 :     case ErmVpnPrefix::NativeRoute:
     283        5133 :         return attr->label_block().get() != NULL;
     284        5178 :     case ErmVpnPrefix::LocalTreeRoute:
     285        5178 :         return attr->edge_discovery() != NULL;
     286        6355 :     case ErmVpnPrefix::GlobalTreeRoute:
     287        6355 :         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        4250 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
     302             :     const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
     303        4250 :     prefix_.BuildProtoPrefix(prefix);
     304        4250 : }
     305             : 
     306        2861 : void ErmVpnRoute::BuildBgpProtoNextHop(
     307             :     vector<uint8_t> &nh, IpAddress nexthop) const {
     308        2861 :     nh.resize(4);
     309        2861 :     const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
     310        2861 :     copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
     311        2861 : }
     312             : 
     313         813 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
     314             :     ErmVpnTable::RequestKey *key;
     315         813 :     key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
     316         813 :     return KeyPtr(key);
     317             : }
     318             : 
     319        9098 : const std::string ErmVpnPrefix::GetType() const {
     320        9098 :     switch (type_) {
     321         382 :     case NativeRoute:
     322         382 :         return "NativeRoute";
     323           0 :     case LocalTreeRoute:
     324           0 :         return "LocalTreeRoute";
     325        8716 :     case GlobalTreeRoute:
     326        8716 :         return "GlobalTreeRoute";
     327           0 :     case Invalid:
     328           0 :         return "Invalid";
     329             :     }
     330           0 :     return "";
     331             : }
     332             : 
     333        9098 : const std::string ErmVpnRoute::GetType() const {
     334        9098 :     return GetPrefix().GetType();
     335             : }

Generated by: LCOV version 1.14