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 :
|