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 5105 : KSyncEntry() { 74 5105 : Reset(); 75 5105 : }; 76 : // Use this constructor if automatic index allocation is needed 77 1096 : KSyncEntry(uint32_t index) { 78 1096 : Reset(index); 79 1096 : }; 80 6201 : virtual ~KSyncEntry() { assert(refcount_ == 0);}; 81 : 82 11201 : void Reset() { 83 11201 : index_ = kInvalidIndex; 84 11201 : state_ = INIT; 85 11201 : seen_ = false; 86 11201 : stale_ = false; 87 11201 : del_add_pending_ = false; 88 11201 : refcount_ = 0; 89 11201 : } 90 1096 : void Reset(uint32_t index) { 91 1096 : Reset(); 92 1096 : index_ = index; 93 1096 : } 94 : 95 : // Comparator for boost::set containing all KSyncEntries in an KSyncObject 96 11702 : bool operator<(const KSyncEntry &rhs) const { 97 11702 : 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 130 : 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 1037 : bool IsInSync() const { return (state_ == IN_SYNC); } 131 : 132 : // Returns true if the entry data is resolved 133 667 : virtual bool IsDataResolved() {return true;} 134 : 135 : // User define KSync Response handler 136 101 : virtual void Response() { }; 137 : 138 : // Allow State Compression for delete. 139 0 : virtual bool AllowDeleteStateComp() {return true;} 140 : 141 : // User defined error handler 142 : virtual void ErrorHandler(int err, uint32_t seqno, KSyncEvent event) const; 143 : 144 : // Error message for vrouter returned errors 145 : virtual std::string VrouterError(uint32_t error) const; 146 : static std::string VrouterErrorToString(uint32_t error); 147 : 148 : // Every ksync operation needs an rx-buffer to read response. The rx buffer 149 : // are pre-allocated to minimize compuation in ksync-tx-queue 150 : // pre-allocation is enabled only for flows for now 151 80 : virtual bool pre_alloc_rx_buffer() const { return false; } 152 : // ksync-tx supports multiple queues for KSync events. Get index of queue 153 : // to use 154 160 : virtual uint32_t GetTableIndex() const { return 0; } 155 : // On stale timer expiration, notify entry for same 156 3 : virtual void StaleTimerExpired() { } 157 : 158 892 : size_t GetIndex() const {return index_;}; 159 45169 : KSyncState GetState() const {return state_;}; 160 146 : bool del_add_pending() const {return del_add_pending_;} 161 3245 : uint32_t GetRefCount() const {return refcount_;} 162 492 : bool Seen() const {return seen_;} 163 20 : bool stale() const {return stale_;} 164 451 : void SetSeen() {seen_ = true;} 165 962 : bool IsDeleted() { return (state_ == DEL_ACK_WAIT || 166 480 : state_ == DEL_DEFER_DEL_ACK || 167 1442 : state_ == DEL_DEFER_SYNC || 168 962 : state_ == DEL_DEFER_REF); }; 169 : 170 : // return true if an entry is actively owned some module, 171 : // i.e., explicit Create was triggered for this entry and it 172 : // is not deleted yet by the Creator. 173 : // this entry however may still be still in unresolved state. 174 : bool IsActive() { return (state_ != TEMP && !IsDeleted()); } 175 : 176 22 : void set_del_add_pending(bool pending) {del_add_pending_ = pending;} 177 1526 : void RecordTransition(KSyncState from, KSyncState to, KSyncEvent event) { 178 1526 : t_history_.RecordTransition(from, to, event); 179 1526 : } 180 : 181 : protected: 182 : void SetIndex(size_t index) {index_ = index;}; 183 1551 : void SetState(KSyncState state) {state_ = state;}; 184 : private: 185 : friend void intrusive_ptr_add_ref(KSyncEntry *p); 186 : friend void intrusive_ptr_release(KSyncEntry *p); 187 : friend class KSyncSock; 188 : friend class KSyncObject; 189 : 190 : boost::intrusive::set_member_hook<> node_; 191 : 192 : size_t index_; 193 : KSyncState state_; 194 : std::atomic<int> refcount_; 195 : bool seen_; 196 : 197 : // Stale Entry flag indicates an entry as stale, which will be 198 : // removed once stale entry timer cleanup gets triggered. 199 : bool stale_; 200 : 201 : // flag to indicate a pending DelAdd operation on entry 202 : // this is set to true when Delete Add operation cannot go 203 : // through as entry is waiting of Ack for previous operation 204 : bool del_add_pending_; 205 : 206 : struct KSyncEntryTransition { 207 : KSyncState from_; 208 : KSyncState to_; 209 : KSyncEvent event_; 210 : }; 211 : class KSyncEntryTransHistory { 212 : public: 213 6201 : KSyncEntryTransHistory() { 214 6201 : idx_ = 0; 215 37206 : for (int i = 0; i < size_; i++) { 216 31005 : history_[i].event_ = INVALID; 217 : } 218 6201 : } 219 : 220 1526 : void RecordTransition(KSyncState from, KSyncState to, 221 : KSyncEvent event) { 222 1526 : history_[idx_].from_ = from; 223 1526 : history_[idx_].to_ = to; 224 1526 : history_[idx_].event_ = event; 225 1526 : idx_ = (idx_+1) % size_; 226 1526 : } 227 : private: 228 : static const int size_ = 5; 229 : int idx_; 230 : struct KSyncEntryTransition history_[size_]; 231 : }; 232 : KSyncEntryTransHistory t_history_; 233 : 234 : DISALLOW_COPY_AND_ASSIGN(KSyncEntry); 235 : }; 236 : 237 : // Implementation of KSyncEntry with with DBTable. Must be used along 238 : // with KSyncDBObject. 239 : // Registers with DBTable and drives state-machine based on DBTable 240 : // notifications 241 : // Applications are not needed to generate any events to the state-machine 242 : class KSyncDBEntry : public KSyncEntry, public DBState { 243 : public: 244 : typedef std::list<DBEntry *> DupEntryList; 245 : 246 53 : KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; }; 247 280 : KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; }; 248 333 : virtual ~KSyncDBEntry() { assert(dup_entry_list_.empty()); } 249 : 250 : // Check if object is in-sync with kernel. 251 : // Return true if object needs sync. Else return false 252 : virtual bool Sync(DBEntry *entry) = 0; 253 : 254 120 : void SetDBEntry(DBEntry *db_entry) { db_entry_ = db_entry; } 255 230 : DBEntry * GetDBEntry() { return db_entry_; } 256 : 257 : private: 258 : friend class KSyncDBObject; 259 : 260 : DBEntry *db_entry_; 261 : DupEntryList dup_entry_list_; 262 : DISALLOW_COPY_AND_ASSIGN(KSyncDBEntry); 263 : }; 264 : 265 : #endif // ctrlplane_ksync_entry_h