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: 219 237 92.4 %
Date: 2026-06-18 01:51:13 Functions: 21 22 95.5 %
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     1471402 : size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) {
      22     1471402 :     if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) {
      23      910101 :         if (prefix.mac_addr().IsBroadcast())
      24      116784 :             return 0;
      25      793313 :         const uint8_t *data = prefix.mac_addr().GetData();
      26      793309 :         uint32_t value = get_value(data + 2, 4);
      27      793307 :         return boost::hash_value(value);
      28             :     }
      29      561205 :     if (prefix.type() == EvpnPrefix::IpPrefixRoute) {
      30      379017 :         if (prefix.ip_address().is_v4()) {
      31      196753 :             return InetTable::HashFunction(prefix.inet_prefix());
      32             :         } else {
      33      182097 :             return Inet6Table::HashFunction(prefix.inet6_prefix());
      34             :         }
      35             :     }
      36      182143 :     return 0;
      37             : }
      38             : 
      39       51134 : EvpnTable::EvpnTable(DB *db, const string &name)
      40       51134 :     : BgpTable(db, name), evpn_manager_(NULL) {
      41       51134 :     mac_route_count_ = 0;
      42       51134 :     unique_mac_route_count_ = 0;
      43       51134 :     im_route_count_ = 0;
      44       51134 :     ip_route_count_ = 0;
      45       51134 : }
      46             : 
      47      131471 : unique_ptr<DBEntry> EvpnTable::AllocEntry(
      48             :         const DBRequestKey *key) const {
      49      131471 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      50      131471 :     return unique_ptr<DBEntry> (new EvpnRoute(pfxkey->prefix));
      51             : }
      52             : 
      53          22 : unique_ptr<DBEntry> EvpnTable::AllocEntryStr(
      54             :         const string &key_str) const {
      55          22 :     EvpnPrefix prefix = EvpnPrefix::FromString(key_str);
      56          44 :     return unique_ptr<DBEntry> (new EvpnRoute(prefix));
      57             : }
      58             : 
      59      163414 : void EvpnTable::AddRemoveCallback(const DBEntryBase *entry, bool add) const {
      60      163414 :     if (IsVpnTable())
      61       87203 :         return;
      62       76192 :     const EvpnRoute *evpn_rt = static_cast<const EvpnRoute *>(entry);
      63       76192 :     const EvpnPrefix &evpn_prefix = evpn_rt->GetPrefix();
      64       76217 :     switch (evpn_prefix.type()) {
      65       14933 :     case EvpnPrefix::MacAdvertisementRoute:
      66             :         // Ignore Broadcast MAC routes.
      67       14933 :         if (evpn_prefix.mac_addr().IsBroadcast())
      68        4302 :             break;
      69             : 
      70       10630 :         if (add) {
      71        5315 :             mac_route_count_++;
      72             :         } else {
      73        5315 :             mac_route_count_--;
      74             :         }
      75             : 
      76             :         // Ignore MAC routes with IP addresses.
      77       10632 :         if (evpn_prefix.family() != Address::UNSPEC)
      78        3456 :             break;
      79             : 
      80        7176 :         if (add) {
      81        3588 :             unique_mac_route_count_++;
      82             :         } else {
      83        3588 :             unique_mac_route_count_--;
      84             :         }
      85        7176 :         break;
      86             : 
      87        8964 :     case EvpnPrefix::InclusiveMulticastRoute:
      88        8964 :         if (add) {
      89        4482 :             im_route_count_++;
      90             :         } else {
      91        4482 :             im_route_count_--;
      92             :         }
      93        8964 :         break;
      94             : 
      95       50977 :     case EvpnPrefix::IpPrefixRoute:
      96       50977 :         if (add) {
      97       25499 :             ip_route_count_++;
      98             :         } else {
      99       25478 :             ip_route_count_--;
     100             :         }
     101       51013 :         break;
     102             : 
     103        1340 :     default:
     104        1340 :         break;
     105             :     }
     106             : }
     107             : 
     108      112396 : size_t EvpnTable::Hash(const DBRequestKey *key) const {
     109      112396 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
     110      112396 :     size_t value = HashFunction(rkey->prefix);
     111      112395 :     return value % DB::PartitionCount();
     112             : }
     113             : 
     114     1359156 : size_t EvpnTable::Hash(const DBEntry *entry) const {
     115     1359156 :     const EvpnRoute *rt_entry = static_cast<const EvpnRoute *>(entry);
     116     1359156 :     size_t value = HashFunction(rt_entry->GetPrefix());
     117     1358185 :     return value % DB::PartitionCount();
     118             : }
     119             : 
     120       69788 : BgpRoute *EvpnTable::TableFind(DBTablePartition *rtp,
     121             :         const DBRequestKey *prefix) {
     122       69788 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
     123       69788 :     EvpnRoute rt_key(pfxkey->prefix);
     124      139579 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
     125       69816 : }
     126             : 
     127       42907 : PathResolver *EvpnTable::CreatePathResolver() {
     128       42907 :     if (routing_instance()->IsMasterRoutingInstance())
     129           0 :         return NULL;
     130       42907 :     return (new PathResolver(this));
     131             : }
     132             : 
     133       51132 : DBTableBase *EvpnTable::CreateTable(DB *db, const string &name) {
     134       51132 :     EvpnTable *table = new EvpnTable(db, name);
     135       51134 :     table->Init();
     136       51134 :     return table;
     137             : }
     138             : 
     139             : // Find the route.
     140        1176 : EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) {
     141        1176 :     EvpnRoute rt_key(prefix);
     142             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     143        1176 :         GetTablePartition(&rt_key));
     144        2352 :     return dynamic_cast<EvpnRoute *>(rtp->Find(&rt_key));
     145        1176 : }
     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      197236 : 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      197236 :     if (IsMaster())
     160       66505 :         return true;
     161             : 
     162             :     // Always replicate Type-5 routes.
     163      130726 :     if (evpn_prefix.type() == EvpnPrefix::IpPrefixRoute)
     164       17593 :         return true;
     165             : 
     166             :     // Don't replicate to a VRF from other VRF tables.
     167             :     const EvpnTable *src_evpn_table =
     168      113136 :         dynamic_cast<const EvpnTable *>(src_table);
     169      113136 :     if (!src_evpn_table->IsMaster())
     170       19500 :         return false;
     171             : 
     172             :     // Replicate to VRF from the VPN table if OriginVn matches.
     173      187272 :     if (community->ContainsOriginVn(server->autonomous_system(),
     174       93636 :                        routing_instance()->virtual_network_index())) {
     175        3730 :         return true;
     176             :     }
     177             : 
     178             :     // Do not replicate non AD routes as the OriginVN does not match.
     179       89906 :     if (evpn_prefix.type() != EvpnPrefix::AutoDiscoveryRoute)
     180       89902 :         return false;
     181             : 
     182           4 :     string es_target = server->autonomous_system() > 0xffFF ?
     183           0 :         integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS4) :
     184           4 :         integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS2);
     185             : 
     186             :     // Replicate if AD route target is associated with the route.
     187           8 :     RouteTarget rtarget = RouteTarget::FromString("target:" +
     188          12 :         integerToString(server->autonomous_system()) + ":" + es_target);
     189           4 :     if (community->ContainsRTarget(rtarget.GetExtCommunity()))
     190           4 :         return true;
     191           0 :     return false;
     192           4 : }
     193             : 
     194      197237 : BgpRoute *EvpnTable::RouteReplicate(BgpServer *server,
     195             :         BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
     196             :         ExtCommunityPtr community) {
     197      197237 :     assert(src_table->family() == Address::EVPN);
     198      197236 :     EvpnRoute *evpn_rt = dynamic_cast<EvpnRoute *>(src_rt);
     199      197236 :     assert(evpn_rt);
     200      197236 :     EvpnPrefix evpn_prefix(evpn_rt->GetPrefix());
     201             : 
     202             :     // Check if this evpn route should be replicated.
     203      197223 :     if (!ShouldReplicate(server, src_table, community, evpn_prefix))
     204      109402 :         return NULL;
     205       87832 :     if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute) {
     206          74 :         if (IsMaster() || evpn_prefix.tag() != EvpnPrefix::kMaxTag)
     207          70 :             return NULL;
     208          12 :         community = server->extcomm_db()->ReplaceRTargetAndLocate(
     209          12 :             community.get(), ExtCommunity::ExtCommunityList());
     210             :     }
     211       87761 :     if (evpn_prefix.type() == EvpnPrefix::SegmentRoute)
     212           3 :         return NULL;
     213      117374 :     if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute &&
     214       29616 :         evpn_prefix.mac_addr().IsBroadcast())
     215       19950 :         return NULL;
     216             : 
     217       67805 :     BgpAttrDB *attr_db = server->attr_db();
     218       67802 :     BgpAttrPtr new_attr(src_path->GetAttr());
     219             : 
     220       67807 :     if (IsMaster()) {
     221       46488 :         if (evpn_prefix.route_distinguisher().IsZero()) {
     222       24904 :             if (new_attr->sub_protocol() == "bgpaas") {
     223        1175 :                 boost::system::error_code ec;
     224             :                 Ip4Address addr =
     225        1175 :                     Ip4Address::from_string(src_path->GetPeer()->ToString(), ec);
     226        1175 :                 if ((ec.value() != 0)) {
     227           0 :                     evpn_prefix.set_route_distinguisher(new_attr->source_rd());
     228             :                 } else {
     229             :                     RouteDistinguisher new_source_rd =
     230        1175 :                         RouteDistinguisher(addr.to_ulong(), 0);
     231        1175 :                     evpn_prefix.set_route_distinguisher(new_source_rd);
     232             :                 }
     233             :             } else {
     234       23729 :                 evpn_prefix.set_route_distinguisher(new_attr->source_rd());
     235             :             }
     236             :         }
     237             :     } else {
     238       42644 :         if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute ||
     239       42644 :             evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute ||
     240       19693 :             evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) {
     241       19227 :             evpn_prefix.set_route_distinguisher(RouteDistinguisher::kZeroRd);
     242             :         }
     243             :     }
     244       67811 :     EvpnRoute rt_key(evpn_prefix);
     245             : 
     246             :     // Find or create the route.
     247             :     DBTablePartition *rtp =
     248       67795 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     249       67768 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     250       67811 :     if (dest_route == NULL) {
     251       34694 :         dest_route = new EvpnRoute(evpn_prefix);
     252       34676 :         rtp->Add(dest_route);
     253             :     } else {
     254       33117 :         dest_route->ClearDelete();
     255             :     }
     256             : 
     257       67808 :     new_attr = attr_db->ReplaceExtCommunityAndLocate(new_attr.get(), community);
     258             : 
     259             :     // Check whether peer already has a path
     260       67813 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     261             :             src_path->GetSource(), src_path->GetPeer(),
     262             :             src_path->GetPathId());
     263       67812 :     if (dest_path != NULL) {
     264       53153 :         if ((new_attr != dest_path->GetOriginalAttr()) ||
     265       44825 :             (src_path->GetFlags() != dest_path->GetFlags()) ||
     266       74295 :             (src_path->GetLabel() != dest_path->GetLabel()) ||
     267       21142 :             (src_path->GetL3Label() != dest_path->GetL3Label())) {
     268        8332 :             if (dest_path->NeedsResolution()) {
     269           0 :                 path_resolver()->StopPathResolution(rtp->index(), dest_path);
     270             :             }
     271        8332 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     272             :                 src_path->GetSource(), src_path->GetPeer(),
     273             :                 src_path->GetPathId());
     274        8332 :             assert(success);
     275             :         } else {
     276       21138 :             return dest_route;
     277             :         }
     278             :     }
     279             : 
     280             :     // Create replicated path and insert it on the route
     281             :     BgpSecondaryPath *replicated_path =
     282       46674 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     283       46674 :                              src_path->GetSource(), new_attr,
     284       46675 :                              src_path->GetFlags(), src_path->GetLabel(),
     285       93349 :                              src_path->GetL3Label());
     286       46675 :     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       46673 :     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       46672 :     dest_route->InsertPath(replicated_path);
     302             : 
     303             :     // Always trigger notification.
     304       46669 :     rtp->Notify(dest_route);
     305             : 
     306       46667 :     return dest_route;
     307       67805 : }
     308             : 
     309       77377 : bool EvpnTable::Export(RibOut *ribout, Route *route,
     310             :         const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     311       77377 :     EvpnRoute *evpn_route = dynamic_cast<EvpnRoute *>(route);
     312       77377 :     assert(evpn_route);
     313             : 
     314       77377 :     if (ribout->IsEncodingBgp()) {
     315       62588 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     316       62589 :         if (!uinfo)
     317       28213 :             return false;
     318       34376 :         uinfo_slist->push_front(*uinfo);
     319       34376 :         return true;
     320             :     }
     321             : 
     322       14789 :     const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
     323       19068 :     if (evpn_prefix.type() != EvpnPrefix::MacAdvertisementRoute &&
     324       19068 :             evpn_prefix.type() != EvpnPrefix::IpPrefixRoute &&
     325        2500 :             evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute) {
     326        2402 :         return false;
     327             :     }
     328             : 
     329       22613 :     if (!evpn_prefix.mac_addr().IsBroadcast() &&
     330       10226 :             (evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute)) {
     331       10128 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     332       10128 :         if (!uinfo)
     333         458 :             return false;
     334        9670 :         uinfo_slist->push_front(*uinfo);
     335        9670 :         return true;
     336             :     }
     337             : 
     338        2259 :     if (!evpn_manager_ || evpn_manager_->deleter()->IsDeleted())
     339           0 :         return false;
     340             : 
     341        2259 :     const IPeer *peer = evpn_route->BestPath()->GetPeer();
     342        2259 :     if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer)))
     343          24 :         return false;
     344             : 
     345        2235 :     size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer));
     346        2235 :     if (!peerset.test(peerbit))
     347         223 :         return false;
     348             : 
     349        2012 :     UpdateInfo *uinfo = evpn_manager_->GetUpdateInfo(evpn_route);
     350        2012 :     if (!uinfo)
     351         250 :         return false;
     352             : 
     353        1762 :     uinfo->target.set(peerbit);
     354        1762 :     uinfo_slist->push_front(*uinfo);
     355        1762 :     return true;
     356             : }
     357             : 
     358       51133 : void EvpnTable::CreateEvpnManager() {
     359       51133 :     if (IsVpnTable())
     360        8227 :         return;
     361       42907 :     assert(!evpn_manager_);
     362       42907 :     evpn_manager_ = BgpStaticObjectFactory::Create<EvpnManager>(this);
     363       42907 :     evpn_manager_->Initialize();
     364             : }
     365             : 
     366       42907 : void EvpnTable::DestroyEvpnManager() {
     367       42907 :     assert(evpn_manager_);
     368       42907 :     evpn_manager_->Terminate();
     369       42907 :     delete evpn_manager_;
     370       42907 :     evpn_manager_ = NULL;
     371       42907 : }
     372             : 
     373         164 : EvpnManager *EvpnTable::GetEvpnManager() {
     374         164 :     return evpn_manager_;
     375             : }
     376             : 
     377         393 : const EvpnManager *EvpnTable::GetEvpnManager() const {
     378         393 :     return evpn_manager_;
     379             : }
     380             : 
     381       51133 : void EvpnTable::set_routing_instance(RoutingInstance *rtinstance) {
     382       51133 :     BgpTable::set_routing_instance(rtinstance);
     383       51134 :     CreateEvpnManager();
     384       51132 : }
     385             : 
     386     1653909 : bool EvpnTable::IsMaster() const {
     387     1653909 :     return routing_instance()->IsMasterRoutingInstance();
     388             : }
     389             : 
     390         159 : static void RegisterFactory() {
     391         159 :     DB::RegisterFactory("evpn.0", &EvpnTable::CreateTable);
     392         159 : }
     393             : 
     394             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14