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

Generated by: LCOV version 1.14