Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_mvpn.h"
6 :
7 : #include <utility>
8 :
9 : #include <boost/foreach.hpp>
10 :
11 : #include "base/task_annotations.h"
12 : #include "bgp/ermvpn/ermvpn_route.h"
13 : #include "bgp/ermvpn/ermvpn_table.h"
14 : #include "bgp/extended-community/vrf_route_import.h"
15 : #include "bgp/bgp_log.h"
16 : #include "bgp/bgp_multicast.h"
17 : #include "bgp/bgp_server.h"
18 : #include "bgp/bgp_update.h"
19 : #include "bgp/mvpn/mvpn_table.h"
20 : #include "bgp/routing-instance/path_resolver.h"
21 : #include "bgp/routing-instance/routing_instance.h"
22 : #include "bgp/routing-instance/routing_instance_analytics_types.h"
23 : #include "bgp/routing-instance/routing_instance_log.h"
24 : #include "bgp/rtarget/rtarget_address.h"
25 : #include "bgp/tunnel_encap/tunnel_encap.h"
26 :
27 : using std::make_pair;
28 : using std::ostringstream;
29 : using std::pair;
30 : using std::string;
31 : using std::vector;
32 :
33 : // A global MVPN state for a given <S.G> within a MvpnProjectManager.
34 8067 : MvpnState::MvpnState(const SG &sg, StatesMap *states, MvpnProjectManager *pm) :
35 16134 : sg_(sg), global_ermvpn_tree_rt_(NULL), spmsi_rt_(NULL),
36 8067 : source_active_rt_(NULL), states_(states), project_manager_(pm) {
37 8067 : refcount_ = 0;
38 8067 : }
39 :
40 16134 : MvpnState::~MvpnState() {
41 8067 : assert(!global_ermvpn_tree_rt_);
42 8067 : assert(!spmsi_rt_);
43 8067 : assert(!source_active_rt_);
44 8067 : assert(spmsi_routes_received_.empty());
45 8067 : assert(leafad_routes_attr_received_.empty());
46 8067 : MVPN_TRACE(MvpnStateCreate, sg_.source.to_string(), sg_.group.to_string());
47 16134 : }
48 :
49 48402 : const ErmVpnTable *MvpnState::table() const {
50 48402 : return project_manager_ ? project_manager_->table() : NULL;
51 : }
52 :
53 : // MvpnProjectManager is deleted when parent ErmVpnTable is deleted.
54 : class MvpnProjectManager::DeleteActor : public LifetimeActor {
55 : public:
56 22563 : explicit DeleteActor(MvpnProjectManager *manager)
57 22563 : : LifetimeActor(manager->table_->routing_instance()->server()->
58 22563 : lifetime_manager()), manager_(manager) {
59 22563 : }
60 :
61 45126 : virtual ~DeleteActor() {
62 45126 : }
63 :
64 24354 : virtual bool MayDelete() const {
65 24354 : CHECK_CONCURRENCY("bgp::Config");
66 24354 : return manager_->MayDelete();
67 : }
68 :
69 22563 : virtual void Shutdown() {
70 22563 : }
71 :
72 22563 : virtual void Destroy() {
73 22563 : manager_->table_->DestroyMvpnProjectManager();
74 22563 : }
75 :
76 : private:
77 : MvpnProjectManager *manager_;
78 : };
79 :
80 : // Create MvpnProjectManager object and take a lifetime reference to the
81 : // parent ErmVpnTable object.
82 22563 : MvpnProjectManager::MvpnProjectManager(ErmVpnTable *table)
83 22563 : : table_(table),
84 22563 : listener_id_(DBTable::kInvalidId),
85 22563 : table_delete_ref_(this, table->deleter()) {
86 22563 : deleter_.reset(new DeleteActor(this));
87 22563 : }
88 :
89 45126 : MvpnProjectManager::~MvpnProjectManager() {
90 45126 : }
91 :
92 : // MvpnProjectManager can be deleted only after all <S,G> MvpnState objects
93 : // are deleted from the map.
94 24354 : bool MvpnProjectManager::MayDelete() const {
95 69480 : BOOST_FOREACH(const MvpnProjectManagerPartition *partition, partitions_) {
96 24354 : if (!partition->states().empty()) {
97 1791 : MVPN_LOG(MvpnProjectManagerDelete,
98 : "MvpnProjectManager::MayDelete() paused due to pending " +
99 : integerToString(partition->states().size()) + " MvpnStates");
100 1791 : return false;
101 : }
102 : }
103 22563 : return true;
104 : }
105 :
106 12477 : LifetimeActor *MvpnProjectManager::deleter() {
107 12477 : return deleter_.get();
108 : }
109 :
110 46801 : const LifetimeActor *MvpnProjectManager::deleter() const {
111 46801 : return deleter_.get();
112 : }
113 :
114 : // Create MvpnProjectManagerPartitions and register with the ErmVpnTable to
115 : // get route change notifications.
116 22563 : void MvpnProjectManager::Initialize() {
117 22563 : if (!table_->server()->mvpn_ipv4_enable())
118 0 : return;
119 :
120 22563 : AllocPartitions();
121 :
122 22562 : listener_id_ = table_->Register(
123 : boost::bind(&MvpnProjectManager::RouteListener, this, _1, _2),
124 : "MvpnProjectManager");
125 22563 : MVPN_LOG(MvpnProjectManagerCreate, "Initialized MvpnProjectManager");
126 : }
127 :
128 22563 : void MvpnProjectManager::Terminate() {
129 22563 : CHECK_CONCURRENCY("bgp::Config");
130 22563 : table_->Unregister(listener_id_);
131 22563 : listener_id_ = DBTable::kInvalidId;
132 22563 : FreePartitions();
133 22563 : MVPN_LOG(MvpnProjectManagerDelete, "Terminated MvpnProjectManager");
134 22563 : }
135 :
136 22561 : void MvpnProjectManager::AllocPartitions() {
137 45123 : for (int part_id = 0; part_id < table_->PartitionCount(); part_id++)
138 22563 : partitions_.push_back(new MvpnProjectManagerPartition(this, part_id));
139 22562 : }
140 :
141 22563 : void MvpnProjectManager::FreePartitions() {
142 45126 : for (size_t part_id = 0; part_id < partitions_.size(); part_id++) {
143 22563 : delete partitions_[part_id];
144 : }
145 22563 : partitions_.clear();
146 22563 : }
147 :
148 54340 : MvpnProjectManagerPartition *MvpnProjectManager::GetPartition(int part_id) {
149 54340 : return partitions_[part_id];
150 : }
151 :
152 2813 : const MvpnProjectManagerPartition *MvpnProjectManager::GetPartition(
153 : int part_id) const {
154 2813 : return partitions_[part_id];
155 : }
156 :
157 22563 : void MvpnProjectManager::ManagedDelete() {
158 22563 : deleter_->Delete();
159 22563 : }
160 :
161 190 : bool MvpnProjectManager::deleted() const {
162 190 : return deleter_->IsDeleted();
163 : }
164 :
165 2311 : MvpnStatePtr MvpnProjectManager::GetState(MvpnRoute *route) const {
166 2311 : MvpnState::SG sg(route->GetPrefix().source(), route->GetPrefix().group());
167 4622 : return GetPartition(route->get_table_partition()->index())->GetState(sg);
168 : }
169 :
170 2311 : MvpnStatePtr MvpnProjectManager::GetState(MvpnRoute *route) {
171 2311 : return static_cast<const MvpnProjectManager *>(this)->GetState(route);
172 : }
173 :
174 381 : MvpnStatePtr MvpnProjectManager::GetState(ErmVpnRoute *route) const {
175 381 : MvpnState::SG sg(route->GetPrefix().source(), route->GetPrefix().group());
176 762 : return GetPartition(route->get_table_partition()->index())->GetState(sg);
177 : }
178 :
179 22563 : MvpnProjectManagerPartition::MvpnProjectManagerPartition(
180 22563 : MvpnProjectManager *manager, int part_id)
181 22563 : : manager_(manager), part_id_(part_id) {
182 22563 : }
183 :
184 45126 : MvpnProjectManagerPartition::~MvpnProjectManagerPartition() {
185 22563 : assert(states_.empty());
186 45126 : }
187 :
188 8067 : MvpnStatePtr MvpnProjectManagerPartition::CreateState(const SG &sg) {
189 8067 : MvpnStatePtr state(new MvpnState(sg, &states_, manager_));
190 8067 : assert(states_.insert(make_pair(sg, state.get())).second);
191 8067 : MVPN_TRACE(MvpnStateCreate, sg.source.to_string(), sg.group.to_string());
192 8067 : return state;
193 0 : }
194 :
195 23824 : MvpnStatePtr MvpnProjectManagerPartition::LocateState(const SG &sg) {
196 23824 : MvpnStatePtr mvpn_state = GetState(sg);
197 23824 : if (mvpn_state)
198 15757 : return mvpn_state;
199 8067 : mvpn_state = CreateState(sg);
200 8067 : assert(mvpn_state);
201 8067 : return mvpn_state;
202 0 : }
203 :
204 10249 : MvpnStatePtr MvpnProjectManagerPartition::GetState(const SG &sg) const {
205 10249 : MvpnState::StatesMap::const_iterator iter = states_.find(sg);
206 10249 : return iter != states_.end() ? iter->second : NULL;
207 : }
208 :
209 23824 : MvpnStatePtr MvpnProjectManagerPartition::GetState(const SG &sg) {
210 23824 : MvpnState::StatesMap::iterator iter = states_.find(sg);
211 23824 : return iter != states_.end() ? iter->second : NULL;
212 : }
213 :
214 173725 : MvpnNeighbor::MvpnNeighbor() : source_as_(0) {
215 173725 : }
216 :
217 47816 : MvpnNeighbor::MvpnNeighbor(const RouteDistinguisher &rd,
218 47816 : const IpAddress &originator) :
219 47816 : rd_(rd), originator_(originator), source_as_(0) {
220 47816 : }
221 :
222 81185 : const RouteDistinguisher &MvpnNeighbor::rd() const {
223 81185 : return rd_;
224 : }
225 :
226 81437 : uint32_t MvpnNeighbor::source_as() const {
227 81437 : return source_as_;
228 : }
229 :
230 81437 : const IpAddress &MvpnNeighbor::originator() const {
231 81437 : return originator_;
232 : }
233 :
234 28711 : bool MvpnNeighbor::operator==(const MvpnNeighbor &rhs) const {
235 57422 : return rd_ == rhs.rd_ && originator_ == rhs.originator_ &&
236 57422 : source_as_ == rhs.source_as_;
237 : }
238 :
239 182545 : bool MvpnManager::FindNeighbor(const RouteDistinguisher &rd,
240 : MvpnNeighbor *nbr) const {
241 182545 : std::shared_lock<std::shared_mutex> lock(neighbors_mutex_);
242 182545 : NeighborMap::const_iterator iter = neighbors_.find(rd);
243 182545 : if (iter != neighbors_.end()) {
244 59336 : *nbr = iter->second;
245 59336 : return true;
246 : }
247 123209 : return false;
248 182545 : }
249 :
250 2 : const MvpnManager::NeighborMap &MvpnManager::neighbors() const {
251 : // Assert that lock cannot be taken now as it must have been taken already.
252 : // assert(!neighbors_mutex_.try_lock_read());
253 2 : return neighbors_;
254 : }
255 :
256 27600 : size_t MvpnManager::neighbors_count() const {
257 27600 : std::shared_lock<std::shared_mutex> lock(neighbors_mutex_);
258 55200 : return neighbors_.size();
259 27600 : }
260 :
261 11512 : MvpnState::SG::SG(const Ip4Address &source, const Ip4Address &group) :
262 11512 : source(IpAddress(source)), group(IpAddress(group)) {
263 11512 : }
264 :
265 1857 : MvpnState::SG::SG(const ErmVpnRoute *route) :
266 1857 : source(route->GetPrefix().source()),
267 1857 : group(route->GetPrefix().group()) {
268 1857 : }
269 :
270 121 : MvpnState::SG::SG(const MvpnRoute *route) :
271 121 : source(route->GetPrefix().source()), group(route->GetPrefix().group()) {
272 121 : }
273 :
274 37047 : MvpnState::SG::SG(const IpAddress &source, const IpAddress &group) :
275 37047 : source(source), group(group) {
276 37047 : }
277 :
278 163443 : bool MvpnState::SG::operator<(const SG &other) const {
279 163443 : if (source < other.source)
280 15 : return true;
281 163427 : if (source > other.source)
282 7 : return false;
283 163418 : if (group < other.group)
284 38682 : return true;
285 124736 : if (group > other.group)
286 27801 : return false;
287 96936 : return false;
288 : }
289 :
290 8069 : const MvpnState::SG &MvpnState::sg() const {
291 8069 : return sg_;
292 : }
293 :
294 12956 : ErmVpnRoute *MvpnState::global_ermvpn_tree_rt() {
295 12956 : return global_ermvpn_tree_rt_;
296 : }
297 :
298 2 : const ErmVpnRoute *MvpnState::global_ermvpn_tree_rt() const {
299 2 : return global_ermvpn_tree_rt_;
300 : }
301 :
302 7214 : MvpnRoute *MvpnState::spmsi_rt() {
303 7214 : return spmsi_rt_;
304 : }
305 :
306 1 : const MvpnRoute *MvpnState::spmsi_rt() const {
307 1 : return spmsi_rt_;
308 : }
309 :
310 19784 : MvpnState::RoutesSet &MvpnState::spmsi_routes_received() {
311 19784 : return spmsi_routes_received_;
312 : }
313 :
314 1 : const MvpnState::RoutesSet &MvpnState::spmsi_routes_received() const {
315 1 : return spmsi_routes_received_;
316 : }
317 :
318 672 : MvpnState::RoutesMap &MvpnState::leafad_routes_attr_received() {
319 672 : return leafad_routes_attr_received_;
320 : }
321 :
322 1 : const MvpnState::RoutesMap &MvpnState::leafad_routes_attr_received() const {
323 1 : return leafad_routes_attr_received_;
324 : }
325 :
326 4358 : void MvpnState::set_global_ermvpn_tree_rt(ErmVpnRoute *global_ermvpn_tree_rt) {
327 4358 : global_ermvpn_tree_rt_ = global_ermvpn_tree_rt;
328 4358 : }
329 :
330 8465 : void MvpnState::set_spmsi_rt(MvpnRoute *spmsi_rt) {
331 8465 : spmsi_rt_ = spmsi_rt;
332 8465 : }
333 :
334 9658 : MvpnRoute *MvpnState::source_active_rt() {
335 9658 : return source_active_rt_;
336 : }
337 :
338 1 : const MvpnRoute *MvpnState::source_active_rt() const {
339 1 : return source_active_rt_;
340 : }
341 :
342 9600 : void MvpnState::set_source_active_rt(MvpnRoute *source_active_rt) {
343 9600 : source_active_rt_ = source_active_rt;
344 9600 : }
345 :
346 15994 : MvpnDBState::MvpnDBState(MvpnStatePtr state) : state_(state) , route_(NULL) {
347 15994 : }
348 :
349 31988 : MvpnDBState::~MvpnDBState() {
350 15994 : set_state(NULL);
351 31988 : }
352 :
353 29919 : MvpnStatePtr MvpnDBState::state() {
354 29919 : return state_;
355 : }
356 :
357 20439 : MvpnRoute *MvpnDBState::route() {
358 20439 : return route_;
359 : }
360 :
361 12631 : void MvpnDBState::set_route(MvpnRoute *route) {
362 12631 : route_ = route;
363 12631 : }
364 :
365 15994 : void MvpnDBState::set_state(MvpnStatePtr state) {
366 15994 : state_ = state;
367 15994 : }
368 :
369 : class MvpnManager::DeleteActor : public LifetimeActor {
370 : public:
371 41841 : explicit DeleteActor(MvpnManager *manager)
372 41841 : : LifetimeActor(manager->table_->routing_instance()->server()->
373 41841 : lifetime_manager()), manager_(manager) {
374 41841 : }
375 83682 : virtual ~DeleteActor() {
376 83682 : }
377 :
378 42200 : virtual bool MayDelete() const {
379 42200 : CHECK_CONCURRENCY("bgp::Config");
380 42200 : return manager_->MayDelete();
381 : }
382 :
383 41841 : virtual void Shutdown() {
384 41841 : if (manager_->table()->IsDeleted())
385 22563 : return;
386 19278 : manager_->table()->NotifyAllEntries();
387 : }
388 :
389 41841 : virtual void Destroy() {
390 41841 : manager_->table_->DestroyManager();
391 41841 : }
392 :
393 : private:
394 : MvpnManager *manager_;
395 : };
396 :
397 41841 : MvpnManager::MvpnManager(MvpnTable *table, ErmVpnTable *ermvpn_table)
398 41841 : : table_(table),
399 41841 : ermvpn_table_(ermvpn_table),
400 41841 : listener_id_(DBTable::kInvalidId),
401 41841 : identifier_listener_id_(-1),
402 41841 : table_delete_ref_(this, table->deleter()),
403 83682 : ermvpn_table_delete_ref_(this, ermvpn_table->deleter()) {
404 41841 : deleter_.reset(new DeleteActor(this));
405 41841 : db_states_count_ = 0;
406 41841 : }
407 :
408 83682 : MvpnManager::~MvpnManager() {
409 83682 : }
410 :
411 1098947 : MvpnTable *MvpnManager::table() {
412 1098947 : return table_;
413 : }
414 :
415 3001 : const MvpnTable *MvpnManager::table() const {
416 3001 : return table_;
417 : }
418 :
419 85307 : int MvpnManager::listener_id() const {
420 85307 : return listener_id_;
421 : }
422 :
423 190 : bool MvpnManager::deleted() const {
424 190 : return deleter_->IsDeleted();
425 : }
426 :
427 190 : const LifetimeActor *MvpnManager::deleter() const {
428 190 : return deleter_.get();
429 : }
430 :
431 41841 : void MvpnManager::Terminate() {
432 41841 : CHECK_CONCURRENCY("bgp::Config");
433 :
434 : // Delete locally originated type-1 route.
435 41841 : MvpnRoute *type1_route = table_->FindType1ADRoute();
436 41841 : if (type1_route) {
437 41283 : BgpPath *path = type1_route->FindPath(BgpPath::Local, 0);
438 41283 : if (path)
439 41283 : type1_route->DeletePath(path);
440 41283 : type1_route->NotifyOrDelete();
441 : }
442 :
443 41841 : if (identifier_listener_id_ != -1) {
444 41841 : table_->server()->UnregisterIdentifierUpdateCallback(
445 : identifier_listener_id_);
446 41841 : identifier_listener_id_ = -1;
447 : }
448 41841 : table_->Unregister(listener_id_);
449 41841 : listener_id_ = DBTable::kInvalidId;
450 41841 : FreePartitions();
451 41841 : MVPN_LOG(MvpnManagerDelete, "Terminated MvpnManager");
452 41841 : }
453 :
454 64404 : void MvpnManager::ManagedDelete() {
455 64404 : deleter_->Delete();
456 64404 : }
457 :
458 41841 : void MvpnManager::AllocPartitions() {
459 83682 : for (int part_id = 0; part_id < table_->PartitionCount(); part_id++)
460 41841 : partitions_.push_back(new MvpnManagerPartition(this, part_id));
461 41841 : }
462 :
463 41841 : void MvpnManager::FreePartitions() {
464 83682 : for (size_t part_id = 0; part_id < partitions_.size(); part_id++) {
465 41841 : delete partitions_[part_id];
466 : }
467 41841 : partitions_.clear();
468 41841 : }
469 :
470 : // MvpnManager can be deleted only after all associated DB States are cleared.
471 42200 : bool MvpnManager::MayDelete() const {
472 42200 : if (!db_states_count_)
473 41841 : return true;
474 359 : MVPN_LOG(MvpnManagerDelete,
475 : "MvpnManager::MayDelete() paused due to pending " +
476 : integerToString(db_states_count_) + " MvpnDBStates");
477 359 : return false;
478 : }
479 :
480 : // Set DB State and update count.
481 14137 : void MvpnManager::SetDBState(MvpnRoute *route, MvpnDBState *mvpn_dbstate) {
482 14137 : route->SetState(table_, listener_id_, mvpn_dbstate);
483 14137 : db_states_count_++;
484 14137 : }
485 :
486 : // Create DB State and update count. If there is no DB State associated in the
487 : // table, resume table deletion if the deletion was pending.
488 14137 : void MvpnManager::ClearDBState(MvpnRoute *route) {
489 14137 : route->ClearState(table_, listener_id_);
490 14137 : assert(db_states_count_);
491 14137 : db_states_count_--;
492 :
493 : // Retry deletion now as there is no more attached db state in the table.
494 14137 : if (!db_states_count_ && deleter_->IsDeleted())
495 2835 : deleter_->RetryDelete();
496 14137 : }
497 :
498 365468 : MvpnTable *MvpnManagerPartition::table() {
499 365468 : return manager_->table();
500 : }
501 :
502 85307 : int MvpnManagerPartition::listener_id() const {
503 85307 : return manager_->listener_id();
504 : }
505 :
506 41841 : MvpnManagerPartition::MvpnManagerPartition(MvpnManager *manager, int part_id)
507 41841 : : manager_(manager), part_id_(part_id) {
508 41841 : }
509 :
510 83682 : MvpnManagerPartition::~MvpnManagerPartition() {
511 83682 : }
512 :
513 : MvpnProjectManagerPartition *
514 28679 : MvpnManagerPartition::GetProjectManagerPartition() {
515 28679 : MvpnProjectManager *project_manager = manager_->GetProjectManager();
516 28679 : return project_manager ? project_manager->GetPartition(part_id_) : NULL;
517 : }
518 :
519 : const MvpnProjectManagerPartition *
520 19652 : MvpnManagerPartition::GetProjectManagerPartition() const {
521 19652 : MvpnProjectManager *project_manager = manager_->GetProjectManager();
522 19652 : return project_manager ? project_manager->GetPartition(part_id_) : NULL;
523 : }
524 :
525 48331 : MvpnProjectManager *MvpnManager::GetProjectManager() {
526 48331 : return table_->GetProjectManager();
527 : }
528 :
529 8243 : int MvpnProjectManager::listener_id() const {
530 8243 : return listener_id_;
531 : }
532 :
533 8243 : int MvpnProjectManagerPartition::listener_id() const {
534 8243 : return manager_->listener_id();
535 : }
536 :
537 21967 : MvpnStatePtr MvpnManagerPartition::LocateState(MvpnRoute *rt) {
538 : MvpnProjectManagerPartition *project_manager_partition =
539 21967 : GetProjectManagerPartition();
540 21967 : assert(project_manager_partition);
541 21967 : MvpnState::SG sg = MvpnState::SG(rt->GetPrefix().sourceIpAddress(),
542 43934 : rt->GetPrefix().groupIpAddress());
543 43934 : return project_manager_partition->LocateState(sg);
544 : }
545 :
546 7436 : MvpnStatePtr MvpnManagerPartition::GetState(MvpnRoute *rt) const {
547 : const MvpnProjectManagerPartition *project_manager_partition =
548 7436 : GetProjectManagerPartition();
549 7436 : if (!project_manager_partition)
550 0 : return NULL;
551 7436 : MvpnState::SG sg = MvpnState::SG(rt->GetPrefix().sourceIpAddress(),
552 14872 : rt->GetPrefix().groupIpAddress());
553 7436 : return project_manager_partition->GetState(sg);
554 : }
555 :
556 7436 : MvpnStatePtr MvpnManagerPartition::GetState(MvpnRoute *rt) {
557 7436 : return static_cast<const MvpnManagerPartition *>(this)->GetState(rt);
558 : }
559 :
560 467057 : ErmVpnTable *MvpnProjectManager::table() {
561 467057 : return table_;
562 : }
563 :
564 11869 : const ErmVpnTable *MvpnProjectManager::table() const {
565 11869 : return table_;
566 : }
567 :
568 96217 : ErmVpnTable *MvpnProjectManagerPartition::table() {
569 96217 : return manager_->table();
570 : }
571 :
572 29624 : const ErmVpnTable *MvpnProjectManagerPartition::table() const {
573 29624 : return manager_->table();
574 : }
575 :
576 6712 : void MvpnProjectManagerPartition::NotifyForestNode(
577 : const Ip4Address &source, const Ip4Address &group) {
578 6712 : if (table()->tree_manager())
579 6712 : table()->tree_manager()->NotifyForestNode(part_id_, source, group);
580 6712 : }
581 :
582 6712 : void MvpnManagerPartition::NotifyForestNode(
583 : const Ip4Address &source, const Ip4Address &group) {
584 6712 : MvpnProjectManagerPartition *pm = GetProjectManagerPartition();
585 6712 : if (pm)
586 6712 : pm->NotifyForestNode(source, group);
587 6712 : }
588 :
589 12216 : bool MvpnProjectManagerPartition::GetForestNodePMSI(ErmVpnRoute *rt,
590 : uint32_t *label, Ip4Address *address, vector<string> *enc) const {
591 12216 : if (!table()->tree_manager())
592 0 : return false;
593 12216 : return table()->tree_manager()->GetForestNodePMSI(rt, label, address, enc);
594 : }
595 :
596 12216 : bool MvpnManagerPartition::GetForestNodePMSI(ErmVpnRoute *rt, uint32_t *label,
597 : Ip4Address *address, vector<string> *encap) const {
598 12216 : const MvpnProjectManagerPartition *pm = GetProjectManagerPartition();
599 12216 : return pm ? pm->GetForestNodePMSI(rt, label, address, encap) : false;
600 : }
601 :
602 : ////////////////////////////////////////////////////////////////////////////////
603 :
604 : // Initialize MvpnManager by allcating one MvpnManagerPartition for each DB
605 : // partition, and register a route listener for the MvpnTable.
606 41841 : void MvpnManager::Initialize() {
607 41841 : if (!table_->server()->mvpn_ipv4_enable())
608 0 : return;
609 :
610 41841 : assert(!table_->IsMaster());
611 41841 : AllocPartitions();
612 :
613 41841 : listener_id_ = table_->Register(
614 : boost::bind(&MvpnManager::RouteListener, this, _1, _2),
615 : "MvpnManager");
616 :
617 41841 : identifier_listener_id_ =
618 41841 : table_->server()->RegisterIdentifierUpdateCallback(boost::bind(
619 : &MvpnManager::ReOriginateType1Route, this, _1));
620 41841 : OriginateType1Route();
621 :
622 41841 : MVPN_LOG(MvpnManagerCreate, "Initialized MvpnManager");
623 : }
624 :
625 1170 : void MvpnManager::ReOriginateType1Route(const Ip4Address &old_identifier) {
626 : // Check if a path is already origianted. If so, delete it.
627 1170 : MvpnRoute *route = table_->FindType1ADRoute(old_identifier);
628 1170 : if (route) {
629 1170 : BgpPath *path = route->FindPath(BgpPath::Local, 0);
630 1170 : if (path) {
631 1170 : route->DeletePath(path);
632 1170 : route->NotifyOrDelete();
633 : }
634 : }
635 1170 : OriginateType1Route();
636 1170 : }
637 :
638 43011 : void MvpnManager::OriginateType1Route() {
639 : // Originate Type1 Intra AS Auto-Discovery path.
640 43011 : BgpServer *server = table_->server();
641 :
642 : // Check for the presence of valid identifier.
643 43011 : if (!table_->server()->bgp_identifier())
644 558 : return;
645 42453 : MvpnRoute *route = table_->LocateType1ADRoute();
646 42453 : BgpAttrSpec attr_spec;
647 42453 : BgpAttrNextHop nexthop(server->bgp_identifier());
648 42453 : attr_spec.push_back(&nexthop);
649 42453 : BgpAttrPtr attr = server->attr_db()->Locate(attr_spec);
650 42453 : BgpPath *path = new BgpPath(NULL, 0, BgpPath::Local, attr, 0, 0, 0);
651 42453 : route->InsertPath(path);
652 42453 : route->Notify();
653 :
654 : // TODO(Ananth) Originate Type2 Inter AS Auto-Discovery Route.
655 42453 : }
656 :
657 : // MvpnTable route listener callback function.
658 : //
659 : // Process changes (create/update/delete) to all different types of MvpnRoute.
660 250212 : void MvpnManager::RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry) {
661 250212 : CHECK_CONCURRENCY("db::DBTable");
662 :
663 250212 : MvpnRoute *route = dynamic_cast<MvpnRoute *>(db_entry);
664 250212 : assert(route);
665 :
666 250212 : MvpnManagerPartition *partition = partitions_[tpart->index()];
667 :
668 : // Process Type1 Intra-AS AD route.
669 250212 : if (route->GetPrefix().type() == MvpnPrefix::IntraASPMSIADRoute) {
670 164905 : ProcessType1ADRoute(route);
671 164905 : return;
672 : }
673 :
674 : // TODO(Ananth) Inter-AS Multiast Site AD.
675 :
676 : // Process Type3 S-PMSI route.
677 85307 : if (route->GetPrefix().type() == MvpnPrefix::SPMSIADRoute) {
678 40243 : partition->ProcessType3SPMSIRoute(route);
679 40243 : return;
680 : }
681 :
682 : // Process Type7 C-Join route.
683 45064 : if (route->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute) {
684 21761 : partition->ProcessType7SourceTreeJoinRoute(route);
685 21761 : return;
686 : }
687 :
688 : // Process Type5 Source Active route.
689 23303 : if (route->GetPrefix().type() == MvpnPrefix::SourceActiveADRoute) {
690 16383 : partition->ProcessType5SourceActiveRoute(route);
691 16383 : return;
692 : }
693 :
694 : // Process Type4 LeafAD route.
695 6920 : if (route->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
696 6920 : partition->ProcessType4LeafADRoute(route);
697 6920 : return;
698 : }
699 : }
700 :
701 : // Update MVPN neighbor list with create/delete/update of auto-discovery routes.
702 : //
703 : // Protect access to neighbors_ map with a mutex as the same be 'read' off other
704 : // DB tasks in parallel. (Type-1 and Type-2 do not carrry any <S,G> information)
705 164905 : void MvpnManager::ProcessType1ADRoute(MvpnRoute *route) {
706 164905 : RouteDistinguisher rd = route->GetPrefix().route_distinguisher();
707 :
708 : // Check if an entry is already present.
709 164905 : MvpnNeighbor old_neighbor;
710 164905 : bool found = FindNeighbor(rd, &old_neighbor);
711 :
712 164905 : if (!route->IsUsable()) {
713 14155 : if (!found)
714 1170 : return;
715 12985 : std::unique_lock<std::shared_mutex> lock(neighbors_mutex_);
716 12985 : MVPN_LOG(MvpnNeighborDelete, old_neighbor.rd().ToString(),
717 : old_neighbor.originator().to_string(),
718 : old_neighbor.source_as());
719 12985 : neighbors_.erase(rd);
720 12985 : return;
721 12985 : }
722 :
723 : // Ignore primary paths.
724 150750 : if (!route->BestPath()->IsReplicated())
725 102934 : return;
726 :
727 47816 : MvpnNeighbor neighbor(route->GetPrefix().route_distinguisher(),
728 95632 : route->GetPrefix().originator());
729 :
730 : // Ignore if there is no change.
731 47816 : if (found && old_neighbor == neighbor)
732 28711 : return;
733 :
734 19105 : std::unique_lock<std::shared_mutex> lock(neighbors_mutex_);
735 19105 : if (found)
736 0 : neighbors_.erase(rd);
737 19105 : neighbors_.insert(make_pair(rd, neighbor));
738 19105 : MVPN_LOG(MvpnNeighborCreate, neighbor.rd().ToString(),
739 : neighbor.originator().to_string(), neighbor.source_as());
740 19105 : }
741 :
742 : // Check whether an ErmVpnRoute is locally originated GlobalTreeRoute.
743 4529 : bool MvpnProjectManagerPartition::IsUsableGlobalTreeRootRoute(
744 : ErmVpnRoute *ermvpn_route) const {
745 4529 : if (!ermvpn_route || !ermvpn_route->IsUsable())
746 1933 : return NULL;
747 2596 : if (!table()->tree_manager())
748 0 : return false;
749 5192 : ErmVpnRoute *global_rt = table()->tree_manager()->GetGlobalTreeRootRoute(
750 2596 : ermvpn_route->GetPrefix().source(), ermvpn_route->GetPrefix().group());
751 2596 : return (global_rt && global_rt == ermvpn_route);
752 : }
753 :
754 : // ErmVpnTable route listener callback function.
755 : //
756 : // Process changes (create/update/delete) to GlobalErmVpnRoute in vrf.ermvpn.0
757 6008 : void MvpnProjectManager::RouteListener(DBTablePartBase *tpart,
758 : DBEntryBase *db_entry) {
759 6008 : CHECK_CONCURRENCY("db::DBTable");
760 6008 : MvpnProjectManagerPartition *partition = GetPartition(tpart->index());
761 6008 : partition->RouteListener(db_entry);
762 6008 : }
763 :
764 : // Process changes to ErmVpnRoutes. We only care about changes to routes of
765 : // type GlobalTreeRoute.
766 6008 : void MvpnProjectManagerPartition::RouteListener(DBEntryBase *db_entry) {
767 6008 : ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(db_entry);
768 6008 : assert(ermvpn_route);
769 :
770 : // We only care about global tree routes for mvpn stitching.
771 6008 : if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute)
772 3507 : return;
773 :
774 4529 : MvpnDBState *mvpn_dbstate = dynamic_cast<MvpnDBState *>(
775 4529 : ermvpn_route->GetState(table(), listener_id()));
776 :
777 : // Handle GlobalTreeRoute route deletion.
778 4529 : if (!IsUsableGlobalTreeRootRoute(ermvpn_route)) {
779 : // Ignore if there is no DB State associated with route.
780 2028 : if (!mvpn_dbstate)
781 171 : return;
782 1857 : MvpnStatePtr mvpn_state = mvpn_dbstate->state();
783 1857 : mvpn_state->set_global_ermvpn_tree_rt(NULL);
784 :
785 : // Notify all received Type3 spmsi routes for PMSI re-computation.
786 : // Since usable global ermvpn is no longer available, any advertised
787 : // type-4 lead-ad routes must now be withdrawn.
788 3087 : BOOST_FOREACH(MvpnRoute *route, mvpn_state->spmsi_routes_received()) {
789 615 : route->Notify();
790 : }
791 1857 : ermvpn_route->ClearState(table(), listener_id());
792 1857 : MVPN_ERMVPN_RT_LOG(ermvpn_route,
793 : "Processed MVPN GlobalErmVpnRoute deletion");
794 1857 : delete mvpn_dbstate;
795 1857 : return;
796 1857 : }
797 :
798 : // Set DB State in the route if not already done so before.
799 2501 : MvpnStatePtr mvpn_state;
800 2501 : if (!mvpn_dbstate) {
801 1857 : MvpnState::SG sg(ermvpn_route);
802 1857 : mvpn_state = LocateState(sg);
803 1857 : mvpn_dbstate = new MvpnDBState(mvpn_state);
804 1857 : ermvpn_route->SetState(table(), listener_id(), mvpn_dbstate);
805 : } else {
806 644 : mvpn_state = mvpn_dbstate->state();
807 : }
808 :
809 : // Note down current usable ermvpn route for stitching to mvpn.
810 2501 : mvpn_dbstate->state()->set_global_ermvpn_tree_rt(ermvpn_route);
811 :
812 : // Notify all originated Type3 spmsi routes for PMSI re-computation.
813 10835 : BOOST_FOREACH(MvpnRoute *route, mvpn_state->spmsi_routes_received()) {
814 4167 : route->Notify();
815 : }
816 :
817 2501 : MVPN_ERMVPN_RT_LOG(ermvpn_route,
818 : "Processed MVPN GlobalErmVpnRoute creation");
819 2501 : }
820 :
821 : // Process change to MVPN Type-5 SourceActive route.
822 16383 : void MvpnManagerPartition::ProcessType5SourceActiveRoute(MvpnRoute *rt) {
823 32766 : MvpnDBState *mvpn_dbstate = dynamic_cast<MvpnDBState *>(rt->GetState(
824 16383 : table(), listener_id()));
825 :
826 : // Process route change as delete if ProjectManager is not set.
827 16383 : bool is_usable = rt->IsUsable() && table()->IsProjectManagerUsable();
828 16383 : if (!is_usable) {
829 6657 : if (!mvpn_dbstate)
830 11876 : return;
831 :
832 : // Delete any associated type-3 s-pmsi route.
833 : MvpnRoute *spmsi_rt =
834 3307 : mvpn_dbstate->state() ? mvpn_dbstate->state()->spmsi_rt() : NULL;
835 3307 : if (spmsi_rt && spmsi_rt->IsUsable()) {
836 1926 : BgpPath *path = spmsi_rt->FindPath(BgpPath::Local, 0);
837 1926 : if (path)
838 1926 : spmsi_rt->DeletePath(path);
839 : }
840 :
841 3307 : mvpn_dbstate->set_route(NULL);
842 3307 : mvpn_dbstate->state()->set_source_active_rt(NULL);
843 3307 : mvpn_dbstate->state()->set_spmsi_rt(NULL);
844 3307 : if (spmsi_rt)
845 1926 : spmsi_rt->NotifyOrDelete();
846 3307 : manager_->ClearDBState(rt);
847 3307 : MVPN_RT_LOG(rt, "Processed MVPN Source Active route deletion");
848 3307 : delete mvpn_dbstate;
849 3307 : return;
850 : }
851 :
852 9726 : const BgpPath *path = rt->BestPath();
853 : // Here in the sender side, we only care about changes to the primary path.
854 9726 : if (path->IsReplicated())
855 3433 : return;
856 :
857 6293 : MvpnStatePtr state = LocateState(rt);
858 6293 : state->set_source_active_rt(rt);
859 :
860 : // Set DB State if not already done so.
861 6293 : if (!mvpn_dbstate) {
862 3307 : mvpn_dbstate = new MvpnDBState(state);
863 3307 : manager_->SetDBState(rt, mvpn_dbstate);
864 : }
865 :
866 : // Check if there is any receiver interested. If not, do not originate
867 : // type-3 spmsi route. Also, we originate Type3 S-PMSI route only if there
868 : // is an imported secondary path for the join route (i.e when the join
869 : // route reached the sender)
870 6293 : const MvpnRoute *join_rt = table()->FindType7SourceTreeJoinRoute(rt);
871 10800 : if (!join_rt || !join_rt->IsUsable() ||
872 4507 : !join_rt->BestPath()->IsReplicated()) {
873 : // Remove any type-3 spmsi path originated before.
874 1786 : MvpnRoute *spmsi_rt = mvpn_dbstate->route();
875 1786 : if (spmsi_rt) {
876 651 : assert(!state->spmsi_rt() || spmsi_rt == state->spmsi_rt());
877 651 : state->set_spmsi_rt(NULL);
878 651 : mvpn_dbstate->set_route(NULL);
879 651 : BgpPath *path = spmsi_rt->FindPath(BgpPath::Local, 0);
880 651 : if (path) {
881 651 : MVPN_RT_LOG(spmsi_rt, "Deleted already originated SPMSI path");
882 651 : spmsi_rt->DeletePath(path);
883 651 : spmsi_rt->NotifyOrDelete();
884 : }
885 : }
886 1786 : return;
887 : }
888 :
889 : // Originate Type-3 S-PMSI route to send towards the receivers.
890 4507 : MvpnRoute *spmsi_rt = table()->LocateType3SPMSIRoute(join_rt);
891 4507 : assert(spmsi_rt);
892 4507 : state->set_spmsi_rt(spmsi_rt);
893 4507 : if (!mvpn_dbstate->route()) {
894 2577 : mvpn_dbstate->set_route(spmsi_rt);
895 : } else {
896 1930 : assert(spmsi_rt == mvpn_dbstate->route());
897 1930 : BgpPath *path = spmsi_rt->FindPath(BgpPath::Local, 0);
898 1930 : assert(path);
899 :
900 : // Ignore if there is no change in the attributes.
901 1930 : if (path->GetAttr() == rt->BestPath()->GetAttr())
902 0 : return;
903 1930 : spmsi_rt->DeletePath(path);
904 : }
905 :
906 4507 : PmsiTunnelSpec pmsi_spec;
907 4507 : pmsi_spec.tunnel_flags = PmsiTunnelSpec::LeafInfoRequired;
908 4507 : BgpAttrDB *attr_db = table()->server()->attr_db();
909 : BgpAttrPtr new_attrp = attr_db->ReplacePmsiTunnelAndLocate(
910 4507 : rt->BestPath()->GetAttr(), &pmsi_spec);
911 :
912 : // Insert new path and notify.
913 : BgpPath *new_path = new BgpPath(NULL, 0, BgpPath::Local,
914 4507 : new_attrp, 0, 0, 0);
915 4507 : spmsi_rt->InsertPath(new_path);
916 4507 : spmsi_rt->Notify();
917 4507 : MVPN_RT_LOG(rt, "Processed MVPN Source Active route creation");
918 6293 : }
919 :
920 21761 : void MvpnManagerPartition::ProcessType7SourceTreeJoinRoute(MvpnRoute *join_rt) {
921 21761 : MvpnDBState *mvpn_dbstate = dynamic_cast<MvpnDBState *>(
922 21761 : join_rt->GetState(table(), listener_id()));
923 :
924 : // Process route change as delete if ProjectManager is not set.
925 21761 : bool is_usable = join_rt->IsUsable() && table()->IsProjectManagerUsable();
926 21761 : if (!is_usable) {
927 10957 : if (!mvpn_dbstate)
928 18421 : return;
929 :
930 : // Notify associatd source-active route so that any s-pmsi route if
931 : // originated before can be withdrawn as there is no more active join
932 : // route (receiver) for this <S,G>.
933 3304 : if (mvpn_dbstate->state()->source_active_rt())
934 651 : mvpn_dbstate->state()->source_active_rt()->Notify();
935 3304 : manager_->ClearDBState(join_rt);
936 3304 : MVPN_RT_LOG(join_rt, "Processed Type 7 Join route deletion");
937 3304 : delete mvpn_dbstate;
938 3304 : return;
939 : }
940 :
941 : // We care only for imported secondary type-7 joins (at the sender).
942 10804 : if (!join_rt->BestPath()->IsReplicated())
943 7464 : return;
944 :
945 3340 : MvpnStatePtr state = LocateState(join_rt);
946 3340 : if (!mvpn_dbstate) {
947 3304 : mvpn_dbstate = new MvpnDBState(state);
948 3304 : manager_->SetDBState(join_rt, mvpn_dbstate);
949 : }
950 :
951 : // A join has been received or updated at the sender. Re-evaluate the
952 : // type5 source active, if one such route is present.
953 3340 : if (state->source_active_rt()) {
954 2155 : state->source_active_rt()->Notify();
955 2155 : MVPN_RT_LOG(join_rt, "Processed Type 7 Join route creation and "
956 : "notified Source Active route");
957 : } else {
958 1185 : MVPN_RT_LOG(join_rt, "Processed Type 7 Join route creation");
959 : }
960 3340 : }
961 :
962 6920 : void MvpnManagerPartition::ProcessType4LeafADRoute(MvpnRoute *leaf_ad) {
963 6920 : MvpnDBState *mvpn_dbstate = dynamic_cast<MvpnDBState *>(
964 6920 : leaf_ad->GetState(table(), listener_id()));
965 : // Process route change as delete if ProjectManager is not set.
966 6920 : bool is_usable = leaf_ad->IsUsable() && table()->IsProjectManagerUsable();
967 6920 : if (!is_usable) {
968 3138 : if (!mvpn_dbstate)
969 6802 : return;
970 90 : assert(mvpn_dbstate->state()->leafad_routes_attr_received().
971 : erase(leaf_ad));
972 90 : MvpnRoute *sa_active_rt = mvpn_dbstate->state()->source_active_rt();
973 :
974 : // Re-evaluate type5 route as secondary type4 leafad route is deleted.
975 : // olist needs to be updated and sent to the sender route agent.
976 90 : if (sa_active_rt && sa_active_rt->IsUsable()) {
977 63 : sa_active_rt->Notify();
978 63 : MVPN_RT_LOG(leaf_ad, "Processed Type 4 LeafAD route deletion"
979 : " and notified type5 source active route");
980 : } else {
981 27 : MVPN_RT_LOG(leaf_ad, "Processed Type 4 LeafAD route deletion");
982 : }
983 90 : manager_->ClearDBState(leaf_ad);
984 90 : delete mvpn_dbstate;
985 90 : return;
986 : }
987 :
988 3782 : const BgpPath *path = leaf_ad->BestPath();
989 3782 : if (!path->IsReplicated())
990 3664 : return;
991 :
992 : // Secondary leaft-ad path has been imported.
993 118 : MvpnStatePtr state = LocateState(leaf_ad);
994 118 : if (!mvpn_dbstate) {
995 90 : mvpn_dbstate = new MvpnDBState(state);
996 90 : manager_->SetDBState(leaf_ad, mvpn_dbstate);
997 : }
998 :
999 : pair<MvpnState::RoutesMap::iterator, bool> result =
1000 236 : state->leafad_routes_attr_received().insert(make_pair(leaf_ad,
1001 118 : leaf_ad->BestPath()->GetAttr()));
1002 :
1003 : // Overwrite the entry with new best path attributes if one already exists.
1004 118 : if (!result.second) {
1005 : // Ignore if there is no change in the best path's attributes.
1006 28 : if (result.first->second.get() == leaf_ad->BestPath()->GetAttr())
1007 0 : return;
1008 28 : result.first->second = leaf_ad->BestPath()->GetAttr();
1009 : }
1010 :
1011 : // Update the sender source-active route to update the olist.
1012 118 : MvpnRoute *sa_active_rt = mvpn_dbstate->state()->source_active_rt();
1013 118 : if (sa_active_rt && sa_active_rt->IsUsable()) {
1014 118 : sa_active_rt->Notify();
1015 118 : MVPN_RT_LOG(sa_active_rt, "Processed Type 4 Leaf AD route creation"
1016 : " and Type-5 source active route was notified");
1017 : } else {
1018 0 : MVPN_RT_LOG(sa_active_rt, "Processed Type 4 Leaf AD route creation");
1019 : }
1020 118 : }
1021 :
1022 : // Process changes to Type3 S-PMSI routes by originating or deleting Type4 Leaf
1023 : // AD paths as appropriate.
1024 40243 : void MvpnManagerPartition::ProcessType3SPMSIRoute(MvpnRoute *spmsi_rt) {
1025 : // Retrieve any state associcated with this S-PMSI route.
1026 40243 : MvpnDBState *mvpn_dbstate = dynamic_cast<MvpnDBState *>(
1027 40243 : spmsi_rt->GetState(table(), listener_id()));
1028 :
1029 40243 : MvpnRoute *leaf_ad_route = NULL;
1030 : // Process route change as delete if ProjectManager is not set.
1031 40243 : bool is_usable = spmsi_rt->IsUsable() && table()->IsProjectManagerUsable();
1032 40243 : if (!is_usable) {
1033 17944 : if (!mvpn_dbstate)
1034 10508 : return;
1035 7436 : MvpnStatePtr mvpn_state = GetState(spmsi_rt);
1036 7436 : assert(mvpn_dbstate->state() == mvpn_state);
1037 :
1038 : // Check if a Type4 LeafAD path was already originated before for this
1039 : // S-PMSI path. If so, delete it as the S-PMSI path is no nonger usable.
1040 7436 : leaf_ad_route = mvpn_dbstate->route();
1041 7436 : if (leaf_ad_route) {
1042 2435 : BgpPath *path = leaf_ad_route->FindPath(BgpPath::Local, 0);
1043 2435 : if (path)
1044 2435 : leaf_ad_route->DeletePath(path);
1045 2435 : mvpn_dbstate->set_route(NULL);
1046 : }
1047 :
1048 7436 : assert(mvpn_state->spmsi_routes_received().erase(spmsi_rt));
1049 7436 : manager_->ClearDBState(spmsi_rt);
1050 7436 : delete mvpn_dbstate;
1051 7436 : if (leaf_ad_route) {
1052 2435 : leaf_ad_route->NotifyOrDelete();
1053 :
1054 : // Forest node route needs to be updated to delete the source
1055 : // address if advertised before.
1056 2435 : NotifyForestNode(spmsi_rt->GetPrefix().source(),
1057 2435 : spmsi_rt->GetPrefix().group());
1058 2435 : MVPN_RT_LOG(spmsi_rt, "Processed Type 3 S-PMSI route deletion"
1059 : " and notified local ForestNode");
1060 : } else {
1061 5001 : MVPN_RT_LOG(spmsi_rt, "Processed Type 3 S-PMSI route deletion");
1062 : }
1063 7436 : return;
1064 7436 : }
1065 :
1066 : // Ignore notifications of primary S-PMSI paths.
1067 22299 : if (!spmsi_rt->BestPath()->IsReplicated())
1068 4507 : return;
1069 :
1070 : // Don't send Type 4 route if there is no receiver in this vrf
1071 17792 : const MvpnRoute *join_rt = table()->FindType7SourceTreeJoinRoute(spmsi_rt);
1072 17792 : if (!join_rt || !join_rt->IsUsable())
1073 5576 : return;
1074 :
1075 : // A valid S-PMSI path has been imported to a table. Originate a new
1076 : // LeafAD path, if GlobalErmVpnTreeRoute is available to stitch.
1077 : // TODO(Ananth) If LeafInfoRequired bit is not set in the S-PMSI route,
1078 : // then we do not need to originate a leaf ad route for this s-pmsi rt.
1079 12216 : MvpnStatePtr mvpn_state = LocateState(spmsi_rt);
1080 12216 : assert(mvpn_state);
1081 12216 : if (!mvpn_dbstate) {
1082 7436 : mvpn_dbstate = new MvpnDBState(mvpn_state);
1083 7436 : manager_->SetDBState(spmsi_rt, mvpn_dbstate);
1084 7436 : assert(mvpn_state->spmsi_routes_received().insert(spmsi_rt).second);
1085 : } else {
1086 4780 : leaf_ad_route = mvpn_dbstate->route();
1087 : }
1088 :
1089 : // If LeafInfoRequired bit is not set, no need to process further
1090 24432 : if (!spmsi_rt->BestPath()->GetAttr()->pmsi_tunnel() ||
1091 12216 : (!(spmsi_rt->BestPath()->GetAttr()->pmsi_tunnel()->tunnel_flags() &
1092 : PmsiTunnelSpec::LeafInfoRequired))) {
1093 0 : MVPN_RT_LOG(spmsi_rt, "No need to process Type 3 S-PMSI route as"
1094 : " LeafInfoRequired bit is not set");
1095 0 : return;
1096 : }
1097 :
1098 12216 : ErmVpnRoute *global_rt = mvpn_state->global_ermvpn_tree_rt();
1099 : uint32_t label;
1100 12216 : Ip4Address address;
1101 12216 : vector<string> tunnel_encaps;
1102 : bool pmsi_found =
1103 12216 : GetForestNodePMSI(global_rt, &label, &address, &tunnel_encaps);
1104 :
1105 12216 : if (!pmsi_found) {
1106 : // There is no ermvpn route available to stitch at this time. Remove any
1107 : // originated Type4 LeafAD route. DB State shall remain on the route as
1108 : // SPMSI route itself is still a usable route.
1109 7964 : if (leaf_ad_route) {
1110 613 : BgpPath *path = leaf_ad_route->FindPath(BgpPath::Local, 0);
1111 613 : if (path)
1112 613 : leaf_ad_route->DeletePath(path);
1113 613 : mvpn_dbstate->set_route(NULL);
1114 613 : leaf_ad_route->NotifyOrDelete();
1115 613 : NotifyForestNode(spmsi_rt->GetPrefix().source(),
1116 613 : spmsi_rt->GetPrefix().group());
1117 613 : MVPN_RT_LOG(spmsi_rt, "Processed Type 3 S-PMSI route as deletion"
1118 : " and notified local ForestNode due to missing PMSI");
1119 : }
1120 7964 : return;
1121 : }
1122 :
1123 4252 : if (!leaf_ad_route) {
1124 3048 : leaf_ad_route = table()->LocateType4LeafADRoute(spmsi_rt);
1125 3048 : mvpn_dbstate->set_route(leaf_ad_route);
1126 : }
1127 4252 : BgpPath *old_path = leaf_ad_route->FindPath(BgpPath::Local, 0);
1128 :
1129 : // For LeafAD routes, rtarget is always <sender-router-id>:0.
1130 4252 : BgpAttrPtr attrp = BgpAttrPtr(spmsi_rt->BestPath()->GetAttr());
1131 4252 : ExtCommunity::ExtCommunityList rtarget;
1132 8504 : rtarget.push_back(RouteTarget(spmsi_rt->GetPrefix().originator(), 0).
1133 4252 : GetExtCommunity());
1134 4252 : ExtCommunityPtr ext_community = table()->server()->extcomm_db()->
1135 4252 : ReplaceRTargetAndLocate(attrp->ext_community(), rtarget);
1136 :
1137 4252 : ExtCommunity::ExtCommunityList tunnel_encaps_list;
1138 12484 : BOOST_FOREACH(string encap, tunnel_encaps) {
1139 4116 : tunnel_encaps_list.push_back(TunnelEncap(encap).GetExtCommunity());
1140 4116 : }
1141 :
1142 4252 : ext_community = table()->server()->extcomm_db()->
1143 8504 : ReplaceTunnelEncapsulationAndLocate(ext_community.get(),
1144 4252 : tunnel_encaps_list);
1145 :
1146 8504 : attrp = table()->server()->attr_db()->ReplaceExtCommunityAndLocate(
1147 4252 : attrp.get(), ext_community);
1148 :
1149 : // Retrieve PMSI tunnel attribute from the GlobalErmVpnTreeRoute.
1150 4252 : PmsiTunnelSpec pmsi_spec;
1151 4252 : pmsi_spec.tunnel_flags = 0;
1152 4252 : pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication;
1153 4252 : pmsi_spec.SetLabel(label, ext_community.get());
1154 4252 : pmsi_spec.SetIdentifier(address);
1155 :
1156 : // Replicate the LeafAD path with appropriate PMSI tunnel info as part of
1157 : // the path attributes. Community should be route-target with root ingress
1158 : // PE router-id + 0 (Page 254).
1159 : BgpAttrPtr new_attrp =
1160 4252 : table()->server()->attr_db()->ReplacePmsiTunnelAndLocate(attrp.get(),
1161 4252 : &pmsi_spec);
1162 :
1163 : // Ignore if there is no change in the path attributes of already originated
1164 : // leaf ad path.
1165 4252 : if (old_path && old_path->GetAttr() == new_attrp.get())
1166 588 : return;
1167 :
1168 3664 : BgpPath *path = new BgpPath(NULL, 0, BgpPath::Local, new_attrp, 0, 0, 0);
1169 3664 : if (old_path)
1170 616 : leaf_ad_route->DeletePath(old_path);
1171 3664 : leaf_ad_route->InsertPath(path);
1172 3664 : leaf_ad_route->NotifyOrDelete();
1173 3664 : NotifyForestNode(spmsi_rt->GetPrefix().source(),
1174 3664 : spmsi_rt->GetPrefix().group());
1175 3664 : MVPN_RT_LOG(spmsi_rt, "Processed Type 3 S-PMSI route creation");
1176 24296 : }
1177 :
1178 121 : void MvpnManager::UpdateSecondaryTablesForReplication(MvpnRoute *mvpn_rt,
1179 : BgpTable::TableSet *secondary_tables) const {
1180 : // Find the right MvpnProjectManagerPartition based on the rt's partition.
1181 : const MvpnProjectManagerPartition *partition =
1182 121 : table()->GetProjectManagerPartition(mvpn_rt);
1183 121 : if (!partition)
1184 0 : return;
1185 :
1186 : // Retrieve MVPN state. Ignore if there is no state or if there is no usable
1187 : // Type3 SPMSI route 0associated with it (perhaps it was deleted already).
1188 121 : MvpnState::SG sg(mvpn_rt);
1189 121 : MvpnStatePtr state = partition->GetState(sg);
1190 121 : if (!state || !state->spmsi_rt() || !state->spmsi_rt()->IsUsable())
1191 0 : return;
1192 :
1193 : // Matching Type-3 S-PMSI route was found. Return its table.
1194 121 : BgpTable *table = dynamic_cast<BgpTable *>(
1195 121 : state->spmsi_rt()->get_table_partition()->parent());
1196 121 : assert(table);
1197 :
1198 : // Update table list to let replicator invoke RouteReplicate() for this
1199 : // LeafAD route for this table which has the corresponding Type3 SPMSI
1200 : // route. This was originated as the 'Sender' since receiver joined to
1201 : // the <C-S,G> group.
1202 121 : secondary_tables->insert(table);
1203 121 : MVPN_RT_LOG(mvpn_rt, "Updated tables for replication with table " +
1204 : table->name());
1205 121 : }
1206 :
1207 : // Return source_address of the type-3 s-pmsi route used for rpf check in the
1208 : // forest node.
1209 381 : void MvpnProjectManager::GetMvpnSourceAddress(ErmVpnRoute *ermvpn_route,
1210 : Ip4Address *addrp) const {
1211 : // Bail if project manager is deleted.
1212 381 : if (deleter_->IsDeleted())
1213 194 : return;
1214 :
1215 : // Bail if there is no state for this <S,G>.
1216 381 : MvpnStatePtr state = GetState(ermvpn_route);
1217 381 : if (!state)
1218 8 : return;
1219 :
1220 : // Bail if there is no usable global_ermvpn_tree_rt.
1221 740 : if (!state->global_ermvpn_tree_rt() ||
1222 367 : !state->global_ermvpn_tree_rt()->IsUsable()) {
1223 6 : return;
1224 : }
1225 :
1226 : // Bail if there is no s-pmsi route received (no active sender)
1227 367 : if (state->spmsi_routes_received().empty())
1228 180 : return;
1229 :
1230 : // Use mvpn type3 spmsi route originator address as the source address.
1231 187 : *addrp = (*(state->spmsi_routes_received().begin()))->
1232 187 : GetPrefix().originator();
1233 187 : MVPN_ERMVPN_RT_LOG(ermvpn_route, "Found Source Address for RPF Check " +
1234 : addrp->to_string());
1235 381 : }
1236 :
1237 113 : UpdateInfo *MvpnProjectManager::GetType7UpdateInfo(MvpnRoute *route) {
1238 113 : BgpAttrPtr attr = route->BestPath()->GetAttr();
1239 113 : UpdateInfo *uinfo = new UpdateInfo;
1240 113 : uinfo->roattr = RibOutAttr(table(), route, attr.get(), 0, false, true);
1241 113 : return uinfo;
1242 113 : }
1243 :
1244 424 : UpdateInfo *MvpnProjectManager::GetUpdateInfo(MvpnRoute *route) {
1245 424 : assert((route->GetPrefix().type() == MvpnPrefix::SourceActiveADRoute) ||
1246 : (route->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute));
1247 :
1248 424 : if (route->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute)
1249 113 : return GetType7UpdateInfo(route);
1250 311 : MvpnStatePtr state = GetState(route);
1251 :
1252 : // If there is no imported leaf-ad route, then essentially there is no
1253 : // olist that can be formed. Route can be withdrawn if already advertised.
1254 311 : if (!state || state->leafad_routes_attr_received().empty())
1255 158 : return NULL;
1256 :
1257 : // Retrieve olist element from each of the imported type-4 leaf-ad route.
1258 153 : BgpOListSpec olist_spec(BgpAttribute::OList);
1259 459 : BOOST_FOREACH(MvpnState::RoutesMap::value_type &iter,
1260 : state->leafad_routes_attr_received()) {
1261 153 : BgpAttrPtr attr = iter.second;
1262 153 : const PmsiTunnel *pmsi = attr->pmsi_tunnel();
1263 153 : if (!pmsi)
1264 0 : continue;
1265 153 : if (pmsi->tunnel_type() != PmsiTunnelSpec::IngressReplication)
1266 0 : continue;
1267 153 : const ExtCommunity *extcomm = attr->ext_community();
1268 153 : uint32_t label = attr->pmsi_tunnel()->GetLabel(extcomm);
1269 153 : if (!label)
1270 0 : continue;
1271 306 : BgpOListElem elem(pmsi->identifier(), label,
1272 306 : extcomm ? extcomm->GetTunnelEncap() : vector<string>());
1273 153 : olist_spec.elements.push_back(elem);
1274 153 : MVPN_RT_LOG(route, "Encoded olist " + pmsi->pmsi_tunnel().ToString());
1275 153 : }
1276 :
1277 153 : if (olist_spec.elements.empty())
1278 0 : return NULL;
1279 :
1280 153 : BgpAttrDB *attr_db = table()->server()->attr_db();
1281 : BgpAttrPtr attr = attr_db->ReplaceOListAndLocate(
1282 153 : route->BestPath()->GetAttr(), &olist_spec);
1283 153 : UpdateInfo *uinfo = new UpdateInfo;
1284 153 : uinfo->roattr = RibOutAttr(table(), route, attr.get(), 0, false, true);
1285 153 : return uinfo;
1286 311 : }
|