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 24 : DeleteActor(AgentRouteTable *rt_table) :
38 : LifetimeActor(rt_table->agent()->lifetime_manager()),
39 24 : table_(rt_table) {
40 24 : }
41 48 : virtual ~DeleteActor() {
42 48 : }
43 24 : virtual bool MayDelete() const {
44 24 : return table_->MayDelete();
45 : }
46 24 : virtual void Shutdown() {
47 24 : }
48 24 : virtual void Destroy() {
49 24 : assert(table_->vrf_entry_.get() != NULL);
50 24 : table_->vrf_entry_->SetRouteTableDeleted(table_->GetTableType());
51 : //Release refernces
52 24 : table_->vrf_delete_ref_.Reset(NULL);
53 24 : table_->vrf_entry_ = NULL;
54 24 : }
55 :
56 : private:
57 : AgentRouteTable *table_;
58 : };
59 :
60 130 : bool RouteComparator::operator() (const AgentRoute *rt1, const AgentRoute *rt2) const {
61 130 : 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 24 : AgentRouteTable::AgentRouteTable(DB *db, const std::string &name):
72 24 : RouteTable(db, name), agent_(NULL), vrf_id_(0), vrf_entry_(NULL, this),
73 24 : deleter_(NULL), vrf_delete_ref_(this, NULL), unresolved_rt_tree_(),
74 48 : unresolved_nh_tree_() {
75 24 : OperDBTraceBuf = SandeshTraceBufferCreate("OperRoute", 5000);
76 24 : }
77 :
78 24 : AgentRouteTable::~AgentRouteTable() {
79 24 : }
80 :
81 : // Allocate a route entry
82 453 : unique_ptr<DBEntry> AgentRouteTable::AllocEntry(const DBRequestKey *k) const {
83 453 : const AgentRouteKey *key = static_cast<const AgentRouteKey*>(k);
84 453 : VrfKey vrf_key(key->vrf_name());
85 : AgentRoute *route =
86 453 : static_cast<AgentRoute *>(key->AllocRouteEntry(vrf_entry_.get(),
87 : false));
88 906 : return unique_ptr<DBEntry>(static_cast<DBEntry *>(route));
89 453 : }
90 :
91 : // Algorithm to select an active path from multiple potential paths.
92 : // Uses comparator in path for selection
93 149 : bool AgentRouteTable::PathSelection(const Path &path1, const Path &path2) {
94 149 : const AgentPath &l_path = dynamic_cast<const AgentPath &> (path1);
95 149 : const AgentPath &r_path = dynamic_cast<const AgentPath &> (path2);
96 149 : return l_path.IsLess(r_path);
97 : }
98 :
99 24 : const string &AgentRouteTable::GetSuffix(Agent::RouteTableType type) {
100 24 : static const string uc_suffix(".uc.route.0");
101 24 : static const string mpls_suffix(".uc.route.3");
102 24 : static const string mc_suffix(".mc.route.0");
103 24 : static const string evpn_suffix(".evpn.route.0");
104 24 : static const string l2_suffix(".l2.route.0");
105 24 : static const string uc_inet6_suffix(".uc.route6.0");
106 :
107 24 : switch (type) {
108 4 : case Agent::INET4_UNICAST:
109 4 : return uc_suffix;
110 4 : case Agent::INET4_MPLS:
111 4 : return mpls_suffix;
112 4 : case Agent::INET4_MULTICAST:
113 4 : return mc_suffix;
114 4 : case Agent::EVPN:
115 4 : return evpn_suffix;
116 4 : case Agent::BRIDGE:
117 4 : return l2_suffix;
118 4 : case Agent::INET6_UNICAST:
119 4 : 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 24 : void AgentRouteTable::SetVrf(VrfEntry *vrf) {
127 24 : agent_ = (static_cast<VrfTable *>(vrf->get_table()))->agent();
128 24 : vrf_entry_ = vrf;
129 24 : vrf_id_ = vrf->vrf_id();
130 24 : vrf_delete_ref_.Reset(vrf->deleter());
131 24 : deleter_.reset(new DeleteActor(this));
132 24 : }
133 :
134 : //Delete all the routes
135 24 : void AgentRouteTable::ManagedDelete() {
136 24 : RouteTableWalkerState *state = new RouteTableWalkerState(deleter());
137 : DBTable::DBTableWalkRef walk_ref = AllocWalker(
138 : boost::bind(&AgentRouteTable::DelExplicitRouteWalkerCb, this, _1, _2),
139 48 : 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 24 : WalkTable(walk_ref);
144 24 : deleter_->Delete();
145 24 : }
146 :
147 24 : void AgentRouteTable::DeleteRouteDone(DBTable::DBTableWalkRef walk_ref,
148 : DBTableBase *base,
149 : RouteTableWalkerState *state) {
150 24 : LOG(DEBUG, "Deleted all BGP injected routes for " << base->name());
151 24 : ReleaseWalker(walk_ref);
152 24 : delete state;
153 24 : }
154 :
155 2 : bool AgentRouteTable::DelExplicitRouteWalkerCb(DBTablePartBase *part,
156 : DBEntryBase *entry) {
157 2 : AgentRoute *route = static_cast<AgentRoute *>(entry);
158 2 : if (route == NULL)
159 0 : return true;
160 :
161 2 : return route->DeleteAllBgpPath(part, this);
162 : }
163 :
164 179 : void AgentRouteTable::RetryDelete() {
165 179 : if (!deleter()->IsDeleted()) {
166 106 : return;
167 : }
168 73 : if (empty()) {
169 70 : vrf_entry()->RetryDelete();
170 : }
171 73 : deleter()->RetryDelete();
172 : }
173 :
174 2 : void AgentRouteTable::NotifyEntry(AgentRoute *e) {
175 2 : agent()->ConcurrencyCheck();
176 : DBTablePartBase *tpart =
177 2 : static_cast<DBTablePartition *>(GetTablePartition(e));
178 2 : tpart->Notify(e);
179 2 : }
180 :
181 : /////////////////////////////////////////////////////////////////////////////
182 : // Agent route input processing
183 : /////////////////////////////////////////////////////////////////////////////
184 :
185 : // Inline processing of Route request.
186 259 : void AgentRouteTable::Process(DBRequest &req) {
187 259 : agent()->ConcurrencyCheck();
188 : DBTablePartition *tpart =
189 259 : static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
190 259 : tpart->Process(NULL, &req);
191 259 : }
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 437 : void AgentRouteTable::Input(DBTablePartition *part, DBClient *client,
200 : DBRequest *req) {
201 437 : AgentRouteKey *key = static_cast<AgentRouteKey *>(req->key.get());
202 437 : AgentRouteData *data = static_cast<AgentRouteData *>(req->data.get());
203 :
204 437 : 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 437 : if (vrf == NULL)
208 0 : 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 437 : AgentRouteTable *req_table = vrf->GetRouteTable(key->GetRouteTableType());
213 437 : if (req_table != this) {
214 83 : if (req_table == NULL) {
215 : // If route table is already deleted from VRF, it means VRF should
216 : // also be in deleted state
217 0 : assert(vrf->IsDeleted());
218 0 : return;
219 : }
220 :
221 : DBTablePartition *p =
222 83 : static_cast<DBTablePartition *>(req_table->GetTablePartition(key));
223 83 : req_table->Input(p, client, req);
224 83 : return;
225 : }
226 :
227 354 : AgentRoute *rt = static_cast<AgentRoute *>(part->Find(key));
228 354 : if (req->oper == DBRequest::DB_ENTRY_DELETE) {
229 171 : if (rt)
230 149 : rt->DeleteInput(part, this, key, data);
231 171 : return;
232 : }
233 :
234 183 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
235 183 : AddChangeInput(part, vrf, rt, key, data);
236 183 : return;
237 : }
238 :
239 0 : assert(0);
240 : }
241 :
242 : // Handle RESYNC and ADD_CHANGE requests
243 183 : void AgentRouteTable::AddChangeInput(DBTablePartition *part, VrfEntry *vrf,
244 : AgentRoute *rt, AgentRouteKey *key,
245 : AgentRouteData *data) {
246 183 : 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 183 : if (vrf->IsDeleted() && vrf->allow_route_add_on_deleted_vrf() == false)
253 0 : return;
254 :
255 183 : AgentPath *path = NULL;
256 183 : bool notify = false;
257 183 : const NextHop *nh = NULL;
258 183 : if (rt) {
259 127 : nh = rt->GetActiveNextHop();
260 : }
261 183 : if (key->sub_op_ == AgentKey::RESYNC) {
262 : // Process RESYNC only if route present and not-deleted
263 35 : if (rt && (rt->IsDeleted() == false))
264 35 : notify |= rt->SubOpResyncInput(vrf, this, &path, key, data);
265 148 : } else if (key->sub_op_ == AgentKey::ADD_DEL_CHANGE) {
266 148 : bool route_added = (rt == NULL);
267 148 : rt = LocateRoute(part, vrf, rt, key, data, ¬ify);
268 148 : 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 183 : if (rt && rt->HasUnresolvedPath() == true) {
277 56 : rt->AddUnresolvedRouteToTable(this);
278 : }
279 : // Route changed, trigger change on dependent routes
280 183 : if (notify) {
281 153 : bool active_path_changed = (path == rt->GetActivePath());
282 153 : const AgentPath *prev_active_path = rt->GetActivePath();
283 153 : CompositeNH *cnh = NULL;
284 153 : if (prev_active_path) {
285 153 : cnh = dynamic_cast<CompositeNH *>(prev_active_path->nexthop());
286 : }
287 153 : const Path *prev_front = rt->front();
288 153 : if (prev_front) {
289 153 : rt->Sort(&AgentRouteTable::PathSelection, prev_front);
290 : }
291 153 : if (rt->GetActiveNextHop() != nh) {
292 68 : 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 238 : if ( (path == rt->GetActivePath()) &&
300 85 : (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 153 : part->Notify(rt);
312 153 : rt->UpdateDependantRoutes();
313 153 : 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 153 : active_path_changed |= (path == rt->GetActivePath());
318 153 : rt->UpdateDerivedRoutes(this, path, active_path_changed);
319 : }
320 : }
321 :
322 148 : 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 148 : if (rt != NULL && rt->IsDeleted() == false)
328 92 : return rt;
329 :
330 : // Add route if not present already
331 56 : if (rt == NULL) {
332 : rt = static_cast<AgentRoute *>
333 56 : (key->AllocRouteEntry(vrf, data->is_multicast()));
334 56 : assert(rt->vrf() != NULL);
335 56 : part->Add(rt);
336 : }
337 :
338 : // Renew the route if its in deleted state
339 56 : if (rt->IsDeleted()) {
340 0 : assert(rt->IsDeleted());
341 0 : rt->ClearDelete();
342 0 : *notify = true;
343 : }
344 :
345 56 : ProcessAdd(rt);
346 56 : RouteInfo rt_info;
347 56 : rt->FillTrace(rt_info, AgentRoute::ADD, NULL);
348 56 : OPER_TRACE_ROUTE_ENTRY(Route, this, rt_info);
349 56 : return rt;
350 56 : }
351 :
352 56 : void AgentRoute::AddUnresolvedRouteToTable(AgentRouteTable *table) {
353 :
354 56 : if (dependent_route_table_ == NULL) {
355 10 : const AgentPath *path = GetActivePath();
356 10 : if (path->GetDependentTable()) {
357 0 : dependent_route_table_ = path->GetDependentTable();
358 : } else {
359 10 : dependent_route_table_ = table;
360 : }
361 : }
362 56 : dependent_route_table_->AddUnresolvedRoute(this);
363 56 : }
364 56 : void AgentRoute::RemoveUnresolvedRouteFromTable(AgentRouteTable *table) {
365 56 : if (dependent_route_table_) {
366 10 : dependent_route_table_->RemoveUnresolvedRoute(this);
367 : } else {
368 46 : table->RemoveUnresolvedRoute(this);
369 : }
370 56 : }
371 :
372 :
373 : // Re-evaluate all unresolved NH. Flush and enqueue RESYNC for all NH in the
374 : // unresolved NH tree
375 56 : void AgentRouteTable::EvaluateUnresolvedNH(void) {
376 56 : for (UnresolvedNHTree::iterator it = unresolved_nh_tree_.begin();
377 57 : it != unresolved_nh_tree_.end(); ++it) {
378 1 : (*it)->EnqueueResync();
379 :
380 1 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
381 1 : req.key = (*it)->GetDBRequestKey();
382 1 : (static_cast<NextHopKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
383 1 : agent_->nexthop_table()->Enqueue(&req);
384 1 : }
385 :
386 56 : unresolved_nh_tree_.clear();
387 56 : }
388 :
389 1 : void AgentRouteTable::AddUnresolvedNH(const NextHop *nh) {
390 1 : unresolved_nh_tree_.insert(nh);
391 1 : }
392 :
393 1 : void AgentRouteTable::RemoveUnresolvedNH(const NextHop *nh) {
394 1 : unresolved_nh_tree_.erase(nh);
395 1 : }
396 :
397 : // Re-evaluate all unresolved routes. Flush and enqueue RESYNC for all routes
398 : // in the unresolved route tree
399 56 : void AgentRouteTable::EvaluateUnresolvedRoutes(void) {
400 56 : for (UnresolvedRouteTree::iterator it = unresolved_rt_tree_.begin();
401 65 : it != unresolved_rt_tree_.end(); ++it) {
402 9 : (*it)->EnqueueRouteResync();
403 : }
404 :
405 56 : unresolved_rt_tree_.clear();
406 56 : }
407 :
408 56 : void AgentRouteTable::AddUnresolvedRoute(const AgentRoute *rt) {
409 56 : unresolved_rt_tree_.insert(rt);
410 56 : }
411 :
412 112 : void AgentRouteTable::RemoveUnresolvedRoute(const AgentRoute *rt) {
413 112 : unresolved_rt_tree_.erase(rt);
414 112 : }
415 :
416 : // Find entry not in deleted state
417 15 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRouteKey *key) {
418 15 : AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
419 15 : if (entry && entry->IsDeleted()) {
420 0 : return NULL;
421 : }
422 15 : return entry;
423 : }
424 :
425 2 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRouteKey *key) {
426 2 : DBTable *table = static_cast<DBTable *>(this);
427 2 : AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
428 2 : if (entry && entry->IsDeleted()) {
429 0 : return NULL;
430 : }
431 2 : return entry;
432 : }
433 :
434 15 : AgentRoute *AgentRouteTable::FindActiveEntry(const AgentRoute *key) {
435 15 : AgentRoute *entry = static_cast<AgentRoute *>(Find(key));
436 15 : if (entry && entry->IsDeleted()) {
437 0 : return NULL;
438 : }
439 15 : return entry;
440 : }
441 :
442 4 : AgentRoute *AgentRouteTable::FindActiveEntryNoLock(const AgentRoute *key) {
443 4 : DBTable *table = static_cast<DBTable *>(this);
444 4 : AgentRoute *entry = static_cast<AgentRoute *>(table->FindNoLock(key));
445 4 : if (entry && entry->IsDeleted()) {
446 0 : return NULL;
447 : }
448 4 : return entry;
449 : }
450 :
451 320 : LifetimeActor *AgentRouteTable::deleter() {
452 320 : return deleter_.get();
453 : }
454 :
455 30 : const std::string &AgentRouteTable::vrf_name() const {
456 30 : return vrf_entry_->GetName();
457 : }
458 :
459 423 : VrfEntry *AgentRouteTable::vrf_entry() const {
460 423 : return vrf_entry_.get();
461 : }
462 :
463 : /////////////////////////////////////////////////////////////////////////////
464 : // AgentRoute routines
465 : /////////////////////////////////////////////////////////////////////////////
466 :
467 : // Hnadle RESYNC operation for a route
468 35 : 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 35 : if (data == NULL || key->peer() == NULL) {
473 33 : Sync();
474 33 : return true;
475 : }
476 :
477 : // Get path to update
478 2 : AgentPath *path = FindPath(key->peer());
479 2 : if (path == NULL)
480 0 : return false;
481 :
482 2 : bool ret = false;
483 2 : *path_ptr = path;
484 2 : bool old_ecmp = path->path_preference().is_ecmp();
485 2 : if (data->AddChangePath(table->agent(), path, this))
486 2 : ret = true;
487 :
488 : // Transition from ECMP to non-ECMP should result in removal of member
489 : // from ECMP path
490 2 : if (old_ecmp && old_ecmp != path->path_preference().is_ecmp()) {
491 0 : ReComputePathDeletion(path);
492 0 : return ret;
493 : }
494 :
495 2 : if (ReComputePathAdd(path))
496 0 : ret = true;
497 :
498 2 : return ret;
499 : }
500 :
501 148 : bool AgentRoute::SubOpAddChangeInput(VrfEntry *vrf, AgentRouteTable *table,
502 : AgentPath **path_ptr, AgentRouteKey *key,
503 : AgentRouteData *data, bool route_added) {
504 148 : bool ret = false;
505 : // Update route level attributes first
506 148 : if (data && data->UpdateRoute(this))
507 10 : ret = true;
508 :
509 : AgentRoute::Trace event;
510 148 : AgentPath *path = FindPathUsingKeyData(key, data);
511 : // Allocate path if not yet present
512 148 : if (path == NULL) {
513 73 : path = data->CreateAgentPath(key->peer(), this);
514 73 : InsertPath(path);
515 73 : data->AddChangePath(table->agent(), path, this);
516 73 : set_origin_vn_name(path->dest_vn_list());
517 73 : ret = true;
518 73 : event = AgentRoute::ADD_PATH;
519 : } else {
520 75 : bool ecmp = path->path_preference().is_ecmp();
521 75 : if (data->AddChangePath(table->agent(), path, this))
522 45 : ret = true;
523 :
524 : // Transition from ECMP to non-ECMP should result in removal of member
525 : // from ECMP path
526 75 : if (ecmp && ecmp != path->path_preference().is_ecmp()) {
527 0 : ReComputePathDeletion(path);
528 : }
529 75 : event = AgentRoute::CHANGE_PATH;
530 : }
531 :
532 : // Trace log for path add/change
533 148 : RouteInfo rt_info;
534 148 : FillTrace(rt_info, event, path);
535 148 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
536 :
537 148 : if (path->RouteNeedsSync())
538 20 : ret |= Sync();
539 :
540 148 : if (route_added) {
541 56 : table->EvaluateUnresolvedRoutes();
542 56 : table->EvaluateUnresolvedNH();
543 : }
544 :
545 : // Do necessary recompute on addition of path
546 148 : if (ReComputePathAdd(path))
547 25 : ret = true;
548 :
549 148 : *path_ptr = path;
550 148 : return ret;
551 148 : }
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 149 : void AgentRoute::DeleteInput(DBTablePartition *part, AgentRouteTable *table,
557 : AgentRouteKey *key, AgentRouteData *data) {
558 149 : assert (key->sub_op_ == AgentKey::ADD_DEL_CHANGE);
559 149 : bool force_delete = false;
560 : // If peer in key is deleted, set force_delete to true.
561 149 : 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 149 : for (Route::PathList::iterator it = GetPathList().begin();
567 676 : it != GetPathList().end(); ) {
568 189 : 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 189 : it++;
572 :
573 189 : if (key->peer() != path->peer())
574 114 : continue;
575 :
576 : bool check_can_delete =
577 150 : ((key->peer()->GetType() == Peer::BGP_PEER) ||
578 150 : (key->peer()->GetType() == Peer::EVPN_ROUTING_PEER) ||
579 225 : (key->peer()->GetType() == Peer::EVPN_PEER) ||
580 62 : (key->peer()->GetType() == Peer::INET_EVPN_PEER));
581 :
582 75 : 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 92 : if (check_can_delete && data &&
593 17 : data->CanDeletePath(table->agent(), path, this) == false) {
594 4 : continue;
595 : }
596 :
597 71 : DeletePathFromPeer(part, table, path);
598 : }
599 149 : }
600 :
601 75 : void AgentRoute::InsertPath(const AgentPath *path) {
602 75 : const Path *prev_front = front();
603 75 : insert(path);
604 75 : Sort(&AgentRouteTable::PathSelection, prev_front);
605 75 : }
606 :
607 75 : void AgentRoute::RemovePath(AgentPath *path) {
608 75 : const Path *prev_front = front();
609 75 : remove(path);
610 75 : Sort(&AgentRouteTable::PathSelection, prev_front);
611 75 : return;
612 : }
613 :
614 : // Delete all paths from BGP Peer. Delete route if no path left
615 2 : bool AgentRoute::DeleteAllBgpPath(DBTablePartBase *part,
616 : AgentRouteTable *table) {
617 2 : for(Route::PathList::iterator it = GetPathList().begin();
618 8 : it != GetPathList().end();) {
619 2 : AgentPath *path = static_cast<AgentPath *>(it.operator->());
620 2 : it++;
621 :
622 2 : const Peer *peer = path->peer();
623 2 : if (peer == NULL)
624 0 : continue;
625 :
626 2 : if (peer->GetType() == Peer::BGP_PEER ||
627 2 : peer->GetType() == Peer::EVPN_ROUTING_PEER ||
628 0 : peer->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER) {
629 2 : 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 2 : 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 73 : void AgentRoute::DeletePathFromPeer(DBTablePartBase *part,
656 : AgentRouteTable *table, AgentPath *path) {
657 :
658 73 : RouteInfo rt_info;
659 73 : FillTrace(rt_info, AgentRoute::DELETE_PATH, path);
660 73 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info);
661 :
662 73 : if (path == NULL) {
663 0 : return;
664 : }
665 :
666 : // Assign path to auto-pointer to delete it on return
667 73 : 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 73 : ReComputePathDeletion(path);
674 :
675 : // Store if this was active path
676 73 : bool active_path = (GetActivePath() == path);
677 73 : const Peer *old_active_path_peer = path->peer();
678 : // Remove path from the route
679 73 : RemovePath(path);
680 :
681 : // TODO : Move this code to ECMP Hash management code.
682 73 : CompositeNH *cnh = dynamic_cast<CompositeNH *>(path->nexthop());
683 73 : if (cnh) {
684 4 : path->ResetEcmpHashFields();
685 4 : cnh->UpdateEcmpHashFieldsUponRouteDelete(table->agent(),
686 : table->vrf_name());
687 : }
688 :
689 : // Delete route if no more paths
690 73 : if (GetActivePath() == NULL) {
691 56 : RouteInfo rt_info_del;
692 56 : FillTrace(rt_info_del, AgentRoute::DEL, NULL);
693 56 : OPER_TRACE_ROUTE_ENTRY(Route, table, rt_info_del);
694 56 : DeleteDerivedRoutes(table);
695 56 : table->RemoveUnresolvedRoute(this); // TODO: remove this call and make changes in gw route
696 56 : RemoveUnresolvedRouteFromTable(table);
697 56 : UpdateDependantRoutes();
698 56 : ResyncTunnelNextHop();
699 56 : table->ProcessDelete(this);
700 56 : part->Delete(this);
701 56 : } 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 17 : const Peer *new_active_path_peer = GetActivePath()->peer();
708 17 : AgentPath *new_active_path = FindPath(new_active_path_peer);
709 17 : CompositeNH *new_cnh = NULL;
710 17 : if (new_active_path && new_active_path->nexthop()) {
711 16 : new_cnh =
712 16 : dynamic_cast<CompositeNH *>(new_active_path->nexthop());
713 : }
714 9 : if (active_path &&
715 4 : cnh && new_cnh &&
716 2 : (old_active_path_peer->GetType() == Peer::BGP_PEER) &&
717 0 : (new_active_path_peer->GetType() == Peer::BGP_PEER) &&
718 26 : (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 17 : part->Notify(this);
724 17 : UpdateDerivedRoutes(table, NULL, active_path);
725 : }
726 73 : }
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 96 : AgentPath *AgentRoute::FindLocalVmPortPath() const {
744 133 : for(Route::PathList::const_iterator it = GetPathList().begin();
745 266 : it != GetPathList().end(); it++) {
746 96 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
747 96 : if (path->peer() == NULL) {
748 0 : continue;
749 : }
750 96 : if (path->peer()->export_to_controller()) {
751 59 : return const_cast<AgentPath *>(path);
752 : }
753 :
754 74 : if (path->peer()->GetType() == Peer::ECMP_PEER ||
755 74 : path->peer()->GetType() == Peer::VGW_PEER ||
756 74 : path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER ||
757 111 : path->peer()->GetType() == Peer::MULTICAST_TOR_PEER ||
758 37 : path->peer()->GetType() == Peer::OVS_PEER) {
759 0 : return const_cast<AgentPath *>(path);
760 : }
761 : }
762 37 : 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 0 : const AgentPath *AgentRoute::FindIntfOrCompLocalVmPortPath() const {
818 0 : const AgentPath *intf_path = NULL;
819 0 : const AgentPath *icom_path = NULL;
820 0 : for (Route::PathList::const_iterator it =
821 0 : this->GetPathList().begin();
822 0 : 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 0 : if (icom_path) {
837 0 : return icom_path;
838 : }
839 0 : if (intf_path) {
840 0 : return intf_path;
841 : }
842 0 : 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 24 : AgentPath *AgentRoute::FindPathUsingKeyData(const AgentRouteKey *key,
861 : const AgentRouteData *data) const {
862 24 : return FindPath(key->peer());
863 : }
864 :
865 228 : AgentPath *AgentRoute::FindPath(const Peer *peer) const {
866 364 : for(Route::PathList::const_iterator it = GetPathList().begin();
867 728 : it != GetPathList().end(); it++) {
868 246 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
869 246 : if (path->peer() == peer) {
870 110 : return const_cast<AgentPath *>(path);
871 : }
872 : }
873 118 : return NULL;
874 : }
875 :
876 : // First path in list is always treated as active path.
877 2332 : const AgentPath *AgentRoute::GetActivePath() const {
878 2332 : const AgentPath *path = static_cast<const AgentPath *>(front());
879 2332 : return (path ? path->UsablePath() : NULL);
880 : }
881 :
882 583 : const NextHop *AgentRoute::GetActiveNextHop() const {
883 583 : const AgentPath *path = GetActivePath();
884 583 : if (path == NULL)
885 0 : return NULL;
886 :
887 583 : return path->ComputeNextHop(static_cast<AgentRouteTable *>(get_table())->
888 583 : 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 209 : void AgentRoute::ResyncTunnelNextHop(void) {
897 209 : for (AgentRoute::TunnelNhDependencyList::iterator iter =
898 418 : 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 209 : }
912 :
913 : // Enqueue request to RESYNC a route
914 32 : void AgentRoute::EnqueueRouteResync(void) const {
915 32 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
916 32 : req.key = GetDBRequestKey();
917 32 : (static_cast<AgentKey *>(req.key.get()))->sub_op_ = AgentKey::RESYNC;
918 32 : Agent *agent = (static_cast<AgentRouteTable *>(get_table()))->agent();
919 : /* Setting req.data only for default route */
920 32 : 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 32 : agent->fabric_inet4_unicast_table()->Enqueue(&req);
930 32 : }
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 216 : void AgentRoute::UpdateDependantRoutes(void) {
937 229 : for (AgentRoute::RouteDependencyList::iterator iter =
938 445 : dependant_routes_.begin(); iter != dependant_routes_.end(); iter++) {
939 13 : AgentRoute *rt = iter.operator->();
940 13 : rt->EnqueueRouteResync();
941 : }
942 216 : }
943 :
944 183 : bool AgentRoute::HasUnresolvedPath(void) {
945 617 : for(Route::PathList::const_iterator it = GetPathList().begin();
946 868 : it != GetPathList().end(); it++) {
947 : const AgentPath *path =
948 307 : static_cast<const AgentPath *>(it.operator->());
949 307 : if (path->unresolved() == true) {
950 56 : return true;
951 : }
952 : }
953 :
954 127 : return false;
955 : }
956 :
957 : // Invoke SYNC on all paths to re-evaluate NH/active state
958 53 : bool AgentRoute::Sync(void) {
959 53 : bool ret = false;
960 120 : for(Route::PathList::iterator it = GetPathList().begin();
961 240 : it != GetPathList().end(); it++) {
962 67 : AgentPath *path = static_cast<AgentPath *>(it.operator->());
963 67 : if (path->Sync(this) == true) {
964 8 : if (GetActivePath() == path) {
965 6 : ret = true;
966 : }
967 : }
968 : }
969 53 : return ret;
970 : }
971 :
972 183 : bool AgentRoute::WaitForTraffic() const {
973 193 : for(Route::PathList::const_iterator it = GetPathList().begin();
974 386 : it != GetPathList().end(); it++) {
975 188 : const AgentPath *path = static_cast<const AgentPath *>(it.operator->());
976 188 : if (path->peer() && path->peer()->GetType() == Peer::INET_EVPN_PEER) {
977 5 : continue;
978 : }
979 183 : if (path->path_preference().wait_for_traffic() == true) {
980 178 : return true;
981 : }
982 : }
983 5 : 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 50 : AgentPath *AgentRouteData::CreateAgentPath(const Peer *peer,
996 : AgentRoute *rt) const {
997 50 : return (new AgentPath(peer, rt));
998 : }
999 :
1000 150 : bool AgentRouteData::AddChangePath(Agent *agent, AgentPath *path,
1001 : const AgentRoute *rt) {
1002 150 : path->set_peer_sequence_number(sequence_number_);
1003 :
1004 150 : 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 150 : return AddChangePathExtended(agent, path, rt);
1026 : }
1027 0 : const string &AgentRoute::dest_vn_name() const {
1028 0 : assert(GetActivePath()->dest_vn_list().size() <= 1);
1029 0 : return *GetActivePath()->dest_vn_list().begin();
1030 : };
1031 :
1032 0 : string AgentRoute::ToString() const {
1033 0 : return "Route Entry";
1034 : }
1035 :
1036 2110 : bool AgentRoute::IsLess(const DBEntry &rhs) const {
1037 2110 : int cmp = CompareTo(static_cast<const Route &>(rhs));
1038 2110 : return (cmp < 0);
1039 : };
1040 :
1041 197 : uint32_t AgentRoute::vrf_id() const {
1042 197 : return vrf_->vrf_id();
1043 : }
1044 :
1045 12 : bool AgentRoute::IsRPFInvalid() const {
1046 12 : const AgentPath *path = GetActivePath();
1047 12 : if (path == NULL) {
1048 0 : return false;
1049 : }
1050 :
1051 12 : 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 29 : 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 29 : *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 29 : switch (path->peer()->GetType()) {
1075 21 : case Peer::LOCAL_VM_PEER:
1076 : //Use local_peer path for label
1077 21 : if (local_peer_path) {
1078 21 : *evpn_label = local_peer_path->label();
1079 21 : assert(*evpn_label != MplsTable::kInvalidLabel);
1080 : }
1081 21 : break;
1082 8 : case Peer::LOCAL_PEER:
1083 : //Use local_peer path for label
1084 8 : if (local_vm_peer_path) {
1085 2 : *evpn_label = local_vm_peer_path->label();
1086 2 : assert(*evpn_label != MplsTable::kInvalidLabel);
1087 : }
1088 8 : 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 29 : if (del) {
1103 4 : 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 4 : if (path->peer()->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER)
1109 0 : delete_label = true;
1110 6 : else if ((path->peer() == agent->local_vm_peer()) ||
1111 2 : (path->peer() == agent->local_peer())) {
1112 4 : if (local_peer_path == NULL &&
1113 : local_vm_peer_path == NULL) {
1114 2 : delete_label = true;
1115 : //Reset evpn label to invalid as it is freed
1116 2 : if (*evpn_label == path->label()) {
1117 0 : *evpn_label = MplsTable::kInvalidLabel;
1118 : }
1119 : }
1120 : }
1121 4 : if (delete_label) {
1122 2 : agent->mpls_table()->FreeLabel(path->label(),
1123 : vrf()->GetName());
1124 : //Reset path label to invalid as it is freed
1125 2 : path->set_label(MplsTable::kInvalidLabel);
1126 : }
1127 4 : return;
1128 : }
1129 :
1130 : // Currently other than evpn label no other multicast path requires dynamic
1131 : // allocation so return.
1132 25 : if ((path != local_peer_path) && (path != local_vm_peer_path))
1133 0 : return;
1134 :
1135 : // Path already has label, return.
1136 25 : if (path->label() != MplsTable::kInvalidLabel) {
1137 21 : if (*evpn_label == MplsTable::kInvalidLabel) {
1138 2 : *evpn_label = path->label();
1139 : }
1140 21 : 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 4 : 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 2 : 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 2 : DiscardNHKey key;
1153 4 : *evpn_label = agent->mpls_table()->CreateRouteLabel(*evpn_label, &key,
1154 : vrf()->GetName(),
1155 4 : ToString());
1156 2 : }
1157 4 : assert(*evpn_label != MplsTable::kInvalidLabel);
1158 4 : path->set_label(*evpn_label);
1159 : }
1160 :
1161 29 : bool AgentRoute::ReComputeMulticastPaths(AgentPath *path, bool del) {
1162 29 : 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 29 : bool delete_all = false;
1173 29 : if (path->is_subnet_discard() && del) {
1174 0 : delete_all = true;
1175 : }
1176 :
1177 29 : Agent *agent = (static_cast<AgentRouteTable *> (get_table()))->agent();
1178 29 : 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 29 : AgentPath *multicast_peer_path = NULL;
1186 29 : AgentPath *local_vm_peer_path = NULL;
1187 29 : AgentPath *evpn_peer_path = NULL;
1188 29 : AgentPath *fabric_peer_path = NULL;
1189 29 : AgentPath *tor_peer_path = NULL;
1190 29 : AgentPath *local_peer_path = NULL;
1191 29 : bool tor_path = false;
1192 :
1193 : const CompositeNH *cnh =
1194 29 : static_cast<const CompositeNH *>(path->nexthop());
1195 29 : if (cnh && (cnh->composite_nh_type() == Composite::TOR)) {
1196 0 : tor_path = true;
1197 : }
1198 :
1199 102 : for (Route::PathList::iterator it = GetPathList().begin();
1200 204 : it != GetPathList().end(); it++) {
1201 : AgentPath *it_path =
1202 73 : static_cast<AgentPath *>(it.operator->());
1203 :
1204 73 : if (delete_all && (it_path->peer() != agent->multicast_peer()))
1205 0 : continue;
1206 :
1207 : //Handle deletions
1208 73 : if (del && (path->peer() == it_path->peer())) {
1209 4 : if (path->peer()->GetType() != Peer::BGP_PEER)
1210 4 : 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 69 : if (it_path->inactive())
1224 0 : continue;
1225 69 : if (it_path->peer() == agent->local_vm_peer()) {
1226 21 : local_vm_peer_path = it_path;
1227 48 : } 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 48 : } else if (it_path->peer()->GetType() ==
1243 : Peer::MULTICAST_FABRIC_TREE_BUILDER) {
1244 0 : fabric_peer_path = it_path;
1245 48 : } else if (it_path->peer() == agent->multicast_peer()) {
1246 21 : multicast_peer_path = it_path;
1247 27 : } else if (it_path->peer() == agent->local_peer()) {
1248 27 : local_peer_path = it_path;
1249 : }
1250 : }
1251 :
1252 29 : if (tor_path) {
1253 0 : if ((del && (tor_peer_path == NULL)) || !del) {
1254 0 : HandleDeviceMastershipUpdate(path, del);
1255 : }
1256 : }
1257 :
1258 29 : uint32_t evpn_label = MplsTable::kInvalidLabel;
1259 29 : 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 29 : if ((local_vm_peer_path == NULL) &&
1264 8 : (tor_peer_path == NULL) &&
1265 8 : (evpn_peer_path == NULL) &&
1266 : (fabric_peer_path == NULL)) {
1267 8 : if (multicast_peer_path != NULL) {
1268 2 : if ((evpn_label != MplsTable::kInvalidLabel) && (local_peer_path)) {
1269 : // Make evpn label point to discard-nh as composite-nh gets
1270 : // deleted.
1271 2 : DiscardNHKey key;
1272 4 : agent->mpls_table()->CreateRouteLabel(evpn_label, &key,
1273 : vrf()->GetName(),
1274 4 : ToString());
1275 2 : }
1276 2 : std::unique_ptr<AgentPath> path_ref(multicast_peer_path);
1277 2 : RemovePath(multicast_peer_path);
1278 2 : }
1279 8 : return true;
1280 : }
1281 :
1282 21 : bool learning_enabled = false;
1283 21 : bool pbb_nh = false;
1284 21 : uint32_t old_fabric_mpls_label = 0;
1285 21 : if (multicast_peer_path == NULL) {
1286 2 : multicast_peer_path = new MulticastRoutePath(agent->multicast_peer());
1287 2 : InsertPath(multicast_peer_path);
1288 : } else {
1289 : //Multicast peer path can have evpn or fabric label.
1290 : //Identify using isfabricmulticastlabel.
1291 19 : if (agent->mpls_table()->
1292 19 : IsFabricMulticastLabel(multicast_peer_path->label()))
1293 : {
1294 0 : old_fabric_mpls_label = multicast_peer_path->label();
1295 : }
1296 : }
1297 :
1298 21 : ComponentNHKeyList component_nh_list;
1299 :
1300 21 : 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 21 : 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 21 : 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 21 : if (local_vm_peer_path) {
1328 : NextHopKey *local_vm_peer_key =
1329 : static_cast<NextHopKey *>((local_vm_peer_path->
1330 21 : ComputeNextHop(agent)->GetDBRequestKey()).release());
1331 21 : std::unique_ptr<const NextHopKey> key4(local_vm_peer_key);
1332 21 : ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, std::move(key4)));
1333 21 : component_nh_list.push_back(component_nh_data4);
1334 :
1335 21 : const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(
1336 21 : local_vm_peer_path->ComputeNextHop(agent));
1337 21 : if (cnh && cnh->learning_enabled() == true) {
1338 0 : learning_enabled = true;
1339 : }
1340 21 : if (cnh && cnh->pbb_nh() == true) {
1341 0 : pbb_nh = true;
1342 : }
1343 21 : }
1344 :
1345 21 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
1346 42 : nh_req.key.reset(new CompositeNHKey(GetMulticastCompType(),
1347 21 : ValidateMcastSrc(), false,
1348 : component_nh_list,
1349 21 : vrf()->GetName()));
1350 21 : nh_req.data.reset(new CompositeNHData(pbb_nh, learning_enabled,
1351 21 : vrf()->layer2_control_word()));
1352 21 : agent->nexthop_table()->Process(nh_req);
1353 42 : NextHop *nh = static_cast<NextHop *>(agent->nexthop_table()->
1354 21 : 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 21 : 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 21 : NextHopRef nh_ref = nh;
1366 :
1367 21 : if (nh->GetType() == NextHop::COMPOSITE) {
1368 21 : CompositeNH *comp_nh = static_cast<CompositeNH *>(nh);
1369 21 : comp_nh->set_validate_mcast_src(ValidateMcastSrc());
1370 : }
1371 :
1372 21 : NextHopKey *key = static_cast<NextHopKey *>(nh_req.key.get());
1373 : //Bake all MPLS label
1374 21 : 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 21 : if (evpn_label != MplsTable::kInvalidLabel) {
1387 42 : evpn_label = agent->mpls_table()->CreateRouteLabel(evpn_label, key,
1388 42 : vrf()->GetName(), ToString());
1389 : }
1390 :
1391 21 : bool ret = false;
1392 : //Identify parameters to be passed to populate multicast_peer path and
1393 : //based on peer priorites for each attribute.
1394 21 : std::string dest_vn_name = "";
1395 21 : bool unresolved = false;
1396 21 : uint32_t vxlan_id = 0;
1397 21 : uint32_t tunnel_bmap = TunnelType::AllType();
1398 :
1399 : //Select based on priority of path peer.
1400 21 : if (local_vm_peer_path) {
1401 21 : dest_vn_name = local_vm_peer_path->dest_vn_name();
1402 21 : unresolved = local_vm_peer_path->unresolved();
1403 21 : vxlan_id = local_vm_peer_path->vxlan_id();
1404 21 : 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 21 : uint32_t label = evpn_label;
1424 : //Mpls label selection needs to be overridden by fabric label
1425 : //if fabric peer is present.
1426 21 : if (fabric_peer_path) {
1427 0 : label = fabric_peer_path->label();
1428 : }
1429 :
1430 21 : 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 21 : dynamic_cast<MulticastRoutePath *>(multicast_peer_path);
1440 21 : if (multicast_route_path) {
1441 21 : multicast_route_path->UpdateLabels(evpn_label, label);
1442 : }
1443 :
1444 21 : return ret;
1445 21 : }
|