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

Generated by: LCOV version 1.14