LCOV - code coverage report
Current view: top level - bgp/routing-instance - service_chaining.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 77 80 96.2 %
Date: 2026-06-18 01:51:13 Functions: 160 164 97.6 %
Legend: Lines: hit not hit

          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        8988 :     explicit ServiceChainState(ServiceChainPtr info) : info_(info) {
      69        8990 :     }
      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       43562 :     ServiceChainRequest(RequestType type, BgpTable *table, BgpRoute *route,
      95             :         PrefixT aggregate_match, ServiceChainPtr info)
      96       43562 :         : type_(type),
      97       43562 :           table_(table),
      98       43562 :           rt_(route),
      99       43562 :           aggregate_match_(aggregate_match),
     100       43560 :           info_(info),
     101       43562 :           snh_resp_(NULL) {
     102       43562 :     }
     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      163613 :     Address::Family GetFamily() const { return manager_->GetFamily(); }
     149       47394 :     Address::Family GetConnectedFamily() const {
     150       47394 :         return manager_->GetConnectedFamily();
     151             :     }
     152       54295 :     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       45521 :     const ConnectedPathIdList &GetConnectedPathIds() {
     163       45521 :         return connected_path_ids_;
     164             :     }
     165             : 
     166      110450 :     BgpRoute *connected_route() const { return connected_route_; }
     167       19680 :     RoutingInstance *src_routing_instance() const { return src_; }
     168       16490 :     RoutingInstance *connected_routing_instance() const { return connected_; }
     169       35152 :     RoutingInstance *dest_routing_instance() const { return dest_; }
     170       54547 :     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        7896 :     ServiceChainGroup *group() const { return group_; }
     183         208 :     void clear_group() { group_ = NULL; }
     184             : 
     185        6098 :     PrefixToRouteListMap *prefix_to_route_list_map() {
     186        6098 :         return &prefix_to_routelist_map_;
     187             :     }
     188      175145 :     const PrefixToRouteListMap *prefix_to_route_list_map() const {
     189      175145 :         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       42162 :     bool dest_table_unregistered() const {
     205       42162 :         return dest_table_unregistered_;
     206             :     }
     207       42350 :     bool connected_table_unregistered() const {
     208       42350 :         return connected_table_unregistered_;
     209             :     }
     210        6357 :     bool unregistered() const {
     211        6357 :         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       36479 :     ExtConnectRouteList *ext_connecting_routes() {
     218       36479 :         return &ext_connect_routes_;
     219             :     }
     220             : 
     221       53614 :     bool aggregate_enable() const { return aggregate_; }
     222       79854 :     bool is_sc_head() const { return sc_head_; }
     223       18940 :     bool retain_as_path() const { return retain_as_path_; }
     224        1672 :     void set_aggregate_enable() { aggregate_ = true; }
     225        6536 :     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        1052 :     bool empty() const { return chain_set_.empty(); }
     307         215 :     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        5304 :     virtual size_t PendingQueueSize() const { return pending_chains_.size(); }
     348        3573 :     virtual size_t ResolvedQueueSize() const { return chain_set_.size(); }
     349             :     virtual uint32_t GetDownServiceChainCount() const;
     350     6660369 :     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        1509 :         PendingChainState(ServiceChainGroup *group, std::string reason)
     375        1509 :             : group(group), reason(reason) {
     376        1509 :         }
     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        1509 :     void AddPendingServiceChain(RoutingInstance *rtinstance,
     405             :         ServiceChainGroup *group, std::string reason) {
     406        1509 :         PendingChainState state(group, reason);
     407        1509 :         pending_chains_.insert(std::make_pair(rtinstance, state));
     408        1509 :     }
     409        3286 :     void DeletePendingServiceChain(RoutingInstance *rtinstance) {
     410        3286 :         pending_chains_.erase(rtinstance);
     411        3286 :     }
     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_

Generated by: LCOV version 1.14