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: 23 237 9.7 %
Date: 2026-09-28 02:13:17 Functions: 6 22 27.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           0 : size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) {
      22           0 :     if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) {
      23           0 :         if (prefix.mac_addr().IsBroadcast())
      24           0 :             return 0;
      25           0 :         const uint8_t *data = prefix.mac_addr().GetData();
      26           0 :         uint32_t value = get_value(data + 2, 4);
      27           0 :         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         378 : EvpnTable::EvpnTable(DB *db, const string &name)
      40         378 :     : BgpTable(db, name), evpn_manager_(NULL) {
      41         378 :     mac_route_count_ = 0;
      42         378 :     unique_mac_route_count_ = 0;
      43         378 :     im_route_count_ = 0;
      44         378 :     ip_route_count_ = 0;
      45         378 : }
      46             : 
      47           0 : unique_ptr<DBEntry> EvpnTable::AllocEntry(
      48             :         const DBRequestKey *key) const {
      49           0 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      50           0 :     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           0 : void EvpnTable::AddRemoveCallback(const DBEntryBase *entry, bool add) const {
      60           0 :     if (IsVpnTable())
      61           0 :         return;
      62           0 :     const EvpnRoute *evpn_rt = static_cast<const EvpnRoute *>(entry);
      63           0 :     const EvpnPrefix &evpn_prefix = evpn_rt->GetPrefix();
      64           0 :     switch (evpn_prefix.type()) {
      65           0 :     case EvpnPrefix::MacAdvertisementRoute:
      66             :         // Ignore Broadcast MAC routes.
      67           0 :         if (evpn_prefix.mac_addr().IsBroadcast())
      68           0 :             break;
      69             : 
      70           0 :         if (add) {
      71           0 :             mac_route_count_++;
      72             :         } else {
      73           0 :             mac_route_count_--;
      74             :         }
      75             : 
      76             :         // Ignore MAC routes with IP addresses.
      77           0 :         if (evpn_prefix.family() != Address::UNSPEC)
      78           0 :             break;
      79             : 
      80           0 :         if (add) {
      81           0 :             unique_mac_route_count_++;
      82             :         } else {
      83           0 :             unique_mac_route_count_--;
      84             :         }
      85           0 :         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           0 : size_t EvpnTable::Hash(const DBRequestKey *key) const {
     109           0 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
     110           0 :     size_t value = HashFunction(rkey->prefix);
     111           0 :     return value % DB::PartitionCount();
     112             : }
     113             : 
     114           0 : size_t EvpnTable::Hash(const DBEntry *entry) const {
     115           0 :     const EvpnRoute *rt_entry = static_cast<const EvpnRoute *>(entry);
     116           0 :     size_t value = HashFunction(rt_entry->GetPrefix());
     117           0 :     return value % DB::PartitionCount();
     118             : }
     119             : 
     120           0 : BgpRoute *EvpnTable::TableFind(DBTablePartition *rtp,
     121             :         const DBRequestKey *prefix) {
     122           0 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
     123           0 :     EvpnRoute rt_key(pfxkey->prefix);
     124           0 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
     125           0 : }
     126             : 
     127           0 : PathResolver *EvpnTable::CreatePathResolver() {
     128           0 :     if (routing_instance()->IsMasterRoutingInstance())
     129           0 :         return NULL;
     130           0 :     return (new PathResolver(this));
     131             : }
     132             : 
     133         378 : DBTableBase *EvpnTable::CreateTable(DB *db, const string &name) {
     134         378 :     EvpnTable *table = new EvpnTable(db, name);
     135         378 :     table->Init();
     136         378 :     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           0 : 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           0 :     if (IsMaster())
     160           0 :         return true;
     161             : 
     162             :     // Always replicate Type-5 routes.
     163           0 :     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           0 :         dynamic_cast<const EvpnTable *>(src_table);
     169           0 :     if (!src_evpn_table->IsMaster())
     170           0 :         return false;
     171             : 
     172             :     // Replicate to VRF from the VPN table if OriginVn matches.
     173           0 :     if (community->ContainsOriginVn(server->autonomous_system(),
     174           0 :                        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           0 :     if (evpn_prefix.type() != EvpnPrefix::AutoDiscoveryRoute)
     180           0 :         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           0 : BgpRoute *EvpnTable::RouteReplicate(BgpServer *server,
     195             :         BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
     196             :         ExtCommunityPtr community) {
     197           0 :     assert(src_table->family() == Address::EVPN);
     198           0 :     EvpnRoute *evpn_rt = dynamic_cast<EvpnRoute *>(src_rt);
     199           0 :     assert(evpn_rt);
     200           0 :     EvpnPrefix evpn_prefix(evpn_rt->GetPrefix());
     201             : 
     202             :     // Check if this evpn route should be replicated.
     203           0 :     if (!ShouldReplicate(server, src_table, community, evpn_prefix))
     204           0 :         return NULL;
     205           0 :     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           0 :     if (evpn_prefix.type() == EvpnPrefix::SegmentRoute)
     212           0 :         return NULL;
     213           0 :     if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute &&
     214           0 :         evpn_prefix.mac_addr().IsBroadcast())
     215           0 :         return NULL;
     216             : 
     217           0 :     BgpAttrDB *attr_db = server->attr_db();
     218           0 :     BgpAttrPtr new_attr(src_path->GetAttr());
     219             : 
     220           0 :     if (IsMaster()) {
     221           0 :         if (evpn_prefix.route_distinguisher().IsZero()) {
     222           0 :             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           0 :                 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           0 :     EvpnRoute rt_key(evpn_prefix);
     245             : 
     246             :     // Find or create the route.
     247             :     DBTablePartition *rtp =
     248           0 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     249           0 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     250           0 :     if (dest_route == NULL) {
     251           0 :         dest_route = new EvpnRoute(evpn_prefix);
     252           0 :         rtp->Add(dest_route);
     253             :     } else {
     254           0 :         dest_route->ClearDelete();
     255             :     }
     256             : 
     257           0 :     new_attr = attr_db->ReplaceExtCommunityAndLocate(new_attr.get(), community);
     258             : 
     259             :     // Check whether peer already has a path
     260           0 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     261             :             src_path->GetSource(), src_path->GetPeer(),
     262             :             src_path->GetPathId());
     263           0 :     if (dest_path != NULL) {
     264           0 :         if ((new_attr != dest_path->GetOriginalAttr()) ||
     265           0 :             (src_path->GetFlags() != dest_path->GetFlags()) ||
     266           0 :             (src_path->GetLabel() != dest_path->GetLabel()) ||
     267           0 :             (src_path->GetL3Label() != dest_path->GetL3Label())) {
     268           0 :             if (dest_path->NeedsResolution()) {
     269           0 :                 path_resolver()->StopPathResolution(rtp->index(), dest_path);
     270             :             }
     271           0 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     272             :                 src_path->GetSource(), src_path->GetPeer(),
     273             :                 src_path->GetPathId());
     274           0 :             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           0 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     283           0 :                              src_path->GetSource(), new_attr,
     284           0 :                              src_path->GetFlags(), src_path->GetLabel(),
     285           0 :                              src_path->GetL3Label());
     286           0 :     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           0 :     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           0 :     dest_route->InsertPath(replicated_path);
     302             : 
     303             :     // Always trigger notification.
     304           0 :     rtp->Notify(dest_route);
     305             : 
     306           0 :     return dest_route;
     307           0 : }
     308             : 
     309           0 : bool EvpnTable::Export(RibOut *ribout, Route *route,
     310             :         const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     311           0 :     EvpnRoute *evpn_route = dynamic_cast<EvpnRoute *>(route);
     312           0 :     assert(evpn_route);
     313             : 
     314           0 :     if (ribout->IsEncodingBgp()) {
     315           0 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     316           0 :         if (!uinfo)
     317           0 :             return false;
     318           0 :         uinfo_slist->push_front(*uinfo);
     319           0 :         return true;
     320             :     }
     321             : 
     322           0 :     const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
     323           0 :     if (evpn_prefix.type() != EvpnPrefix::MacAdvertisementRoute &&
     324           0 :             evpn_prefix.type() != EvpnPrefix::IpPrefixRoute &&
     325           0 :             evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute) {
     326           0 :         return false;
     327             :     }
     328             : 
     329           0 :     if (!evpn_prefix.mac_addr().IsBroadcast() &&
     330           0 :             (evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute)) {
     331           0 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
     332           0 :         if (!uinfo)
     333           0 :             return false;
     334           0 :         uinfo_slist->push_front(*uinfo);
     335           0 :         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         378 : void EvpnTable::CreateEvpnManager() {
     359         378 :     if (IsVpnTable())
     360         378 :         return;
     361           0 :     assert(!evpn_manager_);
     362           0 :     evpn_manager_ = BgpStaticObjectFactory::Create<EvpnManager>(this);
     363           0 :     evpn_manager_->Initialize();
     364             : }
     365             : 
     366           0 : void EvpnTable::DestroyEvpnManager() {
     367           0 :     assert(evpn_manager_);
     368           0 :     evpn_manager_->Terminate();
     369           0 :     delete evpn_manager_;
     370           0 :     evpn_manager_ = NULL;
     371           0 : }
     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         378 : void EvpnTable::set_routing_instance(RoutingInstance *rtinstance) {
     382         378 :     BgpTable::set_routing_instance(rtinstance);
     383         378 :     CreateEvpnManager();
     384         378 : }
     385             : 
     386        1134 : bool EvpnTable::IsMaster() const {
     387        1134 :     return routing_instance()->IsMasterRoutingInstance();
     388             : }
     389             : 
     390           1 : static void RegisterFactory() {
     391           1 :     DB::RegisterFactory("evpn.0", &EvpnTable::CreateTable);
     392           1 : }
     393             : 
     394             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14