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