LCOV - code coverage report
Current view: top level - ksync - ksync_object.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 29 30 96.7 %
Date: 2026-11-09 02:10:49 Functions: 17 18 94.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #ifndef ctrlplane_ksync_object_h
       7             : #define ctrlplane_ksync_object_h
       8             : 
       9             : #include <mutex>
      10             : 
      11             : #include <base/queue_task.h>
      12             : #include <base/timer.h>
      13             : #include <sandesh/sandesh_trace.h>
      14             : 
      15             : #include "ksync_entry.h"
      16             : #include "ksync_index.h"
      17             : /////////////////////////////////////////////////////////////////////////////
      18             : // Back-Ref management needs two trees,
      19             : // Back-Ref tree:
      20             : // --------------
      21             : // An entry of type <key-entry, back-ref-entry> means that key-entry is
      22             : // waiting for back-ref-entry to be added to kernel.
      23             : // Note, there can be more than one key-entry waiting on a single
      24             : // back-ref-entry. However, a key-entry can be waiting on only one
      25             : // back-ref-entry at a time.
      26             : //
      27             : // This is a dynamic tree. Entries are added only when constraints are not
      28             : // met. Entries will not be in tree when constraints are met.
      29             : //
      30             : // Fwd-Ref tree:
      31             : // -------------
      32             : // Holds forward reference information. If Object-A is waiting on Object-B
      33             : // Fwd-Ref tree will have an entry with Object-A as key and Object-B as data.
      34             : /////////////////////////////////////////////////////////////////////////////
      35             : 
      36             : struct KSyncFwdReference {
      37       17564 :     KSyncFwdReference(KSyncEntry *key, KSyncEntry *ref) : key_(key),
      38        8782 :         reference_(ref) { };
      39             : 
      40       43838 :     bool operator<(const KSyncFwdReference &rhs) const {
      41       43838 :         return (key_ < rhs.key_);
      42             :     };
      43             : 
      44             :     boost::intrusive::set_member_hook<>     node_;
      45             :     KSyncEntry      *key_;
      46             :     KSyncEntry      *reference_;
      47             : };
      48             : 
      49             : struct KSyncBackReference {
      50       18428 :     KSyncBackReference(KSyncEntry *key, KSyncEntry *ref) :
      51       18428 :                        key_(key), back_reference_(ref) { };
      52             : 
      53       67685 :     bool operator<(const KSyncBackReference &rhs) const {
      54       67685 :         if (key_ < rhs.key_)
      55       23123 :             return true;
      56             : 
      57       44562 :         if (key_ > rhs.key_)
      58       21943 :             return false;
      59             : 
      60       22619 :         if (back_reference_ < rhs.back_reference_)
      61        9101 :             return true;
      62             : 
      63       13518 :         return false;
      64             :     };
      65             : 
      66             :     boost::intrusive::set_member_hook<>     node_;
      67             :     KSyncEntry      *key_;
      68             :     KSyncEntry      *back_reference_;
      69             : };
      70             : 
      71             : class KSyncObject {
      72             : public:
      73             :     typedef boost::intrusive::member_hook<KSyncEntry,
      74             :             boost::intrusive::set_member_hook<>,
      75             :             &KSyncEntry::node_> KSyncObjectNode;
      76             :     typedef boost::intrusive::set<KSyncEntry, KSyncObjectNode> Tree;
      77             : 
      78             :     typedef boost::intrusive::member_hook<KSyncFwdReference,
      79             :             boost::intrusive::set_member_hook<>,
      80             :             &KSyncFwdReference::node_> KSyncFwdRefNode;
      81             :     typedef boost::intrusive::set<KSyncFwdReference, KSyncFwdRefNode> FwdRefTree;
      82             : 
      83             :     typedef boost::intrusive::member_hook<KSyncBackReference,
      84             :             boost::intrusive::set_member_hook<>,
      85             :             &KSyncBackReference::node_> KSyncBackRefNode;
      86             :     typedef boost::intrusive::set<KSyncBackReference, KSyncBackRefNode> BackRefTree;
      87             : 
      88             :     // Default constructor. No index needed
      89             :     KSyncObject(const std::string &name);
      90             :     // Constructor for objects needing index
      91             :     KSyncObject(const std::string &name, int max_index);
      92             :     // Destructor
      93             :     virtual ~KSyncObject();
      94             : 
      95             :     // Initialise stale entry cleanup state machine.
      96             :     void InitStaleEntryCleanup(boost::asio::io_context &ios,
      97             :                                uint32_t cleanup_time, uint32_t cleanup_intvl,
      98             :                                uint16_t entries_per_intvl);
      99             : 
     100             :     // Notify an event to KSyncEvent state-machine
     101             :     void NotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
     102             :     // Call Notify event with mutex lock held
     103             :     void SafeNotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
     104             :     // Handle Netlink ACK message
     105             :     virtual void NetlinkAck(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
     106             :     // Add a back-reference entry
     107             :     void BackRefAdd(KSyncEntry *key, KSyncEntry *reference);
     108             :     // Delete a back-reference entry
     109             :     void BackRefDel(KSyncEntry *key);
     110             :     // Re-valuate the back-reference entries
     111             :     void BackRefReEval(KSyncEntry *key);
     112             : 
     113             :     // Create an entry
     114             :     KSyncEntry *Create(const KSyncEntry *key);
     115             :     KSyncEntry *Create(const KSyncEntry *key, bool skip_lookup);
     116             :     // Create a Stale entry, which needs to be cleanedup as part for
     117             :     // stale entry cleanup (timer).
     118             :     // Derived class can choose to create this entry to manage stale
     119             :     // states in Kernel
     120             :     KSyncEntry *CreateStale(const KSyncEntry *key);
     121             :     // Called on change to ksync_entry. Will resulting in sync of the entry
     122             :     void Change(KSyncEntry *entry);
     123             :     // Delete a KSyncEntry
     124             :     void Delete(KSyncEntry *entry);
     125             :     // Query function. Key is in entry
     126             :     KSyncEntry *Find(const KSyncEntry *key);
     127             :     // Get Next Function.
     128             :     KSyncEntry *Next(const KSyncEntry *entry) const;
     129             :     // Query KSyncEntry for key in entry. Create temporary entry if not present
     130             :     KSyncEntry *GetReference(const KSyncEntry *key);
     131             : 
     132             :     // Called from Create or GetReference to Allocate a KSyncEntry.
     133             :     // The KSyncEntry must be populated with fields in key and index
     134             :     virtual KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index) = 0;
     135             :     virtual void Free(KSyncEntry *entry);
     136             : 
     137             :     //Callback when all the entries in table are deleted
     138          64 :     virtual void EmptyTable(void) { };
     139         492 :     bool IsEmpty(void) { return tree_.empty(); };
     140             : 
     141       29453 :     virtual bool DoEventTrace(void) { return true; }
     142        5036 :     virtual void PreFree(KSyncEntry *entry) { }
     143             :     static void Shutdown();
     144             : 
     145         324 :     std::size_t Size() { return tree_.size(); }
     146           7 :     void set_delete_scheduled() { delete_scheduled_ = true;}
     147       18357 :     bool delete_scheduled() { return delete_scheduled_;}
     148       40698 :     virtual SandeshTraceBufferPtr GetKSyncTraceBuf() {return KSyncTraceBuf;}
     149             : 
     150             : protected:
     151             :     // Create an entry with default state. Used internally
     152             :     KSyncEntry *CreateImpl(const KSyncEntry *key);
     153             :     // Clear Stale Entry flag
     154             :     void ClearStale(KSyncEntry *entry);
     155             :     // Big lock on the tree
     156             :     // TODO: Make this more fine granular
     157             :     mutable std::recursive_mutex lock_;
     158             :     void ChangeKey(KSyncEntry *entry, uint32_t arg);
     159           0 :     virtual void UpdateKey(KSyncEntry *entry, uint32_t arg) { }
     160             : 
     161             :     // derived class needs to implement GetKey,
     162             :     // default impl will assert
     163             :     virtual uint32_t GetKey(KSyncEntry *entry);
     164             : 
     165             : private:
     166             :     friend class KSyncEntry;
     167             :     friend void TestTriggerStaleEntryCleanupCb(KSyncObject *obj);
     168             : 
     169             :     // Free indication of an KSyncElement.
     170             :     // Removes from tree and free index if allocated earlier
     171             :     void FreeInd(KSyncEntry *entry, uint32_t index);
     172             :     void NetlinkAckInternal(KSyncEntry *entry, KSyncEntry::KSyncEvent event);
     173             : 
     174       25686 :     bool IsIndexValid() const { return need_index_; }
     175             : 
     176             :     // timer Callback to trigger delete of stale entries.
     177             :     bool StaleEntryCleanupCb();
     178             : 
     179             :     //Callback to do cleanup when DEL ACK is received.
     180         733 :     virtual void CleanupOnDel(KSyncEntry *kentry) {}
     181             : 
     182             :     // Tree of all KSyncEntries
     183             :     Tree tree_;
     184             :     // Forward reference tree
     185             :     static FwdRefTree  fwd_ref_tree_;
     186             :     // Back reference tree
     187             :     static BackRefTree  back_ref_tree_;
     188             :     // Does the KSyncEntry need index?
     189             :     bool need_index_;
     190             :     // Index table for KSyncObject
     191             :     KSyncIndexTable index_table_;
     192             :     // scheduled for deletion
     193             :     bool delete_scheduled_;
     194             : 
     195             :     // stale entry tree
     196             :     std::set<KSyncEntry::KSyncEntryPtr> stale_entry_tree_;
     197             : 
     198             :     // Stale Entry Cleanup Timer
     199             :     Timer *stale_entry_cleanup_timer_;
     200             : 
     201             :     uint32_t stale_entry_cleanup_intvl_;
     202             :     uint16_t stale_entries_per_intvl_;
     203             :     SandeshTraceBufferPtr KSyncTraceBuf;
     204             : 
     205             :     DISALLOW_COPY_AND_ASSIGN(KSyncObject);
     206             : };
     207             : 
     208             : // Special KSyncObject for DB client
     209             : class KSyncDBObject : public KSyncObject {
     210             : public:
     211             :     // Response to DB Filter API using which derived class can choose to
     212             :     // ignore or trigger delete for some of the DB entries.
     213             :     // This can be used where we don't want to handle certain type of OPER
     214             :     // DB entries in KSync, using this simplifies the behaviour defination
     215             :     // for KSync Object.
     216             :     enum DBFilterResp {
     217             :         DBFilterAccept,  // Accept DB Entry Add/Change for processing
     218             :         DBFilterIgnore,  // Ignore DB Entry Add/Change
     219             :         DBFilterDelete,  // Ignore DB Entry Add/Change and clear previous state
     220             :         DBFilterDelAdd,  // Delete current ksync and add new one (key change)
     221             :         DBFilterMax
     222             :     };
     223             :     // Create KSyncObject. DB Table will be registered later
     224             :     KSyncDBObject(const std::string &name);
     225             :     KSyncDBObject(const std::string &name, int max_index);
     226             : 
     227             :     KSyncDBObject(const std::string &name, DBTableBase *table);
     228             :     // KSync DB Object with index allocation
     229             :     KSyncDBObject(const std::string &name,
     230             :                   DBTableBase *table,
     231             :                   int max_index);
     232             : 
     233             :     // Destructor
     234             :     virtual ~KSyncDBObject();
     235             : 
     236             :     // Register to a DB Table
     237             :     void RegisterDb(DBTableBase *table);
     238             : 
     239             :     //Unregister from a DB table
     240             :     void UnregisterDb(DBTableBase *table);
     241             : 
     242             :     // Callback registered to DB Table
     243             :     void Notify(DBTablePartBase *partition, DBEntryBase *entry);
     244             : 
     245         296 :     DBTableBase *GetDBTable() { return table_; }
     246             :     DBTableBase::ListenerId GetListenerId(DBTableBase *table);
     247             : 
     248             :     // Function to filter DB Entries to be used, default behaviour will accept
     249             :     // All DB Entries, needs to be overriden by derived class to get desired
     250             :     // behavior.
     251             :     virtual DBFilterResp DBEntryFilter(const DBEntry *entry,
     252             :                                        const KSyncDBEntry *ksync);
     253             :     // Populate Key in KSyncEntry from DB Entry.
     254             :     // Used for lookup of KSyncEntry from DBEntry
     255             :     virtual KSyncEntry *DBToKSyncEntry(const DBEntry *entry) = 0;
     256             :     void set_test_id(DBTableBase::ListenerId id);
     257         324 :     DBTableBase::ListenerId id() const {return id_;}
     258             : 
     259             : private:
     260             :     //Callback to do cleanup when DEL ACK is received.
     261             :     virtual void CleanupOnDel(KSyncEntry *kentry);
     262             : 
     263             :     DBTableBase *table_;
     264             :     DBTableBase::ListenerId id_;
     265             :     DBTableBase::ListenerId test_id_;
     266             : 
     267             :     KSyncIndexTable index_table_;
     268             :     DISALLOW_COPY_AND_ASSIGN(KSyncDBObject);
     269             : };
     270             : 
     271             : struct KSyncObjectEvent {
     272             :     enum Event {
     273             :         UNKNOWN,
     274             :         UNREGISTER,
     275             :         DEL,
     276             :     };
     277         304 :     KSyncObjectEvent(KSyncObject *obj, Event event) :
     278         304 :         obj_(obj), event_(event) {
     279         304 :     }
     280             :     KSyncEntry::KSyncEntryPtr ref_;
     281             :     KSyncObject *obj_;
     282             :     Event event_;
     283             : };
     284             : 
     285             : class KSyncObjectManager {
     286             : public:
     287             :     static const int kMaxEntriesProcess = 100;
     288             : 
     289             :     KSyncObjectManager();
     290             :     ~KSyncObjectManager();
     291             :     bool Process(KSyncObjectEvent *event);
     292             :     void Enqueue(KSyncObjectEvent *event);
     293             :     static KSyncEntry *default_defer_entry();
     294             :     static KSyncObjectManager *Init();
     295             :     static void Shutdown();
     296             :     static void Unregister(KSyncObject *);
     297             :     void Delete(KSyncObject *);
     298             :     static KSyncObjectManager *GetInstance();
     299             : private:
     300             :     WorkQueue<KSyncObjectEvent *> *event_queue_;
     301             :     static std::unique_ptr<KSyncEntry> default_defer_entry_;
     302             :     static KSyncObjectManager *singleton_;
     303             : };
     304             : 
     305             : #define KSYNC_TRACE(obj, parent, ...)\
     306             : do {\
     307             :    KSync##obj::TraceMsg(parent->GetKSyncTraceBuf(), __FILE__, __LINE__, ##__VA_ARGS__);\
     308             : } while (false)
     309             : 
     310             : #endif // ctrlplane_ksync_object_h

Generated by: LCOV version 1.14