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 8 : void RouteLeakState::AddInterfaceRoute(const AgentRoute *route,
63 : const AgentPath *path) {
64 8 : const InetUnicastRouteEntry *uc_rt =
65 : static_cast<const InetUnicastRouteEntry *>(route);
66 8 : const AgentPath *active_path = path;
67 :
68 8 : if (active_path == NULL) {
69 0 : active_path = uc_rt->GetActivePath();
70 : }
71 :
72 8 : InterfaceNH *intf_nh = dynamic_cast<InterfaceNH *>(active_path->nexthop());
73 8 : if (intf_nh == NULL) {
74 3 : return;
75 : }
76 :
77 16 : if (uc_rt->IsHostRoute() &&
78 16 : uc_rt->prefix_address() == agent_->router_id()) {
79 : //Dont overwrite vhost IP in default VRF
80 3 : if (intf_nh->GetInterface() != agent_->vhost_interface()) {
81 0 : return;
82 : }
83 : }
84 :
85 8 : 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 8 : if (intf_nh->GetInterface()->type() == Interface::VM_INTERFACE) {
97 : const VmInterface *vm_intf =
98 8 : static_cast<const VmInterface *>(intf_nh->GetInterface());
99 8 : if (vm_intf->vmi_type() == VmInterface::VHOST) {
100 8 : if (uc_rt->prefix_address() == agent_->router_id()) {
101 3 : if (uc_rt->FindLocalVmPortPath() == NULL) {
102 0 : peer_list_.insert(agent_->local_peer());
103 : } else {
104 3 : peer_list_.insert(agent_->fabric_rt_export_peer());
105 : }
106 3 : AddReceiveRoute(route);
107 3 : return;
108 : }
109 : }
110 : }
111 :
112 5 : const Peer *peer = active_path->peer();
113 5 : 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 10 : if ((uc_rt->IsHostRoute()) &&
120 5 : dest_vrf_->GetName() == agent_->fabric_vrf_name()) {
121 5 : if (agent_->oper_db()->vrouter()->IsSubnetMember(uc_rt->prefix_address())) {
122 0 : peer = agent_->local_peer();
123 : }
124 : }
125 :
126 5 : peer_list_.insert(peer);
127 : VmInterfaceKey intf_key(AgentKey::ADD_DEL_CHANGE, intf_nh->GetIfUuid(),
128 5 : intf_nh->GetInterface()->name());
129 5 : LocalVmRoute *local_vm_route = NULL;
130 15 : local_vm_route =
131 : new LocalVmRoute(intf_key, MplsTable::kInvalidExportLabel,
132 : VxLanTable::kInvalidvxlan_id, false,
133 5 : active_path->dest_vn_list(), InterfaceNHFlags::INET4,
134 5 : SecurityGroupList(),
135 10 : TagList(),
136 10 : CommunityList(),
137 5 : active_path->path_preference(),
138 15 : Ip4Address(0), EcmpLoadBalance(),
139 5 : false, false, peer->sequence_number(),
140 5 : false, true);
141 5 : local_vm_route->set_native_vrf_id(uc_rt->vrf()->rd());
142 :
143 5 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
144 10 : req.key.reset(new InetUnicastRouteKey(peer, dest_vrf_->GetName(),
145 5 : uc_rt->prefix_address(), uc_rt->prefix_length()));
146 5 : req.data.reset(local_vm_route);
147 :
148 : AgentRouteTable *table =
149 5 : agent_->vrf_table()->GetInet4UnicastRouteTable(dest_vrf_->GetName());
150 5 : if (table) {
151 5 : table->Process(req);
152 : }
153 5 : }
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 3 : void RouteLeakState::AddReceiveRoute(const AgentRoute *route) {
166 3 : const InetUnicastRouteEntry *uc_rt =
167 : static_cast<const InetUnicastRouteEntry *>(route);
168 3 : 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 3 : const NextHop* nh = active_path->nexthop();
173 3 : if ((nh->GetType() != NextHop::INTERFACE) &&
174 0 : (nh->GetType() != NextHop::RECEIVE)) {
175 0 : return;
176 : }
177 :
178 : const ReceiveNH *rch_nh =
179 3 : static_cast<const ReceiveNH*>(active_path->nexthop());
180 : const VmInterface *vm_intf =
181 3 : static_cast<const VmInterface *>(rch_nh->GetInterface());
182 :
183 : InetUnicastAgentRouteTable *table =
184 : static_cast<InetUnicastAgentRouteTable *>(
185 3 : dest_vrf_->GetInet4UnicastRouteTable());
186 :
187 : VmInterfaceKey vmi_key(AgentKey::ADD_DEL_CHANGE, vm_intf->GetUuid(),
188 3 : vm_intf->name());
189 3 : table->AddVHostRecvRoute(agent_->fabric_rt_export_peer(),
190 : dest_vrf_->GetName(),
191 : vmi_key,
192 3 : uc_rt->prefix_address(),
193 3 : uc_rt->prefix_length(),
194 3 : agent_->fabric_vn_name(), false, true);
195 3 : }
196 :
197 13 : bool RouteLeakState::CanAdd(const InetUnicastRouteEntry *rt) {
198 : //Never replace resolve route and default route
199 : InetUnicastAgentRouteTable *table =
200 13 : agent_->fabric_vrf()->GetInet4UnicastRouteTable();
201 13 : std::vector<Ip4Address> gateway_list = agent_->vhost_default_gateway();
202 :
203 13 : if (rt->prefix_address() == Ip4Address(0) && rt->prefix_length() == 0) {
204 5 : return false;
205 : }
206 :
207 8 : InetUnicastRouteEntry *rsl_rt = table->FindResolveRoute(rt->prefix_address().to_v4());
208 8 : 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 16 : if (rt->IsHostRoute() &&
215 8 : std::find(gateway_list.begin(), gateway_list.end(),
216 24 : rt->prefix_address()) != gateway_list.end()) {
217 0 : return false;
218 : }
219 :
220 : //Always add gateway and DNS routes
221 : const InterfaceNH *nh =
222 8 : dynamic_cast<const InterfaceNH *>(rt->GetActiveNextHop());
223 8 : if (nh && nh->GetInterface()->type() == Interface::PACKET) {
224 0 : return true;
225 : }
226 :
227 8 : if ((rt->GetActivePath()->tunnel_bmap() & TunnelType::NativeType()) == 0) {
228 0 : return false;
229 : }
230 :
231 8 : return true;
232 13 : }
233 :
234 13 : void RouteLeakState::AddRoute(const AgentRoute *route) {
235 13 : const InetUnicastRouteEntry *uc_rt =
236 : static_cast<const InetUnicastRouteEntry *>(route);
237 13 : const NextHop *anh = uc_rt->GetActiveNextHop();
238 13 : if (CanAdd(uc_rt) == false && anh) {
239 5 : DeleteRoute(route, peer_list_);
240 5 : return;
241 : }
242 :
243 8 : std::set<const Peer *> old_peer_list = peer_list_;
244 8 : peer_list_.clear();
245 :
246 8 : if (anh->GetType() == NextHop::TUNNEL) {
247 0 : AddIndirectRoute(route);
248 16 : } else if ((anh->GetType() == NextHop::COMPOSITE)||
249 8 : (route->FindLocalVmPortPath() &&
250 16 : route->FindLocalVmPortPath()->nexthop() &&
251 8 : route->FindLocalVmPortPath()->nexthop()->GetType()
252 : == NextHop::COMPOSITE)) {
253 0 : AddCompositeRoute(route);
254 8 : } else if (anh->GetType() == NextHop::INTERFACE) {
255 8 : AddInterfaceRoute(route, route->FindLocalVmPortPath());
256 : }
257 :
258 8 : bool sync = false;
259 8 : if (old_peer_list != peer_list_) {
260 2 : sync = true;
261 : }
262 :
263 8 : std::set<const Peer *>::iterator it = old_peer_list.begin();
264 15 : while(it != old_peer_list.end()) {
265 7 : std::set<const Peer *>::iterator prev_it = it;
266 7 : it++;
267 7 : if (peer_list_.find(*prev_it) != peer_list_.end()) {
268 6 : old_peer_list.erase(prev_it);
269 : }
270 : }
271 :
272 8 : DeleteRoute(route, old_peer_list);
273 :
274 8 : if (sync) {
275 : InetUnicastAgentRouteTable *table =
276 2 : dest_vrf_->GetInet4UnicastRouteTable();
277 2 : table->ResyncRoute(agent_->fabric_rt_export_peer(),
278 2 : dest_vrf_->GetName(), uc_rt->prefix_address(), uc_rt->prefix_length());
279 : }
280 8 : }
281 :
282 17 : void RouteLeakState::DeleteRoute(const AgentRoute *route,
283 : const std::set<const Peer *> &peer_list) {
284 17 : if (dest_vrf_ == NULL) {
285 2 : return;
286 : }
287 :
288 15 : std::set<const Peer *>::const_iterator it = peer_list.begin();
289 17 : for(; it != peer_list.end(); it++) {
290 2 : const InetUnicastRouteEntry *uc_rt =
291 : static_cast<const InetUnicastRouteEntry *>(route);
292 4 : dest_vrf_->GetInet4UnicastRouteTable()->Delete(*it,
293 : dest_vrf_->GetName(),
294 2 : uc_rt->prefix_address(),
295 2 : uc_rt->prefix_length());
296 : }
297 : }
298 :
299 1 : RouteLeakVrfState::RouteLeakVrfState(VrfEntry *source_vrf,
300 1 : VrfEntry *dest_vrf):
301 1 : source_vrf_(source_vrf), dest_vrf_(dest_vrf), deleted_(false) {
302 :
303 1 : AgentRouteTable *table = source_vrf->GetInet4UnicastRouteTable();
304 1 : 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 2 : walk_ref_ = table->AllocWalker(
312 : boost::bind(&RouteLeakVrfState::WalkCallBack, this, _1, _2),
313 1 : boost::bind(&RouteLeakVrfState::WalkDoneInternal, this, _2));
314 1 : table->WalkTable(walk_ref_);
315 1 : }
316 :
317 2 : RouteLeakVrfState::~RouteLeakVrfState() {
318 1 : source_vrf_->GetInet4UnicastRouteTable()->ReleaseWalker(walk_ref_);
319 1 : source_vrf_->GetInet4UnicastRouteTable()->Unregister(route_listener_id_);
320 2 : }
321 :
322 2 : void RouteLeakVrfState::WalkDoneInternal(DBTableBase *part) {
323 2 : if (deleted_) {
324 1 : delete this;
325 : }
326 2 : }
327 :
328 2 : bool RouteLeakVrfState::WalkCallBack(DBTablePartBase *partition, DBEntryBase *entry) {
329 2 : Notify(partition, entry);
330 2 : return true;
331 : }
332 :
333 1 : void RouteLeakVrfState::AddDefaultRoute() {
334 1 : InetUnicastAgentRouteTable *table = source_vrf_->GetInet4UnicastRouteTable();
335 :
336 1 : VnListType vn_list;
337 1 : vn_list.insert(table->agent()->fabric_vn_name());
338 :
339 1 : table->AddGatewayRoute(table->agent()->local_peer(),
340 1 : source_vrf_->GetName(), Ip4Address(0), 0,
341 2 : table->agent()->vhost_default_gateway(), vn_list,
342 2 : MplsTable::kInvalidLabel, SecurityGroupList(),
343 2 : TagList(), CommunityList(), true);
344 1 : }
345 :
346 1 : void RouteLeakVrfState::DeleteDefaultRoute() {
347 1 : InetUnicastAgentRouteTable *table = source_vrf_->GetInet4UnicastRouteTable();
348 1 : table->Delete(table->agent()->local_peer(), source_vrf_->GetName(),
349 1 : Ip4Address(0), 0);
350 1 : }
351 :
352 1 : void RouteLeakVrfState::Delete() {
353 1 : deleted_ = true;
354 1 : source_vrf_->GetInet4UnicastRouteTable()->WalkAgain(walk_ref_);
355 1 : DeleteDefaultRoute();
356 1 : }
357 :
358 15 : bool RouteLeakVrfState::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
359 15 : AgentRoute *route = static_cast<AgentRoute *>(entry);
360 : RouteLeakState *state =
361 15 : static_cast<RouteLeakState *>(entry->GetState(partition->parent(),
362 : route_listener_id_));
363 :
364 15 : if (route->IsDeleted() || deleted_) {
365 2 : if (state) {
366 : //Delete the route
367 2 : entry->ClearState(partition->parent(), route_listener_id_);
368 2 : state->DeleteRoute(route, state->peer_list());
369 2 : delete state;
370 : }
371 2 : return true;
372 : }
373 :
374 13 : if (state == NULL && dest_vrf_) {
375 2 : state = new RouteLeakState(dest_vrf_->GetInet4UnicastRouteTable()->agent(),
376 2 : NULL);
377 2 : route->SetState(partition->parent(), route_listener_id_, state);
378 : }
379 :
380 13 : if (state == NULL) {
381 0 : return true;
382 : }
383 :
384 13 : if (state->dest_vrf() != dest_vrf_) {
385 2 : state->DeleteRoute(route, state->peer_list());
386 : }
387 :
388 13 : if (state->dest_vrf() != dest_vrf_) {
389 : //Add the route in new VRF
390 2 : state->set_dest_vrf(dest_vrf_.get());
391 : }
392 :
393 13 : if (state->dest_vrf()) {
394 13 : state->AddRoute(route);
395 : }
396 13 : return true;
397 : }
398 :
399 1 : void RouteLeakVrfState::SetDestVrf(VrfEntry *vrf) {
400 1 : if (dest_vrf_ != vrf) {
401 1 : dest_vrf_ = vrf;
402 1 : source_vrf_->GetInet4UnicastRouteTable()->WalkAgain(walk_ref_);
403 : }
404 :
405 1 : if (vrf == NULL) {
406 0 : DeleteDefaultRoute();
407 : } else {
408 1 : AddDefaultRoute();
409 : }
410 1 : }
411 :
412 1 : RouteLeakManager::RouteLeakManager(Agent *agent): agent_(agent) {
413 1 : vrf_listener_id_ = agent_->vrf_table()->Register(
414 : boost::bind(&RouteLeakManager::Notify, this, _1, _2));
415 1 : }
416 :
417 1 : RouteLeakManager::~RouteLeakManager() {
418 1 : agent_->vrf_table()->Unregister(vrf_listener_id_);
419 1 : }
420 :
421 15 : void RouteLeakManager::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
422 15 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
423 : RouteLeakVrfState *state =
424 15 : static_cast<RouteLeakVrfState *>(entry->GetState(partition->parent(),
425 : vrf_listener_id_));
426 :
427 15 : if (vrf->IsDeleted()) {
428 13 : if (state) {
429 1 : entry->ClearState(partition->parent(), vrf_listener_id_);
430 1 : state->Delete();
431 : }
432 13 : return;
433 : }
434 :
435 :
436 2 : if (state == NULL && vrf->forwarding_vrf()) {
437 1 : state = new RouteLeakVrfState(vrf, NULL);
438 : }
439 :
440 2 : if (state == NULL) {
441 1 : return;
442 : }
443 :
444 1 : vrf->SetState(partition->parent(), vrf_listener_id_, state);
445 :
446 1 : if (vrf->forwarding_vrf() != state->dest_vrf()) {
447 1 : 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 : }
|