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