LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_table.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 2 23 8.7 %
Date: 2026-06-22 02:21:21 Functions: 2 20 10.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef __AGENT_FLOW_TABLE_H__
       6             : #define __AGENT_FLOW_TABLE_H__
       7             : 
       8             : #include <map>
       9             : #include <mutex>
      10             : 
      11             : #if defined(__GNUC__)
      12             : #include "base/compiler.h"
      13             : #if __GNUC_PREREQ(4, 5)
      14             : #pragma GCC diagnostic push
      15             : #pragma GCC diagnostic ignored "-Wunused-result"
      16             : #endif
      17             : #endif
      18             : #include <boost/uuid/random_generator.hpp>
      19             : #if defined(__GNUC__)
      20             : #if __GNUC_PREREQ(4, 6)
      21             : #pragma GCC diagnostic pop
      22             : #endif
      23             : #endif
      24             : 
      25             : #include <boost/uuid/uuid_io.hpp>
      26             : #include <boost/intrusive_ptr.hpp>
      27             : #include <base/util.h>
      28             : #include <base/address.h>
      29             : #include <db/db_table_walker.h>
      30             : #include <cmn/agent_cmn.h>
      31             : #include <oper/mirror_table.h>
      32             : #include <filter/traffic_action.h>
      33             : #include <filter/acl_entry.h>
      34             : #include <filter/acl.h>
      35             : #include <pkt/pkt_types.h>
      36             : #include <pkt/pkt_handler.h>
      37             : #include <pkt/pkt_init.h>
      38             : #include <pkt/pkt_flow_info.h>
      39             : #include <pkt/flow_entry.h>
      40             : #include <sandesh/sandesh_trace.h>
      41             : #include <oper/vn.h>
      42             : #include <oper/vm.h>
      43             : #include <oper/interface_common.h>
      44             : #include <oper/nexthop.h>
      45             : #include <oper/route_common.h>
      46             : #include <oper/sg.h>
      47             : #include <oper/vrf.h>
      48             : #include <filter/acl.h>
      49             : #include <sandesh/common/flow_types.h>
      50             : 
      51             : class FlowStatsCollector;
      52             : class PktSandeshFlow;
      53             : class FetchFlowRecord;
      54             : class FlowEntry;
      55             : class FlowTable;
      56             : class FlowTableKSyncEntry;
      57             : class FlowTableKSyncObject;
      58             : class FlowEvent;
      59             : class FlowEventKSync;
      60             : 
      61             : #define FLOW_LOCK(flow, rflow, flow_event) \
      62             :     bool is_flow_rflow_key_same = false; \
      63             :     if (flow == rflow) { \
      64             :         if (flow_event == FlowEvent::DELETE_FLOW) { \
      65             :             assert(0); \
      66             :         } \
      67             :         is_flow_rflow_key_same = true; \
      68             :         rflow = NULL; \
      69             :     } \
      70             :     std::unique_lock<std::mutex> lock1, lock2; \
      71             :     if (flow && rflow) { \
      72             :         auto l1 = std::unique_lock<std::mutex>(flow->mutex(), std::defer_lock); \
      73             :         lock1.swap(l1); \
      74             :         auto l2 = std::unique_lock<std::mutex>(rflow->mutex(), std::defer_lock); \
      75             :         lock2.swap(l2); \
      76             :         std::lock(lock1, lock2); \
      77             :     } else if (flow) { \
      78             :         auto l1 = std::unique_lock<std::mutex>(flow->mutex(), std::defer_lock); \
      79             :         lock1.swap(l1); \
      80             :         lock1.lock(); \
      81             :     } else if (rflow) { \
      82             :         auto l2 = std::unique_lock<std::mutex>(rflow->mutex(), std::defer_lock); \
      83             :         lock2.swap(l2); \
      84             :         lock2.lock(); \
      85             :     } \
      86             :     if (is_flow_rflow_key_same) { \
      87             :         flow->MakeShortFlow(FlowEntry::SHORT_SAME_FLOW_RFLOW_KEY); \
      88             :     }
      89             : 
      90             : /////////////////////////////////////////////////////////////////////////////
      91             : // Class to manage free-list of flow-entries
      92             : // Flow allocation can happen from multiple threads. In scaled scenarios
      93             : // allocation of flow-entries in multi-thread environment adds overheads.
      94             : // The FlowEntryFreeList helps to maintain a per task free-list. Alloc/Free
      95             : // can happen withou lock.
      96             : //
      97             : // Alloc and Free happens in a chunk. Alloc/Free are done based on thresholds
      98             : // in task context of the corresponding flow-table
      99             : /////////////////////////////////////////////////////////////////////////////
     100             : class FlowEntryFreeList {
     101             : public:
     102             :     static const uint32_t kInitCount = (25 * 1000);
     103             :     static const uint32_t kTestInitCount = (5 * 1000);
     104             :     static const uint32_t kGrowSize = (1 * 1000);
     105             :     static const uint32_t kMinThreshold = (4 * 1000);
     106             :     static const uint32_t kMaxThreshold = (100 * 1000);
     107             : 
     108             :     typedef boost::intrusive::member_hook<FlowEntry,
     109             :             boost::intrusive::list_member_hook<>,
     110             :             &FlowEntry::free_list_node_> Node;
     111             :     typedef boost::intrusive::list<FlowEntry, Node> FreeList;
     112             : 
     113             :     FlowEntryFreeList(FlowTable *table);
     114             :     virtual ~FlowEntryFreeList();
     115             : 
     116             :     FlowEntry *Allocate(const FlowKey &key);
     117             :     void Free(FlowEntry *flow);
     118             :     void Grow();
     119          15 :     uint32_t max_count() const { return max_count_; }
     120           0 :     uint32_t free_count() const { return free_list_.size(); }
     121             :     uint32_t alloc_count() const { return (max_count_ - free_list_.size()); }
     122           0 :     uint32_t total_alloc() const { return total_alloc_; }
     123           0 :     uint32_t total_free() const { return total_free_; }
     124             : private:
     125             :     FlowTable *table_;
     126             :     uint32_t max_count_;
     127             :     bool grow_pending_;
     128             :     uint64_t total_alloc_;
     129             :     uint64_t total_free_;
     130             :     FreeList free_list_;
     131             :     DISALLOW_COPY_AND_ASSIGN(FlowEntryFreeList);
     132             : };
     133             : 
     134             : /////////////////////////////////////////////////////////////////////////////
     135             : // Flow addition is a two step process.
     136             : // - FlowHandler :
     137             : //   Flow is created in this context (file pkt_flow_info.cc).
     138             : //   There can potentially be multiple FlowHandler task running in parallel
     139             : // - FlowTable :
     140             : //   This module will maintain a tree of all flows created. It is also
     141             : //   responsible to generate KSync events. It is run in a single task context
     142             : //
     143             : //   Functionality of FlowTable:
     144             : //   1. Manage flow_entry_map_ which contains all flows
     145             : //   2. Enforce the per-VM flow limits
     146             : //   3. Generate events to KSync and FlowMgmt modueles
     147             : /////////////////////////////////////////////////////////////////////////////
     148             : struct FlowTaskMsg : public InterTaskMsg {
     149           0 :     FlowTaskMsg(FlowEntry * fe) : InterTaskMsg(0), fe_ptr(fe) { }
     150           0 :     virtual ~FlowTaskMsg() { }
     151             : 
     152             :     FlowEntryPtr fe_ptr;
     153             : };
     154             : 
     155             : struct Inet4FlowKeyCmp {
     156           0 :     bool operator()(const FlowKey &lhs, const FlowKey &rhs) const {
     157           0 :         const FlowKey &lhs_base = static_cast<const FlowKey &>(lhs);
     158           0 :         return lhs_base.IsLess(rhs);
     159             :     }
     160             : };
     161             : 
     162             : class FlowTable {
     163             : public:
     164             :     static const uint32_t kPortNatFlowTableInstance = 0;
     165             :     static const uint32_t kInvalidFlowTableInstance = 0xFF;
     166             : 
     167             :     typedef std::map<FlowKey, FlowEntry *, Inet4FlowKeyCmp> FlowEntryMap;
     168             :     typedef std::pair<FlowKey, FlowEntry *> FlowEntryMapPair;
     169             :     typedef boost::function<bool(FlowEntry *flow)> FlowEntryCb;
     170             :     typedef std::vector<FlowEntryPtr> FlowIndexTree;
     171             : 
     172             :     struct LinkLocalFlowInfo {
     173             :         uint32_t flow_index;
     174             :         FlowKey flow_key;
     175             :         uint64_t timestamp;
     176             : 
     177           0 :         LinkLocalFlowInfo(uint32_t index, const FlowKey &key, uint64_t t) :
     178           0 :             flow_index(index), flow_key(key), timestamp(t) {}
     179             :     };
     180             :     typedef std::map<int, LinkLocalFlowInfo> LinkLocalFlowInfoMap;
     181             :     typedef std::pair<int, LinkLocalFlowInfo> LinkLocalFlowInfoPair;
     182             : 
     183             :     FlowTable(Agent *agent, uint16_t table_index);
     184             :     virtual ~FlowTable();
     185             : 
     186             :     void Init();
     187             :     void InitDone();
     188             :     void Shutdown();
     189             : 
     190             :     // Accessor routines
     191           0 :     void set_ksync_object(FlowTableKSyncObject *obj) { ksync_object_ = obj; }
     192         276 :     FlowTableKSyncObject *ksync_object() const { return ksync_object_; }
     193             : 
     194             :     // Table managment routines
     195             :     FlowEntry *Locate(FlowEntry *flow, uint64_t t);
     196             :     FlowEntry *Find(const FlowKey &key);
     197             :     void Add(FlowEntry *flow, FlowEntry *rflow);
     198             :     void Update(FlowEntry *flow, FlowEntry *rflow);
     199             :     //bool Delete(const FlowKey &flow_key);
     200             :     bool Delete(const FlowKey &key, bool del_reverse_flow);
     201             :     void DeleteAll();
     202             :     // Test code only used method
     203             :     void DeleteFlow(const AclDBEntry *acl, const FlowKey &key,
     204             :                     AclEntryIDList &id_list);
     205             : 
     206             :     // Accessor routines
     207           0 :     Agent *agent() const { return agent_; }
     208           0 :     uint16_t table_index() const { return table_index_; }
     209           0 :     size_t Size() { return flow_entry_map_.size(); }
     210             :     FlowTable::FlowEntryMap::iterator begin() {
     211             :         return flow_entry_map_.begin();
     212             :     }
     213             :     FlowTable::FlowEntryMap::iterator end() {
     214             :         return flow_entry_map_.end();
     215             :     }
     216             : 
     217           0 :     const LinkLocalFlowInfoMap &linklocal_flow_info_map() {
     218           0 :         return linklocal_flow_info_map_;
     219             :     }
     220             :     void AddLinkLocalFlowInfo(int fd, uint32_t index, const FlowKey &key,
     221             :                               const uint64_t timestamp);
     222             :     void DelLinkLocalFlowInfo(int fd);
     223             : 
     224             :     static const char *TaskName() { return kTaskFlowEvent; }
     225             :     // Sandesh routines
     226             :     void Copy(FlowEntry *lhs, FlowEntry *rhs, bool update);
     227             :     void SetAclFlowSandeshData(const AclDBEntry *acl, AclFlowResp &data,
     228             :                                const int last_count);
     229             :     void SetAceSandeshData(const AclDBEntry *acl, AclFlowCountResp &data,
     230             :                            int ace_id);
     231             : 
     232             :     void RecomputeFlow(FlowEntry *flow);
     233             :     void DeleteMessage(FlowEntry *flow);
     234             : 
     235             :     void DeleteVrf(VrfEntry *vrf);
     236             : 
     237             :     void HandleRevaluateDBEntry(const DBEntry *entry, FlowEntry *flow,
     238             :                                 bool active_flow, bool deleted_flow);
     239             :     void HandleKSyncError(FlowEntry *flow, FlowTableKSyncEntry *ksync_entry,
     240             :                           int ksync_error, uint32_t flow_handle,
     241             :                           uint32_t gen_id);
     242             :     boost::uuids::uuid rand_gen();
     243             : 
     244             :     void UpdateKSync(FlowEntry *flow, bool update);
     245             :     void DeleteKSync(FlowEntry *flow);
     246             : 
     247             :     // Free list
     248             :     void GrowFreeList();
     249           0 :     FlowEntryFreeList *free_list() { return &free_list_; }
     250             : 
     251             :     void ProcessKSyncFlowEvent(const FlowEventKSync *req, FlowEntry *flow);
     252             :     bool ProcessFlowEvent(const FlowEvent *req, FlowEntry *flow,
     253             :                           FlowEntry *rflow);
     254             :     void PopulateFlowEntriesUsingKey(const FlowKey &key, bool reverse_flow,
     255             :                                      FlowEntry** flow, FlowEntry** rflow);
     256             : 
     257             :     // Concurrency check to ensure all flow-table and free-list manipulations
     258             :     // are done from FlowEvent task context only
     259             :     //exception: freelist free function can be accessed by flow logging task
     260             :     bool ConcurrencyCheck(int task_id, bool check_task_instance);
     261             :     bool ConcurrencyCheck(int task_id);
     262           0 :     int flow_task_id() const { return flow_task_id_; }
     263             :     int flow_update_task_id() const { return flow_update_task_id_; }
     264           0 :     int flow_delete_task_id() const { return flow_delete_task_id_; }
     265           0 :     int flow_ksync_task_id() const { return flow_ksync_task_id_; }
     266           0 :     int flow_logging_task_id() const { return flow_logging_task_id_; }
     267             :     static void GetFlowSandeshActionParams(const FlowAction &action_info,
     268             :                                            std::string &action_str);
     269             : 
     270             :     friend class FlowStatsCollector;
     271             :     friend class PktSandeshFlow;
     272             :     friend class PktSandeshFlowStats;
     273             :     friend class FetchFlowRecord;
     274             :     friend class PktFlowInfo;
     275             :     friend void intrusive_ptr_release(FlowEntry *fe);
     276             : private:
     277             :     void DisableKSyncSend(FlowEntry *flow, uint32_t evict_gen_id);
     278             :     bool IsEvictedFlow(const FlowKey &key);
     279             : 
     280             :     void DeleteFlowUveInfo(FlowEntry *fe);
     281             : 
     282             :     void DeleteInternal(FlowEntry *fe, uint64_t t, const RevFlowDepParams &p);
     283             :     void DeleteFlowInfo(FlowEntry *fe, const RevFlowDepParams &params);
     284             : 
     285             :     void AddFlowInfo(FlowEntry *fe);
     286             :     void UpdateReverseFlow(FlowEntry *flow, FlowEntry *rflow);
     287             : 
     288             :     void UpdateUnLocked(FlowEntry *flow, FlowEntry *rflow);
     289             :     void AddInternal(FlowEntry *flow, FlowEntry *new_flow, FlowEntry *rflow,
     290             :                      FlowEntry *new_rflow, bool fwd_flow_update,
     291             :                      bool rev_flow_update);
     292             :     void Add(FlowEntry *flow, FlowEntry *new_flow, FlowEntry *rflow,
     293             :              FlowEntry *new_rflow, bool fwd_flow_update, bool rev_flow_update);
     294             :     void EvictFlow(FlowEntry *flow, FlowEntry *rflow, uint32_t evict_gen_id);
     295             :     bool DeleteFlows(FlowEntry *flow, FlowEntry *rflow);
     296             :     bool DeleteUnLocked(const FlowKey &key, bool del_reverse_flow);
     297             :     bool DeleteUnLocked(bool del_reverse_flow, FlowEntry *flow,
     298             :                         FlowEntry *rflow);
     299             :     void ReleasePort(FlowEntry *flow, bool evict);
     300             : 
     301             :     Agent *agent_;
     302             :     boost::uuids::random_generator rand_gen_;
     303             :     uint16_t table_index_;
     304             :     FlowTableKSyncObject *ksync_object_;
     305             :     FlowEntryMap flow_entry_map_;
     306             : 
     307             :     FlowIndexTree flow_index_tree_;
     308             :     // maintain the linklocal flow info against allocated fd, debug purpose only
     309             :     LinkLocalFlowInfoMap linklocal_flow_info_map_;
     310             :     FlowEntryFreeList free_list_;
     311             :     std::mutex mutex_;
     312             :     int flow_task_id_;
     313             :     int flow_update_task_id_;
     314             :     int flow_delete_task_id_;
     315             :     int flow_ksync_task_id_;
     316             :     int flow_logging_task_id_;
     317             :     DISALLOW_COPY_AND_ASSIGN(FlowTable);
     318             : };
     319             : 
     320             : struct FlowEntryCmp {
     321             :     bool operator()(const FlowEntryPtr &l, const FlowEntryPtr &r) {
     322             :         FlowEntry *lhs = l.get();
     323             :         FlowEntry *rhs = r.get();
     324             : 
     325             :         return (lhs < rhs);
     326             :     }
     327             : };
     328             : 
     329             : typedef std::set<FlowEntryPtr, FlowEntryCmp> FlowEntryTree;
     330             : extern SandeshTraceBufferPtr FlowTraceBuf;
     331             : extern void SetActionStr(const FlowAction &, std::vector<ActionStr> &);
     332             : 
     333             : #define FLOW_TRACE(obj, ...)\
     334             : do {\
     335             :     Flow##obj::TraceMsg(FlowTraceBuf, __FILE__, __LINE__, ##__VA_ARGS__);\
     336             : } while (false)
     337             : 
     338             : #endif

Generated by: LCOV version 1.14