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