LCOV - code coverage report
Current view: top level - vnsw/agent/oper - vxlan_routes_leaking.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 16 198 8.1 %
Date: 2026-08-03 02:19:58 Functions: 2 9 22.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright (c) 2022 - 2026 Matvey Kraposhin.
       4             :  * Copyright (c) 2024 - 2026 Elena Zizganova.
       5             :  */
       6             : 
       7             : #include <boost/uuid/uuid_io.hpp>
       8             : #include <boost/lexical_cast.hpp>
       9             : #include <cmn/agent_cmn.h>
      10             : 
      11             : #include <base/logging.h>
      12             : #include <oper/operdb_init.h>
      13             : #include <oper/route_common.h>
      14             : #include <oper/vrf.h>
      15             : #include <oper/bridge_route.h>
      16             : #include <oper/inet_unicast_route.h>
      17             : #include <oper/evpn_route.h>
      18             : #include <oper/agent_route.h>
      19             : #include <oper/agent_route_walker.h>
      20             : #include <oper/vn.h>
      21             : #include <oper/vrf.h>
      22             : #include <oper/vxlan_routing_manager.h>
      23             : #include <oper/tunnel_nh.h> //for tunnel interception
      24             : 
      25             : uint32_t VxlanRoutingManager::loc_sequence_ = 0;
      26             : 
      27             : /*
      28             :  *
      29             :  * Routes Leaking
      30             :  *
      31             :  */
      32             : 
      33         227 : bool VxlanRoutingManager::RouteNotify(DBTablePartBase *partition,
      34             :                                       DBEntryBase *e) {
      35             :     const InetUnicastRouteEntry *inet_rt =
      36         227 :         dynamic_cast<const InetUnicastRouteEntry*>(e);
      37         227 :     if (inet_rt) {
      38         132 :         if (IsBridgeVrf(inet_rt->vrf())) {
      39          69 :             return InetRouteNotify(partition, e);
      40             :         }
      41             :         // // Deactive redundant bgp paths by moving local peer
      42             :         // // path to top
      43             :         // if (IsRoutingVrf(inet_rt->vrf())) {
      44             :         //     const AgentPath * loc_vm_port =
      45             :         //         FindInterfacePathWithGivenPeer(inet_rt,
      46             :         //         routing_vrf_interface_peer_->GetType(), true);
      47             :         //     if (loc_vm_port) {
      48             :         //         Route::PathList & path_list =
      49             :         //             const_cast<Route::PathList &>(inet_rt->GetPathList());
      50             :         //         path_list.reverse();
      51             :         //     }
      52             :         // }
      53             :     }
      54             : 
      55             :     const EvpnRouteEntry *evpn_rt =
      56         158 :         dynamic_cast<const EvpnRouteEntry *>(e);
      57         158 :     if (evpn_rt && IsRoutingVrf(evpn_rt->vrf())) {
      58           0 :         return EvpnRouteNotify(partition, e);
      59             :     }
      60         158 :     return true;
      61             : }
      62             : 
      63             : /*
      64             :  *
      65             :  * 
      66             :  * Step 1. InetRouteNotify
      67             :  * Handles changes in inet routes originating from a bridge VRF.
      68             :  * Copies new routes to the routing VRF EVPN Type 5 table.
      69             :  * Or deletes old routes from the routing VRF EVPN Type 5 table.
      70             :  * 
      71             :  * 
      72             :  */
      73             : //Handles change in NH of local vm port path
      74             : //For all host routes with non local vm port path, evpn route in routing vrf
      75             : //need not be added. It should come from CN.
      76          69 : bool VxlanRoutingManager::InetRouteNotify(DBTablePartBase *partition,
      77             :                                           DBEntryBase *e) {
      78             :     const InetUnicastRouteEntry *inet_rt =
      79          69 :         dynamic_cast<const InetUnicastRouteEntry*>(e);
      80             : 
      81          96 :     if (inet_rt->prefix_address().is_v6() &&
      82          96 :         inet_rt->prefix_address().to_v6().is_link_local()) {
      83           9 :         return true;
      84             :     }
      85             : 
      86             :     const VrfEntry *routing_vrf =
      87          60 :         vrf_mapper_.GetRoutingVrfUsingAgentRoute(inet_rt);
      88          60 :     if (routing_vrf == NULL || routing_vrf == inet_rt->vrf()) {
      89          60 :         return true;
      90             :     }
      91             : 
      92             :     EvpnAgentRouteTable *evpn_table =
      93           0 :         dynamic_cast<EvpnAgentRouteTable *>(routing_vrf->GetEvpnRouteTable());
      94           0 :     if (evpn_table == NULL) {
      95           0 :         return true;
      96             :     }
      97             : 
      98           0 :     const AgentPath *local_vm_port_path = NULL;
      99           0 :     local_vm_port_path = inet_rt->FindIntfOrCompLocalVmPortPath();
     100             : 
     101             :     // if path with LOCAL_VM_PORT hasn't been found, then
     102             :     // this probably may mean that it was deleted
     103           0 :     if (local_vm_port_path == NULL) {
     104           0 :         ClearRedundantVrfPath(e);
     105           0 :         WhenBridgeInetIntfWasDeleted(inet_rt, routing_vrf);
     106           0 :         return true;
     107             :     }
     108             : 
     109           0 :     PathPreference preference = local_vm_port_path->path_preference();
     110           0 :     preference.set_loc_sequence(GetNewLocalSequence(local_vm_port_path));
     111             :     // preference.set_preference(100);
     112           0 :     VnListType dest_vns;
     113           0 :     dest_vns.insert(routing_vrf->vn()->GetName());
     114             : 
     115           0 :     CopyInterfacePathToEvpnTable(local_vm_port_path,
     116           0 :         inet_rt->prefix_address(),
     117           0 :         inet_rt->prefix_length(),
     118             :         routing_vrf_interface_peer_,  // agent->local_vm_export_peer(),
     119           0 :         RouteParameters(IpAddress(),  // not needed here
     120           0 :             MacAddress(),             // not needed here ?
     121             :             dest_vns,
     122             :             local_vm_port_path->sg_list(),
     123             :             local_vm_port_path->communities(),
     124             :             local_vm_port_path->tag_list(),
     125             :             preference,
     126             :             local_vm_port_path->ecmp_load_balance(),
     127             :             routing_vrf_interface_peer_->sequence_number()),
     128             :         evpn_table);
     129             : 
     130           0 :     return true;
     131           0 : }
     132             : 
     133             : /*
     134             :  * Step 2.
     135             :  * Copies a route from the routing VRF EVPN Type 5 table into the
     136             :  * routing VRF Inet table.
     137             :  *  
     138             :  */
     139           0 : bool VxlanRoutingManager::EvpnRouteNotify(DBTablePartBase *partition,
     140             :                                           DBEntryBase *e) {
     141             :     const EvpnRouteEntry *evpn_rt =
     142           0 :         dynamic_cast<const EvpnRouteEntry *>(e);
     143             : 
     144           0 :     if (evpn_rt->IsType5() == false) {
     145           0 :         return true;
     146             :     }
     147             : 
     148           0 :     VrfEntry *vrf = evpn_rt->vrf();
     149           0 :     const AgentPath *local_vm_port_path = evpn_rt->FindPath(
     150             :         routing_vrf_interface_peer_);
     151             : 
     152             :     const AgentPath *bgp_path =
     153           0 :         FindPathWithGivenPeer(evpn_rt, Peer::BGP_PEER);
     154             : 
     155           0 :     if (bgp_path) {
     156           0 :         XmppAdvertiseInetRoute(evpn_rt->prefix_address(),
     157           0 :             evpn_rt->prefix_length(), vrf->GetName(), bgp_path);
     158             :     }
     159             : 
     160           0 :     if (local_vm_port_path) {
     161           0 :         const NextHop *anh = local_vm_port_path->nexthop();
     162           0 :         if (anh == NULL) {
     163           0 :             return true;
     164             :         }
     165           0 :         CopyPathToInetTable(local_vm_port_path,
     166           0 :             evpn_rt->prefix_address(),
     167           0 :             evpn_rt->prefix_length(),
     168             :             routing_vrf_interface_peer_,
     169           0 :                 RouteParameters(IpAddress(),
     170           0 :                 MacAddress(),
     171             :                 local_vm_port_path->dest_vn_list(),
     172             :                 local_vm_port_path->sg_list(),
     173             :                 local_vm_port_path->communities(),
     174             :                 local_vm_port_path->tag_list(),
     175             :                 local_vm_port_path->path_preference(),
     176             :                 local_vm_port_path->ecmp_load_balance(),
     177             :                 routing_vrf_interface_peer_->sequence_number()),
     178           0 :             vrf->GetInetUnicastRouteTable(evpn_rt->prefix_address()));
     179             : 
     180           0 :         LeakRoutesIntoBridgeTables(partition,
     181             :             e, vrf->vn()->logical_router_uuid(), NULL, true);
     182             :     }
     183             : 
     184           0 :     if (bgp_path == NULL) {
     185             :         // the route might be deleted
     186           0 :         WhenRoutingEvpnRouteWasDeleted(evpn_rt,
     187             :             routing_vrf_vxlan_bgp_peer_);
     188             :     }
     189             : 
     190           0 :     if (local_vm_port_path == NULL) {
     191             :         // the route might be deleted
     192           0 :         WhenRoutingEvpnRouteWasDeleted(evpn_rt,
     193             :             routing_vrf_interface_peer_);
     194             :         // and/or it requires publishing in bridge
     195           0 :         LeakRoutesIntoBridgeTables(partition, e,
     196             :            vrf->vn()->logical_router_uuid(), NULL, true);
     197           0 :         return true;
     198             :     }
     199             : 
     200           0 :     return true;
     201             : }
     202             : 
     203             : /*
     204             :  *
     205             :  * Routes Deletion
     206             :  *
     207             :  */
     208           0 : void VxlanRoutingManager::ClearRedundantVrfPath(DBEntryBase *e) {
     209             :     InetUnicastRouteEntry *inet_route =
     210           0 :         dynamic_cast<InetUnicastRouteEntry*>(e);
     211           0 :     if (inet_route == NULL) {
     212           0 :         return;
     213             :     }
     214           0 :     if (inet_route->GetPathList().size() > 1 &&
     215           0 :         inet_route->FindPath(agent_->evpn_routing_peer())) {
     216           0 :         InetUnicastAgentRouteTable::Delete(agent_->evpn_routing_peer(),
     217             :             inet_route->vrf()->GetName(),
     218           0 :             inet_route->prefix_address(),
     219           0 :             inet_route->prefix_length());
     220             :     }
     221             : }
     222             : 
     223             : /*
     224             :  *
     225             :  * Step 1. If a route is deleted / changed in a bridge VRF INET,
     226             :  * then schedule deletion of a route / path in a routing VRF EVPN
     227             :  * Type 5.
     228             :  * 
     229             :  */
     230             : 
     231           0 : void VxlanRoutingManager::WhenBridgeInetIntfWasDeleted(
     232             :     const InetUnicastRouteEntry *inet_rt,
     233             :     const VrfEntry* routing_vrf) {
     234             : 
     235           0 :     if (inet_rt->FindPath(agent_->evpn_routing_peer())) {
     236           0 :         return;
     237             :     }
     238             : 
     239             :     // Check that this route is present in the routing VRF
     240             :     const EvpnAgentRouteTable *evpn_table =
     241           0 :         dynamic_cast<const EvpnAgentRouteTable *>
     242           0 :         (routing_vrf->GetEvpnRouteTable());
     243           0 :     if (evpn_table == NULL) {
     244           0 :         return;
     245             :     }
     246             : 
     247             :     const EvpnRouteEntry *evpn_rt =
     248             :         const_cast<EvpnAgentRouteTable *>
     249           0 :         (evpn_table)->FindRoute(MacAddress(),
     250           0 :         inet_rt->prefix_address(), inet_rt->prefix_length(), 0);
     251           0 :     if (RoutePrefixIsEqualTo(evpn_rt, inet_rt->prefix_address(), inet_rt->prefix_length()) == false) {
     252           0 :         if (inet_rt->IsDeleted()) {
     253             :             // That might be an IPAM route from neighb. bridge VRF instances.
     254           0 :             if (IsHostRoute(inet_rt->prefix_address(), inet_rt->prefix_length()) == false) {
     255           0 :                 DeleteIpamRoutes(inet_rt->vrf()->vn(),
     256             :                     inet_rt->vrf()->GetName(),
     257           0 :                     inet_rt->prefix_address(), inet_rt->prefix_length());
     258             :             }
     259             :         }
     260           0 :         return;
     261             :     }
     262             : 
     263           0 :     bool ok_to_delete = inet_rt->IsDeleted() ||
     264           0 :         evpn_rt->FindPath(routing_vrf_interface_peer_);
     265             : 
     266           0 :     if ((ok_to_delete) && (!inet_rt->origin_vn_name().empty()) &&
     267           0 :         (inet_rt->origin_vn_name()!=inet_rt->vrf()->vn()->GetName()) &&
     268           0 :         (inet_rt->origin_vn_name()!=routing_vrf->vn()->GetName())) {
     269           0 :         return;
     270             :     }
     271             : 
     272           0 :     if (ok_to_delete) {
     273             :         // Delete EVPN Type 5 record in the routing VRF
     274           0 :         EvpnAgentRouteTable::DeleteReq(
     275             :             routing_vrf_interface_peer_,
     276             :             routing_vrf->GetName(),
     277           0 :             MacAddress(),
     278           0 :             inet_rt->prefix_address(),
     279           0 :             inet_rt->prefix_length(),
     280             :             0,  // ethernet_tag = 0 for Type5
     281             :             NULL);
     282             :     }
     283             : }
     284             : 
     285             : /*
     286             :  *
     287             :  * Step 2. Delete the routing VRF Inet route
     288             :  * 
     289             :  */
     290           0 : void VxlanRoutingManager::WhenRoutingEvpnRouteWasDeleted
     291             :     (const EvpnRouteEntry *routing_evpn_rt, const Peer *delete_from_peer) {
     292             : 
     293           0 :     if (routing_evpn_rt->FindPath(agent_->evpn_routing_peer())) {
     294             :         // Actually, VRF NH Routes are not allowed here
     295           0 :         return;
     296             :     }
     297             : 
     298           0 :     VrfEntry *vrf = routing_evpn_rt->vrf();
     299           0 :     if (vrf == NULL) {
     300           0 :         return;
     301             :     }
     302             :     InetUnicastAgentRouteTable *routing_inet_table =
     303           0 :         vrf->GetInetUnicastRouteTable(routing_evpn_rt->prefix_address());
     304           0 :     if (routing_inet_table == NULL) {
     305           0 :         return;
     306             :     }
     307             : 
     308             :     // check that the Inet table holds the corresponding route
     309             :     InetUnicastRouteEntry local_vm_route_key(
     310             :         routing_inet_table->vrf_entry(),
     311           0 :         routing_evpn_rt->prefix_address(),
     312           0 :         routing_evpn_rt->prefix_length(), false);
     313             :     InetUnicastRouteEntry *inet_rt =
     314             :         dynamic_cast<InetUnicastRouteEntry *>
     315           0 :         (routing_inet_table->FindLPM(local_vm_route_key));
     316           0 :     if (RoutePrefixIsEqualTo(inet_rt, routing_evpn_rt->prefix_address(),
     317           0 :         routing_evpn_rt->prefix_length()) == false) {
     318           0 :         return;
     319             :     }
     320             : 
     321           0 :     bool ok_to_delete = routing_evpn_rt->IsDeleted() ||
     322           0 :         inet_rt->FindPath(delete_from_peer);
     323             : 
     324           0 :     if (ok_to_delete) {
     325             :         // Delete EVPN Type 5 record in the routing VRF
     326           0 :         InetUnicastAgentRouteTable::DeleteReq(
     327             :             delete_from_peer,
     328             :             vrf->GetName(),
     329           0 :             routing_evpn_rt->prefix_address(),
     330           0 :             routing_evpn_rt->prefix_length(),
     331             :             NULL);
     332             :     }
     333           0 : }
     334             : 
     335           0 : bool VxlanRoutingManager::WithdrawEvpnRouteFromRoutingVrf(
     336             :     const VrfEntry *routing_vrf,
     337             :     DBTablePartBase *partition, DBEntryBase *e) {
     338             : 
     339           0 :     InetUnicastRouteEntry *inet_rt = dynamic_cast<InetUnicastRouteEntry *>(e);
     340             : 
     341           0 :     if (!routing_vrf || !routing_vrf->GetEvpnRouteTable()  ||  !inet_rt) {
     342           0 :         return true;
     343             :     }
     344             :     EvpnAgentRouteTable *routing_evpn = static_cast<EvpnAgentRouteTable*>(
     345           0 :         routing_vrf->GetEvpnRouteTable());
     346           0 :     const EvpnRouteEntry *rt_route = routing_evpn->FindRoute(
     347           0 :         MacAddress(), inet_rt->prefix_address(), inet_rt->prefix_length(), 0);
     348           0 :     if (RoutePrefixIsEqualTo(rt_route, inet_rt->prefix_address(),
     349           0 :         inet_rt->prefix_length())) {
     350             :         // Remove deleted EVPN Type 5 record in the routing VRF
     351           0 :         EvpnAgentRouteTable::DeleteReq(
     352             :             routing_vrf_interface_peer_,
     353             :             routing_vrf->GetName(),
     354           0 :             MacAddress(),
     355           0 :             inet_rt->prefix_address(),
     356           0 :             inet_rt->prefix_length(),
     357             :             0,  // ethernet_tag = 0 for Type5
     358             :             NULL);
     359             :     }
     360           0 :     return true;
     361             : }
     362             : 
     363           0 : bool VxlanRoutingManager::LeakRoutesIntoBridgeTables
     364             : (DBTablePartBase *partition, DBEntryBase *e, const boost::uuids::uuid &uuid,
     365             :  const VnEntry *vn, bool update) {
     366             : 
     367           0 :     EvpnRouteEntry *evpn_rt = dynamic_cast<EvpnRouteEntry *>(e);
     368           0 :     if (!evpn_rt || (evpn_rt->vrf()->vn() == NULL) || (!evpn_rt->IsType5()))
     369           0 :         return true;
     370           0 :     if (uuid == boost::uuids::nil_uuid())
     371           0 :         return true;
     372             :     // Only non-local non-/32 and non-/128 routes are
     373             :     // copied to bridge vrfs
     374           0 :     if (IsHostRouteFromLocalSubnet(evpn_rt)) { //IsLocalSubnetHostRoute
     375           0 :         return true;
     376             :     }
     377             : 
     378             :     VxlanRoutingVrfMapper::RoutedVrfInfo &lr_vrf_info =
     379           0 :         vrf_mapper_.lr_vrf_info_map_[uuid];
     380           0 :     VxlanRoutingVrfMapper::RoutedVrfInfo::BridgeVnList update_bridge_vn_list;
     381           0 :     VxlanRoutingVrfMapper::RoutedVrfInfo::BridgeVnListIter it;
     382           0 :     if (update && vn != NULL) {
     383           0 :         update_bridge_vn_list.insert(vn);
     384           0 :         it = update_bridge_vn_list.find(vn);
     385             :     } else {
     386           0 :         update_bridge_vn_list = lr_vrf_info.bridge_vn_list_;
     387           0 :         it = update_bridge_vn_list.begin();
     388             :     }
     389           0 :     while (it != update_bridge_vn_list.end()) {
     390           0 :         VrfEntry *bridge_vrf =  VnVrf((*it), lr_vrf_info.bridge_vrf_names_list_[(*it)]);
     391             : 
     392           0 :         if (bridge_vrf == NULL) {
     393           0 :             it++;
     394           0 :             continue;
     395             :         }
     396             : 
     397           0 :         if (IsVrfLocalRoute(evpn_rt, bridge_vrf)) {
     398           0 :             it++;
     399           0 :             continue;
     400             :         }
     401             : 
     402             :         InetUnicastAgentRouteTable *inet_table =
     403           0 :                 bridge_vrf->GetInetUnicastRouteTable(evpn_rt->prefix_address());
     404             : 
     405           0 :         if (evpn_rt->IsDeleted()) {
     406           0 :             InetUnicastAgentRouteTable::DeleteReq(agent_->evpn_routing_peer(),
     407             :                               bridge_vrf->GetName(),
     408           0 :                               evpn_rt->prefix_address(),
     409           0 :                               evpn_rt->prefix_length(),
     410             :                               NULL);
     411             :         } else {
     412           0 :             const AgentPath *p = evpn_rt->GetActivePath();
     413           0 :             const VrfEntry *routing_vrf = lr_vrf_info.routing_vrf_;
     414             :             // Now all interface routes in routing vrf have BGP_PEER copies
     415           0 :             if (routing_vrf == NULL) {
     416           0 :                 return true;
     417             :             }
     418             : 
     419           0 :             DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
     420           0 :             nh_req.key.reset(new VrfNHKey(routing_vrf->GetName(), false, false));
     421           0 :             nh_req.data.reset(new VrfNHData(false, false, false));
     422           0 :             inet_table->AddEvpnRoutingRouteReq(evpn_rt->prefix_address(),
     423           0 :                                     evpn_rt->prefix_length(),
     424             :                                     bridge_vrf,
     425           0 :                                     agent_->evpn_routing_peer(),
     426             :                                     p->sg_list(),
     427             :                                     p->communities(),
     428             :                                     p->path_preference(),
     429             :                                     p->ecmp_load_balance(),
     430             :                                     p->tag_list(),
     431             :                                     nh_req,
     432             :                                     routing_vrf->vxlan_id(),
     433             :                                     p->dest_vn_list());
     434           0 :         }
     435           0 :         it++;
     436             :     }
     437           0 :     return true;
     438           0 : }
     439             : 
     440           0 : bool VxlanRoutingManager::RemoveRoutesFromRoutingToBridgeVrf
     441             :     (DBTablePartBase *partition, DBEntryBase *e,
     442             :     const VnEntry *vn, std::string bridge_vrf_name) {
     443             : 
     444           0 :     EvpnRouteEntry *evpn_rt = dynamic_cast<EvpnRouteEntry *>(e);
     445           0 :     if (!evpn_rt || (evpn_rt->vrf()->vn() == nullptr) ||
     446           0 :         (!evpn_rt->IsType5()))
     447           0 :         return true;
     448           0 :     VrfEntry *bridge_vrf = VnVrf(vn, bridge_vrf_name);
     449           0 :     if (bridge_vrf == nullptr) {
     450           0 :         return true;
     451             :     }
     452             :     InetUnicastAgentRouteTable *inet_table =
     453           0 :         bridge_vrf->GetInetUnicastRouteTable(evpn_rt->prefix_address());
     454             :     InetUnicastRouteEntry rt_key(inet_table->vrf_entry(),
     455           0 :        evpn_rt->prefix_address(), evpn_rt->prefix_length(), false);
     456           0 :     InetUnicastRouteEntry *inet_rt = inet_table->FindRouteUsingKey(rt_key);
     457             : 
     458           0 :     if ((inet_rt != nullptr) && (inet_rt->GetActivePath() != nullptr) &&
     459           0 :         (inet_rt->GetActivePath()->peer() != nullptr) &&
     460           0 :         (inet_rt->GetActivePath()->peer()->GetType() ==
     461             :             Peer::EVPN_ROUTING_PEER)) {
     462           0 :         InetUnicastAgentRouteTable::DeleteReq(agent_->evpn_routing_peer(),
     463             :                                               bridge_vrf->GetName(),
     464           0 :                                               evpn_rt->prefix_address(),
     465           0 :                                               evpn_rt->prefix_length(),
     466             :                                               NULL);
     467             :     }
     468           0 :     return true;
     469           0 : }
     470             : 
     471             : //
     472             : //END-OF-FILE
     473             : //
     474             : 

Generated by: LCOV version 1.14