Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_evpn.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <algorithm>
10 : #include <string>
11 :
12 : #include "base/set_util.h"
13 : #include "base/task_annotations.h"
14 : #include "bgp/bgp_log.h"
15 : #include "bgp/bgp_multicast.h"
16 : #include "bgp/bgp_peer_types.h"
17 : #include "bgp/bgp_server.h"
18 : #include "bgp/bgp_update.h"
19 : #include "bgp/ermvpn/ermvpn_route.h"
20 : #include "bgp/ermvpn/ermvpn_table.h"
21 : #include "bgp/evpn/evpn_table.h"
22 : #include "bgp/extended-community/multicast_flags.h"
23 : #include "bgp/routing-instance/routing_instance.h"
24 : #include "bgp/routing-instance/routing_instance_analytics_types.h"
25 : #include "bgp/routing-instance/routing_instance_log.h"
26 :
27 : using std::pair;
28 : using std::set;
29 : using std::sort;
30 : using std::string;
31 : using std::vector;
32 :
33 : // A global MVPN state for a given <S.G> within a EvpnProjectManager.
34 2698 : EvpnState::EvpnState(const SG &sg, StatesMap *states, EvpnManager *manager) :
35 8094 : sg_(sg), global_ermvpn_tree_rt_(NULL), states_(states),
36 2698 : manager_(manager) {
37 2698 : refcount_ = 0;
38 2698 : }
39 :
40 5396 : EvpnState::~EvpnState() {
41 2698 : assert(!global_ermvpn_tree_rt_);
42 2698 : EVPN_TRACE(EvpnStateCreate, sg_.source.to_string(), sg_.group.to_string());
43 5396 : }
44 :
45 15102 : const ErmVpnTable *EvpnState::table() const {
46 15102 : return manager_ ? manager_->ermvpn_table() : NULL;
47 : }
48 :
49 : class EvpnManager::DeleteActor : public LifetimeActor {
50 : public:
51 42907 : explicit DeleteActor(EvpnManager *evpn_manager)
52 42907 : : LifetimeActor(evpn_manager->server()->lifetime_manager()),
53 42907 : evpn_manager_(evpn_manager) {
54 42907 : }
55 85814 : virtual ~DeleteActor() {
56 85814 : }
57 :
58 42907 : virtual bool MayDelete() const {
59 42907 : CHECK_CONCURRENCY("bgp::Config");
60 42907 : return evpn_manager_->MayDelete();
61 : }
62 :
63 42907 : virtual void Shutdown() {
64 42907 : evpn_manager_->Shutdown();
65 42907 : }
66 :
67 42907 : virtual void Destroy() {
68 42907 : evpn_manager_->table_->DestroyEvpnManager();
69 42907 : }
70 :
71 : private:
72 : EvpnManager *evpn_manager_;
73 : };
74 :
75 : //
76 : // Constructor for EvpnMcastNode. The type indicates whether this is a local
77 : // or remote EvpnMcastNode.
78 : //
79 5099 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
80 5099 : EvpnRoute *route, uint8_t type)
81 5099 : : partition_(partition),
82 5099 : state_(NULL),
83 5099 : route_(route),
84 5099 : type_(type),
85 5099 : label_(0),
86 5099 : edge_replication_not_supported_(false),
87 5099 : assisted_replication_supported_(false),
88 5099 : assisted_replication_leaf_(false) {
89 5099 : UpdateAttributes(route);
90 5099 : }
91 :
92 3331 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
93 3331 : EvpnRoute *route, uint8_t type, EvpnStatePtr state)
94 3331 : : partition_(partition),
95 3331 : state_(state),
96 3331 : route_(route),
97 3331 : type_(type),
98 3331 : label_(0),
99 3331 : edge_replication_not_supported_(false),
100 3331 : assisted_replication_supported_(false),
101 3331 : assisted_replication_leaf_(false) {
102 3331 : if (route)
103 642 : UpdateAttributes(route);
104 3331 : }
105 :
106 : //
107 : // Destructor for EvpnMcastNode.
108 : //
109 8430 : EvpnMcastNode::~EvpnMcastNode() {
110 8430 : set_state(NULL);
111 8430 : }
112 :
113 : //
114 : // Update the label and attributes for a EvpnMcastNode.
115 : // Return true if either of them changed.
116 : //
117 41831 : bool EvpnMcastNode::UpdateAttributes(EvpnRoute *route) {
118 41831 : bool changed = false;
119 41831 : const BgpPath *path = route->BestPath();
120 41831 : if (path->GetLabel() != label_) {
121 6533 : label_ = path->GetLabel();
122 6533 : changed = true;
123 : }
124 41831 : if (path->GetAttr() != attr_) {
125 24439 : attr_ = path->GetAttr();
126 24439 : changed = true;
127 : }
128 :
129 41831 : const PmsiTunnel *pmsi_tunnel = attr_->pmsi_tunnel();
130 41831 : uint8_t ar_type = 0;
131 41831 : bool edge_replication_not_supported = false;
132 41831 : if (pmsi_tunnel) {
133 41189 : ar_type = pmsi_tunnel->tunnel_flags() &
134 : PmsiTunnelSpec::AssistedReplicationType;
135 41189 : if ((pmsi_tunnel->tunnel_flags() &
136 41189 : PmsiTunnelSpec::EdgeReplicationSupported) == 0) {
137 6455 : edge_replication_not_supported = true;
138 : }
139 41189 : if (replicator_address_ != pmsi_tunnel->identifier()) {
140 5099 : replicator_address_ = pmsi_tunnel->identifier();
141 5099 : changed = true;
142 : }
143 : }
144 :
145 41831 : if (edge_replication_not_supported != edge_replication_not_supported_) {
146 1655 : edge_replication_not_supported_ = edge_replication_not_supported;
147 1655 : changed = true;
148 : }
149 :
150 41831 : bool assisted_replication_supported = false;
151 41831 : if (ar_type == PmsiTunnelSpec::ARReplicator)
152 3560 : assisted_replication_supported = true;
153 41831 : if (assisted_replication_supported != assisted_replication_supported_) {
154 184 : assisted_replication_supported_ = assisted_replication_supported;
155 184 : changed = true;
156 : }
157 :
158 41831 : bool assisted_replication_leaf = false;
159 41831 : if (ar_type == PmsiTunnelSpec::ARLeaf)
160 965 : assisted_replication_leaf = true;
161 41831 : if (assisted_replication_leaf != assisted_replication_leaf_) {
162 531 : assisted_replication_leaf_ = assisted_replication_leaf;
163 531 : changed = true;
164 : }
165 :
166 41831 : if (address_ != path->GetAttr()->nexthop().to_v4()) {
167 5139 : address_ = path->GetAttr()->nexthop().to_v4();
168 5139 : changed = true;
169 : }
170 :
171 41831 : return changed;
172 : }
173 :
174 : //
175 : // Constructor for EvpnLocalMcastNode.
176 : //
177 : // Add an Inclusive Multicast route corresponding to Broadcast MAC route.
178 : //
179 : // Need to Notify the Broadcast MAC route so that the table Export method
180 : // can run and build the OList. OList is not built till EvpnLocalMcastNode
181 : // has been created.
182 : //
183 2150 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
184 2150 : EvpnRoute *route)
185 : : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode),
186 2150 : inclusive_mcast_route_(NULL) {
187 2150 : AddInclusiveMulticastRoute();
188 2150 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
189 2150 : tbl_partition->Notify(route_);
190 2150 : }
191 :
192 3307 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
193 3307 : EvpnRoute *route, EvpnStatePtr state)
194 : : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode, state),
195 3307 : inclusive_mcast_route_(NULL) {
196 3307 : if (!route)
197 2689 : return;
198 618 : AddInclusiveMulticastRoute();
199 618 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
200 618 : tbl_partition->Notify(route_);
201 0 : }
202 :
203 : //
204 : // Destructor for EvpnLocalMcastNode.
205 : //
206 10914 : EvpnLocalMcastNode::~EvpnLocalMcastNode() {
207 5457 : DeleteInclusiveMulticastRoute();
208 10914 : }
209 :
210 : //
211 : // Add Inclusive Multicast route for this EvpnLocalMcastNode.
212 : // The attributes are based on the Broadcast MAC route.
213 : //
214 20690 : void EvpnLocalMcastNode::AddInclusiveMulticastRoute() {
215 : // No need to create IMET route if group is specified
216 20690 : if (!route_->GetPrefix().group().is_unspecified())
217 618 : return;
218 20072 : assert(!inclusive_mcast_route_);
219 20072 : if (label_ == 0)
220 0 : return;
221 :
222 : // Construct the prefix and route key.
223 : // Build the RD using the TOR IP address, not the TOR agent IP address.
224 : // This ensures that the MAC broadcast route from the primary and backup
225 : // TOR Agents results in the same Inclusive Multicast prefix.
226 20072 : const EvpnPrefix &mac_prefix = route_->GetPrefix();
227 : RouteDistinguisher rd(
228 20072 : address_.to_ulong(), mac_prefix.route_distinguisher().GetVrfId());
229 20072 : EvpnPrefix prefix(rd, mac_prefix.tag(), address_);
230 20072 : EvpnRoute rt_key(prefix);
231 :
232 : // Find or create the route.
233 20072 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
234 20072 : EvpnRoute *route = static_cast<EvpnRoute *>(tbl_partition->Find(&rt_key));
235 20072 : if (!route) {
236 2149 : route = new EvpnRoute(prefix);
237 2149 : tbl_partition->Add(route);
238 : } else {
239 17923 : route->ClearDelete();
240 : }
241 : // Add MulticastFlags community to specify that it supports SMET route
242 20072 : ExtCommunity::ExtCommunityList mcastFlags;
243 20072 : mcastFlags.push_back(MulticastFlags().GetExtCommunity());
244 20072 : ExtCommunityPtr ext_community = partition_->server()->extcomm_db()->
245 20072 : ReplaceMFlagsAndLocate(attr_->ext_community(), mcastFlags);
246 40144 : attr_ = partition_->server()->attr_db()->ReplaceExtCommunityAndLocate(
247 20072 : attr_.get(), ext_community);
248 :
249 : // Add a path with source BgpPath::Local and the peer address as path_id.
250 20072 : uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
251 20072 : BgpPath *path = new BgpPath(path_id, BgpPath::Local, attr_, 0, label_);
252 20072 : route->InsertPath(path);
253 20072 : inclusive_mcast_route_ = route;
254 20072 : tbl_partition->Notify(inclusive_mcast_route_);
255 20072 : BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
256 : route, "Insert new Local path");
257 20072 : }
258 :
259 : //
260 : // Delete Inclusive Multicast route for this EvpnLocalMcastNode.
261 : //
262 23379 : void EvpnLocalMcastNode::DeleteInclusiveMulticastRoute() {
263 23379 : if (!inclusive_mcast_route_)
264 3307 : return;
265 :
266 20072 : const EvpnPrefix &mac_prefix = route_->GetPrefix();
267 20072 : uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
268 20072 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
269 20072 : inclusive_mcast_route_->RemovePath(BgpPath::Local, path_id);
270 20072 : BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
271 : inclusive_mcast_route_, "Delete Local path");
272 :
273 20072 : if (!inclusive_mcast_route_->HasPaths()) {
274 20071 : tbl_partition->Delete(inclusive_mcast_route_);
275 : } else {
276 1 : tbl_partition->Notify(inclusive_mcast_route_);
277 : }
278 20072 : inclusive_mcast_route_ = NULL;
279 : }
280 :
281 : //
282 : // Handle update of EvpnLocalMcastNode.
283 : //
284 : // We delete and add the Inclusive Multicast route to ensure that all the
285 : // attributes are updated. An in-place update is not always possible since
286 : // the vRouter address is part of the key for the Inclusive Multicast route.
287 : //
288 17922 : void EvpnLocalMcastNode::TriggerUpdate() {
289 17922 : DeleteInclusiveMulticastRoute();
290 17922 : AddInclusiveMulticastRoute();
291 17922 : }
292 :
293 : //
294 : // Construct an UpdateInfo with the RibOutAttr that needs to be advertised to
295 : // the IPeer for the EvpnRoute associated with this EvpnLocalMcastNode. This
296 : // is used the Export method of the EvpnTable. It is expected that the caller
297 : // fills in the target RibPeerSet in the UpdateInfo.
298 : //
299 : // The main functionality here is to build a per-IPeer BgpOList from the list
300 : // of EvpnRemoteMcastNodes.
301 : //
302 7238 : UpdateInfo *EvpnLocalMcastNode::GetUpdateInfo(EvpnRoute *route) {
303 7238 : CHECK_CONCURRENCY("db::DBTable");
304 :
305 : // Nothing to send for a leaf as it already knows the replicator-address.
306 7238 : if (assisted_replication_leaf_)
307 18 : return NULL;
308 :
309 7220 : const RoutingInstance *rti = partition_->table()->routing_instance();
310 7220 : bool pbb_evpn_enable = rti->virtual_network_pbb_evpn_enable();
311 7220 : uint32_t local_ethernet_tag = route_->GetPrefix().tag();
312 :
313 7220 : EvpnState::SG sg = EvpnState::SG(route->GetPrefix().source(),
314 14440 : route->GetPrefix().group());
315 : // Go through list of EvpnRemoteMcastNodes and build the BgpOList.
316 7220 : BgpOListSpec olist_spec(BgpAttribute::OList);
317 7220 : if (partition_->remote_mcast_node_list()->count(sg)) {
318 7058 : set<EvpnMcastNode*> nodes = (*partition_->remote_mcast_node_list())[sg];
319 211124 : BOOST_FOREACH(EvpnMcastNode *node, nodes) {
320 102033 : if (node->address() == address_)
321 84039 : continue;
322 95113 : if (node->assisted_replication_leaf())
323 1648 : continue;
324 180850 : if (!edge_replication_not_supported_ &&
325 87385 : !node->edge_replication_not_supported())
326 75215 : continue;
327 18250 : uint32_t remote_ethernet_tag = node->route()->GetPrefix().tag();
328 :
329 18250 : if (pbb_evpn_enable && remote_ethernet_tag &&
330 : (local_ethernet_tag != remote_ethernet_tag))
331 256 : continue;
332 :
333 17994 : const ExtCommunity *extcomm = node->attr()->ext_community();
334 35988 : BgpOListElem elem(node->address(), node->label(),
335 35988 : extcomm ? extcomm->GetTunnelEncap() : vector<string>());
336 17994 : olist_spec.elements.push_back(elem);
337 17994 : }
338 7058 : }
339 :
340 : // Go through list of leaf EvpnMcastNodes and build the leaf BgpOList.
341 7220 : BgpOListSpec leaf_olist_spec(BgpAttribute::LeafOList);
342 7220 : if (assisted_replication_supported_) {
343 384 : if (partition_->leaf_node_list()->count(sg)) {
344 212 : set<EvpnMcastNode*> nodes = (*partition_->leaf_node_list())[sg];
345 3508 : BOOST_FOREACH(EvpnMcastNode *node, nodes) {
346 1648 : if (node->replicator_address() != address_)
347 816 : continue;
348 :
349 832 : const ExtCommunity *extcomm = node->attr()->ext_community();
350 1664 : BgpOListElem elem(node->address(), node->label(),
351 1664 : extcomm ? extcomm->GetTunnelEncap() : vector<string>());
352 832 : leaf_olist_spec.elements.push_back(elem);
353 832 : }
354 212 : }
355 : }
356 :
357 : // Bail if both BgpOLists are empty.
358 7220 : if (olist_spec.elements.empty() && leaf_olist_spec.elements.empty())
359 2502 : return NULL;
360 :
361 : // Add BgpOList and leaf BgpOList to RibOutAttr for broadcast MAC route.
362 4718 : BgpAttrDB *attr_db = partition_->server()->attr_db();
363 4718 : BgpAttrPtr attr = attr_db->ReplaceOListAndLocate(attr_.get(), &olist_spec);
364 4718 : attr = attr_db->ReplaceLeafOListAndLocate(attr.get(), &leaf_olist_spec);
365 :
366 4718 : UpdateInfo *uinfo = new UpdateInfo;
367 : uinfo->roattr =
368 4718 : RibOutAttr(partition_->table(), route_, attr.get(), 0, false, true);
369 4718 : return uinfo;
370 7220 : }
371 :
372 : //
373 : // Constructor for EvpnRemoteMcastNode.
374 : //
375 2949 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
376 2949 : EvpnRoute *route)
377 2949 : : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode) {
378 2949 : }
379 :
380 24 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
381 24 : EvpnRoute *route, EvpnStatePtr state)
382 24 : : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode, state) {
383 24 : }
384 :
385 : //
386 : // Destructor for EvpnRemoteMcastNode.
387 : //
388 5946 : EvpnRemoteMcastNode::~EvpnRemoteMcastNode() {
389 5946 : }
390 :
391 : //
392 : // Handle update of EvpnRemoteMcastNode.
393 : //
394 776 : void EvpnRemoteMcastNode::TriggerUpdate() {
395 776 : }
396 :
397 : //
398 : // Constructor for EvpnSegment.
399 : //
400 34 : EvpnSegment::EvpnSegment(EvpnManager *manager, const EthernetSegmentId &esi)
401 34 : : evpn_manager_(manager),
402 34 : esi_(esi),
403 34 : esi_ad_route_(NULL),
404 34 : single_active_(true),
405 34 : route_lists_(DB::PartitionCount()) {
406 34 : }
407 :
408 : //
409 : // Destructor for EvpnSegment.
410 : //
411 68 : EvpnSegment::~EvpnSegment() {
412 34 : assert(!esi_ad_route_);
413 34 : assert(pe_list_.empty());
414 68 : }
415 :
416 : //
417 : // Add the given MAC route as a dependent of this EvpnSegment.
418 : //
419 54 : void EvpnSegment::AddMacRoute(size_t part_id, EvpnRoute *route) {
420 54 : pair<RouteList::iterator, bool> ret = route_lists_[part_id].insert(route);
421 54 : assert(ret.second);
422 54 : }
423 :
424 : //
425 : // Delete the given MAC route as a dependent of this EvpnSegment.
426 : // Trigger deletion of the EvpnSegment if there are no dependent
427 : // routes in the partition.
428 : //
429 54 : void EvpnSegment::DeleteMacRoute(size_t part_id, EvpnRoute *route) {
430 54 : size_t count = route_lists_[part_id].erase(route);
431 54 : assert(count == 1);
432 54 : if (route_lists_[part_id].empty())
433 38 : evpn_manager_->TriggerSegmentDelete(this);
434 54 : }
435 :
436 : //
437 : // Trigger an update of all dependent MAC routes for this EvpnSegment.
438 : // Note that the bgp::EvpnSegment task is mutually exclusive with the
439 : // db::DBTable task.
440 : //
441 61 : void EvpnSegment::TriggerMacRouteUpdate() {
442 61 : CHECK_CONCURRENCY("bgp::EvpnSegment");
443 :
444 305 : for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
445 244 : EvpnManagerPartition *partition = evpn_manager_->GetPartition(part_id);
446 324 : BOOST_FOREACH(EvpnRoute *route, route_lists_[part_id]) {
447 40 : partition->TriggerMacRouteUpdate(route);
448 : }
449 : }
450 61 : }
451 :
452 : //
453 : // Update the PE list for this EvpnSegment. This should be called when
454 : // the AutoDisocvery route is updated.
455 : // Return true if there's a change in the PE list i.e. if an entry is
456 : // added, deleted or updated.
457 : //
458 63 : bool EvpnSegment::UpdatePeList() {
459 63 : CHECK_CONCURRENCY("bgp::EvpnSegment");
460 :
461 : // Mark all entries as invalid.
462 63 : for (RemotePeList::iterator it = pe_list_.begin();
463 124 : it != pe_list_.end(); ++it) {
464 61 : it->esi_valid = false;
465 : }
466 :
467 : // Go through all paths for the route and refresh/update existing entries
468 : // or add new ones as necessary. Remember that there was a change in the
469 : // list if any element changed or is added/deleted.
470 63 : bool changed = false;
471 63 : for (Route::PathList::const_iterator path_it =
472 126 : esi_ad_route_->GetPathList().begin();
473 252 : path_it != esi_ad_route_->GetPathList().end(); ++path_it) {
474 : const BgpPath *path =
475 63 : static_cast<const BgpPath *>(path_it.operator->());
476 63 : const BgpAttr *attr = path->GetAttr();
477 :
478 : // Skip non-VXLAN paths for now.
479 63 : const ExtCommunity *extcomm = attr->ext_community();
480 63 : if (!extcomm || !extcomm->ContainsTunnelEncapVxlan())
481 2 : continue;
482 :
483 : // Go through existing pe list and try to find the RemotePe.
484 61 : bool found = false;
485 61 : RemotePe remote_pe(path);
486 61 : for (RemotePeList::iterator it = pe_list_.begin();
487 95 : it != pe_list_.end(); ++it) {
488 : // Skip if the nexthop doesn't match.
489 51 : if (it->attr->nexthop() != remote_pe.attr->nexthop())
490 30 : continue;
491 :
492 : // We're done if there are multiple paths for the same remote PE
493 : // e.g. when a pair of route reflectors is being used.
494 21 : if (it->esi_valid) {
495 0 : found = true;
496 0 : break;
497 : }
498 :
499 : // Check if we have a match.
500 21 : if (*it == remote_pe) {
501 17 : it->esi_valid = true;
502 17 : found = true;
503 17 : break;
504 : }
505 : }
506 :
507 : // Add a new entry to the pe list if we didn't find the RemotePe.
508 61 : if (!found) {
509 44 : pe_list_.push_back(remote_pe);
510 44 : changed = true;
511 : }
512 61 : }
513 :
514 : // Erase invalid entries from the list.
515 63 : for (RemotePeList::iterator it = pe_list_.begin(), next = it;
516 168 : it != pe_list_.end(); it = next) {
517 105 : ++next;
518 105 : if (!it->esi_valid) {
519 44 : pe_list_.erase(it);
520 44 : changed = true;
521 : }
522 : }
523 :
524 : // Update the single active status of the EvpnSegment itself.
525 63 : single_active_ = false;
526 63 : for (RemotePeList::iterator it = pe_list_.begin();
527 113 : it != pe_list_.end(); ++it) {
528 60 : if (it->single_active) {
529 10 : single_active_ = true;
530 10 : break;
531 : }
532 : }
533 :
534 63 : return changed;
535 : }
536 :
537 : //
538 : // Return true if it's safe to delete this EvpnSegment.
539 : //
540 51 : bool EvpnSegment::MayDelete() const {
541 51 : CHECK_CONCURRENCY("bgp::EvpnSegment");
542 :
543 : // Bail if we have state set on the per-ESI AD route.
544 51 : if (esi_ad_route_)
545 14 : return false;
546 :
547 : // Bail if the dependent route list for any partition is not empty.
548 173 : for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
549 139 : if (!route_lists_[part_id].empty())
550 3 : return false;
551 : }
552 :
553 34 : return true;
554 : }
555 :
556 : //
557 : // Constructor for EvpnSegment::RemotePe.
558 : //
559 61 : EvpnSegment::RemotePe::RemotePe(const BgpPath *path)
560 61 : : esi_valid(true),
561 61 : single_active(path->GetAttr()->evpn_single_active()),
562 61 : peer(path->GetPeer()),
563 61 : attr(path->GetAttr()),
564 61 : flags(path->GetFlags()),
565 61 : src(path->GetSource()) {
566 61 : }
567 :
568 : //
569 : // Equality operator for EvpnSegment::RemotePe.
570 : // Do not compare esi_valid and single_active fields since they are
571 : // derived.
572 : //
573 21 : bool EvpnSegment::RemotePe::operator==(const RemotePe &rhs) const {
574 21 : if (peer != rhs.peer)
575 0 : return false;
576 21 : if (attr != rhs.attr)
577 4 : return false;
578 17 : if (flags != rhs.flags)
579 0 : return false;
580 17 : if (src != rhs.src)
581 0 : return false;
582 17 : return true;
583 : }
584 :
585 : //
586 : // Constructor for EvpnMacState.
587 : //
588 52 : EvpnMacState::EvpnMacState(EvpnManager *evpn_manager, EvpnRoute *route)
589 52 : : evpn_manager_(evpn_manager), route_(route), segment_(NULL) {
590 52 : }
591 :
592 : //
593 : // Destructor for EvpnMacState.
594 : //
595 102 : EvpnMacState::~EvpnMacState() {
596 51 : assert(segment_ == NULL);
597 51 : assert(aliased_path_list_.empty());
598 102 : }
599 :
600 : //
601 : // Add the BgpPath specified by the iterator to the aliased path list.
602 : // Also inserts the BgpPath to the BgpRoute.
603 : //
604 28 : void EvpnMacState::AddAliasedPath(AliasedPathList::const_iterator it) {
605 28 : BgpPath *path = *it;
606 28 : const IPeer *peer = path->GetPeer();
607 28 : aliased_path_list_.insert(path);
608 28 : route_->InsertPath(path);
609 28 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
610 : "Added aliased path " << route_->ToString() <<
611 : " peer " << (peer ? peer->ToString() : "None") <<
612 : " nexthop " << path->GetAttr()->nexthop().to_string() <<
613 : " label " << path->GetLabel() <<
614 : " in table " << evpn_manager_->table()->name());
615 28 : }
616 :
617 : //
618 : // Delete the BgpPath specified by the iterator from the aliased path list.
619 : // Also deletes the BgpPath from the BgpRoute.
620 : //
621 28 : void EvpnMacState::DeleteAliasedPath(AliasedPathList::const_iterator it) {
622 28 : BgpPath *path = *it;
623 28 : const IPeer *peer = path->GetPeer();
624 28 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
625 : "Deleted aliased path " << route_->ToString() <<
626 : " peer " << (peer ? peer->ToString() : "None") <<
627 : " nexthop " << path->GetAttr()->nexthop().to_string() <<
628 : " label " << path->GetLabel() <<
629 : " in table " << evpn_manager_->table()->name());
630 28 : route_->DeletePath(path);
631 28 : aliased_path_list_.erase(it);
632 28 : }
633 :
634 : //
635 : // Find or create the matching aliased BgpPath.
636 : //
637 58 : BgpPath *EvpnMacState::LocateAliasedPath(
638 : const EvpnSegment::RemotePe *remote_pe, uint32_t label) {
639 58 : const IPeer *peer = remote_pe->peer;
640 58 : const BgpAttr *attr = remote_pe->attr.get();
641 58 : uint32_t flags = remote_pe->flags | BgpPath::AliasedPath;
642 58 : BgpPath::PathSource src = remote_pe->src;
643 58 : for (AliasedPathList::iterator it = aliased_path_list_.begin();
644 69 : it != aliased_path_list_.end(); ++it) {
645 41 : BgpPath *path = *it;
646 71 : if (path->GetPeer() == peer &&
647 60 : path->GetAttr() == attr &&
648 101 : path->GetFlags() == flags &&
649 30 : path->GetLabel() == label) {
650 30 : return path;
651 : }
652 : }
653 :
654 28 : return (new BgpPath(peer, src, attr, flags, label));
655 : }
656 :
657 : //
658 : // Update aliased BgpPaths for the EvpnRoute based on the remote PEs
659 : // for the EvpnSegment.
660 : // Return true if the list of aliased paths is modified.
661 : //
662 174 : bool EvpnMacState::ProcessMacRouteAliasing() {
663 174 : CHECK_CONCURRENCY("db::DBTable");
664 :
665 171 : const BgpPath *path = route_->BestPath();
666 :
667 : // Find the remote PE entry that corresponds to the primary path.
668 171 : bool found_primary_pe = false;
669 171 : EvpnSegment::const_iterator it;
670 171 : if (path && segment_ && !segment_->single_active())
671 65 : it = segment_->begin();
672 246 : for (; path && segment_ && !segment_->single_active() &&
673 251 : it != segment_->end(); ++it) {
674 51 : if (path->GetAttr()->nexthop() != it->attr->nexthop())
675 5 : continue;
676 46 : found_primary_pe = true;
677 46 : break;
678 : }
679 :
680 : // Go through the remote PE list for the EvpnSegment and build the
681 : // list of future aliased paths.
682 171 : AliasedPathList future_aliased_path_list;
683 171 : if (found_primary_pe && path && segment_ && !segment_->single_active())
684 46 : it = segment_->begin();
685 323 : for (; found_primary_pe && path && segment_ &&
686 429 : !segment_->single_active() && it != segment_->end(); ++it) {
687 : // Skip if there's a BGP_XMPP path with the remote PE as nexthop.
688 106 : if (route_->FindPath(it->attr->nexthop()))
689 48 : continue;
690 :
691 : // Locate the aliased path using attributes for the remote PE and
692 : // label from the primary path.
693 : BgpPath *aliased_path =
694 58 : LocateAliasedPath(it.operator->(), path->GetLabel());
695 58 : future_aliased_path_list.insert(aliased_path);
696 : }
697 :
698 : // Reconcile the current and future aliased paths and notify/delete the
699 : // route as appropriate.
700 171 : bool modified = set_synchronize(&aliased_path_list_,
701 : &future_aliased_path_list,
702 : boost::bind(&EvpnMacState::AddAliasedPath, this, _1),
703 : boost::bind(&EvpnMacState::DeleteAliasedPath, this, _1));
704 171 : return modified;
705 171 : }
706 :
707 : //
708 : // Constructor for EvpnManagerPartition.
709 : //
710 170329 : EvpnManagerPartition::EvpnManagerPartition(EvpnManager *evpn_manager,
711 170329 : size_t part_id)
712 170329 : : evpn_manager_(evpn_manager),
713 170329 : part_id_(part_id),
714 340658 : mac_update_trigger_(new TaskTrigger(
715 : boost::bind(&EvpnManagerPartition::ProcessMacUpdateList, this),
716 340643 : TaskScheduler::GetInstance()->GetTaskId("db::DBTable"),
717 340661 : part_id)) {
718 170330 : table_partition_ = evpn_manager_->GetTablePartition(part_id);
719 170330 : }
720 :
721 : //
722 : // Destructor for EvpnManagerPartition.
723 : //
724 170333 : EvpnManagerPartition::~EvpnManagerPartition() {
725 170333 : assert(local_mcast_node_list_.empty());
726 170333 : assert(remote_mcast_node_list_.empty());
727 170333 : assert(mac_update_list_.empty());
728 170333 : }
729 :
730 : //
731 : // Get the DBTablePartition for the EvpnTable for our partition id.
732 : //
733 71724 : DBTablePartition *EvpnManagerPartition::GetTablePartition() {
734 71724 : return evpn_manager_->GetTablePartition(part_id_);
735 : }
736 :
737 : //
738 : // Notify the Broadcast MAC route for the given EvpnMcastNode.
739 : //
740 20690 : void EvpnManagerPartition::NotifyNodeRoute(EvpnMcastNode *node) {
741 20690 : DBTablePartition *tbl_partition = GetTablePartition();
742 20690 : tbl_partition->Notify(node->route());
743 20690 : }
744 :
745 : //
746 : // Go through all replicator EvpnMcastNodes and notify associated Broadcast
747 : // MAC route.
748 : //
749 1026 : void EvpnManagerPartition::NotifyReplicatorNodeRoutes() {
750 1026 : DBTablePartition *tbl_partition = GetTablePartition();
751 1026 : EvpnMcastNodeList::const_iterator it = replicator_node_list_.begin();
752 1986 : for (; it != replicator_node_list_.end(); it++) {
753 4800 : BOOST_FOREACH(EvpnMcastNode *node, it->second)
754 1920 : tbl_partition->Notify(node->route());
755 : }
756 1026 : }
757 :
758 : //
759 : // Go through all ingress replication client EvpnMcastNodes and notify the
760 : // associated Broadcast MAC route.
761 : //
762 7096 : void EvpnManagerPartition::NotifyIrClientNodeRoutes(
763 : bool exclude_edge_replication_supported) {
764 7096 : DBTablePartition *tbl_partition = GetTablePartition();
765 7096 : EvpnMcastNodeList::const_iterator it = ir_client_node_list_.begin();
766 13031 : for (; it != ir_client_node_list_.end(); it++) {
767 116959 : BOOST_FOREACH(EvpnMcastNode *node, it->second) {
768 94673 : if (exclude_edge_replication_supported &&
769 39161 : !node->edge_replication_not_supported()) {
770 37581 : continue;
771 : }
772 17931 : tbl_partition->Notify(node->route());
773 : }
774 : }
775 7096 : }
776 :
777 : //
778 : // Add an EvpnMcastNode to the EvpnManagerPartition.
779 : //
780 5741 : void EvpnManagerPartition::AddMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
781 5741 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
782 11482 : rt->GetPrefix().group());
783 5741 : if (node->type() == EvpnMcastNode::LocalNode) {
784 2768 : local_mcast_node_list_[sg].insert(node);
785 2768 : if (node->assisted_replication_supported())
786 92 : replicator_node_list_[sg].insert(node);
787 2768 : if (!node->assisted_replication_leaf())
788 2606 : ir_client_node_list_[sg].insert(node);
789 2768 : NotifyNodeRoute(node);
790 : } else {
791 2973 : remote_mcast_node_list_[sg].insert(node);
792 2973 : if (node->assisted_replication_leaf()) {
793 369 : leaf_node_list_[sg].insert(node);
794 369 : NotifyReplicatorNodeRoutes();
795 2604 : } else if (node->edge_replication_not_supported()) {
796 728 : regular_node_list_[sg].insert(node);
797 728 : NotifyIrClientNodeRoutes(false);
798 1876 : } else if (!node->assisted_replication_leaf()) {
799 1876 : NotifyIrClientNodeRoutes(true);
800 : }
801 : }
802 5741 : }
803 :
804 : //
805 : // Delete an EvpnMcastNode from the EvpnManagerPartition.
806 : //
807 54619 : bool EvpnManagerPartition::RemoveMcastNodeFromList(EvpnState::SG &sg,
808 : EvpnMcastNode *node,
809 : EvpnMcastNodeList *list) {
810 54619 : size_t deleted = 0;
811 54619 : if (list->count(sg)) {
812 31096 : deleted = (*list)[sg].erase(node);
813 31096 : if ((*list)[sg].size() == 0)
814 2191 : list->erase(sg);
815 : }
816 54619 : return (deleted > 0);
817 : }
818 :
819 : //
820 : // Delete an EvpnMcastNode from the EvpnManagerPartition.
821 : //
822 5741 : void EvpnManagerPartition::DeleteMcastNode(EvpnMcastNode *node,
823 : EvpnRoute * rt) {
824 5741 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
825 11482 : rt->GetPrefix().group());
826 5741 : if (node->type() == EvpnMcastNode::LocalNode) {
827 2768 : RemoveMcastNodeFromList(sg, node, &local_mcast_node_list_);
828 2768 : RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
829 2768 : RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
830 : } else {
831 2973 : RemoveMcastNodeFromList(sg, node, &remote_mcast_node_list_);
832 2973 : if (RemoveMcastNodeFromList(sg, node, &leaf_node_list_)) {
833 369 : NotifyReplicatorNodeRoutes();
834 : } else {
835 2604 : NotifyIrClientNodeRoutes(true);
836 : }
837 2973 : if (RemoveMcastNodeFromList(sg, node, ®ular_node_list_)) {
838 912 : NotifyIrClientNodeRoutes(false);
839 : }
840 : }
841 5741 : if (empty())
842 511 : evpn_manager_->RetryDelete();
843 5741 : }
844 :
845 : //
846 : // Update an EvpnMcastNode in the EvpnManagerPartition.
847 : // Need to remove/add EvpnMcastNode from the replicator, leaf and ir client
848 : // lists as appropriate.
849 : //
850 18698 : void EvpnManagerPartition::UpdateMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
851 18698 : node->TriggerUpdate();
852 18698 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
853 37396 : rt->GetPrefix().group());
854 18698 : if (node->type() == EvpnMcastNode::LocalNode) {
855 17922 : RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
856 17922 : if (node->assisted_replication_supported())
857 1688 : replicator_node_list_[sg].insert(node);
858 17922 : RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
859 17922 : if (!node->assisted_replication_leaf())
860 17778 : ir_client_node_list_[sg].insert(node);
861 17922 : NotifyNodeRoute(node);
862 : } else {
863 776 : bool was_leaf = RemoveMcastNodeFromList(sg, node, &leaf_node_list_);
864 776 : if (node->assisted_replication_leaf())
865 288 : leaf_node_list_[sg].insert(node);
866 776 : if (was_leaf || node->assisted_replication_leaf())
867 288 : NotifyReplicatorNodeRoutes();
868 776 : if (!was_leaf || !node->assisted_replication_leaf())
869 488 : NotifyIrClientNodeRoutes(true);
870 776 : bool was_regular = RemoveMcastNodeFromList(
871 : sg, node, ®ular_node_list_);
872 776 : if (node->edge_replication_not_supported())
873 456 : regular_node_list_[sg].insert(node);
874 776 : if (was_regular || node->edge_replication_not_supported())
875 488 : NotifyIrClientNodeRoutes(false);
876 : }
877 18698 : }
878 :
879 : //
880 : // Add the given MAC route to the update list.
881 : // This method gets called either when the MAC route itself changes or when
882 : // the remote PE list for the EvpnSegment of the MAC route gets updated.
883 : //
884 180 : void EvpnManagerPartition::TriggerMacRouteUpdate(EvpnRoute *route) {
885 180 : CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
886 :
887 181 : mac_update_list_.insert(route);
888 181 : mac_update_trigger_->Set();
889 181 : }
890 :
891 : //
892 : // Process the MAC route update list for this EvpnManagerPartition.
893 : //
894 156 : bool EvpnManagerPartition::ProcessMacUpdateList() {
895 156 : CHECK_CONCURRENCY("db::DBTable");
896 :
897 157 : BgpTable *table = evpn_manager_->table();
898 157 : int listener_id = evpn_manager_->listener_id();
899 :
900 502 : BOOST_FOREACH(EvpnRoute *route, mac_update_list_) {
901 : // Skip if the route is on the change list. We will get another
902 : // chance to process it after the MacAdvertisement listener sees
903 : // it and changes the EvpnMacState to point to the updated value
904 : // of EvpnSegment.
905 173 : if (route->is_onlist())
906 0 : continue;
907 :
908 : EvpnMacState *mac_state =
909 173 : dynamic_cast<EvpnMacState *>(route->GetState(table, listener_id));
910 174 : assert(mac_state);
911 174 : bool modified = mac_state->ProcessMacRouteAliasing();
912 171 : if (route->HasPaths()) {
913 129 : if (!mac_state->segment()) {
914 7 : route->ClearState(table, listener_id);
915 9 : delete mac_state;
916 : }
917 130 : if (modified) {
918 32 : table_partition_->Notify(route);
919 : }
920 : } else {
921 42 : route->ClearState(table, listener_id);
922 43 : table_partition_->Delete(route);
923 43 : delete mac_state;
924 : }
925 : }
926 :
927 156 : mac_update_list_.clear();
928 156 : evpn_manager_->RetryDelete();
929 156 : return true;
930 : }
931 :
932 1428 : bool EvpnManagerPartition::GetForestNodeAddress(ErmVpnRoute *rt,
933 : Ip4Address *address) const {
934 1428 : if (!evpn_manager_->ermvpn_table()->tree_manager())
935 0 : return false;
936 : uint32_t label;
937 1428 : vector<string> te;
938 1428 : return evpn_manager_->ermvpn_table()->tree_manager()->GetForestNodePMSI(
939 1428 : rt, &label, address, &te);
940 1428 : }
941 :
942 0 : EvpnStatePtr EvpnManagerPartition::GetState(const SG &sg) const {
943 0 : EvpnState::StatesMap::const_iterator iter = states_.find(sg);
944 0 : return iter != states_.end() ? iter->second : NULL;
945 : }
946 :
947 5095 : EvpnStatePtr EvpnManagerPartition::GetState(const SG &sg) {
948 5095 : EvpnState::StatesMap::iterator iter = states_.find(sg);
949 5095 : return iter != states_.end() ? iter->second : NULL;
950 : }
951 :
952 642 : EvpnStatePtr EvpnManagerPartition::GetState(EvpnRoute *rt) {
953 642 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
954 1284 : rt->GetPrefix().group());
955 1284 : return GetState(sg);
956 : }
957 :
958 2698 : EvpnStatePtr EvpnManagerPartition::CreateState(const SG &sg) {
959 2698 : EvpnStatePtr state(new EvpnState(sg, &states_, evpn_manager_));
960 2698 : assert(states_.insert(make_pair(sg, state.get())).second);
961 2698 : EVPN_TRACE(EvpnStateCreate, sg.source.to_string(), sg.group.to_string());
962 2698 : return state;
963 0 : }
964 :
965 4453 : EvpnStatePtr EvpnManagerPartition::LocateState(const SG &sg) {
966 4453 : EvpnStatePtr evpn_state = GetState(sg);
967 4453 : if (evpn_state)
968 1755 : return evpn_state;
969 2698 : evpn_state = CreateState(sg);
970 2698 : assert(evpn_state);
971 2698 : return evpn_state;
972 0 : }
973 :
974 1764 : EvpnStatePtr EvpnManagerPartition::LocateState(EvpnRoute *rt) {
975 1764 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
976 3528 : rt->GetPrefix().group());
977 3528 : return LocateState(sg);
978 : }
979 :
980 : //
981 : // Disable processing of the update list.
982 : // For testing only.
983 : //
984 12 : void EvpnManagerPartition::DisableMacUpdateProcessing() {
985 12 : mac_update_trigger_->set_disable();
986 12 : }
987 :
988 : //
989 : // Enable processing of the update list.
990 : // For testing only.
991 : //
992 12 : void EvpnManagerPartition::EnableMacUpdateProcessing() {
993 12 : mac_update_trigger_->set_enable();
994 12 : }
995 :
996 : //
997 : // Return true if the EvpnManagerPartition is empty i.e. it has no local
998 : // or remote EvpnMcastNodes and no MAC routes that need to be updated.
999 : //
1000 176074 : bool EvpnManagerPartition::empty() const {
1001 176074 : if (!local_mcast_node_list_.empty())
1002 4650 : return false;
1003 171424 : if (!remote_mcast_node_list_.empty())
1004 580 : return false;
1005 170844 : if (!mac_update_list_.empty())
1006 0 : return false;
1007 170844 : assert(leaf_node_list_.empty());
1008 170844 : assert(replicator_node_list_.empty());
1009 170844 : assert(regular_node_list_.empty());
1010 170844 : assert(ir_client_node_list_.empty());
1011 170844 : return true;
1012 : }
1013 :
1014 : //
1015 : // Return the BgpServer for the EvpnManagerPartition.
1016 : //
1017 45487 : BgpServer *EvpnManagerPartition::server() {
1018 45487 : return evpn_manager_->server();
1019 : }
1020 :
1021 : //
1022 : // Return the EvpnTable for the EvpnManagerPartition.
1023 : //
1024 27052 : const EvpnTable *EvpnManagerPartition::table() const {
1025 27052 : return evpn_manager_->table();
1026 : }
1027 :
1028 : //
1029 : // Constructor for EvpnManager.
1030 : //
1031 42907 : EvpnManager::EvpnManager(EvpnTable *table)
1032 42907 : : table_(table),
1033 42907 : listener_id_(DBTable::kInvalidId),
1034 85813 : segment_delete_trigger_(new TaskTrigger(
1035 : boost::bind(&EvpnManager::ProcessSegmentDeleteSet, this),
1036 85813 : TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
1037 85814 : segment_update_trigger_(new TaskTrigger(
1038 : boost::bind(&EvpnManager::ProcessSegmentUpdateSet, this),
1039 85813 : TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
1040 85814 : table_delete_ref_(this, table->deleter()) {
1041 42907 : deleter_.reset(new DeleteActor(this));
1042 42907 : db_states_count_ = 0;
1043 42907 : }
1044 :
1045 : //
1046 : // Destructor for EvpnManager.
1047 : //
1048 85662 : EvpnManager::~EvpnManager() {
1049 42907 : assert(segment_map_.empty());
1050 42907 : assert(segment_delete_set_.empty());
1051 42907 : assert(segment_update_set_.empty());
1052 85662 : }
1053 :
1054 : //
1055 : // Initialize the EvpnManager. We allocate the EvpnManagerPartitions
1056 : // and register a DBListener for the EvpnTable.
1057 : //
1058 42755 : void EvpnManager::Initialize() {
1059 42755 : AllocPartitions();
1060 42753 : listener_id_ = table_->Register(
1061 : boost::bind(&EvpnManager::RouteListener, this, _1, _2),
1062 : "EvpnManager");
1063 42754 : ermvpn_table_ = dynamic_cast<ErmVpnTable *>(
1064 42753 : table_->routing_instance()->GetTable(Address::ERMVPN));
1065 42754 : if (ermvpn_table_)
1066 42751 : ermvpn_listener_id_ = ermvpn_table_->Register(
1067 : boost::bind(&EvpnManager::ErmVpnRouteListener, this, _1, _2),
1068 : "EvpnManager");
1069 42758 : }
1070 :
1071 : //
1072 : // Terminate the EvpnManager. We free the EvpnManagerPartitions
1073 : // and unregister from the EvpnTable.
1074 : //
1075 42755 : void EvpnManager::Terminate() {
1076 42755 : CHECK_CONCURRENCY("bgp::Config");
1077 42755 : table_->Unregister(listener_id_);
1078 42755 : listener_id_ = DBTable::kInvalidId;
1079 42755 : if (ermvpn_listener_id_ != DBTable::kInvalidId) {
1080 42755 : ermvpn_table_->Unregister(ermvpn_listener_id_);
1081 42755 : ermvpn_listener_id_ = DBTable::kInvalidId;
1082 : }
1083 42755 : FreePartitions();
1084 42755 : }
1085 :
1086 : //
1087 : // Allocate the EvpnManagerPartitions.
1088 : //
1089 42754 : void EvpnManager::AllocPartitions() {
1090 213082 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1091 170330 : partitions_.push_back(new EvpnManagerPartition(this, part_id));
1092 : }
1093 42752 : }
1094 :
1095 : //
1096 : // Free the EvpnManagerPartitions.
1097 : //
1098 42755 : void EvpnManager::FreePartitions() {
1099 42755 : STLDeleteValues(&partitions_);
1100 42755 : }
1101 :
1102 : //
1103 : // Disable processing of the update lists in all partitions.
1104 : // For testing only.
1105 : //
1106 3 : void EvpnManager::DisableMacUpdateProcessing() {
1107 15 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1108 12 : partitions_[part_id]->DisableMacUpdateProcessing();
1109 : }
1110 3 : }
1111 :
1112 : //
1113 : // Enable processing of the update lists in all partitions.
1114 : // For testing only.
1115 : //
1116 3 : void EvpnManager::EnableMacUpdateProcessing() {
1117 15 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1118 12 : partitions_[part_id]->EnableMacUpdateProcessing();
1119 : }
1120 3 : }
1121 :
1122 : //
1123 : // Get the EvpnManagerPartition for the given partition id.
1124 : //
1125 116939 : EvpnManagerPartition *EvpnManager::GetPartition(size_t part_id) {
1126 116939 : return partitions_[part_id];
1127 : }
1128 :
1129 : //
1130 : // Get the DBTablePartition for the EvpnTable for given partition id.
1131 : //
1132 242054 : DBTablePartition *EvpnManager::GetTablePartition(size_t part_id) {
1133 242054 : return static_cast<DBTablePartition *>(table_->GetTablePartition(part_id));
1134 : }
1135 :
1136 : //
1137 : // Construct export state for the given EvpnRoute. Note that the route
1138 : // only needs to be exported to the IPeer from which it was learnt.
1139 : //
1140 7238 : UpdateInfo *EvpnManager::GetUpdateInfo(EvpnRoute *route) {
1141 7238 : CHECK_CONCURRENCY("db::DBTable");
1142 :
1143 7238 : DBState *dbstate = route->GetState(table_, listener_id_);
1144 : EvpnLocalMcastNode *local_node =
1145 7238 : dynamic_cast<EvpnLocalMcastNode *>(dbstate);
1146 :
1147 7238 : if (!local_node)
1148 0 : return NULL;
1149 :
1150 7238 : return local_node->GetUpdateInfo(route);
1151 : }
1152 :
1153 88394 : BgpServer *EvpnManager::server() {
1154 88394 : return table_->server();
1155 : }
1156 :
1157 : //
1158 : // Find or create the EvpnSegment for the given EthernetSegmentId.
1159 : //
1160 76 : EvpnSegment *EvpnManager::LocateSegment(const EthernetSegmentId &esi) {
1161 76 : assert(!esi.IsZero());
1162 76 : tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
1163 76 : SegmentMap::iterator loc = segment_map_.find(esi);
1164 76 : EvpnSegment *segment = (loc != segment_map_.end()) ? loc->second : NULL;
1165 76 : if (!segment) {
1166 34 : segment = new EvpnSegment(this, esi);
1167 34 : segment_map_.insert(esi, segment);
1168 : }
1169 76 : return segment;
1170 76 : }
1171 :
1172 : //
1173 : // Find the EvpnSegment for the given EthernetSegmentId.
1174 : //
1175 77 : EvpnSegment *EvpnManager::FindSegment(const EthernetSegmentId &esi) {
1176 77 : assert(!esi.IsZero());
1177 77 : tbb::spin_rw_mutex::scoped_lock read_lock(segment_rw_mutex_, false);
1178 77 : SegmentMap::iterator loc = segment_map_.find(esi);
1179 154 : return (loc != segment_map_.end()) ? loc->second : NULL;
1180 77 : }
1181 :
1182 : //
1183 : // Trigger deletion of the given EvpnSegment.
1184 : // The EvpnSegment is added to a set of EvpnSegments that can potentially
1185 : // be deleted. This method can be invoked from multiple db::DBTable tasks
1186 : // in parallel when a MAC routes are removed from the dependency list in an
1187 : // EvpnSegment. Hence we ensure exclusive access using a write lock.
1188 : //
1189 : // The list is processed from the context of bgp::EvpnSegment task which is
1190 : // mutually exclusive with db::DBTable task.
1191 : //
1192 60 : void EvpnManager::TriggerSegmentDelete(EvpnSegment *segment) {
1193 60 : CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
1194 :
1195 60 : tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
1196 60 : segment_delete_set_.insert(segment);
1197 60 : segment_delete_trigger_->Set();
1198 60 : }
1199 :
1200 : //
1201 : // Process the set of EvpnSegments that can potentially be deleted.
1202 : // Remove the EvpnSegment from the map and destroy if it's fine to
1203 : // to delete the EvpnSegment.
1204 : //
1205 50 : bool EvpnManager::ProcessSegmentDeleteSet() {
1206 50 : CHECK_CONCURRENCY("bgp::EvpnSegment");
1207 :
1208 152 : BOOST_FOREACH(EvpnSegment *segment, segment_delete_set_) {
1209 51 : if (segment->MayDelete()) {
1210 34 : segment_update_set_.erase(segment);
1211 34 : EthernetSegmentId esi = segment->esi();
1212 34 : segment_map_.erase(esi);
1213 : }
1214 : }
1215 50 : segment_delete_set_.clear();
1216 50 : RetryDelete();
1217 50 : return true;
1218 : }
1219 :
1220 : //
1221 : // Disable processing of the delete list.
1222 : // For testing only.
1223 : //
1224 0 : void EvpnManager::DisableSegmentDeleteProcessing() {
1225 0 : segment_delete_trigger_->set_disable();
1226 0 : }
1227 :
1228 : //
1229 : // Enable processing of the delete list.
1230 : // For testing only.
1231 : //
1232 0 : void EvpnManager::EnableSegmentDeleteProcessing() {
1233 0 : segment_delete_trigger_->set_enable();
1234 0 : }
1235 :
1236 : //
1237 : // Trigger update of the given EvpnSegment.
1238 : // The EvpnSegment is added to a set of EvpnSegments for which updates
1239 : // need triggered. This method is called in the context of db::DBTable
1240 : // task and a task instance of 0 since all AutoDisocvery routes always
1241 : // get sharded to partition 0.
1242 : //
1243 : // The set is processed in the context of bgp::EvpnSegment task, which
1244 : // is mutually exclusive with db::DBTable task.
1245 : //
1246 63 : void EvpnManager::TriggerSegmentUpdate(EvpnSegment *segment) {
1247 63 : CHECK_CONCURRENCY("db::DBTable");
1248 :
1249 63 : segment_update_set_.insert(segment);
1250 63 : segment_update_trigger_->Set();
1251 63 : }
1252 :
1253 : //
1254 : // Process the set of EvpnSegments that need to be updated.
1255 : //
1256 : // Go through each EvpnSegment and update it's PE list. Trigger updates
1257 : // of all it's dependent MAC routes if there's a change in the PE list.
1258 : //
1259 63 : bool EvpnManager::ProcessSegmentUpdateSet() {
1260 63 : CHECK_CONCURRENCY("bgp::EvpnSegment");
1261 :
1262 189 : BOOST_FOREACH(EvpnSegment *segment, segment_update_set_) {
1263 63 : EvpnRoute *esi_ad_route = segment->esi_ad_route();
1264 63 : bool changed = segment->UpdatePeList();
1265 63 : if (changed)
1266 61 : segment->TriggerMacRouteUpdate();
1267 63 : if (!esi_ad_route->IsValid()) {
1268 22 : segment->clear_esi_ad_route();
1269 22 : esi_ad_route->ClearState(table_, listener_id_);
1270 22 : TriggerSegmentDelete(segment);
1271 : }
1272 : }
1273 63 : segment_update_set_.clear();
1274 63 : RetryDelete();
1275 63 : return true;
1276 : }
1277 :
1278 : //
1279 : // Disable processing of the update list.
1280 : // For testing only.
1281 : //
1282 2 : void EvpnManager::DisableSegmentUpdateProcessing() {
1283 2 : segment_update_trigger_->set_disable();
1284 2 : }
1285 :
1286 : //
1287 : // Enable processing of the update list.
1288 : // For testing only.
1289 : //
1290 2 : void EvpnManager::EnableSegmentUpdateProcessing() {
1291 2 : segment_update_trigger_->set_enable();
1292 2 : }
1293 :
1294 : //
1295 : // DBListener callback handler for AutoDisocvery routes in the EvpnTable.
1296 : //
1297 63 : void EvpnManager::AutoDiscoveryRouteListener(EvpnRoute *route) {
1298 63 : CHECK_CONCURRENCY("db::DBTable");
1299 :
1300 63 : DBState *dbstate = route->GetState(table_, listener_id_);
1301 63 : if (!dbstate) {
1302 : // We have no previous DBState for this route.
1303 : // Bail if the route is not valid.
1304 22 : if (!route->IsValid())
1305 0 : return;
1306 :
1307 : // Locate the EvpnSegment and associate it with the route.
1308 : // Trigger an update of EvpnSegment so that it's PE list
1309 : // gets updated.
1310 22 : EvpnSegment *segment = LocateSegment(route->GetPrefix().esi());
1311 22 : segment->set_esi_ad_route(route);
1312 22 : route->SetState(table_, listener_id_, segment);
1313 22 : TriggerSegmentUpdate(segment);
1314 : } else {
1315 : // Trigger an update of EvpnSegment so that it's PE list
1316 : // gets updated.
1317 41 : EvpnSegment *segment = dynamic_cast<EvpnSegment *>(dbstate);
1318 41 : assert(segment);
1319 41 : TriggerSegmentUpdate(segment);
1320 : }
1321 : }
1322 :
1323 : //
1324 : // DBListener callback handler for MacAdvertisement routes in the EvpnTable.
1325 : //
1326 9317 : void EvpnManager::MacAdvertisementRouteListener(
1327 : EvpnManagerPartition *partition, EvpnRoute *route) {
1328 9317 : CHECK_CONCURRENCY("db::DBTable");
1329 :
1330 9317 : DBState *dbstate = route->GetState(table_, listener_id_);
1331 9318 : if (!dbstate) {
1332 : // We have no previous DBState for this route.
1333 : // Bail if the route is not valid or if it doesn't have an ESI.
1334 9230 : if (!route->IsValid())
1335 3204 : return;
1336 6025 : const BgpPath *path = route->BestPath();
1337 6025 : if (path->GetAttr()->esi().IsZero())
1338 5973 : return;
1339 :
1340 : // Create a new EvpnMacState and associate it with the route.
1341 52 : EvpnMacState *mac_state = new EvpnMacState(this, route);
1342 52 : route->SetState(table_, listener_id_, mac_state);
1343 :
1344 : // Locate the EvpnSegment and add the MAC route as a dependent
1345 : // of the EvpnSegment.
1346 52 : EvpnSegment *segment = LocateSegment(path->GetAttr()->esi());
1347 52 : mac_state->set_segment(segment);
1348 52 : segment->AddMacRoute(partition->part_id(), route);
1349 52 : partition->TriggerMacRouteUpdate(route);
1350 : } else {
1351 88 : EvpnMacState *mac_state = dynamic_cast<EvpnMacState *>(dbstate);
1352 88 : assert(mac_state);
1353 88 : EvpnSegment *segment = mac_state->segment();
1354 :
1355 : // Handle change in the ESI and update the dependency on the
1356 : // EvpnSegment as appropriate.
1357 : // Note that the DBState on the EvpnRoute doesn't get cleared
1358 : // here. That only happens when aliasing for the route is being
1359 : // processed.
1360 88 : const BgpPath *path = route->BestPath();
1361 89 : if (!route->IsValid() || (path && path->GetAttr()->esi().IsZero())) {
1362 54 : if (segment) {
1363 53 : segment->DeleteMacRoute(partition->part_id(), route);
1364 53 : mac_state->clear_segment();
1365 : }
1366 34 : } else if (!segment && !path->GetAttr()->esi().IsZero()) {
1367 1 : segment = LocateSegment(path->GetAttr()->esi());
1368 1 : mac_state->set_segment(segment);
1369 1 : segment->AddMacRoute(partition->part_id(), route);
1370 33 : } else if (segment && segment->esi() != path->GetAttr()->esi()) {
1371 1 : segment->DeleteMacRoute(partition->part_id(), route);
1372 1 : mac_state->clear_segment();
1373 1 : segment = LocateSegment(path->GetAttr()->esi());
1374 1 : mac_state->set_segment(segment);
1375 1 : segment->AddMacRoute(partition->part_id(), route);
1376 : }
1377 88 : partition->TriggerMacRouteUpdate(route);
1378 : }
1379 : }
1380 :
1381 : //
1382 : // DBListener callback handler for InclusiveMulticast routes in the EvpnTable.
1383 : //
1384 46288 : void EvpnManager::InclusiveMulticastRouteListener(
1385 : EvpnManagerPartition *partition, EvpnRoute *route) {
1386 46288 : CHECK_CONCURRENCY("db::DBTable");
1387 :
1388 46288 : DBState *dbstate = route->GetState(table_, listener_id_);
1389 46288 : if (!dbstate) {
1390 : // We have no previous DBState for this route.
1391 : // Bail if the route is not valid.
1392 5099 : if (!route->IsValid())
1393 0 : return;
1394 :
1395 : // Create a new EvpnMcastNode and associate it with the route.
1396 : EvpnMcastNode *node;
1397 5099 : if (route->GetPrefix().type() == EvpnPrefix::MacAdvertisementRoute) {
1398 2150 : node = new EvpnLocalMcastNode(partition, route);
1399 : } else {
1400 2949 : node = new EvpnRemoteMcastNode(partition, route);
1401 : }
1402 5099 : partition->AddMcastNode(node, route);
1403 5099 : route->SetState(table_, listener_id_, node);
1404 : } else {
1405 41189 : EvpnMcastNode *node = dynamic_cast<EvpnMcastNode *>(dbstate);
1406 41189 : assert(node);
1407 :
1408 41189 : if (!route->IsValid()) {
1409 : // Delete the EvpnMcastNode associated with the route.
1410 5099 : route->ClearState(table_, listener_id_);
1411 5099 : partition->DeleteMcastNode(node, route);
1412 5099 : delete node;
1413 36090 : } else if (node->UpdateAttributes(route)) {
1414 : // Update the EvpnMcastNode associated with the route.
1415 18698 : partition->UpdateMcastNode(node, route);
1416 : }
1417 : }
1418 : }
1419 :
1420 : //
1421 : // DBListener callback handler for SelectiveMulticast routes in the EvpnTable.
1422 : //
1423 2406 : void EvpnManager::SelectiveMulticastRouteListener(
1424 : EvpnManagerPartition *partition, EvpnRoute *route) {
1425 :
1426 2406 : CHECK_CONCURRENCY("db::DBTable");
1427 2406 : EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
1428 2406 : route->GetState(table_, listener_id_));
1429 2406 : bool is_usable = route->IsUsable();
1430 2406 : bool is_deleted = route->IsDeleted();
1431 2406 : bool checkErmvpnRoute = false;
1432 2406 : if (route->BestPath()) {
1433 1764 : checkErmvpnRoute = route->BestPath()->GetFlags() &
1434 : BgpPath::CheckGlobalErmVpnRoute;
1435 : }
1436 2406 : if ((!is_usable && !checkErmvpnRoute) || is_deleted) {
1437 642 : if (!dbstate)
1438 0 : return;
1439 :
1440 642 : EvpnStatePtr evpn_state = partition->GetState(route);
1441 642 : if (evpn_state)
1442 642 : evpn_state->smet_routes().erase(route);
1443 642 : EVPN_RT_LOG(route, "Processed Smet route deletion");
1444 642 : ClearDBState(route);
1445 642 : partition->NotifyForestNode(route, ermvpn_table());
1446 642 : partition->DeleteMcastNode(dbstate, route);
1447 642 : delete dbstate;
1448 642 : return;
1449 642 : }
1450 :
1451 1764 : EvpnStatePtr evpn_state = partition->LocateState(route);
1452 1764 : assert(evpn_state);
1453 1764 : evpn_state->smet_routes().insert(route);
1454 1764 : BgpPath *path = const_cast<BgpPath *>(route->BestPath());
1455 1764 : if (path && path->CheckErmVpn()) {
1456 1428 : ErmVpnRoute *global_rt = evpn_state->global_ermvpn_tree_rt();
1457 1428 : Ip4Address address;
1458 1428 : bool nh_found = partition->GetForestNodeAddress(global_rt, &address);
1459 1428 : if (nh_found) {
1460 625 : BgpAttrPtr attr = path->GetAttr();
1461 : BgpAttrPtr new_attr = partition->server()->attr_db()->
1462 625 : ReplaceNexthopAndLocate(attr.get(), address);
1463 625 : path->SetAttr(new_attr, attr);
1464 625 : path->ResetCheckErmVpn();
1465 625 : partition->NotifyForestNode(route, ermvpn_table());
1466 625 : }
1467 : }
1468 :
1469 1764 : if (!dbstate) {
1470 : // Create a new DBState and associate it with the route.
1471 : EvpnMcastNode *node;
1472 642 : if (route->GetPrefix().ip_address() ==
1473 1284 : Ip4Address(table_->server()->bgp_identifier())) {
1474 618 : node = new EvpnLocalMcastNode(partition, route, evpn_state);
1475 : } else {
1476 24 : node = new EvpnRemoteMcastNode(partition, route, evpn_state);
1477 : }
1478 642 : SetDBState(route, node);
1479 642 : partition->AddMcastNode(node, route);
1480 642 : EVPN_RT_LOG(route, "Processed Smet route creation");
1481 : }
1482 1764 : }
1483 :
1484 1267 : void EvpnManagerPartition::NotifyForestNode(EvpnRoute *route,
1485 : ErmVpnTable *table) {
1486 1267 : const Ip4Address &source = route->GetPrefix().source().to_v4();
1487 1267 : const Ip4Address &group = route->GetPrefix().group().to_v4();
1488 1267 : if (table->tree_manager())
1489 1267 : table->tree_manager()->NotifyForestNode(part_id_, source, group);
1490 1267 : }
1491 :
1492 : // Set DB State and update count.
1493 642 : void EvpnManager::SetDBState(EvpnRoute *route, EvpnMcastNode *dbstate) {
1494 642 : route->SetState(table_, listener_id_, dbstate);
1495 642 : db_states_count_++;
1496 642 : }
1497 :
1498 : // Create DB State and update count. If there is no DB State associated in the
1499 : // table, resume table deletion if the deletion was pending.
1500 642 : void EvpnManager::ClearDBState(EvpnRoute *route) {
1501 642 : route->ClearState(table_, listener_id_);
1502 642 : assert(db_states_count_);
1503 642 : db_states_count_--;
1504 :
1505 : // Retry deletion now as there is no more attached db state in the table.
1506 642 : if (!db_states_count_ && deleter_->IsDeleted())
1507 0 : deleter_->RetryDelete();
1508 642 : }
1509 :
1510 : // Check whether an ErmVpnRoute is locally originated GlobalTreeRoute.
1511 10215 : bool EvpnManager::IsUsableGlobalTreeRootRoute(
1512 : ErmVpnRoute *ermvpn_route) const {
1513 10215 : if (!ermvpn_route || !ermvpn_route->IsUsable())
1514 3510 : return false;
1515 6705 : if (!ermvpn_table()->tree_manager())
1516 0 : return false;
1517 6705 : if (ermvpn_table()->tree_manager()->begin() ==
1518 13410 : ermvpn_table()->tree_manager()->end())
1519 321 : return false;
1520 6384 : ErmVpnRoute *global_rt = ermvpn_table()->tree_manager()->
1521 6384 : GetGlobalTreeRootRoute(
1522 6384 : ermvpn_route->GetPrefix().source(),
1523 6384 : ermvpn_route->GetPrefix().group());
1524 6384 : return (global_rt && global_rt == ermvpn_route);
1525 : }
1526 :
1527 : // ErmVpnTable route listener callback function.
1528 : //
1529 : // Process changes (create/update/delete) to GlobalErmVpnRoute in vrf.ermvpn.0
1530 24803 : void EvpnManager::ErmVpnRouteListener(DBTablePartBase *tpart,
1531 : DBEntryBase *db_entry) {
1532 24803 : CHECK_CONCURRENCY("db::DBTable");
1533 :
1534 24803 : ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(db_entry);
1535 24803 : assert(ermvpn_route);
1536 :
1537 : // We only care about global tree routes for evpn stitching.
1538 24803 : if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute) {
1539 20653 : return;
1540 : }
1541 :
1542 10215 : EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
1543 10215 : ermvpn_route->GetState(ermvpn_table(), ermvpn_listener_id()));
1544 :
1545 : // Handle GlobalTreeRoute route deletion.
1546 10215 : if (!IsUsableGlobalTreeRootRoute(ermvpn_route)) {
1547 : // Ignore if there is no DB State associated with route.
1548 6065 : if (!dbstate)
1549 3376 : return;
1550 2689 : EvpnStatePtr evpn_state = dbstate->state();
1551 2689 : evpn_state->set_global_ermvpn_tree_rt(NULL);
1552 :
1553 : // Notify all received smet routes for PMSI re-computation.
1554 : // Since usable global ermvpn is no longer available, any advertised
1555 : // smet routes must now be withdrawn.
1556 3041 : BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
1557 176 : BgpPath *path = const_cast<BgpPath *>(route->BestPath());
1558 176 : if (path && (path->GetPathId() == 0)) {
1559 176 : path->SetCheckErmVpn();
1560 : }
1561 176 : route->Notify();
1562 : }
1563 2689 : ermvpn_route->ClearState(ermvpn_table(), ermvpn_listener_id());
1564 2689 : EVPN_ERMVPN_RT_LOG(ermvpn_route,
1565 : "Processed EVPN GlobalErmVpnRoute deletion");
1566 2689 : delete dbstate;
1567 2689 : return;
1568 2689 : }
1569 :
1570 : // Set DB State in the route if not already done so before.
1571 4150 : EvpnManagerPartition *partition = GetPartition(tpart->index());
1572 4150 : EvpnStatePtr evpn_state;
1573 4150 : if (!dbstate) {
1574 2689 : EvpnState::SG sg(ermvpn_route);
1575 2689 : evpn_state = partition->LocateState(sg);
1576 2689 : dbstate = new EvpnLocalMcastNode(partition, NULL, evpn_state);
1577 2689 : ermvpn_route->SetState(ermvpn_table(), ermvpn_listener_id(), dbstate);
1578 : } else {
1579 1461 : evpn_state = dbstate->state();
1580 : }
1581 :
1582 : // Note down current usable ermvpn route for stitching to evpn.
1583 4150 : dbstate->state()->set_global_ermvpn_tree_rt(ermvpn_route);
1584 :
1585 : // Notify all originated Type6 routes.
1586 5986 : BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
1587 918 : route->Notify();
1588 : }
1589 4150 : EVPN_ERMVPN_RT_LOG(ermvpn_route,
1590 : "Processed EVPN GlobalErmVpnRoute creation");
1591 4150 : }
1592 :
1593 : //
1594 : // DBListener callback handler for the EvpnTable.
1595 : //
1596 112585 : void EvpnManager::RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry) {
1597 112585 : CHECK_CONCURRENCY("db::DBTable");
1598 :
1599 112548 : EvpnManagerPartition *partition = GetPartition(tpart->index());
1600 112555 : EvpnRoute *route = dynamic_cast<EvpnRoute *>(db_entry);
1601 112555 : assert(route);
1602 :
1603 112555 : switch (route->GetPrefix().type()) {
1604 63 : case EvpnPrefix::AutoDiscoveryRoute:
1605 63 : AutoDiscoveryRouteListener(route);
1606 63 : break;
1607 31539 : case EvpnPrefix::MacAdvertisementRoute:
1608 31539 : if (route->GetPrefix().mac_addr().IsBroadcast()) {
1609 22222 : InclusiveMulticastRouteListener(partition, route);
1610 : } else {
1611 9317 : MacAdvertisementRouteListener(partition, route);
1612 : }
1613 31540 : break;
1614 24066 : case EvpnPrefix::InclusiveMulticastRoute:
1615 24066 : InclusiveMulticastRouteListener(partition, route);
1616 24066 : break;
1617 2406 : case EvpnPrefix::SelectiveMulticastRoute:
1618 2406 : SelectiveMulticastRouteListener(partition, route);
1619 2406 : break;
1620 54475 : default:
1621 54475 : break;
1622 : }
1623 112550 : }
1624 :
1625 : //
1626 : // Fill information for introspect command.
1627 : // Note that all IM routes are always in partition 0.
1628 : //
1629 190 : void EvpnManager::FillShowInfo(ShowEvpnTable *sevt) const {
1630 190 : CHECK_CONCURRENCY("db::DBTable");
1631 :
1632 190 : vector<string> regular_nves;
1633 190 : vector<string> ar_replicators;
1634 190 : vector<ShowEvpnMcastLeaf> ar_leafs;
1635 : EvpnManagerPartition::EvpnMcastNodeList::const_iterator it =
1636 190 : partitions_[0]->remote_mcast_node_list()->begin();
1637 190 : for (; it != partitions_[0]->remote_mcast_node_list()->end(); it++) {
1638 0 : BOOST_FOREACH(const EvpnMcastNode *node, it->second) {
1639 0 : if (node->assisted_replication_leaf()) {
1640 0 : ShowEvpnMcastLeaf leaf;
1641 0 : leaf.set_address(node->address().to_string());
1642 0 : leaf.set_replicator(node->replicator_address().to_string());
1643 0 : ar_leafs.push_back(leaf);
1644 0 : } else if (node->assisted_replication_supported()) {
1645 0 : ar_replicators.push_back(node->address().to_string());
1646 0 : } else if (node->edge_replication_not_supported()) {
1647 0 : regular_nves.push_back(node->address().to_string());
1648 : }
1649 : }
1650 : }
1651 :
1652 190 : sort(regular_nves.begin(), regular_nves.end());
1653 190 : sort(ar_replicators.begin(), ar_replicators.end());
1654 190 : sort(ar_leafs.begin(), ar_leafs.end());
1655 190 : sevt->set_regular_nves(regular_nves);
1656 190 : sevt->set_ar_replicators(ar_replicators);
1657 190 : sevt->set_ar_leafs(ar_leafs);
1658 190 : }
1659 :
1660 : //
1661 : // Check if the EvpnManager can be deleted. This can happen only if all the
1662 : // EvpnManagerPartitions are empty.
1663 : //
1664 42907 : bool EvpnManager::MayDelete() const {
1665 42907 : CHECK_CONCURRENCY("bgp::Config");
1666 :
1667 42907 : if (!segment_map_.empty())
1668 0 : return false;
1669 :
1670 42907 : if (!segment_update_set_.empty())
1671 0 : return false;
1672 42907 : if (segment_update_trigger_->IsSet())
1673 0 : return false;
1674 :
1675 42907 : if (!segment_delete_set_.empty())
1676 0 : return false;
1677 42907 : if (segment_delete_trigger_->IsSet())
1678 0 : return false;
1679 :
1680 383573 : BOOST_FOREACH(const EvpnManagerPartition *partition, partitions_) {
1681 170333 : if (!partition->empty())
1682 0 : return false;
1683 170333 : if (!partition->states().empty())
1684 0 : return false;
1685 : }
1686 42907 : if (db_states_count_)
1687 0 : return false;
1688 42907 : return true;
1689 : }
1690 :
1691 : //
1692 : // Initiate shutdown for the EvpnManager.
1693 : //
1694 42907 : void EvpnManager::Shutdown() {
1695 42907 : CHECK_CONCURRENCY("bgp::Config");
1696 42907 : }
1697 :
1698 : //
1699 : // Trigger deletion of the EvpnManager and propagate the delete to any
1700 : // dependents.
1701 : //
1702 42907 : void EvpnManager::ManagedDelete() {
1703 42907 : deleter_->Delete();
1704 42907 : }
1705 :
1706 : //
1707 : // Attempt to enqueue a delete for the EvpnManager.
1708 : //
1709 780 : void EvpnManager::RetryDelete() {
1710 780 : if (!deleter()->IsDeleted())
1711 780 : return;
1712 0 : deleter()->RetryDelete();
1713 : }
1714 :
1715 : //
1716 : // Return the LifetimeActor for the EvpnManager.
1717 : //
1718 5832 : LifetimeActor *EvpnManager::deleter() {
1719 5832 : return deleter_.get();
1720 : }
1721 :
1722 1470 : EvpnState::SG::SG(const Ip4Address &source, const Ip4Address &group) :
1723 1470 : source(IpAddress(source)), group(IpAddress(group)) {
1724 1470 : }
1725 :
1726 2689 : EvpnState::SG::SG(const ErmVpnRoute *route) :
1727 2689 : source(route->GetPrefix().source()),
1728 2689 : group(route->GetPrefix().group()) {
1729 2689 : }
1730 :
1731 0 : EvpnState::SG::SG(const EvpnRoute *route) :
1732 0 : source(route->GetPrefix().source()), group(route->GetPrefix().group()) {
1733 0 : }
1734 :
1735 41570 : EvpnState::SG::SG(const IpAddress &source, const IpAddress &group) :
1736 41570 : source(source), group(group) {
1737 41570 : }
1738 :
1739 308767 : bool EvpnState::SG::operator<(const SG &other) const {
1740 308767 : if (source < other.source)
1741 45 : return true;
1742 308722 : if (source > other.source)
1743 34 : return false;
1744 308688 : if (group < other.group)
1745 9297 : return true;
1746 299391 : if (group > other.group)
1747 8761 : return false;
1748 290630 : return false;
1749 : }
1750 :
1751 2698 : const EvpnState::SG &EvpnState::sg() const {
1752 2698 : return sg_;
1753 : }
1754 :
1755 6839 : void EvpnState::set_global_ermvpn_tree_rt(ErmVpnRoute *global_ermvpn_tree_rt) {
1756 6839 : global_ermvpn_tree_rt_ = global_ermvpn_tree_rt;
1757 6839 : }
1758 :
1759 1428 : ErmVpnRoute *EvpnState::global_ermvpn_tree_rt() {
1760 1428 : return global_ermvpn_tree_rt_;
1761 : }
1762 :
1763 0 : const ErmVpnRoute *EvpnState::global_ermvpn_tree_rt() const {
1764 0 : return global_ermvpn_tree_rt_;
1765 : }
|