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

Generated by: LCOV version 1.14