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