Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include <boost/uuid/uuid_io.hpp>
5 : #include <boost/lexical_cast.hpp>
6 :
7 : #include <cmn/agent_cmn.h>
8 : #include <route/route.h>
9 :
10 : #include <vnc_cfg_types.h>
11 : #include <agent_types.h>
12 :
13 : #include <init/agent_param.h>
14 : #include <oper/peer.h>
15 : #include <oper/vrf.h>
16 : #include <oper/interface_common.h>
17 : #include <oper/nexthop.h>
18 : #include <oper/tunnel_nh.h>
19 : #include <oper/vn.h>
20 : #include <oper/mirror_table.h>
21 : #include <oper/vxlan.h>
22 : #include <oper/mpls.h>
23 : #include <oper/route_common.h>
24 : #include <oper/multicast.h>
25 : #include <sandesh/sandesh_trace.h>
26 : #include <sandesh/common/vns_constants.h>
27 : #include <resource_manager/resource_manager.h>
28 : #include <resource_manager/resource_table.h>
29 : #include <resource_manager/mpls_index.h>
30 :
31 : #include <oper/physical_device.h>
32 : using namespace std;
33 : using namespace boost::asio;
34 :
35 : class AgentRouteTable::DeleteActor : public LifetimeActor {
36 : public:
37 144 : DeleteActor(AgentRouteTable *rt_table) :
38 : LifetimeActor(rt_table->agent()->lifetime_manager()),
39 144 : table_(rt_table) {
40 144 : }
41 288 : virtual ~DeleteActor() {
42 288 : }
43 146 : virtual bool MayDelete() const {
44 146 : return table_->MayDelete();
45 : }
46 144 : virtual void Shutdown() {
47 144 : }
48 144 : virtual void Destroy() {
49 144 : assert(table_->vrf_entry_.get() != NULL);
50 144 : table_->vrf_entry_->SetRouteTableDeleted(table_->GetTableType());
51 : //Release refernces
52 144 : table_->vrf_delete_ref_.Reset(NULL);
53 144 : table_->vrf_entry_ = NULL;
54 144 : }
55 :
56 : private:
57 : AgentRouteTable *table_;
58 : };
59 :
60 821 : bool RouteComparator::operator() (const AgentRoute *rt1, const AgentRoute *rt2) const {
61 821 : return rt1->IsLess(*rt2);
62 : }
63 :
64 0 : bool NHComparator::operator() (const NextHop *nh1, const NextHop *nh2) const {
65 0 : return nh1->IsLess(*nh2);
66 : }
67 :
68 : /////////////////////////////////////////////////////////////////////////////
69 : // AgentRouteTable routines
70 : /////////////////////////////////////////////////////////////////////////////
71 144 : AgentRouteTable::AgentRouteTable(DB *db, const std::string &name):
72 144 : RouteTable(db, name), agent_(NULL), vrf_id_(0), vrf_entry_(NULL, this),
73 144 : deleter_(NULL), vrf_delete_ref_(this, NULL), unresolved_rt_tree_(),
74 288 : unresolved_nh_tree_() {
75 144 : OperDBTraceBuf = SandeshTraceBufferCreate("OperRoute", 5000);
76 144 : }
77 :
78 144 : AgentRouteTable::~AgentRouteTable() {
79 144 : }
80 :
81 : // Allocate a route entry
82 2960 : unique_ptr<DBEntry> AgentRouteTable::AllocEntry(const DBRequestKey *k) const {
83 2960 : const AgentRouteKey *key = static_cast<const AgentRouteKey*>(k);
84 2960 : VrfKey vrf_key(key->vrf_name());
85 : AgentRoute *route =
86 2960 : static_cast<AgentRoute *>(key->AllocRouteEntry(vrf_entry_.get(),
87 : false));
88 5920 : return unique_ptr<DBEntry>(static_cast<DBEntry *>(route));
89 2960 : }
90 :
91 : // Algorithm to select an active path from multiple potential paths.
92 : // Uses comparator in path for selection
93 878 : bool AgentRouteTable::PathSelection(const Path &path1, const Path &path2) {
94 878 : const AgentPath &l_path = dynamic_cast<const AgentPath &> (path1);
95 878 : const AgentPath &r_path = dynamic_cast<const AgentPath &> (path2);
96 878 : return l_path.IsLess(r_path);
97 : }
98 :
99 144 : const string &AgentRouteTable::GetSuffix(Agent::RouteTableType type) {
100 144 : static const string uc_suffix(".uc.route.0");
101 144 : static const string mpls_suffix(".uc.route.3");
102 144 : static const string mc_suffix(".mc.route.0");
103 144 : static const string evpn_suffix(".evpn.route.0");
104 144 : static const string l2_suffix(".l2.route.0");
105 144 : static const string uc_inet6_suffix(".uc.route6.0");
106 :
107 144 : switch (type) {
108 24 : case Agent::INET4_UNICAST:
109 24 : return uc_suffix;
110 24 : case Agent::INET4_MPLS:
111 24 : return mpls_suffix;
112 24 : case Agent::INET4_MULTICAST:
113 24 : return mc_suffix;
114 24 : case Agent::EVPN:
115 24 : return evpn_suffix;
116 24 : case Agent::BRIDGE:
117 24 : return l2_suffix;
118 24 : case Agent::INET6_UNICAST:
119 24 : return uc_inet6_suffix;
120 0 : default:
121 0 : return Agent::NullString();
122 : }
123 : }
124 :
125 : // Set VRF and delete life-time actor reference to VRF
126 144 : void AgentRouteTable::SetVrf(VrfEntry *vrf) {
127 144 : agent_ = (static_cast<VrfTable *>(vrf->get_table()))->agent();
128 144 : vrf_entry_ = vrf;
129 144 : vrf_id_ = vrf->vrf_id();
130 144 : vrf_delete_ref_.Reset(vrf->deleter());
131 144 : deleter_.reset(new DeleteActor(this));
132 144 : }
133 :
134 : //Delete all the routes
135 144 : void AgentRouteTable::ManagedDelete() {
136 144 : RouteTableWalkerState *state = new RouteTableWalkerState(deleter());
137 : DBTable::DBTableWalkRef walk_ref = AllocWalker(
138 : boost::bind(&AgentRouteTable::DelExplicitRouteWalkerCb, this, _1, _2),
139 288 : boost::bind(&AgentRouteTable::DeleteRouteDone, this, _1, _2, state));
140 : //On managed delete, walk to delete paths need to be done once as no route
141 : //should be added in deleted vrf.
142 : //Once the walk is over walkdone will reset walk_ref.
143 144 : WalkTable(walk_ref);
144 144 : deleter_->Delete();
145 144 : }
146 :
147 144 : void AgentRouteTable::DeleteRouteDone(DBTable::DBTableWalkRef walk_ref,
148 : DBTableBase *base,
149 : RouteTableWalkerState *state) {
150 144 : LOG(DEBUG, "Deleted all BGP injected routes for " << base->name());
151 144 : ReleaseWalker(walk_ref);
152 144 : delete state;
153 144 : }
154 :
155 1 : bool AgentRouteTable::DelExplicitRouteWalkerCb(DBTablePartBase *part,
156 : DBEntryBase *entry) {
157 1 : AgentRoute *route = static_cast<AgentRoute *>(entry);
158 1 : if (route == NULL)
159 0 : return true;
160 :
161 1 : return route->DeleteAllBgpPath(part, this);
162 : }
163 :
164 1394 : void AgentRouteTable::RetryDelete() {
165 1394 : if (!deleter()->IsDeleted()) {
166 796 : return;
167 : }
168 598 : if (empty()) {
169 594 : vrf_entry()->RetryDelete();
170 : }
171 598 : deleter()->RetryDelete();
172 : }
173 :
174 0 : void AgentRouteTable::NotifyEntry(AgentRoute *e) {
175 0 : agent()->ConcurrencyCheck();
176 : DBTablePartBase *tpart =
177 0 : static_cast<DBTablePartition *>(GetTablePartition(e));
178 0 : tpart->Notify(e);
179 0 : }
180 :
181 : /////////////////////////////////////////////////////////////////////////////
182 : // Agent route input processing
183 : /////////////////////////////////////////////////////////////////////////////
184 :
185 : // Inline processing of Route request.
186 952 : void AgentRouteTable::Process(DBRequest &req) {
187 952 : agent()->ConcurrencyCheck();
188 : DBTablePartition *tpart =
189 952 : static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
190 952 : tpart->Process(NULL, &req);
191 952 : }
192 :
193 : // Input handler for Route Table.
194 : // Adds a route entry if not present.
195 : // Adds path to route entry
196 : // Paths are sorted in order of their precedence
197 : // A DELETE request always removes path from the peer
198 : // Route entry with no paths is automatically deleted
199 3582 : void AgentRouteTable::Input(DBTablePartition *part, DBClient *client,
200 : DBRequest *req) {
201 3582 : AgentRouteKey *key = static_cast<AgentRouteKey *>(req->key.get());
202 3582 : AgentRouteData *data = static_cast<AgentRouteData *>(req->data.get());
203 :
204 3582 : VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(key->vrf_name());
205 : // Ignore request if VRF not found.
206 : // VRF in deleted state is handled below based on operation
207 3582 : if (vrf == NULL)
208 1 : return;
209 :
210 : // We dont force DBRequest to be enqueued to the right DB Table.
211 : // Find the right DBTable from VRF and invoke Input from right table
212 3581 : AgentRouteTable *req_table = vrf->GetRouteTable(key->GetRouteTableType());
213 3581 : if (req_table != this) {
214 1218 : if (req_table == NULL) {
215 : // If route table is already deleted from VRF, it means VRF should
216 : // also be in deleted state
217 3 : assert(vrf->IsDeleted());
218 3 : return;
219 : }
220 :
221 : DBTablePartition *p =
222 1215 : static_cast<DBTablePartition *>(req_table->GetTablePartition(key));
223 1215 : req_table->Input(p, client, req);
224 1215 : return;
225 : }
226 :
227 2363 : AgentRoute *rt = static_cast<AgentRoute *>(part->Find(key));
228 2363 : if (req->oper == DBRequest::DB_ENTRY_DELETE) {
229 934 : if (rt)
230 556 : rt->DeleteInput(part, this, key, data);
231 934 : return;
232 : }
233 :
234 1429 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
235 1429 : AddChangeInput(part, vrf, rt, key, data);
236 1429 : return;
237 : }
238 :
239 0 : assert(0);
240 : }
241 :
242 : // Handle RESYNC and ADD_CHANGE requests
243 1429 : void AgentRouteTable::AddChangeInput(DBTablePartition *part, VrfEntry *vrf,
244 : AgentRoute *rt, AgentRouteKey *key,
245 : AgentRouteData *data) {
246 1429 : if (key->peer()->SkipAddChangeRequest()) {
247 0 : AGENT_ROUTE_LOG(this, "Route operation ignored. Deleted Peer ",
248 : key->ToString(), vrf_name(), key->peer()->GetName());
249 0 : return;
250 : }
251 :
252 1429 : if (vrf->IsDeleted() && vrf->allow_route_add_on_deleted_vrf() == false)
253 0 : return;
254 :
255 1429 : AgentPath *path = NULL;
256 1429 : bool notify = false;
257 1429 : const NextHop *nh = NULL;
258 1429 : if (rt) {
259 1053 : nh = rt->GetActiveNextHop();
260 : }
261 1429 : if (key->sub_op_ == AgentKey::RESYNC) {
262 : // Process RESYNC only if route present and not-deleted
263 680 : if (rt && (rt->IsDeleted() == false))
264 678 : notify |= rt->SubOpResyncInput(vrf, this, &path, key, data);
265 749 : } else if (key->sub_op_ == AgentKey::ADD_DEL_CHANGE) {
266 749 : bool route_added = (rt == NULL);
267 749 : rt = LocateRoute(part, vrf, rt, key, data, ¬ify);
268 749 : notify |= rt->SubOpAddChangeInput(vrf, this, &path, key, data,
269 : route_added);
270 : } else {
271 0 : assert(0);
272 : }
273 :
274 : // If this route has a unresolved path, insert to unresolved list
275 : // this is a hack , TODO: fix unresolved route handling correctly
276 1429 : if (rt && rt->HasUnresolvedPath() == true) {
277 358 : rt->AddUnresolvedRouteToTable(this);
278 : }
279 : // Route changed, trigger change on dependent routes
280 1429 : if (notify) {
281 1256 : bool active_path_changed = (path == rt->GetActivePath());
282 1256 : const AgentPath *prev_active_path = rt->GetActivePath();
283 1256 : CompositeNH *cnh = NULL;
284 1256 : if (prev_active_path) {
285 1256 : cnh = dynamic_cast<CompositeNH *>(prev_active_path->nexthop());
286 : }
287 1256 : const Path *prev_front = rt->front();
288 1256 : if (prev_front) {
289 1256 : rt->Sort(&AgentRouteTable::PathSelection, prev_front);
290 : }
291 1256 : if (rt->GetActiveNextHop() != nh) {
292 437 : active_path_changed = true;
293 : }
294 : // for flow stickiness , maintain same component NH grid
295 : // if the newly insterted path becomes active,
296 : // if peer type is same, and it is composite NH
297 : // then import previous active NH to current active path
298 : // Note: Change is limited to BGP peer paths
299 1730 : if ( (path == rt->GetActivePath()) &&
300 474 : (path != prev_active_path)) {
301 : CompositeNH *new_cnh =
302 0 : dynamic_cast<CompositeNH *>(path->nexthop());
303 0 : if (cnh && new_cnh &&
304 0 : (path->peer()->GetType() == Peer::BGP_PEER) &&
305 0 : (prev_active_path->peer()->GetType() == Peer::BGP_PEER) &&
306 0 : (cnh->composite_nh_type() == Composite::ECMP) &&
307 0 : (new_cnh->composite_nh_type() == Composite::ECMP)) {
308 0 : path->ImportPrevActiveNH(agent_, cnh);
309 : }
310 : }
311 1256 : part->Notify(rt);
312 1256 : rt->UpdateDependantRoutes();
313 1256 : rt->ResyncTunnelNextHop();
314 :
315 : // Since newly added path became active path, send path with
316 : // path_changed flag as true. Path can be NULL for resync requests
317 1256 : active_path_changed |= (path == rt->GetActivePath());
318 1256 : rt->UpdateDerivedRoutes(this, path, active_path_changed);
319 : }
320 : }
321 :
322 749 : AgentRoute *AgentRouteTable::LocateRoute(DBTablePartition *part,
323 : VrfEntry *vrf, AgentRoute *rt,
324 : AgentRouteKey *key,
325 : AgentRouteData *data, bool *notify) {
326 : // Return if route already present and not deleted
327 749 : if (rt != NULL && rt->IsDeleted() == false)
328 375 : return rt;
329 :
330 : // Add route if not present already
331 374 : if (rt == NULL) {
332 : rt = static_cast<AgentRoute *>
333 374 : (key->AllocRouteEntry(vrf, data->is_multicast()));
334 374 : assert(rt->vrf() != NULL);
335 374 : part->Add(rt);
336 : }
337 :
338 : // Renew the route if its in deleted state
339 374 : if (rt->IsDeleted()) {
340 0 : assert(rt->IsDeleted());
341 0 : rt->ClearDelete();
342 0 : *notify = true;
343 : }
344 :
345 374 : ProcessAdd(rt);
346 374 : RouteInfo rt_info;
347 374 : rt->FillTrace(rt_info, AgentRoute::ADD, NULL);
348 374 : OPER_TRACE_ROUTE_ENTRY(Route, this, rt_info);
349 374 : return rt;
350 374 : }
351 :
352 358 : void AgentRoute::AddUnresolvedRouteToTable(AgentRouteTable *table) {
353 :
354 358 : if (dependent_route_table_ == NULL) {
355 58 : const AgentPath *path = GetActivePath();
356 58 : if (path->GetDependentTable()) {
357 0 : dependent_route_table_ = path->GetDependentTable();
358 : } else {
359 58 : dependent_route_table_ = table;
360 : }
361 : }
362 358 : dependent_route_table_->AddUnresolvedRoute(this);
363 358 : }
364 374 : void AgentRoute::RemoveUnresolvedRouteFromTable(AgentRouteTable *table) {
365 374 : if (dependent_route_table_) {
366 58 : dependent_route_table_->RemoveUnresolvedRoute(this);
367 : } else {
368 316 : table->RemoveUnresolvedRoute(this);
369 : }
370 374 : }
371 :
372 :
373 : // Re-evaluate all unresolved NH. Flush and enqueue RESYNC for all NH in the
374 : // unresolved NH tree
375 374 : void AgentRouteTable::EvaluateUnresolvedNH(void) {
376 374 : for (UnresolvedNHTree::iterator it = unresolved_nh_tree_.begin();
377 374 : it != unresolved_nh_tree_.end(); ++it) {
378 0 : (*it)->EnqueueResync();
379 :
380 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
381 0 : req.key = (*it)->GetDBRequestKey();
382 0 : (static_cast<NextHopKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
383 0 : agent_->nexthop_table()->Enqueue(&req);
384 0 : }
385 :
386 374 : unresolved_nh_tree_.clear();
387 374 : }
388 :
389 0 : void AgentRouteTable::AddUnresolvedNH(const NextHop *nh) {
390 0 : unresolved_nh_tree_.insert(nh);
391 0 : }
392 :
393 9 : void AgentRouteTable::RemoveUnresolvedNH(const NextHop *nh) {
394 9 : unresolved_nh_tree_.erase(nh);
395 9 : }
396 :
397 : // Re-evaluate all unresolved routes. Flush and enqueue RESYNC for all routes
398 : // in the unresolved route tree
399 374 : void AgentRouteTable::EvaluateUnresolvedRoutes(void) {
400 374 : for (UnresolvedRouteTree::iterator it = unresolved_rt_tree_.begin();
401 444 : it != unresolved_rt_tree_.end(); ++it) {
402 70 : (*it)->EnqueueRouteResync();
403 : }
404 :
405 374 : unresolved_rt_tree_.clear();
406 374 : }
407 :
408 358 : void AgentRouteTable::AddUnresolvedRoute(const AgentRoute *rt) {
409 358 : unresolved_rt_tree_.insert(rt);
410 358 : }
411 :
412 748 : void AgentRouteTable::RemoveUnresolvedRoute(const AgentRoute *rt) {
413 748 : unresolved_rt_tree_.erase(rt);
414 748 : }
415 :
416 : // Find entry not in deleted state
417 18 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRouteKey *key) {
418 18 : AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
419 18 : if (entry && entry->IsDeleted()) {
420 0 : return NULL;
421 : }
422 18 : return entry;
423 : }
424 :
425 9 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRouteKey *key) {
426 9 : DBTable *table = static_cast<DBTable *>(this);
427 9 : AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
428 9 : if (entry && entry->IsDeleted()) {
429 0 : return NULL;
430 : }
431 9 : return entry;
432 : }
433 :
434 54 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRoute *key) {
435 54 : AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
436 54 : if (entry && entry->IsDeleted()) {
437 0 : return NULL;
438 : }
439 54 : return entry;
440 : }
441 :
442 98 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRoute *key) {
443 98 : DBTable *table = static_cast<DBTable *>(this);
444 98 : AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
445 98 : if (entry && entry->IsDeleted()) {
446 5 : return NULL;
447 : }
448 93 : return entry;
449 : }
450 :
451 2532 : LifetimeActor *AgentRouteTable::deleter() {
452 2532 : return deleter_.get();
453 : }
454 :
455 163 : const std::string &AgentRouteTable::vrf_name() const {
456 163 : return vrf_entry_->GetName();
457 : }
458 :
459 3478 : VrfEntry *AgentRouteTable::vrf_entry() const {
460 3478 : return vrf_entry_.get();
461 : }
462 :
463 : /////////////////////////////////////////////////////////////////////////////
464 : // AgentRoute routines
465 : /////////////////////////////////////////////////////////////////////////////
466 :
467 : // Hnadle RESYNC operation for a route
468 678 : bool AgentRoute::SubOpResyncInput(VrfEntry *vrf, AgentRouteTable *table,
469 : AgentPath **path_ptr, AgentRouteKey *key,
470 : AgentRouteData *data) {
471 : // Handle change to route itself and not to a particular path
472 678 : if (data == NULL || key->peer() == NULL) {
473 665 : Sync();
474 665 : return true;
475 : }
476 :
477 : // Get path to update
478 13 : AgentPath *path = FindPath(key->peer());
479 13 : if (path == NULL)
480 0 : return false;
481 :
482 13 : bool ret = false;
483 13 : *path_ptr = path;
484 13 : bool old_ecmp = path->path_preference().is_ecmp();
485 13 : if (data->AddChangePath(table->agent(), path, this))
486 13 : ret = true;
487 :
488 : // Transition from ECMP to non-ECMP should result in removal of member
489 : // from ECMP path
490 13 : if (old_ecmp && old_ecmp != path->path_preference().is_ecmp()) {
491 0 : ReComputePathDeletion(path);
492 0 : return ret;
493 : }
494 :
495 13 : if (ReComputePathAdd(path))
496 1 : ret = true;
497 :
498 13 : return ret;
499 : }
500 :
501 749 : bool AgentRoute::SubOpAddChangeInput(VrfEntry *vrf, AgentRouteTable *table,
502 : AgentPath **path_ptr, AgentRouteKey *key,
503 : AgentRouteData *data, bool route_added) {
504 749 : bool ret = false;
505 : // Update route level attributes first
506 749 : if (data && data->UpdateRoute(this))
507 96 : ret = true;
508 :
509 : AgentRoute::Trace event;
510 749 : AgentPath *path = FindPathUsingKeyData(key, data);
511 : // Allocate path if not yet present
512 749 : if (path == NULL) {
513 476 : path = data->CreateAgentPath(key->peer(), this);
514 476 : InsertPath(path);
515 476 : data->AddChangePath(table->agent(), path, this);
516 476 : set_origin_vn_name(path->dest_vn_list());
517 476 : ret = true;
518 476 : event = AgentRoute::ADD_PATH;
519 : } else {
520 273 : bool ecmp = path->path_preference().is_ecmp();
521 273 : if (data->AddChangePath(table->agent(), path, this))
522 102 : ret = true;
523 :
524 : // Transition from ECMP to non-ECMP should result in removal of member
525 : // from ECMP path
526 273 : if (ecmp && ecmp != path->path_preference().is_ecmp()) {
527 0 : ReComputePathDeletion(path);
528 : }
529 273 : event = AgentRoute::CHANGE_PATH;
530 : }
531 :
532 : // Trace log for path add/change
533 749 : RouteInfo rt_info;
534 749 : FillTrace(rt_info, event, path);
535 749 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
536 :
537 749 : if (path->RouteNeedsSync())
538 125 : ret |= Sync();
539 :
540 749 : if (route_added) {
541 374 : table->EvaluateUnresolvedRoutes();
542 374 : table->EvaluateUnresolvedNH();
543 : }
544 :
545 : // Do necessary recompute on addition of path
546 749 : if (ReComputePathAdd(path))
547 67 : ret = true;
548 :
549 749 : *path_ptr = path;
550 749 : return ret;
551 749 : }
552 :
553 : // Handle DELETE operation for a route. Deletes path created by peer in key.
554 : // Ideally only peer match is required in path however for few cases
555 : // more than peer comparision be required.
556 556 : void AgentRoute::DeleteInput(DBTablePartition *part, AgentRouteTable *table,
557 : AgentRouteKey *key, AgentRouteData *data) {
558 556 : assert (key->sub_op_ == AgentKey::ADD_DEL_CHANGE);
559 556 : bool force_delete = false;
560 : // If peer in key is deleted, set force_delete to true.
561 556 : if (key->peer()->IsDeleted() || key->peer()->SkipAddChangeRequest())
562 0 : force_delete = true;
563 :
564 : // In case of multicast routes, BGP can give multiple paths.
565 : // So, iterate thru all paths and identify paths that can be deleted
566 556 : for (Route::PathList::iterator it = GetPathList().begin();
567 2406 : it != GetPathList().end(); ) {
568 647 : AgentPath *path = static_cast<AgentPath *>(it.operator->());
569 : // Current path can be deleted below. Incremnt the iterator and dont
570 : // use it again below
571 647 : it++;
572 :
573 647 : if (key->peer() != path->peer())
574 146 : continue;
575 :
576 : bool check_can_delete =
577 994 : ((key->peer()->GetType() == Peer::BGP_PEER) ||
578 986 : (key->peer()->GetType() == Peer::EVPN_ROUTING_PEER) ||
579 1487 : (key->peer()->GetType() == Peer::EVPN_PEER) ||
580 412 : (key->peer()->GetType() == Peer::INET_EVPN_PEER));
581 :
582 501 : if (force_delete)
583 0 : check_can_delete = false;
584 :
585 : // There are two ways to receive delete of BGP peer path in l2 route.
586 : // First is via withdraw meesage from control node in which
587 : // force_delete will be false and vxlan_id will be matched to
588 : // decide.
589 : // Second can be via route walkers where on peer going down or vrf
590 : // delete, paths from BGP peer should be deleted irrespective of
591 : // vxlan_id.
592 616 : if (check_can_delete && data &&
593 115 : data->CanDeletePath(table->agent(), path, this) == false) {
594 26 : continue;
595 : }
596 :
597 475 : DeletePathFromPeer(part, table, path);
598 : }
599 556 : }
600 :
601 495 : void AgentRoute::InsertPath(const AgentPath *path) {
602 495 : const Path *prev_front = front();
603 495 : insert(path);
604 495 : Sort(&AgentRouteTable::PathSelection, prev_front);
605 495 : }
606 :
607 495 : void AgentRoute::RemovePath(AgentPath *path) {
608 495 : const Path *prev_front = front();
609 495 : remove(path);
610 495 : Sort(&AgentRouteTable::PathSelection, prev_front);
611 495 : return;
612 : }
613 :
614 : // Delete all paths from BGP Peer. Delete route if no path left
615 1 : bool AgentRoute::DeleteAllBgpPath(DBTablePartBase *part,
616 : AgentRouteTable *table) {
617 1 : for(Route::PathList::iterator it = GetPathList().begin();
618 4 : it != GetPathList().end();) {
619 1 : AgentPath *path = static_cast<AgentPath *>(it.operator->());
620 1 : it++;
621 :
622 1 : const Peer *peer = path->peer();
623 1 : if (peer == NULL)
624 0 : continue;
625 :
626 1 : if (peer->GetType() == Peer::BGP_PEER ||
627 1 : peer->GetType() == Peer::EVPN_ROUTING_PEER ||
628 0 : peer->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER) {
629 1 : DeletePathFromPeer(part, table, path);
630 0 : } else if (peer->GetType() == Peer::LOCAL_VM_PEER) {
631 : // Delete LOCAL_VM_PEER paths only from routes belonging to
632 : // routing VRFs
633 0 : VrfEntry *vrf = vrf_;
634 0 : if (vrf && vrf->routing_vrf() && (table->GetTableType() == Agent::EVPN)) {
635 0 : DeletePathFromPeer(part, table, path);
636 : }
637 : }
638 : }
639 :
640 1 : return true;
641 : }
642 :
643 : // Delete path from the given peer.
644 : // If all paths are deleted,
645 : // delete the route and notify
646 : // Else
647 : // Notify the DBEntry if any path is deleted
648 : //
649 : // Ideally, route must be notified only when active-path is deleted,
650 : // But, notification of deleting non-active path is needed in one case.
651 : //
652 : // For VM spawned locally, we path BGP_PEER path with higher priority than
653 : // LOCAL_VM peer path. But, controller-peer needs to know deletion of
654 : // LOCAL_VM path to retract the route. So, force notify deletion of any path.
655 476 : void AgentRoute::DeletePathFromPeer(DBTablePartBase *part,
656 : AgentRouteTable *table, AgentPath *path) {
657 :
658 476 : RouteInfo rt_info;
659 476 : FillTrace(rt_info, AgentRoute::DELETE_PATH, path);
660 476 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
661 :
662 476 : if (path == NULL) {
663 0 : return;
664 : }
665 :
666 : // Assign path to auto-pointer to delete it on return
667 476 : std::unique_ptr<AgentPath> path_ref(path);
668 :
669 : // TODO : Move this to end of delete processing?
670 : // Path deletion can result in changes such as ECMP-NH, Mulitcast NH etc
671 : // The algirthms expect path to be present in route still. So, do the
672 : // necessary recompute before path is deleted from route
673 476 : ReComputePathDeletion(path);
674 :
675 : // Store if this was active path
676 476 : bool active_path = (GetActivePath() == path);
677 476 : const Peer *old_active_path_peer = path->peer();
678 : // Remove path from the route
679 476 : RemovePath(path);
680 :
681 : // TODO : Move this code to ECMP Hash management code.
682 476 : CompositeNH *cnh = dynamic_cast<CompositeNH *>(path->nexthop());
683 476 : if (cnh) {
684 36 : path->ResetEcmpHashFields();
685 36 : cnh->UpdateEcmpHashFieldsUponRouteDelete(table->agent(),
686 : table->vrf_name());
687 : }
688 :
689 : // Delete route if no more paths
690 476 : if (GetActivePath() == NULL) {
691 374 : RouteInfo rt_info_del;
692 374 : FillTrace(rt_info_del, AgentRoute::DEL, NULL);
693 374 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info_del);
694 374 : DeleteDerivedRoutes(table);
695 374 : table->RemoveUnresolvedRoute(this); // TODO: remove this call and make changes in gw route
696 374 : RemoveUnresolvedRouteFromTable(table);
697 374 : UpdateDependantRoutes();
698 374 : ResyncTunnelNextHop();
699 374 : table->ProcessDelete(this);
700 374 : part->Delete(this);
701 374 : } else {
702 : // change to support flow stickiness for ecmp paths
703 : // find new active path peer
704 : // if peer type is same, and it is composite NH
705 : // then import previous active NH to current active path
706 : // Note: Change is limited to paths of same type
707 102 : const Peer *new_active_path_peer = GetActivePath()->peer();
708 102 : AgentPath *new_active_path = FindPath(new_active_path_peer);
709 102 : CompositeNH *new_cnh = NULL;
710 102 : if (new_active_path && new_active_path->nexthop()) {
711 100 : new_cnh =
712 100 : dynamic_cast<CompositeNH *>(new_active_path->nexthop());
713 : }
714 51 : if (active_path &&
715 30 : cnh && new_cnh &&
716 15 : (old_active_path_peer->GetType() == Peer::BGP_PEER) &&
717 0 : (new_active_path_peer->GetType() == Peer::BGP_PEER) &&
718 153 : (cnh->composite_nh_type() == Composite::ECMP) &&
719 0 : (new_cnh->composite_nh_type() == Composite::ECMP)) {
720 0 : new_active_path->ImportPrevActiveNH(table->agent(), cnh);
721 : }
722 : // Notify deletion of path.
723 102 : part->Notify(this);
724 102 : UpdateDerivedRoutes(table, NULL, active_path);
725 : }
726 476 : }
727 :
728 0 : AgentPath *AgentRoute::FindLocalPath() const {
729 0 : for(Route::PathList::const_iterator it = GetPathList().begin();
730 0 : it != GetPathList().end(); it++) {
731 0 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
732 0 : if (path->peer() == NULL) {
733 0 : continue;
734 : }
735 0 : if (path->peer()->GetType() == Peer::LOCAL_PEER ||
736 0 : path->peer()->GetType() == Peer::LINKLOCAL_PEER) {
737 0 : return const_cast<AgentPath *>(path);
738 : }
739 : }
740 0 : return NULL;
741 : }
742 :
743 1132 : AgentPath *AgentRoute::FindLocalVmPortPath() const {
744 1541 : for(Route::PathList::const_iterator it = GetPathList().begin();
745 3082 : it != GetPathList().end(); it++) {
746 1060 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
747 1060 : if (path->peer() == NULL) {
748 0 : continue;
749 : }
750 1060 : if (path->peer()->export_to_controller()) {
751 651 : return const_cast<AgentPath *>(path);
752 : }
753 :
754 818 : if (path->peer()->GetType() == Peer::ECMP_PEER ||
755 818 : path->peer()->GetType() == Peer::VGW_PEER ||
756 818 : path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER ||
757 1227 : path->peer()->GetType() == Peer::MULTICAST_TOR_PEER ||
758 409 : path->peer()->GetType() == Peer::OVS_PEER) {
759 0 : return const_cast<AgentPath *>(path);
760 : }
761 : }
762 481 : return NULL;
763 : }
764 :
765 : /// @brief returns true if the given path is not null and points
766 : // to a local composite interface
767 0 : bool RtPathHasInterfaceComposite (const AgentPath* a_path) {
768 0 : const NextHop *a_nh = NULL;
769 :
770 0 : if (!a_path) {
771 0 : return false;
772 : }
773 :
774 0 : a_nh = a_path->nexthop();
775 0 : if (!a_nh) {
776 0 : return false;
777 : }
778 :
779 0 : if (a_path->peer()->export_to_controller() &&
780 0 : a_nh->GetType() == NextHop::COMPOSITE) {
781 0 : return true;
782 : }
783 :
784 0 : if (a_path->peer()->GetType() == Peer::ECMP_PEER) {
785 0 : return true;
786 : }
787 :
788 0 : return false;
789 : }
790 :
791 : /// @brief returns true if the given path is not null and points
792 : // to a local interface
793 0 : bool RtPathHasLocalInterface(const AgentPath* a_path) {
794 0 : const NextHop *a_nh = NULL;
795 :
796 0 : if (!a_path) {
797 0 : return false;
798 : }
799 :
800 0 : a_nh = a_path->nexthop();
801 0 : if (!a_nh) {
802 0 : return false;
803 : }
804 :
805 0 : if (a_path->peer()->export_to_controller() &&
806 0 : a_nh->GetType() == NextHop::INTERFACE) {
807 0 : return true;
808 : }
809 :
810 0 : if (a_path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
811 0 : return true;
812 : }
813 :
814 0 : return false;
815 : }
816 :
817 11 : const AgentPath *AgentRoute::FindIntfOrCompLocalVmPortPath() const {
818 11 : const AgentPath *intf_path = NULL;
819 11 : const AgentPath *icom_path = NULL;
820 11 : for (Route::PathList::const_iterator it =
821 11 : this->GetPathList().begin();
822 22 : it != this->GetPathList().end(); it++) {
823 : const AgentPath *path = static_cast<const AgentPath *>
824 0 : (it.operator->());
825 :
826 0 : if (intf_path == NULL &&
827 0 : RtPathHasLocalInterface(path)) {
828 0 : intf_path = path;
829 0 : continue;
830 : }
831 0 : if (RtPathHasInterfaceComposite(path)) {
832 0 : icom_path = path;
833 0 : continue;
834 : }
835 : }
836 11 : if (icom_path) {
837 0 : return icom_path;
838 : }
839 11 : if (intf_path) {
840 0 : return intf_path;
841 : }
842 11 : return NULL;
843 : }
844 :
845 0 : AgentPath *AgentRoute::GetLocalVmPortPath() const {
846 0 : for(Route::PathList::const_iterator it = GetPathList().begin();
847 0 : it != GetPathList().end(); it++) {
848 0 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
849 0 : if (path->peer() == NULL) {
850 0 : continue;
851 : }
852 :
853 0 : if (path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) {
854 0 : return const_cast<AgentPath *>(path);
855 : }
856 : }
857 0 : return NULL;
858 : }
859 :
860 86 : AgentPath *AgentRoute::FindPathUsingKeyData(const AgentRouteKey *key,
861 : const AgentRouteData *data) const {
862 86 : return FindPath(key->peer());
863 : }
864 :
865 1607 : AgentPath *AgentRoute::FindPath(const Peer *peer) const {
866 2542 : for(Route::PathList::const_iterator it = GetPathList().begin();
867 5084 : it != GetPathList().end(); it++) {
868 1683 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
869 1683 : if (path->peer() == peer) {
870 748 : return const_cast<AgentPath *>(path);
871 : }
872 : }
873 859 : return NULL;
874 : }
875 :
876 : // First path in list is always treated as active path.
877 22411 : const AgentPath *AgentRoute::GetActivePath() const {
878 22411 : const AgentPath *path = static_cast<const AgentPath *>(front());
879 22411 : return (path ? path->UsablePath() : NULL);
880 : }
881 :
882 6272 : const NextHop *AgentRoute::GetActiveNextHop() const {
883 6272 : const AgentPath *path = GetActivePath();
884 6272 : if (path == NULL)
885 101 : return NULL;
886 :
887 6171 : return path->ComputeNextHop(static_cast<AgentRouteTable *>(get_table())->
888 6171 : agent());
889 : }
890 :
891 0 : uint32_t AgentRoute::GetActiveLabel() const {
892 0 : return GetActivePath()->label();
893 : };
894 :
895 : // If a direct route has changed, invoke a change on tunnel NH dependent on it
896 1630 : void AgentRoute::ResyncTunnelNextHop(void) {
897 1630 : for (AgentRoute::TunnelNhDependencyList::iterator iter =
898 3260 : tunnel_nh_list_.begin(); iter != tunnel_nh_list_.end(); iter++) {
899 :
900 0 : NextHop *nh = static_cast<NextHop *>(iter.operator->());
901 0 : DBEntryBase::KeyPtr key = nh->GetDBRequestKey();
902 0 : NextHopKey *nh_key = static_cast<NextHopKey *>(key.get());
903 0 : nh_key->sub_op_ = AgentKey::RESYNC;
904 :
905 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
906 0 : req.key = std::move(key);
907 0 : req.data.reset(NULL);
908 0 : Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
909 0 : agent->nexthop_table()->Enqueue(&req);
910 0 : }
911 1630 : }
912 :
913 : // Enqueue request to RESYNC a route
914 665 : void AgentRoute::EnqueueRouteResync(void) const {
915 665 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
916 665 : req.key = GetDBRequestKey();
917 665 : (static_cast<AgentKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
918 665 : Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
919 : /* Setting req.data only for default route */
920 665 : if (agent->is_l3mh() && this->ToString().compare("0.0.0.0/0") == 0) {
921 0 : VnListType vn_list;
922 0 : vn_list.insert(agent->fabric_vn_name());
923 0 : req.data.reset(new Inet4UnicastGatewayRoute(
924 0 : agent->params()->gateway_list(), agent->fabric_vrf_name(),
925 0 : vn_list, MplsTable::kInvalidLabel, SecurityGroupList(),
926 0 : TagList(), CommunityList(),
927 0 : true));
928 0 : }
929 665 : agent->fabric_inet4_unicast_table()->Enqueue(&req);
930 665 : }
931 :
932 : //If a direct route get modified invariably trigger change
933 : //on all dependent indirect routes, coz if a nexthop has
934 : //changed we need to update the same in datapath for indirect
935 : //routes
936 1660 : void AgentRoute::UpdateDependantRoutes(void) {
937 1749 : for (AgentRoute::RouteDependencyList::iterator iter =
938 3409 : dependant_routes_.begin(); iter != dependant_routes_.end(); iter++) {
939 89 : AgentRoute *rt = iter.operator->();
940 89 : rt->EnqueueRouteResync();
941 : }
942 1660 : }
943 :
944 1427 : bool AgentRoute::HasUnresolvedPath(void) {
945 4550 : for(Route::PathList::const_iterator it = GetPathList().begin();
946 6246 : it != GetPathList().end(); it++) {
947 : const AgentPath *path =
948 2054 : static_cast<const AgentPath *>(it.operator->());
949 2054 : if (path->unresolved() == true) {
950 358 : return true;
951 : }
952 : }
953 :
954 1069 : return false;
955 : }
956 :
957 : // Invoke SYNC on all paths to re-evaluate NH/active state
958 790 : bool AgentRoute::Sync(void) {
959 790 : bool ret = false;
960 1796 : for(Route::PathList::iterator it = GetPathList().begin();
961 3592 : it != GetPathList().end(); it++) {
962 1006 : AgentPath *path = static_cast<AgentPath *>(it.operator->());
963 1006 : if (path->Sync(this) == true) {
964 119 : if (GetActivePath() == path) {
965 107 : ret = true;
966 : }
967 : }
968 : }
969 790 : return ret;
970 : }
971 :
972 1535 : bool AgentRoute::WaitForTraffic() const {
973 1648 : for(Route::PathList::const_iterator it = GetPathList().begin();
974 3296 : it != GetPathList().end(); it++) {
975 1599 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
976 1599 : if (path->peer() && path->peer()->GetType() == Peer::INET_EVPN_PEER) {
977 36 : continue;
978 : }
979 1563 : if (path->path_preference().wait_for_traffic() == true) {
980 1486 : return true;
981 : }
982 : }
983 49 : return false;
984 : }
985 :
986 0 : bool AgentRoute::ProcessPath(Agent *agent, DBTablePartition *part,
987 : AgentPath *path, AgentRouteData *data) {
988 0 : bool ret = data->AddChangePath(agent, path, this);
989 0 : if (RecomputeRoutePath(agent, part, path, data)) {
990 0 : ret = true;
991 : }
992 0 : return ret;
993 : }
994 :
995 330 : AgentPath *AgentRouteData::CreateAgentPath(const Peer *peer,
996 : AgentRoute *rt) const {
997 330 : return (new AgentPath(peer, rt));
998 : }
999 :
1000 762 : bool AgentRouteData::AddChangePath(Agent *agent, AgentPath *path,
1001 : const AgentRoute *rt) {
1002 762 : path->set_peer_sequence_number(sequence_number_);
1003 :
1004 762 : if (agent->tsn_enabled() && !agent->forwarding_enabled()) {
1005 0 : bool is_inet_rt = false;
1006 0 : bool service_address = false;
1007 0 : if ((rt->GetTableType() == Agent::INET4_UNICAST) ||
1008 0 : (rt->GetTableType() == Agent::INET6_UNICAST)) {
1009 0 : is_inet_rt = true;
1010 : service_address = agent->params()->
1011 0 : IsConfiguredTsnHostRoute(rt->GetAddressString());
1012 : }
1013 0 : Peer::Type type = path->peer()->GetType();
1014 0 : bool local_route = false;
1015 0 : if ((type == Peer::LINKLOCAL_PEER) ||
1016 : (type == Peer::LOCAL_PEER))
1017 0 : local_route = true;
1018 0 : if (rt->FindLocalPath())
1019 0 : local_route = true;
1020 0 : if (is_inet_rt && (!service_address && !local_route) &&
1021 0 : (rt->vrf()->GetName().compare(agent->fabric_vrf_name()) != 0))
1022 0 : path->set_inactive(true);
1023 : }
1024 :
1025 762 : return AddChangePathExtended(agent, path, rt);
1026 : }
1027 14 : const string &AgentRoute::dest_vn_name() const {
1028 14 : assert(GetActivePath()->dest_vn_list().size() <= 1);
1029 14 : return *GetActivePath()->dest_vn_list().begin();
1030 : };
1031 :
1032 0 : string AgentRoute::ToString() const {
1033 0 : return "Route Entry";
1034 : }
1035 :
1036 12468 : bool AgentRoute::IsLess(const DBEntry &rhs) const {
1037 12468 : int cmp = CompareTo(static_cast<const Route &>(rhs));
1038 12468 : return (cmp < 0);
1039 : };
1040 :
1041 1612 : uint32_t AgentRoute::vrf_id() const {
1042 1612 : return vrf_->vrf_id();
1043 : }
1044 :
1045 146 : bool AgentRoute::IsRPFInvalid() const {
1046 146 : const AgentPath *path = GetActivePath();
1047 146 : if (path == NULL) {
1048 0 : return false;
1049 : }
1050 :
1051 146 : return path->is_subnet_discard();
1052 : }
1053 :
1054 0 : void AgentRoute::HandleDeviceMastershipUpdate(AgentPath *path, bool del) {
1055 0 : Agent *agent = Agent::GetInstance();
1056 0 : PhysicalDeviceTable *table = agent->physical_device_table();
1057 0 : CompositeNH *nh = static_cast<CompositeNH *>(path->nexthop());
1058 0 : ComponentNHList clist = nh->component_nh_list();
1059 0 : table->UpdateDeviceMastership(vrf()->GetName(), clist, del);
1060 0 : }
1061 :
1062 101 : void AgentRoute::HandleMulticastLabel(const Agent *agent,
1063 : AgentPath *path,
1064 : const AgentPath *local_peer_path,
1065 : const AgentPath *local_vm_peer_path,
1066 : bool del, uint32_t *evpn_label) {
1067 101 : *evpn_label = MplsTable::kInvalidLabel;
1068 :
1069 : //EVPN label is present in two paths:
1070 : // local_vm_peer(courtesy: vmi) or local_peer(courtesy: vn)
1071 : // Irrespective of delete/add operation if one of them is present and is not
1072 : // the affected path, then extract the label from same.
1073 : // By default pick it from available path (local or local_vm).
1074 101 : switch (path->peer()->GetType()) {
1075 67 : case Peer::LOCAL_VM_PEER:
1076 : //Use local_peer path for label
1077 67 : if (local_peer_path) {
1078 39 : *evpn_label = local_peer_path->label();
1079 39 : assert(*evpn_label != MplsTable::kInvalidLabel);
1080 : }
1081 67 : break;
1082 34 : case Peer::LOCAL_PEER:
1083 : //Use local_peer path for label
1084 34 : if (local_vm_peer_path) {
1085 0 : *evpn_label = local_vm_peer_path->label();
1086 0 : assert(*evpn_label != MplsTable::kInvalidLabel);
1087 : }
1088 34 : break;
1089 0 : default:
1090 0 : if (local_vm_peer_path) {
1091 0 : *evpn_label = local_vm_peer_path->label();
1092 0 : assert(*evpn_label != MplsTable::kInvalidLabel);
1093 0 : } else if (local_peer_path) {
1094 0 : *evpn_label = local_peer_path->label();
1095 0 : assert(*evpn_label != MplsTable::kInvalidLabel);
1096 : }
1097 0 : break;
1098 : }
1099 :
1100 : //Delete path evpn label if path is local_peer or local_vm_peer.
1101 : //Delete fabric label if path is multicast_fabric_tree
1102 101 : if (del) {
1103 35 : bool delete_label = false;
1104 : // On deletion of fabric path delete fabric label.
1105 : // Other type of label is evpn mcast label.
1106 : // EVPN label is deleted when both local peer and local_vm_peer path are
1107 : // gone.
1108 35 : if (path->peer()->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER)
1109 0 : delete_label = true;
1110 52 : else if ((path->peer() == agent->local_vm_peer()) ||
1111 17 : (path->peer() == agent->local_peer())) {
1112 35 : if (local_peer_path == NULL &&
1113 : local_vm_peer_path == NULL) {
1114 20 : delete_label = true;
1115 : //Reset evpn label to invalid as it is freed
1116 20 : if (*evpn_label == path->label()) {
1117 0 : *evpn_label = MplsTable::kInvalidLabel;
1118 : }
1119 : }
1120 : }
1121 35 : if (delete_label) {
1122 20 : agent->mpls_table()->FreeLabel(path->label(),
1123 : vrf()->GetName());
1124 : //Reset path label to invalid as it is freed
1125 20 : path->set_label(MplsTable::kInvalidLabel);
1126 : }
1127 35 : return;
1128 : }
1129 :
1130 : // Currently other than evpn label no other multicast path requires dynamic
1131 : // allocation so return.
1132 66 : if ((path != local_peer_path) && (path != local_vm_peer_path))
1133 0 : return;
1134 :
1135 : // Path already has label, return.
1136 66 : if (path->label() != MplsTable::kInvalidLabel) {
1137 31 : if (*evpn_label == MplsTable::kInvalidLabel) {
1138 22 : *evpn_label = path->label();
1139 : }
1140 31 : return;
1141 : }
1142 :
1143 : // If this is the first time i.e. local_peer has come with no local_vm_peer
1144 : // and vice versa then allocate label.
1145 : // If its not then we should have valid evpn label calculated above.
1146 35 : if (*evpn_label == MplsTable::kInvalidLabel) {
1147 : // XOR use - we shud never reach here when both are NULL or set.
1148 : // Only one should be present.
1149 20 : assert((local_vm_peer_path != NULL) ^ (local_peer_path != NULL));
1150 : // Allocate route label with discard nh, nh in label gets updated
1151 : // after composite-nh is created.
1152 20 : DiscardNHKey key;
1153 40 : *evpn_label = agent->mpls_table()->CreateRouteLabel(*evpn_label, &key,
1154 : vrf()->GetName(),
1155 40 : ToString());
1156 20 : }
1157 35 : assert(*evpn_label != MplsTable::kInvalidLabel);
1158 35 : path->set_label(*evpn_label);
1159 : }
1160 :
1161 101 : bool AgentRoute::ReComputeMulticastPaths(AgentPath *path, bool del) {
1162 101 : if (path->peer() == NULL) {
1163 0 : return false;
1164 : }
1165 :
1166 : //HACK: subnet route uses multicast NH. During IPAM delete
1167 : //subnet discard is deleted. Consider this as delete of all
1168 : //paths. Though this can be handled via multicast module
1169 : //which can also issue delete of all peers, however
1170 : //this is a temporary code as subnet route will not use
1171 : //multicast NH.
1172 101 : bool delete_all = false;
1173 101 : if (path->is_subnet_discard() && del) {
1174 0 : delete_all = true;
1175 : }
1176 :
1177 101 : Agent *agent = (static_cast<AgentRouteTable *> (get_table()))->agent();
1178 101 : if (del && (path->peer() == agent->multicast_peer()))
1179 0 : return false;
1180 :
1181 : //Possible paths:
1182 : //EVPN path - can be from multiple peers.
1183 : //Fabric path - from multicast builder
1184 : //Multicast peer
1185 101 : AgentPath *multicast_peer_path = NULL;
1186 101 : AgentPath *local_vm_peer_path = NULL;
1187 101 : AgentPath *evpn_peer_path = NULL;
1188 101 : AgentPath *fabric_peer_path = NULL;
1189 101 : AgentPath *tor_peer_path = NULL;
1190 101 : AgentPath *local_peer_path = NULL;
1191 101 : bool tor_path = false;
1192 :
1193 : const CompositeNH *cnh =
1194 101 : static_cast<const CompositeNH *>(path->nexthop());
1195 101 : if (cnh && (cnh->composite_nh_type() == Composite::TOR)) {
1196 0 : tor_path = true;
1197 : }
1198 :
1199 290 : for (Route::PathList::iterator it = GetPathList().begin();
1200 580 : it != GetPathList().end(); it++) {
1201 : AgentPath *it_path =
1202 189 : static_cast<AgentPath *>(it.operator->());
1203 :
1204 189 : if (delete_all && (it_path->peer() != agent->multicast_peer()))
1205 0 : continue;
1206 :
1207 : //Handle deletions
1208 189 : if (del && (path->peer() == it_path->peer())) {
1209 35 : if (path->peer()->GetType() != Peer::BGP_PEER)
1210 35 : continue;
1211 :
1212 : //Dive into comp NH type for BGP peer
1213 : const CompositeNH *it_path_comp_nh =
1214 0 : static_cast<const CompositeNH *>(it_path->nexthop());
1215 : const CompositeNH *comp_nh =
1216 0 : static_cast<const CompositeNH *>(path->nexthop());
1217 0 : if (it_path_comp_nh->composite_nh_type() ==
1218 0 : comp_nh->composite_nh_type())
1219 0 : continue;
1220 : }
1221 :
1222 : //Handle Add/Changes
1223 154 : if (it_path->inactive())
1224 0 : continue;
1225 154 : if (it_path->peer() == agent->local_vm_peer()) {
1226 49 : local_vm_peer_path = it_path;
1227 105 : } else if (it_path->peer()->GetType() == Peer::BGP_PEER) {
1228 : const CompositeNH *bgp_comp_nh =
1229 0 : static_cast<const CompositeNH *>(it_path->nexthop());
1230 : //Its a TOR NH
1231 0 : if (bgp_comp_nh && (bgp_comp_nh->composite_nh_type() ==
1232 : Composite::TOR)) {
1233 0 : if (tor_peer_path == NULL)
1234 0 : tor_peer_path = it_path;
1235 : }
1236 : //Pick up the first peer.
1237 0 : if (bgp_comp_nh && (bgp_comp_nh->composite_nh_type() ==
1238 : Composite::EVPN)) {
1239 0 : if (evpn_peer_path == NULL)
1240 0 : evpn_peer_path = it_path;
1241 : }
1242 105 : } else if (it_path->peer()->GetType() ==
1243 : Peer::MULTICAST_FABRIC_TREE_BUILDER) {
1244 0 : fabric_peer_path = it_path;
1245 105 : } else if (it_path->peer() == agent->multicast_peer()) {
1246 49 : multicast_peer_path = it_path;
1247 56 : } else if (it_path->peer() == agent->local_peer()) {
1248 56 : local_peer_path = it_path;
1249 : }
1250 : }
1251 :
1252 101 : if (tor_path) {
1253 0 : if ((del && (tor_peer_path == NULL)) || !del) {
1254 0 : HandleDeviceMastershipUpdate(path, del);
1255 : }
1256 : }
1257 :
1258 101 : uint32_t evpn_label = MplsTable::kInvalidLabel;
1259 101 : HandleMulticastLabel(agent, path, local_peer_path, local_vm_peer_path, del,
1260 : &evpn_label);
1261 :
1262 : //all paths are gone so delete multicast_peer path as well
1263 101 : if ((local_vm_peer_path == NULL) &&
1264 52 : (tor_peer_path == NULL) &&
1265 52 : (evpn_peer_path == NULL) &&
1266 : (fabric_peer_path == NULL)) {
1267 52 : if (multicast_peer_path != NULL) {
1268 18 : if ((evpn_label != MplsTable::kInvalidLabel) && (local_peer_path)) {
1269 : // Make evpn label point to discard-nh as composite-nh gets
1270 : // deleted.
1271 15 : DiscardNHKey key;
1272 30 : agent->mpls_table()->CreateRouteLabel(evpn_label, &key,
1273 : vrf()->GetName(),
1274 30 : ToString());
1275 15 : }
1276 18 : std::unique_ptr<AgentPath> path_ref(multicast_peer_path);
1277 18 : RemovePath(multicast_peer_path);
1278 18 : }
1279 52 : return true;
1280 : }
1281 :
1282 49 : bool learning_enabled = false;
1283 49 : bool pbb_nh = false;
1284 49 : uint32_t old_fabric_mpls_label = 0;
1285 49 : if (multicast_peer_path == NULL) {
1286 18 : multicast_peer_path = new MulticastRoutePath(agent->multicast_peer());
1287 18 : InsertPath(multicast_peer_path);
1288 : } else {
1289 : //Multicast peer path can have evpn or fabric label.
1290 : //Identify using isfabricmulticastlabel.
1291 31 : if (agent->mpls_table()->
1292 31 : IsFabricMulticastLabel(multicast_peer_path->label()))
1293 : {
1294 0 : old_fabric_mpls_label = multicast_peer_path->label();
1295 : }
1296 : }
1297 :
1298 49 : ComponentNHKeyList component_nh_list;
1299 :
1300 49 : if (tor_peer_path) {
1301 : NextHopKey *tor_peer_key =
1302 : static_cast<NextHopKey *>((tor_peer_path->
1303 0 : ComputeNextHop(agent)->GetDBRequestKey()).release());
1304 0 : std::unique_ptr<const NextHopKey> key4(tor_peer_key);
1305 0 : ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
1306 0 : component_nh_list.push_back(component_nh_data4);
1307 0 : }
1308 :
1309 49 : if (evpn_peer_path) {
1310 : NextHopKey *evpn_peer_key =
1311 : static_cast<NextHopKey *>((evpn_peer_path->
1312 0 : ComputeNextHop(agent)->GetDBRequestKey()).release());
1313 0 : std::unique_ptr<const NextHopKey> key2(evpn_peer_key);
1314 0 : ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(0, std::move(key2)));
1315 0 : component_nh_list.push_back(component_nh_data2);
1316 0 : }
1317 :
1318 49 : if (fabric_peer_path) {
1319 : NextHopKey *fabric_peer_key =
1320 : static_cast<NextHopKey *>((fabric_peer_path->
1321 0 : ComputeNextHop(agent)->GetDBRequestKey()).release());
1322 0 : std::unique_ptr<const NextHopKey> key3(fabric_peer_key);
1323 0 : ComponentNHKeyPtr component_nh_data3(new ComponentNHKey(0, std::move(key3)));
1324 0 : component_nh_list.push_back(component_nh_data3);
1325 0 : }
1326 :
1327 49 : if (local_vm_peer_path) {
1328 : NextHopKey *local_vm_peer_key =
1329 : static_cast<NextHopKey *>((local_vm_peer_path->
1330 49 : ComputeNextHop(agent)->GetDBRequestKey()).release());
1331 49 : std::unique_ptr<const NextHopKey> key4(local_vm_peer_key);
1332 49 : ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
1333 49 : component_nh_list.push_back(component_nh_data4);
1334 :
1335 49 : const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(
1336 49 : local_vm_peer_path->ComputeNextHop(agent));
1337 49 : if (cnh && cnh->learning_enabled() == true) {
1338 0 : learning_enabled = true;
1339 : }
1340 49 : if (cnh && cnh->pbb_nh() == true) {
1341 0 : pbb_nh = true;
1342 : }
1343 49 : }
1344 :
1345 49 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
1346 98 : nh_req.key.reset(new CompositeNHKey(GetMulticastCompType(),
1347 49 : ValidateMcastSrc(), false,
1348 : component_nh_list,
1349 49 : vrf()->GetName()));
1350 49 : nh_req.data.reset(new CompositeNHData(pbb_nh, learning_enabled,
1351 49 : vrf()->layer2_control_word()));
1352 49 : agent->nexthop_table()->Process(nh_req);
1353 98 : NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
1354 49 : FindActiveEntry(nh_req.key.get()));
1355 : //NH may not get added if VRF is marked for delete. Route may be in
1356 : //transition of getting deleted, skip NH modification.
1357 49 : if (!nh) {
1358 0 : return false;
1359 : }
1360 :
1361 : // Since we holding a ref to composite NHs from FMG labels now,
1362 : // it is possible for nh's ref to drop to zerp becuase of freelabel
1363 : // call below. Hold a ref until the nh is updated in labels i.e.,
1364 : // till the end of this function
1365 49 : NextHopRef nh_ref = nh;
1366 :
1367 49 : if (nh->GetType() == NextHop::COMPOSITE) {
1368 49 : CompositeNH *comp_nh = static_cast<CompositeNH *>(nh);
1369 49 : comp_nh->set_validate_mcast_src(ValidateMcastSrc());
1370 : }
1371 :
1372 49 : NextHopKey *key = static_cast<NextHopKey *>(nh_req.key.get());
1373 : //Bake all MPLS label
1374 49 : if (fabric_peer_path) {
1375 : //Add new label
1376 0 : agent->mpls_table()->CreateRouteLabel(fabric_peer_path->label(), key,
1377 0 : vrf()->GetName(), ToString());
1378 : //Delete Old label, in case label has changed for same peer.
1379 0 : if (old_fabric_mpls_label != fabric_peer_path->label()) {
1380 0 : agent->mpls_table()->FreeLabel(old_fabric_mpls_label,
1381 : vrf()->GetName());
1382 : }
1383 : }
1384 :
1385 : // Rebake label with whatever comp NH has been calculated.
1386 49 : if (evpn_label != MplsTable::kInvalidLabel) {
1387 98 : evpn_label = agent->mpls_table()->CreateRouteLabel(evpn_label, key,
1388 98 : vrf()->GetName(), ToString());
1389 : }
1390 :
1391 49 : bool ret = false;
1392 : //Identify parameters to be passed to populate multicast_peer path and
1393 : //based on peer priorites for each attribute.
1394 49 : std::string dest_vn_name = "";
1395 49 : bool unresolved = false;
1396 49 : uint32_t vxlan_id = 0;
1397 49 : uint32_t tunnel_bmap = TunnelType::AllType();
1398 :
1399 : //Select based on priority of path peer.
1400 49 : if (local_vm_peer_path) {
1401 49 : dest_vn_name = local_vm_peer_path->dest_vn_name();
1402 49 : unresolved = local_vm_peer_path->unresolved();
1403 49 : vxlan_id = local_vm_peer_path->vxlan_id();
1404 49 : tunnel_bmap = TunnelType::AllType();
1405 0 : } else if (tor_peer_path) {
1406 0 : dest_vn_name = tor_peer_path->dest_vn_name();
1407 0 : unresolved = tor_peer_path->unresolved();
1408 0 : vxlan_id = tor_peer_path->vxlan_id();
1409 0 : tunnel_bmap = TunnelType::VxlanType();
1410 0 : } else if (fabric_peer_path) {
1411 0 : dest_vn_name = fabric_peer_path->dest_vn_name();
1412 0 : unresolved = fabric_peer_path->unresolved();
1413 0 : vxlan_id = fabric_peer_path->vxlan_id();
1414 0 : tunnel_bmap = TunnelType::MplsType();
1415 0 : } else if (evpn_peer_path) {
1416 0 : dest_vn_name = evpn_peer_path->dest_vn_name();
1417 0 : unresolved = evpn_peer_path->unresolved();
1418 0 : vxlan_id = evpn_peer_path->vxlan_id();
1419 0 : tunnel_bmap = TunnelType::VxlanType();
1420 : }
1421 :
1422 : //By default mark label stored in multicast_peer path to be evpn label.
1423 49 : uint32_t label = evpn_label;
1424 : //Mpls label selection needs to be overridden by fabric label
1425 : //if fabric peer is present.
1426 49 : if (fabric_peer_path) {
1427 0 : label = fabric_peer_path->label();
1428 : }
1429 :
1430 49 : ret = MulticastRoute::CopyPathParameters(agent,
1431 : multicast_peer_path,
1432 : dest_vn_name,
1433 : unresolved,
1434 : vxlan_id,
1435 : label,
1436 : tunnel_bmap,
1437 : nh, this);
1438 : MulticastRoutePath *multicast_route_path =
1439 49 : dynamic_cast<MulticastRoutePath *>(multicast_peer_path);
1440 49 : if (multicast_route_path) {
1441 49 : multicast_route_path->UpdateLabels(evpn_label, label);
1442 : }
1443 :
1444 49 : return ret;
1445 49 : }
|