Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #ifndef SRC_BGP_ROUTING_INSTANCE_SERVICE_CHAINING_H_
6 : #define SRC_BGP_ROUTING_INSTANCE_SERVICE_CHAINING_H_
7 :
8 : #include <boost/ptr_container/ptr_map.hpp>
9 : #include <boost/shared_ptr.hpp>
10 :
11 : #include <list>
12 : #include <map>
13 : #include <set>
14 : #include <string>
15 : #include <vector>
16 : #include <mutex>
17 :
18 : #include "base/lifetime.h"
19 : #include "base/queue_task.h"
20 : #include "bgp/bgp_condition_listener.h"
21 : #include "bgp/inet/inet_route.h"
22 : #include "bgp/inet6/inet6_route.h"
23 : #include "bgp/evpn/evpn_route.h"
24 : #include "bgp/routing-instance/iservice_chain_mgr.h"
25 :
26 : class BgpRoute;
27 : class BgpTable;
28 : class RoutingInstance;
29 : class BgpTable;
30 : class BgpServer;
31 : class InetVpnRoute;
32 : class Inet6VpnRoute;
33 : class SandeshResponse;
34 : class ServiceChainConfig;
35 : class ServiceChainGroup;
36 : class ShowServicechainInfo;
37 :
38 : template <typename T> class ServiceChainMgr;
39 :
40 : template <typename T1, typename T2, typename T3, typename T4>
41 : struct ServiceChainBase {
42 : typedef T1 RouteT;
43 : typedef T2 VpnRouteT;
44 : typedef T3 PrefixT;
45 : typedef T4 AddressT;
46 : };
47 :
48 : class ServiceChainInet : public ServiceChainBase<
49 : InetRoute, InetVpnRoute, Ip4Prefix, Ip4Address> {
50 : };
51 :
52 : class ServiceChainInet6 : public ServiceChainBase<
53 : Inet6Route, Inet6VpnRoute, Inet6Prefix, Ip6Address> {
54 : };
55 :
56 : class ServiceChainEvpn : public ServiceChainBase<
57 : EvpnRoute, InetVpnRoute, EvpnPrefix, Ip4Address> {
58 : };
59 :
60 : class ServiceChainEvpn6 : public ServiceChainBase<
61 : EvpnRoute, Inet6VpnRoute, EvpnPrefix, Ip6Address> {
62 : };
63 :
64 : typedef ConditionMatchPtr ServiceChainPtr;
65 :
66 : class ServiceChainState : public ConditionMatchState {
67 : public:
68 8991 : explicit ServiceChainState(ServiceChainPtr info) : info_(info) {
69 8991 : }
70 : ServiceChainPtr info() { return info_; }
71 :
72 : private:
73 : ServiceChainPtr info_;
74 : DISALLOW_COPY_AND_ASSIGN(ServiceChainState);
75 : };
76 :
77 : template <typename T>
78 : class ServiceChainRequest {
79 : public:
80 : typedef typename T::PrefixT PrefixT;
81 :
82 : enum RequestType {
83 : MORE_SPECIFIC_ADD_CHG,
84 : MORE_SPECIFIC_DELETE,
85 : CONNECTED_ROUTE_ADD_CHG,
86 : CONNECTED_ROUTE_DELETE,
87 : EXT_CONNECT_ROUTE_ADD_CHG,
88 : EXT_CONNECT_ROUTE_DELETE,
89 : UPDATE_ALL_ROUTES,
90 : DELETE_ALL_ROUTES,
91 : STOP_CHAIN_DONE,
92 : };
93 :
94 43577 : ServiceChainRequest(RequestType type, BgpTable *table, BgpRoute *route,
95 : PrefixT aggregate_match, ServiceChainPtr info)
96 43577 : : type_(type),
97 43577 : table_(table),
98 43577 : rt_(route),
99 43577 : aggregate_match_(aggregate_match),
100 43574 : info_(info),
101 43574 : snh_resp_(NULL) {
102 43574 : }
103 :
104 : ServiceChainRequest(RequestType type, SandeshResponse *resp)
105 : : type_(type),
106 : table_(NULL),
107 : rt_(NULL),
108 : snh_resp_(resp) {
109 : }
110 :
111 : RequestType type_;
112 : BgpTable *table_;
113 : BgpRoute *rt_;
114 : PrefixT aggregate_match_;
115 : ServiceChainPtr info_;
116 : SandeshResponse *snh_resp_;
117 :
118 : private:
119 : DISALLOW_COPY_AND_ASSIGN(ServiceChainRequest);
120 : };
121 :
122 : template <typename T>
123 : class ServiceChain : public ConditionMatch {
124 : public:
125 : typedef typename T::RouteT RouteT;
126 : typedef typename T::VpnRouteT VpnRouteT;
127 : typedef typename T::PrefixT PrefixT;
128 : typedef typename T::AddressT AddressT;
129 : typedef ServiceChainRequest<T> ServiceChainRequestT;
130 : typedef ServiceChainMgr<T> ServiceChainMgrT;
131 :
132 : // List of more specific routes resulted in Aggregate route
133 : typedef std::set<BgpRoute *> RouteList;
134 :
135 : // Map of Virtual Network subnet prefix to List of More Specific routes
136 : typedef std::map<PrefixT, RouteList> PrefixToRouteListMap;
137 :
138 : // Map of External Connecting route to Service Chain Route
139 : typedef std::set<BgpRoute *> ExtConnectRouteList;
140 :
141 : // List of path ids for the connected route
142 : typedef std::set<uint32_t> ConnectedPathIdList;
143 :
144 : ServiceChain(ServiceChainMgrT *manager, ServiceChainGroup *group,
145 : RoutingInstance *src, RoutingInstance *dest, RoutingInstance *connected,
146 : const std::vector<std::string> &subnets, AddressT addr, bool head,
147 : bool retain_as_path);
148 163082 : Address::Family GetFamily() const { return manager_->GetFamily(); }
149 47070 : Address::Family GetConnectedFamily() const {
150 47070 : return manager_->GetConnectedFamily();
151 : }
152 54206 : SCAddress::Family GetSCFamily() const { return manager_->GetSCFamily(); }
153 :
154 : // Delete is triggered from configuration, not via LifetimeManager.
155 5397 : void ManagedDelete() { }
156 :
157 : bool CompareServiceChainConfig(const ServiceChainConfig &config);
158 : void RemoveMatchState(BgpRoute *route, ServiceChainState *state);
159 :
160 : void SetConnectedRoute(BgpRoute *connected);
161 : bool IsConnectedRouteValid() const;
162 45650 : const ConnectedPathIdList &GetConnectedPathIds() {
163 45650 : return connected_path_ids_;
164 : }
165 :
166 110167 : BgpRoute *connected_route() const { return connected_route_; }
167 19660 : RoutingInstance *src_routing_instance() const { return src_; }
168 16468 : RoutingInstance *connected_routing_instance() const { return connected_; }
169 35112 : RoutingInstance *dest_routing_instance() const { return dest_; }
170 54339 : const AddressT &service_chain_addr() const { return service_chain_addr_; }
171 : void UpdateServiceChainRoute(PrefixT prefix, const RouteT *orig_route,
172 : const ConnectedPathIdList &old_path_ids, bool aggregate);
173 : void DeleteServiceChainRoute(PrefixT prefix, bool aggregate);
174 :
175 : bool AddMoreSpecific(PrefixT aggregate, BgpRoute *more_specific);
176 : bool DeleteMoreSpecific(PrefixT aggregate, BgpRoute *more_specific);
177 :
178 : BgpTable *src_table() const;
179 : BgpTable *connected_table() const;
180 : BgpTable *dest_table() const;
181 :
182 7890 : ServiceChainGroup *group() const { return group_; }
183 208 : void clear_group() { group_ = NULL; }
184 :
185 6201 : PrefixToRouteListMap *prefix_to_route_list_map() {
186 6201 : return &prefix_to_routelist_map_;
187 : }
188 174553 : const PrefixToRouteListMap *prefix_to_route_list_map() const {
189 174553 : return &prefix_to_routelist_map_;
190 : }
191 :
192 : virtual bool Match(BgpServer *server, BgpTable *table, BgpRoute *route,
193 : bool deleted);
194 : virtual std::string ToString() const;
195 :
196 : void FillServiceChainInfo(ShowServicechainInfo *info) const;
197 :
198 2263 : void set_connected_table_unregistered() {
199 2263 : connected_table_unregistered_ = true;
200 2263 : }
201 2263 : void set_dest_table_unregistered() {
202 2263 : dest_table_unregistered_ = true;
203 2263 : }
204 42096 : bool dest_table_unregistered() const {
205 42096 : return dest_table_unregistered_;
206 : }
207 42178 : bool connected_table_unregistered() const {
208 42178 : return connected_table_unregistered_;
209 : }
210 6361 : bool unregistered() const {
211 6361 : return connected_table_unregistered_ && dest_table_unregistered_;
212 : }
213 :
214 288 : const ExtConnectRouteList &ext_connecting_routes() const {
215 288 : return ext_connect_routes_;
216 : }
217 36406 : ExtConnectRouteList *ext_connecting_routes() {
218 36406 : return &ext_connect_routes_;
219 : }
220 :
221 53509 : bool aggregate_enable() const { return aggregate_; }
222 79690 : bool is_sc_head() const { return sc_head_; }
223 18877 : bool retain_as_path() const { return retain_as_path_; }
224 1672 : void set_aggregate_enable() { aggregate_ = true; }
225 6935 : bool group_oper_state_up() const { return group_oper_state_up_; }
226 192 : void set_group_oper_state_up(bool up) { group_oper_state_up_ = up; }
227 :
228 : private:
229 : ServiceChainMgrT *manager_;
230 : ServiceChainGroup *group_;
231 : RoutingInstance *src_;
232 : RoutingInstance *dest_;
233 : RoutingInstance *connected_;
234 : ConnectedPathIdList connected_path_ids_;
235 : BgpRoute *connected_route_;
236 : AddressT service_chain_addr_;
237 : PrefixToRouteListMap prefix_to_routelist_map_;
238 : ExtConnectRouteList ext_connect_routes_;
239 : bool group_oper_state_up_;
240 : bool connected_table_unregistered_;
241 : bool dest_table_unregistered_;
242 : bool aggregate_; // Whether the host route needs to be aggregated
243 : bool sc_head_; // Whether this SI is at the head of the chain
244 : bool retain_as_path_;
245 : LifetimeRef<ServiceChain> src_table_delete_ref_;
246 : LifetimeRef<ServiceChain> dest_table_delete_ref_;
247 : LifetimeRef<ServiceChain> connected_table_delete_ref_;
248 :
249 : // Helper function to match
250 : bool IsMoreSpecific(BgpRoute *route, PrefixT *aggregate_match) const;
251 : bool IsAggregate(BgpRoute *route) const;
252 : bool IsConnectedRoute(BgpRoute *route, bool is_conn_table=false) const;
253 : bool IsEvpnType5Route(BgpRoute *route) const;
254 : void GetReplicationFamilyInfo(DBTablePartition *&partition,
255 : BgpRoute *&route, BgpTable *&table, PrefixT prefix, bool create);
256 : void ProcessServiceChainPath(uint32_t path_id, BgpPath *path,
257 : BgpAttrPtr attr, BgpRoute *&route, DBTablePartition *&partition,
258 : bool aggregate, BgpTable *bgptable);
259 : void UpdateServiceChainRouteInternal(const RouteT *orig_route,
260 : const ConnectedPathIdList &old_path_ids, BgpRoute *sc_route,
261 : DBTablePartition *partition, BgpTable *bgptable, bool aggregate);
262 : void DeleteServiceChainRouteInternal(BgpRoute *service_chain_route,
263 : DBTablePartition *partition,
264 : BgpTable *bgptable, bool aggregate);
265 :
266 : DISALLOW_COPY_AND_ASSIGN(ServiceChain);
267 : };
268 :
269 : //
270 : // This represents a service chain group within a ServiceChainMgr. All the
271 : // individual ServiceChains that are part of the same logical service chain
272 : // in the configuration are part of a given ServiceChainGroup.
273 : //
274 : // A ServiceChainGroup maintains operational state for itself based on the
275 : // operational state of the individual ServiceChains that are part of the
276 : // group. This is used to force fate sharing for all the ServiceChains in
277 : // the group. If the operational status of the group is down, re-originated
278 : // routes for all ServiceChainTs are deleted/withdrawn.
279 : //
280 : // A ServiceChainGroup gets created when the ServiceChainMgr processes a
281 : // ServiceChainConfig with a non-empty service_chain_id. It gets deleted
282 : // when there are no more ServiceChainTs or pending chains that belong to
283 : // the ServiceChainGroup.
284 : //
285 : // The set of member chains is tracked using RoutingInstance pointers (as
286 : // opposed to ServiceChainT pointers) so that the state of pending chains
287 : // can also be tracked. Note that ServiceChainT objects are not allocated
288 : // for pending chains.
289 : //
290 : // The membership of RoutingInstances in a ServiceChainGroup is updated as
291 : // the group in the ServiceChainConfig for the RoutingInstances is updated.
292 : //
293 : // The operational state of the group is updated whenever a RoutingInstance
294 : // is added or deleted to/from the ServiceChainGroup and when the connected
295 : // route for the ServiceChainT is added/updated/deleted.
296 : //
297 : class ServiceChainGroup {
298 : public:
299 : ServiceChainGroup(IServiceChainMgr *manager, const std::string &name);
300 : ~ServiceChainGroup();
301 :
302 : void AddRoutingInstance(RoutingInstance *rtinstance);
303 : void DeleteRoutingInstance(RoutingInstance *rtinstance);
304 : void UpdateOperState();
305 624 : std::string name() const { return name_; }
306 1055 : bool empty() const { return chain_set_.empty(); }
307 216 : bool oper_state_up() const { return oper_state_up_; }
308 :
309 : private:
310 : typedef std::set<RoutingInstance *> ServiceChainSet;
311 :
312 : IServiceChainMgr *manager_;
313 : std::string name_;
314 : ServiceChainSet chain_set_;
315 : bool oper_state_up_;
316 : };
317 :
318 : template <typename T>
319 : class ServiceChainMgr : public IServiceChainMgr {
320 : public:
321 : typedef typename T::RouteT RouteT;
322 : typedef typename T::PrefixT PrefixT;
323 : typedef typename T::AddressT AddressT;
324 : typedef ServiceChain<T> ServiceChainT;
325 : typedef ServiceChainRequest<T> ServiceChainRequestT;
326 :
327 : explicit ServiceChainMgr(BgpServer *server);
328 : virtual ~ServiceChainMgr();
329 :
330 : void Terminate();
331 : void ManagedDelete();
332 : bool MayDelete() const;
333 : void RetryDelete();
334 :
335 : // Creates a new service chain between two Virtual network
336 : // If the two routing instance is already connected, it updates the
337 : // connected route address for existing service chain
338 : virtual bool LocateServiceChain(RoutingInstance *rtinstance,
339 : const ServiceChainConfig &config);
340 :
341 : // Remove the existing service chain between from routing instance
342 : virtual void StopServiceChain(RoutingInstance *rtinstance);
343 : virtual void UpdateServiceChain(RoutingInstance *rtinstance,
344 : bool group_oper_state_up);
345 : void UpdateServiceChainGroup(ServiceChainGroup *group);
346 :
347 5200 : virtual size_t PendingQueueSize() const { return pending_chains_.size(); }
348 3521 : virtual size_t ResolvedQueueSize() const { return chain_set_.size(); }
349 : virtual uint32_t GetDownServiceChainCount() const;
350 6664436 : virtual bool IsQueueEmpty() const { return process_queue_->IsQueueEmpty(); }
351 : virtual bool ServiceChainIsPending(RoutingInstance *rtinstance,
352 : std::string *reason = NULL) const;
353 : virtual bool ServiceChainIsUp(RoutingInstance *rtinstance) const;
354 :
355 : Address::Family GetFamily() const;
356 : Address::Family GetConnectedFamily() const;
357 : SCAddress::Family GetSCFamily() const;
358 : void Enqueue(ServiceChainRequestT *req);
359 : virtual bool FillServiceChainInfo(RoutingInstance *rtinstance,
360 : ShowServicechainInfo *info) const;
361 : virtual BgpConditionListener *GetListener();
362 : private:
363 : template <typename U> friend class ServiceChainIntegrationTest;
364 : template <typename U> friend class ServiceChainTest;
365 : class DeleteActor;
366 :
367 : // All service chain related actions are performed in the context
368 : // of this task. This task has exclusion with db::DBTable task.
369 : static int service_chain_task_id_;
370 :
371 : struct PendingChainState {
372 0 : PendingChainState() : group(NULL) {
373 0 : }
374 1528 : PendingChainState(ServiceChainGroup *group, std::string reason)
375 1528 : : group(group), reason(reason) {
376 1528 : }
377 : ServiceChainGroup *group;
378 : std::string reason;
379 : };
380 :
381 : // Set of service chains created in the system
382 : typedef std::map<RoutingInstance *, ServiceChainPtr> ServiceChainMap;
383 :
384 : // At the time of processing, service chain request, all required info
385 : // may not be available (e.g. dest routing instance may not be created,
386 : // or marked deleted etc). Create a list of pending service chains that
387 : // are waiting to get created and maintain a reason string for why the
388 : // service chain is on the pending list.
389 : typedef std::map<RoutingInstance *, PendingChainState> PendingChainList;
390 :
391 : typedef boost::ptr_map<std::string, ServiceChainGroup> GroupMap;
392 : typedef std::set<ServiceChainGroup *> GroupSet;
393 :
394 : ServiceChainGroup *FindServiceChainGroup(RoutingInstance *rtinstance);
395 : ServiceChainGroup *FindServiceChainGroup(const std::string &group_name);
396 : ServiceChainGroup *LocateServiceChainGroup(const std::string &group_name);
397 : bool ProcessServiceChainGroups();
398 :
399 : bool RequestHandler(ServiceChainRequestT *req);
400 : void StopServiceChainDone(BgpTable *table, ConditionMatch *info);
401 : ServiceChainT *FindServiceChain(const std::string &instance) const;
402 : ServiceChainT *FindServiceChain(RoutingInstance *rtinstance) const;
403 :
404 1528 : void AddPendingServiceChain(RoutingInstance *rtinstance,
405 : ServiceChainGroup *group, std::string reason) {
406 1528 : PendingChainState state(group, reason);
407 1528 : pending_chains_.insert(std::make_pair(rtinstance, state));
408 1528 : }
409 3305 : void DeletePendingServiceChain(RoutingInstance *rtinstance) {
410 3305 : pending_chains_.erase(rtinstance);
411 3305 : }
412 514 : PendingChainState GetPendingServiceChain(RoutingInstance *rtinstance) {
413 514 : typename PendingChainList::const_iterator loc =
414 514 : pending_chains_.find(rtinstance);
415 514 : if (loc != pending_chains_.end()) {
416 514 : return loc->second;
417 : } else {
418 0 : return PendingChainState();
419 : }
420 : }
421 :
422 : void UpdateServiceChainRoutes(ServiceChainT *chain,
423 : const typename ServiceChainT::ConnectedPathIdList &old_path_ids);
424 : void DeleteServiceChainRoutes(ServiceChainT *chain);
425 :
426 : void StartResolve();
427 : bool ResolvePendingServiceChain();
428 : void RoutingInstanceCallback(std::string name, int op);
429 : void PeerRegistrationCallback(IPeer *peer, BgpTable *table,
430 : bool unregister);
431 :
432 2263 : bool aggregate_host_route() const { return aggregate_host_route_; }
433 1424 : virtual void set_aggregate_host_route(bool value) {
434 1424 : aggregate_host_route_ = value;
435 1424 : }
436 :
437 : virtual void DisableResolveTrigger();
438 : virtual void EnableResolveTrigger();
439 : virtual void DisableGroupTrigger();
440 : virtual void EnableGroupTrigger();
441 :
442 : // Work Queue to handle requests posted from Match function, called
443 : // in the context of db::DBTable task.
444 : // The actions are performed in the bgp::ServiceChain task context.
445 128 : virtual void DisableQueue() { process_queue_->set_disable(true); }
446 128 : virtual void EnableQueue() { process_queue_->set_disable(false); }
447 :
448 : // Mutex is used to serialize access from multiple bgp::ConfigHelper tasks.
449 : BgpServer *server_;
450 : std::mutex mutex_;
451 : BgpConditionListener *listener_;
452 : boost::scoped_ptr<TaskTrigger> resolve_trigger_;
453 : boost::scoped_ptr<WorkQueue<ServiceChainRequestT *> > process_queue_;
454 : ServiceChainMap chain_set_;
455 : PendingChainList pending_chains_;
456 : boost::scoped_ptr<TaskTrigger> group_trigger_;
457 : GroupMap group_map_;
458 : GroupSet group_set_;
459 : bool aggregate_host_route_;
460 : int id_;
461 : int registration_id_;
462 : boost::scoped_ptr<DeleteActor> deleter_;
463 : LifetimeRef<ServiceChainMgr> server_delete_ref_;
464 :
465 : DISALLOW_COPY_AND_ASSIGN(ServiceChainMgr);
466 : };
467 :
468 : typedef ServiceChainMgr<ServiceChainInet> ServiceChainMgrInet;
469 : typedef ServiceChainMgr<ServiceChainInet6> ServiceChainMgrInet6;
470 : typedef ServiceChainMgr<ServiceChainEvpn> ServiceChainMgrEvpn;
471 : typedef ServiceChainMgr<ServiceChainEvpn6> ServiceChainMgrEvpn6;
472 :
473 : #endif // SRC_BGP_ROUTING_INSTANCE_SERVICE_CHAINING_H_
|