Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/evpn/evpn_table.h"
6 :
7 : #include "bgp/ipeer.h"
8 : #include "bgp/bgp_factory.h"
9 : #include "bgp/bgp_evpn.h"
10 : #include "bgp/bgp_server.h"
11 : #include "bgp/bgp_update.h"
12 : #include "bgp/inet/inet_table.h"
13 : #include "bgp/inet6/inet6_table.h"
14 : #include "bgp/origin-vn/origin_vn.h"
15 : #include "bgp/routing-instance/path_resolver.h"
16 : #include "bgp/routing-instance/routing_instance.h"
17 :
18 : using std::unique_ptr;
19 : using std::string;
20 :
21 1476555 : size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) {
22 1476555 : if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) {
23 914699 : if (prefix.mac_addr().IsBroadcast())
24 118274 : return 0;
25 796407 : const uint8_t *data = prefix.mac_addr().GetData();
26 796405 : uint32_t value = get_value(data + 2, 4);
27 796407 : return boost::hash_value(value);
28 : }
29 561799 : if (prefix.type() == EvpnPrefix::IpPrefixRoute) {
30 378858 : if (prefix.ip_address().is_v4()) {
31 196557 : return InetTable::HashFunction(prefix.inet_prefix());
32 : } else {
33 182196 : return Inet6Table::HashFunction(prefix.inet6_prefix());
34 : }
35 : }
36 182927 : return 0;
37 : }
38 :
39 51131 : EvpnTable::EvpnTable(DB *db, const string &name)
40 51131 : : BgpTable(db, name), evpn_manager_(NULL) {
41 51131 : mac_route_count_ = 0;
42 51131 : unique_mac_route_count_ = 0;
43 51131 : im_route_count_ = 0;
44 51131 : ip_route_count_ = 0;
45 51131 : }
46 :
47 131137 : unique_ptr<DBEntry> EvpnTable::AllocEntry(
48 : const DBRequestKey *key) const {
49 131137 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
50 131137 : return unique_ptr<DBEntry> (new EvpnRoute(pfxkey->prefix));
51 : }
52 :
53 22 : unique_ptr<DBEntry> EvpnTable::AllocEntryStr(
54 : const string &key_str) const {
55 22 : EvpnPrefix prefix = EvpnPrefix::FromString(key_str);
56 44 : return unique_ptr<DBEntry> (new EvpnRoute(prefix));
57 : }
58 :
59 163471 : void EvpnTable::AddRemoveCallback(const DBEntryBase *entry, bool add) const {
60 163471 : if (IsVpnTable())
61 87254 : return;
62 76205 : const EvpnRoute *evpn_rt = static_cast<const EvpnRoute *>(entry);
63 76205 : const EvpnPrefix &evpn_prefix = evpn_rt->GetPrefix();
64 76217 : switch (evpn_prefix.type()) {
65 14934 : case EvpnPrefix::MacAdvertisementRoute:
66 : // Ignore Broadcast MAC routes.
67 14934 : if (evpn_prefix.mac_addr().IsBroadcast())
68 4302 : break;
69 :
70 10632 : if (add) {
71 5316 : mac_route_count_++;
72 : } else {
73 5316 : mac_route_count_--;
74 : }
75 :
76 : // Ignore MAC routes with IP addresses.
77 10632 : if (evpn_prefix.family() != Address::UNSPEC)
78 3456 : break;
79 :
80 7176 : if (add) {
81 3588 : unique_mac_route_count_++;
82 : } else {
83 3588 : unique_mac_route_count_--;
84 : }
85 7176 : break;
86 :
87 8964 : case EvpnPrefix::InclusiveMulticastRoute:
88 8964 : if (add) {
89 4482 : im_route_count_++;
90 : } else {
91 4482 : im_route_count_--;
92 : }
93 8964 : break;
94 :
95 50976 : case EvpnPrefix::IpPrefixRoute:
96 50976 : if (add) {
97 25499 : ip_route_count_++;
98 : } else {
99 25477 : ip_route_count_--;
100 : }
101 51012 : break;
102 :
103 1340 : default:
104 1340 : break;
105 : }
106 : }
107 :
108 112389 : size_t EvpnTable::Hash(const DBRequestKey *key) const {
109 112389 : const RequestKey *rkey = static_cast<const RequestKey *>(key);
110 112389 : size_t value = HashFunction(rkey->prefix);
111 112389 : return value % DB::PartitionCount();
112 : }
113 :
114 1364259 : size_t EvpnTable::Hash(const DBEntry *entry) const {
115 1364259 : const EvpnRoute *rt_entry = static_cast<const EvpnRoute *>(entry);
116 1364259 : size_t value = HashFunction(rt_entry->GetPrefix());
117 1363636 : return value % DB::PartitionCount();
118 : }
119 :
120 69775 : BgpRoute *EvpnTable::TableFind(DBTablePartition *rtp,
121 : const DBRequestKey *prefix) {
122 69775 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
123 69775 : EvpnRoute rt_key(pfxkey->prefix);
124 139552 : return static_cast<BgpRoute *>(rtp->Find(&rt_key));
125 69797 : }
126 :
127 42904 : PathResolver *EvpnTable::CreatePathResolver() {
128 42904 : if (routing_instance()->IsMasterRoutingInstance())
129 0 : return NULL;
130 42904 : return (new PathResolver(this));
131 : }
132 :
133 51130 : DBTableBase *EvpnTable::CreateTable(DB *db, const string &name) {
134 51130 : EvpnTable *table = new EvpnTable(db, name);
135 51131 : table->Init();
136 51131 : return table;
137 : }
138 :
139 : // Find the route.
140 1176 : EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) {
141 1176 : EvpnRoute rt_key(prefix);
142 : DBTablePartition *rtp = static_cast<DBTablePartition *>(
143 1176 : GetTablePartition(&rt_key));
144 2352 : return dynamic_cast<EvpnRoute *>(rtp->Find(&rt_key));
145 1176 : }
146 :
147 0 : const EvpnRoute *EvpnTable::FindRoute(const EvpnPrefix &prefix) const {
148 0 : EvpnRoute rt_key(prefix);
149 : const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
150 0 : GetTablePartition(&rt_key));
151 0 : return dynamic_cast<const EvpnRoute *>(rtp->Find(&rt_key));
152 0 : }
153 :
154 197463 : bool EvpnTable::ShouldReplicate(const BgpServer *server,
155 : const BgpTable *src_table,
156 : const ExtCommunityPtr community,
157 : const EvpnPrefix &evpn_prefix) const {
158 : // Always replicate into master table.
159 197463 : if (IsMaster())
160 66964 : return true;
161 :
162 : // Always replicate Type-5 routes.
163 130495 : if (evpn_prefix.type() == EvpnPrefix::IpPrefixRoute)
164 17604 : return true;
165 :
166 : // Don't replicate to a VRF from other VRF tables.
167 : const EvpnTable *src_evpn_table =
168 112892 : dynamic_cast<const EvpnTable *>(src_table);
169 112892 : if (!src_evpn_table->IsMaster())
170 19482 : return false;
171 :
172 : // Replicate to VRF from the VPN table if OriginVn matches.
173 186820 : if (community->ContainsOriginVn(server->autonomous_system(),
174 93410 : routing_instance()->virtual_network_index())) {
175 3727 : return true;
176 : }
177 :
178 : // Do not replicate non AD routes as the OriginVN does not match.
179 89682 : if (evpn_prefix.type() != EvpnPrefix::AutoDiscoveryRoute)
180 89678 : return false;
181 :
182 4 : string es_target = server->autonomous_system() > 0xffFF ?
183 0 : integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS4) :
184 4 : integerToString(EVPN_ES_IMPORT_ROUTE_TARGET_AS2);
185 :
186 : // Replicate if AD route target is associated with the route.
187 8 : RouteTarget rtarget = RouteTarget::FromString("target:" +
188 12 : integerToString(server->autonomous_system()) + ":" + es_target);
189 4 : if (community->ContainsRTarget(rtarget.GetExtCommunity()))
190 4 : return true;
191 0 : return false;
192 4 : }
193 :
194 197452 : BgpRoute *EvpnTable::RouteReplicate(BgpServer *server,
195 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
196 : ExtCommunityPtr community) {
197 197452 : assert(src_table->family() == Address::EVPN);
198 197460 : EvpnRoute *evpn_rt = dynamic_cast<EvpnRoute *>(src_rt);
199 197460 : assert(evpn_rt);
200 197460 : EvpnPrefix evpn_prefix(evpn_rt->GetPrefix());
201 :
202 : // Check if this evpn route should be replicated.
203 197453 : if (!ShouldReplicate(server, src_table, community, evpn_prefix))
204 109160 : return NULL;
205 88302 : if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute) {
206 63 : if (IsMaster() || evpn_prefix.tag() != EvpnPrefix::kMaxTag)
207 59 : return NULL;
208 12 : community = server->extcomm_db()->ReplaceRTargetAndLocate(
209 12 : community.get(), ExtCommunity::ExtCommunityList());
210 : }
211 88243 : if (evpn_prefix.type() == EvpnPrefix::SegmentRoute)
212 3 : return NULL;
213 118065 : if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute &&
214 29825 : evpn_prefix.mac_addr().IsBroadcast())
215 20179 : return NULL;
216 :
217 68060 : BgpAttrDB *attr_db = server->attr_db();
218 68059 : BgpAttrPtr new_attr(src_path->GetAttr());
219 :
220 68062 : if (IsMaster()) {
221 46730 : if (evpn_prefix.route_distinguisher().IsZero()) {
222 24913 : if (new_attr->sub_protocol() == "bgpaas") {
223 1191 : boost::system::error_code ec;
224 : Ip4Address addr =
225 1191 : Ip4Address::from_string(src_path->GetPeer()->ToString(), ec);
226 1191 : if ((ec.value() != 0)) {
227 0 : evpn_prefix.set_route_distinguisher(new_attr->source_rd());
228 : } else {
229 : RouteDistinguisher new_source_rd =
230 1191 : RouteDistinguisher(addr.to_ulong(), 0);
231 1191 : evpn_prefix.set_route_distinguisher(new_source_rd);
232 : }
233 : } else {
234 23721 : evpn_prefix.set_route_distinguisher(new_attr->source_rd());
235 : }
236 : }
237 : } else {
238 42660 : if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute ||
239 42660 : evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute ||
240 19703 : evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) {
241 19235 : evpn_prefix.set_route_distinguisher(RouteDistinguisher::kZeroRd);
242 : }
243 : }
244 68061 : EvpnRoute rt_key(evpn_prefix);
245 :
246 : // Find or create the route.
247 : DBTablePartition *rtp =
248 68048 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
249 68032 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
250 68061 : if (dest_route == NULL) {
251 34700 : dest_route = new EvpnRoute(evpn_prefix);
252 34686 : rtp->Add(dest_route);
253 : } else {
254 33361 : dest_route->ClearDelete();
255 : }
256 :
257 68060 : new_attr = attr_db->ReplaceExtCommunityAndLocate(new_attr.get(), community);
258 :
259 : // Check whether peer already has a path
260 68062 : BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
261 : src_path->GetSource(), src_path->GetPeer(),
262 : src_path->GetPathId());
263 68060 : if (dest_path != NULL) {
264 53640 : if ((new_attr != dest_path->GetOriginalAttr()) ||
265 45332 : (src_path->GetFlags() != dest_path->GetFlags()) ||
266 75045 : (src_path->GetLabel() != dest_path->GetLabel()) ||
267 21405 : (src_path->GetL3Label() != dest_path->GetL3Label())) {
268 8312 : if (dest_path->NeedsResolution()) {
269 0 : path_resolver()->StopPathResolution(rtp->index(), dest_path);
270 : }
271 8312 : bool success = dest_route->RemoveSecondaryPath(src_rt,
272 : src_path->GetSource(), src_path->GetPeer(),
273 : src_path->GetPathId());
274 8313 : assert(success);
275 : } else {
276 21401 : return dest_route;
277 : }
278 : }
279 :
280 : // Create replicated path and insert it on the route
281 : BgpSecondaryPath *replicated_path =
282 46660 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
283 46660 : src_path->GetSource(), new_attr,
284 46661 : src_path->GetFlags(), src_path->GetLabel(),
285 93321 : src_path->GetL3Label());
286 46661 : replicated_path->SetReplicateInfo(src_table, src_rt);
287 :
288 : // For VPN to VRF replication, start path resolution if fast convergence is
289 : // enabled and update path flag to indicate need for resolution.
290 46661 : if (!IsMaster() && server->IsNextHopCheckEnabled() &&
291 0 : (replicated_path->GetSource() == BgpPath::BGP_XMPP)) {
292 0 : Address::Family family = src_path->GetAttr()->nexthop_family();
293 0 : RoutingInstanceMgr *mgr = server->routing_instance_mgr();
294 0 : RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance();
295 0 : BgpTable *table = master_ri->GetTable(family);
296 0 : replicated_path->SetResolveNextHop();
297 0 : path_resolver()->StartPathResolution(dest_route,
298 : replicated_path, table);
299 : }
300 :
301 46659 : dest_route->InsertPath(replicated_path);
302 :
303 : // Always trigger notification.
304 46660 : rtp->Notify(dest_route);
305 :
306 46659 : return dest_route;
307 68060 : }
308 :
309 76919 : bool EvpnTable::Export(RibOut *ribout, Route *route,
310 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
311 76919 : EvpnRoute *evpn_route = dynamic_cast<EvpnRoute *>(route);
312 76919 : assert(evpn_route);
313 :
314 76919 : if (ribout->IsEncodingBgp()) {
315 61989 : UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
316 61989 : if (!uinfo)
317 27873 : return false;
318 34116 : uinfo_slist->push_front(*uinfo);
319 34116 : return true;
320 : }
321 :
322 14930 : const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
323 19300 : if (evpn_prefix.type() != EvpnPrefix::MacAdvertisementRoute &&
324 19300 : evpn_prefix.type() != EvpnPrefix::IpPrefixRoute &&
325 2583 : evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute) {
326 2487 : return false;
327 : }
328 :
329 22636 : if (!evpn_prefix.mac_addr().IsBroadcast() &&
330 10193 : (evpn_prefix.type() != EvpnPrefix::SelectiveMulticastRoute)) {
331 10097 : UpdateInfo *uinfo = GetUpdateInfo(ribout, evpn_route, peerset);
332 10097 : if (!uinfo)
333 449 : return false;
334 9648 : uinfo_slist->push_front(*uinfo);
335 9648 : return true;
336 : }
337 :
338 2346 : if (!evpn_manager_ || evpn_manager_->deleter()->IsDeleted())
339 0 : return false;
340 :
341 2346 : const IPeer *peer = evpn_route->BestPath()->GetPeer();
342 2346 : if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer)))
343 24 : return false;
344 :
345 2322 : size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer));
346 2322 : if (!peerset.test(peerbit))
347 207 : return false;
348 :
349 2115 : UpdateInfo *uinfo = evpn_manager_->GetUpdateInfo(evpn_route);
350 2115 : if (!uinfo)
351 240 : return false;
352 :
353 1875 : uinfo->target.set(peerbit);
354 1875 : uinfo_slist->push_front(*uinfo);
355 1875 : return true;
356 : }
357 :
358 51131 : void EvpnTable::CreateEvpnManager() {
359 51131 : if (IsVpnTable())
360 8227 : return;
361 42904 : assert(!evpn_manager_);
362 42904 : evpn_manager_ = BgpStaticObjectFactory::Create<EvpnManager>(this);
363 42904 : evpn_manager_->Initialize();
364 : }
365 :
366 42904 : void EvpnTable::DestroyEvpnManager() {
367 42904 : assert(evpn_manager_);
368 42904 : evpn_manager_->Terminate();
369 42904 : delete evpn_manager_;
370 42904 : evpn_manager_ = NULL;
371 42904 : }
372 :
373 164 : EvpnManager *EvpnTable::GetEvpnManager() {
374 164 : return evpn_manager_;
375 : }
376 :
377 393 : const EvpnManager *EvpnTable::GetEvpnManager() const {
378 393 : return evpn_manager_;
379 : }
380 :
381 51130 : void EvpnTable::set_routing_instance(RoutingInstance *rtinstance) {
382 51130 : BgpTable::set_routing_instance(rtinstance);
383 51131 : CreateEvpnManager();
384 51131 : }
385 :
386 1653851 : bool EvpnTable::IsMaster() const {
387 1653851 : return routing_instance()->IsMasterRoutingInstance();
388 : }
389 :
390 159 : static void RegisterFactory() {
391 159 : DB::RegisterFactory("evpn.0", &EvpnTable::CreateTable);
392 159 : }
393 :
394 : MODULE_INITIALIZER(RegisterFactory);
|