LCOV - code coverage report
Current view: top level - bgp/evpn - evpn_table.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 145 237 61.2 %
Date: 2026-10-05 02:12:29 Functions: 17 22 77.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 "bgp/evpn/evpn_table.h"
       6             : 
       7             : #include "bgp/ipeer.h"
       8             : #include "bgp/bgp_factory.h"
       9             : #include "bgp/bgp_evpn.h"
      10             : #include "bgp/bgp_server.h"
      11             : #include "bgp/bgp_update.h"
      12             : #include "bgp/inet/inet_table.h"
      13             : #include "bgp/inet6/inet6_table.h"
      14             : #include "bgp/origin-vn/origin_vn.h"
      15             : #include "bgp/routing-instance/path_resolver.h"
      16             : #include "bgp/routing-instance/routing_instance.h"
      17             : 
      18             : using std::unique_ptr;
      19             : using std::string;
      20             : 
      21      124686 : size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) {
      22      124686 :     if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) {
      23      124686 :         if (prefix.mac_addr().IsBroadcast())
      24           0 :             return 0;
      25      124686 :         const uint8_t *data = prefix.mac_addr().GetData();
      26      124686 :         uint32_t value = get_value(data + 2, 4);
      27      124686 :         return boost::hash_value(value);
      28             :     }
      29           0 :     if (prefix.type() == EvpnPrefix::IpPrefixRoute) {
      30           0 :         if (prefix.ip_address().is_v4()) {
      31           0 :             return InetTable::HashFunction(prefix.inet_prefix());
      32             :         } else {
      33           0 :             return Inet6Table::HashFunction(prefix.inet6_prefix());
      34             :         }
      35             :     }
      36           0 :     return 0;
      37             : }
      38             : 
      39         578 : EvpnTable::EvpnTable(DB *db, const string &name)
      40         578 :     : BgpTable(db, name), evpn_manager_(NULL) {
      41         578 :     mac_route_count_ = 0;
      42         578 :     unique_mac_route_count_ = 0;
      43         578 :     im_route_count_ = 0;
      44         578 :     ip_route_count_ = 0;
      45         578 : }
      46             : 
      47       11972 : unique_ptr<DBEntry> EvpnTable::AllocEntry(
      48             :         const DBRequestKey *key) const {
      49       11972 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      50       11972 :     return unique_ptr<DBEntry> (new EvpnRoute(pfxkey->prefix));
      51             : }
      52             : 
      53           0 : unique_ptr<DBEntry> EvpnTable::AllocEntryStr(
      54             :         const string &key_str) const {
      55           0 :     EvpnPrefix prefix = EvpnPrefix::FromString(key_str);
      56           0 :     return unique_ptr<DBEntry> (new EvpnRoute(prefix));
      57             : }
      58             : 
      59        7424 : void EvpnTable::AddRemoveCallback(const DBEntryBase *entry, bool add) const {
      60        7424 :     if (IsVpnTable())
      61        6400 :         return;
      62        1024 :     const EvpnRoute *evpn_rt = static_cast<const EvpnRoute *>(entry);
      63        1024 :     const EvpnPrefix &evpn_prefix = evpn_rt->GetPrefix();
      64        1024 :     switch (evpn_prefix.type()) {
      65        1024 :     case EvpnPrefix::MacAdvertisementRoute:
      66             :         // Ignore Broadcast MAC routes.
      67        1024 :         if (evpn_prefix.mac_addr().IsBroadcast())
      68           0 :             break;
      69             : 
      70        1024 :         if (add) {
      71         512 :             mac_route_count_++;
      72             :         } else {
      73         512 :             mac_route_count_--;
      74             :         }
      75             : 
      76             :         // Ignore MAC routes with IP addresses.
      77        1024 :         if (evpn_prefix.family() != Address::UNSPEC)
      78           0 :             break;
      79             : 
      80        1024 :         if (add) {
      81         512 :             unique_mac_route_count_++;
      82             :         } else {
      83         512 :             unique_mac_route_count_--;
      84             :         }
      85        1024 :         break;
      86             : 
      87           0 :     case EvpnPrefix::InclusiveMulticastRoute:
      88           0 :         if (add) {
      89           0 :             im_route_count_++;
      90             :         } else {
      91           0 :             im_route_count_--;
      92             :         }
      93           0 :         break;
      94             : 
      95           0 :     case EvpnPrefix::IpPrefixRoute:
      96           0 :         if (add) {
      97           0 :             ip_route_count_++;
      98             :         } else {
      99           0 :             ip_route_count_--;
     100             :         }
     101           0 :         break;
     102             : 
     103           0 :     default:
     104           0 :         break;
     105             :     }
     106             : }
     107             : 
     108        3840 : size_t EvpnTable::Hash(const DBRequestKey *key) const {
     109        3840 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
     110        3840 :     size_t value = HashFunction(rkey->prefix);
     111        3840 :     return value % DB::PartitionCount();
     112             : }
     113             : 
     114      120846 : size_t EvpnTable::Hash(const DBEntry *entry) const {
     115      120846 :     const EvpnRoute *rt_entry = static_cast<const EvpnRoute *>(entry);
     116      120846 :     size_t value = HashFunction(rt_entry->GetPrefix());
     117      120846 :     return value % DB::PartitionCount();
     118             : }
     119             : 
     120        3840 : BgpRoute *EvpnTable::TableFind(DBTablePartition *rtp,
     121             :         const DBRequestKey *prefix) {
     122        3840 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
     123        3840 :     EvpnRoute rt_key(pfxkey->prefix);
     124        7680 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
     125        3840 : }
     126             : 
     127         160 : PathResolver *EvpnTable::CreatePathResolver() {
     128         160 :     if (routing_instance()->IsMasterRoutingInstance())
     129           0 :         return NULL;
     130         160 :     return (new PathResolver(this));
     131             : }
     132             : 
     133         578 : DBTableBase *EvpnTable::CreateTable(DB *db, const string &name) {
     134         578 :     EvpnTable *table = new EvpnTable(db, name);
     135         578 :     table->Init();
     136         578 :     return table;
     137             : }
     138             : 
     139             : // Find the route.
     140           0 : EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) {
     141           0 :     EvpnRoute rt_key(prefix);
     142             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     143           0 :         GetTablePartition(&rt_key));
     144           0 :     return dynamic_cast<EvpnRoute *>(rtp->Find(&rt_key));
     145           0 : }
     146             : 
     147           0 : const EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) const {
     148           0 :     EvpnRoute rt_key(prefix);
     149             :     const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
     150           0 :         GetTablePartition(&rt_key));
     151           0 :     return dynamic_cast<const EvpnRoute *>(rtp->Find(&rt_key));
     152           0 : }
     153             : 
     154       16128 : bool EvpnTable::ShouldReplicate(const BgpServer *server,
     155             :                                 const BgpTable *src_table,
     156             :                                 const ExtCommunityPtr community,
     157             :                                 const  EvpnPrefix &evpn_prefix) const {
     158             :     // Always replicate into master table.
     159       16128 :     if (IsMaster())
     160        1024 :         return true;
     161             : 
     162             :     // Always replicate Type-5 routes.
     163       15104 :     if (evpn_prefix.type() == EvpnPrefix::IpPrefixRoute)
     164           0 :         return true;
     165             : 
     166             :     // Don't replicate to a VRF from other VRF tables.
     167             :     const EvpnTable *src_evpn_table =
     168       15104 :         dynamic_cast<const EvpnTable *>(src_table);
     169       15104 :     if (!src_evpn_table->IsMaster())
     170        3072 :         return false;
     171             : 
     172             :     // Replicate to VRF from the VPN table if OriginVn matches.
     173       24064 :     if (community->ContainsOriginVn(server->autonomous_system(),
     174       12032 :                        routing_instance()->virtual_network_index())) {
     175           0 :         return true;
     176             :     }
     177             : 
     178             :     // Do not replicate non AD routes as the OriginVN does not match.
     179       12032 :     if (evpn_prefix.type() != EvpnPrefix::AutoDiscoveryRoute)
     180       12032 :         return false;
     181             : 
     182           0 :     string es_target = server->autonomous_system() > 0xffFF ?
     183           0 :         integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS4) :
     184           0 :         integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS2);
     185             : 
     186             :     // Replicate if AD route target is associated with the route.
     187           0 :     RouteTarget rtarget = RouteTarget::FromString("target:" +
     188           0 :         integerToString(server->autonomous_system()) + ":" + es_target);
     189           0 :     if (community->ContainsRTarget(rtarget.GetExtCommunity()))
     190           0 :         return true;
     191           0 :     return false;
     192           0 : }
     193             : 
     194       16128 : BgpRoute *EvpnTable::RouteReplicate(BgpServer *server,
     195             :         BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
     196             :         ExtCommunityPtr community) {
     197       16128 :     assert(src_table->family() == Address::EVPN);
     198       16128 :     EvpnRoute *evpn_rt = dynamic_cast<EvpnRoute *>(src_rt);
     199       16128 :     assert(evpn_rt);
     200       16128 :     EvpnPrefix evpn_prefix(evpn_rt->GetPrefix());
     201             : 
     202             :     // Check if this evpn route should be replicated.
     203       16128 :     if (!ShouldReplicate(server, src_table, community, evpn_prefix))
     204       15104 :         return NULL;
     205        1024 :     if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute) {
     206           0 :         if (IsMaster() || evpn_prefix.tag() != EvpnPrefix::kMaxTag)
     207           0 :             return NULL;
     208           0 :         community = server->extcomm_db()->ReplaceRTargetAndLocate(
     209           0 :             community.get(), ExtCommunity::ExtCommunityList());
     210             :     }
     211        1024 :     if (evpn_prefix.type() == EvpnPrefix::SegmentRoute)
     212           0 :         return NULL;
     213        2048 :     if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute &&
     214        1024 :         evpn_prefix.mac_addr().IsBroadcast())
     215           0 :         return NULL;
     216             : 
     217        1024 :     BgpAttrDB *attr_db = server->attr_db();
     218        1024 :     BgpAttrPtr new_attr(src_path->GetAttr());
     219             : 
     220        1024 :     if (IsMaster()) {
     221        1024 :         if (evpn_prefix.route_distinguisher().IsZero()) {
     222        1024 :             if (new_attr->sub_protocol() == "bgpaas") {
     223           0 :                 boost::system::error_code ec;
     224             :                 Ip4Address addr =
     225           0 :                     Ip4Address::from_string(src_path->GetPeer()->ToString(), ec);
     226           0 :                 if ((ec.value() != 0)) {
     227           0 :                     evpn_prefix.set_route_distinguisher(new_attr->source_rd());
     228             :                 } else {
     229             :                     RouteDistinguisher new_source_rd =
     230           0 :                         RouteDistinguisher(addr.to_ulong(), 0);
     231           0 :                     evpn_prefix.set_route_distinguisher(new_source_rd);
     232             :                 }
     233             :             } else {
     234        1024 :                 evpn_prefix.set_route_distinguisher(new_attr->source_rd());
     235             :             }
     236             :         }
     237             :     } else {
     238           0 :         if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute ||
     239           0 :             evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute ||
     240           0 :             evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) {
     241           0 :             evpn_prefix.set_route_distinguisher(RouteDistinguisher::kZeroRd);
     242             :         }
     243             :     }
     244        1024 :     EvpnRoute rt_key(evpn_prefix);
     245             : 
     246             :     // Find or create the route.
     247             :     DBTablePartition *rtp =
     248        1024 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     249        1024 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     250        1024 :     if (dest_route == NULL) {
     251         512 :         dest_route = new EvpnRoute(evpn_prefix);
     252         512 :         rtp->Add(dest_route);
     253             :     } else {
     254         512 :         dest_route->ClearDelete();
     255             :     }
     256             : 
     257        1024 :     new_attr = attr_db->ReplaceExtCommunityAndLocate(new_attr.get(), community);
     258             : 
     259             :     // Check whether peer already has a path
     260        1024 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     261             :             src_path->GetSource(), src_path->GetPeer(),
     262             :             src_path->GetPathId());
     263        1024 :     if (dest_path != NULL) {
     264        1024 :         if ((new_attr != dest_path->GetOriginalAttr()) ||
     265         512 :             (src_path->GetFlags() != dest_path->GetFlags()) ||
     266        1024 :             (src_path->GetLabel() != dest_path->GetLabel()) ||
     267           0 :             (src_path->GetL3Label() != dest_path->GetL3Label())) {
     268         512 :             if (dest_path->NeedsResolution()) {
     269           0 :                 path_resolver()->StopPathResolution(rtp->index(), dest_path);
     270             :             }
     271         512 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     272             :                 src_path->GetSource(), src_path->GetPeer(),
     273             :                 src_path->GetPathId());
     274         512 :             assert(success);
     275             :         } else {
     276           0 :             return dest_route;
     277             :         }
     278             :     }
     279             : 
     280             :     // Create replicated path and insert it on the route
     281             :     BgpSecondaryPath *replicated_path =
     282        1024 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     283        1024 :                              src_path->GetSource(), new_attr,
     284        1024 :                              src_path->GetFlags(), src_path->GetLabel(),
     285        2048 :                              src_path->GetL3Label());
     286        1024 :     replicated_path->SetReplicateInfo(src_table, src_rt);
     287             : 
     288             :     // For VPN to VRF replication, start path resolution if fast convergence is
     289             :     // enabled and update path flag to indicate need for resolution.
     290        1024 :     if (!IsMaster() && server->IsNextHopCheckEnabled() &&
     291           0 :         (replicated_path->GetSource() == BgpPath::BGP_XMPP)) {
     292           0 :         Address::Family family = src_path->GetAttr()->nexthop_family();
     293           0 :         RoutingInstanceMgr *mgr = server->routing_instance_mgr();
     294           0 :         RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance();
     295           0 :         BgpTable *table = master_ri->GetTable(family);
     296           0 :         replicated_path->SetResolveNextHop();
     297           0 :         path_resolver()->StartPathResolution(dest_route,
     298             :                                              replicated_path, table);
     299             :     }
     300             : 
     301        1024 :     dest_route->InsertPath(replicated_path);
     302             : 
     303             :     // Always trigger notification.
     304        1024 :     rtp->Notify(dest_route);
     305             : 
     306        1024 :     return dest_route;
     307        1024 : }
     308             : 
     309        8710 : bool EvpnTable::Export(RibOut *ribout, Route *route,
     310             :         const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     311        8710 :     EvpnRoute *evpn_route = dynamic_cast<EvpnRoute *>(route);
     312        8710 :     assert(evpn_route);
     313             : 
     314        8710 :     if (ribout->IsEncodingBgp()) {
     315        7260 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     316        7260 :         if (!uinfo)
     317        3429 :             return false;
     318        3831 :         uinfo_slist->push_front(*uinfo);
     319        3831 :         return true;
     320             :     }
     321             : 
     322        1450 :     const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
     323        1450 :     if (evpn_prefix.type() != EvpnPrefix::MacAdvertisementRoute &&
     324        1450 :             evpn_prefix.type() != EvpnPrefix::IpPrefixRoute &&
     325           0 :             evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute) {
     326           0 :         return false;
     327             :     }
     328             : 
     329        2900 :     if (!evpn_prefix.mac_addr().IsBroadcast() &&
     330        1450 :             (evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute)) {
     331        1450 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     332        1450 :         if (!uinfo)
     333           0 :             return false;
     334        1450 :         uinfo_slist->push_front(*uinfo);
     335        1450 :         return true;
     336             :     }
     337             : 
     338           0 :     if (!evpn_manager_ || evpn_manager_->deleter()->IsDeleted())
     339           0 :         return false;
     340             : 
     341           0 :     const IPeer *peer = evpn_route->BestPath()->GetPeer();
     342           0 :     if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer)))
     343           0 :         return false;
     344             : 
     345           0 :     size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer));
     346           0 :     if (!peerset.test(peerbit))
     347           0 :         return false;
     348             : 
     349           0 :     UpdateInfo *uinfo = evpn_manager_->GetUpdateInfo(evpn_route);
     350           0 :     if (!uinfo)
     351           0 :         return false;
     352             : 
     353           0 :     uinfo->target.set(peerbit);
     354           0 :     uinfo_slist->push_front(*uinfo);
     355           0 :     return true;
     356             : }
     357             : 
     358         578 : void EvpnTable::CreateEvpnManager() {
     359         578 :     if (IsVpnTable())
     360         418 :         return;
     361         160 :     assert(!evpn_manager_);
     362         160 :     evpn_manager_ = BgpStaticObjectFactory::Create<EvpnManager>(this);
     363         160 :     evpn_manager_->Initialize();
     364             : }
     365             : 
     366         160 : void EvpnTable::DestroyEvpnManager() {
     367         160 :     assert(evpn_manager_);
     368         160 :     evpn_manager_->Terminate();
     369         160 :     delete evpn_manager_;
     370         160 :     evpn_manager_ = NULL;
     371         160 : }
     372             : 
     373           0 : EvpnManager *EvpnTable::GetEvpnManager() {
     374           0 :     return evpn_manager_;
     375             : }
     376             : 
     377           0 : const EvpnManager *EvpnTable::GetEvpnManager() const {
     378           0 :     return evpn_manager_;
     379             : }
     380             : 
     381         578 : void EvpnTable::set_routing_instance(RoutingInstance *rtinstance) {
     382         578 :     BgpTable::set_routing_instance(rtinstance);
     383         578 :     CreateEvpnManager();
     384         578 : }
     385             : 
     386       58282 : bool EvpnTable::IsMaster() const {
     387       58282 :     return routing_instance()->IsMasterRoutingInstance();
     388             : }
     389             : 
     390           3 : static void RegisterFactory() {
     391           3 :     DB::RegisterFactory("evpn.0", &EvpnTable::CreateTable);
     392           3 : }
     393             : 
     394             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14