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