Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/mvpn/mvpn_table.h"
6 :
7 : #include <utility>
8 : #include <boost/foreach.hpp>
9 :
10 : #include "base/task_annotations.h"
11 : #include "bgp/ermvpn/ermvpn_table.h"
12 : #include "bgp/extended-community/source_as.h"
13 : #include "bgp/ipeer.h"
14 : #include "bgp/bgp_factory.h"
15 : #include "bgp/bgp_log.h"
16 : #include "bgp/bgp_multicast.h"
17 : #include "bgp/bgp_mvpn.h"
18 : #include "bgp/bgp_server.h"
19 : #include "bgp/bgp_update.h"
20 : #include "bgp/inet/inet_table.h"
21 : #include "bgp/origin-vn/origin_vn.h"
22 : #include "bgp/routing-instance/path_resolver.h"
23 : #include "bgp/routing-instance/routing_instance.h"
24 : #include "bgp/routing-instance/routing_instance_analytics_types.h"
25 : #include "bgp/routing-instance/routing_instance_log.h"
26 :
27 : using std::unique_ptr;
28 : using std::pair;
29 : using std::string;
30 : using std::set;
31 :
32 1769458 : size_t MvpnTable::HashFunction(const MvpnPrefix &prefix) const {
33 2324168 : if ((prefix.type() == MvpnPrefix::IntraASPMSIADRoute) ||
34 554709 : (prefix.type() == MvpnPrefix::LeafADRoute)) {
35 1269400 : uint32_t data = prefix.originator().to_ulong();
36 1269400 : return boost::hash_value(data);
37 : }
38 500058 : if (prefix.type() == MvpnPrefix::InterASPMSIADRoute) {
39 10 : uint32_t data = prefix.asn();
40 10 : return boost::hash_value(data);
41 : }
42 500048 : return boost::hash_value(prefix.group().to_ulong());
43 : }
44 :
45 51133 : MvpnTable::MvpnTable(DB *db, const string &name)
46 51133 : : BgpTable(db, name), manager_(NULL) {
47 51134 : }
48 :
49 42907 : PathResolver *MvpnTable::CreatePathResolver() {
50 42907 : if (routing_instance()->IsMasterRoutingInstance())
51 0 : return NULL;
52 42907 : PathResolver * path_resolver = new PathResolver(this);
53 42907 : path_resolver->set_nexthop_longest_match(true);
54 42907 : return path_resolver;
55 : }
56 :
57 83529 : unique_ptr<DBEntry> MvpnTable::AllocEntry(
58 : const DBRequestKey *key) const {
59 83529 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
60 83529 : return unique_ptr<DBEntry> (new MvpnRoute(pfxkey->prefix));
61 : }
62 :
63 49 : unique_ptr<DBEntry> MvpnTable::AllocEntryStr(
64 : const string &key_str) const {
65 49 : MvpnPrefix prefix = MvpnPrefix::FromString(key_str);
66 98 : return unique_ptr<DBEntry> (new MvpnRoute(prefix));
67 49 : }
68 :
69 1769458 : size_t MvpnTable::Hash(const DBEntry *entry) const {
70 1769458 : const MvpnRoute *rt_entry = static_cast<const MvpnRoute *>(entry);
71 1769458 : const MvpnPrefix &mvpnprefix = rt_entry->GetPrefix();
72 1769458 : size_t value = MvpnTable::HashFunction(mvpnprefix);
73 1769456 : return value % kPartitionCount;
74 : }
75 :
76 40302 : size_t MvpnTable::Hash(const DBRequestKey *key) const {
77 40302 : const RequestKey *rkey = static_cast<const RequestKey *>(key);
78 40302 : Ip4Prefix prefix(rkey->prefix.group(), 32);
79 40302 : size_t value = InetTable::HashFunction(prefix);
80 40302 : return value % kPartitionCount;
81 : }
82 :
83 40135 : BgpRoute *MvpnTable::TableFind(DBTablePartition *rtp,
84 : const DBRequestKey *prefix) {
85 40135 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
86 40135 : MvpnRoute rt_key(pfxkey->prefix);
87 80270 : return static_cast<BgpRoute *>(rtp->Find(&rt_key));
88 40135 : }
89 :
90 51134 : DBTableBase *MvpnTable::CreateTable(DB *db, const string &name) {
91 51134 : MvpnTable *table = new MvpnTable(db, name);
92 51134 : table->Init();
93 51134 : return table;
94 : }
95 :
96 59328 : void MvpnTable::CreateManager() {
97 59328 : if (manager_)
98 12600 : return;
99 :
100 : // Don't create the MvpnManager if ProjectManager is not present.
101 46728 : MvpnProjectManager *pm = GetProjectManager();
102 46728 : if (!pm)
103 4887 : return;
104 41841 : manager_ = BgpStaticObjectFactory::Create<MvpnManager>(this, pm->table());
105 41841 : manager_->Initialize();
106 :
107 : // Notify all routes in the table for further evaluation.
108 41841 : NotifyAllEntries();
109 :
110 : // TODO(Ananth): Should we also notify routes in the bgp.mvpn.0 table ?
111 : }
112 :
113 41841 : void MvpnTable::DestroyManager() {
114 41841 : if (!manager_)
115 0 : return;
116 41841 : if (IsDeleted())
117 22563 : DeleteMvpnManager();
118 41841 : manager_->Terminate();
119 41841 : delete manager_;
120 41841 : manager_ = NULL;
121 : }
122 :
123 51134 : void MvpnTable::CreateMvpnManagers() {
124 51134 : if (!server()->mvpn_ipv4_enable())
125 38545 : return;
126 22563 : RoutingInstance *rtinstance = routing_instance();
127 22563 : std::scoped_lock lock(rtinstance->manager()->mutex());
128 :
129 : // Don't create the MvpnManager for the VPN table.
130 45126 : if (!rtinstance->IsMasterRoutingInstance() &&
131 22563 : !rtinstance->mvpn_project_manager_network().empty()) {
132 : pair<MvpnProjectManagerNetworks::iterator, bool> ret =
133 45126 : rtinstance->manager()->mvpn_project_managers().insert(make_pair(
134 45126 : rtinstance->mvpn_project_manager_network(), set<string>()));
135 22563 : ret.first->second.insert(rtinstance->name());
136 :
137 : // Initialize MVPN Manager.
138 22563 : CreateManager();
139 : }
140 :
141 : MvpnProjectManagerNetworks::iterator iter =
142 45126 : rtinstance->manager()->mvpn_project_managers().find(
143 22563 : rtinstance->name());
144 22563 : if (iter == rtinstance->manager()->mvpn_project_managers().end())
145 9974 : return;
146 :
147 86119 : BOOST_FOREACH(const string &mvpn_network, iter->second) {
148 : RoutingInstance *rti =
149 36765 : rtinstance->manager()->GetRoutingInstance(mvpn_network);
150 36765 : if (!rti || rti->deleted())
151 0 : continue;
152 : MvpnTable *table =
153 36765 : dynamic_cast<MvpnTable *>(rti->GetTable(Address::MVPN));
154 36765 : if (!table || table->IsDeleted())
155 0 : continue;
156 36765 : table->CreateManager();
157 : }
158 22563 : }
159 :
160 22563 : void MvpnTable::DeleteMvpnManager() {
161 22563 : if (!server()->mvpn_ipv4_enable())
162 0 : return;
163 22563 : if (routing_instance()->mvpn_project_manager_network().empty())
164 0 : return;
165 22563 : std::scoped_lock lock(routing_instance()->manager()->mutex());
166 : MvpnProjectManagerNetworks::iterator iter =
167 45126 : routing_instance()->manager()->mvpn_project_managers().find(
168 22563 : routing_instance()->mvpn_project_manager_network());
169 22563 : if (iter != routing_instance()->manager()->mvpn_project_managers().end()) {
170 22563 : iter->second.erase(routing_instance()->name());
171 22563 : if (iter->second.empty())
172 6163 : routing_instance()->manager()->mvpn_project_managers().erase(iter);
173 : }
174 22563 : }
175 :
176 : // Call the const version to avoid code duplication.
177 97493 : MvpnProjectManager *MvpnTable::GetProjectManager() {
178 : return const_cast<MvpnProjectManager *>(
179 97493 : static_cast<const MvpnTable *>(this)->GetProjectManager());
180 : }
181 :
182 : // Get MvpnProjectManager object for this Mvpn. Each MVPN network is associated
183 : // with a parent project maanger network via configuration. MvpnProjectManager
184 : // is retrieved from this parent network RoutingInstance's ErmVpnTable.
185 97614 : const MvpnProjectManager *MvpnTable::GetProjectManager() const {
186 97614 : std::string pm_network = routing_instance()->mvpn_project_manager_network();
187 97614 : if (pm_network.empty())
188 0 : return NULL;
189 : const RoutingInstance *rtinstance =
190 97614 : routing_instance()->manager()->GetRoutingInstance(pm_network);
191 97614 : if (!rtinstance)
192 4887 : return NULL;
193 92727 : const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
194 92727 : rtinstance->GetTable(Address::ERMVPN));
195 92727 : if (!table)
196 0 : return NULL;
197 92727 : return table->mvpn_project_manager();
198 97614 : }
199 :
200 64826 : bool MvpnTable::IsProjectManagerUsable() const {
201 64826 : std::string pm_network = routing_instance()->mvpn_project_manager_network();
202 64826 : if (pm_network.empty())
203 0 : return false;
204 : const RoutingInstance *rtinstance =
205 64826 : routing_instance()->manager()->GetRoutingInstance(pm_network);
206 64826 : if (!rtinstance || rtinstance->deleted())
207 18215 : return false;
208 46611 : const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
209 46611 : rtinstance->GetTable(Address::ERMVPN));
210 46611 : if (!table || table->IsDeleted())
211 0 : return false;
212 :
213 93222 : if (!table->mvpn_project_manager() ||
214 46611 : table->mvpn_project_manager()->deleter()->IsDeleted()) {
215 0 : return false;
216 : }
217 46611 : return true;
218 64826 : }
219 :
220 : // Return the MvpnProjectManagerPartition for this route using the same DB
221 : // partition index as of the route.
222 121 : const MvpnProjectManagerPartition *MvpnTable::GetProjectManagerPartition(
223 : BgpRoute *route) const {
224 121 : const MvpnProjectManager *manager = GetProjectManager();
225 121 : if (!manager)
226 0 : return NULL;
227 121 : int part_id = route->get_table_partition()->index();
228 121 : return manager->GetPartition(part_id);
229 : }
230 :
231 : // Override virtual method to retrive target table for MVPN routes. For now,
232 : // only Type-4 LeafAD routes require special treatment, as they always come
233 : // with the same route target <router-id>:0. Hence, if normal rtf selection
234 : // mode is used, every table with MVPN enalbled would have to be notified for
235 : // replication. Instead, find the table based on the correspondong S-PMSI route.
236 : // This route can be retrieved from the MVPN state of the <S-G> maintained in
237 : // the MvpnProjectManagerPartition object.
238 196695 : void MvpnTable::UpdateSecondaryTablesForReplication(BgpRoute *rt,
239 : TableSet *secondary_tables) {
240 196695 : MvpnRoute *mvpn_rt = dynamic_cast<MvpnRoute *>(rt);
241 196695 : assert(mvpn_rt);
242 :
243 : // Special table lookup is required only for the Type4 LeafAD routes.
244 196695 : if (mvpn_rt->GetPrefix().type() != MvpnPrefix::LeafADRoute)
245 196574 : return;
246 :
247 : // Find Type-3 S-PMSI route from the Type-4 prefix route.
248 3776 : MvpnPrefix spmsi_prefix;
249 3776 : spmsi_prefix.SetSPMSIPrefixFromLeafADPrefix(mvpn_rt->GetPrefix());
250 3776 : const MvpnRoute *spmsi_rt = FindRoute(spmsi_prefix);
251 3776 : if (!spmsi_rt || !spmsi_rt->IsUsable())
252 0 : return;
253 3776 : if (!spmsi_rt->BestPath()->IsReplicated())
254 1 : return;
255 :
256 3775 : const BgpTable *table = dynamic_cast<const BgpSecondaryPath *>(
257 7550 : spmsi_rt->BestPath())->src_table();
258 3775 : const MvpnTable *mvpn_table = dynamic_cast<const MvpnTable *>(table);
259 3775 : if (!mvpn_table || mvpn_table->IsMaster() || !mvpn_table->manager())
260 3654 : return;
261 121 : mvpn_table->manager()->UpdateSecondaryTablesForReplication(
262 : mvpn_rt, secondary_tables);
263 3776 : }
264 :
265 : // Find or create the route.
266 82301 : MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) {
267 82301 : MvpnRoute rt_key(prefix);
268 : DBTablePartition *rtp = static_cast<DBTablePartition *>(
269 82301 : GetTablePartition(&rt_key));
270 164602 : return dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
271 82301 : }
272 :
273 24085 : const MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) const {
274 24085 : MvpnRoute rt_key(prefix);
275 : const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
276 24085 : GetTablePartition(&rt_key));
277 48170 : return dynamic_cast<const MvpnRoute *>(rtp->Find(&rt_key));
278 24085 : }
279 :
280 : // Find or create the route.
281 50008 : MvpnRoute *MvpnTable::LocateRoute(const MvpnPrefix &prefix) {
282 50008 : MvpnRoute rt_key(prefix);
283 : DBTablePartition *rtp = static_cast<DBTablePartition *>(
284 50008 : GetTablePartition(&rt_key));
285 50008 : MvpnRoute *dest_route = dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
286 50008 : if (dest_route == NULL) {
287 48078 : dest_route = new MvpnRoute(prefix);
288 48078 : rtp->Add(dest_route);
289 : } else {
290 1930 : dest_route->ClearDelete();
291 : }
292 50008 : return dest_route;
293 50008 : }
294 :
295 3049 : MvpnPrefix MvpnTable::CreateType4LeafADRoutePrefix(const MvpnRoute *type3_rt) {
296 3049 : assert(type3_rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute);
297 3049 : const Ip4Address originator_ip(server()->bgp_identifier());
298 3049 : MvpnPrefix prefix(MvpnPrefix::LeafADRoute, originator_ip);
299 3049 : prefix.SetLeafADPrefixFromSPMSIPrefix(type3_rt->GetPrefix());
300 6098 : return prefix;
301 0 : }
302 :
303 3048 : MvpnRoute *MvpnTable::LocateType4LeafADRoute(const MvpnRoute *type3_spmsi_rt) {
304 3048 : MvpnPrefix prefix = CreateType4LeafADRoutePrefix(type3_spmsi_rt);
305 6096 : return LocateRoute(prefix);
306 3048 : }
307 :
308 4508 : MvpnPrefix MvpnTable::CreateType3SPMSIRoutePrefix(const MvpnRoute *type7_rt) {
309 4508 : assert(type7_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute);
310 4508 : const RouteDistinguisher rd = type7_rt->GetPrefix().route_distinguisher();
311 4508 : Ip4Address source = type7_rt->GetPrefix().source();
312 4508 : Ip4Address group = type7_rt->GetPrefix().group();
313 4508 : const Ip4Address originator_ip(server()->bgp_identifier());
314 : MvpnPrefix prefix(MvpnPrefix::SPMSIADRoute, rd, originator_ip,
315 4508 : group, source);
316 9016 : return prefix;
317 : }
318 :
319 17792 : MvpnPrefix MvpnTable::CreateLocalType7Prefix(MvpnRoute *rt) const {
320 17792 : const RouteDistinguisher rd = RouteDistinguisher::kZeroRd;
321 17792 : Ip4Address source = rt->GetPrefix().source();
322 17792 : Ip4Address group = rt->GetPrefix().group();
323 : MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
324 17792 : 0, group, source);
325 35584 : return prefix;
326 : }
327 :
328 6293 : MvpnPrefix MvpnTable::CreateType7SourceTreeJoinRoutePrefix(
329 : MvpnRoute *rt) const {
330 : // get the source-rd from attributes as we store type-5 route with zero-rd
331 6293 : const BgpAttr *attr = rt->BestPath()->GetAttr();
332 6293 : assert(attr);
333 6293 : assert(!attr->source_rd().IsZero());
334 6293 : const RouteDistinguisher rd = attr->source_rd();
335 6293 : Ip4Address source = rt->GetPrefix().source();
336 6293 : Ip4Address group = rt->GetPrefix().group();
337 : MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
338 6293 : server()->autonomous_system(), group, source);
339 12586 : return prefix;
340 : }
341 :
342 4507 : MvpnRoute *MvpnTable::LocateType3SPMSIRoute(const MvpnRoute *type7_rt) {
343 4507 : MvpnPrefix prefix = CreateType3SPMSIRoutePrefix(type7_rt);
344 9014 : return LocateRoute(prefix);
345 4507 : }
346 :
347 1 : MvpnPrefix MvpnTable::CreateType2ADRoutePrefix() {
348 1 : const RouteDistinguisher *rd = routing_instance()->GetRD();
349 : MvpnPrefix prefix(MvpnPrefix::InterASPMSIADRoute, *rd,
350 1 : server()->autonomous_system());
351 1 : return prefix;
352 : }
353 :
354 112747 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix(
355 : const Ip4Address &originator_ip) {
356 112747 : const RouteDistinguisher rd(originator_ip.to_ulong(),
357 112747 : routing_instance()->index());
358 112747 : MvpnPrefix prefix(MvpnPrefix::IntraASPMSIADRoute, rd, originator_ip);
359 225494 : return prefix;
360 : }
361 :
362 42454 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix() {
363 84908 : return CreateType1ADRoutePrefix(Ip4Address(server()->bgp_identifier()));
364 : }
365 :
366 42453 : MvpnRoute *MvpnTable::LocateType1ADRoute() {
367 42453 : MvpnPrefix prefix = CreateType1ADRoutePrefix();
368 84906 : return LocateRoute(prefix);
369 42453 : }
370 :
371 70293 : MvpnRoute *MvpnTable::FindType1ADRoute(const Ip4Address &originator_ip) {
372 70293 : MvpnPrefix prefix = CreateType1ADRoutePrefix(originator_ip);
373 140586 : return FindRoute(prefix);
374 70293 : }
375 :
376 69123 : MvpnRoute *MvpnTable::FindType1ADRoute() {
377 69123 : Ip4Address originator_ip(server()->bgp_identifier());
378 69123 : return FindType1ADRoute(Ip4Address(server()->bgp_identifier()));
379 : }
380 :
381 24085 : const MvpnRoute *MvpnTable::FindType7SourceTreeJoinRoute(MvpnRoute *rt) const {
382 24085 : MvpnPrefix prefix;
383 24085 : if (rt->GetPrefix().type() == MvpnPrefix::SourceActiveADRoute)
384 6293 : prefix = CreateType7SourceTreeJoinRoutePrefix(rt);
385 24085 : if (rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute) {
386 17792 : prefix = CreateLocalType7Prefix(rt);
387 : }
388 48170 : return FindRoute(prefix);
389 24085 : }
390 :
391 272694 : BgpRoute *MvpnTable::RouteReplicate(BgpServer *server, BgpTable *stable,
392 : BgpRoute *rt, const BgpPath *src_path, ExtCommunityPtr community) {
393 272694 : MvpnTable *src_table = dynamic_cast<MvpnTable *>(stable);
394 272694 : assert(src_table);
395 272694 : MvpnRoute *src_rt = dynamic_cast<MvpnRoute *>(rt);
396 272694 : assert(src_rt);
397 :
398 272694 : if (!server->mvpn_ipv4_enable()) {
399 572 : return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
400 286 : src_path, community);
401 : }
402 :
403 : // Replicate Type7 C-Join route.
404 272408 : if (src_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute) {
405 100446 : return ReplicateType7SourceTreeJoin(server, src_table, src_rt,
406 50223 : src_path, community);
407 : }
408 :
409 222185 : if (!IsMaster()) {
410 : // For type-4 paths, only replicate if there is a type-3 primary path
411 : // present in the table.
412 88750 : if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
413 2000 : MvpnProjectManager *pm = GetProjectManager();
414 2000 : if (!pm)
415 1879 : return NULL;
416 2000 : MvpnStatePtr mvpn_state = pm->GetState(src_rt);
417 2121 : if (!mvpn_state || !mvpn_state->spmsi_rt() ||
418 121 : !mvpn_state->spmsi_rt()->IsUsable()) {
419 1879 : return NULL;
420 : }
421 121 : if (mvpn_state->spmsi_rt()->table() != this)
422 0 : return NULL;
423 2000 : }
424 : }
425 :
426 : // Replicate all other types.
427 440612 : return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
428 220306 : src_path, community);
429 : }
430 :
431 50223 : BgpRoute *MvpnTable::ReplicateType7SourceTreeJoin(BgpServer *server,
432 : MvpnTable *src_table, MvpnRoute *src_rt, const BgpPath *src_path,
433 : ExtCommunityPtr ext_community) {
434 :
435 : // Only replicate if route has a target that matches this table's auto
436 : // created route target (vit).
437 50223 : if (!IsMaster()) {
438 19214 : RouteTarget vit(Ip4Address(server->bgp_identifier()),
439 38428 : routing_instance()->index());
440 19214 : bool vit_found = false;
441 56344 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
442 : ext_community->communities()) {
443 20345 : if (ExtCommunity::is_route_target(comm)) {
444 19561 : RouteTarget rtarget(comm);
445 19561 : if (rtarget == vit) {
446 3560 : vit_found = true;
447 3560 : break;
448 : }
449 : }
450 : }
451 :
452 19214 : if (!vit_found) {
453 15654 : MVPN_RT_LOG(src_rt, "Route was not replicated as rt-import "
454 : "extended-community was not found");
455 15654 : return NULL;
456 : }
457 : }
458 :
459 : // If replicating from Master table, no special checks are required.
460 34569 : if (src_table->IsMaster()) {
461 7076 : return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
462 3538 : src_path, ext_community);
463 : }
464 :
465 : // This is the case when routes are replicated either to Master or to other
466 : // vrf.mvpn.0 as identified the route targets. In either case, basic idea
467 : // is to target the replicated path directly to vrf where sender resides.
468 : //
469 : // Route-target of the target vrf is derived from the Vrf Import Target of
470 : // the route the source resolves to. Resolver code would have already
471 : // computed this and encoded inside source-rd. Also source-as to encode in
472 : // the RD is also encoded as part of the SourceAS extended community.
473 31031 : const BgpAttr *attr = src_path->GetAttr();
474 31031 : if (!attr)
475 0 : return NULL;
476 :
477 : // Do not resplicate if the source is not resolvable.
478 31031 : if (attr->source_rd().IsZero()) {
479 30871 : MVPN_RT_LOG(src_rt, "Route was not replicated as source_rd is zero");
480 30871 : return NULL;
481 : }
482 :
483 : // Find source-as extended-community. If not present, do not replicate
484 160 : bool source_as_found = false;
485 160 : SourceAs source_as;
486 320 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
487 : attr->ext_community()->communities()) {
488 160 : if (ExtCommunity::is_source_as(value)) {
489 160 : source_as_found = true;
490 160 : source_as = SourceAs(value);
491 160 : break;
492 : }
493 : }
494 :
495 160 : if (!source_as_found) {
496 0 : MVPN_RT_LOG(src_rt, "Route was not replicated as source_as is zero");
497 0 : return NULL;
498 : }
499 :
500 : // No need to send SourceAS with this mvpn route. This is only sent along
501 : // with the unicast routes.
502 : ext_community =
503 160 : server->extcomm_db()->RemoveSourceASAndLocate(ext_community.get());
504 :
505 : // Replicate path using source route's<C-S,G>, source_rd and asn as encoded
506 : // in the source-as attribute.
507 : MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, attr->source_rd(),
508 160 : source_as.GetAsn(), src_rt->GetPrefix().group(),
509 320 : src_rt->GetPrefix().source());
510 :
511 : // Replicate the path with the computed prefix and attributes.
512 320 : return ReplicatePath(server, prefix, src_table, src_rt, src_path,
513 160 : ext_community);
514 160 : }
515 :
516 224290 : BgpRoute *MvpnTable::ReplicatePath(BgpServer *server, const MvpnPrefix &mprefix,
517 : MvpnTable *src_table, MvpnRoute *src_rt, const BgpPath *src_path,
518 : ExtCommunityPtr comm) {
519 224290 : MvpnRoute rt_key(mprefix);
520 :
521 : // Find or create the route.
522 : DBTablePartition *rtp =
523 224290 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
524 224290 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
525 224290 : if (dest_route == NULL) {
526 77733 : dest_route = new MvpnRoute(mprefix);
527 77733 : rtp->Add(dest_route);
528 : } else {
529 146557 : dest_route->ClearDelete();
530 : }
531 :
532 : BgpAttrPtr new_attr =
533 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(),
534 224290 : comm.get());
535 : // Replace Nexthop with controller address, MX rejects the route if
536 : // nexthop is same as neighbor address, needed for Type-7 routes
537 672870 : new_attr = server->attr_db()->ReplaceNexthopAndLocate(new_attr.get(),
538 448580 : Ip4Address(server->bgp_identifier()));
539 : // Need to strip off route targets other than sender-ip:0
540 224290 : if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
541 3794 : ExtCommunity::ExtCommunityList rtarget;
542 3794 : Ip4Address ip = src_rt->GetPrefix().GetType3OriginatorFromType4Route();
543 3794 : RouteTarget leaf_ad_rtarget(ip, 0);
544 14971 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
545 : comm->communities()) {
546 7485 : if (ExtCommunity::is_route_target(value)) {
547 7484 : if (leaf_ad_rtarget == RouteTarget(value)) {
548 3793 : rtarget.push_back(value);
549 3793 : break;
550 : }
551 : }
552 : }
553 :
554 3794 : if (rtarget.size() == 1) {
555 : ExtCommunityPtr ext_community = server->extcomm_db()->
556 3793 : ReplaceRTargetAndLocate(new_attr->ext_community(), rtarget);
557 7586 : new_attr = server->attr_db()->ReplaceExtCommunityAndLocate(
558 3793 : src_path->GetAttr(), ext_community.get());
559 3793 : } else {
560 1 : MVPN_RT_LOG(src_rt,
561 : "Could not find <originator>:0 route-target community");
562 : }
563 3794 : }
564 :
565 : // Check whether peer already has a path.
566 224290 : BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
567 : src_path->GetSource(), src_path->GetPeer(),
568 : src_path->GetPathId());
569 224290 : if (dest_path != NULL) {
570 265977 : if (new_attr != dest_path->GetOriginalAttr() ||
571 132657 : src_path->GetFlags() != dest_path->GetFlags()) {
572 663 : bool success = dest_route->RemoveSecondaryPath(src_rt,
573 : src_path->GetSource(), src_path->GetPeer(),
574 : src_path->GetPathId());
575 663 : assert(success);
576 : } else {
577 132657 : return dest_route;
578 : }
579 : }
580 :
581 : // Create replicated path and insert it on the route.
582 : BgpSecondaryPath *replicated_path =
583 91633 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
584 91633 : src_path->GetSource(), new_attr,
585 91633 : src_path->GetFlags(), src_path->GetLabel());
586 91633 : replicated_path->SetReplicateInfo(src_table, src_rt);
587 91633 : dest_route->InsertPath(replicated_path);
588 91633 : rtp->Notify(dest_route);
589 91633 : MVPN_RT_LOG(src_rt, "Route was successfully replicated");
590 91633 : return dest_route;
591 224290 : }
592 :
593 11896 : bool MvpnTable::Export(RibOut *ribout, Route *route,
594 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
595 11896 : MvpnRoute *mvpn_route = dynamic_cast<MvpnRoute *>(route);
596 :
597 11896 : if (ribout->IsEncodingXmpp()) {
598 7858 : UpdateInfo *uinfo = GetMvpnUpdateInfo(ribout, mvpn_route, peerset);
599 7858 : if (!uinfo)
600 7592 : return false;
601 266 : uinfo_slist->push_front(*uinfo);
602 266 : return true;
603 : }
604 4038 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route);
605 :
606 4038 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset);
607 4038 : if (!uinfo) {
608 2912 : MVPN_RT_LOG(mvpn_route, "Route was exported as update_info could not "
609 : "be computed");
610 2912 : return false;
611 : }
612 1126 : uinfo_slist->push_front(*uinfo);
613 1126 : return true;
614 : }
615 :
616 434 : void MvpnTable::GetPeerSet(RibOut *ribout, MvpnRoute *route,
617 : const RibPeerSet &peerset, RibPeerSet *new_peerset) {
618 434 : RibOut::PeerIterator iter(ribout, peerset);
619 1709 : while (iter.HasNext()) {
620 1275 : int current_index = iter.index();
621 1275 : IPeer *peer = dynamic_cast<IPeer *>(iter.Next());
622 1275 : assert(peer);
623 2550 : for (Route::PathList::const_iterator it = route->GetPathList().begin();
624 4632 : it != route->GetPathList().end(); ++it) {
625 1482 : const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
626 1482 : if (path->IsFeasible() && peer == path->GetPeer()) {
627 441 : new_peerset->set(current_index);
628 441 : break;
629 : }
630 : }
631 : }
632 434 : }
633 :
634 7858 : UpdateInfo *MvpnTable::GetMvpnUpdateInfo(RibOut *ribout, MvpnRoute *route,
635 : const RibPeerSet &peerset) {
636 15197 : if ((route->GetPrefix().type() != MvpnPrefix::SourceActiveADRoute) &&
637 7339 : (route->GetPrefix().type() != MvpnPrefix::SourceTreeJoinRoute))
638 6945 : return NULL;
639 913 : if (!route->IsUsable())
640 176 : return NULL;
641 :
642 737 : if (route->BestPath()->IsReplicated())
643 303 : return NULL;
644 :
645 434 : MvpnProjectManager *pm = GetProjectManager();
646 434 : if (!pm) {
647 0 : MVPN_RT_LOG(route, "Route was exported as ProjectManager was "
648 : "not found");
649 0 : return NULL;
650 : }
651 :
652 434 : RibPeerSet new_peerset;
653 434 : GetPeerSet(ribout, route, peerset, &new_peerset);
654 :
655 434 : if (new_peerset.empty())
656 10 : return NULL;
657 :
658 424 : UpdateInfo *uinfo = pm->GetUpdateInfo(route);
659 424 : if (uinfo)
660 266 : uinfo->target = new_peerset;
661 424 : return uinfo;
662 434 : }
663 :
664 1381088 : bool MvpnTable::IsMaster() const {
665 1381088 : return routing_instance()->IsMasterRoutingInstance();
666 : }
667 :
668 159 : static void RegisterFactory() {
669 159 : DB::RegisterFactory("mvpn.0", &MvpnTable::CreateTable);
670 159 : }
671 :
672 : MODULE_INITIALIZER(RegisterFactory);
|