Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/routing-instance/routepath_replicator.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <utility>
10 :
11 : #include "base/set_util.h"
12 : #include "base/task_annotations.h"
13 : #include "base/task_trigger.h"
14 : #include "bgp/bgp_config.h"
15 : #include "bgp/bgp_log.h"
16 : #include "bgp/bgp_route.h"
17 : #include "bgp/bgp_server.h"
18 : #include "bgp/origin-vn/origin_vn.h"
19 : #include "bgp/routing-instance/path_resolver.h"
20 : #include "bgp/routing-instance/routing_instance.h"
21 : #include "bgp/routing-instance/rtarget_group_mgr.h"
22 : #include "bgp/routing-instance/routing_instance_analytics_types.h"
23 :
24 : using std::ostringstream;
25 : using std::make_pair;
26 : using std::pair;
27 : using std::string;
28 : using std::vector;
29 :
30 : //
31 : // RoutePathReplication trace macro. Optionally logs the server name as well for
32 : // easier debugging in multi server unit tests
33 : //
34 : #define RPR_TRACE(obj, ...) \
35 : do { \
36 : if (LoggingDisabled()) break; \
37 : bgp_log_test::LogServerName(server()); \
38 : Rpr##obj##Log::Send("RoutingInstance", \
39 : SandeshLevel::SYS_DEBUG, __FILE__, __LINE__, __VA_ARGS__); \
40 : Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__); \
41 : } while (false)
42 :
43 : #define RPR_TRACE_ONLY(obj, ...) \
44 : do { \
45 : if (LoggingDisabled()) break; \
46 : bgp_log_test::LogServerName(server()); \
47 : Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__); \
48 : } while (false)
49 :
50 : class TableState::DeleteActor : public LifetimeActor {
51 : public:
52 254211 : explicit DeleteActor(TableState *ts)
53 254211 : : LifetimeActor(ts->replicator()->server()->lifetime_manager()),
54 254211 : ts_(ts) {
55 254211 : }
56 :
57 254294 : virtual bool MayDelete() const {
58 254294 : return ts_->MayDelete();
59 : }
60 :
61 254215 : virtual void Shutdown() {
62 254215 : }
63 :
64 254215 : virtual void Destroy() {
65 254215 : ts_->replicator()->DeleteTableState(ts_->table());
66 254215 : }
67 :
68 : private:
69 : TableState *ts_;
70 : };
71 :
72 254210 : TableState::TableState(RoutePathReplicator *replicator, BgpTable *table)
73 254210 : : replicator_(replicator),
74 254210 : table_(table),
75 254210 : listener_id_(DBTableBase::kInvalidId),
76 254210 : deleter_(new DeleteActor(this)),
77 254208 : table_delete_ref_(this, table->deleter()) {
78 254182 : assert(table->deleter() != NULL);
79 254180 : }
80 :
81 254215 : TableState::~TableState() {
82 254215 : if (walk_ref() != NULL) {
83 22605 : table()->ReleaseWalker(walk_ref());
84 : }
85 254215 : }
86 :
87 254215 : void TableState::ManagedDelete() {
88 254215 : deleter()->Delete();
89 254215 : }
90 :
91 0 : bool TableState::deleted() const {
92 0 : return deleter()->IsDeleted();
93 : }
94 :
95 901727 : LifetimeActor *TableState::deleter() {
96 901727 : return deleter_.get();
97 : }
98 :
99 0 : const LifetimeActor *TableState::deleter() const {
100 0 : return deleter_.get();
101 : }
102 :
103 254294 : bool TableState::MayDelete() const {
104 531214 : if (list_.empty() && !route_count() &&
105 276920 : ((walk_ref() == NULL) || !walk_ref()->walk_is_active()))
106 254215 : return true;
107 79 : return false;
108 : }
109 :
110 628517 : void TableState::RetryDelete() {
111 628517 : if (!deleter()->IsDeleted())
112 609483 : return;
113 18998 : deleter()->RetryDelete();
114 : }
115 :
116 668155 : void TableState::AddGroup(RtGroup *group) {
117 668155 : list_.insert(group);
118 668307 : }
119 :
120 668402 : void TableState::RemoveGroup(RtGroup *group) {
121 668402 : list_.erase(group);
122 668405 : }
123 :
124 429467 : const RtGroup *TableState::FindGroup(RtGroup *group) const {
125 429467 : GroupList::const_iterator it = list_.find(group);
126 429454 : return (it != list_.end() ? *it : NULL);
127 : }
128 :
129 254305 : uint32_t TableState::route_count() const {
130 254305 : return table_->GetDBStateCount(listener_id());
131 : }
132 :
133 1038960 : RtReplicated::RtReplicated(RoutePathReplicator *replicator)
134 1038960 : : replicator_(replicator) {
135 1038952 : }
136 :
137 517217 : void RtReplicated::AddRouteInfo(BgpTable *table, BgpRoute *rt,
138 : ReplicatedRtPathList::const_iterator it) {
139 517217 : pair<ReplicatedRtPathList::iterator, bool> result;
140 517217 : result = replicate_list_.insert(*it);
141 517234 : assert(result.second);
142 517234 : }
143 :
144 516602 : void RtReplicated::DeleteRouteInfo(BgpTable *table, BgpRoute *rt,
145 : ReplicatedRtPathList::const_iterator it) {
146 516602 : replicator_->DeleteSecondaryPath(table, rt, *it);
147 516956 : replicate_list_.erase(it);
148 517020 : }
149 :
150 : //
151 : // Return the list of secondary table names for the given primary path.
152 : // We go through all SecondaryRouteInfos and skip the ones that don't
153 : // match the primary path.
154 : //
155 281 : vector<string> RtReplicated::GetTableNameList(const BgpPath *path) const {
156 281 : vector<string> table_list;
157 1367 : BOOST_FOREACH(const SecondaryRouteInfo &rinfo, replicate_list_) {
158 543 : if (rinfo.peer_ != path->GetPeer())
159 0 : continue;
160 543 : if (rinfo.path_id_ != path->GetPathId())
161 16 : continue;
162 527 : if (rinfo.src_ != path->GetSource())
163 0 : continue;
164 527 : table_list.push_back(rinfo.table_->name());
165 : }
166 281 : return table_list;
167 0 : }
168 :
169 48710 : RoutePathReplicator::RoutePathReplicator(BgpServer *server,
170 48710 : Address::Family family)
171 48710 : : server_(server),
172 48710 : family_(family),
173 48710 : vpn_table_(NULL),
174 48710 : trace_buf_(SandeshTraceBufferCreate("RoutePathReplicator", 500)) {
175 48710 : }
176 :
177 97420 : RoutePathReplicator::~RoutePathReplicator() {
178 48710 : assert(table_state_list_.empty());
179 97420 : }
180 :
181 41135 : void RoutePathReplicator::Initialize() {
182 41135 : assert(!vpn_table_);
183 41135 : RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
184 41135 : assert(mgr);
185 41135 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
186 41135 : assert(master);
187 41135 : vpn_table_ = master->GetTable(family_);
188 41135 : assert(vpn_table_);
189 41135 : assert(AddTableState(vpn_table_));
190 41135 : }
191 :
192 709447 : TableState *RoutePathReplicator::AddTableState(BgpTable *table,
193 : RtGroup *group) {
194 709447 : assert(table->IsVpnTable() || group);
195 :
196 709427 : TableStateList::iterator loc = table_state_list_.find(table);
197 709223 : if (loc == table_state_list_.end()) {
198 254199 : TableState *ts = new TableState(this, table);
199 254180 : DBTableBase::ListenerId id = table->Register(
200 : boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
201 : "RoutePathReplicator");
202 254168 : ts->set_listener_id(id);
203 254167 : if (group)
204 213032 : ts->AddGroup(group);
205 254191 : table_state_list_.insert(make_pair(table, ts));
206 254195 : RPR_TRACE(RegTable, table->name());
207 254196 : return ts;
208 : } else {
209 455148 : assert(group);
210 455148 : TableState *ts = loc->second;
211 455141 : ts->AddGroup(group);
212 455286 : return ts;
213 : }
214 : }
215 :
216 668403 : void RoutePathReplicator::RemoveTableState(BgpTable *table, RtGroup *group) {
217 668403 : TableState *ts = FindTableState(table);
218 668402 : assert(ts);
219 668402 : ts->RemoveGroup(group);
220 668405 : }
221 :
222 254215 : void RoutePathReplicator::DeleteTableState(BgpTable *table) {
223 254215 : TableState *ts = FindTableState(table);
224 254215 : assert(ts);
225 254215 : RPR_TRACE(UnregTable, table->name());
226 254215 : table->Unregister(ts->listener_id());
227 254215 : table_state_list_.erase(table);
228 254215 : delete ts;
229 254215 : }
230 :
231 1858396 : TableState *RoutePathReplicator::FindTableState(BgpTable *table) {
232 1858396 : TableStateList::iterator loc = table_state_list_.find(table);
233 1858334 : return (loc != table_state_list_.end() ? loc->second : NULL);
234 : }
235 :
236 5640 : const TableState *RoutePathReplicator::FindTableState(
237 : const BgpTable *table) const {
238 : TableStateList::const_iterator loc =
239 5640 : table_state_list_.find(const_cast<BgpTable *>(table));
240 5635 : return (loc != table_state_list_.end() ? loc->second : NULL);
241 : }
242 :
243 : void
244 51311 : RoutePathReplicator::RequestWalk(BgpTable *table) {
245 51311 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
246 51311 : TableState *ts = FindTableState(table);
247 51311 : assert(ts);
248 51311 : if (!ts->walk_ref()) {
249 : DBTable::DBTableWalkRef walk_ref = table->AllocWalker(
250 : boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
251 45209 : boost::bind(&RoutePathReplicator::BulkReplicationDone, this, _2));
252 22604 : table->WalkTable(walk_ref);
253 22605 : ts->set_walk_ref(walk_ref);
254 22605 : } else {
255 28706 : table->WalkAgain(ts->walk_ref());
256 : }
257 51311 : }
258 :
259 : void
260 24583 : RoutePathReplicator::BulkReplicationDone(DBTableBase *dbtable) {
261 24583 : CHECK_CONCURRENCY("db::Walker");
262 24583 : BgpTable *table = static_cast<BgpTable *>(dbtable);
263 24583 : RPR_TRACE(WalkDone, table->name());
264 24583 : TableState *ts = FindTableState(table);
265 24583 : ts->RetryDelete();
266 24583 : }
267 :
268 429893 : void RoutePathReplicator::JoinVpnTable(RtGroup *group) {
269 429893 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
270 429923 : TableState *vpn_ts = FindTableState(vpn_table_);
271 429837 : if (!vpn_ts || vpn_ts->FindGroup(group))
272 370 : return;
273 429442 : RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), true);
274 429586 : group->AddImportTable(family(), vpn_table_);
275 429731 : RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), false);
276 429721 : group->AddExportTable(family(), vpn_table_);
277 429731 : AddTableState(vpn_table_, group);
278 : }
279 :
280 429950 : void RoutePathReplicator::LeaveVpnTable(RtGroup *group) {
281 429950 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
282 429950 : TableState *vpn_ts = FindTableState(vpn_table_);
283 429950 : if (!vpn_ts)
284 185 : return;
285 429765 : RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), true);
286 429765 : group->RemoveImportTable(family(), vpn_table_);
287 429762 : RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), false);
288 429762 : group->RemoveExportTable(family(), vpn_table_);
289 429763 : RemoveTableState(vpn_table_, group);
290 : }
291 :
292 : //
293 : // Add a given BgpTable to RtGroup of given RouteTarget.
294 : // It will create a new RtGroup if none exists.
295 : // In case of export RouteTarget, create TableState if it doesn't exist.
296 : //
297 927867 : void RoutePathReplicator::Join(BgpTable *table, const RouteTarget &rt,
298 : bool import) {
299 927867 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
300 :
301 927565 : std::scoped_lock lock(mutex_);
302 928355 : RPR_TRACE(TableJoin, table->name(), rt.ToString(), import);
303 :
304 928345 : bool first = false;
305 928345 : RtGroup *group = server()->rtarget_group_mgr()->LocateRtGroup(rt);
306 928599 : if (import) {
307 689959 : first = group->AddImportTable(family(), table);
308 689943 : if (group->HasDepRoutes())
309 95 : server()->rtarget_group_mgr()->NotifyRtGroup(rt);
310 689873 : if (family_ == Address::INETVPN)
311 137994 : server_->NotifyAllStaticRoutes();
312 1339424 : BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
313 324769 : if (sec_table->IsVpnTable() || sec_table->empty())
314 323550 : continue;
315 1208 : RequestWalk(sec_table);
316 : }
317 : } else {
318 238640 : first = group->AddExportTable(family(), table);
319 238640 : AddTableState(table, group);
320 238619 : if (!table->empty()) {
321 58 : RequestWalk(table);
322 : }
323 : }
324 :
325 : // Join the vpn table when group is created.
326 928118 : if (first)
327 429892 : JoinVpnTable(group);
328 928321 : }
329 :
330 : //
331 : // Remove a BgpTable from RtGroup of given RouteTarget.
332 : // If the last group is going away, the RtGroup will be removed
333 : // In case of export RouteTarget, trigger remove of TableState appropriate.
334 : //
335 928609 : void RoutePathReplicator::Leave(BgpTable *table, const RouteTarget &rt,
336 : bool import) {
337 928609 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
338 :
339 928609 : std::scoped_lock lock(mutex_);
340 928609 : RtGroup *group = server()->rtarget_group_mgr()->GetRtGroup(rt);
341 928610 : assert(group);
342 928610 : RPR_TRACE(TableLeave, table->name(), rt.ToString(), import);
343 :
344 928610 : if (import) {
345 689970 : group->RemoveImportTable(family(), table);
346 689964 : if (group->HasDepRoutes())
347 132265 : server()->rtarget_group_mgr()->NotifyRtGroup(rt);
348 689964 : if (family_ == Address::INETVPN)
349 137994 : server_->NotifyAllStaticRoutes();
350 2673875 : BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
351 991952 : if (sec_table->IsVpnTable() || sec_table->empty())
352 965090 : continue;
353 26867 : RequestWalk(sec_table);
354 : }
355 : } else {
356 238640 : group->RemoveExportTable(family(), table);
357 238640 : RemoveTableState(table, group);
358 238640 : if (!table->empty()) {
359 23153 : RequestWalk(table);
360 : }
361 : }
362 :
363 : // Leave the vpn table when the last VRF has left the group.
364 928609 : if (!group->HasVrfTables(family())) {
365 429950 : LeaveVpnTable(group);
366 429950 : server()->rtarget_group_mgr()->RemoveRtGroup(rt);
367 : }
368 928609 : }
369 :
370 1427506 : void RoutePathReplicator::DBStateSync(BgpTable *table, TableState *ts,
371 : BgpRoute *rt, RtReplicated *dbstate,
372 : const RtReplicated::ReplicatedRtPathList *future) {
373 1427506 : set_synchronize(dbstate->GetMutableList(), future,
374 : boost::bind(&RtReplicated::AddRouteInfo, dbstate, table, rt, _1),
375 : boost::bind(&RtReplicated::DeleteRouteInfo, dbstate, table, rt, _1));
376 :
377 1427338 : if (dbstate->GetList().empty()) {
378 1039071 : rt->ClearState(table, ts->listener_id());
379 1039245 : delete dbstate;
380 1039104 : if (table->GetDBStateCount(ts->listener_id()) == 0)
381 603944 : ts->RetryDelete();
382 : }
383 1427526 : }
384 :
385 225621 : static ExtCommunityPtr UpdateOriginVn(BgpServer *server,
386 : const ExtCommunity *ext_community,
387 : int vn_index) {
388 225621 : as_t asn = server->autonomous_system();
389 225619 : ExtCommunityPtr extcomm_ptr;
390 225619 : if (vn_index) {
391 54139 : if (asn > AS2_MAX && vn_index > 0xffff) {
392 0 : OriginVn origin_vn(asn, AS_TRANS);
393 0 : extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
394 0 : ext_community, origin_vn.GetExtCommunity());
395 0 : OriginVn origin_vn2(AS_TRANS, vn_index);
396 0 : extcomm_ptr = server->extcomm_db()->AppendAndLocate(
397 0 : extcomm_ptr.get(), origin_vn2.GetExtCommunity());
398 0 : } else {
399 54139 : OriginVn origin_vn(asn, vn_index);
400 162422 : extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
401 108282 : ext_community, origin_vn.GetExtCommunity());
402 54144 : return extcomm_ptr;
403 : }
404 : }
405 171480 : extcomm_ptr = server->extcomm_db()->RemoveOriginVnAndLocate(ext_community);
406 171498 : return extcomm_ptr;
407 0 : }
408 :
409 : //
410 : // Update the ExtCommunity with the RouteTargets from the export list
411 : // and the OriginVn. The OriginVn is derived from the RouteTargets in
412 : // vpn routes.
413 : //
414 518287 : static ExtCommunityPtr UpdateExtCommunity(BgpServer *server,
415 : const RoutingInstance *rtinstance, const ExtCommunity *ext_community,
416 : const ExtCommunity::ExtCommunityList &export_list) {
417 : // Add RouteTargets exported by the instance for a non-master instance.
418 518287 : ExtCommunityPtr extcomm_ptr;
419 518287 : if (!rtinstance->IsMasterRoutingInstance()) {
420 : extcomm_ptr =
421 322908 : server->extcomm_db()->AppendAndLocate(ext_community, export_list);
422 322966 : return extcomm_ptr;
423 : }
424 :
425 : // Bail if we have a vpn route without extended communities.
426 195382 : if (!ext_community)
427 1051 : return ExtCommunityPtr(NULL);
428 :
429 : // Nothing to do if we already have the OriginVn community with our AS
430 : // or with a vn index from the global range.
431 3454173 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
432 : ext_community->communities()) {
433 1646677 : if (!ExtCommunity::is_origin_vn(comm))
434 1629941 : continue;
435 18712 : OriginVn origin_vn(comm);
436 37426 : if (!origin_vn.IsGlobal() &&
437 18713 : origin_vn.as_number() != server->autonomous_system()) {
438 1995 : continue;
439 : }
440 16718 : return ExtCommunityPtr(ext_community);
441 : }
442 :
443 : // Add the OriginVn if we have a valid vn index.
444 : int vn_index =
445 177628 : server->routing_instance_mgr()->GetVnIndexByExtCommunity(ext_community);
446 177692 : return UpdateOriginVn(server, ext_community, vn_index);
447 518451 : }
448 :
449 : //
450 : // Concurrency: Called in the context of the DB partition task.
451 : //
452 : // This function handles
453 : // 1. Table Notification for path replication
454 : // 2. Table walk for import/export of new targets
455 : //
456 : // Replicate a path (clone the BgpPath) to secondary BgpTables based on the
457 : // export targets of the primary BgpTable.
458 : // If primary table is a VRF table attach it's export targets to replicated
459 : // path in the VPN table.
460 : //
461 1986589 : bool RoutePathReplicator::RouteListener(TableState *ts,
462 : DBTablePartBase *root, DBEntryBase *entry) {
463 1986589 : CHECK_CONCURRENCY("db::DBTable");
464 :
465 1986354 : BgpTable *table = static_cast<BgpTable *>(root->parent());
466 1986331 : BgpRoute *rt = static_cast<BgpRoute *>(entry);
467 1986331 : const RoutingInstance *rtinstance = table->routing_instance();
468 :
469 1986330 : DBTableBase::ListenerId id = ts->listener_id();
470 1986286 : assert(id != DBTableBase::kInvalidId);
471 :
472 : // Get the DBState.
473 : RtReplicated *dbstate =
474 1986286 : static_cast<RtReplicated *>(rt->GetState(table, id));
475 1987790 : RtReplicated::ReplicatedRtPathList replicated_path_list;
476 :
477 : //Flag to track if any change happenned to route in last 30 minutes
478 1987205 : bool route_unchanged = false;
479 : //List of tables that needs replication of route
480 1987205 : RtGroup::RtGroupMemberList addedTables;
481 : //List of tables that doesn't need replication of route
482 1986614 : RtGroup::RtGroupMemberList deletedTables;
483 : //List of tables having the latest changes in route
484 1986349 : RtGroup::RtGroupMemberList previousTables;
485 : //Threshold used for optimised replication
486 1986289 : uint64_t optimizationThresholdTime = 30ULL * 60 * 1000000;
487 1986289 : uint64_t start = UTCTimestampUsec();
488 :
489 : //Optimize only if last route change occurred 30 mins before.
490 : //We update the route_unchanged flag to true
491 1987745 : if ( (start - rt->last_update_at() > optimizationThresholdTime) &&
492 : dbstate != NULL)
493 : {
494 101 : RPR_TRACE(RouteListener, "Route change occurred before threshold \
495 : time, optimising replication");
496 101 : route_unchanged = true;
497 : }
498 :
499 : //
500 : // Cleanup if the route is not usable.
501 : // If route aggregation is enabled, contributing route/more specific route
502 : // for a aggregate route will NOT be replicated to destination table
503 : //
504 2450295 : if (!rt->IsUsable() || (table->IsRouteAggregationSupported() &&
505 462815 : !rtinstance->deleted() &&
506 459791 : table->IsContributingRoute(rt))) {
507 716903 : if (!dbstate) {
508 560119 : return true;
509 : }
510 156784 : DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
511 156919 : return true;
512 : }
513 :
514 : // Create and set new DBState on the route. This will get cleaned up via
515 : // via the call to DBStateSync if we don't need to replicate the route to
516 : // any tables.
517 1270084 : if (dbstate == NULL) {
518 1038981 : dbstate = new RtReplicated(this);
519 1038945 : rt->SetState(table, id, dbstate);
520 : }
521 :
522 : // Get the export route target list from the routing instance.
523 1270281 : ExtCommunity::ExtCommunityList export_list;
524 1270310 : if (!rtinstance->IsMasterRoutingInstance()) {
525 5801974 : BOOST_FOREACH(RouteTarget rtarget, rtinstance->GetExportList()) {
526 2493463 : export_list.push_back(rtarget.GetExtCommunity());
527 : }
528 : }
529 :
530 : // Updating previousTables with the list of tables having the information
531 : // about the route.
532 1270208 : if (route_unchanged){
533 101 : replicated_path_list = dbstate->GetList();
534 321 : BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
535 : replicated_path_list){
536 110 : previousTables.insert(path.table_);
537 : }
538 : }
539 :
540 : // Replicate all feasible and non-replicated paths.
541 1270208 : for (Route::PathList::iterator it = rt->GetPathList().begin();
542 6058915 : it != rt->GetPathList().end(); ++it) {
543 1765182 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
544 :
545 : // Skip if the source peer is down.
546 2598383 : if (!path->IsStale() && !path->IsLlgrStale() && path->GetPeer() &&
547 832870 : !path->GetPeer()->IsReady())
548 1272509 : continue;
549 :
550 : // No need to replicate aliased or replicated paths.
551 1669777 : if (path->IsReplicated() || path->IsAliased())
552 1145253 : continue;
553 :
554 : // Do not replicate non-ecmp paths.
555 524514 : if (rt->BestPath()->PathCompare(*path, true))
556 6206 : break;
557 :
558 : // Do not replicate if nexthop is not hitched by ermvpn tree.
559 518294 : if (path->CheckErmVpn())
560 0 : break;
561 :
562 518290 : const BgpAttr *attr = path->GetAttr();
563 518290 : const ExtCommunity *ext_community = attr->ext_community();
564 :
565 : ExtCommunityPtr extcomm_ptr =
566 518292 : UpdateExtCommunity(server(), rtinstance, ext_community, export_list);
567 518450 : ext_community = extcomm_ptr.get();
568 518450 : if (!ext_community)
569 1052 : continue;
570 :
571 : // Go through all extended communities.
572 : //
573 : // Get the vn_index from the OriginVn extended community.
574 : // For each RouteTarget extended community, get the list of tables
575 : // to which we need to replicate the path.
576 517398 : int vn_index = 0;
577 517398 : RtGroup::RtGroupMemberList secondary_tables;
578 6037698 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
579 : ext_community->communities()) {
580 2760115 : if (ExtCommunity::is_origin_vn(comm)) {
581 79726 : OriginVn origin_vn(comm);
582 79726 : vn_index = origin_vn.vn_index();
583 2680327 : } else if (ExtCommunity::is_route_target(comm)) {
584 : RtGroup *group =
585 2219258 : server()->rtarget_group_mgr()->GetRtGroup(comm);
586 2219576 : if (!group)
587 673360 : continue;
588 : RtGroup::RtGroupMemberList import_list =
589 2217508 : group->GetImportTables(family());
590 2217332 : if (import_list.empty())
591 671296 : continue;
592 1546030 : secondary_tables.insert(import_list.begin(), import_list.end());
593 2217265 : }
594 : }
595 :
596 : // Update with family specific secondary tables.
597 517381 : table->UpdateSecondaryTablesForReplication(rt, &secondary_tables);
598 :
599 : // Skip if we don't need to replicate the path to any tables.
600 517376 : if (secondary_tables.empty())
601 30520 : continue;
602 :
603 : // Add OriginVn when replicating self-originated routes from a VRF.
604 407311 : if (!vn_index && !rtinstance->IsMasterRoutingInstance() &&
605 894163 : path->IsVrfOriginated() && rtinstance->virtual_network_index()) {
606 47557 : vn_index = rtinstance->virtual_network_index();
607 47556 : extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(), vn_index);
608 : }
609 :
610 486853 : if (route_unchanged){
611 103 : addedTables = RtGroup::RtGroupMemberList();
612 : // Finding the difference between sets, secondary_tables and
613 : // previousTables
614 103 : std::set_difference(secondary_tables.begin(), secondary_tables.end(),
615 : previousTables.begin(), previousTables.end(),
616 : std::inserter(addedTables, addedTables.end()));
617 103 : std::set_difference(previousTables.begin(), previousTables.end(),
618 : secondary_tables.begin(), secondary_tables.end(),
619 : std::inserter(deletedTables, deletedTables.end()));
620 347 : BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
621 : dbstate->GetList()){
622 122 : if (deletedTables.find(path.table_)!=deletedTables.end()) {
623 1 : replicated_path_list.erase(path);
624 : }
625 : }
626 : //Updating the secondary tables with the difference.
627 103 : secondary_tables = addedTables;
628 :
629 : }
630 :
631 :
632 : // Replicate path to all destination tables.
633 3731789 : BOOST_FOREACH(BgpTable *dest, secondary_tables) {
634 : // Skip if destination is same as source table.
635 1622429 : if (dest == table)
636 670033 : continue;
637 :
638 1135709 : const RoutingInstance *dest_rtinstance = dest->routing_instance();
639 1135718 : ExtCommunityPtr new_extcomm_ptr = extcomm_ptr;
640 :
641 : // If the origin vn is unresolved, see if route has a RouteTarget
642 : // that's in the set of export RouteTargets for the dest instance.
643 : // If so, we set the origin vn for the replicated route to be the
644 : // vn for the dest instance.
645 1136418 : if (!vn_index && dest_rtinstance->virtual_network_index() &&
646 468 : dest_rtinstance->HasExportTarget(ext_community)) {
647 368 : int dest_vn_index = dest_rtinstance->virtual_network_index();
648 736 : new_extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(),
649 368 : dest_vn_index);
650 : }
651 :
652 : // Replicate the route to the destination table. The destination
653 : // table may decide to not replicate based on it's own policy e.g.
654 : // multicast routes are never leaked across routing-instances.
655 1135909 : BgpRoute *replicated_rt = dest->RouteReplicate(
656 : server_, table, rt, path, new_extcomm_ptr);
657 1135956 : if (!replicated_rt)
658 183317 : continue;
659 :
660 : // Add information about the secondary path to the replicated path
661 : // list.
662 952605 : RtReplicated::SecondaryRouteInfo rtinfo(dest, path->GetPeer(),
663 1905231 : path->GetPathId(), path->GetSource(), replicated_rt);
664 952585 : pair<RtReplicated::ReplicatedRtPathList::iterator, bool> result;
665 952562 : result = replicated_path_list.insert(rtinfo);
666 : // Assert if the insertion to replication path list fails
667 952595 : if (!route_unchanged)
668 952594 : assert(result.second);
669 952595 : RPR_TRACE_ONLY(Replicate, table->name(), rt->ToString(),
670 : path->ToString(),
671 : BgpPath::PathIdString(path->GetPathId()),
672 : dest->name(), replicated_rt->ToString());
673 1135958 : }
674 548971 : }
675 :
676 : // Update the DBState to reflect the new list of secondary paths. The
677 : // DBState will get cleared if the list is empty.
678 1270274 : DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
679 1270589 : return true;
680 1987627 : }
681 173 : const RtReplicated *RoutePathReplicator::GetReplicationState(
682 : BgpTable *table, BgpRoute *rt) const {
683 173 : const TableState *ts = FindTableState(table);
684 173 : if (!ts)
685 0 : return NULL;
686 : RtReplicated *dbstate =
687 173 : static_cast<RtReplicated *>(rt->GetState(table, ts->listener_id()));
688 173 : return dbstate;
689 : }
690 :
691 : //
692 : // Return the list of secondary table names for the given primary path.
693 : //
694 5467 : vector<string> RoutePathReplicator::GetReplicatedTableNameList(
695 : const BgpTable *table, const BgpRoute *rt, const BgpPath *path) const {
696 5467 : const TableState *ts = FindTableState(table);
697 5462 : if (!ts)
698 5160 : return vector<string>();
699 : const RtReplicated *dbstate = static_cast<const RtReplicated *>(
700 302 : rt->GetState(table, ts->listener_id()));
701 302 : if (!dbstate)
702 21 : return vector<string>();
703 281 : return dbstate->GetTableNameList(path);
704 : }
705 :
706 516693 : void RoutePathReplicator::DeleteSecondaryPath(BgpTable *table, BgpRoute *rt,
707 : const RtReplicated::SecondaryRouteInfo &rtinfo) {
708 516693 : BgpRoute *rt_secondary = rtinfo.rt_;
709 516693 : BgpTable *secondary_table = rtinfo.table_;
710 516693 : const IPeer *peer = rtinfo.peer_;
711 516693 : uint32_t path_id = rtinfo.path_id_;
712 516693 : BgpPath::PathSource src = rtinfo.src_;
713 :
714 : DBTablePartBase *partition =
715 516693 : secondary_table->GetTablePartition(rt_secondary);
716 516701 : BgpPath *secondary_path = rt_secondary->FindSecondaryPath(rt, src,
717 : peer, path_id);
718 516728 : if (secondary_path && secondary_path->NeedsResolution()) {
719 0 : secondary_table->path_resolver()->StopPathResolution(partition->index(),
720 : secondary_path);
721 : }
722 516713 : assert(rt_secondary->RemoveSecondaryPath(rt, src, peer, path_id));
723 516891 : if (rt_secondary->count() == 0) {
724 492938 : RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
725 : peer ? peer->ToString() : "Nil",
726 : BgpPath::PathIdString(path_id), table->name(),
727 : rt->ToString(), "Delete");
728 493208 : partition->Delete(rt_secondary);
729 : } else {
730 23842 : partition->Notify(rt_secondary);
731 23847 : RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
732 : peer ? peer->ToString() : "Nil",
733 : BgpPath::PathIdString(path_id), table->name(),
734 : rt->ToString(), "Path update");
735 : }
736 516943 : }
737 :
738 0 : string RtReplicated::SecondaryRouteInfo::ToString() const {
739 0 : ostringstream out;
740 0 : out << table_->name() << "(" << table_ << ")" << ":" <<
741 0 : peer_->ToString() << "(" << peer_ << ")" << ":" <<
742 0 : rt_->ToString() << "(" << rt_ << ")";
743 0 : return out.str();
744 0 : }
|