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