LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_mgmt.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 7 8 87.5 %
Date: 2026-06-11 01:56:02 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #ifndef __AGENT_FLOW_TABLE_MGMT_H__
       5             : #define __AGENT_FLOW_TABLE_MGMT_H__
       6             : 
       7             : #include <boost/scoped_ptr.hpp>
       8             : #include "pkt/flow_table.h"
       9             : #include <pkt/flow_mgmt/flow_mgmt_dbclient.h>
      10             : #include <pkt/flow_mgmt/flow_mgmt_tree.h>
      11             : #include "pkt/flow_event.h"
      12             : 
      13             : ////////////////////////////////////////////////////////////////////////////
      14             : // Flow Management module is responsible to keep flow action in-sync with
      15             : // changes to operational-db changes.
      16             : //
      17             : // Flow Management module tracks following,
      18             : // 1. Changes to fields of interest in the operational-db
      19             : // 2. Flows dependenent on operational-db entries
      20             : //
      21             : // On any change to an operational-db, it will ensure the dependent flows are
      22             : // revaluated to keep the flow action in-sync with latest operational state
      23             : //
      24             : // A flow can depend on following operational-entires,
      25             : // 1. Interface : Flow depends on the SG-Id of interface
      26             : // 2. VN        : Flow depends on policy of VN
      27             : // 3. ACL       : Flow depends on ACL Entries in ACL
      28             : // 4. Route     : Flow depends on the SG-Id list in the route for both source
      29             : //                and destination addresses
      30             : // 5. NextHop   : Flow depends on NH for RPF checks and for ECMP Component index
      31             : //
      32             : // An operational entry can potentially have many flows dependent on it. On
      33             : // change to an operational entry if flows are processed inline, it can lead to
      34             : // significant latency. The flow management module runs from a work-queue
      35             : // (flow-manager queue) to avoid the latency.
      36             : //
      37             : // The Flow Management module is responsible only to track the dependency
      38             : // between flows and operational entries. It does not *own* the flow entries.
      39             : // When flow management module identifies that a flow has to be revaluated
      40             : // it will invoke flow-table APIs.
      41             : //
      42             : // There are two sub-modules,
      43             : // - Flow Management DBClient
      44             : //   This module registers to DB notification for all tables of interest. It
      45             : //   enqueues events for flow revaluation in response to DBTable changes
      46             : // - Flow Management Tree module
      47             : //   This module maintains different data-structures to track flows affected
      48             : //   by change to a DBEntry. Its also responsible to trigger revaluation of
      49             : //   flows on change to a DBEntry
      50             : //
      51             : // There are 2 work-queues defined for flow-management,
      52             : // - Flow Management Request
      53             : //   All request events to flow-management module are enqueued thru this.
      54             : //   The Flow Management Tree module acts on events on this queue.
      55             : //   * Add of FLow
      56             : //   * Delete of Flow
      57             : //   * Add of DBEntry
      58             : //   * Change of DBEntry
      59             : //   * Delete of DBEntry
      60             : //   * Export of Flow
      61             : //
      62             : // - Flow Events
      63             : //   Flow Management Tree module may generate events in response to
      64             : //   requests. The response events are enqueued here. Example events are,
      65             : //   * Flow revaluation in response to DBEntry change
      66             : //   * Flow revaluation in response to DBEntry Add/Delete
      67             : //   * Flow deletion in response to DBEntry delete
      68             : //
      69             : // Workflow for flow manager module is given below,
      70             : // 1. Flow Table module will enqueue message to Flow Management queue on
      71             : //    add/delete/change of a flow. On Flow delete event, Flow Table module will
      72             : //    will also enqueue export of the flow.
      73             : // 2. Flow stats collection module will enqueue message to Flow Management
      74             : //    queue on export of flow
      75             : // 3. Flow Management module builds the following tracking information
      76             : //    - Operational entry to list of dependent flows
      77             : //    - Flow entry to list of operational-entries it is dependent on
      78             : // 4. DBClient module registers to DBTables of interest and tracks changes to
      79             : //    operational-db entries
      80             : // 5. Flow Table module will enqueue a message to Flow Management queue on
      81             : //    add/delete/change of operational entries
      82             : // 6. The action in flow-management module for operational entry events will
      83             : //    depend on the operational entry type
      84             : //
      85             : //    VN Add/Change      : Revaluate flows for change in policy
      86             : //    VN Delete          : Delete dependent flows
      87             : //    VMI Add/Change     : Revaluate flows for change in SG entry in VMI
      88             : //    Interface Delete   : Delete dependent flows
      89             : //    NH Add/Change      : Revaluate flows for change in RPF-NH
      90             : //    NH Delete          : Delete dependent flows
      91             : //    ACL Add/Change     : Revaluate flows for change in ACL rules
      92             : //    ACL Delete         : Delete dependent flows
      93             : //    Bridge Add/Change  : Flow entries are revaluated for change in SG
      94             : //    Bridge Delete      : Delete dependent flows
      95             : //    Inet Route Add     : Add of an inet route can potentially alter the route
      96             : //                         used for a route. It can also potentially alter
      97             : //                         other attributes such as floating-ip used etc...
      98             : //                         So, all flows dependent on the "covering route" are
      99             : //                         enqueued for revluation by PktFlowInfo module
     100             : //    Inet Route Change  : Revluate for for change in RPF-NH, VN and SG
     101             : //    Inet Route Delete  : Flows depending on this route will start using the
     102             : //                         covering route. It can also potentially alter
     103             : //                         other attributes such as floating-ip used etc...
     104             : //                         So, all flows dependent on the "covering route" are
     105             : //                         enqueued for revluation by PktFlowInfo module
     106             : //
     107             : // Concurrency and references
     108             : // The Flow Management module can often lead to compute spikes. To ensure this
     109             : // doesnt affect flow setup rates, it is preferable to run flow-management
     110             : // module in parallel to both DBTable and Flow setup/teardown task.
     111             : //
     112             : // Since flow-management module runs in parallel to DBTable/Flow tasks, we must
     113             : // ensure that flows and the operational dbentries are not deleted till
     114             : // flow-management module references are gone. This is achieved by following,
     115             : //
     116             : // Flow reference
     117             : // --------------
     118             : // 1. All message between flow-management and flow-table/flow-stats module will
     119             : //    hold object references. This will ensure ref-count for object dont drop
     120             : //    till messages are processed.
     121             : // 2. Each flow seen by flow-management will hold a reference to FlowEntryInfo
     122             : //    in FlowEntry as flow_mgmt_info_
     123             : //
     124             : // Per FlowEntry mutex is used to synchronize access to same Flow between
     125             : // FlowTable and Flow Management module
     126             : //
     127             : // DBEntry reference
     128             : // -----------------
     129             : // Flow Management module will rely on DBState set by DBClient module to
     130             : // ensure a DBEntry is not deleted till all its flows are deleted.
     131             : //
     132             : // Flow Management DBClient               Flow Management module
     133             : //
     134             : // 1. On DBEntry deletion, enqueue a
     135             : //    message to Flow Management module
     136             : //                                        2. Find all dependent flows and
     137             : //                                           enqueue flow-delete request for
     138             : //                                           all flows. Mark the entry as
     139             : //                                           deleted
     140             : // 3. Delete the flow and enqueue a
     141             : //    flow-deleted message to
     142             : //    flow-management module
     143             : //                                        4. Find all operational entries the
     144             : //                                           flow is dependent on and remove
     145             : //                                           the flow from their dependent tree.
     146             : //                                           If an operational entry is deleted
     147             : //                                           and there are no more dependent
     148             : //                                           flows, enqueue a message to delete
     149             : //                                           the operational entry
     150             : // 5. Remove DBState for the DBEntry
     151             : //
     152             : // RouteTable reference
     153             : // -----------------
     154             : // The Inet and Bridge route tables should not be deleted till all flows using
     155             : // them are deleted. Flow Management module holds Lifetime reference to ensure
     156             : // DBTables are deleted only after all its flows are deleted
     157             : //
     158             : // VRF Reference
     159             : // -------------
     160             : // When a VRF add is seen, the DBClient sub-module will register for Inet and
     161             : // Bridge route tables for the VRF. The unregister for these tables should
     162             : // happen only after all flows on them are deleted. The Flow Management module
     163             : // will enqueue delete of VRF only after flow entries in all Inet and Bridge
     164             : // routes are deleted
     165             : //
     166             : // Additional functionality:
     167             : // -------------------------
     168             : // A few more additional functionality is pushed to flow-management module
     169             : // 1. Logging of flows
     170             : // 2. Flow UVE
     171             : // 3. Tracking per VN flows
     172             : //
     173             : // Duplicate Deletes:
     174             : // -----------------
     175             : // Consider following sequence of events,
     176             : // 1. Add ACL
     177             : // 2. Delete ACL
     178             : // 3. Delete ACL
     179             : //
     180             : // Correspondingly, 3 events are enqueued to Flow Management Request queue.
     181             : // When event (2) is processed, if ACL does not have any more flows, it will
     182             : // result in removing DBState for the ACL and eventual free of ACL before
     183             : // event (3) is processed. When event (3) is being processed, it may refer to
     184             : // a free'd DBEntry
     185             : //
     186             : // We use a gen-id to handle this scenario.The gen-id is incremented on every
     187             : // Delete notification received for DBEntry. When DELETE event is enqueued, it
     188             : // will also carry the gen-id field. The gen-id is also carried in the
     189             : // response events generated.
     190             : //
     191             : // When Flow Management Dbclient module receives FREE_DBENTRY event, it will
     192             : // ignore the message if gen-id does not match with latest value.
     193             : ////////////////////////////////////////////////////////////////////////////
     194             : 
     195             : ////////////////////////////////////////////////////////////////////////////
     196             : // Flow Management module maintains following data structures
     197             : //
     198             : // - FlowEntryTree : Tree of all flow entries
     199             : //   FlowEntryPtr  : Key for the tree. Holds reference to FlowEntry
     200             : //   FlowEntryInfo : Data for the tree. Contains tree of DBEntries the flow is
     201             : //                   dependent on.
     202             : //
     203             : // - FlowMgmtTree  : Per operational entry tree. Tracks flow entries dependent
     204             : //                   on the operational entry
     205             : //
     206             : //                   An entry into the tree can be added when,
     207             : //                   1. Flow is added/changed and it refers to the DBEntry
     208             : //                   or
     209             : //                   2. DBEntry add/change message is got from DBClient
     210             : //
     211             : //                   Entry from the tree is removed,
     212             : //                   1. All flows dependent on the entry are deleted
     213             : //                   AND
     214             : //                   2. DBEntry delete message is got from DBClient
     215             : //
     216             : //   FlowEntryKey  : Key for the tree. Contains DBEntry pointer as key
     217             : //   FlowMgmtEntry : Data fot the tree. Maintains intrusive-list of
     218             : //                   FlowMgmtKeyNodes(which contains references to Flow entries)
     219             : //                   dependent on the DBEntry
     220             : //
     221             : // - AclFlowMgmtTree        : FlowMgmtTree for ACL
     222             : // - InterfaceFlowMgmtTree  : FlowMgmtTree for VM-Interfaces
     223             : // - VnFlowMgmtTree         : FlowMgmtTree for VN
     224             : // - InetRouteFlowMgmtTree  : FlowMgmtTree for IPv4 routes
     225             : // - InetRouteFlowMgmtTree  : FlowMgmtTree for IPv6 routes
     226             : // - BridgeRouteFlowMgmtTree: FlowMgmtTree for Bridge routes
     227             : // - NhFlowMgmtTree         : FlowMgmtTree for NH
     228             : // - VrfFlowMgmtTree        : FlowMgmtTree for VRF. It doesnt track the flows
     229             : //                            for the VRF. But is used to ensure VRF entry is
     230             : //                            not deleted till all route-entries are freed and
     231             : //                            DELETE event for VRF is processed
     232             : // - BgpAsAServiceFlowMgmtTree : FlowMgmtTree per control-node. This is
     233             : //                               maintained per control node because VMI can
     234             : //                               establish a bgp peer session with each control
     235             : //                               node.
     236             : ////////////////////////////////////////////////////////////////////////////
     237             : 
     238             : class FlowMgmtManager {
     239             : public:
     240             :     typedef boost::shared_ptr<FlowMgmtRequest> FlowMgmtRequestPtr;
     241             :     typedef WorkQueue<FlowMgmtRequestPtr> FlowMgmtQueue;
     242             : 
     243             :     // Comparator for FlowEntryPtr
     244             :     struct FlowEntryRefCmp {
     245             :         bool operator()(const FlowEntryPtr &l, const FlowEntryPtr &r) {
     246             :             FlowEntry *lhs = l.get();
     247             :             FlowEntry *rhs = r.get();
     248             : 
     249             :             return (lhs < rhs);
     250             :         }
     251             :     };
     252             : 
     253             :     // We want flow to be valid till Flow Management task is complete. So,
     254             :     // use FlowEntryPtr as key and hold reference to flow till we are done
     255             :     typedef std::map<FlowEntryPtr, FlowEntryInfo, FlowEntryRefCmp>
     256             :         FlowEntryTree;
     257             : 
     258             :     FlowMgmtManager(Agent *agent, uint16_t table_index);
     259           8 :     virtual ~FlowMgmtManager() { }
     260             : 
     261             :     void Init();
     262             :     void Shutdown();
     263             :     static void InitLogQueue(Agent *agent);
     264             :     static void ShutdownLogQueue();
     265             :     static void LogFlowUnlocked(FlowEntry *flow, const std::string &op);
     266             :     static bool LogHandler(FlowMgmtRequestPtr req);
     267             : 
     268             :     bool RequestHandler(FlowMgmtRequestPtr req);
     269             :     bool DBRequestHandler(FlowMgmtRequestPtr req);
     270             :     static bool ProcessEvent(FlowMgmtRequest *req, FlowMgmtKey *key,
     271             :                              FlowMgmtTree *tree);
     272             : 
     273             :     bool DBRequestHandler(FlowMgmtRequest *req, const DBEntry *entry);
     274             :     bool BgpAsAServiceRequestHandler(FlowMgmtRequest *req);
     275             :     bool DbClientHandler(const DBEntry *entry);
     276             :     void EnqueueFlowEvent(FlowEvent *event);
     277             :     void NonOperEntryEvent(FlowEvent::Event event, FlowEntry *flow);
     278             :     void DBEntryEvent(FlowEvent::Event event, FlowMgmtKey *key,
     279             :                       FlowEntry *flow);
     280             :     void FreeDBEntryEvent(FlowEvent::Event event, FlowMgmtKey *key,
     281             :                           uint32_t gen_id);
     282             : 
     283         298 :     Agent *agent() const { return agent_; }
     284             :     uint16_t table_index() const { return table_index_; }
     285             :     void AddEvent(FlowEntry *low);
     286             :     void DeleteEvent(FlowEntry *flow, const RevFlowDepParams &params);
     287             :     void FlowStatsUpdateEvent(FlowEntry *flow, uint32_t bytes, uint32_t packets,
     288             :                               uint32_t oflow_bytes,
     289             :                               const boost::uuids::uuid &u);
     290             :     void AddDBEntryEvent(const DBEntry *entry, uint32_t gen_id);
     291             :     void ChangeDBEntryEvent(const DBEntry *entry, uint32_t gen_id);
     292             :     void DeleteDBEntryEvent(const DBEntry *entry, uint32_t gen_id);
     293             :     void RouteNHChangeEvent(const DBEntry *entry, uint32_t gen_id);
     294             :     void RetryVrfDeleteEvent(const VrfEntry *vrf);
     295             :     void RetryVrfDelete(uint32_t vrf_id);
     296             :     // Dummy event used for testing
     297             :     void DummyEvent();
     298             : 
     299             :     void VnFlowCounters(const VnEntry *vn,
     300             :                         uint32_t *ingress_flow_count,
     301             :                         uint32_t *egress_flow_count);
     302             :     void InterfaceFlowCount(const Interface *itf, uint64_t *created,
     303             :                             uint64_t *aged, uint32_t *active_flows);
     304             :     bool HasVrfFlows(uint32_t vrf);
     305             : 
     306         313 :     FlowMgmtDbClient *flow_mgmt_dbclient() const {
     307         313 :         return flow_mgmt_dbclient_.get();
     308             :     }
     309             : 
     310           0 :     const FlowMgmtQueue *request_queue() const { return &request_queue_; }
     311             :     const FlowMgmtQueue *log_queue() const { return log_queue_; }
     312           1 :     void DisableWorkQueue(bool disable) { request_queue_.set_disable(disable); }
     313             :     void BgpAsAServiceNotify(const boost::uuids::uuid &vm_uuid,
     314             :                              uint32_t source_port);
     315             :     void BgpAsAServiceHealthCheckNotify(const boost::uuids::uuid &vm_uuid,
     316             :                                         uint32_t source_port,
     317             :                                         const boost::uuids::uuid &hc_uuid,
     318             :                                         bool add);
     319             :     void EnqueueUveAddEvent(const FlowEntry *flow) const;
     320             :     void EnqueueUveDeleteEvent(const FlowEntry *flow) const;
     321             : 
     322             :     void FlowUpdateQueueDisable(bool val);
     323             :     size_t FlowUpdateQueueLength();
     324             :     size_t FlowDBQueueLength();
     325          16 :     InetRouteFlowMgmtTree* ip4_route_flow_mgmt_tree() {
     326          16 :         return &ip4_route_flow_mgmt_tree_;
     327             :     }
     328             : 
     329             :     BgpAsAServiceFlowMgmtKey *FindBgpAsAServiceInfo(
     330             :                                 FlowEntry *flow,
     331             :                                 BgpAsAServiceFlowMgmtKey &key);
     332             : 
     333             : private:
     334             :     // Handle Add/Change of a flow. Builds FlowMgmtKeyTree for all objects
     335             :     void AddFlow(FlowEntryPtr &flow);
     336             :     // Handle Delete of a flow. Updates FlowMgmtKeyTree for all objects
     337             :     void DeleteFlow(FlowEntryPtr &flow, const RevFlowDepParams &p);
     338             :     void UpdateFlowStats(FlowEntryPtr &flow, uint32_t bytes, uint32_t packets,
     339             :                          uint32_t oflow_bytes, const boost::uuids::uuid &u);
     340             : 
     341             :     // Add a FlowMgmtKey into the FlowMgmtKeyTree for an object
     342             :     // The FlowMgmtKeyTree for object is passed as argument
     343             :     void AddFlowMgmtKey(FlowEntry *flow, FlowEntryInfo *info,
     344             :                         FlowMgmtKey *key, FlowMgmtKey *old_key);
     345             :     // Delete a FlowMgmtKey from FlowMgmtKeyTree for an object
     346             :     // The FlowMgmtKeyTree for object is passed as argument
     347             :     void DeleteFlowMgmtKey(FlowEntry *flow, FlowEntryInfo *info,
     348             :                            FlowMgmtKey *key, FlowMgmtKeyNode *node);
     349             :     FlowEntryInfo *FindFlowEntryInfo(const FlowEntryPtr &flow);
     350             :     FlowEntryInfo *LocateFlowEntryInfo(FlowEntryPtr &flow);
     351             :     void DeleteFlowEntryInfo(FlowEntryPtr &flow);
     352             :     void MakeFlowMgmtKeyTree(FlowEntry *flow, FlowMgmtKeyTree *tree);
     353             :     void SetAceSandeshData(const AclDBEntry *acl, AclFlowCountResp &data,
     354             :                            const std::string &ace_id);
     355             :     void SetAclFlowSandeshData(const AclDBEntry *acl, AclFlowResp &data,
     356             :                                const int last_count);
     357             :     void ControllerNotify(uint8_t index);
     358             : 
     359             :     Agent *agent_;
     360             :     uint16_t table_index_;
     361             :     AclFlowMgmtTree acl_flow_mgmt_tree_;
     362             :     InterfaceFlowMgmtTree interface_flow_mgmt_tree_;
     363             :     VnFlowMgmtTree vn_flow_mgmt_tree_;
     364             :     InetRouteFlowMgmtTree ip4_route_flow_mgmt_tree_;
     365             :     InetRouteFlowMgmtTree ip6_route_flow_mgmt_tree_;
     366             :     BridgeRouteFlowMgmtTree bridge_route_flow_mgmt_tree_;
     367             :     VrfFlowMgmtTree vrf_flow_mgmt_tree_;
     368             :     NhFlowMgmtTree nh_flow_mgmt_tree_;
     369             :     boost::scoped_ptr<BgpAsAServiceFlowMgmtTree> bgp_as_a_service_flow_mgmt_tree_[MAX_XMPP_SERVERS];
     370             :     std::unique_ptr<FlowMgmtDbClient> flow_mgmt_dbclient_;
     371             :     FlowMgmtQueue request_queue_;
     372             :     FlowMgmtQueue db_event_queue_;
     373             :     static FlowMgmtQueue *log_queue_;
     374             :     DISALLOW_COPY_AND_ASSIGN(FlowMgmtManager);
     375             : };
     376             : 
     377             : #define FLOW_TRACE(obj, ...)\
     378             : do {\
     379             :     Flow##obj::TraceMsg(FlowTraceBuf, __FILE__, __LINE__, ##__VA_ARGS__);\
     380             : } while (false)
     381             : 
     382             : #endif // __AGENT_FLOW_TABLE_MGMT_H__

Generated by: LCOV version 1.14