Line data Source code
1 : #include <cmn/agent_cmn.h>
2 : #include <route/route.h>
3 : #include <oper/nexthop.h>
4 : #include <oper/tunnel_nh.h>
5 : #include <oper/route_common.h>
6 : #include <oper/vrf.h>
7 : #include <oper/vrouter.h>
8 : #include <oper/route_leak.h>
9 :
10 0 : void RouteLeakState::AddIndirectRoute(const AgentRoute *route) {
11 0 : InetUnicastAgentRouteTable *table = dest_vrf_->GetInet4UnicastRouteTable();
12 0 : const InetUnicastRouteEntry *uc_rt =
13 : static_cast<const InetUnicastRouteEntry *>(route);
14 0 : const AgentPath *active_path = uc_rt->GetActivePath();
15 0 : const TunnelNH *nh = dynamic_cast<const TunnelNH *>(active_path->nexthop());
16 :
17 0 : if (nh == NULL) {
18 0 : return;
19 : }
20 :
21 0 : Ip4Address gw_ip = *(nh->GetDip());
22 :
23 0 : if (gw_ip == uc_rt->prefix_address().to_v4() &&
24 0 : InetUnicastAgentRouteTable::FindResolveRoute(dest_vrf_->GetName(),
25 0 : uc_rt->prefix_address().to_v4())) {
26 0 : bool resolved = false;
27 0 : MacAddress mac;
28 0 : const Interface *itf = agent_->vhost_interface();
29 0 : ArpNHKey nh_key(dest_vrf_->GetName(), uc_rt->prefix_address().to_v4(), false);
30 0 : ArpNH *arp_nh = static_cast<ArpNH *>(agent_->nexthop_table()->
31 0 : FindActiveEntry(&nh_key));
32 0 : if (arp_nh) {
33 0 : resolved = arp_nh->GetResolveState();
34 0 : mac = arp_nh->GetMac();
35 0 : itf = arp_nh->GetInterface();
36 : }
37 : InetUnicastAgentRouteTable::CheckAndAddArpRoute
38 0 : (dest_vrf_->GetName(), uc_rt->prefix_address().to_v4(), mac, itf,
39 : resolved, active_path->dest_vn_list(),
40 : active_path->sg_list(), active_path->tag_list());
41 0 : return;
42 0 : }
43 :
44 0 : const Peer *peer = agent_->local_peer();
45 0 : peer_list_.insert(peer);
46 :
47 0 : if (gw_ip == uc_rt->prefix_address().to_v4()) {
48 0 : gw_ip = agent_->vhost_default_gateway()[0];
49 : }
50 :
51 0 : table->AddGatewayRoute(peer, dest_vrf_->GetName(),
52 0 : uc_rt->prefix_address().to_v4(),
53 0 : uc_rt->prefix_length(),
54 0 : AddressList(1, gw_ip),
55 : active_path->dest_vn_list(),
56 : MplsTable::kInvalidExportLabel,
57 : active_path->sg_list(),
58 : active_path->tag_list(),
59 : active_path->communities(), true);
60 : }
61 :
62 24 : void RouteLeakState::AddInterfaceRoute(const AgentRoute *route,
63 : const AgentPath *path) {
64 24 : const InetUnicastRouteEntry *uc_rt =
65 : static_cast<const InetUnicastRouteEntry *>(route);
66 24 : const AgentPath *active_path = path;
67 :
68 24 : if (active_path == NULL) {
69 0 : active_path = uc_rt->GetActivePath();
70 : }
71 :
72 24 : InterfaceNH *intf_nh = dynamic_cast<InterfaceNH *>(active_path->nexthop());
73 24 : if (intf_nh == NULL) {
74 14 : return;
75 : }
76 :
77 48 : if (uc_rt->IsHostRoute() &&
78 48 : uc_rt->prefix_address() == agent_->router_id()) {
79 : //Dont overwrite vhost IP in default VRF
80 14 : if (intf_nh->GetInterface() != agent_->vhost_interface()) {
81 0 : return;
82 : }
83 : }
84 :
85 24 : if (intf_nh->GetInterface()->type() == Interface::PACKET) {
86 0 : peer_list_.insert(agent_->local_peer());
87 : InetUnicastAgentRouteTable *table =
88 : static_cast<InetUnicastAgentRouteTable *>
89 0 : (dest_vrf_->GetInet4UnicastRouteTable());
90 :
91 0 : table->AddHostRoute(dest_vrf_->GetName(), uc_rt->prefix_address(), uc_rt->prefix_length(),
92 : "", true);
93 0 : return;
94 : }
95 :
96 24 : if (intf_nh->GetInterface()->type() == Interface::VM_INTERFACE) {
97 : const VmInterface *vm_intf =
98 24 : static_cast<const VmInterface *>(intf_nh->GetInterface());
99 24 : if (vm_intf->vmi_type() == VmInterface::VHOST) {
100 24 : if (uc_rt->prefix_address() == agent_->router_id()) {
101 14 : if (uc_rt->FindLocalVmPortPath() == NULL) {
102 0 : peer_list_.insert(agent_->local_peer());
103 : } else {
104 14 : peer_list_.insert(agent_->fabric_rt_export_peer());
105 : }
106 14 : AddReceiveRoute(route);
107 14 : return;
108 : }
109 : }
110 : }
111 :
112 10 : const Peer *peer = active_path->peer();
113 10 : if (uc_rt->FindLocalVmPortPath() == NULL) {
114 0 : peer = agent_->local_peer();
115 : }
116 :
117 : /* Don't export /32 routes on fabric-vrf, if they are part of vrouter's
118 : * subnet list. To disable export, use local_peer */
119 20 : if ((uc_rt->IsHostRoute()) &&
120 10 : dest_vrf_->GetName() == agent_->fabric_vrf_name()) {
121 10 : if (agent_->oper_db()->vrouter()->IsSubnetMember(uc_rt->prefix_address())) {
122 0 : peer = agent_->local_peer();
123 : }
124 : }
125 :
126 10 : peer_list_.insert(peer);
127 : VmInterfaceKey intf_key(AgentKey::ADD_DEL_CHANGE, intf_nh->GetIfUuid(),
128 10 : intf_nh->GetInterface()->name());
129 10 : LocalVmRoute *local_vm_route = NULL;
130 30 : local_vm_route =
131 : new LocalVmRoute(intf_key, MplsTable::kInvalidExportLabel,
132 : VxLanTable::kInvalidvxlan_id, false,
133 10 : active_path->dest_vn_list(), InterfaceNHFlags::INET4,
134 10 : SecurityGroupList(),
135 20 : TagList(),
136 20 : CommunityList(),
137 10 : active_path->path_preference(),
138 30 : Ip4Address(0), EcmpLoadBalance(),
139 10 : false, false, peer->sequence_number(),
140 10 : false, true);
141 10 : local_vm_route->set_native_vrf_id(uc_rt->vrf()->rd());
142 :
143 10 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
144 20 : req.key.reset(new InetUnicastRouteKey(peer, dest_vrf_->GetName(),
145 10 : uc_rt->prefix_address(), uc_rt->prefix_length()));
146 10 : req.data.reset(local_vm_route);
147 :
148 : AgentRouteTable *table =
149 10 : agent_->vrf_table()->GetInet4UnicastRouteTable(dest_vrf_->GetName());
150 10 : if (table) {
151 10 : table->Process(req);
152 : }
153 10 : }
154 :
155 0 : void RouteLeakState::AddCompositeRoute(const AgentRoute *route) {
156 0 : for(Route::PathList::const_iterator it = route->GetPathList().begin();
157 0 : it != route->GetPathList().end(); it++) {
158 0 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
159 0 : if (path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
160 0 : AddInterfaceRoute(route, path);
161 : }
162 : }
163 0 : }
164 :
165 14 : void RouteLeakState::AddReceiveRoute(const AgentRoute *route) {
166 14 : const InetUnicastRouteEntry *uc_rt =
167 : static_cast<const InetUnicastRouteEntry *>(route);
168 14 : const AgentPath *active_path = uc_rt->GetActivePath();
169 :
170 : /* This is a defensive check added to prevent the code below from casting NHs
171 : * not containing an interface to RECEIVE NH */
172 14 : const NextHop* nh = active_path->nexthop();
173 14 : if ((nh->GetType() != NextHop::INTERFACE) &&
174 0 : (nh->GetType() != NextHop::RECEIVE)) {
175 0 : return;
176 : }
177 :
178 : const ReceiveNH *rch_nh =
179 14 : static_cast<const ReceiveNH*>(active_path->nexthop());
180 : const VmInterface *vm_intf =
181 14 : static_cast<const VmInterface *>(rch_nh->GetInterface());
182 :
183 : InetUnicastAgentRouteTable *table =
184 : static_cast<InetUnicastAgentRouteTable *>(
185 14 : dest_vrf_->GetInet4UnicastRouteTable());
186 :
187 : VmInterfaceKey vmi_key(AgentKey::ADD_DEL_CHANGE, vm_intf->GetUuid(),
188 14 : vm_intf->name());
189 14 : table->AddVHostRecvRoute(agent_->fabric_rt_export_peer(),
190 : dest_vrf_->GetName(),
191 : vmi_key,
192 14 : uc_rt->prefix_address(),
193 14 : uc_rt->prefix_length(),
194 14 : agent_->fabric_vn_name(), false, true);
195 14 : }
196 :
197 39 : bool RouteLeakState::CanAdd(const InetUnicastRouteEntry *rt) {
198 : //Never replace resolve route and default route
199 : InetUnicastAgentRouteTable *table =
200 39 : agent_->fabric_vrf()->GetInet4UnicastRouteTable();
201 39 : std::vector<Ip4Address> gateway_list = agent_->vhost_default_gateway();
202 :
203 39 : if (rt->prefix_address() == Ip4Address(0) && rt->prefix_length() == 0) {
204 15 : return false;
205 : }
206 :
207 24 : InetUnicastRouteEntry *rsl_rt = table->FindResolveRoute(rt->prefix_address().to_v4());
208 24 : if (rsl_rt && rt->prefix_address() == rsl_rt->prefix_address() &&
209 0 : rt->prefix_length() == rsl_rt->prefix_length()) {
210 : //Dont overwrite resolve route
211 0 : return false;
212 : }
213 :
214 48 : if (rt->IsHostRoute() &&
215 24 : std::find(gateway_list.begin(), gateway_list.end(),
216 72 : rt->prefix_address()) != gateway_list.end()) {
217 0 : return false;
218 : }
219 :
220 : //Always add gateway and DNS routes
221 : const InterfaceNH *nh =
222 24 : dynamic_cast<const InterfaceNH *>(rt->GetActiveNextHop());
223 24 : if (nh && nh->GetInterface()->type() == Interface::PACKET) {
224 0 : return true;
225 : }
226 :
227 24 : if ((rt->GetActivePath()->tunnel_bmap() & TunnelType::NativeType()) == 0) {
228 0 : return false;
229 : }
230 :
231 24 : return true;
232 39 : }
233 :
234 39 : void RouteLeakState::AddRoute(const AgentRoute *route) {
235 39 : const InetUnicastRouteEntry *uc_rt =
236 : static_cast<const InetUnicastRouteEntry *>(route);
237 39 : const NextHop *anh = uc_rt->GetActiveNextHop();
238 39 : if (CanAdd(uc_rt) == false && anh) {
239 15 : DeleteRoute(route, peer_list_);
240 15 : return;
241 : }
242 :
243 24 : std::set<const Peer *> old_peer_list = peer_list_;
244 24 : peer_list_.clear();
245 :
246 24 : if (anh->GetType() == NextHop::TUNNEL) {
247 0 : AddIndirectRoute(route);
248 48 : } else if ((anh->GetType() == NextHop::COMPOSITE)||
249 24 : (route->FindLocalVmPortPath() &&
250 48 : route->FindLocalVmPortPath()->nexthop() &&
251 24 : route->FindLocalVmPortPath()->nexthop()->GetType()
252 : == NextHop::COMPOSITE)) {
253 0 : AddCompositeRoute(route);
254 24 : } else if (anh->GetType() == NextHop::INTERFACE) {
255 24 : AddInterfaceRoute(route, route->FindLocalVmPortPath());
256 : }
257 :
258 24 : bool sync = false;
259 24 : if (old_peer_list != peer_list_) {
260 5 : sync = true;
261 : }
262 :
263 24 : std::set<const Peer *>::iterator it = old_peer_list.begin();
264 45 : while(it != old_peer_list.end()) {
265 21 : std::set<const Peer *>::iterator prev_it = it;
266 21 : it++;
267 21 : if (peer_list_.find(*prev_it) != peer_list_.end()) {
268 19 : old_peer_list.erase(prev_it);
269 : }
270 : }
271 :
272 24 : DeleteRoute(route, old_peer_list);
273 :
274 24 : if (sync) {
275 : InetUnicastAgentRouteTable *table =
276 5 : dest_vrf_->GetInet4UnicastRouteTable();
277 5 : table->ResyncRoute(agent_->fabric_rt_export_peer(),
278 5 : dest_vrf_->GetName(), uc_rt->prefix_address(), uc_rt->prefix_length());
279 : }
280 24 : }
281 :
282 51 : void RouteLeakState::DeleteRoute(const AgentRoute *route,
283 : const std::set<const Peer *> &peer_list) {
284 51 : if (dest_vrf_ == NULL) {
285 6 : return;
286 : }
287 :
288 45 : std::set<const Peer *>::const_iterator it = peer_list.begin();
289 50 : for(; it != peer_list.end(); it++) {
290 5 : const InetUnicastRouteEntry *uc_rt =
291 : static_cast<const InetUnicastRouteEntry *>(route);
292 10 : dest_vrf_->GetInet4UnicastRouteTable()->Delete(*it,
293 : dest_vrf_->GetName(),
294 5 : uc_rt->prefix_address(),
295 5 : uc_rt->prefix_length());
296 : }
297 : }
298 :
299 3 : RouteLeakVrfState::RouteLeakVrfState(VrfEntry *source_vrf,
300 3 : VrfEntry *dest_vrf):
301 3 : source_vrf_(source_vrf), dest_vrf_(dest_vrf), deleted_(false) {
302 :
303 3 : AgentRouteTable *table = source_vrf->GetInet4UnicastRouteTable();
304 3 : route_listener_id_ = table->Register(boost::bind(&RouteLeakVrfState::Notify,
305 : this, _1, _2));
306 :
307 : //Walker would be used to address change of dest VRF table
308 : //Everytime dest vrf change all the route from old dest VRF
309 : //would be deleted and added to new dest VRF if any
310 : //If VRF is deleted upon walk done state would be deleted.
311 6 : walk_ref_ = table->AllocWalker(
312 : boost::bind(&RouteLeakVrfState::WalkCallBack, this, _1, _2),
313 3 : boost::bind(&RouteLeakVrfState::WalkDoneInternal, this, _2));
314 3 : table->WalkTable(walk_ref_);
315 3 : }
316 :
317 6 : RouteLeakVrfState::~RouteLeakVrfState() {
318 3 : source_vrf_->GetInet4UnicastRouteTable()->ReleaseWalker(walk_ref_);
319 3 : source_vrf_->GetInet4UnicastRouteTable()->Unregister(route_listener_id_);
320 6 : }
321 :
322 6 : void RouteLeakVrfState::WalkDoneInternal(DBTableBase *part) {
323 6 : if (deleted_) {
324 3 : delete this;
325 : }
326 6 : }
327 :
328 6 : bool RouteLeakVrfState::WalkCallBack(DBTablePartBase *partition, DBEntryBase *entry) {
329 6 : Notify(partition, entry);
330 6 : return true;
331 : }
332 :
333 3 : void RouteLeakVrfState::AddDefaultRoute() {
334 3 : InetUnicastAgentRouteTable *table = source_vrf_->GetInet4UnicastRouteTable();
335 :
336 3 : VnListType vn_list;
337 3 : vn_list.insert(table->agent()->fabric_vn_name());
338 :
339 3 : table->AddGatewayRoute(table->agent()->local_peer(),
340 3 : source_vrf_->GetName(), Ip4Address(0), 0,
341 6 : table->agent()->vhost_default_gateway(), vn_list,
342 6 : MplsTable::kInvalidLabel, SecurityGroupList(),
343 6 : TagList(), CommunityList(), true);
344 3 : }
345 :
346 3 : void RouteLeakVrfState::DeleteDefaultRoute() {
347 3 : InetUnicastAgentRouteTable *table = source_vrf_->GetInet4UnicastRouteTable();
348 3 : table->Delete(table->agent()->local_peer(), source_vrf_->GetName(),
349 3 : Ip4Address(0), 0);
350 3 : }
351 :
352 3 : void RouteLeakVrfState::Delete() {
353 3 : deleted_ = true;
354 3 : source_vrf_->GetInet4UnicastRouteTable()->WalkAgain(walk_ref_);
355 3 : DeleteDefaultRoute();
356 3 : }
357 :
358 45 : bool RouteLeakVrfState::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
359 45 : AgentRoute *route = static_cast<AgentRoute *>(entry);
360 : RouteLeakState *state =
361 45 : static_cast<RouteLeakState *>(entry->GetState(partition->parent(),
362 : route_listener_id_));
363 :
364 45 : if (route->IsDeleted() || deleted_) {
365 6 : if (state) {
366 : //Delete the route
367 6 : entry->ClearState(partition->parent(), route_listener_id_);
368 6 : state->DeleteRoute(route, state->peer_list());
369 6 : delete state;
370 : }
371 6 : return true;
372 : }
373 :
374 39 : if (state == NULL && dest_vrf_) {
375 6 : state = new RouteLeakState(dest_vrf_->GetInet4UnicastRouteTable()->agent(),
376 6 : NULL);
377 6 : route->SetState(partition->parent(), route_listener_id_, state);
378 : }
379 :
380 39 : if (state == NULL) {
381 0 : return true;
382 : }
383 :
384 39 : if (state->dest_vrf() != dest_vrf_) {
385 6 : state->DeleteRoute(route, state->peer_list());
386 : }
387 :
388 39 : if (state->dest_vrf() != dest_vrf_) {
389 : //Add the route in new VRF
390 6 : state->set_dest_vrf(dest_vrf_.get());
391 : }
392 :
393 39 : if (state->dest_vrf()) {
394 39 : state->AddRoute(route);
395 : }
396 39 : return true;
397 : }
398 :
399 3 : void RouteLeakVrfState::SetDestVrf(VrfEntry *vrf) {
400 3 : if (dest_vrf_ != vrf) {
401 3 : dest_vrf_ = vrf;
402 3 : source_vrf_->GetInet4UnicastRouteTable()->WalkAgain(walk_ref_);
403 : }
404 :
405 3 : if (vrf == NULL) {
406 0 : DeleteDefaultRoute();
407 : } else {
408 3 : AddDefaultRoute();
409 : }
410 3 : }
411 :
412 3 : RouteLeakManager::RouteLeakManager(Agent *agent): agent_(agent) {
413 3 : vrf_listener_id_ = agent_->vrf_table()->Register(
414 : boost::bind(&RouteLeakManager::Notify, this, _1, _2));
415 3 : }
416 :
417 3 : RouteLeakManager::~RouteLeakManager() {
418 3 : agent_->vrf_table()->Unregister(vrf_listener_id_);
419 3 : }
420 :
421 106 : void RouteLeakManager::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
422 106 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
423 : RouteLeakVrfState *state =
424 106 : static_cast<RouteLeakVrfState *>(entry->GetState(partition->parent(),
425 : vrf_listener_id_));
426 :
427 106 : if (vrf->IsDeleted()) {
428 88 : if (state) {
429 3 : entry->ClearState(partition->parent(), vrf_listener_id_);
430 3 : state->Delete();
431 : }
432 88 : return;
433 : }
434 :
435 :
436 18 : if (state == NULL && vrf->forwarding_vrf()) {
437 3 : state = new RouteLeakVrfState(vrf, NULL);
438 : }
439 :
440 18 : if (state == NULL) {
441 15 : return;
442 : }
443 :
444 3 : vrf->SetState(partition->parent(), vrf_listener_id_, state);
445 :
446 3 : if (vrf->forwarding_vrf() != state->dest_vrf()) {
447 3 : state->SetDestVrf(vrf->forwarding_vrf());
448 : }
449 : }
450 :
451 0 : void RouteLeakManager::ReEvaluateRouteExports() {
452 0 : if (vrf_walk_ref_.get() == NULL) {
453 0 : vrf_walk_ref_ = agent_->vrf_table()->AllocWalker(
454 : boost::bind(&RouteLeakManager::VrfWalkNotify, this, _1, _2),
455 0 : boost::bind(&RouteLeakManager::VrfWalkDone, this, _2));
456 : }
457 0 : agent_->vrf_table()->WalkAgain(vrf_walk_ref_);
458 0 : }
459 :
460 0 : bool RouteLeakManager::VrfWalkNotify(DBTablePartBase *partition,
461 : DBEntryBase *e) {
462 0 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
463 : RouteLeakVrfState *state =
464 0 : static_cast<RouteLeakVrfState *>(e->GetState(partition->parent(),
465 : vrf_listener_id_));
466 0 : if (vrf->IsDeleted()) {
467 0 : return true;
468 : }
469 : /* Ignore VRFs on which routes are not leaked by RouteLeakManager */
470 0 : if (state == NULL) {
471 0 : return true;
472 : }
473 0 : if (state->deleted()) {
474 0 : return true;
475 : }
476 :
477 0 : StartRouteWalk(vrf, state);
478 0 : return true;
479 : }
480 :
481 0 : void RouteLeakManager::VrfWalkDone(DBTableBase *part) {
482 0 : }
483 :
484 0 : void RouteLeakManager::StartRouteWalk(VrfEntry *vrf, RouteLeakVrfState *state) {
485 0 : InetUnicastAgentRouteTable *table = vrf->GetInet4UnicastRouteTable();
486 0 : if (!table) {
487 0 : return;
488 : }
489 : DBTable::DBTableWalkRef rt_table_walk_ref = table->AllocWalker(
490 : boost::bind(&RouteLeakVrfState::Notify, state, _1, _2),
491 0 : boost::bind(&RouteLeakManager::RouteWalkDone, this, _2));
492 0 : table->WalkAgain(rt_table_walk_ref);
493 0 : }
494 :
495 0 : void RouteLeakManager::RouteWalkDone(DBTableBase *part) {
496 0 : }
|