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

Generated by: LCOV version 1.14