LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/ksync - ksync_flow_index_manager.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 99 131 75.6 %
Date: 2026-08-03 02:19:58 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             :  #include <mutex>
       6             : 
       7             : #include <pkt/flow_proto.h>
       8             : #include <pkt/pkt_types.h>
       9             : #include <pkt/flow_entry.h>
      10             : #include <init/agent_param.h>
      11             : #include "ksync_flow_index_manager.h"
      12             : #include "flowtable_ksync.h"
      13             : #include "ksync_init.h"
      14             : 
      15             : #define INDEX_LOCK(idx) \
      16             :     auto lock = (idx != FlowEntry::kInvalidFlowHandle) \
      17             :         ? std::unique_lock<std::mutex>(index_list_[idx].mutex_) \
      18             :         : std::unique_lock<std::mutex>();
      19             : 
      20             : //////////////////////////////////////////////////////////////////////////////
      21             : // KSyncFlowIndexManager routines
      22             : //////////////////////////////////////////////////////////////////////////////
      23           3 : KSyncFlowIndexManager::KSyncFlowIndexManager(KSync *ksync) :
      24           3 :     ksync_(ksync), proto_(NULL), count_(0), index_list_(), sm_log_count_(0) {
      25           3 : }
      26             : 
      27           6 : KSyncFlowIndexManager::~KSyncFlowIndexManager() {
      28           3 :     if (count_ > 0)
      29      393219 :         delete [] index_list_;
      30           6 : }
      31             : 
      32           3 : void KSyncFlowIndexManager::InitDone(uint32_t count) {
      33           3 :     proto_ = ksync_->agent()->pkt()->get_flow_proto();
      34           3 :     count_ = count;
      35      393219 :     index_list_ = new struct IndexEntry[count_];
      36           3 :     sm_log_count_ = ksync_->agent()->params()->flow_index_sm_log_count();
      37           3 : }
      38             : 
      39             : //////////////////////////////////////////////////////////////////////////////
      40             : // KSyncFlowIndexManager Utility methods
      41             : //////////////////////////////////////////////////////////////////////////////
      42          22 : FlowEntryPtr KSyncFlowIndexManager::FindByIndex(uint32_t idx) {
      43          22 :     if (index_list_[idx].owner_.get() != NULL)
      44           0 :         return index_list_[idx].owner_;
      45          22 :     return FlowEntryPtr(NULL);
      46             : }
      47             : 
      48             : //////////////////////////////////////////////////////////////////////////////
      49             : // Update:
      50             : //     Flow module triggers this API to propagate Add/Change to vrouter
      51             : //
      52             : //     API tries to acquire flow handle and create the KSync entry for
      53             : //     flow, if there is an existing KSync entry, if validates for change
      54             : //     in flow handle and triggers change / Delete-Add accordingly
      55             : //////////////////////////////////////////////////////////////////////////////
      56         122 : void KSyncFlowIndexManager::Update(FlowEntry *flow) {
      57         122 :     FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
      58             :     // flow should not be delete marked
      59         122 :     assert(!flow->deleted());
      60         122 :     if (flow->ksync_entry_ == NULL) {
      61          44 :         CreateInternal(flow);
      62             :     } else {
      63          78 :         if (flow->flow_handle() != flow->ksync_entry_->hash_id()) {
      64             :             // if flow handle changes delete the previous record from
      65             :             // vrouter and install new
      66           0 :             Delete(flow);
      67           0 :             CreateInternal(flow);
      68             :         } else {
      69          78 :             INDEX_LOCK(flow->flow_handle());
      70          78 :             uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
      71          78 :                                                         flow->gen_id(),
      72             :                                                         flow);
      73          78 :             flow->ksync_entry_->set_gen_id(flow->gen_id());
      74          78 :             flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
      75          78 :             flow->LogFlow(FlowEventLog::FLOW_UPDATE, flow->ksync_entry_,
      76          78 :                           flow->flow_handle(), flow->gen_id());
      77          78 :             object->Change(flow->ksync_entry_);
      78          78 :         }
      79             :     }
      80         122 : }
      81             : 
      82             : //////////////////////////////////////////////////////////////////////////////
      83             : // Delete:
      84             : //     Flow module triggers this API to propagate Delete to vrouter
      85             : //
      86             : //     API tries triggers Delete and Release index ownership
      87             : //////////////////////////////////////////////////////////////////////////////
      88          44 : void KSyncFlowIndexManager::Delete(FlowEntry *flow) {
      89          44 :     if (flow->ksync_entry_ != NULL) {
      90          44 :         FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
      91          44 :         INDEX_LOCK(flow->ksync_entry_->hash_id());
      92          44 :         ReleaseIndexUnLocked(flow);
      93          44 :         flow->LogFlow(FlowEventLog::FLOW_DELETE, flow->ksync_entry_,
      94          44 :                       flow->flow_handle(), flow->gen_id());
      95          44 :         FlowTableKSyncEntry *kentry = flow->ksync_entry_;
      96             :         // reset ksync_entry_ before triggering delete as Delete
      97             :         // may just free the entry, if there is nothing to encode
      98             :         // which may inturn free the flow entry pointer
      99          44 :         flow->ksync_entry_ = NULL;
     100          44 :         object->Delete(kentry);
     101          44 :     }
     102          44 : }
     103             : 
     104             : //////////////////////////////////////////////////////////////////////////////
     105             : // Delete:
     106             : //     Flow module triggers this API to suppress message to vrouter
     107             : //
     108             : //     API ensures that evict_gen_id has different value from gen_id
     109             : //////////////////////////////////////////////////////////////////////////////
     110           0 : void KSyncFlowIndexManager::DisableSend(FlowEntry *flow,
     111             :                                         uint8_t evict_gen_id) {
     112           0 :     FlowTableKSyncEntry *kentry = flow->ksync_entry_;
     113           0 :     if (kentry != NULL) {
     114           0 :         INDEX_LOCK(flow->flow_handle());
     115           0 :         kentry->set_evict_gen_id(evict_gen_id);
     116           0 :     }
     117           0 : }
     118             : 
     119             : //////////////////////////////////////////////////////////////////////////////
     120             : // UpdateFlowHandle:
     121             : //     Flow module triggers this API to update flow handle for the reverse
     122             : //     flow.
     123             : //
     124             : //     API Assigns index and gen id received from vrouter to KSync entry
     125             : //     an let the further operation use correct index and gen-id to
     126             : //     communicate with vrouter
     127             : //     KsyncEntry here should always have kInvalidFlowHandle
     128             : //////////////////////////////////////////////////////////////////////////////
     129         100 : void KSyncFlowIndexManager::UpdateFlowHandle(FlowTableKSyncEntry *kentry,
     130             :                                              uint32_t index,
     131             :                                              uint8_t gen_id) {
     132         100 :     assert(index != FlowEntry::kInvalidFlowHandle);
     133             : 
     134             :     // Check if index and gen id is corresponding to the info sent
     135             :     // to vrouter, if vrouter has allocated flow index, following
     136             :     // check will fail and it will follow through
     137             :     // to process index allocation
     138         178 :     if (kentry->vrouter_hash_id() == index &&
     139          78 :         kentry->vrouter_gen_id() == gen_id) {
     140          78 :         return;
     141             :     }
     142             : 
     143          22 :     FlowEntry *flow = kentry->flow_entry().get();
     144          22 :     FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
     145             :     uint8_t evict_gen_id;
     146          22 :     if (!kentry->IsDeleted() && flow->ksync_entry_!=NULL) {
     147             :         // if kentry is not deleted flow should always point to this
     148             :         // ksync entry only
     149          22 :         assert(kentry == flow->ksync_entry_);
     150          22 :         FlowEntry *rflow = flow->reverse_flow_entry();
     151             : 
     152             :         // Index allocation should happen only if flow_handle is
     153             :         // kInvalidFlowHandle
     154          22 :         assert(flow->flow_handle() == FlowEntry::kInvalidFlowHandle);
     155          22 :         INDEX_LOCK(index);
     156          22 :         flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
     157          22 :         flow->set_flow_handle(index, gen_id);
     158          22 :         object->UpdateFlowHandle(kentry, index);
     159          22 :         evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
     160          22 :                                             flow->gen_id(), flow);
     161          22 :         kentry->set_gen_id(gen_id);
     162          22 :         kentry->set_evict_gen_id(evict_gen_id);
     163          22 :         if (rflow) {
     164             :                 // forward and reverse flow handle should not be same
     165             :             //assert process to avoid deadlock if both are same
     166          22 :             assert(flow->flow_handle() != rflow->flow_handle());
     167          22 :             rflow->flow_table()->UpdateKSync(rflow, true);
     168             :         }
     169          22 :     } else {
     170             :         // KSync entry is deleted, This happens when Reverse flow
     171             :         // is deleted before getting an ACK from vrouter.
     172             :         // this can happen if we delete the flow itself or if we
     173             :         // get a new index from packet processing which will result
     174             :         // in deletion of this KSync entry
     175             :         // just use the correct key to encode delete msg
     176           0 :         INDEX_LOCK(index);
     177           0 :         flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
     178           0 :         evict_gen_id = AcquireIndexUnLocked(index, gen_id, NULL);
     179             :         // following processing is required only if kentry successfully
     180             :         // acquired the index, on index acquire failure we will anyway
     181             :         // skip sending message to vrouter due to evicted state.
     182             :         // So avoid changing ksync entry handle to avoid replacing
     183             :         // hash id of an active ksync entry (Bug - 1587540)
     184           0 :         if (evict_gen_id == gen_id) {
     185           0 :             object->UpdateFlowHandle(kentry, index);
     186           0 :             kentry->set_gen_id(gen_id);
     187           0 :             kentry->set_evict_gen_id(evict_gen_id);
     188             :         }
     189           0 :     }
     190             : }
     191             : 
     192             : //////////////////////////////////////////////////////////////////////////////
     193             : // TriggerKSyncEvent:
     194             : //     Flow module triggers this API to propagate KSyncEvent to KSync Entry
     195             : //
     196             : //     API ensures that we hold Index Lock, to allow any pending operation
     197             : //     on KSync Entry to happen with Index Lock Held
     198             : //////////////////////////////////////////////////////////////////////////////
     199         144 : void KSyncFlowIndexManager::TriggerKSyncEvent(FlowTableKSyncEntry *kentry,
     200             :                                               KSyncEntry::KSyncEvent event) {
     201             :     FlowTableKSyncObject *object = static_cast<FlowTableKSyncObject *>
     202         144 :         (kentry->GetObject());
     203         144 :     INDEX_LOCK(kentry->hash_id());
     204         144 :     object->GenerateKSyncEvent(kentry, event);
     205         144 : }
     206             : 
     207             : //////////////////////////////////////////////////////////////////////////////
     208             : // AcquireIndexUnLocked:
     209             : //     Tries to Acquire flow index by comparing gen id, evicts the entry
     210             : //     which has an older gen id
     211             : //////////////////////////////////////////////////////////////////////////////
     212         144 : uint8_t KSyncFlowIndexManager::AcquireIndexUnLocked(uint32_t index,
     213             :                                                     uint8_t gen_id,
     214             :                                                     FlowEntry *flow) {
     215         144 :     uint8_t evict_gen_id = gen_id;
     216         144 :     if (index == FlowEntry::kInvalidFlowHandle) {
     217          22 :         return evict_gen_id;
     218             :     }
     219             : 
     220         122 :     if (index_list_[index].owner_ != flow) {
     221          44 :         if (index_list_[index].owner_ != NULL) {
     222           0 :             FlowTableKSyncEntry *old = index_list_[index].owner_->ksync_entry_;
     223           0 :             uint8_t diff = gen_id - old->gen_id();
     224           0 :             if (diff < kActiveGenIdDiffMax) {
     225             :                 // evict old entry
     226           0 :                 old->set_evict_gen_id(gen_id);
     227           0 :                 old->flow_entry()->LogFlow(FlowEventLog::FLOW_EVICT, old,
     228             :                                            index, gen_id);
     229           0 :                 proto_->EvictFlowRequest(old->flow_entry().get(),
     230           0 :                                          old->hash_id(), old->gen_id(), gen_id);
     231           0 :                 index_list_[index].owner_ = flow;
     232             :             } else {
     233             :                 // evict current entry
     234           0 :                 evict_gen_id = old->gen_id();
     235           0 :                 if (flow) {
     236             :                     // KSyncEntry can be NULL at this point since acquire
     237             :                     // index can be done before creating KSyncEntry
     238             :                     // LogFlow needs to handle NULL KSyncEntry pointer
     239           0 :                     flow->LogFlow(FlowEventLog::FLOW_EVICT, flow->ksync_entry_,
     240             :                                   flow->flow_handle(), evict_gen_id);
     241           0 :                     proto_->EvictFlowRequest(flow, flow->flow_handle(),
     242           0 :                                              flow->gen_id(), evict_gen_id);
     243             :                 }
     244             :             }
     245             :         } else {
     246          44 :             index_list_[index].owner_ = flow;
     247             :         }
     248             :     }
     249             : 
     250         122 :     return evict_gen_id;
     251             : }
     252             : 
     253             : //////////////////////////////////////////////////////////////////////////////
     254             : // ReleaseIndexUnLocked:
     255             : //     Release the held flow index
     256             : //////////////////////////////////////////////////////////////////////////////
     257          44 : void KSyncFlowIndexManager::ReleaseIndexUnLocked(FlowEntry *flow) {
     258          44 :     if (flow->ksync_entry_->hash_id() == FlowEntry::kInvalidFlowHandle) {
     259           0 :         return;
     260             :     }
     261             : 
     262          44 :     if (index_list_[flow->ksync_entry_->hash_id()].owner_ == flow) {
     263          44 :         index_list_[flow->ksync_entry_->hash_id()].owner_ = NULL;
     264             :     }
     265             : }
     266             : 
     267          44 : void KSyncFlowIndexManager::CreateInternal(FlowEntry *flow) {
     268          44 :     FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
     269          44 :     INDEX_LOCK(flow->flow_handle());
     270          44 :     uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
     271          44 :                                                 flow->gen_id(),
     272             :                                                 flow);
     273          44 :     FlowTableKSyncEntry key(object, flow, flow->flow_handle());
     274          44 :     key.set_evict_gen_id(evict_gen_id);
     275          44 :     flow->ksync_entry_ =
     276          44 :         static_cast<FlowTableKSyncEntry *>(object->Create(&key));
     277             :     // Update gen id after create to handle case where ksync entry
     278             :     // was not constructed newly and was resued, thus gen id was
     279             :     // not updated in create
     280          44 :     flow->ksync_entry_->set_gen_id(flow->gen_id());
     281          44 :     flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
     282          44 :     flow->ksync_entry_->set_transaction_id(flow->GetTransactionId());
     283          44 :     flow->LogFlow(FlowEventLog::FLOW_ADD, flow->ksync_entry_,
     284          44 :                   flow->flow_handle(), flow->gen_id());
     285          44 : }

Generated by: LCOV version 1.14