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 0 : EvpnState::EvpnState(const SG &sg, StatesMap *states, EvpnManager *manager) :
35 0 : sg_(sg), global_ermvpn_tree_rt_(NULL), states_(states),
36 0 : manager_(manager) {
37 0 : refcount_ = 0;
38 0 : }
39 :
40 0 : EvpnState::~EvpnState() {
41 0 : assert(!global_ermvpn_tree_rt_);
42 0 : EVPN_TRACE(EvpnStateCreate, sg_.source.to_string(), sg_.group.to_string());
43 0 : }
44 :
45 0 : const ErmVpnTable *EvpnState::table() const {
46 0 : return manager_ ? manager_->ermvpn_table() : NULL;
47 : }
48 :
49 : class EvpnManager::DeleteActor : public LifetimeActor {
50 : public:
51 0 : explicit DeleteActor(EvpnManager *evpn_manager)
52 0 : : LifetimeActor(evpn_manager->server()->lifetime_manager()),
53 0 : evpn_manager_(evpn_manager) {
54 0 : }
55 0 : virtual ~DeleteActor() {
56 0 : }
57 :
58 0 : virtual bool MayDelete() const {
59 0 : CHECK_CONCURRENCY("bgp::Config");
60 0 : return evpn_manager_->MayDelete();
61 : }
62 :
63 0 : virtual void Shutdown() {
64 0 : evpn_manager_->Shutdown();
65 0 : }
66 :
67 0 : virtual void Destroy() {
68 0 : evpn_manager_->table_->DestroyEvpnManager();
69 0 : }
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 0 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
80 0 : EvpnRoute *route, uint8_t type)
81 0 : : partition_(partition),
82 0 : state_(NULL),
83 0 : route_(route),
84 0 : type_(type),
85 0 : label_(0),
86 0 : edge_replication_not_supported_(false),
87 0 : assisted_replication_supported_(false),
88 0 : assisted_replication_leaf_(false) {
89 0 : UpdateAttributes(route);
90 0 : }
91 :
92 0 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
93 0 : EvpnRoute *route, uint8_t type, EvpnStatePtr state)
94 0 : : partition_(partition),
95 0 : state_(state),
96 0 : route_(route),
97 0 : type_(type),
98 0 : label_(0),
99 0 : edge_replication_not_supported_(false),
100 0 : assisted_replication_supported_(false),
101 0 : assisted_replication_leaf_(false) {
102 0 : if (route)
103 0 : UpdateAttributes(route);
104 0 : }
105 :
106 : //
107 : // Destructor for EvpnMcastNode.
108 : //
109 0 : EvpnMcastNode::~EvpnMcastNode() {
110 0 : set_state(NULL);
111 0 : }
112 :
113 : //
114 : // Update the label and attributes for a EvpnMcastNode.
115 : // Return true if either of them changed.
116 : //
117 0 : bool EvpnMcastNode::UpdateAttributes(EvpnRoute *route) {
118 0 : bool changed = false;
119 0 : const BgpPath *path = route->BestPath();
120 0 : if (path->GetLabel() != label_) {
121 0 : label_ = path->GetLabel();
122 0 : changed = true;
123 : }
124 0 : if (path->GetAttr() != attr_) {
125 0 : attr_ = path->GetAttr();
126 0 : changed = true;
127 : }
128 :
129 0 : const PmsiTunnel *pmsi_tunnel = attr_->pmsi_tunnel();
130 0 : uint8_t ar_type = 0;
131 0 : bool edge_replication_not_supported = false;
132 0 : if (pmsi_tunnel) {
133 0 : ar_type = pmsi_tunnel->tunnel_flags() &
134 : PmsiTunnelSpec::AssistedReplicationType;
135 0 : if ((pmsi_tunnel->tunnel_flags() &
136 0 : PmsiTunnelSpec::EdgeReplicationSupported) == 0) {
137 0 : edge_replication_not_supported = true;
138 : }
139 0 : if (replicator_address_ != pmsi_tunnel->identifier()) {
140 0 : replicator_address_ = pmsi_tunnel->identifier();
141 0 : changed = true;
142 : }
143 : }
144 :
145 0 : if (edge_replication_not_supported != edge_replication_not_supported_) {
146 0 : edge_replication_not_supported_ = edge_replication_not_supported;
147 0 : changed = true;
148 : }
149 :
150 0 : bool assisted_replication_supported = false;
151 0 : if (ar_type == PmsiTunnelSpec::ARReplicator)
152 0 : assisted_replication_supported = true;
153 0 : if (assisted_replication_supported != assisted_replication_supported_) {
154 0 : assisted_replication_supported_ = assisted_replication_supported;
155 0 : changed = true;
156 : }
157 :
158 0 : bool assisted_replication_leaf = false;
159 0 : if (ar_type == PmsiTunnelSpec::ARLeaf)
160 0 : assisted_replication_leaf = true;
161 0 : if (assisted_replication_leaf != assisted_replication_leaf_) {
162 0 : assisted_replication_leaf_ = assisted_replication_leaf;
163 0 : changed = true;
164 : }
165 :
166 0 : if (address_ != path->GetAttr()->nexthop().to_v4()) {
167 0 : address_ = path->GetAttr()->nexthop().to_v4();
168 0 : changed = true;
169 : }
170 :
171 0 : 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 0 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
184 0 : EvpnRoute *route)
185 : : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode),
186 0 : inclusive_mcast_route_(NULL) {
187 0 : AddInclusiveMulticastRoute();
188 0 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
189 0 : tbl_partition->Notify(route_);
190 0 : }
191 :
192 0 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
193 0 : EvpnRoute *route, EvpnStatePtr state)
194 : : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode, state),
195 0 : inclusive_mcast_route_(NULL) {
196 0 : if (!route)
197 0 : return;
198 0 : AddInclusiveMulticastRoute();
199 0 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
200 0 : tbl_partition->Notify(route_);
201 0 : }
202 :
203 : //
204 : // Destructor for EvpnLocalMcastNode.
205 : //
206 0 : EvpnLocalMcastNode::~EvpnLocalMcastNode() {
207 0 : DeleteInclusiveMulticastRoute();
208 0 : }
209 :
210 : //
211 : // Add Inclusive Multicast route for this EvpnLocalMcastNode.
212 : // The attributes are based on the Broadcast MAC route.
213 : //
214 0 : void EvpnLocalMcastNode::AddInclusiveMulticastRoute() {
215 : // No need to create IMET route if group is specified
216 0 : if (!route_->GetPrefix().group().is_unspecified())
217 0 : return;
218 0 : assert(!inclusive_mcast_route_);
219 0 : 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 0 : const EvpnPrefix &mac_prefix = route_->GetPrefix();
227 : RouteDistinguisher rd(
228 0 : address_.to_ulong(), mac_prefix.route_distinguisher().GetVrfId());
229 0 : EvpnPrefix prefix(rd, mac_prefix.tag(), address_);
230 0 : EvpnRoute rt_key(prefix);
231 :
232 : // Find or create the route.
233 0 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
234 0 : EvpnRoute *route = static_cast<EvpnRoute *>(tbl_partition->Find(&rt_key));
235 0 : if (!route) {
236 0 : route = new EvpnRoute(prefix);
237 0 : tbl_partition->Add(route);
238 : } else {
239 0 : route->ClearDelete();
240 : }
241 : // Add MulticastFlags community to specify that it supports SMET route
242 0 : ExtCommunity::ExtCommunityList mcastFlags;
243 0 : mcastFlags.push_back(MulticastFlags().GetExtCommunity());
244 0 : ExtCommunityPtr ext_community = partition_->server()->extcomm_db()->
245 0 : ReplaceMFlagsAndLocate(attr_->ext_community(), mcastFlags);
246 0 : attr_ = partition_->server()->attr_db()->ReplaceExtCommunityAndLocate(
247 0 : attr_.get(), ext_community);
248 :
249 : // Add a path with source BgpPath::Local and the peer address as path_id.
250 0 : uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
251 0 : BgpPath *path = new BgpPath(path_id, BgpPath::Local, attr_, 0, label_);
252 0 : route->InsertPath(path);
253 0 : inclusive_mcast_route_ = route;
254 0 : tbl_partition->Notify(inclusive_mcast_route_);
255 0 : BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
256 : route, "Insert new Local path");
257 0 : }
258 :
259 : //
260 : // Delete Inclusive Multicast route for this EvpnLocalMcastNode.
261 : //
262 0 : void EvpnLocalMcastNode::DeleteInclusiveMulticastRoute() {
263 0 : if (!inclusive_mcast_route_)
264 0 : return;
265 :
266 0 : const EvpnPrefix &mac_prefix = route_->GetPrefix();
267 0 : uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
268 0 : DBTablePartition *tbl_partition = partition_->GetTablePartition();
269 0 : inclusive_mcast_route_->RemovePath(BgpPath::Local, path_id);
270 0 : BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
271 : inclusive_mcast_route_, "Delete Local path");
272 :
273 0 : if (!inclusive_mcast_route_->HasPaths()) {
274 0 : tbl_partition->Delete(inclusive_mcast_route_);
275 : } else {
276 0 : tbl_partition->Notify(inclusive_mcast_route_);
277 : }
278 0 : 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 0 : void EvpnLocalMcastNode::TriggerUpdate() {
289 0 : DeleteInclusiveMulticastRoute();
290 0 : AddInclusiveMulticastRoute();
291 0 : }
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 0 : UpdateInfo *EvpnLocalMcastNode::GetUpdateInfo(EvpnRoute *route) {
303 0 : CHECK_CONCURRENCY("db::DBTable");
304 :
305 : // Nothing to send for a leaf as it already knows the replicator-address.
306 0 : if (assisted_replication_leaf_)
307 0 : return NULL;
308 :
309 0 : const RoutingInstance *rti = partition_->table()->routing_instance();
310 0 : bool pbb_evpn_enable = rti->virtual_network_pbb_evpn_enable();
311 0 : uint32_t local_ethernet_tag = route_->GetPrefix().tag();
312 :
313 0 : EvpnState::SG sg = EvpnState::SG(route->GetPrefix().source(),
314 0 : route->GetPrefix().group());
315 : // Go through list of EvpnRemoteMcastNodes and build the BgpOList.
316 0 : BgpOListSpec olist_spec(BgpAttribute::OList);
317 0 : if (partition_->remote_mcast_node_list()->count(sg)) {
318 0 : set<EvpnMcastNode*> nodes = (*partition_->remote_mcast_node_list())[sg];
319 0 : BOOST_FOREACH(EvpnMcastNode *node, nodes) {
320 0 : if (node->address() == address_)
321 0 : continue;
322 0 : if (node->assisted_replication_leaf())
323 0 : continue;
324 0 : if (!edge_replication_not_supported_ &&
325 0 : !node->edge_replication_not_supported())
326 0 : continue;
327 0 : uint32_t remote_ethernet_tag = node->route()->GetPrefix().tag();
328 :
329 0 : if (pbb_evpn_enable && remote_ethernet_tag &&
330 : (local_ethernet_tag != remote_ethernet_tag))
331 0 : continue;
332 :
333 0 : const ExtCommunity *extcomm = node->attr()->ext_community();
334 0 : BgpOListElem elem(node->address(), node->label(),
335 0 : extcomm ? extcomm->GetTunnelEncap() : vector<string>());
336 0 : olist_spec.elements.push_back(elem);
337 0 : }
338 0 : }
339 :
340 : // Go through list of leaf EvpnMcastNodes and build the leaf BgpOList.
341 0 : BgpOListSpec leaf_olist_spec(BgpAttribute::LeafOList);
342 0 : if (assisted_replication_supported_) {
343 0 : if (partition_->leaf_node_list()->count(sg)) {
344 0 : set<EvpnMcastNode*> nodes = (*partition_->leaf_node_list())[sg];
345 0 : BOOST_FOREACH(EvpnMcastNode *node, nodes) {
346 0 : if (node->replicator_address() != address_)
347 0 : continue;
348 :
349 0 : const ExtCommunity *extcomm = node->attr()->ext_community();
350 0 : BgpOListElem elem(node->address(), node->label(),
351 0 : extcomm ? extcomm->GetTunnelEncap() : vector<string>());
352 0 : leaf_olist_spec.elements.push_back(elem);
353 0 : }
354 0 : }
355 : }
356 :
357 : // Bail if both BgpOLists are empty.
358 0 : if (olist_spec.elements.empty() && leaf_olist_spec.elements.empty())
359 0 : return NULL;
360 :
361 : // Add BgpOList and leaf BgpOList to RibOutAttr for broadcast MAC route.
362 0 : BgpAttrDB *attr_db = partition_->server()->attr_db();
363 0 : BgpAttrPtr attr = attr_db->ReplaceOListAndLocate(attr_.get(), &olist_spec);
364 0 : attr = attr_db->ReplaceLeafOListAndLocate(attr.get(), &leaf_olist_spec);
365 :
366 0 : UpdateInfo *uinfo = new UpdateInfo;
367 : uinfo->roattr =
368 0 : RibOutAttr(partition_->table(), route_, attr.get(), 0, false, true);
369 0 : return uinfo;
370 0 : }
371 :
372 : //
373 : // Constructor for EvpnRemoteMcastNode.
374 : //
375 0 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
376 0 : EvpnRoute *route)
377 0 : : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode) {
378 0 : }
379 :
380 0 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
381 0 : EvpnRoute *route, EvpnStatePtr state)
382 0 : : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode, state) {
383 0 : }
384 :
385 : //
386 : // Destructor for EvpnRemoteMcastNode.
387 : //
388 0 : EvpnRemoteMcastNode::~EvpnRemoteMcastNode() {
389 0 : }
390 :
391 : //
392 : // Handle update of EvpnRemoteMcastNode.
393 : //
394 0 : void EvpnRemoteMcastNode::TriggerUpdate() {
395 0 : }
396 :
397 : //
398 : // Constructor for EvpnSegment.
399 : //
400 0 : EvpnSegment::EvpnSegment(EvpnManager *manager, const EthernetSegmentId &esi)
401 0 : : evpn_manager_(manager),
402 0 : esi_(esi),
403 0 : esi_ad_route_(NULL),
404 0 : single_active_(true),
405 0 : route_lists_(DB::PartitionCount()) {
406 0 : }
407 :
408 : //
409 : // Destructor for EvpnSegment.
410 : //
411 0 : EvpnSegment::~EvpnSegment() {
412 0 : assert(!esi_ad_route_);
413 0 : assert(pe_list_.empty());
414 0 : }
415 :
416 : //
417 : // Add the given MAC route as a dependent of this EvpnSegment.
418 : //
419 0 : void EvpnSegment::AddMacRoute(size_t part_id, EvpnRoute *route) {
420 0 : pair<RouteList::iterator, bool> ret = route_lists_[part_id].insert(route);
421 0 : assert(ret.second);
422 0 : }
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 0 : void EvpnSegment::DeleteMacRoute(size_t part_id, EvpnRoute *route) {
430 0 : size_t count = route_lists_[part_id].erase(route);
431 0 : assert(count == 1);
432 0 : if (route_lists_[part_id].empty())
433 0 : evpn_manager_->TriggerSegmentDelete(this);
434 0 : }
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 0 : void EvpnSegment::TriggerMacRouteUpdate() {
442 0 : CHECK_CONCURRENCY("bgp::EvpnSegment");
443 :
444 0 : for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
445 0 : EvpnManagerPartition *partition = evpn_manager_->GetPartition(part_id);
446 0 : BOOST_FOREACH(EvpnRoute *route, route_lists_[part_id]) {
447 0 : partition->TriggerMacRouteUpdate(route);
448 : }
449 : }
450 0 : }
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 0 : bool EvpnSegment::UpdatePeList() {
459 0 : CHECK_CONCURRENCY("bgp::EvpnSegment");
460 :
461 : // Mark all entries as invalid.
462 0 : for (RemotePeList::iterator it = pe_list_.begin();
463 0 : it != pe_list_.end(); ++it) {
464 0 : 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 0 : bool changed = false;
471 0 : for (Route::PathList::const_iterator path_it =
472 0 : esi_ad_route_->GetPathList().begin();
473 0 : path_it != esi_ad_route_->GetPathList().end(); ++path_it) {
474 : const BgpPath *path =
475 0 : static_cast<const BgpPath *>(path_it.operator->());
476 0 : const BgpAttr *attr = path->GetAttr();
477 :
478 : // Skip non-VXLAN paths for now.
479 0 : const ExtCommunity *extcomm = attr->ext_community();
480 0 : if (!extcomm || !extcomm->ContainsTunnelEncapVxlan())
481 0 : continue;
482 :
483 : // Go through existing pe list and try to find the RemotePe.
484 0 : bool found = false;
485 0 : RemotePe remote_pe(path);
486 0 : for (RemotePeList::iterator it = pe_list_.begin();
487 0 : it != pe_list_.end(); ++it) {
488 : // Skip if the nexthop doesn't match.
489 0 : if (it->attr->nexthop() != remote_pe.attr->nexthop())
490 0 : 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 0 : if (it->esi_valid) {
495 0 : found = true;
496 0 : break;
497 : }
498 :
499 : // Check if we have a match.
500 0 : if (*it == remote_pe) {
501 0 : it->esi_valid = true;
502 0 : found = true;
503 0 : break;
504 : }
505 : }
506 :
507 : // Add a new entry to the pe list if we didn't find the RemotePe.
508 0 : if (!found) {
509 0 : pe_list_.push_back(remote_pe);
510 0 : changed = true;
511 : }
512 0 : }
513 :
514 : // Erase invalid entries from the list.
515 0 : for (RemotePeList::iterator it = pe_list_.begin(), next = it;
516 0 : it != pe_list_.end(); it = next) {
517 0 : ++next;
518 0 : if (!it->esi_valid) {
519 0 : pe_list_.erase(it);
520 0 : changed = true;
521 : }
522 : }
523 :
524 : // Update the single active status of the EvpnSegment itself.
525 0 : single_active_ = false;
526 0 : for (RemotePeList::iterator it = pe_list_.begin();
527 0 : it != pe_list_.end(); ++it) {
528 0 : if (it->single_active) {
529 0 : single_active_ = true;
530 0 : break;
531 : }
532 : }
533 :
534 0 : return changed;
535 : }
536 :
537 : //
538 : // Return true if it's safe to delete this EvpnSegment.
539 : //
540 0 : bool EvpnSegment::MayDelete() const {
541 0 : CHECK_CONCURRENCY("bgp::EvpnSegment");
542 :
543 : // Bail if we have state set on the per-ESI AD route.
544 0 : if (esi_ad_route_)
545 0 : return false;
546 :
547 : // Bail if the dependent route list for any partition is not empty.
548 0 : for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
549 0 : if (!route_lists_[part_id].empty())
550 0 : return false;
551 : }
552 :
553 0 : return true;
554 : }
555 :
556 : //
557 : // Constructor for EvpnSegment::RemotePe.
558 : //
559 0 : EvpnSegment::RemotePe::RemotePe(const BgpPath *path)
560 0 : : esi_valid(true),
561 0 : single_active(path->GetAttr()->evpn_single_active()),
562 0 : peer(path->GetPeer()),
563 0 : attr(path->GetAttr()),
564 0 : flags(path->GetFlags()),
565 0 : src(path->GetSource()) {
566 0 : }
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 0 : bool EvpnSegment::RemotePe::operator==(const RemotePe &rhs) const {
574 0 : if (peer != rhs.peer)
575 0 : return false;
576 0 : if (attr != rhs.attr)
577 0 : return false;
578 0 : if (flags != rhs.flags)
579 0 : return false;
580 0 : if (src != rhs.src)
581 0 : return false;
582 0 : return true;
583 : }
584 :
585 : //
586 : // Constructor for EvpnMacState.
587 : //
588 0 : EvpnMacState::EvpnMacState(EvpnManager *evpn_manager, EvpnRoute *route)
589 0 : : evpn_manager_(evpn_manager), route_(route), segment_(NULL) {
590 0 : }
591 :
592 : //
593 : // Destructor for EvpnMacState.
594 : //
595 0 : EvpnMacState::~EvpnMacState() {
596 0 : assert(segment_ == NULL);
597 0 : assert(aliased_path_list_.empty());
598 0 : }
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 0 : void EvpnMacState::AddAliasedPath(AliasedPathList::const_iterator it) {
605 0 : BgpPath *path = *it;
606 0 : const IPeer *peer = path->GetPeer();
607 0 : aliased_path_list_.insert(path);
608 0 : route_->InsertPath(path);
609 0 : 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 0 : }
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 0 : void EvpnMacState::DeleteAliasedPath(AliasedPathList::const_iterator it) {
622 0 : BgpPath *path = *it;
623 0 : const IPeer *peer = path->GetPeer();
624 0 : 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 0 : route_->DeletePath(path);
631 0 : aliased_path_list_.erase(it);
632 0 : }
633 :
634 : //
635 : // Find or create the matching aliased BgpPath.
636 : //
637 0 : BgpPath *EvpnMacState::LocateAliasedPath(
638 : const EvpnSegment::RemotePe *remote_pe, uint32_t label) {
639 0 : const IPeer *peer = remote_pe->peer;
640 0 : const BgpAttr *attr = remote_pe->attr.get();
641 0 : uint32_t flags = remote_pe->flags | BgpPath::AliasedPath;
642 0 : BgpPath::PathSource src = remote_pe->src;
643 0 : for (AliasedPathList::iterator it = aliased_path_list_.begin();
644 0 : it != aliased_path_list_.end(); ++it) {
645 0 : BgpPath *path = *it;
646 0 : if (path->GetPeer() == peer &&
647 0 : path->GetAttr() == attr &&
648 0 : path->GetFlags() == flags &&
649 0 : path->GetLabel() == label) {
650 0 : return path;
651 : }
652 : }
653 :
654 0 : 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 0 : bool EvpnMacState::ProcessMacRouteAliasing() {
663 0 : CHECK_CONCURRENCY("db::DBTable");
664 :
665 0 : const BgpPath *path = route_->BestPath();
666 :
667 : // Find the remote PE entry that corresponds to the primary path.
668 0 : bool found_primary_pe = false;
669 0 : EvpnSegment::const_iterator it;
670 0 : if (path && segment_ && !segment_->single_active())
671 0 : it = segment_->begin();
672 0 : for (; path && segment_ && !segment_->single_active() &&
673 0 : it != segment_->end(); ++it) {
674 0 : if (path->GetAttr()->nexthop() != it->attr->nexthop())
675 0 : continue;
676 0 : found_primary_pe = true;
677 0 : break;
678 : }
679 :
680 : // Go through the remote PE list for the EvpnSegment and build the
681 : // list of future aliased paths.
682 0 : AliasedPathList future_aliased_path_list;
683 0 : if (found_primary_pe && path && segment_ && !segment_->single_active())
684 0 : it = segment_->begin();
685 0 : for (; found_primary_pe && path && segment_ &&
686 0 : !segment_->single_active() && it != segment_->end(); ++it) {
687 : // Skip if there's a BGP_XMPP path with the remote PE as nexthop.
688 0 : if (route_->FindPath(it->attr->nexthop()))
689 0 : 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 0 : LocateAliasedPath(it.operator->(), path->GetLabel());
695 0 : 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 0 : 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 0 : return modified;
705 0 : }
706 :
707 : //
708 : // Constructor for EvpnManagerPartition.
709 : //
710 0 : EvpnManagerPartition::EvpnManagerPartition(EvpnManager *evpn_manager,
711 0 : size_t part_id)
712 0 : : evpn_manager_(evpn_manager),
713 0 : part_id_(part_id),
714 0 : mac_update_trigger_(new TaskTrigger(
715 : boost::bind(&EvpnManagerPartition::ProcessMacUpdateList, this),
716 0 : TaskScheduler::GetInstance()->GetTaskId("db::DBTable"),
717 0 : part_id)) {
718 0 : table_partition_ = evpn_manager_->GetTablePartition(part_id);
719 0 : }
720 :
721 : //
722 : // Destructor for EvpnManagerPartition.
723 : //
724 0 : EvpnManagerPartition::~EvpnManagerPartition() {
725 0 : assert(local_mcast_node_list_.empty());
726 0 : assert(remote_mcast_node_list_.empty());
727 0 : assert(mac_update_list_.empty());
728 0 : }
729 :
730 : //
731 : // Get the DBTablePartition for the EvpnTable for our partition id.
732 : //
733 0 : DBTablePartition *EvpnManagerPartition::GetTablePartition() {
734 0 : return evpn_manager_->GetTablePartition(part_id_);
735 : }
736 :
737 : //
738 : // Notify the Broadcast MAC route for the given EvpnMcastNode.
739 : //
740 0 : void EvpnManagerPartition::NotifyNodeRoute(EvpnMcastNode *node) {
741 0 : DBTablePartition *tbl_partition = GetTablePartition();
742 0 : tbl_partition->Notify(node->route());
743 0 : }
744 :
745 : //
746 : // Go through all replicator EvpnMcastNodes and notify associated Broadcast
747 : // MAC route.
748 : //
749 0 : void EvpnManagerPartition::NotifyReplicatorNodeRoutes() {
750 0 : DBTablePartition *tbl_partition = GetTablePartition();
751 0 : EvpnMcastNodeList::const_iterator it = replicator_node_list_.begin();
752 0 : for (; it != replicator_node_list_.end(); it++) {
753 0 : BOOST_FOREACH(EvpnMcastNode *node, it->second)
754 0 : tbl_partition->Notify(node->route());
755 : }
756 0 : }
757 :
758 : //
759 : // Go through all ingress replication client EvpnMcastNodes and notify the
760 : // associated Broadcast MAC route.
761 : //
762 0 : void EvpnManagerPartition::NotifyIrClientNodeRoutes(
763 : bool exclude_edge_replication_supported) {
764 0 : DBTablePartition *tbl_partition = GetTablePartition();
765 0 : EvpnMcastNodeList::const_iterator it = ir_client_node_list_.begin();
766 0 : for (; it != ir_client_node_list_.end(); it++) {
767 0 : BOOST_FOREACH(EvpnMcastNode *node, it->second) {
768 0 : if (exclude_edge_replication_supported &&
769 0 : !node->edge_replication_not_supported()) {
770 0 : continue;
771 : }
772 0 : tbl_partition->Notify(node->route());
773 : }
774 : }
775 0 : }
776 :
777 : //
778 : // Add an EvpnMcastNode to the EvpnManagerPartition.
779 : //
780 0 : void EvpnManagerPartition::AddMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
781 0 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
782 0 : rt->GetPrefix().group());
783 0 : if (node->type() == EvpnMcastNode::LocalNode) {
784 0 : local_mcast_node_list_[sg].insert(node);
785 0 : if (node->assisted_replication_supported())
786 0 : replicator_node_list_[sg].insert(node);
787 0 : if (!node->assisted_replication_leaf())
788 0 : ir_client_node_list_[sg].insert(node);
789 0 : NotifyNodeRoute(node);
790 : } else {
791 0 : remote_mcast_node_list_[sg].insert(node);
792 0 : if (node->assisted_replication_leaf()) {
793 0 : leaf_node_list_[sg].insert(node);
794 0 : NotifyReplicatorNodeRoutes();
795 0 : } else if (node->edge_replication_not_supported()) {
796 0 : regular_node_list_[sg].insert(node);
797 0 : NotifyIrClientNodeRoutes(false);
798 0 : } else if (!node->assisted_replication_leaf()) {
799 0 : NotifyIrClientNodeRoutes(true);
800 : }
801 : }
802 0 : }
803 :
804 : //
805 : // Delete an EvpnMcastNode from the EvpnManagerPartition.
806 : //
807 0 : bool EvpnManagerPartition::RemoveMcastNodeFromList(EvpnState::SG &sg,
808 : EvpnMcastNode *node,
809 : EvpnMcastNodeList *list) {
810 0 : size_t deleted = 0;
811 0 : if (list->count(sg)) {
812 0 : deleted = (*list)[sg].erase(node);
813 0 : if ((*list)[sg].size() == 0)
814 0 : list->erase(sg);
815 : }
816 0 : return (deleted > 0);
817 : }
818 :
819 : //
820 : // Delete an EvpnMcastNode from the EvpnManagerPartition.
821 : //
822 0 : void EvpnManagerPartition::DeleteMcastNode(EvpnMcastNode *node,
823 : EvpnRoute * rt) {
824 0 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
825 0 : rt->GetPrefix().group());
826 0 : if (node->type() == EvpnMcastNode::LocalNode) {
827 0 : RemoveMcastNodeFromList(sg, node, &local_mcast_node_list_);
828 0 : RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
829 0 : RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
830 : } else {
831 0 : RemoveMcastNodeFromList(sg, node, &remote_mcast_node_list_);
832 0 : if (RemoveMcastNodeFromList(sg, node, &leaf_node_list_)) {
833 0 : NotifyReplicatorNodeRoutes();
834 : } else {
835 0 : NotifyIrClientNodeRoutes(true);
836 : }
837 0 : if (RemoveMcastNodeFromList(sg, node, ®ular_node_list_)) {
838 0 : NotifyIrClientNodeRoutes(false);
839 : }
840 : }
841 0 : if (empty())
842 0 : evpn_manager_->RetryDelete();
843 0 : }
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 0 : void EvpnManagerPartition::UpdateMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
851 0 : node->TriggerUpdate();
852 0 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
853 0 : rt->GetPrefix().group());
854 0 : if (node->type() == EvpnMcastNode::LocalNode) {
855 0 : RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
856 0 : if (node->assisted_replication_supported())
857 0 : replicator_node_list_[sg].insert(node);
858 0 : RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
859 0 : if (!node->assisted_replication_leaf())
860 0 : ir_client_node_list_[sg].insert(node);
861 0 : NotifyNodeRoute(node);
862 : } else {
863 0 : bool was_leaf = RemoveMcastNodeFromList(sg, node, &leaf_node_list_);
864 0 : if (node->assisted_replication_leaf())
865 0 : leaf_node_list_[sg].insert(node);
866 0 : if (was_leaf || node->assisted_replication_leaf())
867 0 : NotifyReplicatorNodeRoutes();
868 0 : if (!was_leaf || !node->assisted_replication_leaf())
869 0 : NotifyIrClientNodeRoutes(true);
870 0 : bool was_regular = RemoveMcastNodeFromList(
871 : sg, node, ®ular_node_list_);
872 0 : if (node->edge_replication_not_supported())
873 0 : regular_node_list_[sg].insert(node);
874 0 : if (was_regular || node->edge_replication_not_supported())
875 0 : NotifyIrClientNodeRoutes(false);
876 : }
877 0 : }
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 0 : void EvpnManagerPartition::TriggerMacRouteUpdate(EvpnRoute *route) {
885 0 : CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
886 :
887 0 : mac_update_list_.insert(route);
888 0 : mac_update_trigger_->Set();
889 0 : }
890 :
891 : //
892 : // Process the MAC route update list for this EvpnManagerPartition.
893 : //
894 0 : bool EvpnManagerPartition::ProcessMacUpdateList() {
895 0 : CHECK_CONCURRENCY("db::DBTable");
896 :
897 0 : BgpTable *table = evpn_manager_->table();
898 0 : int listener_id = evpn_manager_->listener_id();
899 :
900 0 : 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 0 : if (route->is_onlist())
906 0 : continue;
907 :
908 : EvpnMacState *mac_state =
909 0 : dynamic_cast<EvpnMacState *>(route->GetState(table, listener_id));
910 0 : assert(mac_state);
911 0 : bool modified = mac_state->ProcessMacRouteAliasing();
912 0 : if (route->HasPaths()) {
913 0 : if (!mac_state->segment()) {
914 0 : route->ClearState(table, listener_id);
915 0 : delete mac_state;
916 : }
917 0 : if (modified) {
918 0 : table_partition_->Notify(route);
919 : }
920 : } else {
921 0 : route->ClearState(table, listener_id);
922 0 : table_partition_->Delete(route);
923 0 : delete mac_state;
924 : }
925 : }
926 :
927 0 : mac_update_list_.clear();
928 0 : evpn_manager_->RetryDelete();
929 0 : return true;
930 : }
931 :
932 0 : bool EvpnManagerPartition::GetForestNodeAddress(ErmVpnRoute *rt,
933 : Ip4Address *address) const {
934 0 : if (!evpn_manager_->ermvpn_table()->tree_manager())
935 0 : return false;
936 : uint32_t label;
937 0 : vector<string> te;
938 0 : return evpn_manager_->ermvpn_table()->tree_manager()->GetForestNodePMSI(
939 0 : rt, &label, address, &te);
940 0 : }
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 0 : EvpnStatePtr EvpnManagerPartition::GetState(const SG &sg) {
948 0 : EvpnState::StatesMap::iterator iter = states_.find(sg);
949 0 : return iter != states_.end() ? iter->second : NULL;
950 : }
951 :
952 0 : EvpnStatePtr EvpnManagerPartition::GetState(EvpnRoute *rt) {
953 0 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
954 0 : rt->GetPrefix().group());
955 0 : return GetState(sg);
956 : }
957 :
958 0 : EvpnStatePtr EvpnManagerPartition::CreateState(const SG &sg) {
959 0 : EvpnStatePtr state(new EvpnState(sg, &states_, evpn_manager_));
960 0 : assert(states_.insert(make_pair(sg, state.get())).second);
961 0 : EVPN_TRACE(EvpnStateCreate, sg.source.to_string(), sg.group.to_string());
962 0 : return state;
963 0 : }
964 :
965 0 : EvpnStatePtr EvpnManagerPartition::LocateState(const SG &sg) {
966 0 : EvpnStatePtr evpn_state = GetState(sg);
967 0 : if (evpn_state)
968 0 : return evpn_state;
969 0 : evpn_state = CreateState(sg);
970 0 : assert(evpn_state);
971 0 : return evpn_state;
972 0 : }
973 :
974 0 : EvpnStatePtr EvpnManagerPartition::LocateState(EvpnRoute *rt) {
975 0 : EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
976 0 : rt->GetPrefix().group());
977 0 : return LocateState(sg);
978 : }
979 :
980 : //
981 : // Disable processing of the update list.
982 : // For testing only.
983 : //
984 0 : void EvpnManagerPartition::DisableMacUpdateProcessing() {
985 0 : mac_update_trigger_->set_disable();
986 0 : }
987 :
988 : //
989 : // Enable processing of the update list.
990 : // For testing only.
991 : //
992 0 : void EvpnManagerPartition::EnableMacUpdateProcessing() {
993 0 : mac_update_trigger_->set_enable();
994 0 : }
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 0 : bool EvpnManagerPartition::empty() const {
1001 0 : if (!local_mcast_node_list_.empty())
1002 0 : return false;
1003 0 : if (!remote_mcast_node_list_.empty())
1004 0 : return false;
1005 0 : if (!mac_update_list_.empty())
1006 0 : return false;
1007 0 : assert(leaf_node_list_.empty());
1008 0 : assert(replicator_node_list_.empty());
1009 0 : assert(regular_node_list_.empty());
1010 0 : assert(ir_client_node_list_.empty());
1011 0 : return true;
1012 : }
1013 :
1014 : //
1015 : // Return the BgpServer for the EvpnManagerPartition.
1016 : //
1017 0 : BgpServer *EvpnManagerPartition::server() {
1018 0 : return evpn_manager_->server();
1019 : }
1020 :
1021 : //
1022 : // Return the EvpnTable for the EvpnManagerPartition.
1023 : //
1024 0 : const EvpnTable *EvpnManagerPartition::table() const {
1025 0 : return evpn_manager_->table();
1026 : }
1027 :
1028 : //
1029 : // Constructor for EvpnManager.
1030 : //
1031 0 : EvpnManager::EvpnManager(EvpnTable *table)
1032 0 : : table_(table),
1033 0 : listener_id_(DBTable::kInvalidId),
1034 0 : segment_delete_trigger_(new TaskTrigger(
1035 : boost::bind(&EvpnManager::ProcessSegmentDeleteSet, this),
1036 0 : TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
1037 0 : segment_update_trigger_(new TaskTrigger(
1038 : boost::bind(&EvpnManager::ProcessSegmentUpdateSet, this),
1039 0 : TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
1040 0 : table_delete_ref_(this, table->deleter()) {
1041 0 : deleter_.reset(new DeleteActor(this));
1042 0 : db_states_count_ = 0;
1043 0 : }
1044 :
1045 : //
1046 : // Destructor for EvpnManager.
1047 : //
1048 0 : EvpnManager::~EvpnManager() {
1049 0 : assert(segment_map_.empty());
1050 0 : assert(segment_delete_set_.empty());
1051 0 : assert(segment_update_set_.empty());
1052 0 : }
1053 :
1054 : //
1055 : // Initialize the EvpnManager. We allocate the EvpnManagerPartitions
1056 : // and register a DBListener for the EvpnTable.
1057 : //
1058 0 : void EvpnManager::Initialize() {
1059 0 : AllocPartitions();
1060 0 : listener_id_ = table_->Register(
1061 : boost::bind(&EvpnManager::RouteListener, this, _1, _2),
1062 : "EvpnManager");
1063 0 : ermvpn_table_ = dynamic_cast<ErmVpnTable *>(
1064 0 : table_->routing_instance()->GetTable(Address::ERMVPN));
1065 0 : if (ermvpn_table_)
1066 0 : ermvpn_listener_id_ = ermvpn_table_->Register(
1067 : boost::bind(&EvpnManager::ErmVpnRouteListener, this, _1, _2),
1068 : "EvpnManager");
1069 0 : }
1070 :
1071 : //
1072 : // Terminate the EvpnManager. We free the EvpnManagerPartitions
1073 : // and unregister from the EvpnTable.
1074 : //
1075 0 : void EvpnManager::Terminate() {
1076 0 : CHECK_CONCURRENCY("bgp::Config");
1077 0 : table_->Unregister(listener_id_);
1078 0 : listener_id_ = DBTable::kInvalidId;
1079 0 : if (ermvpn_listener_id_ != DBTable::kInvalidId) {
1080 0 : ermvpn_table_->Unregister(ermvpn_listener_id_);
1081 0 : ermvpn_listener_id_ = DBTable::kInvalidId;
1082 : }
1083 0 : FreePartitions();
1084 0 : }
1085 :
1086 : //
1087 : // Allocate the EvpnManagerPartitions.
1088 : //
1089 0 : void EvpnManager::AllocPartitions() {
1090 0 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1091 0 : partitions_.push_back(new EvpnManagerPartition(this, part_id));
1092 : }
1093 0 : }
1094 :
1095 : //
1096 : // Free the EvpnManagerPartitions.
1097 : //
1098 0 : void EvpnManager::FreePartitions() {
1099 0 : STLDeleteValues(&partitions_);
1100 0 : }
1101 :
1102 : //
1103 : // Disable processing of the update lists in all partitions.
1104 : // For testing only.
1105 : //
1106 0 : void EvpnManager::DisableMacUpdateProcessing() {
1107 0 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1108 0 : partitions_[part_id]->DisableMacUpdateProcessing();
1109 : }
1110 0 : }
1111 :
1112 : //
1113 : // Enable processing of the update lists in all partitions.
1114 : // For testing only.
1115 : //
1116 0 : void EvpnManager::EnableMacUpdateProcessing() {
1117 0 : for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
1118 0 : partitions_[part_id]->EnableMacUpdateProcessing();
1119 : }
1120 0 : }
1121 :
1122 : //
1123 : // Get the EvpnManagerPartition for the given partition id.
1124 : //
1125 0 : EvpnManagerPartition *EvpnManager::GetPartition(size_t part_id) {
1126 0 : return partitions_[part_id];
1127 : }
1128 :
1129 : //
1130 : // Get the DBTablePartition for the EvpnTable for given partition id.
1131 : //
1132 0 : DBTablePartition *EvpnManager::GetTablePartition(size_t part_id) {
1133 0 : 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 0 : UpdateInfo *EvpnManager::GetUpdateInfo(EvpnRoute *route) {
1141 0 : CHECK_CONCURRENCY("db::DBTable");
1142 :
1143 0 : DBState *dbstate = route->GetState(table_, listener_id_);
1144 : EvpnLocalMcastNode *local_node =
1145 0 : dynamic_cast<EvpnLocalMcastNode *>(dbstate);
1146 :
1147 0 : if (!local_node)
1148 0 : return NULL;
1149 :
1150 0 : return local_node->GetUpdateInfo(route);
1151 : }
1152 :
1153 0 : BgpServer *EvpnManager::server() {
1154 0 : return table_->server();
1155 : }
1156 :
1157 : //
1158 : // Find or create the EvpnSegment for the given EthernetSegmentId.
1159 : //
1160 0 : EvpnSegment *EvpnManager::LocateSegment(const EthernetSegmentId &esi) {
1161 0 : assert(!esi.IsZero());
1162 0 : tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
1163 0 : SegmentMap::iterator loc = segment_map_.find(esi);
1164 0 : EvpnSegment *segment = (loc != segment_map_.end()) ? loc->second : NULL;
1165 0 : if (!segment) {
1166 0 : segment = new EvpnSegment(this, esi);
1167 0 : segment_map_.insert(esi, segment);
1168 : }
1169 0 : return segment;
1170 0 : }
1171 :
1172 : //
1173 : // Find the EvpnSegment for the given EthernetSegmentId.
1174 : //
1175 0 : EvpnSegment *EvpnManager::FindSegment(const EthernetSegmentId &esi) {
1176 0 : assert(!esi.IsZero());
1177 0 : tbb::spin_rw_mutex::scoped_lock read_lock(segment_rw_mutex_, false);
1178 0 : SegmentMap::iterator loc = segment_map_.find(esi);
1179 0 : return (loc != segment_map_.end()) ? loc->second : NULL;
1180 0 : }
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 0 : void EvpnManager::TriggerSegmentDelete(EvpnSegment *segment) {
1193 0 : CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
1194 :
1195 0 : tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
1196 0 : segment_delete_set_.insert(segment);
1197 0 : segment_delete_trigger_->Set();
1198 0 : }
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 0 : bool EvpnManager::ProcessSegmentDeleteSet() {
1206 0 : CHECK_CONCURRENCY("bgp::EvpnSegment");
1207 :
1208 0 : BOOST_FOREACH(EvpnSegment *segment, segment_delete_set_) {
1209 0 : if (segment->MayDelete()) {
1210 0 : segment_update_set_.erase(segment);
1211 0 : EthernetSegmentId esi = segment->esi();
1212 0 : segment_map_.erase(esi);
1213 : }
1214 : }
1215 0 : segment_delete_set_.clear();
1216 0 : RetryDelete();
1217 0 : 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 0 : void EvpnManager::TriggerSegmentUpdate(EvpnSegment *segment) {
1247 0 : CHECK_CONCURRENCY("db::DBTable");
1248 :
1249 0 : segment_update_set_.insert(segment);
1250 0 : segment_update_trigger_->Set();
1251 0 : }
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 0 : bool EvpnManager::ProcessSegmentUpdateSet() {
1260 0 : CHECK_CONCURRENCY("bgp::EvpnSegment");
1261 :
1262 0 : BOOST_FOREACH(EvpnSegment *segment, segment_update_set_) {
1263 0 : EvpnRoute *esi_ad_route = segment->esi_ad_route();
1264 0 : bool changed = segment->UpdatePeList();
1265 0 : if (changed)
1266 0 : segment->TriggerMacRouteUpdate();
1267 0 : if (!esi_ad_route->IsValid()) {
1268 0 : segment->clear_esi_ad_route();
1269 0 : esi_ad_route->ClearState(table_, listener_id_);
1270 0 : TriggerSegmentDelete(segment);
1271 : }
1272 : }
1273 0 : segment_update_set_.clear();
1274 0 : RetryDelete();
1275 0 : return true;
1276 : }
1277 :
1278 : //
1279 : // Disable processing of the update list.
1280 : // For testing only.
1281 : //
1282 0 : void EvpnManager::DisableSegmentUpdateProcessing() {
1283 0 : segment_update_trigger_->set_disable();
1284 0 : }
1285 :
1286 : //
1287 : // Enable processing of the update list.
1288 : // For testing only.
1289 : //
1290 0 : void EvpnManager::EnableSegmentUpdateProcessing() {
1291 0 : segment_update_trigger_->set_enable();
1292 0 : }
1293 :
1294 : //
1295 : // DBListener callback handler for AutoDisocvery routes in the EvpnTable.
1296 : //
1297 0 : void EvpnManager::AutoDiscoveryRouteListener(EvpnRoute *route) {
1298 0 : CHECK_CONCURRENCY("db::DBTable");
1299 :
1300 0 : DBState *dbstate = route->GetState(table_, listener_id_);
1301 0 : if (!dbstate) {
1302 : // We have no previous DBState for this route.
1303 : // Bail if the route is not valid.
1304 0 : 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 0 : EvpnSegment *segment = LocateSegment(route->GetPrefix().esi());
1311 0 : segment->set_esi_ad_route(route);
1312 0 : route->SetState(table_, listener_id_, segment);
1313 0 : TriggerSegmentUpdate(segment);
1314 : } else {
1315 : // Trigger an update of EvpnSegment so that it's PE list
1316 : // gets updated.
1317 0 : EvpnSegment *segment = dynamic_cast<EvpnSegment *>(dbstate);
1318 0 : assert(segment);
1319 0 : TriggerSegmentUpdate(segment);
1320 : }
1321 : }
1322 :
1323 : //
1324 : // DBListener callback handler for MacAdvertisement routes in the EvpnTable.
1325 : //
1326 0 : void EvpnManager::MacAdvertisementRouteListener(
1327 : EvpnManagerPartition *partition, EvpnRoute *route) {
1328 0 : CHECK_CONCURRENCY("db::DBTable");
1329 :
1330 0 : DBState *dbstate = route->GetState(table_, listener_id_);
1331 0 : 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 0 : if (!route->IsValid())
1335 0 : return;
1336 0 : const BgpPath *path = route->BestPath();
1337 0 : if (path->GetAttr()->esi().IsZero())
1338 0 : return;
1339 :
1340 : // Create a new EvpnMacState and associate it with the route.
1341 0 : EvpnMacState *mac_state = new EvpnMacState(this, route);
1342 0 : 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 0 : EvpnSegment *segment = LocateSegment(path->GetAttr()->esi());
1347 0 : mac_state->set_segment(segment);
1348 0 : segment->AddMacRoute(partition->part_id(), route);
1349 0 : partition->TriggerMacRouteUpdate(route);
1350 : } else {
1351 0 : EvpnMacState *mac_state = dynamic_cast<EvpnMacState *>(dbstate);
1352 0 : assert(mac_state);
1353 0 : 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 0 : const BgpPath *path = route->BestPath();
1361 0 : if (!route->IsValid() || (path && path->GetAttr()->esi().IsZero())) {
1362 0 : if (segment) {
1363 0 : segment->DeleteMacRoute(partition->part_id(), route);
1364 0 : mac_state->clear_segment();
1365 : }
1366 0 : } else if (!segment && !path->GetAttr()->esi().IsZero()) {
1367 0 : segment = LocateSegment(path->GetAttr()->esi());
1368 0 : mac_state->set_segment(segment);
1369 0 : segment->AddMacRoute(partition->part_id(), route);
1370 0 : } else if (segment && segment->esi() != path->GetAttr()->esi()) {
1371 0 : segment->DeleteMacRoute(partition->part_id(), route);
1372 0 : mac_state->clear_segment();
1373 0 : segment = LocateSegment(path->GetAttr()->esi());
1374 0 : mac_state->set_segment(segment);
1375 0 : segment->AddMacRoute(partition->part_id(), route);
1376 : }
1377 0 : partition->TriggerMacRouteUpdate(route);
1378 : }
1379 : }
1380 :
1381 : //
1382 : // DBListener callback handler for InclusiveMulticast routes in the EvpnTable.
1383 : //
1384 0 : void EvpnManager::InclusiveMulticastRouteListener(
1385 : EvpnManagerPartition *partition, EvpnRoute *route) {
1386 0 : CHECK_CONCURRENCY("db::DBTable");
1387 :
1388 0 : DBState *dbstate = route->GetState(table_, listener_id_);
1389 0 : if (!dbstate) {
1390 : // We have no previous DBState for this route.
1391 : // Bail if the route is not valid.
1392 0 : if (!route->IsValid())
1393 0 : return;
1394 :
1395 : // Create a new EvpnMcastNode and associate it with the route.
1396 : EvpnMcastNode *node;
1397 0 : if (route->GetPrefix().type() == EvpnPrefix::MacAdvertisementRoute) {
1398 0 : node = new EvpnLocalMcastNode(partition, route);
1399 : } else {
1400 0 : node = new EvpnRemoteMcastNode(partition, route);
1401 : }
1402 0 : partition->AddMcastNode(node, route);
1403 0 : route->SetState(table_, listener_id_, node);
1404 : } else {
1405 0 : EvpnMcastNode *node = dynamic_cast<EvpnMcastNode *>(dbstate);
1406 0 : assert(node);
1407 :
1408 0 : if (!route->IsValid()) {
1409 : // Delete the EvpnMcastNode associated with the route.
1410 0 : route->ClearState(table_, listener_id_);
1411 0 : partition->DeleteMcastNode(node, route);
1412 0 : delete node;
1413 0 : } else if (node->UpdateAttributes(route)) {
1414 : // Update the EvpnMcastNode associated with the route.
1415 0 : partition->UpdateMcastNode(node, route);
1416 : }
1417 : }
1418 : }
1419 :
1420 : //
1421 : // DBListener callback handler for SelectiveMulticast routes in the EvpnTable.
1422 : //
1423 0 : void EvpnManager::SelectiveMulticastRouteListener(
1424 : EvpnManagerPartition *partition, EvpnRoute *route) {
1425 :
1426 0 : CHECK_CONCURRENCY("db::DBTable");
1427 0 : EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
1428 0 : route->GetState(table_, listener_id_));
1429 0 : bool is_usable = route->IsUsable();
1430 0 : bool is_deleted = route->IsDeleted();
1431 0 : bool checkErmvpnRoute = false;
1432 0 : if (route->BestPath()) {
1433 0 : checkErmvpnRoute = route->BestPath()->GetFlags() &
1434 : BgpPath::CheckGlobalErmVpnRoute;
1435 : }
1436 0 : if ((!is_usable && !checkErmvpnRoute) || is_deleted) {
1437 0 : if (!dbstate)
1438 0 : return;
1439 :
1440 0 : EvpnStatePtr evpn_state = partition->GetState(route);
1441 0 : if (evpn_state)
1442 0 : evpn_state->smet_routes().erase(route);
1443 0 : EVPN_RT_LOG(route, "Processed Smet route deletion");
1444 0 : ClearDBState(route);
1445 0 : partition->NotifyForestNode(route, ermvpn_table());
1446 0 : partition->DeleteMcastNode(dbstate, route);
1447 0 : delete dbstate;
1448 0 : return;
1449 0 : }
1450 :
1451 0 : EvpnStatePtr evpn_state = partition->LocateState(route);
1452 0 : assert(evpn_state);
1453 0 : evpn_state->smet_routes().insert(route);
1454 0 : BgpPath *path = const_cast<BgpPath *>(route->BestPath());
1455 0 : if (path && path->CheckErmVpn()) {
1456 0 : ErmVpnRoute *global_rt = evpn_state->global_ermvpn_tree_rt();
1457 0 : Ip4Address address;
1458 0 : bool nh_found = partition->GetForestNodeAddress(global_rt, &address);
1459 0 : if (nh_found) {
1460 0 : BgpAttrPtr attr = path->GetAttr();
1461 : BgpAttrPtr new_attr = partition->server()->attr_db()->
1462 0 : ReplaceNexthopAndLocate(attr.get(), address);
1463 0 : path->SetAttr(new_attr, attr);
1464 0 : path->ResetCheckErmVpn();
1465 0 : partition->NotifyForestNode(route, ermvpn_table());
1466 0 : }
1467 : }
1468 :
1469 0 : if (!dbstate) {
1470 : // Create a new DBState and associate it with the route.
1471 : EvpnMcastNode *node;
1472 0 : if (route->GetPrefix().ip_address() ==
1473 0 : Ip4Address(table_->server()->bgp_identifier())) {
1474 0 : node = new EvpnLocalMcastNode(partition, route, evpn_state);
1475 : } else {
1476 0 : node = new EvpnRemoteMcastNode(partition, route, evpn_state);
1477 : }
1478 0 : SetDBState(route, node);
1479 0 : partition->AddMcastNode(node, route);
1480 0 : EVPN_RT_LOG(route, "Processed Smet route creation");
1481 : }
1482 0 : }
1483 :
1484 0 : void EvpnManagerPartition::NotifyForestNode(EvpnRoute *route,
1485 : ErmVpnTable *table) {
1486 0 : const Ip4Address &source = route->GetPrefix().source().to_v4();
1487 0 : const Ip4Address &group = route->GetPrefix().group().to_v4();
1488 0 : if (table->tree_manager())
1489 0 : table->tree_manager()->NotifyForestNode(part_id_, source, group);
1490 0 : }
1491 :
1492 : // Set DB State and update count.
1493 0 : void EvpnManager::SetDBState(EvpnRoute *route, EvpnMcastNode *dbstate) {
1494 0 : route->SetState(table_, listener_id_, dbstate);
1495 0 : db_states_count_++;
1496 0 : }
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 0 : void EvpnManager::ClearDBState(EvpnRoute *route) {
1501 0 : route->ClearState(table_, listener_id_);
1502 0 : assert(db_states_count_);
1503 0 : db_states_count_--;
1504 :
1505 : // Retry deletion now as there is no more attached db state in the table.
1506 0 : if (!db_states_count_ && deleter_->IsDeleted())
1507 0 : deleter_->RetryDelete();
1508 0 : }
1509 :
1510 : // Check whether an ErmVpnRoute is locally originated GlobalTreeRoute.
1511 0 : bool EvpnManager::IsUsableGlobalTreeRootRoute(
1512 : ErmVpnRoute *ermvpn_route) const {
1513 0 : if (!ermvpn_route || !ermvpn_route->IsUsable())
1514 0 : return false;
1515 0 : if (!ermvpn_table()->tree_manager())
1516 0 : return false;
1517 0 : if (ermvpn_table()->tree_manager()->begin() ==
1518 0 : ermvpn_table()->tree_manager()->end())
1519 0 : return false;
1520 0 : ErmVpnRoute *global_rt = ermvpn_table()->tree_manager()->
1521 0 : GetGlobalTreeRootRoute(
1522 0 : ermvpn_route->GetPrefix().source(),
1523 0 : ermvpn_route->GetPrefix().group());
1524 0 : 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 0 : void EvpnManager::ErmVpnRouteListener(DBTablePartBase *tpart,
1531 : DBEntryBase *db_entry) {
1532 0 : CHECK_CONCURRENCY("db::DBTable");
1533 :
1534 0 : ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(db_entry);
1535 0 : assert(ermvpn_route);
1536 :
1537 : // We only care about global tree routes for evpn stitching.
1538 0 : if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute) {
1539 0 : return;
1540 : }
1541 :
1542 0 : EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
1543 0 : ermvpn_route->GetState(ermvpn_table(), ermvpn_listener_id()));
1544 :
1545 : // Handle GlobalTreeRoute route deletion.
1546 0 : if (!IsUsableGlobalTreeRootRoute(ermvpn_route)) {
1547 : // Ignore if there is no DB State associated with route.
1548 0 : if (!dbstate)
1549 0 : return;
1550 0 : EvpnStatePtr evpn_state = dbstate->state();
1551 0 : 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 0 : BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
1557 0 : BgpPath *path = const_cast<BgpPath *>(route->BestPath());
1558 0 : if (path && (path->GetPathId() == 0)) {
1559 0 : path->SetCheckErmVpn();
1560 : }
1561 0 : route->Notify();
1562 : }
1563 0 : ermvpn_route->ClearState(ermvpn_table(), ermvpn_listener_id());
1564 0 : EVPN_ERMVPN_RT_LOG(ermvpn_route,
1565 : "Processed EVPN GlobalErmVpnRoute deletion");
1566 0 : delete dbstate;
1567 0 : return;
1568 0 : }
1569 :
1570 : // Set DB State in the route if not already done so before.
1571 0 : EvpnManagerPartition *partition = GetPartition(tpart->index());
1572 0 : EvpnStatePtr evpn_state;
1573 0 : if (!dbstate) {
1574 0 : EvpnState::SG sg(ermvpn_route);
1575 0 : evpn_state = partition->LocateState(sg);
1576 0 : dbstate = new EvpnLocalMcastNode(partition, NULL, evpn_state);
1577 0 : ermvpn_route->SetState(ermvpn_table(), ermvpn_listener_id(), dbstate);
1578 : } else {
1579 0 : evpn_state = dbstate->state();
1580 : }
1581 :
1582 : // Note down current usable ermvpn route for stitching to evpn.
1583 0 : dbstate->state()->set_global_ermvpn_tree_rt(ermvpn_route);
1584 :
1585 : // Notify all originated Type6 routes.
1586 0 : BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
1587 0 : route->Notify();
1588 : }
1589 0 : EVPN_ERMVPN_RT_LOG(ermvpn_route,
1590 : "Processed EVPN GlobalErmVpnRoute creation");
1591 0 : }
1592 :
1593 : //
1594 : // DBListener callback handler for the EvpnTable.
1595 : //
1596 0 : void EvpnManager::RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry) {
1597 0 : CHECK_CONCURRENCY("db::DBTable");
1598 :
1599 0 : EvpnManagerPartition *partition = GetPartition(tpart->index());
1600 0 : EvpnRoute *route = dynamic_cast<EvpnRoute *>(db_entry);
1601 0 : assert(route);
1602 :
1603 0 : switch (route->GetPrefix().type()) {
1604 0 : case EvpnPrefix::AutoDiscoveryRoute:
1605 0 : AutoDiscoveryRouteListener(route);
1606 0 : break;
1607 0 : case EvpnPrefix::MacAdvertisementRoute:
1608 0 : if (route->GetPrefix().mac_addr().IsBroadcast()) {
1609 0 : InclusiveMulticastRouteListener(partition, route);
1610 : } else {
1611 0 : MacAdvertisementRouteListener(partition, route);
1612 : }
1613 0 : break;
1614 0 : case EvpnPrefix::InclusiveMulticastRoute:
1615 0 : InclusiveMulticastRouteListener(partition, route);
1616 0 : break;
1617 0 : case EvpnPrefix::SelectiveMulticastRoute:
1618 0 : SelectiveMulticastRouteListener(partition, route);
1619 0 : break;
1620 0 : default:
1621 0 : break;
1622 : }
1623 0 : }
1624 :
1625 : //
1626 : // Fill information for introspect command.
1627 : // Note that all IM routes are always in partition 0.
1628 : //
1629 0 : void EvpnManager::FillShowInfo(ShowEvpnTable *sevt) const {
1630 0 : CHECK_CONCURRENCY("db::DBTable");
1631 :
1632 0 : vector<string> regular_nves;
1633 0 : vector<string> ar_replicators;
1634 0 : vector<ShowEvpnMcastLeaf> ar_leafs;
1635 : EvpnManagerPartition::EvpnMcastNodeList::const_iterator it =
1636 0 : partitions_[0]->remote_mcast_node_list()->begin();
1637 0 : 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 0 : sort(regular_nves.begin(), regular_nves.end());
1653 0 : sort(ar_replicators.begin(), ar_replicators.end());
1654 0 : sort(ar_leafs.begin(), ar_leafs.end());
1655 0 : sevt->set_regular_nves(regular_nves);
1656 0 : sevt->set_ar_replicators(ar_replicators);
1657 0 : sevt->set_ar_leafs(ar_leafs);
1658 0 : }
1659 :
1660 : //
1661 : // Check if the EvpnManager can be deleted. This can happen only if all the
1662 : // EvpnManagerPartitions are empty.
1663 : //
1664 0 : bool EvpnManager::MayDelete() const {
1665 0 : CHECK_CONCURRENCY("bgp::Config");
1666 :
1667 0 : if (!segment_map_.empty())
1668 0 : return false;
1669 :
1670 0 : if (!segment_update_set_.empty())
1671 0 : return false;
1672 0 : if (segment_update_trigger_->IsSet())
1673 0 : return false;
1674 :
1675 0 : if (!segment_delete_set_.empty())
1676 0 : return false;
1677 0 : if (segment_delete_trigger_->IsSet())
1678 0 : return false;
1679 :
1680 0 : BOOST_FOREACH(const EvpnManagerPartition *partition, partitions_) {
1681 0 : if (!partition->empty())
1682 0 : return false;
1683 0 : if (!partition->states().empty())
1684 0 : return false;
1685 : }
1686 0 : if (db_states_count_)
1687 0 : return false;
1688 0 : return true;
1689 : }
1690 :
1691 : //
1692 : // Initiate shutdown for the EvpnManager.
1693 : //
1694 0 : void EvpnManager::Shutdown() {
1695 0 : CHECK_CONCURRENCY("bgp::Config");
1696 0 : }
1697 :
1698 : //
1699 : // Trigger deletion of the EvpnManager and propagate the delete to any
1700 : // dependents.
1701 : //
1702 0 : void EvpnManager::ManagedDelete() {
1703 0 : deleter_->Delete();
1704 0 : }
1705 :
1706 : //
1707 : // Attempt to enqueue a delete for the EvpnManager.
1708 : //
1709 0 : void EvpnManager::RetryDelete() {
1710 0 : if (!deleter()->IsDeleted())
1711 0 : return;
1712 0 : deleter()->RetryDelete();
1713 : }
1714 :
1715 : //
1716 : // Return the LifetimeActor for the EvpnManager.
1717 : //
1718 0 : LifetimeActor *EvpnManager::deleter() {
1719 0 : return deleter_.get();
1720 : }
1721 :
1722 0 : EvpnState::SG::SG(const Ip4Address &source, const Ip4Address &group) :
1723 0 : source(IpAddress(source)), group(IpAddress(group)) {
1724 0 : }
1725 :
1726 0 : EvpnState::SG::SG(const ErmVpnRoute *route) :
1727 0 : source(route->GetPrefix().source()),
1728 0 : group(route->GetPrefix().group()) {
1729 0 : }
1730 :
1731 0 : EvpnState::SG::SG(const EvpnRoute *route) :
1732 0 : source(route->GetPrefix().source()), group(route->GetPrefix().group()) {
1733 0 : }
1734 :
1735 0 : EvpnState::SG::SG(const IpAddress &source, const IpAddress &group) :
1736 0 : source(source), group(group) {
1737 0 : }
1738 :
1739 0 : bool EvpnState::SG::operator<(const SG &other) const {
1740 0 : if (source < other.source)
1741 0 : return true;
1742 0 : if (source > other.source)
1743 0 : return false;
1744 0 : if (group < other.group)
1745 0 : return true;
1746 0 : if (group > other.group)
1747 0 : return false;
1748 0 : return false;
1749 : }
1750 :
1751 0 : const EvpnState::SG &EvpnState::sg() const {
1752 0 : return sg_;
1753 : }
1754 :
1755 0 : void EvpnState::set_global_ermvpn_tree_rt(ErmVpnRoute *global_ermvpn_tree_rt) {
1756 0 : global_ermvpn_tree_rt_ = global_ermvpn_tree_rt;
1757 0 : }
1758 :
1759 0 : ErmVpnRoute *EvpnState::global_ermvpn_tree_rt() {
1760 0 : 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 : }
|