Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/routing-instance/static_route.h"
6 :
7 : #include <boost/assign/list_of.hpp>
8 : #include <boost/foreach.hpp>
9 :
10 : #include <algorithm>
11 : #include <string>
12 : #include <vector>
13 :
14 : #include "base/map_util.h"
15 : #include "base/task_annotations.h"
16 : #include "base/task_trigger.h"
17 : #include "bgp/bgp_config.h"
18 : #include "bgp/bgp_log.h"
19 : #include "bgp/bgp_server.h"
20 : #include "bgp/inet6vpn/inet6vpn_route.h"
21 : #include "bgp/l3vpn/inetvpn_route.h"
22 : #include "bgp/origin-vn/origin_vn.h"
23 : #include "bgp/routing-instance/routepath_replicator.h"
24 : #include "bgp/routing-instance/routing_instance.h"
25 : #include "bgp/routing-instance/static_route_types.h"
26 : #include "bgp/routing-policy/routing_policy_match.h"
27 : #include "net/community_type.h"
28 :
29 : using boost::assign::list_of;
30 : using boost::system::error_code;
31 : using std::make_pair;
32 : using std::set;
33 : using std::string;
34 : using std::vector;
35 :
36 : class StaticRouteState : public ConditionMatchState {
37 : public:
38 128 : explicit StaticRouteState(StaticRoutePtr info) : info_(info) {
39 128 : }
40 : StaticRoutePtr info() {
41 : return info_;
42 : }
43 :
44 : private:
45 : StaticRoutePtr info_;
46 : DISALLOW_COPY_AND_ASSIGN(StaticRouteState);
47 : };
48 :
49 : template <typename T>
50 : class StaticRoute : public ConditionMatch {
51 : public:
52 : typedef typename T::RouteT RouteT;
53 : typedef typename T::VpnRouteT VpnRouteT;
54 : typedef typename T::PrefixT PrefixT;
55 : typedef typename T::AddressT AddressT;
56 : typedef StaticRouteMgr<T> StaticRouteMgrT;
57 :
58 : // List of Route targets
59 : typedef set<RouteTarget> RouteTargetList;
60 :
61 : // List of path ids for the Nexthop
62 : typedef set<uint32_t> NexthopPathIdList;
63 :
64 : enum CompareResult {
65 : NoChange = 0,
66 : PrefixChange = 1,
67 : NexthopChange = 2,
68 : AttributeChange = 3
69 : };
70 :
71 : StaticRoute(RoutingInstance *rtinstance, StaticRouteMgrT *manager,
72 : const PrefixT &static_route, const StaticRouteConfig &config);
73 8426 : Address::Family GetFamily() const { return manager_->GetFamily(); }
74 60 : AddressT GetAddress(IpAddress addr) const {
75 60 : return manager_->GetAddress(addr);
76 : }
77 :
78 : CompareResult CompareConfig(const StaticRouteConfig &config);
79 : void FillShowInfo(StaticRouteInfo *info) const;
80 :
81 196 : const PrefixT &prefix() const {
82 196 : return prefix_;
83 : }
84 :
85 196 : const IpAddress &nexthop() const {
86 196 : return nexthop_;
87 : }
88 :
89 1139 : RoutingInstance *routing_instance() const {
90 1139 : return routing_instance_;
91 : }
92 :
93 8019 : BgpTable *bgp_table() const {
94 8019 : return routing_instance_->GetTable(this->GetFamily());
95 : }
96 :
97 1458 : BgpRoute *nexthop_route() const {
98 1458 : return nexthop_route_;
99 : }
100 :
101 1005 : NexthopPathIdList *NexthopPathIds() { return &nexthop_path_ids_; }
102 :
103 361 : void set_nexthop_route(BgpRoute *nexthop_route) {
104 361 : nexthop_route_ = nexthop_route;
105 :
106 361 : if (!nexthop_route_) {
107 130 : nexthop_path_ids_.clear();
108 130 : return;
109 : }
110 :
111 231 : assert(nexthop_path_ids_.empty());
112 :
113 563 : for (Route::PathList::iterator it =
114 231 : nexthop_route->GetPathList().begin();
115 1126 : it != nexthop_route->GetPathList().end(); it++) {
116 332 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
117 :
118 : // Infeasible paths are not considered
119 332 : if (!path->IsFeasible()) break;
120 :
121 : // take snapshot of all ECMP paths
122 332 : if (nexthop_route_->BestPath()->PathCompare(*path, true)) break;
123 :
124 : // Use the nexthop attribute of the nexthop path as the path id.
125 332 : uint32_t path_id = path->GetAttr()->nexthop().to_v4().to_ulong();
126 332 : nexthop_path_ids_.insert(path_id);
127 : }
128 : }
129 :
130 1204 : const RouteTargetList &rtarget_list() const {
131 1204 : return rtarget_list_;
132 : }
133 :
134 : void UpdateAttributes(const StaticRouteConfig &config);
135 : void AddStaticRoute(NexthopPathIdList *list);
136 : void UpdateStaticRoute();
137 : void RemoveStaticRoute();
138 : void NotifyRoute();
139 : bool IsPending() const;
140 :
141 : virtual bool Match(BgpServer *server, BgpTable *table,
142 : BgpRoute *route, bool deleted);
143 :
144 0 : virtual string ToString() const {
145 0 : return (string("StaticRoute ") + nexthop_.to_string());
146 : }
147 :
148 196 : void set_unregistered() {
149 196 : unregistered_ = true;
150 196 : }
151 :
152 693 : bool unregistered() const {
153 693 : return unregistered_;
154 : }
155 :
156 : private:
157 : // Helper function to match
158 1255 : bool is_nexthop_route(BgpRoute *route) {
159 1255 : RouteT *ip_route = dynamic_cast<RouteT *>(route);
160 1255 : return (nexthop_ == ip_route->GetPrefix().addr());
161 : }
162 :
163 : CommunityPtr GetCommunity(const StaticRouteConfig &config);
164 : ExtCommunityPtr UpdateExtCommunity(const BgpAttr *attr) const;
165 :
166 : RoutingInstance *routing_instance_;
167 : StaticRouteMgrT *manager_;
168 : PrefixT prefix_;
169 : IpAddress nexthop_;
170 : BgpRoute *nexthop_route_;
171 : NexthopPathIdList nexthop_path_ids_;
172 : RouteTargetList rtarget_list_;
173 : CommunityPtr community_;
174 : bool unregistered_;
175 :
176 : DISALLOW_COPY_AND_ASSIGN(StaticRoute);
177 : };
178 :
179 : template <typename T>
180 196 : StaticRoute<T>::StaticRoute(RoutingInstance *rtinstance,
181 : StaticRouteMgrT *manager, const PrefixT &prefix,
182 : const StaticRouteConfig &config)
183 196 : : routing_instance_(rtinstance),
184 196 : manager_(manager),
185 196 : prefix_(prefix),
186 196 : nexthop_(config.nexthop),
187 196 : nexthop_route_(NULL),
188 392 : unregistered_(false) {
189 196 : UpdateAttributes(config);
190 196 : }
191 :
192 : //
193 : // Compare the given config against the current state of the StaticRoute.
194 : // Return the appropriate value from CompareResult.
195 : //
196 : template <typename T>
197 60 : typename StaticRoute<T>::CompareResult StaticRoute<T>::CompareConfig(
198 : const StaticRouteConfig &config) {
199 60 : AddressT address = this->GetAddress(config.address);
200 60 : PrefixT prefix(address, config.prefix_length);
201 60 : if (prefix_ != prefix) {
202 0 : return PrefixChange;
203 : }
204 60 : if (nexthop_ != config.nexthop) {
205 0 : return NexthopChange;
206 : }
207 60 : if (rtarget_list_.size() != config.route_targets.size()) {
208 8 : return AttributeChange;
209 : }
210 52 : for (vector<string>::const_iterator it = config.route_targets.begin();
211 172 : it != config.route_targets.end(); ++it) {
212 122 : error_code ec;
213 122 : RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
214 122 : if (rtarget_list_.find(rtarget) == rtarget_list_.end()) {
215 2 : return AttributeChange;
216 : }
217 : }
218 50 : if (community_ != GetCommunity(config)) {
219 2 : return AttributeChange;
220 : }
221 :
222 48 : return NoChange;
223 : }
224 :
225 : template <typename T>
226 48 : void StaticRoute<T>::FillShowInfo(StaticRouteInfo *info) const {
227 48 : BgpTable *table = bgp_table();
228 48 : RouteT rt_key(prefix_);
229 48 : const BgpRoute *route = static_cast<const BgpRoute *>(table->Find(&rt_key));
230 48 : const BgpPath *path = route ? route->FindPath(BgpPath::StaticRoute) : NULL;
231 :
232 48 : info->set_prefix(prefix_.ToString());
233 48 : info->set_static_rt(path ? true : false);
234 48 : info->set_nexthop(nexthop_.to_string());
235 48 : if (nexthop_route_) {
236 38 : ShowRouteBrief show_route;
237 38 : nexthop_route_->FillRouteInfo(table, &show_route);
238 38 : info->set_nexthop_rt(show_route);
239 38 : }
240 :
241 48 : vector<string> community_list;
242 144 : BOOST_FOREACH(uint32_t value, community_->communities()) {
243 48 : community_list.push_back(CommunityType::CommunityToString(value));
244 : }
245 48 : info->set_community_list(community_list);
246 :
247 48 : vector<string> route_target_list;
248 48 : for (RouteTargetList::const_iterator it = rtarget_list_.begin();
249 172 : it != rtarget_list_.end(); ++it) {
250 124 : route_target_list.push_back(it->ToString());
251 : }
252 48 : info->set_route_target_list(route_target_list);
253 :
254 48 : if (path) {
255 44 : const RoutePathReplicator *replicator = table->server()->replicator(
256 : Address::VpnFamilyFromFamily(GetFamily()));
257 44 : info->set_secondary_tables(
258 : replicator->GetReplicatedTableNameList(table, route, path));
259 : }
260 48 : }
261 :
262 : // Match function called from BgpConditionListener
263 : // Concurrency : db::DBTable
264 : template <typename T>
265 1254 : bool StaticRoute<T>::Match(BgpServer *server, BgpTable *table,
266 : BgpRoute *route, bool deleted) {
267 1254 : CHECK_CONCURRENCY("db::DBTable");
268 : StaticRouteRequest::RequestType type;
269 :
270 1255 : if (is_nexthop_route(route) && !unregistered()) {
271 363 : if (deleted)
272 130 : type = StaticRouteRequest::NEXTHOP_DELETE;
273 : else
274 233 : type = StaticRouteRequest::NEXTHOP_ADD_CHG;
275 : } else {
276 895 : return false;
277 : }
278 :
279 363 : BgpConditionListener *listener = server->condition_listener(GetFamily());
280 : StaticRouteState *state = static_cast<StaticRouteState *>
281 363 : (listener->GetMatchState(table, route, this));
282 363 : if (!deleted) {
283 : // MatchState is added to the Route to ensure that DBEntry is not
284 : // deleted before the module processes the WorkQueue request.
285 233 : if (!state) {
286 128 : state = new StaticRouteState(StaticRoutePtr(this));
287 128 : listener->SetMatchState(table, route, this, state);
288 : }
289 : } else {
290 : // MatchState is set on all the Routes that matches the conditions
291 : // Retrieve to check and ignore delete of unseen Add Match
292 130 : if (state == NULL) {
293 : // Not seen ADD ignore DELETE
294 0 : return false;
295 : }
296 : }
297 :
298 : // The MatchState reference is taken to ensure that the route is not
299 : // deleted when request is still present in the queue
300 : // This is to handle the case where MatchState already exists and
301 : // deleted entry gets reused or reused entry gets deleted.
302 363 : state->IncrementRefCnt();
303 :
304 : // Post the Match result to StaticRoute processing task to take Action
305 : // Nexthop route found in NAT instance ==> Add Static Route
306 : // and stitch the Path Attribute from nexthop route
307 726 : StaticRouteRequest *req =
308 363 : new StaticRouteRequest(type, table, route, StaticRoutePtr(this));
309 363 : manager_->EnqueueStaticRouteReq(req);
310 :
311 363 : return true;
312 : }
313 :
314 : //
315 : // Build a Community for the given StaticRouteConfig.
316 : // Always add the AcceptOwnNexthop community in addition to the configured
317 : // list.
318 : //
319 : template <typename T>
320 258 : CommunityPtr StaticRoute<T>::GetCommunity(const StaticRouteConfig &config) {
321 258 : CommunitySpec comm_spec;
322 258 : comm_spec.communities.push_back(CommunityType::AcceptOwnNexthop);
323 258 : for (vector<string>::const_iterator it = config.communities.begin();
324 270 : it != config.communities.end(); ++it) {
325 12 : uint32_t value = CommunityType::CommunityFromString(*it);
326 12 : if (!value)
327 0 : continue;
328 12 : comm_spec.communities.push_back(value);
329 : }
330 258 : CommunityDB *comm_db = routing_instance()->server()->comm_db();
331 516 : return comm_db->Locate(comm_spec);
332 258 : }
333 :
334 : //
335 : // Build an updated ExtCommunity for the static route.
336 : //
337 : // Replace any RouteTargets with the list of RouteTargets for the StaticRoute.
338 : // If the StaticRoute has an empty RouteTarget list, then we infer that this
339 : // is not a snat use case and add the OriginVn as well. We don't want to add
340 : // OriginVn in snat scenario because the route has to be imported into many
341 : // VRFs and we want to set the OriginVn differently for each imported route.
342 : //
343 : template <typename T>
344 318 : ExtCommunityPtr StaticRoute<T>::UpdateExtCommunity(const BgpAttr *attr) const {
345 318 : ExtCommunity::ExtCommunityList export_list;
346 318 : for (RouteTargetList::const_iterator it = rtarget_list().begin();
347 886 : it != rtarget_list().end(); it++) {
348 568 : export_list.push_back(it->GetExtCommunity());
349 : }
350 :
351 318 : BgpServer *server = routing_instance()->server();
352 318 : ExtCommunityDB *extcomm_db = server->extcomm_db();
353 318 : ExtCommunityPtr new_ext_community = extcomm_db->ReplaceRTargetAndLocate(
354 : attr->ext_community(), export_list);
355 :
356 318 : int vn_index = routing_instance()->virtual_network_index();
357 318 : if (export_list.empty() && vn_index) {
358 58 : as_t asn = server->autonomous_system();
359 58 : if (asn > AS2_MAX && vn_index > 0xffff) {
360 0 : OriginVn origin_vn(asn, AS_TRANS);
361 0 : new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
362 0 : new_ext_community.get(), origin_vn.GetExtCommunity());
363 0 : OriginVn origin_vn2(AS_TRANS, vn_index);
364 0 : new_ext_community = extcomm_db->AppendAndLocate(
365 0 : new_ext_community.get(), origin_vn2.GetExtCommunity());
366 0 : } else {
367 58 : OriginVn origin_vn(server->autonomous_system(), vn_index);
368 58 : new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
369 58 : new_ext_community.get(), origin_vn.GetExtCommunity());
370 : }
371 : }
372 636 : return new_ext_community;
373 318 : }
374 :
375 : template <typename T>
376 208 : void StaticRoute<T>::UpdateAttributes(const StaticRouteConfig &config) {
377 208 : rtarget_list_.clear();
378 208 : for (vector<string>::const_iterator it = config.route_targets.begin();
379 632 : it != config.route_targets.end(); ++it) {
380 424 : error_code ec;
381 424 : RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
382 424 : if (ec.failed())
383 6 : continue;
384 418 : rtarget_list_.insert(rtarget);
385 : }
386 208 : community_ = GetCommunity(config);
387 208 : }
388 :
389 : // RemoveStaticRoute
390 : template <typename T>
391 130 : void StaticRoute<T>::RemoveStaticRoute() {
392 130 : CHECK_CONCURRENCY("bgp::StaticRoute");
393 130 : RouteT rt_key(prefix_);
394 : DBTablePartition *partition =
395 130 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
396 : BgpRoute *static_route =
397 130 : static_cast<BgpRoute *>(partition->Find(&rt_key));
398 130 : if (!static_route || static_route->IsDeleted()) return;
399 :
400 128 : for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
401 260 : it != NexthopPathIds()->end(); it++) {
402 132 : static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
403 132 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
404 : "Removed Static route path " << static_route->ToString() <<
405 : " path_id " << BgpPath::PathIdString(*it) <<
406 : " in table " << bgp_table()->name());
407 : }
408 :
409 128 : if (!static_route->HasPaths()) {
410 109 : partition->Delete(static_route);
411 : } else {
412 19 : partition->Notify(static_route);
413 : }
414 130 : }
415 :
416 : // UpdateStaticRoute
417 : template <typename T>
418 14 : void StaticRoute<T>::UpdateStaticRoute() {
419 14 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
420 14 : RouteT rt_key(prefix_);
421 : DBTablePartition *partition =
422 14 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
423 : BgpRoute *static_route =
424 14 : static_cast<BgpRoute *>(partition->Find(&rt_key));
425 14 : if (static_route == NULL) return;
426 :
427 14 : static_route->ClearDelete();
428 :
429 14 : BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
430 28 : for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
431 28 : it != NexthopPathIds()->end(); it++) {
432 : BgpPath *existing_path =
433 14 : static_route->FindPath(BgpPath::StaticRoute, NULL, *it);
434 14 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
435 : "Update attributes of StaticRoute path "
436 : << static_route->ToString() << " path_id "
437 : << BgpPath::PathIdString(*it) << " in table "
438 : << bgp_table()->name());
439 :
440 : // Add the RouteTarget and OrignVn in the ExtCommunity attribute.
441 14 : ExtCommunityPtr ptr = UpdateExtCommunity(existing_path->GetAttr());
442 14 : BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
443 : existing_path->GetAttr(), ptr);
444 :
445 : // Use pre-calculated community from the StaticRoute.
446 14 : new_attr =
447 14 : attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
448 :
449 28 : BgpPath *new_path =
450 28 : new BgpPath(*it, BgpPath::StaticRoute, new_attr.get(),
451 14 : existing_path->GetFlags(), existing_path->GetLabel());
452 :
453 14 : static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
454 :
455 14 : static_route->InsertPath(new_path);
456 : }
457 14 : partition->Notify(static_route);
458 14 : }
459 :
460 : // AddStaticRoute
461 : template <typename T>
462 231 : void StaticRoute<T>::AddStaticRoute(NexthopPathIdList *old_path_ids) {
463 231 : CHECK_CONCURRENCY("bgp::StaticRoute");
464 :
465 231 : RouteT rt_key(prefix_);
466 : DBTablePartition *partition =
467 231 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
468 : BgpRoute *static_route =
469 231 : static_cast<BgpRoute *>(partition->Find(&rt_key));
470 :
471 231 : if (static_route == NULL) {
472 123 : static_route = new RouteT(prefix_);
473 123 : partition->Add(static_route);
474 : } else {
475 108 : static_route->ClearDelete();
476 : }
477 :
478 231 : BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
479 867 : for (Route::PathList::iterator it = nexthop_route()->GetPathList().begin();
480 1126 : it != nexthop_route()->GetPathList().end(); it++) {
481 332 : BgpPath *nexthop_route_path = static_cast<BgpPath *>(it.operator->());
482 :
483 : // Infeasible paths are not considered
484 332 : if (!nexthop_route_path->IsFeasible()) break;
485 :
486 : // take snapshot of all ECMP paths
487 332 : if (nexthop_route()->BestPath()->PathCompare(*nexthop_route_path, true))
488 0 : break;
489 :
490 : // Skip paths with duplicate forwarding information. This ensures
491 : // that we generate only one path with any given next hop and label
492 : // when there are multiple nexthop paths from the original source
493 : // received via different peers e.g. directly via XMPP and via BGP.
494 332 : if (nexthop_route()->DuplicateForwardingPath(nexthop_route_path))
495 28 : continue;
496 :
497 : // Add the route target in the ExtCommunity attribute.
498 304 : ExtCommunityPtr ptr = UpdateExtCommunity(nexthop_route_path->GetAttr());
499 304 : BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
500 : nexthop_route_path->GetAttr(), ptr);
501 :
502 : // Use pre-calculated community from the static route.
503 304 : new_attr =
504 304 : attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
505 :
506 : // Strip aspath. This is required when the nexthop route is learnt
507 : // via BGP.
508 304 : new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(), AsPathPtr());
509 :
510 : // Replace the source rd if the nexthop path is a secondary path
511 : // of a primary path in the l3vpn table. Use the RD of the primary.
512 304 : if (nexthop_route_path->IsReplicated()) {
513 80 : const BgpSecondaryPath *spath =
514 : static_cast<const BgpSecondaryPath *>(nexthop_route_path);
515 80 : const RoutingInstance *ri = spath->src_table()->routing_instance();
516 80 : if (ri->IsMasterRoutingInstance()) {
517 : const VpnRouteT *vpn_route =
518 56 : static_cast<const VpnRouteT *>(spath->src_rt());
519 56 : new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(),
520 56 : vpn_route->GetPrefix().route_distinguisher());
521 : }
522 : }
523 :
524 : // Check whether we already have a path with the associated path id.
525 304 : uint32_t path_id =
526 304 : nexthop_route_path->GetAttr()->nexthop().to_v4().to_ulong();
527 304 : BgpPath *existing_path = static_route->FindPath(BgpPath::StaticRoute,
528 : NULL, path_id);
529 304 : if (existing_path != NULL) {
530 140 : if ((new_attr.get() != existing_path->GetAttr()) ||
531 140 : (nexthop_route_path->GetFlags() != existing_path->GetFlags()) ||
532 0 : (nexthop_route_path->GetLabel() != existing_path->GetLabel())) {
533 : // Update Attributes and notify (if needed)
534 140 : static_route->RemovePath(BgpPath::StaticRoute, NULL, path_id);
535 : } else {
536 0 : continue;
537 : }
538 : }
539 :
540 : // Populate SubProtocol for StaticRoute.
541 304 : new_attr = attr_db->ReplaceSubProtocolAndLocate(new_attr.get(),
542 : MatchProtocolToString(MatchProtocol::StaticRoute));
543 :
544 608 : BgpPath *new_path =
545 304 : new BgpPath(path_id, BgpPath::StaticRoute, new_attr.get(),
546 304 : nexthop_route_path->GetFlags(), nexthop_route_path->GetLabel());
547 304 : static_route->InsertPath(new_path);
548 304 : partition->Notify(static_route);
549 :
550 304 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
551 : "Added Static Route path " << static_route->ToString() <<
552 : " path_id " << BgpPath::PathIdString(path_id) <<
553 : " in table " << bgp_table()->name());
554 : }
555 :
556 231 : if (!old_path_ids) return;
557 :
558 231 : for (NexthopPathIdList::iterator it = old_path_ids->begin();
559 403 : it != old_path_ids->end(); it++) {
560 172 : if (NexthopPathIds()->find(*it) != NexthopPathIds()->end())
561 140 : continue;
562 32 : static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
563 32 : partition->Notify(static_route);
564 :
565 32 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
566 : "Removed StaticRoute path " << static_route->ToString() <<
567 : " path_id " << BgpPath::PathIdString(*it) <<
568 : " in table " << bgp_table()->name());
569 : }
570 231 : }
571 :
572 : template <typename T>
573 6640 : void StaticRoute<T>::NotifyRoute() {
574 6640 : RouteT rt_key(prefix_);
575 : DBTablePartition *partition =
576 6640 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
577 6640 : BgpRoute *static_route = static_cast<BgpRoute *>(partition->Find(&rt_key));
578 6640 : if (!static_route)
579 6632 : return;
580 8 : partition->Notify(static_route);
581 6640 : }
582 :
583 : template <typename T>
584 24 : bool StaticRoute<T>::IsPending() const {
585 24 : RouteT rt_key(prefix_);
586 : DBTablePartition *partition =
587 24 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
588 24 : const BgpRoute *route = static_cast<BgpRoute *>(partition->Find(&rt_key));
589 48 : return (!route || !route->FindPath(BgpPath::StaticRoute));
590 24 : }
591 :
592 : template <>
593 : int StaticRouteMgr<StaticRouteInet>::static_route_task_id_ = -1;
594 : template <>
595 : int StaticRouteMgr<StaticRouteInet6>::static_route_task_id_ = -1;
596 :
597 : template <typename T>
598 122 : StaticRouteMgr<T>::StaticRouteMgr(RoutingInstance *rtinstance)
599 122 : : rtinstance_(rtinstance),
600 122 : listener_(rtinstance_->server()->condition_listener(GetFamily())),
601 244 : unregister_list_trigger_(new TaskTrigger(
602 : boost::bind(&StaticRouteMgr::ProcessUnregisterList, this),
603 488 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)) {
604 122 : if (static_route_task_id_ == -1) {
605 11 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
606 11 : static_route_task_id_ = scheduler->GetTaskId("bgp::StaticRoute");
607 : }
608 :
609 122 : static_route_queue_ = new WorkQueue<StaticRouteRequest *>
610 : (static_route_task_id_, 0,
611 : boost::bind(&StaticRouteMgr::StaticRouteEventCallback, this, _1));
612 122 : }
613 :
614 : template <>
615 7498 : Address::Family StaticRouteMgr<StaticRouteInet>::GetFamily() const {
616 7498 : return Address::INET;
617 : }
618 :
619 : template <>
620 1246 : Address::Family StaticRouteMgr<StaticRouteInet6>::GetFamily() const {
621 1246 : return Address::INET6;
622 : }
623 :
624 : template <>
625 218 : Ip4Address StaticRouteMgr<StaticRouteInet>::GetAddress(IpAddress addr) const {
626 218 : assert(addr.is_v4());
627 218 : return addr.to_v4();
628 : }
629 :
630 : template <>
631 150 : Ip6Address StaticRouteMgr<StaticRouteInet6>::GetAddress(IpAddress addr) const {
632 150 : assert(addr.is_v6());
633 150 : return addr.to_v6();
634 : }
635 :
636 : template <typename T>
637 363 : void StaticRouteMgr<T>::EnqueueStaticRouteReq(StaticRouteRequest *req) {
638 363 : static_route_queue_->Enqueue(req);
639 363 : }
640 :
641 : template <typename T>
642 363 : bool StaticRouteMgr<T>::StaticRouteEventCallback(StaticRouteRequest *req) {
643 363 : CHECK_CONCURRENCY("bgp::StaticRoute");
644 363 : BgpTable *table = req->table_;
645 363 : BgpRoute *route = req->rt_;
646 363 : StaticRouteT *info = static_cast<StaticRouteT *>(req->info_.get());
647 :
648 363 : StaticRouteState *state = NULL;
649 363 : if (route) {
650 : state = static_cast<StaticRouteState *>
651 363 : (listener_->GetMatchState(table, route, info));
652 : }
653 :
654 363 : switch (req->type_) {
655 233 : case StaticRouteRequest::NEXTHOP_ADD_CHG: {
656 233 : assert(state);
657 233 : state->reset_deleted();
658 464 : if (route->IsDeleted() || !route->BestPath() ||
659 231 : !route->BestPath()->IsFeasible()) {
660 2 : break;
661 : }
662 :
663 : // Store the old path list
664 231 : typename StaticRouteT::NexthopPathIdList path_ids;
665 231 : path_ids.swap(*(info->NexthopPathIds()));
666 :
667 : // Populate the Nexthop PathID
668 231 : info->set_nexthop_route(route);
669 :
670 231 : info->AddStaticRoute(&path_ids);
671 231 : break;
672 231 : }
673 130 : case StaticRouteRequest::NEXTHOP_DELETE: {
674 130 : assert(state);
675 130 : info->RemoveStaticRoute();
676 130 : if (info->deleted() || route->IsDeleted()) {
677 130 : state->set_deleted();
678 : }
679 130 : info->set_nexthop_route(NULL);
680 130 : break;
681 : }
682 0 : default: {
683 0 : assert(0);
684 : break;
685 : }
686 : }
687 :
688 363 : if (state) {
689 363 : state->DecrementRefCnt();
690 363 : if (state->refcnt() == 0 && state->deleted()) {
691 128 : listener_->RemoveMatchState(table, route, info);
692 128 : delete state;
693 128 : if (!info->num_matchstate() && info->unregistered()) {
694 2 : UnregisterAndResolveStaticRoute(info);
695 : }
696 : }
697 : }
698 :
699 363 : delete req;
700 363 : return true;
701 : }
702 :
703 : template <typename T>
704 138 : bool StaticRouteMgr<T>::ProcessUnregisterList() {
705 138 : CHECK_CONCURRENCY("bgp::Config");
706 :
707 138 : for (StaticRouteProcessList::iterator
708 138 : it = unregister_static_route_list_.begin();
709 334 : it != unregister_static_route_list_.end(); ++it) {
710 196 : StaticRouteT *info = static_cast<StaticRouteT *>(it->get());
711 196 : listener_->UnregisterMatchCondition(info->bgp_table(), info);
712 196 : static_route_map_.erase(RouteKey(info->prefix(), info->nexthop()));
713 : }
714 :
715 138 : unregister_static_route_list_.clear();
716 :
717 138 : if (static_route_map_.empty()) {
718 122 : rtinstance_->server()->RemoveStaticRouteMgr(this);
719 : }
720 :
721 160 : if (!routing_instance()->deleted() &&
722 22 : routing_instance()->config()) {
723 22 : ProcessStaticRouteConfig();
724 : }
725 138 : return true;
726 : }
727 :
728 : template <typename T>
729 196 : void StaticRouteMgr<T>::UnregisterAndResolveStaticRoute(StaticRoutePtr entry) {
730 196 : std::scoped_lock lock(mutex_);
731 196 : unregister_static_route_list_.insert(entry);
732 196 : unregister_list_trigger_->Set();
733 196 : }
734 :
735 : template <typename T>
736 256 : void StaticRouteMgr<T>::LocateStaticRoutePrefix(
737 : const StaticRouteConfig &config) {
738 256 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
739 256 : AddressT address = this->GetAddress(config.address);
740 256 : PrefixT prefix(address, config.prefix_length);
741 256 : RouteKey route_key(prefix, config.nexthop);
742 :
743 : // Verify whether the entry already exists
744 256 : typename StaticRouteMap::iterator it = static_route_map_.find(route_key);
745 256 : if (it != static_route_map_.end()) {
746 : // Wait for the delete complete cb
747 60 : if (it->second->deleted()) return;
748 :
749 : StaticRouteT *match =
750 60 : static_cast<StaticRouteT *>(it->second.get());
751 : // Check whether the config has got updated
752 : typename StaticRouteT::CompareResult change =
753 60 : match->CompareConfig(config);
754 :
755 : // StaticRoutePrefix is the key, it can't change.
756 60 : assert(change != StaticRouteT::PrefixChange);
757 :
758 : // Skip if there's no change.
759 60 : if (change == StaticRouteT::NoChange)
760 48 : return;
761 :
762 : // Update the attributes and any existing BgpPaths.
763 12 : if (change == StaticRouteT::AttributeChange) {
764 12 : match->UpdateAttributes(config);
765 12 : match->UpdateStaticRoute();
766 12 : return;
767 : }
768 :
769 : // If the nexthop changes, remove the static route, if already added.
770 : // To do this, remove match condition and wait for remove completion.
771 0 : BgpConditionListener::RequestDoneCb callback =
772 : boost::bind(&StaticRouteMgr::StopStaticRouteDone, this, _1, _2);
773 0 : listener_->RemoveMatchCondition(
774 0 : match->bgp_table(), it->second.get(), callback);
775 0 : return;
776 0 : }
777 :
778 196 : StaticRouteT *match =
779 196 : new StaticRouteT(routing_instance(), this, prefix, config);
780 196 : StaticRoutePtr static_route_match = StaticRoutePtr(match);
781 :
782 196 : if (static_route_map_.empty())
783 122 : rtinstance_->server()->InsertStaticRouteMgr(this);
784 196 : static_route_map_.insert(make_pair(route_key, static_route_match));
785 :
786 196 : listener_->AddMatchCondition(match->bgp_table(), static_route_match.get(),
787 392 : BgpConditionListener::RequestDoneCb());
788 196 : }
789 :
790 : template <typename T>
791 196 : void StaticRouteMgr<T>::StopStaticRouteDone(BgpTable *table,
792 : ConditionMatch *info) {
793 196 : CHECK_CONCURRENCY("db::Walker");
794 196 : StaticRoute<T> *match = static_cast<StaticRoute<T> *>(info);
795 196 : match->set_unregistered();
796 196 : if (!match->num_matchstate() && match->unregistered()) {
797 194 : UnregisterAndResolveStaticRoute(match);
798 : }
799 196 : return;
800 : }
801 :
802 : template <typename T>
803 287 : void StaticRouteMgr<T>::RemoveStaticRoutePrefix(const RouteKey &static_route) {
804 287 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
805 287 : typename StaticRouteMap::iterator it = static_route_map_.find(static_route);
806 378 : if (it == static_route_map_.end()) return;
807 :
808 287 : if (it->second->deleted()) return;
809 :
810 196 : BgpConditionListener::RequestDoneCb callback =
811 : boost::bind(&StaticRouteMgr::StopStaticRouteDone, this, _1, _2);
812 :
813 196 : StaticRouteT *match = static_cast<StaticRouteT *>(it->second.get());
814 196 : listener_->RemoveMatchCondition(match->bgp_table(), match, callback);
815 196 : }
816 :
817 : template <typename T>
818 58 : void StaticRouteMgr<T>::ProcessStaticRouteConfig() {
819 58 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
820 58 : if (routing_instance()->deleted() || !routing_instance()->config()) return;
821 : const BgpInstanceConfig::StaticRouteList &list =
822 58 : routing_instance()->config()->static_routes(GetFamily());
823 : typedef BgpInstanceConfig::StaticRouteList::const_iterator iterator_t;
824 158 : for (iterator_t iter = list.begin(); iter != list.end(); ++iter) {
825 100 : LocateStaticRoutePrefix(*iter);
826 : }
827 : }
828 :
829 : template <typename T>
830 244 : StaticRouteMgr<T>::~StaticRouteMgr() {
831 122 : if (static_route_queue_)
832 122 : delete static_route_queue_;
833 366 : }
834 :
835 : template <typename T>
836 138 : void StaticRouteMgr<T>::UpdateStaticRouteConfig() {
837 138 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
838 138 : StaticRouteConfigList config_list =
839 138 : routing_instance()->config()->static_routes(GetFamily());
840 :
841 138 : map_difference(&static_route_map_,
842 : config_list.begin(), config_list.end(),
843 : boost::bind(&StaticRouteMgr<T>::CompareStaticRoute, this, _1, _2),
844 : boost::bind(&StaticRouteMgr<T>::AddStaticRoute, this, _1),
845 : boost::bind(&StaticRouteMgr<T>::DelStaticRoute, this, _1),
846 : boost::bind(&StaticRouteMgr<T>::UpdateStaticRoute, this, _1, _2));
847 138 : }
848 :
849 : template <typename T>
850 167 : void StaticRouteMgr<T>::FlushStaticRouteConfig() {
851 167 : CHECK_CONCURRENCY("bgp::Config");
852 167 : for (typename StaticRouteMap::iterator it = static_route_map_.begin();
853 418 : it != static_route_map_.end(); it++) {
854 251 : RemoveStaticRoutePrefix(it->first);
855 : }
856 167 : }
857 :
858 : template <typename T>
859 52 : int StaticRouteMgr<T>::CompareStaticRoute(
860 : typename StaticRouteMap::iterator loc,
861 : StaticRouteConfigList::iterator it) {
862 52 : AddressT address = this->GetAddress(it->address);
863 52 : PrefixT prefix(address, it->prefix_length);
864 52 : RouteKey route_key(prefix, it->nexthop);
865 52 : KEY_COMPARE(loc->first, route_key);
866 30 : return 0;
867 : }
868 :
869 : template <typename T>
870 126 : void StaticRouteMgr<T>::AddStaticRoute(StaticRouteConfigList::iterator it) {
871 126 : LocateStaticRoutePrefix(*it);
872 126 : }
873 :
874 : template <typename T>
875 36 : void StaticRouteMgr<T>::DelStaticRoute(typename StaticRouteMap::iterator loc) {
876 36 : RemoveStaticRoutePrefix(loc->first);
877 36 : }
878 :
879 : template <typename T>
880 30 : void StaticRouteMgr<T>::UpdateStaticRoute(typename StaticRouteMap::iterator loc,
881 : StaticRouteConfigList::iterator it) {
882 30 : LocateStaticRoutePrefix(*it);
883 30 : }
884 :
885 : template <typename T>
886 3650 : void StaticRouteMgr<T>::NotifyAllRoutes() {
887 3650 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
888 3650 : for (typename StaticRouteMap::iterator it = static_route_map_.begin();
889 10290 : it != static_route_map_.end(); ++it) {
890 : StaticRouteT *static_route =
891 6640 : static_cast<StaticRouteT *>(it->second.get());
892 6640 : static_route->NotifyRoute();
893 : }
894 3650 : }
895 :
896 : template <typename T>
897 2 : void StaticRouteMgr<T>::UpdateAllRoutes() {
898 2 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
899 2 : for (typename StaticRouteMap::iterator it = static_route_map_.begin();
900 4 : it != static_route_map_.end(); ++it) {
901 : StaticRouteT *static_route =
902 2 : static_cast<StaticRouteT *>(it->second.get());
903 2 : static_route->UpdateStaticRoute();
904 : }
905 2 : }
906 :
907 : template <typename T>
908 12 : void StaticRouteMgr<T>::DisableUnregisterTrigger() {
909 12 : unregister_list_trigger_->set_disable();
910 12 : }
911 :
912 : template <typename T>
913 12 : void StaticRouteMgr<T>::EnableUnregisterTrigger() {
914 12 : unregister_list_trigger_->set_enable();
915 12 : }
916 :
917 : template <typename T>
918 40 : uint32_t StaticRouteMgr<T>::GetRouteCount() const {
919 40 : CHECK_CONCURRENCY("bgp::ShowCommand");
920 40 : return static_route_map_.size();
921 : }
922 :
923 : template <typename T>
924 8 : uint32_t StaticRouteMgr<T>::GetDownRouteCount() const {
925 8 : CHECK_CONCURRENCY("bgp::ShowCommand");
926 8 : uint32_t count = 0;
927 8 : for (typename StaticRouteMap::const_iterator it = static_route_map_.begin();
928 32 : it != static_route_map_.end(); ++it) {
929 : const StaticRouteT *static_route =
930 24 : static_cast<const StaticRouteT *>(it->second.get());
931 24 : if (static_route->IsPending())
932 16 : count++;
933 : }
934 8 : return count;
935 : }
936 :
937 38 : template <typename T> bool StaticRouteMgr<T>::FillStaticRouteInfo(
938 : RoutingInstance *ri, StaticRouteEntriesInfo *info) const {
939 38 : if (static_route_map_.empty())
940 0 : return false;
941 :
942 38 : info->set_ri_name(ri->name());
943 86 : for (typename StaticRouteMgr<T>::StaticRouteMap::const_iterator it =
944 124 : static_route_map_.begin(); it != static_route_map_.end(); ++it) {
945 : StaticRoute<T> *match =
946 48 : static_cast<StaticRoute<T> *>(it->second.get());
947 48 : StaticRouteInfo static_info;
948 48 : match->FillShowInfo(&static_info);
949 48 : info->static_route_list.push_back(static_info);
950 : }
951 38 : return true;
952 : }
953 :
954 : // Explicit instantiation of StaticRouteMgr for INET and INET6.
955 : template class StaticRouteMgr<StaticRouteInet>;
956 : template class StaticRouteMgr<StaticRouteInet6>;
|