OpenSDN source code
vxlan_routes_leaking.cc
Go to the documentation of this file.
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>
17 #include <oper/evpn_route.h>
18 #include <oper/agent_route.h>
20 #include <oper/vn.h>
21 #include <oper/vrf.h>
23 #include <oper/tunnel_nh.h> //for tunnel interception
24 
26 
27 /*
28  *
29  * Routes Leaking
30  *
31  */
32 
34  DBEntryBase *e) {
35  const InetUnicastRouteEntry *inet_rt =
36  dynamic_cast<const InetUnicastRouteEntry*>(e);
37  if (inet_rt) {
38  if (IsBridgeVrf(inet_rt->vrf())) {
39  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  dynamic_cast<const EvpnRouteEntry *>(e);
57  if (evpn_rt && IsRoutingVrf(evpn_rt->vrf())) {
58  return EvpnRouteNotify(partition, e);
59  }
60  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.
77  DBEntryBase *e) {
78  const InetUnicastRouteEntry *inet_rt =
79  dynamic_cast<const InetUnicastRouteEntry*>(e);
80 
81  if (inet_rt->prefix_address().is_v6() &&
82  inet_rt->prefix_address().to_v6().is_link_local()) {
83  return true;
84  }
85 
86  const VrfEntry *routing_vrf =
88  if (routing_vrf == NULL || routing_vrf == inet_rt->vrf()) {
89  return true;
90  }
91 
92  EvpnAgentRouteTable *evpn_table =
93  dynamic_cast<EvpnAgentRouteTable *>(routing_vrf->GetEvpnRouteTable());
94  if (evpn_table == NULL) {
95  return true;
96  }
97 
98  const AgentPath *local_vm_port_path = NULL;
99  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  if (local_vm_port_path == NULL) {
105  WhenBridgeInetIntfWasDeleted(inet_rt, routing_vrf);
106  return true;
107  }
108 
109  PathPreference preference = local_vm_port_path->path_preference();
110  preference.set_loc_sequence(GetNewLocalSequence(local_vm_port_path));
111  // preference.set_preference(100);
112  VnListType dest_vns;
113  dest_vns.insert(routing_vrf->vn()->GetName());
114 
115  CopyInterfacePathToEvpnTable(local_vm_port_path,
116  inet_rt->prefix_address(),
117  inet_rt->prefix_length(),
118  routing_vrf_interface_peer_, // agent->local_vm_export_peer(),
119  RouteParameters(IpAddress(), // not needed here
120  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(),
128  evpn_table);
129 
130  return true;
131 }
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  */
140  DBEntryBase *e) {
141  const EvpnRouteEntry *evpn_rt =
142  dynamic_cast<const EvpnRouteEntry *>(e);
143 
144  if (evpn_rt->IsType5() == false) {
145  return true;
146  }
147 
148  VrfEntry *vrf = evpn_rt->vrf();
149  const AgentPath *local_vm_port_path = evpn_rt->FindPath(
151 
152  const AgentPath *bgp_path =
154 
155  if (bgp_path) {
157  evpn_rt->prefix_length(), vrf->GetName(), bgp_path);
158  }
159 
160  if (local_vm_port_path) {
161  const NextHop *anh = local_vm_port_path->nexthop();
162  if (anh == NULL) {
163  return true;
164  }
165  CopyPathToInetTable(local_vm_port_path,
166  evpn_rt->prefix_address(),
167  evpn_rt->prefix_length(),
170  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(),
178  vrf->GetInetUnicastRouteTable(evpn_rt->prefix_address()));
179 
180  LeakRoutesIntoBridgeTables(partition,
181  e, vrf->vn()->logical_router_uuid(), NULL, true);
182  }
183 
184  if (bgp_path == NULL) {
185  // the route might be deleted
188  }
189 
190  if (local_vm_port_path == NULL) {
191  // the route might be deleted
194  // and/or it requires publishing in bridge
195  LeakRoutesIntoBridgeTables(partition, e,
196  vrf->vn()->logical_router_uuid(), NULL, true);
197  return true;
198  }
199 
200  return true;
201 }
202 
203 /*
204  *
205  * Routes Deletion
206  *
207  */
209  InetUnicastRouteEntry *inet_route =
210  dynamic_cast<InetUnicastRouteEntry*>(e);
211  if (inet_route == NULL) {
212  return;
213  }
214  if (inet_route->GetPathList().size() > 1 &&
215  inet_route->FindPath(agent_->evpn_routing_peer())) {
217  inet_route->vrf()->GetName(),
218  inet_route->prefix_address(),
219  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 
232  const InetUnicastRouteEntry *inet_rt,
233  const VrfEntry* routing_vrf) {
234 
235  if (inet_rt->FindPath(agent_->evpn_routing_peer())) {
236  return;
237  }
238 
239  // Check that this route is present in the routing VRF
240  const EvpnAgentRouteTable *evpn_table =
241  dynamic_cast<const EvpnAgentRouteTable *>
242  (routing_vrf->GetEvpnRouteTable());
243  if (evpn_table == NULL) {
244  return;
245  }
246 
247  const EvpnRouteEntry *evpn_rt =
248  const_cast<EvpnAgentRouteTable *>
249  (evpn_table)->FindRoute(MacAddress(),
250  inet_rt->prefix_address(), inet_rt->prefix_length(), 0);
251  if (RoutePrefixIsEqualTo(evpn_rt, inet_rt->prefix_address(), inet_rt->prefix_length()) == false) {
252  if (inet_rt->IsDeleted()) {
253  // That might be an IPAM route from neighb. bridge VRF instances.
254  if (IsHostRoute(inet_rt->prefix_address(), inet_rt->prefix_length()) == false) {
255  DeleteIpamRoutes(inet_rt->vrf()->vn(),
256  inet_rt->vrf()->GetName(),
257  inet_rt->prefix_address(), inet_rt->prefix_length());
258  }
259  }
260  return;
261  }
262 
263  bool ok_to_delete = inet_rt->IsDeleted() ||
265 
266  if ((ok_to_delete) && (!inet_rt->origin_vn_name().empty()) &&
267  (inet_rt->origin_vn_name()!=inet_rt->vrf()->vn()->GetName()) &&
268  (inet_rt->origin_vn_name()!=routing_vrf->vn()->GetName())) {
269  return;
270  }
271 
272  if (ok_to_delete) {
273  // Delete EVPN Type 5 record in the routing VRF
276  routing_vrf->GetName(),
277  MacAddress(),
278  inet_rt->prefix_address(),
279  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  */
291  (const EvpnRouteEntry *routing_evpn_rt, const Peer *delete_from_peer) {
292 
293  if (routing_evpn_rt->FindPath(agent_->evpn_routing_peer())) {
294  // Actually, VRF NH Routes are not allowed here
295  return;
296  }
297 
298  VrfEntry *vrf = routing_evpn_rt->vrf();
299  if (vrf == NULL) {
300  return;
301  }
302  InetUnicastAgentRouteTable *routing_inet_table =
303  vrf->GetInetUnicastRouteTable(routing_evpn_rt->prefix_address());
304  if (routing_inet_table == NULL) {
305  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  routing_evpn_rt->prefix_address(),
312  routing_evpn_rt->prefix_length(), false);
313  InetUnicastRouteEntry *inet_rt =
314  dynamic_cast<InetUnicastRouteEntry *>
315  (routing_inet_table->FindLPM(local_vm_route_key));
316  if (RoutePrefixIsEqualTo(inet_rt, routing_evpn_rt->prefix_address(),
317  routing_evpn_rt->prefix_length()) == false) {
318  return;
319  }
320 
321  bool ok_to_delete = routing_evpn_rt->IsDeleted() ||
322  inet_rt->FindPath(delete_from_peer);
323 
324  if (ok_to_delete) {
325  // Delete EVPN Type 5 record in the routing VRF
327  delete_from_peer,
328  vrf->GetName(),
329  routing_evpn_rt->prefix_address(),
330  routing_evpn_rt->prefix_length(),
331  NULL);
332  }
333 }
334 
336  const VrfEntry *routing_vrf,
337  DBTablePartBase *partition, DBEntryBase *e) {
338 
339  InetUnicastRouteEntry *inet_rt = dynamic_cast<InetUnicastRouteEntry *>(e);
340 
341  if (!routing_vrf || !routing_vrf->GetEvpnRouteTable() || !inet_rt) {
342  return true;
343  }
344  EvpnAgentRouteTable *routing_evpn = static_cast<EvpnAgentRouteTable*>(
345  routing_vrf->GetEvpnRouteTable());
346  const EvpnRouteEntry *rt_route = routing_evpn->FindRoute(
347  MacAddress(), inet_rt->prefix_address(), inet_rt->prefix_length(), 0);
348  if (RoutePrefixIsEqualTo(rt_route, inet_rt->prefix_address(),
349  inet_rt->prefix_length())) {
350  // Remove deleted EVPN Type 5 record in the routing VRF
353  routing_vrf->GetName(),
354  MacAddress(),
355  inet_rt->prefix_address(),
356  inet_rt->prefix_length(),
357  0, // ethernet_tag = 0 for Type5
358  NULL);
359  }
360  return true;
361 }
362 
364 (DBTablePartBase *partition, DBEntryBase *e, const boost::uuids::uuid &uuid,
365  const VnEntry *vn, bool update) {
366 
367  EvpnRouteEntry *evpn_rt = dynamic_cast<EvpnRouteEntry *>(e);
368  if (!evpn_rt || (evpn_rt->vrf()->vn() == NULL) || (!evpn_rt->IsType5()))
369  return true;
370  if (uuid == boost::uuids::nil_uuid())
371  return true;
372  // Only non-local non-/32 and non-/128 routes are
373  // copied to bridge vrfs
374  if (IsHostRouteFromLocalSubnet(evpn_rt)) { //IsLocalSubnetHostRoute
375  return true;
376  }
377 
382  if (update && vn != NULL) {
383  update_bridge_vn_list.insert(vn);
384  it = update_bridge_vn_list.find(vn);
385  } else {
386  update_bridge_vn_list = lr_vrf_info.bridge_vn_list_;
387  it = update_bridge_vn_list.begin();
388  }
389  while (it != update_bridge_vn_list.end()) {
390  VrfEntry *bridge_vrf = VnVrf((*it), lr_vrf_info.bridge_vrf_names_list_[(*it)]);
391 
392  if (bridge_vrf == NULL) {
393  it++;
394  continue;
395  }
396 
397  if (IsVrfLocalRoute(evpn_rt, bridge_vrf)) {
398  it++;
399  continue;
400  }
401 
402  InetUnicastAgentRouteTable *inet_table =
403  bridge_vrf->GetInetUnicastRouteTable(evpn_rt->prefix_address());
404 
405  if (evpn_rt->IsDeleted()) {
407  bridge_vrf->GetName(),
408  evpn_rt->prefix_address(),
409  evpn_rt->prefix_length(),
410  NULL);
411  } else {
412  const AgentPath *p = evpn_rt->GetActivePath();
413  const VrfEntry *routing_vrf = lr_vrf_info.routing_vrf_;
414  // Now all interface routes in routing vrf have BGP_PEER copies
415  if (routing_vrf == NULL) {
416  return true;
417  }
418 
420  nh_req.key.reset(new VrfNHKey(routing_vrf->GetName(), false, false));
421  nh_req.data.reset(new VrfNHData(false, false, false));
422  inet_table->AddEvpnRoutingRouteReq(evpn_rt->prefix_address(),
423  evpn_rt->prefix_length(),
424  bridge_vrf,
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  }
435  it++;
436  }
437  return true;
438 }
439 
440 //
441 //END-OF-FILE
442 //
443 
boost::asio::ip::address IpAddress
Definition: address.h:13
std::set< std::string > VnListType
Definition: agent.h:212
const VnListType & dest_vn_list() const
Definition: agent_path.h:258
NextHop * nexthop() const
Definition: agent_path.cc:87
const EcmpLoadBalance & ecmp_load_balance() const
Definition: agent_path.h:365
const PathPreference & path_preference() const
Definition: agent_path.h:329
const SecurityGroupList & sg_list() const
Definition: agent_path.h:248
const TagList & tag_list() const
Definition: agent_path.h:249
const CommunityList & communities() const
Definition: agent_path.h:250
virtual const PrefixType & prefix_address() const
Returns the value of a stored prefix address (IPv4, IPv6 or MAC address)
Definition: agent_route.h:389
VrfEntry * vrf_entry() const
Definition: agent_route.cc:459
const std::string & origin_vn_name() const
Definition: agent_route.h:281
const AgentPath * FindIntfOrCompLocalVmPortPath() const
Finds path to an interface or a composite of interfaces and returns it. The priority is given to comp...
Definition: agent_route.cc:817
const AgentPath * GetActivePath() const
Definition: agent_route.cc:877
VrfEntry * vrf() const
Definition: agent_route.h:275
virtual AgentPath * FindPath(const Peer *peer) const
Definition: agent_route.cc:865
const Peer * evpn_routing_peer() const
Definition: agent.h:1029
bool IsDeleted() const
Definition: db_entry.h:48
EvpnRouteEntry * FindRoute(const MacAddress &mac, const IpAddress &ip_addr, uint32_t plen, uint32_t ethernet_tag)
static void DeleteReq(const Peer *peer, const std::string &vrf_name, const MacAddress &mac, const IpAddress &ip_addr, uint32_t plen, uint32_t ethernet_tag, AgentRouteData *data)
uint8_t prefix_length() const
!
static void Delete(const Peer *peer, const string &vrf_name, const IpAddress &addr, uint8_t plen)
InetUnicastRouteEntry * FindLPM(const IpAddress &ip)
void AddEvpnRoutingRouteReq(const IpAddress &ip_addr, uint8_t plen, const VrfEntry *vrf, const Peer *peer, const SecurityGroupList &sg_list, const CommunityList &communities, const PathPreference &path_preference, const EcmpLoadBalance &ecmp_load_balance, const TagList &tag_list, DBRequest &nh_req, uint32_t vxlan_id, const VnListType &vn_list, const std::string &origin_vn="")
static void DeleteReq(const Peer *peer, const string &vrf_name, const IpAddress &addr, uint8_t plen, AgentRouteData *data)
uint8_t prefix_length() const
!
void set_loc_sequence(uint32_t loc_sequence)
Definition: agent_path.h:76
Definition: peer.h:44
@ BGP_PEER
Definition: peer.h:51
uint64_t sequence_number() const
Definition: peer.h:94
const PathList & GetPathList() const
Definition: route.h:46
Definition: vn.h:151
const string & GetName() const
Definition: vn.h:162
const boost::uuids::uuid & logical_router_uuid() const
Definition: vn.h:260
Definition: vrf.h:89
const string & GetName() const
Definition: vrf.h:103
InetUnicastAgentRouteTable * GetInetUnicastRouteTable(const IpAddress &addr) const
Definition: vrf.cc:575
AgentRouteTable * GetEvpnRouteTable() const
Definition: vrf.cc:330
uint32_t vxlan_id() const
Definition: vrf.h:168
VnEntry * vn() const
Definition: vrf.h:104
void DeleteIpamRoutes(const VnEntry *vn, const std::string &vrf_name, const IpAddress &ipam_prefix, const uint32_t plen)
Delete routes to IPAM, specified by IP prefix and prefix length.
bool LeakRoutesIntoBridgeTables(DBTablePartBase *partition, DBEntryBase *e, const boost::uuids::uuid &uuid, const VnEntry *vn, bool update=false)
Performs advertisement and deletion of routing routes (with VrfNH) in bridge VRF instances....
static void CopyInterfacePathToEvpnTable(const AgentPath *path, const IpAddress &prefix_ip, const uint32_t plen, const Peer *peer, const RouteParameters &params, EvpnAgentRouteTable *evpn_table)
Copies the path to the prefix address into the EVPN table with the given Peer. The function is used d...
bool RouteNotify(DBTablePartBase *partition, DBEntryBase *e)
Handler for changes (new/update/delete) in a route (EVPN or Inet). Main entry point for routes leakin...
static bool RoutePrefixIsEqualTo(const EvpnRouteEntry *route, const IpAddress &prefix_ip, const uint32_t prefix_len)
Determines whether route prefix in the EVPN route is equal to the given pair of prefix IP address and...
void ClearRedundantVrfPath(DBEntryBase *e)
Removes redundant VrfNH path from a given route. These routes might arise with small chance in a brid...
static uint32_t loc_sequence_
An always increasing counter for new paths (used to signal controoler about new routes).
static bool IsHostRoute(const IpAddress &prefix_ip, uint32_t prefix_len)
Determines whether the prefix address and the prefix length point to a host route (/32 for IPv4,...
static const AgentPath * FindPathWithGivenPeer(const AgentRoute *inet_rt, const Peer::Type peer_type)
Finds in the given route the path with a specified Peer type.
bool EvpnRouteNotify(DBTablePartBase *partition, DBEntryBase *e)
Performs routes leaking between the EVPN table of the routing VRF instance and the Inet table of the ...
static uint32_t GetNewLocalSequence(const AgentPath *)
Auxilliary functions.
bool WithdrawEvpnRouteFromRoutingVrf(const VrfEntry *routing_vrf, DBTablePartBase *partition, DBEntryBase *e)
Deletes a given EVPN route from EVPN table of the routing VRF instance.
static const Peer * routing_vrf_interface_peer_
Internal data of this class.
static bool IsBridgeVrf(const VrfEntry *vrf)
Determines whether the pointer to the VRF instance is of bridge type.
static const Peer * routing_vrf_vxlan_bgp_peer_
A pointer to the Peer where all BGP routes are stored.
void WhenBridgeInetIntfWasDeleted(const InetUnicastRouteEntry *inet_rt, const VrfEntry *routing_vrf)
Handles deletion of a route in the EVPN table of the routing VRF instance.
bool IsHostRouteFromLocalSubnet(const EvpnRouteEntry *rt)
Determines whether the given EVPN route is a host one and belongs to a subnet of a local bridge VRF....
static bool IsRoutingVrf(const VrfEntry *vrf)
Determines whether the pointer to the VRF instance is of routing type.
Agent * agent_
A pointer to the Agent instance.
void CopyPathToInetTable(const AgentPath *path, const IpAddress &prefix_ip, const uint32_t plen, const Peer *peer, const RouteParameters &params, InetUnicastAgentRouteTable *inet_table)
Copies the path to the prefix address into the EVPN table with the given Peer. The function is used d...
static VrfEntry * VnVrf(const VnEntry *vn, const std::string &vrf_name)
Finds a VRF table (VrfEntry) for the given virtual network (VN). Returns nullptr if no VRF table asso...
bool IsVrfLocalRoute(EvpnRouteEntry *routing_evpn_rt, VrfEntry *bridge_vrf)
Determines if the given EVPN route has an interface NH or a composite of interfaces NH that belongs t...
void XmppAdvertiseInetRoute(const IpAddress &prefix_ip, const int prefix_len, uint32_t vxlan_id, const std::string vrf_name, const RouteParameters &params, const Peer *bgp_peer)
Advertises an Inet route received using XMPP channel.
bool InetRouteNotify(DBTablePartBase *partition, DBEntryBase *e)
Routes leaking functions.
VxlanRoutingVrfMapper vrf_mapper_
A map between LR uuids and associated bridge and routing VRF instances.
void WhenRoutingEvpnRouteWasDeleted(const EvpnRouteEntry *routing_evpn_rt, const Peer *delete_from_peer)
Handles deletion of a route in the Inet table of the routing VRF instance.
LrVrfInfoMap lr_vrf_info_map_
The map between Logical router UUID and RoutedVrfInfo.
const VrfEntry * GetRoutingVrfUsingAgentRoute(const AgentRoute *rt)
Find the routing VRF instance using a given route (AgentRoute).
@ DB_ENTRY_ADD_CHANGE
Definition: db_table.h:38
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
A structure to hold path parameters during the transfer (routes leaking) of data between VRF instance...
The structure holds information about virtual networks connected to a logical router (LR)
std::set< const VnEntry * > BridgeVnList
A typedef to store the list of bridge virtual networks connected to a LR.
BridgeVnList::iterator BridgeVnListIter
A type for iterator of the list of bridge virtual networks connected to a LR.
BridgeVnList bridge_vn_list_
The list of bridge virtual networks (VirtualNetwork) connected to a LR.
BridgeVrfNamesList bridge_vrf_names_list_
The list of bridge virtual networks (VirtualNetwork) names connected to a LR.
VrfEntry * routing_vrf_
A pointer to the routing VRF instance (L3 VRF) connected to a LR.
boost::uuids::uuid uuid