LCOV - code coverage report
Current view: top level - ksync - ksync_entry.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 61 62 98.4 %
Date: 2026-08-03 02:19:58 Functions: 32 35 91.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef ctrlplane_ksync_entry_h
       6             : #define ctrlplane_ksync_entry_h
       7             : 
       8             : #include <boost/intrusive_ptr.hpp>
       9             : #include <boost/intrusive/set.hpp>
      10             : #include <atomic>
      11             : #include <sandesh/common/vns_constants.h>
      12             : #include <sandesh/common/vns_types.h>
      13             : #include <sandesh/sandesh_trace.h>
      14             : #include <db/db_entry.h>
      15             : 
      16             : #define KSYNC_ERROR(obj, ...)\
      17             : do {\
      18             :     if (LoggingDisabled()) break;\
      19             :     obj::Send(g_vns_constants.CategoryNames.find(Category::VROUTER)->second,\
      20             :               SandeshLevel::SYS_DEBUG, __FILE__, __LINE__, ##__VA_ARGS__);\
      21             : } while (false)
      22             : 
      23             : extern SandeshTraceBufferPtr KSyncErrorTraceBuf;
      24             : #define KSYNC_ERROR_TRACE(obj, ...)                                           \
      25             : do {                                                                          \
      26             :     KSyncError##obj::TraceMsg(KSyncErrorTraceBuf,                             \
      27             :                               __FILE__, __LINE__, __VA_ARGS__);               \
      28             : } while (false)
      29             : 
      30             : class KSyncObject;
      31             : class KSyncDBObject;
      32             : 
      33             : class KSyncEntry {
      34             : public:
      35             :     enum KSyncState {
      36             :         INIT,           // Init state. Not notified
      37             :         TEMP,           // Temporary entry created on reference
      38             :         ADD_DEFER,      // Add of entry deferred due to unmet dependencies
      39             :         CHANGE_DEFER,   // Change of entry deferred due to unmet dependencies
      40             :         IN_SYNC,        // Object in sync
      41             :         SYNC_WAIT,      // Waiting on ACK for add/change
      42             :         NEED_SYNC,      // Object changed. Needs Sync
      43             :         DEL_DEFER_SYNC, // Del pending to be sent due to sync_wait
      44             :         DEL_DEFER_REF,  // Del pending to be sent due to ref-count
      45             :         DEL_DEFER_DEL_ACK, // Del pending to be sent due to Del Ack wait
      46             :         DEL_ACK_WAIT,   // Del request sent waiting for ack
      47             :         RENEW_WAIT,     // Object renewal waiting for delete-ack
      48             :         FREE_WAIT       // Entry to be freed
      49             :     };
      50             : 
      51             :     enum KSyncEvent {
      52             :         ADD_CHANGE_REQ,
      53             :         ADD_ACK,
      54             :         CHANGE_ACK,
      55             :         DEL_REQ,
      56             :         DEL_ADD_REQ,
      57             :         DEL_ACK,
      58             :         RE_EVAL,
      59             :         INT_PTR_REL,
      60             :         INVALID
      61             :     };
      62             : 
      63             :     std::string StateString() const;
      64             :     std::string AckOperationString(KSyncEvent ack_event) const;
      65             :     std::string EventString(KSyncEvent event) const;
      66             :     // All referring KSyncEntries must use KSyncEntryPtr. The ref-count
      67             :     // maintained is optionally used to defer DELETE till refcount is 0
      68             :     typedef boost::intrusive_ptr<KSyncEntry> KSyncEntryPtr;
      69             :     static const size_t kInvalidIndex = 0xFFFFFFFF;
      70             :     static const int kDefaultMsgSize = 512;
      71             : 
      72             :     // Use this constructor if automatic index allocation is *not* needed
      73       15149 :     KSyncEntry() {
      74       15149 :         Reset();
      75       15149 :     };
      76             :     // Use this constructor if automatic index allocation is needed
      77        3709 :     KSyncEntry(uint32_t index) {
      78        3709 :         Reset(index);
      79        3709 :     };
      80       18858 :     virtual ~KSyncEntry() { assert(refcount_ == 0);};
      81             : 
      82       33946 :     void Reset() {
      83       33946 :         index_ = kInvalidIndex;
      84       33946 :         state_ = INIT;
      85       33946 :         seen_ = false;
      86       33946 :         stale_ = false;
      87       33946 :         del_add_pending_ = false;
      88       33946 :         refcount_ = 0;
      89       33946 :     }
      90        3709 :     void Reset(uint32_t index) {
      91        3709 :         Reset();
      92        3709 :         index_ = index;
      93        3709 :     }
      94             : 
      95             :     // Comparator for boost::set containing all KSyncEntries in an KSyncObject
      96       38465 :     bool operator<(const KSyncEntry &rhs) const {
      97       38465 :         return IsLess(rhs);
      98             :     };
      99             :     // Comparator to manage the tree
     100             :     virtual bool IsLess(const KSyncEntry &rhs) const = 0;
     101             : 
     102             :     // Convert KSync to String
     103             :     virtual std::string ToString() const = 0;
     104             : 
     105             :     // Create handler.
     106             :     // Return true if operation is complete
     107             :     // Return false if operation asynchronously
     108             :     virtual bool Add() = 0;
     109             : 
     110             :     // Change handler.
     111             :     // Return true if operation is complete
     112             :     // Return false if operation asynchronously
     113             :     virtual bool Change() = 0;
     114             : 
     115             :     // Delete handler.
     116             :     // Return true if operation is complete
     117             :     // Return false if operation asynchronously
     118             :     virtual bool Delete() = 0;
     119             : 
     120             :     // KSyncObject for this entry. Used to release the index
     121             :     virtual KSyncObject *GetObject() const = 0;
     122             :     // Get an unresolved reference.
     123             :     // This entry will be added into resolveq_ of unresolved-entry
     124             :     virtual KSyncEntry *UnresolvedReference() = 0;
     125         883 :     virtual bool ShouldReEvalBackReference() const { return true; }
     126             : 
     127             :     // Returns true if entry is resolved and referring entry can be written
     128             :     bool IsResolved();
     129             : 
     130        2969 :     bool IsInSync() const { return (state_ == IN_SYNC); }
     131             : 
     132             :     /// @brief True only when the entry is resolved AND kernel-acknowledged (IN_SYNC).
     133             :     ///
     134             :     /// @details
     135             :     /// Dependencies that are programmed into vrouter must be gated on this
     136             :     /// condition instead of IsResolved() alone. An entry that is merely sent
     137             :     /// (SYNC_WAIT/NEED_SYNC) is not yet applied by the datapath, and a
     138             :     /// dependent sent against it races it in vrouter (EINVAL/ENOENT, the error
     139             :     /// ack is swallowed and the dependent is silently stuck out of vrouter).
     140             :     ///
     141             :     /// @return true if entry is resolved and kernel-acknowledged (IN_SYNC)
     142             :     /// @warning Entries in SYNC_WAIT or NEED_SYNC states may cause race conditions
     143             :     ///
     144             :     /// @see IsResolved()
     145             : 
     146         874 :     bool IsResolvedAndInSync() { return IsResolved() && IsInSync(); }
     147             : 
     148             :     // Returns true if the entry data is resolved
     149        2683 :     virtual bool IsDataResolved() {return true;}
     150             : 
     151             :     // User define KSync Response handler
     152        1111 :     virtual void Response() { };
     153             : 
     154             :     // Allow State Compression for delete.
     155           0 :     virtual bool AllowDeleteStateComp() {return true;}
     156             : 
     157             :     // User defined error handler
     158             :     virtual void ErrorHandler(int err, uint32_t seqno, KSyncEvent event) const;
     159             : 
     160             :     // Error message for vrouter returned errors
     161             :     virtual std::string VrouterError(uint32_t error) const;
     162             :     static std::string VrouterErrorToString(uint32_t error);
     163             : 
     164             :     // Every ksync operation needs an rx-buffer to read response. The rx buffer
     165             :     // are pre-allocated to minimize compuation in ksync-tx-queue
     166             :     // pre-allocation is enabled only for flows for now
     167         946 :     virtual bool pre_alloc_rx_buffer() const { return false; }
     168             :     // ksync-tx supports multiple queues for KSync events. Get index of queue
     169             :     // to use
     170        1892 :     virtual uint32_t GetTableIndex() const { return 0; }
     171             :     // On stale timer expiration, notify entry for same
     172           3 :     virtual void StaleTimerExpired() { }
     173             : 
     174        1816 :     size_t GetIndex() const {return index_;};
     175       55945 :     KSyncState GetState() const {return state_;};
     176        1156 :     bool del_add_pending() const {return del_add_pending_;}
     177        7450 :     uint32_t GetRefCount() const {return refcount_;}
     178        1170 :     bool Seen() const {return seen_;}
     179          55 :     bool stale() const {return stale_;}
     180         879 :     void SetSeen() {seen_ = true;}
     181        3204 :     bool IsDeleted() { return (state_ == DEL_ACK_WAIT ||
     182        1601 :                                state_ == DEL_DEFER_DEL_ACK ||
     183        4805 :                                state_ == DEL_DEFER_SYNC ||
     184        3204 :                                state_ == DEL_DEFER_REF); };
     185             : 
     186             :     // return true if an entry is actively owned some module,
     187             :     // i.e., explicit Create was triggered for this entry and it
     188             :     // is not deleted yet by the Creator.
     189             :     // this entry however may still be still in unresolved state.
     190             :     bool IsActive() { return (state_ != TEMP && !IsDeleted()); }
     191             : 
     192          22 :     void set_del_add_pending(bool pending) {del_add_pending_ = pending;}
     193        4129 :     void RecordTransition(KSyncState from, KSyncState to, KSyncEvent event) {
     194        4129 :         t_history_.RecordTransition(from, to, event);
     195        4129 :     }
     196             : 
     197             : protected:
     198             :     void SetIndex(size_t index) {index_ = index;};
     199        4189 :     void SetState(KSyncState state) {state_ = state;};
     200             : private:
     201             :     friend void intrusive_ptr_add_ref(KSyncEntry *p);
     202             :     friend void intrusive_ptr_release(KSyncEntry *p);
     203             :     friend class KSyncSock;
     204             :     friend class KSyncObject;
     205             : 
     206             :     boost::intrusive::set_member_hook<> node_;
     207             : 
     208             :     size_t              index_;
     209             :     KSyncState          state_;
     210             :     std::atomic<int>    refcount_;
     211             :     bool                seen_;
     212             : 
     213             :     // Stale Entry flag indicates an entry as stale, which will be
     214             :     // removed once stale entry timer cleanup gets triggered.
     215             :     bool                stale_;
     216             : 
     217             :     // flag to indicate a pending DelAdd operation on entry
     218             :     // this is set to true when Delete Add operation cannot go
     219             :     // through as entry is waiting of Ack for previous operation
     220             :     bool                del_add_pending_;
     221             : 
     222             :     struct KSyncEntryTransition {
     223             :             KSyncState from_;
     224             :             KSyncState to_;
     225             :             KSyncEvent event_;
     226             :     };
     227             :     class KSyncEntryTransHistory {
     228             :         public:
     229       18858 :             KSyncEntryTransHistory() {
     230       18858 :                 idx_ = 0;
     231      113148 :                 for (int i = 0; i < size_; i++) {
     232       94290 :                     history_[i].event_ = INVALID;
     233             :                 }
     234       18858 :             }
     235             : 
     236        4129 :             void RecordTransition(KSyncState from, KSyncState to,
     237             :                                    KSyncEvent event) {
     238        4129 :                 history_[idx_].from_ = from;
     239        4129 :                 history_[idx_].to_ = to;
     240        4129 :                 history_[idx_].event_ = event;
     241        4129 :                 idx_ = (idx_+1) % size_;
     242        4129 :             }
     243             :         private:
     244             :             static const int size_ = 5;
     245             :             int idx_;
     246             :             struct KSyncEntryTransition history_[size_];
     247             :     };
     248             :     KSyncEntryTransHistory t_history_;
     249             : 
     250             :     DISALLOW_COPY_AND_ASSIGN(KSyncEntry);
     251             : };
     252             : 
     253             : // Implementation of KSyncEntry with with DBTable. Must be used along
     254             : // with KSyncDBObject.
     255             : // Registers with DBTable and drives state-machine based on DBTable
     256             : // notifications
     257             : // Applications are not needed to generate any events to the state-machine
     258             : class KSyncDBEntry : public KSyncEntry, public DBState {
     259             : public:
     260             :     typedef std::list<DBEntry *> DupEntryList;
     261             : 
     262          53 :     KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; };
     263        2893 :     KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; };
     264        2946 :     virtual ~KSyncDBEntry() { assert(dup_entry_list_.empty()); }
     265             : 
     266             :     // Check if object is in-sync with kernel.
     267             :     // Return true if object needs sync. Else return false
     268             :     virtual bool Sync(DBEntry *entry) = 0;
     269             : 
     270         888 :     void SetDBEntry(DBEntry *db_entry) { db_entry_ = db_entry; }
     271        1707 :     DBEntry * GetDBEntry() { return db_entry_; }
     272             : 
     273             : private:
     274             :     friend class KSyncDBObject;
     275             : 
     276             :     DBEntry *db_entry_;
     277             :     DupEntryList dup_entry_list_;
     278             :     DISALLOW_COPY_AND_ASSIGN(KSyncDBEntry);
     279             : };
     280             : 
     281             : #endif // ctrlplane_ksync_entry_h

Generated by: LCOV version 1.14