Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "bgp/evpn/evpn_table.h"
7 :
8 : #include "bgp/ipeer.h"
9 : #include "bgp/bgp_factory.h"
10 : #include "bgp/bgp_evpn.h"
11 : #include "bgp/bgp_server.h"
12 : #include "bgp/bgp_update.h"
13 : #include "bgp/inet/inet_table.h"
14 : #include "bgp/inet6/inet6_table.h"
15 : #include "bgp/origin-vn/origin_vn.h"
16 : #include "bgp/routing-instance/path_resolver.h"
17 : #include "bgp/routing-instance/routing_instance.h"
18 :
19 : using std::unique_ptr;
20 : using std::string;
21 :
22 1507829 : size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) {
23 1507829 : if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) {
24 939699 : if (prefix.mac_addr().IsBroadcast())
25 116471 : return 0;
26 823216 : const uint8_t *data = prefix.mac_addr().GetData();
27 823208 : uint32_t value = get_value(data + 2, 4);
28 823209 : return boost::hash_value(value);
29 : }
30 568081 : if (prefix.type() == EvpnPrefix::IpPrefixRoute) {
31 386019 : if (prefix.ip_address().is_v4()) {
32 201095 : return InetTable::HashFunction(prefix.inet_prefix());
33 : } else {
34 184814 : return Inet6Table::HashFunction(prefix.inet6_prefix());
35 : }
36 : }
37 182044 : return 0;
38 : }
39 :
40 51137 : EvpnTable::EvpnTable(DB *db, const string &name)
41 51137 : : BgpTable(db, name), evpn_manager_(NULL) {
42 51137 : mac_route_count_ = 0;
43 51137 : unique_mac_route_count_ = 0;
44 51137 : im_route_count_ = 0;
45 51137 : ip_route_count_ = 0;
46 51137 : }
47 :
48 132158 : unique_ptr<DBEntry> EvpnTable::AllocEntry(
49 : const DBRequestKey *key) const {
50 132158 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
51 132158 : return unique_ptr<DBEntry> (new EvpnRoute(pfxkey->prefix));
52 : }
53 :
54 22 : unique_ptr<DBEntry> EvpnTable::AllocEntryStr(
55 : const string &key_str) const {
56 22 : EvpnPrefix prefix = EvpnPrefix::FromString(key_str);
57 44 : return unique_ptr<DBEntry> (new EvpnRoute(prefix));
58 : }
59 :
60 163492 : void EvpnTable::AddRemoveCallback(const DBEntryBase *entry, bool add) const {
61 163492 : if (IsVpnTable())
62 87279 : return;
63 76200 : const EvpnRoute *evpn_rt = static_cast<const EvpnRoute *>(entry);
64 76200 : const EvpnPrefix &evpn_prefix = evpn_rt->GetPrefix();
65 76213 : switch (evpn_prefix.type()) {
66 14934 : case EvpnPrefix::MacAdvertisementRoute:
67 : // Ignore Broadcast MAC routes.
68 14934 : if (evpn_prefix.mac_addr().IsBroadcast())
69 4302 : break;
70 :
71 10631 : if (add) {
72 5315 : mac_route_count_++;
73 : } else {
74 5316 : mac_route_count_--;
75 : }
76 :
77 : // Ignore MAC routes with IP addresses.
78 10632 : if (evpn_prefix.family() != Address::UNSPEC)
79 3456 : break;
80 :
81 7176 : if (add) {
82 3588 : unique_mac_route_count_++;
83 : } else {
84 3588 : unique_mac_route_count_--;
85 : }
86 7176 : break;
87 :
88 8964 : case EvpnPrefix::InclusiveMulticastRoute:
89 8964 : if (add) {
90 4482 : im_route_count_++;
91 : } else {
92 4482 : im_route_count_--;
93 : }
94 8964 : break;
95 :
96 50973 : case EvpnPrefix::IpPrefixRoute:
97 50973 : if (add) {
98 25498 : ip_route_count_++;
99 : } else {
100 25475 : ip_route_count_--;
101 : }
102 51016 : break;
103 :
104 1340 : default:
105 1340 : break;
106 : }
107 : }
108 :
109 112644 : size_t EvpnTable::Hash(const DBRequestKey *key) const {
110 112644 : const RequestKey *rkey = static_cast<const RequestKey *>(key);
111 112644 : size_t value = HashFunction(rkey->prefix);
112 112643 : return value % DB::PartitionCount();
113 : }
114 :
115 1395255 : size_t EvpnTable::Hash(const DBEntry *entry) const {
116 1395255 : const EvpnRoute *rt_entry = static_cast<const EvpnRoute *>(entry);
117 1395255 : size_t value = HashFunction(rt_entry->GetPrefix());
118 1394689 : return value % DB::PartitionCount();
119 : }
120 :
121 70029 : BgpRoute *EvpnTable::TableFind(DBTablePartition *rtp,
122 : const DBRequestKey *prefix) {
123 70029 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
124 70029 : EvpnRoute rt_key(pfxkey->prefix);
125 140076 : return static_cast<BgpRoute *>(rtp->Find(&rt_key));
126 70059 : }
127 :
128 42908 : PathResolver *EvpnTable::CreatePathResolver() {
129 42908 : if (routing_instance()->IsMasterRoutingInstance())
130 0 : return NULL;
131 42909 : return (new PathResolver(this));
132 : }
133 :
134 51137 : DBTableBase *EvpnTable::CreateTable(DB *db, const string &name) {
135 51137 : EvpnTable *table = new EvpnTable(db, name);
136 51137 : table->Init();
137 51137 : return table;
138 : }
139 :
140 : // Find the route.
141 1176 : EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) {
142 1176 : EvpnRoute rt_key(prefix);
143 : DBTablePartition *rtp = static_cast<DBTablePartition *>(
144 1176 : GetTablePartition(&rt_key));
145 2352 : return dynamic_cast<EvpnRoute *>(rtp->Find(&rt_key));
146 1176 : }
147 :
148 0 : const EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) const {
149 0 : EvpnRoute rt_key(prefix);
150 : const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
151 0 : GetTablePartition(&rt_key));
152 0 : return dynamic_cast<const EvpnRoute *>(rtp->Find(&rt_key));
153 0 : }
154 :
155 197961 : bool EvpnTable::ShouldReplicate(const BgpServer *server,
156 : const BgpTable *src_table,
157 : const ExtCommunityPtr community,
158 : const EvpnPrefix &evpn_prefix) const {
159 : // Always replicate into master table.
160 197961 : if (IsMaster())
161 66380 : return true;
162 :
163 : // Always replicate Type-5 routes.
164 131580 : if (evpn_prefix.type() == EvpnPrefix::IpPrefixRoute)
165 17593 : return true;
166 :
167 : // Don't replicate to a VRF from other VRF tables.
168 : const EvpnTable *src_evpn_table =
169 113987 : dynamic_cast<const EvpnTable *>(src_table);
170 113987 : if (!src_evpn_table->IsMaster())
171 19510 : return false;
172 :
173 : // Replicate to VRF from the VPN table if OriginVn matches.
174 188954 : if (community->ContainsOriginVn(server->autonomous_system(),
175 94477 : routing_instance()->virtual_network_index())) {
176 3726 : return true;
177 : }
178 :
179 : // Do not replicate non AD routes as the OriginVN does not match.
180 90750 : if (evpn_prefix.type() != EvpnPrefix::AutoDiscoveryRoute)
181 90746 : return false;
182 :
183 4 : string es_target = server->autonomous_system() > 0xffFF ?
184 0 : integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS4) :
185 4 : integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS2);
186 :
187 : // Replicate if AD route target is associated with the route.
188 8 : RouteTarget rtarget = RouteTarget::FromString("target:" +
189 12 : integerToString(server->autonomous_system()) + ":" + es_target);
190 4 : if (community->ContainsRTarget(rtarget.GetExtCommunity()))
191 4 : return true;
192 0 : return false;
193 4 : }
194 :
195 197961 : BgpRoute *EvpnTable::RouteReplicate(BgpServer *server,
196 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
197 : ExtCommunityPtr community) {
198 197961 : assert(src_table->family() == Address::EVPN);
199 197959 : EvpnRoute *evpn_rt = dynamic_cast<EvpnRoute *>(src_rt);
200 197959 : assert(evpn_rt);
201 197959 : EvpnPrefix evpn_prefix(evpn_rt->GetPrefix());
202 :
203 : // Check if this evpn route should be replicated.
204 197951 : if (!ShouldReplicate(server, src_table, community, evpn_prefix))
205 110256 : return NULL;
206 87707 : if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute) {
207 63 : if (IsMaster() || evpn_prefix.tag() != EvpnPrefix::kMaxTag)
208 59 : return NULL;
209 12 : community = server->extcomm_db()->ReplaceRTargetAndLocate(
210 12 : community.get(), ExtCommunity::ExtCommunityList());
211 : }
212 87647 : if (evpn_prefix.type() == EvpnPrefix::SegmentRoute)
213 3 : return NULL;
214 117187 : if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute &&
215 29547 : evpn_prefix.mac_addr().IsBroadcast())
216 19891 : return NULL;
217 :
218 67747 : BgpAttrDB *attr_db = server->attr_db();
219 67743 : BgpAttrPtr new_attr(src_path->GetAttr());
220 :
221 67754 : if (IsMaster()) {
222 46434 : if (evpn_prefix.route_distinguisher().IsZero()) {
223 24902 : if (new_attr->sub_protocol() == "bgpaas") {
224 1181 : boost::system::error_code ec;
225 : Ip4Address addr =
226 1181 : Ip4Address::from_string(src_path->GetPeer()->ToString(), ec);
227 1181 : if ((ec.value() != 0)) {
228 0 : evpn_prefix.set_route_distinguisher(new_attr->source_rd());
229 : } else {
230 : RouteDistinguisher new_source_rd =
231 1181 : RouteDistinguisher(addr.to_ulong(), 0);
232 1181 : evpn_prefix.set_route_distinguisher(new_source_rd);
233 : }
234 : } else {
235 23718 : evpn_prefix.set_route_distinguisher(new_attr->source_rd());
236 : }
237 : }
238 : } else {
239 42631 : if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute ||
240 42630 : evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute ||
241 19689 : evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) {
242 19220 : evpn_prefix.set_route_distinguisher(RouteDistinguisher::kZeroRd);
243 : }
244 : }
245 67746 : EvpnRoute rt_key(evpn_prefix);
246 :
247 : // Find or create the route.
248 : DBTablePartition *rtp =
249 67744 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
250 67728 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
251 67755 : if (dest_route == NULL) {
252 34698 : dest_route = new EvpnRoute(evpn_prefix);
253 34678 : rtp->Add(dest_route);
254 : } else {
255 33057 : dest_route->ClearDelete();
256 : }
257 :
258 67750 : new_attr = attr_db->ReplaceExtCommunityAndLocate(new_attr.get(), community);
259 :
260 : // Check whether peer already has a path
261 67756 : BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
262 : src_path->GetSource(), src_path->GetPeer(),
263 : src_path->GetPathId());
264 67756 : if (dest_path != NULL) {
265 53033 : if ((new_attr != dest_path->GetOriginalAttr()) ||
266 44711 : (src_path->GetFlags() != dest_path->GetFlags()) ||
267 74121 : (src_path->GetLabel() != dest_path->GetLabel()) ||
268 21088 : (src_path->GetL3Label() != dest_path->GetL3Label())) {
269 8326 : if (dest_path->NeedsResolution()) {
270 0 : path_resolver()->StopPathResolution(rtp->index(), dest_path);
271 : }
272 8326 : bool success = dest_route->RemoveSecondaryPath(src_rt,
273 : src_path->GetSource(), src_path->GetPeer(),
274 : src_path->GetPathId());
275 8326 : assert(success);
276 : } else {
277 21084 : return dest_route;
278 : }
279 : }
280 :
281 : // Create replicated path and insert it on the route
282 : BgpSecondaryPath *replicated_path =
283 46672 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
284 46672 : src_path->GetSource(), new_attr,
285 46672 : src_path->GetFlags(), src_path->GetLabel(),
286 93344 : src_path->GetL3Label());
287 46672 : replicated_path->SetReplicateInfo(src_table, src_rt);
288 :
289 : // For VPN to VRF replication, start path resolution if fast convergence is
290 : // enabled and update path flag to indicate need for resolution.
291 46672 : if (!IsMaster() && server->IsNextHopCheckEnabled() &&
292 0 : (replicated_path->GetSource() == BgpPath::BGP_XMPP)) {
293 0 : Address::Family family = src_path->GetAttr()->nexthop_family();
294 0 : RoutingInstanceMgr *mgr = server->routing_instance_mgr();
295 0 : RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance();
296 0 : BgpTable *table = master_ri->GetTable(family);
297 0 : replicated_path->SetResolveNextHop();
298 0 : path_resolver()->StartPathResolution(dest_route,
299 : replicated_path, table);
300 : }
301 :
302 46672 : dest_route->InsertPath(replicated_path);
303 :
304 : // Always trigger notification.
305 46668 : rtp->Notify(dest_route);
306 :
307 46669 : return dest_route;
308 67753 : }
309 :
310 78870 : bool EvpnTable::Export(RibOut *ribout, Route *route,
311 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
312 78870 : EvpnRoute *evpn_route = dynamic_cast<EvpnRoute *>(route);
313 78870 : assert(evpn_route);
314 :
315 78870 : if (ribout->IsEncodingBgp()) {
316 64149 : UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
317 64151 : if (!uinfo)
318 28937 : return false;
319 35214 : uinfo_slist->push_front(*uinfo);
320 35214 : return true;
321 : }
322 :
323 14721 : const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
324 18968 : if (evpn_prefix.type() != EvpnPrefix::MacAdvertisementRoute &&
325 18968 : evpn_prefix.type() != EvpnPrefix::IpPrefixRoute &&
326 2482 : evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute) {
327 2372 : return false;
328 : }
329 :
330 22561 : if (!evpn_prefix.mac_addr().IsBroadcast() &&
331 10211 : (evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute)) {
332 10101 : UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
333 10100 : if (!uinfo)
334 439 : return false;
335 9661 : uinfo_slist->push_front(*uinfo);
336 9661 : return true;
337 : }
338 :
339 2249 : if (!evpn_manager_ || evpn_manager_->deleter()->IsDeleted())
340 0 : return false;
341 :
342 2249 : const IPeer *peer = evpn_route->BestPath()->GetPeer();
343 2249 : if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer)))
344 24 : return false;
345 :
346 2225 : size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer));
347 2225 : if (!peerset.test(peerbit))
348 232 : return false;
349 :
350 1993 : UpdateInfo *uinfo = evpn_manager_->GetUpdateInfo(evpn_route);
351 1993 : if (!uinfo)
352 249 : return false;
353 :
354 1744 : uinfo->target.set(peerbit);
355 1744 : uinfo_slist->push_front(*uinfo);
356 1744 : return true;
357 : }
358 :
359 51137 : void EvpnTable::CreateEvpnManager() {
360 51137 : if (IsVpnTable())
361 8228 : return;
362 42909 : assert(!evpn_manager_);
363 42909 : evpn_manager_ = BgpStaticObjectFactory::Create<EvpnManager>(this);
364 42905 : evpn_manager_->Initialize();
365 : }
366 :
367 42909 : void EvpnTable::DestroyEvpnManager() {
368 42909 : assert(evpn_manager_);
369 42909 : evpn_manager_->Terminate();
370 42909 : delete evpn_manager_;
371 42909 : evpn_manager_ = NULL;
372 42909 : }
373 :
374 164 : EvpnManager *EvpnTable::GetEvpnManager() {
375 164 : return evpn_manager_;
376 : }
377 :
378 393 : const EvpnManager *EvpnTable::GetEvpnManager() const {
379 393 : return evpn_manager_;
380 : }
381 :
382 51137 : void EvpnTable::set_routing_instance(RoutingInstance *rtinstance) {
383 51137 : BgpTable::set_routing_instance(rtinstance);
384 51137 : CreateEvpnManager();
385 51136 : }
386 :
387 1656488 : bool EvpnTable::IsMaster() const {
388 1656488 : return routing_instance()->IsMasterRoutingInstance();
389 : }
390 :
391 159 : static void RegisterFactory() {
392 159 : DB::RegisterFactory("evpn.0", &EvpnTable::CreateTable);
393 159 : }
394 :
395 : MODULE_INITIALIZER(RegisterFactory);
|