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
|