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 20 : void RouteLeakState::AddInterfaceRoute(const AgentRoute *route,
63 : const AgentPath *path) {
64 20 : const InetUnicastRouteEntry *uc_rt =
65 : static_cast<const InetUnicastRouteEntry *>(route);
66 20 : const AgentPath *active_path = path;
67 :
68 20 : if (active_path == NULL) {
69 0 : active_path = uc_rt->GetActivePath();
70 : }
71 :
72 20 : InterfaceNH *intf_nh = dynamic_cast<InterfaceNH *>(active_path->nexthop());
73 20 : if (intf_nh == NULL) {
74 15 : return;
75 : }
76 :
77 40 : if (uc_rt->IsHostRoute() &&
78 40 : uc_rt->prefix_address() == agent_->router_id()) {
79 : //Dont overwrite vhost IP in default VRF
80 15 : if (intf_nh->GetInterface() != agent_->vhost_interface()) {
81 0 : return;
82 : }
83 : }
84 :
85 20 : 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 20 : if (intf_nh->GetInterface()->type() == Interface::VM_INTERFACE) {
97 : const VmInterface *vm_intf =
98 20 : static_cast<const VmInterface *>(intf_nh->GetInterface());
99 20 : if (vm_intf->vmi_type() == VmInterface::VHOST) {
100 20 : if (uc_rt->prefix_address() == agent_->router_id()) {
101 15 : if (uc_rt->FindLocalVmPortPath() == NULL) {
102 0 : peer_list_.insert(agent_->local_peer());
103 : } else {
104 15 : peer_list_.insert(agent_->fabric_rt_export_peer());
105 : }
106 15 : AddReceiveRoute(route);
107 15 : 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 15 : void RouteLeakState::AddReceiveRoute(const AgentRoute *route) {
166 15 : const InetUnicastRouteEntry *uc_rt =
167 : static_cast<const InetUnicastRouteEntry *>(route);
168 15 : 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 15 : const NextHop* nh = active_path->nexthop();
173 15 : if ((nh->GetType() != NextHop::INTERFACE) &&
174 0 : (nh->GetType() != NextHop::RECEIVE)) {
175 0 : return;
176 : }
177 :
178 : const ReceiveNH *rch_nh =
179 15 : static_cast<const ReceiveNH*>(active_path->nexthop());
180 : const VmInterface *vm_intf =
181 15 : static_cast<const VmInterface *>(rch_nh->GetInterface());
182 :
183 : InetUnicastAgentRouteTable *table =
184 : static_cast<InetUnicastAgentRouteTable *>(
185 15 : dest_vrf_->GetInet4UnicastRouteTable());
186 :
187 : VmInterfaceKey vmi_key(AgentKey::ADD_DEL_CHANGE, vm_intf->GetUuid(),
188 15 : vm_intf->name());
189 15 : table->AddVHostRecvRoute(agent_->fabric_rt_export_peer(),
190 : dest_vrf_->GetName(),
191 : vmi_key,
192 15 : uc_rt->prefix_address(),
193 15 : uc_rt->prefix_length(),
194 15 : agent_->fabric_vn_name(), false, true);
195 15 : }
196 :
197 33 : bool RouteLeakState::CanAdd(const InetUnicastRouteEntry *rt) {
198 : //Never replace resolve route and default route
199 : InetUnicastAgentRouteTable *table =
200 33 : agent_->fabric_vrf()->GetInet4UnicastRouteTable();
201 33 : std::vector<Ip4Address> gateway_list = agent_->vhost_default_gateway();
202 :
203 33 : if (rt->prefix_address() == Ip4Address(0) && rt->prefix_length() == 0) {
204 13 : return false;
205 : }
206 :
207 20 : InetUnicastRouteEntry *rsl_rt = table->FindResolveRoute(rt->prefix_address().to_v4());
208 20 : 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 40 : if (rt->IsHostRoute() &&
215 20 : std::find(gateway_list.begin(), gateway_list.end(),
216 60 : rt->prefix_address()) != gateway_list.end()) {
217 0 : return false;
218 : }
219 :
220 : //Always add gateway and DNS routes
221 : const InterfaceNH *nh =
222 20 : dynamic_cast<const InterfaceNH *>(rt->GetActiveNextHop());
223 20 : if (nh && nh->GetInterface()->type() == Interface::PACKET) {
224 0 : return true;
225 : }
226 :
227 20 : if ((rt->GetActivePath()->tunnel_bmap() & TunnelType::NativeType()) == 0) {
228 0 : return false;
229 : }
230 :
231 20 : return true;
232 33 : }
233 :
234 33 : void RouteLeakState::AddRoute(const AgentRoute *route) {
235 33 : const InetUnicastRouteEntry *uc_rt =
236 : static_cast<const InetUnicastRouteEntry *>(route);
237 33 : const NextHop *anh = uc_rt->GetActiveNextHop();
238 33 : if (CanAdd(uc_rt) == false && anh) {
239 13 : DeleteRoute(route, peer_list_);
240 13 : return;
241 : }
242 :
243 20 : std::set<const Peer *> old_peer_list = peer_list_;
244 20 : peer_list_.clear();
245 :
246 20 : if (anh->GetType() == NextHop::TUNNEL) {
247 0 : AddIndirectRoute(route);
248 40 : } else if ((anh->GetType() == NextHop::COMPOSITE)||
249 20 : (route->FindLocalVmPortPath() &&
250 40 : route->FindLocalVmPortPath()->nexthop() &&
251 20 : route->FindLocalVmPortPath()->nexthop()->GetType()
252 : == NextHop::COMPOSITE)) {
253 0 : AddCompositeRoute(route);
254 20 : } else if (anh->GetType() == NextHop::INTERFACE) {
255 20 : AddInterfaceRoute(route, route->FindLocalVmPortPath());
256 : }
257 :
258 20 : bool sync = false;
259 20 : if (old_peer_list != peer_list_) {
260 4 : sync = true;
261 : }
262 :
263 20 : std::set<const Peer *>::iterator it = old_peer_list.begin();
264 37 : while(it != old_peer_list.end()) {
265 17 : std::set<const Peer *>::iterator prev_it = it;
266 17 : it++;
267 17 : if (peer_list_.find(*prev_it) != peer_list_.end()) {
268 16 : old_peer_list.erase(prev_it);
269 : }
270 : }
271 :
272 20 : DeleteRoute(route, old_peer_list);
273 :
274 20 : if (sync) {
275 : InetUnicastAgentRouteTable *table =
276 4 : dest_vrf_->GetInet4UnicastRouteTable();
277 4 : table->ResyncRoute(agent_->fabric_rt_export_peer(),
278 4 : dest_vrf_->GetName(), uc_rt->prefix_address(), uc_rt->prefix_length());
279 : }
280 20 : }
281 :
282 45 : void RouteLeakState::DeleteRoute(const AgentRoute *route,
283 : const std::set<const Peer *> &peer_list) {
284 45 : if (dest_vrf_ == NULL) {
285 6 : return;
286 : }
287 :
288 39 : std::set<const Peer *>::const_iterator it = peer_list.begin();
289 43 : for(; it != peer_list.end(); it++) {
290 4 : const InetUnicastRouteEntry *uc_rt =
291 : static_cast<const InetUnicastRouteEntry *>(route);
292 8 : dest_vrf_->GetInet4UnicastRouteTable()->Delete(*it,
293 : dest_vrf_->GetName(),
294 4 : uc_rt->prefix_address(),
295 4 : 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 39 : bool RouteLeakVrfState::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
359 39 : AgentRoute *route = static_cast<AgentRoute *>(entry);
360 : RouteLeakState *state =
361 39 : static_cast<RouteLeakState *>(entry->GetState(partition->parent(),
362 : route_listener_id_));
363 :
364 39 : 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 33 : 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 33 : if (state == NULL) {
381 0 : return true;
382 : }
383 :
384 33 : if (state->dest_vrf() != dest_vrf_) {
385 6 : state->DeleteRoute(route, state->peer_list());
386 : }
387 :
388 33 : 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 33 : if (state->dest_vrf()) {
394 33 : state->AddRoute(route);
395 : }
396 33 : 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 304 : void RouteLeakManager::Notify(DBTablePartBase *partition, DBEntryBase *entry) {
422 304 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
423 : RouteLeakVrfState *state =
424 304 : static_cast<RouteLeakVrfState *>(entry->GetState(partition->parent(),
425 : vrf_listener_id_));
426 :
427 304 : if (vrf->IsDeleted()) {
428 252 : if (state) {
429 3 : entry->ClearState(partition->parent(), vrf_listener_id_);
430 3 : state->Delete();
431 : }
432 252 : return;
433 : }
434 :
435 :
436 52 : if (state == NULL && vrf->forwarding_vrf()) {
437 3 : state = new RouteLeakVrfState(vrf, NULL);
438 : }
439 :
440 52 : if (state == NULL) {
441 49 : 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 : }
|