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: 14 27 51.9 %
Date: 2026-11-09 02:10:49 Functions: 13 22 59.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14