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 180 : KSyncEntry() {
74 180 : Reset();
75 180 : };
76 : // Use this constructor if automatic index allocation is needed
77 818 : KSyncEntry(uint32_t index) {
78 818 : Reset(index);
79 818 : };
80 998 : virtual ~KSyncEntry() { assert(refcount_ == 0);};
81 :
82 998 : void Reset() {
83 998 : index_ = kInvalidIndex;
84 998 : state_ = INIT;
85 998 : seen_ = false;
86 998 : stale_ = false;
87 998 : del_add_pending_ = false;
88 998 : refcount_ = 0;
89 998 : }
90 818 : void Reset(uint32_t index) {
91 818 : Reset();
92 818 : index_ = index;
93 818 : }
94 :
95 : // Comparator for boost::set containing all KSyncEntries in an KSyncObject
96 10123 : bool operator<(const KSyncEntry &rhs) const {
97 10123 : 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 95 : 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 2231 : 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 0 : bool IsResolvedAndInSync() { return IsResolved() && IsInSync(); }
147 :
148 : // Returns true if the entry data is resolved
149 539 : virtual bool IsDataResolved() {return true;}
150 :
151 : // User define KSync Response handler
152 74 : 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 0 : 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 146 : virtual uint32_t GetTableIndex() const { return 0; }
171 : // On stale timer expiration, notify entry for same
172 3 : virtual void StaleTimerExpired() { }
173 :
174 830 : size_t GetIndex() const {return index_;};
175 50635 : KSyncState GetState() const {return state_;};
176 67 : bool del_add_pending() const {return del_add_pending_;}
177 2906 : uint32_t GetRefCount() const {return refcount_;}
178 452 : bool Seen() const {return seen_;}
179 16 : bool stale() const {return stale_;}
180 413 : void SetSeen() {seen_ = true;}
181 734 : bool IsDeleted() { return (state_ == DEL_ACK_WAIT ||
182 366 : state_ == DEL_DEFER_DEL_ACK ||
183 1100 : state_ == DEL_DEFER_SYNC ||
184 734 : 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 21 : void set_del_add_pending(bool pending) {del_add_pending_ = pending;}
193 1320 : void RecordTransition(KSyncState from, KSyncState to, KSyncEvent event) {
194 1320 : t_history_.RecordTransition(from, to, event);
195 1320 : }
196 :
197 : protected:
198 : void SetIndex(size_t index) {index_ = index;};
199 1341 : 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 998 : KSyncEntryTransHistory() {
230 998 : idx_ = 0;
231 5988 : for (int i = 0; i < size_; i++) {
232 4990 : history_[i].event_ = INVALID;
233 : }
234 998 : }
235 :
236 1320 : void RecordTransition(KSyncState from, KSyncState to,
237 : KSyncEvent event) {
238 1320 : history_[idx_].from_ = from;
239 1320 : history_[idx_].to_ = to;
240 1320 : history_[idx_].event_ = event;
241 1320 : idx_ = (idx_+1) % size_;
242 1320 : }
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 91 : KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; };
263 0 : KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; };
264 91 : 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 42 : void SetDBEntry(DBEntry *db_entry) { db_entry_ = db_entry; }
271 77 : 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
|