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: 117 131 89.3 %
Date: 2026-11-09 02:10:49 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14