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 252 : KSyncFwdReference(KSyncEntry *key, KSyncEntry *ref) : key_(key),
37 126 : reference_(ref) { };
38 :
39 263 : bool operator<(const KSyncFwdReference &rhs) const {
40 263 : 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 688 : KSyncBackReference(KSyncEntry *key, KSyncEntry *ref) :
50 688 : key_(key), back_reference_(ref) { };
51 :
52 363 : bool operator<(const KSyncBackReference &rhs) const {
53 363 : if (key_ < rhs.key_)
54 64 : return true;
55 :
56 299 : if (key_ > rhs.key_)
57 47 : return false;
58 :
59 252 : if (back_reference_ < rhs.back_reference_)
60 85 : return true;
61 :
62 167 : 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 12 : virtual void EmptyTable(void) { };
138 47 : bool IsEmpty(void) { return tree_.empty(); };
139 :
140 3054 : virtual bool DoEventTrace(void) { return true; }
141 812 : virtual void PreFree(KSyncEntry *entry) { }
142 : static void Shutdown();
143 :
144 32 : std::size_t Size() { return tree_.size(); }
145 5 : void set_delete_scheduled() { delete_scheduled_ = true;}
146 1398 : bool delete_scheduled() { return delete_scheduled_;}
147 3891 : 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 1743 : 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 32 : 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 36 : 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 37 : KSyncObjectEvent(KSyncObject *obj, Event event) :
277 37 : obj_(obj), event_(event) {
278 37 : }
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
|