LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_table.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 357 510 70.0 %
Date: 2026-11-09 02:10:49 Functions: 38 47 80.9 %
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             : #include <vector>
       7             : #include <bitset>
       8             : #include <mutex>
       9             : 
      10             : #include <boost/date_time/posix_time/posix_time.hpp>
      11             : #include <boost/assign/list_of.hpp>
      12             : #include <boost/unordered_map.hpp>
      13             : #include <sandesh/sandesh_trace.h>
      14             : #include <base/address_util.h>
      15             : #include <pkt/flow_table.h>
      16             : #include <vrouter/ksync/ksync_init.h>
      17             : #include <vrouter/ksync/ksync_flow_index_manager.h>
      18             : 
      19             : #include <arpa/inet.h>
      20             : #include <netinet/in.h>
      21             : #include <base/os.h>
      22             : 
      23             : #include <route/route.h>
      24             : #include <cmn/agent_cmn.h>
      25             : #include <oper/interface_common.h>
      26             : #include <oper/nexthop.h>
      27             : 
      28             : #include <init/agent_param.h>
      29             : #include <cmn/agent_cmn.h>
      30             : #include <cmn/agent_stats.h>
      31             : #include <oper/route_common.h>
      32             : #include <oper/vrf.h>
      33             : #include <oper/vm.h>
      34             : #include <oper/sg.h>
      35             : #include <oper/tunnel_nh.h>
      36             : 
      37             : #include <filter/packet_header.h>
      38             : #include <filter/acl.h>
      39             : 
      40             : #include <pkt/proto.h>
      41             : #include <pkt/proto_handler.h>
      42             : #include <pkt/pkt_handler.h>
      43             : #include <pkt/flow_proto.h>
      44             : #include <pkt/pkt_types.h>
      45             : #include <pkt/pkt_sandesh_flow.h>
      46             : #include <pkt/flow_mgmt.h>
      47             : #include <pkt/flow_event.h>
      48             : 
      49             : const uint32_t FlowEntryFreeList::kInitCount;
      50             : const uint32_t FlowEntryFreeList::kTestInitCount;
      51             : const uint32_t FlowEntryFreeList::kGrowSize;
      52             : const uint32_t FlowEntryFreeList::kMinThreshold;
      53             : const uint32_t FlowEntryFreeList::kMaxThreshold;
      54             : 
      55             : SandeshTraceBufferPtr FlowTraceBuf(SandeshTraceBufferCreate("Flow", 5000));
      56             : 
      57             : /////////////////////////////////////////////////////////////////////////////
      58             : // FlowTable constructor/destructor
      59             : /////////////////////////////////////////////////////////////////////////////
      60           2 : FlowTable::FlowTable(Agent *agent, uint16_t table_index) :
      61           2 :     agent_(agent),
      62             :     rand_gen_(boost::uuids::random_generator()),
      63           2 :     table_index_(table_index),
      64           2 :     ksync_object_(NULL),
      65           2 :     flow_entry_map_(),
      66           2 :     free_list_(this),
      67           2 :     flow_task_id_(0),
      68           2 :     flow_update_task_id_(0),
      69           2 :     flow_delete_task_id_(0),
      70           2 :     flow_ksync_task_id_(0),
      71           4 :     flow_logging_task_id_(0) {
      72           2 : }
      73             : 
      74           4 : FlowTable::~FlowTable() {
      75           2 :     assert(flow_entry_map_.size() == 0);
      76           4 : }
      77             : 
      78           2 : void FlowTable::Init() {
      79           2 :     flow_task_id_ = agent_->task_scheduler()->GetTaskId(kTaskFlowEvent);
      80           2 :     flow_update_task_id_ = agent_->task_scheduler()->GetTaskId(kTaskFlowUpdate);
      81           2 :     flow_delete_task_id_ = agent_->task_scheduler()->GetTaskId(kTaskFlowDelete);
      82           2 :     flow_ksync_task_id_ = agent_->task_scheduler()->GetTaskId(kTaskFlowKSync);
      83           2 :     flow_logging_task_id_ = agent_->task_scheduler()->GetTaskId(kTaskFlowLogging);
      84           2 :     FlowEntry::Init();
      85           2 :     return;
      86             : }
      87             : 
      88           2 : void FlowTable::InitDone() {
      89           2 : }
      90             : 
      91           2 : void FlowTable::Shutdown() {
      92           2 : }
      93             : 
      94             : // Concurrency check to ensure all flow-table and free-list manipulations
      95             : // are done from FlowEvent task context only
      96             : //exception: freelist free function can be accessed by flow logging task
      97        6547 : bool FlowTable::ConcurrencyCheck(int task_id, bool check_task_instance) {
      98        6547 :     Task *current = Task::Running();
      99             :     // test code invokes FlowTable API from main thread. The running task
     100             :     // will be NULL in such cases
     101        6542 :     if (current == NULL) {
     102        1427 :         return true;
     103             :     }
     104             : 
     105        5115 :     if (current->task_code_id() != task_id)
     106         144 :         return false;
     107        4971 :     if (check_task_instance) {
     108        4975 :         if (current->task_data_id() != table_index_)
     109           0 :            return false;
     110             :     }
     111        4971 :     return true;
     112             : }
     113             : 
     114        6547 : bool FlowTable::ConcurrencyCheck(int task_id) {
     115        6547 :         return ConcurrencyCheck(task_id, true);
     116             : }
     117             : 
     118             : /////////////////////////////////////////////////////////////////////////////
     119             : // FlowTable Add/Delete routines
     120             : /////////////////////////////////////////////////////////////////////////////
     121             : 
     122        1501 : FlowEntry *FlowTable::Find(const FlowKey &key) {
     123        1501 :     assert(ConcurrencyCheck(flow_task_id_) == true);
     124        1501 :     FlowEntryMap::iterator it;
     125             : 
     126        1501 :     it = flow_entry_map_.find(key);
     127        1501 :     if (it != flow_entry_map_.end()) {
     128         169 :         return it->second;
     129             :     } else {
     130        1332 :         return NULL;
     131             :     }
     132             : }
     133             : 
     134          80 : void FlowTable::Copy(FlowEntry *lhs, FlowEntry *rhs, bool update) {
     135             :     /* Flow copy, if results in UUID change, stop updating UVE stats
     136             :      * for old flow
     137             :      */
     138          80 :     if (update==false)
     139           8 :         DeleteFlowUveInfo(lhs);
     140             : 
     141          80 :     RevFlowDepParams params;
     142          80 :     lhs->RevFlowDepInfo(&params);
     143          80 :     DeleteFlowInfo(lhs, params);
     144          80 :     if (rhs)
     145          80 :         lhs->Copy(rhs, update);
     146          80 : }
     147             : 
     148         152 : FlowEntry *FlowTable::Locate(FlowEntry *flow, uint64_t time) {
     149         152 :     assert(ConcurrencyCheck(flow_task_id_) == true);
     150         152 :     std::pair<FlowEntryMap::iterator, bool> ret;
     151         152 :     ret = flow_entry_map_.insert(FlowEntryMapPair(flow->key(), flow));
     152         152 :     if (ret.second == true) {
     153         144 :         agent_->stats()->incr_flow_created();
     154         144 :         ret.first->second->set_on_tree();
     155         144 :         return flow;
     156             :     }
     157             : 
     158           8 :     return ret.first->second;
     159             : }
     160             : 
     161          75 : void FlowTable::Add(FlowEntry *flow, FlowEntry *rflow) {
     162          75 :     uint64_t time = UTCTimestampUsec();
     163          75 :     FlowEntry *new_flow = Locate(flow, time);
     164          75 :     FlowEntry *new_rflow = (rflow != NULL) ? Locate(rflow, time) : NULL;
     165             : 
     166          75 :     FLOW_LOCK(new_flow, new_rflow, FlowEvent::FLOW_MESSAGE);
     167          75 :     AddInternal(flow, new_flow, rflow, new_rflow, false, false);
     168          75 : }
     169             : 
     170          37 : void FlowTable::Update(FlowEntry *flow, FlowEntry *rflow) {
     171          37 :     bool fwd_flow_update = true;
     172          37 :     FlowEntry *new_flow = Find(flow->key());
     173             : 
     174          37 :     FlowEntry *new_rflow = (rflow != NULL) ? Find(rflow->key()) : NULL;
     175          37 :     bool rev_flow_update = true;
     176          37 :     if (rflow && new_rflow == NULL) {
     177           2 :         uint64_t time = UTCTimestampUsec();
     178           2 :         new_rflow = Locate(rflow, time);
     179           2 :         rev_flow_update = false;
     180             :     }
     181             : 
     182          37 :     FLOW_LOCK(new_flow, new_rflow, FlowEvent::FLOW_MESSAGE);
     183          37 :     AddInternal(flow, new_flow, rflow, new_rflow, fwd_flow_update,
     184             :                 rev_flow_update);
     185          37 : }
     186             : 
     187         112 : void FlowTable::AddInternal(FlowEntry *flow_req, FlowEntry *flow,
     188             :                             FlowEntry *rflow_req, FlowEntry *rflow,
     189             :                             bool fwd_flow_update, bool rev_flow_update) {
     190             :     // Set trace flags for a flow
     191         112 :     bool trace = agent_->pkt()->get_flow_proto()->ShouldTrace(flow, rflow);
     192         112 :     if (flow)
     193         112 :         flow->set_trace(trace);
     194         112 :     if (rflow)
     195         112 :         rflow->set_trace(trace);
     196             : 
     197             :     // The forward and reverse flow in request are linked. Unlink the flows
     198             :     // first. Flow table processing will link them if necessary
     199         112 :     flow_req->set_reverse_flow_entry(NULL);
     200         112 :     if (rflow_req)
     201         112 :         rflow_req->set_reverse_flow_entry(NULL);
     202             : 
     203         112 :     bool force_update_rflow = false;
     204         112 :     if (fwd_flow_update) {
     205          37 :         if (flow == NULL)
     206           0 :             return;
     207             : 
     208          37 :         if (flow->deleted() || flow->IsShortFlow()) {
     209           0 :             return;
     210             :         }
     211             :     }
     212             : 
     213         112 :     if (flow_req != flow) {
     214          41 :         if (flow->flow_handle() == FlowEntry::kInvalidFlowHandle &&
     215           0 :             !flow->deleted()) {
     216             :             // In this scenario packet trap for forward flow should
     217             :             // not cause eviction of the reverse flow due to add event
     218             :             // so trigger a force update instead of add for reverse flow
     219           0 :             force_update_rflow = true;
     220             :         }
     221          41 :         Copy(flow, flow_req, fwd_flow_update);
     222          41 :         flow->set_deleted(false);
     223             :         // this flow entry is reused , increment the transaction id
     224             :         // so that flow events with old transaction id will be ingnored
     225          41 :         flow->IncrementTransactionId();
     226             :     }
     227             : 
     228         112 :     if (rflow) {
     229         112 :         if (rflow_req != rflow) {
     230          39 :             Copy(rflow, rflow_req, (rev_flow_update || force_update_rflow));
     231             :             // if the reverse flow was marked delete, reset its flow handle
     232             :             // to invalid index to assure it is attempted to reprogram using
     233             :             // kInvalidFlowHandle, this also ensures that flow entry wont
     234             :             // give fake notion of being available in the flow index tree
     235             :             // delete for which has already happend while triggering delete
     236             :             // for flow entry
     237          39 :             if (rflow->deleted()) {
     238           0 :                 rflow->flow_handle_ = FlowEntry::kInvalidFlowHandle;
     239             :                 // rflow was delete marked skip force update
     240           0 :                 force_update_rflow = false;
     241             :             }
     242          39 :             rflow->set_deleted(false);
     243             :             // this flow entry is reused , increment the transaction id
     244             :             // so that flow events with old transaction id will be ingnored
     245          39 :             rflow->IncrementTransactionId();
     246             :         } else {
     247             :             // we are creating a new reverse flow, so avoid triggering
     248             :             // force update in this case
     249          73 :             force_update_rflow = false;
     250             :         }
     251             :     }
     252             : 
     253         112 :     if (flow) {
     254         112 :         if (fwd_flow_update) {
     255          37 :             flow->set_last_event(FlowEvent::FLOW_MESSAGE);
     256             :         } else {
     257          75 :             flow->set_last_event(FlowEvent::VROUTER_FLOW_MSG);
     258             :         }
     259             :     }
     260         112 :     if (rflow) {
     261         112 :         if (rev_flow_update) {
     262          35 :             rflow->set_last_event(FlowEvent::FLOW_MESSAGE);
     263             :         } else {
     264          77 :             rflow->set_last_event(FlowEvent::VROUTER_FLOW_MSG);
     265             :         }
     266             :     }
     267             : 
     268             :     // If the flows are already present, we want to retain the Forward and
     269             :     // Reverse flow characteristics for flow.
     270             :     // We have following conditions,
     271             :     // flow has ReverseFlow set, rflow has ReverseFlow reset
     272             :     //      Swap flow and rflow
     273             :     // flow has ReverseFlow set, rflow has ReverseFlow set
     274             :     //      Unexpected case. Continue with flow as forward flow
     275             :     // flow has ReverseFlow reset, rflow has ReverseFlow reset
     276             :     //      Unexpected case. Continue with flow as forward flow
     277             :     // flow has ReverseFlow reset, rflow has ReverseFlow set
     278             :     //      No change in forward/reverse flow. Continue as forward-flow
     279         112 :     if (flow->is_flags_set(FlowEntry::ReverseFlow) &&
     280         112 :         rflow && !rflow->is_flags_set(FlowEntry::ReverseFlow)) {
     281           0 :         FlowEntry *tmp = flow;
     282           0 :         flow = rflow;
     283           0 :         rflow = tmp;
     284             :     }
     285             : 
     286         112 :     UpdateReverseFlow(flow, rflow);
     287             : 
     288             :     // Add the forward flow after adding the reverse flow first to avoid
     289             :     // following sequence
     290             :     // 1. Agent adds forward flow
     291             :     // 2. vrouter releases the packet
     292             :     // 3. Packet reaches destination VM and destination VM replies
     293             :     // 4. Agent tries adding reverse flow. vrouter processes request in core-0
     294             :     // 5. vrouter gets reverse packet in core-1
     295             :     // 6. If (4) and (3) happen together, vrouter can allocate 2 hash entries
     296             :     //    for the flow.
     297             :     //
     298             :     // While the scenario above cannot be totally avoided, programming reverse
     299             :     // flow first will reduce the probability
     300         112 :     if (rflow) {
     301         112 :         UpdateKSync(rflow, (rev_flow_update || force_update_rflow));
     302         112 :         AddFlowInfo(rflow);
     303             :     }
     304             : 
     305         112 :     UpdateKSync(flow, fwd_flow_update);
     306         112 :     AddFlowInfo(flow);
     307             : }
     308             : 
     309         144 : void FlowTable::DeleteInternal(FlowEntry *fe, uint64_t time,
     310             :                                const RevFlowDepParams &params) {
     311         144 :     fe->set_deleted(true);
     312             : 
     313             :     // Unlink the reverse flow, if one exists
     314         144 :     FlowEntry *rflow = fe->reverse_flow_entry();
     315         144 :     if (rflow) {
     316          71 :         rflow->set_reverse_flow_entry(NULL);
     317             :     }
     318         144 :     fe->set_reverse_flow_entry(NULL);
     319             : 
     320         144 :     ReleasePort(fe, true);
     321             : 
     322         144 :     DeleteFlowInfo(fe, params);
     323         144 :     DeleteKSync(fe);
     324             : 
     325         144 :     agent_->stats()->incr_flow_aged();
     326         144 : }
     327             : 
     328         126 : bool FlowTable::DeleteFlows(FlowEntry *flow, FlowEntry *rflow) {
     329         126 :     uint64_t time = UTCTimestampUsec();
     330             : 
     331             :     /* Fetch reverse-flow info for both flows before their reverse-flow
     332             :      * links are broken. This info is required during FlowExport
     333             :      *
     334             :      * DeleteFlows() is invoked for both forward and reverse flows. So, get
     335             :      * reverse-flow info only when flows are not deleted
     336             :      */
     337         126 :     RevFlowDepParams r_params;
     338         126 :     if (rflow && rflow->deleted() == false) {
     339          38 :         rflow->RevFlowDepInfo(&r_params);
     340             :     }
     341         126 :     if (flow && flow->deleted() == false) {
     342         106 :         RevFlowDepParams f_params;
     343         106 :         flow->RevFlowDepInfo(&f_params);
     344             :         /* Delete the forward flow */
     345         106 :         DeleteInternal(flow, time, f_params);
     346         106 :     }
     347             : 
     348         126 :     if (rflow && rflow->deleted() == false) {
     349          38 :         DeleteInternal(rflow, time, r_params);
     350             :     }
     351         126 :     return true;
     352         126 : }
     353             : 
     354           0 : void FlowTable::PopulateFlowEntriesUsingKey(const FlowKey &key,
     355             :                                             bool reverse_flow,
     356             :                                             FlowEntry** flow,
     357             :                                             FlowEntry** rflow) {
     358           0 :     *flow = Find(key);
     359           0 :     *rflow = NULL;
     360             : 
     361             :     //No flow entry, nothing to populate
     362           0 :     if (!(*flow)) {
     363           0 :         return;
     364             :     }
     365             : 
     366             :     //No reverse flow requested, so dont populate rflow
     367           0 :     if (!reverse_flow) {
     368           0 :         return;
     369             :     }
     370             : 
     371           0 :     FlowEntry *reverse_flow_entry = (*flow)->reverse_flow_entry();
     372           0 :     if (reverse_flow_entry) {
     373           0 :         *rflow = Find(reverse_flow_entry->key());
     374             :     }
     375             : }
     376             : 
     377             : //Caller makes sure lock is taken on flow.
     378         126 : bool FlowTable::DeleteUnLocked(bool del_reverse_flow,
     379             :                                FlowEntry *flow,
     380             :                                FlowEntry *rflow) {
     381         126 :     if (!flow) {
     382           0 :         return false;
     383             :     }
     384             : 
     385         126 :     DeleteFlows(flow, rflow);
     386             : 
     387             :     //If deletion of reverse flow is to be done,
     388             :     //make sure that rflow is populated if flow has a reverse flow pointer.
     389             :     //In case rflow is not located with the reverse flow key, consider it as
     390             :     //failure.
     391         126 :     if (del_reverse_flow && flow->reverse_flow_entry() && !rflow) {
     392           0 :         return false;
     393             :     }
     394         126 :     return true;
     395             : }
     396             : 
     397             : //Caller has to ensure lock is taken for flow.
     398           0 : bool FlowTable::DeleteUnLocked(const FlowKey &key, bool del_reverse_flow) {
     399           0 :     FlowEntry *flow = NULL;
     400           0 :     FlowEntry *rflow = NULL;
     401             : 
     402           0 :     PopulateFlowEntriesUsingKey(key, del_reverse_flow, &flow, &rflow);
     403           0 :     return DeleteUnLocked(del_reverse_flow, flow, rflow);
     404             : }
     405             : 
     406           0 : bool FlowTable::Delete(const FlowKey &key, bool del_reverse_flow) {
     407           0 :     FlowEntry *flow = NULL;
     408           0 :     FlowEntry *rflow = NULL;
     409             : 
     410           0 :     PopulateFlowEntriesUsingKey(key, del_reverse_flow, &flow, &rflow);
     411           0 :     FLOW_LOCK(flow, rflow, FlowEvent::DELETE_FLOW);
     412           0 :     return DeleteUnLocked(del_reverse_flow, flow, rflow);
     413           0 : }
     414             : 
     415          20 : void FlowTable::DeleteAll() {
     416          20 :     FlowEntryMap::iterator it;
     417             : 
     418          20 :     it = flow_entry_map_.begin();
     419          65 :     while (it != flow_entry_map_.end()) {
     420          45 :         FlowEntry *entry = it->second;
     421          45 :         FlowEntry *reverse_entry = NULL;
     422          45 :         ++it;
     423          88 :         if (it != flow_entry_map_.end() &&
     424          43 :             it->second == entry->reverse_flow_entry()) {
     425          11 :             reverse_entry = it->second;
     426          11 :             ++it;
     427             :         }
     428          79 :         FLOW_LOCK(entry, reverse_entry, FlowEvent::DELETE_FLOW);
     429          45 :         DeleteUnLocked(true, entry, reverse_entry);
     430          45 :     }
     431          20 : }
     432             : 
     433         112 : void FlowTable::UpdateReverseFlow(FlowEntry *flow, FlowEntry *rflow) {
     434         112 :     FlowEntry *flow_rev = flow->reverse_flow_entry();
     435         112 :     FlowEntry *rflow_rev = NULL;
     436             : 
     437         112 :     if (rflow) {
     438         112 :         rflow_rev = rflow->reverse_flow_entry();
     439             :     }
     440             : 
     441         112 :     if (rflow_rev) {
     442          39 :         assert(rflow_rev->reverse_flow_entry() == rflow);
     443          39 :         rflow_rev->set_reverse_flow_entry(NULL);
     444             :     }
     445             : 
     446         112 :     if (flow_rev) {
     447          41 :         flow_rev->set_reverse_flow_entry(NULL);
     448             :     }
     449             : 
     450         112 :     flow->set_reverse_flow_entry(rflow);
     451         112 :     if (rflow) {
     452         112 :         rflow->set_reverse_flow_entry(flow);
     453             :     }
     454             : 
     455         112 :     if (flow_rev && (flow_rev->reverse_flow_entry() == NULL)) {
     456           2 :         flow_rev->MakeShortFlow(FlowEntry::SHORT_NO_REVERSE_FLOW);
     457             :     }
     458             : 
     459         112 :     if (rflow_rev && (rflow_rev->reverse_flow_entry() == NULL)) {
     460           0 :         rflow_rev->MakeShortFlow(FlowEntry::SHORT_NO_REVERSE_FLOW);
     461             :     }
     462             : 
     463         112 :     if (flow->reverse_flow_entry() == NULL) {
     464           0 :         flow->MakeShortFlow(FlowEntry::SHORT_NO_REVERSE_FLOW);
     465             :     }
     466             : 
     467         112 :     if (rflow && rflow->reverse_flow_entry() == NULL) {
     468           0 :         rflow->MakeShortFlow(FlowEntry::SHORT_NO_REVERSE_FLOW);
     469             :     }
     470             : 
     471         112 :     if (rflow) {
     472         208 :         if (flow->is_flags_set(FlowEntry::ShortFlow) ||
     473         208 :             rflow->is_flags_set(FlowEntry::ShortFlow)) {
     474          16 :             flow->MakeShortFlow(FlowEntry::SHORT_REVERSE_FLOW_CHANGE);
     475             :         }
     476         112 :         if (flow->is_flags_set(FlowEntry::Multicast)) {
     477           0 :             rflow->set_flags(FlowEntry::Multicast);
     478             :         }
     479             :     }
     480         112 : }
     481             : 
     482           8 : void FlowTable::DeleteFlowUveInfo(FlowEntry *fe) {
     483           8 :     agent_->pkt()->flow_mgmt_manager(table_index_)->EnqueueUveDeleteEvent(fe);
     484           8 : }
     485             : 
     486             : ////////////////////////////////////////////////////////////////////////////
     487             : // Flow Info tree management
     488             : ////////////////////////////////////////////////////////////////////////////
     489         230 : void FlowTable::AddFlowInfo(FlowEntry *fe) {
     490         230 :     agent_->pkt()->flow_mgmt_manager(table_index_)->AddEvent(fe);
     491         230 : }
     492             : 
     493         224 : void FlowTable::DeleteFlowInfo(FlowEntry *fe, const RevFlowDepParams &params) {
     494         224 :     agent_->pkt()->flow_mgmt_manager(table_index_)->DeleteEvent(fe, params);
     495         224 : }
     496             : 
     497             : /////////////////////////////////////////////////////////////////////////////
     498             : // Flow revluation routines. Processing will vary based on DBEntry type
     499             : /////////////////////////////////////////////////////////////////////////////
     500       40912 : boost::uuids::uuid FlowTable::rand_gen() {
     501       40912 :     return rand_gen_();
     502             : }
     503             : 
     504             : // Enqueue message to recompute a flow
     505          40 : void FlowTable::RecomputeFlow(FlowEntry *flow) {
     506          40 :     if (flow->is_flags_set(FlowEntry::ShortFlow))
     507           0 :         return;
     508             : 
     509             :     // If this is reverse flow, enqueue the corresponding forward flow
     510          40 :     if (flow->is_flags_set(FlowEntry::ReverseFlow)) {
     511          20 :         flow = flow->reverse_flow_entry();
     512             :     }
     513             : 
     514          40 :     if (flow != NULL)
     515          40 :         agent_->pkt()->get_flow_proto()->MessageRequest(flow);
     516             : }
     517             : 
     518             : // Handle deletion of a Route. Flow management module has identified that route
     519             : // must be deleted
     520          49 : void FlowTable::DeleteMessage(FlowEntry *flow) {
     521          49 :     DeleteUnLocked(true, flow, flow->reverse_flow_entry());
     522          49 : }
     523             : 
     524         144 : void FlowTable::ReleasePort(FlowEntry *flow, bool evict) {
     525         144 :     if (flow->allocated_port() == 0) {
     526         144 :         return;
     527             :     }
     528             : 
     529           0 :     PortTableManager *pm = agent_->pkt()->get_flow_proto()->port_table_manager();
     530           0 :     pm->Free(flow->key(), flow->allocated_port(), evict);
     531             : }
     532             : 
     533          32 : void FlowTable::EvictFlow(FlowEntry *flow, FlowEntry *reverse_flow,
     534             :                           uint32_t evict_gen_id) {
     535          32 :     DisableKSyncSend(flow, evict_gen_id);
     536          32 :     DeleteUnLocked(false, flow, NULL);
     537             : 
     538             :     // Reverse flow unlinked with forward flow. Make it short-flow
     539             :     // Dont update ksync, it will shortly get either evicted or deleted by
     540             :     // ageing process
     541          32 :     if (reverse_flow)
     542          32 :         reverse_flow->MakeShortFlow(FlowEntry::SHORT_NO_REVERSE_FLOW);
     543          32 : }
     544             : 
     545           4 : void FlowTable::HandleRevaluateDBEntry(const DBEntry *entry, FlowEntry *flow,
     546             :                                        bool active_flow, bool deleted_flow) {
     547             :     // Ignore revluate of deleted/short flows
     548           4 :     if (flow->IsShortFlow())
     549           1 :         return;
     550             : 
     551           3 :     if (flow->deleted())
     552           0 :         return;
     553             : 
     554           3 :     FlowEntry *rflow = flow->reverse_flow_entry();
     555             :     // Update may happen for reverse-flow. We act on both forward and
     556             :     // reverse-flow. Get both forward and reverse flows
     557           3 :     if (flow->is_flags_set(FlowEntry::ReverseFlow)) {
     558           0 :         FlowEntry *tmp = flow;
     559           0 :         flow = rflow;
     560           0 :         rflow = tmp;
     561             :     }
     562             : 
     563             :     // We want to update only if both forward and reverse flow are valid
     564           3 :     if (flow == NULL || rflow == NULL)
     565           0 :         return;
     566             : 
     567             :     // Ignore update, if any of the DBEntries referred is deleted
     568           3 :     if (flow->vn_entry() && flow->vn_entry()->IsDeleted())
     569           0 :         return;
     570             : 
     571           3 :     if (flow->rpf_nh() && flow->rpf_nh()->IsDeleted())
     572           0 :         return;
     573             : 
     574           3 :     if (flow->intf_entry() && flow->intf_entry()->IsDeleted())
     575           0 :         return;
     576             : 
     577             :     // Revaluate flood unknown-unicast flag. If flow has UnknownUnicastFlood and
     578             :     // VN doesnt allow it, make Short Flow
     579           3 :     if (flow->vn_entry() &&
     580           6 :         flow->vn_entry()->flood_unknown_unicast() == false &&
     581           6 :         flow->is_flags_set(FlowEntry::UnknownUnicastFlood)) {
     582           0 :         flow->MakeShortFlow(FlowEntry::SHORT_NO_DST_ROUTE);
     583             :     }
     584             : 
     585             :     // On a l3mh compute, when physical interfaces state is down on host
     586             :     // make all flows with underlay_gw_index same as phy intf encap index short
     587           3 :     if (flow->data().underlay_gw_index_ != 0xff && agent()->is_l3mh()) {
     588           0 :         InetUnicastRouteEntry *rt = NULL;
     589           0 :         if (flow->is_flags_set(FlowEntry::IngressDir)) {
     590             :             rt = static_cast<InetUnicastRouteEntry *>
     591           0 :             (FlowEntry::GetUcRoute(flow->GetDestinationVrf(), flow->key().dst_addr));
     592           0 :         } else if (rflow->is_flags_set(FlowEntry::IngressDir)) {
     593             :             rt = static_cast<InetUnicastRouteEntry *>
     594           0 :             (FlowEntry::GetUcRoute(rflow->GetDestinationVrf(), rflow->key().dst_addr));
     595             :         }
     596           0 :         if (rt != NULL) {
     597             :             const TunnelNH *tunnel_nh =
     598           0 :                 dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
     599           0 :             if (tunnel_nh != NULL) {
     600           0 :                 TunnelNH::EncapDataList encap_list = tunnel_nh->GetEncapDataList();
     601           0 :                 if (encap_list[flow->data().underlay_gw_index_].get()->valid_ == false) {
     602           0 :                     flow->MakeShortFlow(FlowEntry::SHORT_L3MH_PHY_INTF_DOWN);
     603             :                 }
     604           0 :             }
     605             :         }
     606             :     }
     607           3 :     flow->UpdateL2RouteInfo();
     608           3 :     rflow->UpdateL2RouteInfo();
     609             : 
     610             :     // Get policy attributes again and redo the flows
     611           3 :     flow->GetPolicyInfo();
     612           3 :     rflow->GetPolicyInfo();
     613             : 
     614             :     // Resync reverse flow first and then forward flow
     615             :     // as forward flow resync will try to update reverse flow
     616           3 :     rflow->ResyncFlow();
     617           3 :     flow->ResyncFlow();
     618             : 
     619             :     // RPF computation can be done only after policy processing.
     620             :     // Do RPF computation now
     621           3 :     flow->RpfUpdate();
     622           3 :     rflow->RpfUpdate();
     623             : 
     624             :     // the SG action could potentially have changed
     625             :     // due to reflexive nature. Update KSync for reverse flow first
     626           3 :     UpdateKSync(rflow, true);
     627           3 :     UpdateKSync(flow, true);
     628             : 
     629             :     // Update flow-mgmt with new values
     630           3 :     AddFlowInfo(flow);
     631           3 :     AddFlowInfo(rflow);
     632           3 :     return;
     633             : }
     634             : 
     635           0 : void FlowTable::HandleKSyncError(FlowEntry *flow,
     636             :                                  FlowTableKSyncEntry *ksync_entry,
     637             :                                  int ksync_error, uint32_t flow_handle,
     638             :                                  uint32_t gen_id) {
     639             :     // flow not associated with ksync anymore. Ignore the message
     640           0 :     if (flow == NULL || flow != ksync_entry->flow_entry()) {
     641           0 :         return;
     642             :     }
     643             : 
     644             :     // VRouter can return EBADF and ENONENT error if flow-handle changed before
     645             :     // getting KSync response back. Avoid making short-flow in such case
     646           0 :     if ((ksync_error == EBADF || ksync_error == ENOENT)) {
     647           0 :         if (flow->flow_handle() != flow_handle || flow->gen_id() != gen_id) {
     648           0 :             return;
     649             :         }
     650             :     }
     651             : 
     652             :     // If VRouter returns error, mark the flow entry as short flow and
     653             :     // update ksync error event to ksync index manager
     654             :     //
     655             :     // For EEXIST error donot mark the flow as ShortFlow since Vrouter
     656             :     // generates EEXIST only for cases where another add should be
     657             :     // coming from the pkt trap from Vrouter
     658           0 :     if (ksync_error != EEXIST || flow->is_flags_set(FlowEntry::NatFlow)) {
     659             :         // FIXME : We dont have good scheme to handle following scenario,
     660             :         // - VM1 in VN1 has floating-ip FIP1 in VN2
     661             :         // - VM2 in VN2
     662             :         // - VM1 pings VM2 (using floating-ip)
     663             :         // The forward and reverse flows go to different partitions.
     664             :         //
     665             :         // If packets for both forward and reverse flows are trapped together
     666             :         // we try to setup following flows from different partitions,
     667             :         // FlowPair-1
     668             :         //    - VM1 to VM2
     669             :         //    - VM2 to FIP1
     670             :         // FlowPair-2
     671             :         //    - VM2 to FIP1
     672             :         //    - VM1 to VM2
     673             :         //
     674             :         // CEM-18166: BGPaaS corrupted NAT flow after repeated BGP session flap
     675             :         // In the test environment it was observed that flows would remain stuck
     676             :         // with old reverse indexes, after a few operations of disabling and
     677             :         // re-enabling the interface on the VNF.
     678             :         // A previous attempt to fix this in CEM-10354 proved to be incomplete.
     679             :         // A better way to handle this case is to make the flows in question
     680             :         // short, but since EEXIST is returned for the RF (from Controller), it
     681             :         // is necessary to update the ksync_entry to the flow handle returned by
     682             :         // vrouter DP, Agent does not know it and is thus -1.
     683           0 :         if (flow->is_flags_set(FlowEntry::ReverseFlow) && 
     684           0 :             ksync_error == EEXIST && 
     685           0 :             flow->is_flags_set(FlowEntry::BgpRouterService)) {
     686             :             KSyncFlowIndexManager *mgr =
     687           0 :                     agent()->ksync()->ksync_flow_index_manager();
     688           0 :             mgr->UpdateFlowHandle(ksync_entry,
     689           0 :                                   ksync_entry->ksync_response_info()->flow_handle_,
     690           0 :                                   ksync_entry->ksync_response_info()->gen_id_);
     691           0 :             flow->MakeShortFlow(FlowEntry::SHORT_FAILED_VROUTER_INSTALL);
     692           0 :             return;
     693             :         }
     694             :         // The reverse flows for both FlowPair-1 and FlowPair-2 are not
     695             :         // installed due to EEXIST error. We are converting flows to
     696             :         // short-flow till this case is handled properly
     697           0 :         flow->MakeShortFlow(FlowEntry::SHORT_FAILED_VROUTER_INSTALL);
     698             :     }
     699           0 :     if (ksync_error == EEXIST) {
     700             :         const VmInterface *intf =
     701           0 :         dynamic_cast<const VmInterface*>(flow->data().intf_entry.get());
     702           0 :         KSyncFlowMemory *ksync_obj = agent()->ksync()->ksync_flow_memory();
     703           0 :         const vr_flow_entry *kflow = ksync_obj->GetKernelFlowEntry(flow_handle, false);
     704           0 :         if (kflow != nullptr &&
     705           0 :             intf != nullptr &&
     706           0 :             (kflow->fe_action != VR_FLOW_ACTION_HOLD)) {
     707           0 :             if (flow->flow_handle() == FlowEntry::kInvalidFlowHandle) {
     708             :                 KSyncFlowIndexManager *mgr =
     709           0 :                    agent()->ksync()->ksync_flow_index_manager();
     710           0 :                 mgr->UpdateFlowHandle(ksync_entry,
     711             :                                       flow_handle, //ksync_entry->ksync_response_info()->flow_handle_,
     712             :                                       gen_id); //ksync_entry->ksync_response_info()->gen_id_);
     713             :                 }
     714           0 :                 flow->MakeShortFlow(FlowEntry::SHORT_FAILED_VROUTER_INSTALL);
     715             :         }
     716             :     }
     717           0 :     return;
     718             : }
     719             : 
     720             : /////////////////////////////////////////////////////////////////////////////
     721             : // KSync Routines
     722             : /////////////////////////////////////////////////////////////////////////////
     723         144 : void FlowTable::DeleteKSync(FlowEntry *flow) {
     724         144 :     KSyncFlowIndexManager *mgr = agent()->ksync()->ksync_flow_index_manager();
     725         144 :     mgr->Delete(flow);
     726         144 : }
     727             : 
     728         307 : void FlowTable::UpdateKSync(FlowEntry *flow, bool update) {
     729         307 :     KSyncFlowIndexManager *mgr = agent()->ksync()->ksync_flow_index_manager();
     730         307 :     if (flow->deleted()) {
     731             :         // ignore update on a deleted flow
     732             :         // flow should already be non deleted of an Add case
     733           0 :         assert(update == false);
     734           0 :         return;
     735             :     }
     736         307 :     mgr->Update(flow);
     737             : }
     738             : 
     739          32 : void FlowTable::DisableKSyncSend(FlowEntry *flow, uint32_t evict_gen_id) {
     740          32 :     KSyncFlowIndexManager *mgr = agent()->ksync()->ksync_flow_index_manager();
     741          32 :     mgr->DisableSend(flow, evict_gen_id);
     742          32 : }
     743             : 
     744             : /////////////////////////////////////////////////////////////////////////////
     745             : // Link local flow information tree
     746             : /////////////////////////////////////////////////////////////////////////////
     747           0 : void FlowTable::AddLinkLocalFlowInfo(int fd, uint32_t index, const FlowKey &key,
     748             :                                      const uint64_t timestamp) {
     749           0 :     std::scoped_lock mutext(mutex_);
     750           0 :     LinkLocalFlowInfoMap::iterator it = linklocal_flow_info_map_.find(fd);
     751           0 :     if (it == linklocal_flow_info_map_.end()) {
     752           0 :         linklocal_flow_info_map_.insert(
     753           0 :           LinkLocalFlowInfoPair(fd, LinkLocalFlowInfo(index, key, timestamp)));
     754             :     } else {
     755           0 :         it->second.flow_index = index;
     756           0 :         it->second.flow_key = key;
     757             :     }
     758           0 : }
     759             : 
     760           0 : void FlowTable::DelLinkLocalFlowInfo(int fd) {
     761           0 :     std::scoped_lock mutext(mutex_);
     762           0 :     linklocal_flow_info_map_.erase(fd);
     763           0 : }
     764             : 
     765             : /////////////////////////////////////////////////////////////////////////////
     766             : // Event handler routines
     767             : /////////////////////////////////////////////////////////////////////////////
     768             : 
     769             : // KSync flow event handler. Handles response for both vr_flow message only
     770         378 : void FlowTable::ProcessKSyncFlowEvent(const FlowEventKSync *req,
     771             :                                       FlowEntry *flow) {
     772             :     FlowTableKSyncEntry *ksync_entry =
     773         378 :         (static_cast<FlowTableKSyncEntry *> (req->ksync_entry()));
     774         378 :     KSyncFlowIndexManager *imgr = agent()->ksync()->ksync_flow_index_manager();
     775             : 
     776             :     // flow not associated with ksync anymore. Ignore the message
     777         378 :     if (flow == NULL) {
     778           0 :         return;
     779             :     }
     780             : 
     781             :     // Ignore error for Delete messages
     782         378 :     if (req->ksync_event() == KSyncEntry::DEL_ACK) {
     783         148 :         return;
     784             :     }
     785             :     
     786             :     // if transaction id is not same, then ignore the old
     787             :     // vrouter add-ack response. this is possible that
     788             :     // after vrouter add-ack response, flows will be evicted
     789             :     // and new wflow with same flow tuple as evicted one will
     790             :     // trigger new flow request to agent. this old add-ack response
     791             :     // has no relevance, so should be ignored.
     792         230 :     if (req->transaction_id() != flow->GetTransactionId()) {
     793           0 :         return;
     794             :     }
     795             : 
     796         230 :     if (req->ksync_error() != 0) {
     797             :         // Handle KSync Errors
     798           0 :         HandleKSyncError(flow, ksync_entry, req->ksync_error(),
     799             :                          req->flow_handle(), req->gen_id());
     800             :     } else {
     801             :         // Operation succeeded. Update flow-handle if not assigned
     802             :         KSyncFlowIndexManager *mgr =
     803         230 :             agent()->ksync()->ksync_flow_index_manager();
     804         230 :         mgr->UpdateFlowHandle(ksync_entry, req->flow_handle(),
     805         230 :                               req->gen_id());
     806             :     }
     807             : 
     808             :     // Log message if flow-handle change
     809         230 :     if (flow->flow_handle() != FlowEntry::kInvalidFlowHandle) {
     810         230 :         if (flow->flow_handle() != req->flow_handle()) {
     811           0 :             LOG(DEBUG, "Flow index changed from <"
     812             :                 << flow->flow_handle() << "> to <"
     813             :                 << req->flow_handle() << ">");
     814             :         }
     815             :     }
     816             : 
     817             :     // When vrouter allocates a flow-index or changes flow-handle, its
     818             :     // possible that a flow in vrouter is evicted. Update stats for
     819             :     // evicted flow
     820         460 :     if (req->flow_handle() != FlowEntry::kInvalidFlowHandle &&
     821         230 :         req->flow_handle() != flow->flow_handle()) {
     822           0 :         FlowEntryPtr evicted_flow = imgr->FindByIndex(req->flow_handle());
     823           0 :         if (evicted_flow.get() && evicted_flow->deleted() == false) {
     824           0 :             FlowMgmtManager *mgr = agent()->pkt()->flow_mgmt_manager(table_index_);
     825           0 :             mgr->FlowStatsUpdateEvent(evicted_flow.get(),
     826           0 :                                       req->evict_flow_bytes(),
     827           0 :                                       req->evict_flow_packets(),
     828           0 :                                       req->evict_flow_oflow(),
     829             :                                       evicted_flow->uuid());
     830             :         }
     831           0 :     }
     832             : 
     833         230 :     return;
     834             : }
     835             : 
     836         511 : bool FlowTable::ProcessFlowEvent(const FlowEvent *req, FlowEntry *flow,
     837             :                                  FlowEntry *rflow) {
     838             :     //Take lock
     839         679 :     FLOW_LOCK(flow, rflow, req->event());
     840             : 
     841         511 :     if (flow)
     842         511 :         flow->set_last_event(req->event());
     843         511 :     if (rflow)
     844         343 :         rflow->set_last_event(req->event());
     845         511 :     bool active_flow = true;
     846         511 :     bool deleted_flow = flow->deleted();
     847         511 :     if (deleted_flow || flow->is_flags_set(FlowEntry::ShortFlow))
     848         219 :         active_flow = false;
     849             : 
     850             :     //Now process events.
     851         511 :     switch (req->event()) {
     852           0 :     case FlowEvent::DELETE_FLOW: {
     853             :         //In case of continous stream of short lived TCP flows with same 5 tuple,
     854             :         //flow eviction logic might cause below set of event
     855             :         //1> F1 and R1 flow are added to flow table
     856             :         //2> R1 is written to vrouter
     857             :         //3> F1 is written to vrouter
     858             :         //4> R1 flow add response is received, triggering update of
     859             :         //   F1(not needed now as reverse flow index is not written to kernel?)
     860             :         //5> In the meantime flow is evicted in vrouter, hence flow update for F1
     861             :         //   would result in error from vrouter resulting in short flow
     862             :         //6> Since F1 is shortflow Flow delete gets enqueued
     863             :         //7> Since R1 is evict marked, flow evict gets enqueued
     864             :         //8> Both event F1 and R1 delete and evict event can run in parallel,
     865             :         //   and hence reverse flow pointer obtained before FLOW lock could
     866             :         //   be invalid, hence read back the same
     867           0 :         rflow = flow->reverse_flow_entry();
     868           0 :         DeleteUnLocked(true, flow, rflow);
     869           0 :         break;
     870             :     }
     871             : 
     872          49 :     case FlowEvent::DELETE_DBENTRY: {
     873          49 :         DeleteMessage(flow);
     874          49 :         break;
     875             :     }
     876             : 
     877           4 :     case FlowEvent::REVALUATE_DBENTRY: {
     878           4 :         const DBEntry *entry = req->db_entry();
     879           4 :         HandleRevaluateDBEntry(entry, flow, active_flow, deleted_flow);
     880           4 :         break;
     881             :     }
     882             : 
     883          48 :     case FlowEvent::RECOMPUTE_FLOW: {
     884          48 :         if (active_flow)
     885          40 :             RecomputeFlow(flow);
     886          48 :         break;
     887             :     }
     888             : 
     889             :     // Check if flow-handle changed. This can happen if vrouter tries to
     890             :     // setup the flow which was evicted earlier
     891          32 :     case FlowEvent::EVICT_FLOW: {
     892          64 :         if (flow->flow_handle() != req->flow_handle() ||
     893          32 :             flow->gen_id() != req->gen_id())
     894           0 :             break;
     895          32 :         EvictFlow(flow, rflow, req->evict_gen_id());
     896          32 :         break;
     897             :     }
     898             : 
     899         378 :     case FlowEvent::KSYNC_EVENT: {
     900         378 :         const FlowEventKSync *ksync_event =
     901             :             static_cast<const FlowEventKSync *>(req);
     902             :         // Handle vr_flow message
     903         378 :         ProcessKSyncFlowEvent(ksync_event, flow);
     904             :         // Handle vr_response message
     905             :         // Trigger the ksync flow event to move ksync state-machine
     906             :         KSyncFlowIndexManager *imgr =
     907         378 :             agent()->ksync()->ksync_flow_index_manager();
     908             :         FlowTableKSyncEntry *ksync_entry = static_cast<FlowTableKSyncEntry *>
     909         378 :             (ksync_event->ksync_entry());
     910         378 :         imgr->TriggerKSyncEvent(ksync_entry, ksync_event->ksync_event());
     911         378 :         break;
     912             :     }
     913             : 
     914           0 :     case FlowEvent::UNRESOLVED_FLOW_ENTRY: {
     915           0 :         if (flow->deleted()) {
     916           0 :             break;
     917             :         }
     918             : 
     919           0 :         if (flow->GetMaxRetryAttempts() < FlowEntry::kFlowRetryAttempts) {
     920           0 :             flow->IncrementRetrycount();
     921             :         } else {
     922           0 :             flow->MakeShortFlow(FlowEntry::SHORT_NO_MIRROR_ENTRY);
     923           0 :             flow->ResetRetryCount();
     924             :         }
     925             : 
     926           0 :         UpdateKSync(flow, true);
     927           0 :         break;
     928             :     }
     929             : 
     930           0 :     default: {
     931           0 :         assert(0);
     932             :         break;
     933             :     }
     934             :     }
     935         511 :     return true;
     936         511 : }
     937             : 
     938         428 : void FlowTable::GetFlowSandeshActionParams(const FlowAction &action_info,
     939             :                                            std::string &action_str) {
     940         428 :     std::bitset<32> bs(action_info.action);
     941       14050 :     for (unsigned int i = 0; i < bs.size(); i++) {
     942       13627 :         if (bs[i]) {
     943         366 :             if (!action_str.empty()) {
     944          10 :                 action_str += "|";
     945             :             }
     946         732 :             action_str += TrafficAction::ActionToString(
     947         366 :                 static_cast<TrafficAction::Action>(i));
     948             :         }
     949             :     }
     950         423 : }
     951             : /////////////////////////////////////////////////////////////////////////////
     952             : // FlowEntryFreeList implementation
     953             : /////////////////////////////////////////////////////////////////////////////
     954           0 : void FlowTable::GrowFreeList() {
     955           0 :     free_list_.Grow();
     956           0 :     ksync_object_->GrowFreeList();
     957           0 : }
     958             : 
     959           2 : FlowEntryFreeList::FlowEntryFreeList(FlowTable *table) :
     960           2 :     table_(table), max_count_(0), grow_pending_(false), total_alloc_(0),
     961           2 :     total_free_(0), free_list_() {
     962           2 :     uint32_t count = kInitCount;
     963           2 :     if (table->agent()->test_mode()) {
     964           2 :         count = kTestInitCount;
     965             :     }
     966             : 
     967       10002 :     while (max_count_ < count) {
     968       10000 :         free_list_.push_back(*new FlowEntry(table));
     969       10000 :         max_count_++;
     970             :     }
     971           2 : }
     972             : 
     973           2 : FlowEntryFreeList::~FlowEntryFreeList() {
     974       10002 :     while (free_list_.empty() == false) {
     975       10000 :         FreeList::iterator it = free_list_.begin();
     976       10000 :         FlowEntry *flow = &(*it);
     977       20000 :         free_list_.erase(it);
     978       10000 :         delete flow;
     979             :     }
     980           2 : }
     981             : 
     982             : // Allocate a chunk of FlowEntries
     983           0 : void FlowEntryFreeList::Grow() {
     984           0 :     assert(table_->ConcurrencyCheck(table_->flow_task_id()) == true);
     985           0 :     grow_pending_ = false;
     986           0 :     if (free_list_.size() >= kMinThreshold)
     987           0 :         return;
     988             : 
     989           0 :     for (uint32_t i = 0; i < kGrowSize; i++) {
     990           0 :         free_list_.push_back(*new FlowEntry(table_));
     991           0 :         max_count_++;
     992             :     }
     993             : }
     994             : 
     995         224 : FlowEntry *FlowEntryFreeList::Allocate(const FlowKey &key) {
     996         224 :     assert(table_->ConcurrencyCheck(table_->flow_task_id()) == true);
     997         224 :     FlowEntry *flow = NULL;
     998         224 :     if (free_list_.size() == 0) {
     999           0 :         flow = new FlowEntry(table_);
    1000           0 :         max_count_++;
    1001             :     } else {
    1002         224 :         FreeList::iterator it = free_list_.begin();
    1003         224 :         flow = &(*it);
    1004         448 :         free_list_.erase(it);
    1005             :     }
    1006             : 
    1007         224 :     if (grow_pending_ == false && free_list_.size() < kMinThreshold) {
    1008           0 :         grow_pending_ = true;
    1009           0 :         FlowProto *proto = table_->agent()->pkt()->get_flow_proto();
    1010           0 :         proto->GrowFreeListRequest(table_);
    1011             :     }
    1012         224 :     flow->Reset(key);
    1013         224 :     total_alloc_++;
    1014         224 :     return flow;
    1015             : }
    1016             : 
    1017         224 : void FlowEntryFreeList::Free(FlowEntry *flow) {
    1018             :    // only flow logging task and flow event task can  free up the flow entry ,
    1019         224 :    assert((table_->ConcurrencyCheck(table_->flow_task_id()) == true) ||
    1020             :         (table_->ConcurrencyCheck(
    1021             :             table_->flow_logging_task_id(), false) == true));
    1022         224 :     total_free_++;
    1023         224 :     flow->Reset();
    1024         224 :     if (free_list_.size() < kMaxThreshold) {
    1025         224 :         free_list_.push_back(*flow);
    1026         224 :         assert(flow->flow_mgmt_info() == NULL);
    1027             :     } else {
    1028           0 :         delete flow;
    1029           0 :         --max_count_;
    1030             :     }
    1031         224 : }

Generated by: LCOV version 1.14