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 15149 : KSyncEntry() { 74 15149 : Reset(); 75 15149 : }; 76 : // Use this constructor if automatic index allocation is needed 77 3709 : KSyncEntry(uint32_t index) { 78 3709 : Reset(index); 79 3709 : }; 80 18858 : virtual ~KSyncEntry() { assert(refcount_ == 0);}; 81 : 82 33946 : void Reset() { 83 33946 : index_ = kInvalidIndex; 84 33946 : state_ = INIT; 85 33946 : seen_ = false; 86 33946 : stale_ = false; 87 33946 : del_add_pending_ = false; 88 33946 : refcount_ = 0; 89 33946 : } 90 3709 : void Reset(uint32_t index) { 91 3709 : Reset(); 92 3709 : index_ = index; 93 3709 : } 94 : 95 : // Comparator for boost::set containing all KSyncEntries in an KSyncObject 96 38465 : bool operator<(const KSyncEntry &rhs) const { 97 38465 : 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 883 : 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 2969 : 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 874 : bool IsResolvedAndInSync() { return IsResolved() && IsInSync(); } 147 : 148 : // Returns true if the entry data is resolved 149 2683 : virtual bool IsDataResolved() {return true;} 150 : 151 : // User define KSync Response handler 152 1111 : 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 946 : 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 1892 : virtual uint32_t GetTableIndex() const { return 0; } 171 : // On stale timer expiration, notify entry for same 172 3 : virtual void StaleTimerExpired() { } 173 : 174 1816 : size_t GetIndex() const {return index_;}; 175 55945 : KSyncState GetState() const {return state_;}; 176 1156 : bool del_add_pending() const {return del_add_pending_;} 177 7450 : uint32_t GetRefCount() const {return refcount_;} 178 1170 : bool Seen() const {return seen_;} 179 55 : bool stale() const {return stale_;} 180 879 : void SetSeen() {seen_ = true;} 181 3204 : bool IsDeleted() { return (state_ == DEL_ACK_WAIT || 182 1601 : state_ == DEL_DEFER_DEL_ACK || 183 4805 : state_ == DEL_DEFER_SYNC || 184 3204 : 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 22 : void set_del_add_pending(bool pending) {del_add_pending_ = pending;} 193 4129 : void RecordTransition(KSyncState from, KSyncState to, KSyncEvent event) { 194 4129 : t_history_.RecordTransition(from, to, event); 195 4129 : } 196 : 197 : protected: 198 : void SetIndex(size_t index) {index_ = index;}; 199 4189 : 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 18858 : KSyncEntryTransHistory() { 230 18858 : idx_ = 0; 231 113148 : for (int i = 0; i < size_; i++) { 232 94290 : history_[i].event_ = INVALID; 233 : } 234 18858 : } 235 : 236 4129 : void RecordTransition(KSyncState from, KSyncState to, 237 : KSyncEvent event) { 238 4129 : history_[idx_].from_ = from; 239 4129 : history_[idx_].to_ = to; 240 4129 : history_[idx_].event_ = event; 241 4129 : idx_ = (idx_+1) % size_; 242 4129 : } 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 53 : KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; }; 263 2893 : KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; }; 264 2946 : 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 888 : void SetDBEntry(DBEntry *db_entry) { db_entry_ = db_entry; } 271 1707 : 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