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