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_entry_h 7 : #define ctrlplane_ksync_entry_h 8 : 9 : #include <boost/intrusive_ptr.hpp> 10 : #include <boost/intrusive/set.hpp> 11 : #include <atomic> 12 : #include <sandesh/common/vns_constants.h> 13 : #include <sandesh/common/vns_types.h> 14 : #include <sandesh/sandesh_trace.h> 15 : #include <db/db_entry.h> 16 : 17 : #define KSYNC_ERROR(obj, ...)\ 18 : do {\ 19 : if (LoggingDisabled()) break;\ 20 : obj::Send(g_vns_constants.CategoryNames.find(Category::VROUTER)->second,\ 21 : SandeshLevel::SYS_DEBUG, __FILE__, __LINE__, ##__VA_ARGS__);\ 22 : } while (false) 23 : 24 : extern SandeshTraceBufferPtr KSyncErrorTraceBuf; 25 : #define KSYNC_ERROR_TRACE(obj, ...) \ 26 : do { \ 27 : KSyncError##obj::TraceMsg(KSyncErrorTraceBuf, \ 28 : __FILE__, __LINE__, __VA_ARGS__); \ 29 : } while (false) 30 : 31 : class KSyncObject; 32 : class KSyncDBObject; 33 : 34 : class KSyncEntry { 35 : public: 36 : enum KSyncState { 37 : INIT, // Init state. Not notified 38 : TEMP, // Temporary entry created on reference 39 : ADD_DEFER, // Add of entry deferred due to unmet dependencies 40 : CHANGE_DEFER, // Change of entry deferred due to unmet dependencies 41 : IN_SYNC, // Object in sync 42 : SYNC_WAIT, // Waiting on ACK for add/change 43 : NEED_SYNC, // Object changed. Needs Sync 44 : DEL_DEFER_SYNC, // Del pending to be sent due to sync_wait 45 : DEL_DEFER_REF, // Del pending to be sent due to ref-count 46 : DEL_DEFER_DEL_ACK, // Del pending to be sent due to Del Ack wait 47 : DEL_ACK_WAIT, // Del request sent waiting for ack 48 : RENEW_WAIT, // Object renewal waiting for delete-ack 49 : FREE_WAIT // Entry to be freed 50 : }; 51 : 52 : enum KSyncEvent { 53 : ADD_CHANGE_REQ, 54 : ADD_ACK, 55 : CHANGE_ACK, 56 : DEL_REQ, 57 : DEL_ADD_REQ, 58 : DEL_ACK, 59 : RE_EVAL, 60 : INT_PTR_REL, 61 : INVALID 62 : }; 63 : 64 : std::string StateString() const; 65 : std::string AckOperationString(KSyncEvent ack_event) const; 66 : std::string EventString(KSyncEvent event) const; 67 : // All referring KSyncEntries must use KSyncEntryPtr. The ref-count 68 : // maintained is optionally used to defer DELETE till refcount is 0 69 : typedef boost::intrusive_ptr<KSyncEntry> KSyncEntryPtr; 70 : static const size_t kInvalidIndex = 0xFFFFFFFF; 71 : static const int kDefaultMsgSize = 512; 72 : 73 : // Use this constructor if automatic index allocation is *not* needed 74 10328 : KSyncEntry() { 75 10328 : Reset(); 76 10328 : }; 77 : // Use this constructor if automatic index allocation is needed 78 38003 : KSyncEntry(uint32_t index) { 79 38003 : Reset(index); 80 38003 : }; 81 48331 : virtual ~KSyncEntry() { assert(refcount_ == 0);}; 82 : 83 58627 : void Reset() { 84 58627 : index_ = kInvalidIndex; 85 58627 : state_ = INIT; 86 58627 : seen_ = false; 87 58627 : stale_ = false; 88 58627 : del_add_pending_ = false; 89 58627 : refcount_ = 0; 90 58627 : } 91 38003 : void Reset(uint32_t index) { 92 38003 : Reset(); 93 38003 : index_ = index; 94 38003 : } 95 : 96 : // Comparator for boost::set containing all KSyncEntries in an KSyncObject 97 446768 : bool operator<(const KSyncEntry &rhs) const { 98 446768 : return IsLess(rhs); 99 : }; 100 : // Comparator to manage the tree 101 : virtual bool IsLess(const KSyncEntry &rhs) const = 0; 102 : 103 : // Convert KSync to String 104 : virtual std::string ToString() const = 0; 105 : 106 : // Create handler. 107 : // Return true if operation is complete 108 : // Return false if operation asynchronously 109 : virtual bool Add() = 0; 110 : 111 : // Change handler. 112 : // Return true if operation is complete 113 : // Return false if operation asynchronously 114 : virtual bool Change() = 0; 115 : 116 : // Delete handler. 117 : // Return true if operation is complete 118 : // Return false if operation asynchronously 119 : virtual bool Delete() = 0; 120 : 121 : // KSyncObject for this entry. Used to release the index 122 : virtual KSyncObject *GetObject() const = 0; 123 : // Get an unresolved reference. 124 : // This entry will be added into resolveq_ of unresolved-entry 125 : virtual KSyncEntry *UnresolvedReference() = 0; 126 9683 : virtual bool ShouldReEvalBackReference() const { return true; } 127 : 128 : // Returns true if entry is resolved and referring entry can be written 129 : bool IsResolved(); 130 : 131 11624 : bool IsInSync() const { return (state_ == IN_SYNC); } 132 : 133 : /// @brief True only when the entry is resolved AND kernel-acknowledged (IN_SYNC). 134 : /// 135 : /// @details 136 : /// Dependencies that are programmed into vrouter must be gated on this 137 : /// condition instead of IsResolved() alone. An entry that is merely sent 138 : /// (SYNC_WAIT/NEED_SYNC) is not yet applied by the datapath, and a 139 : /// dependent sent against it races it in vrouter (EINVAL/ENOENT, the error 140 : /// ack is swallowed and the dependent is silently stuck out of vrouter). 141 : /// 142 : /// @return true if entry is resolved and kernel-acknowledged (IN_SYNC) 143 : /// @warning Entries in SYNC_WAIT or NEED_SYNC states may cause race conditions 144 : /// 145 : /// @see IsResolved() 146 : 147 10773 : bool IsResolvedAndInSync() { return IsResolved() && IsInSync(); } 148 : 149 : // Returns true if the entry data is resolved 150 25723 : virtual bool IsDataResolved() {return true;} 151 : 152 : // User define KSync Response handler 153 11323 : virtual void Response() { }; 154 : 155 : // Allow State Compression for delete. 156 0 : virtual bool AllowDeleteStateComp() {return true;} 157 : 158 : // User defined error handler 159 : virtual void ErrorHandler(int err, uint32_t seqno, KSyncEvent event) const; 160 : 161 : // Error message for vrouter returned errors 162 : virtual std::string VrouterError(uint32_t error) const; 163 : static std::string VrouterErrorToString(uint32_t error); 164 : 165 : // Every ksync operation needs an rx-buffer to read response. The rx buffer 166 : // are pre-allocated to minimize compuation in ksync-tx-queue 167 : // pre-allocation is enabled only for flows for now 168 10871 : virtual bool pre_alloc_rx_buffer() const { return false; } 169 : // ksync-tx supports multiple queues for KSync events. Get index of queue 170 : // to use 171 21888 : virtual uint32_t GetTableIndex() const { return 0; } 172 : // On stale timer expiration, notify entry for same 173 3 : virtual void StaleTimerExpired() { } 174 : 175 12198 : size_t GetIndex() const {return index_;}; 176 108587 : KSyncState GetState() const {return state_;}; 177 11314 : bool del_add_pending() const {return del_add_pending_;} 178 49248 : uint32_t GetRefCount() const {return refcount_;} 179 8244 : bool Seen() const {return seen_;} 180 379 : bool stale() const {return stale_;} 181 4983 : void SetSeen() {seen_ = true;} 182 28794 : bool IsDeleted() { return (state_ == DEL_ACK_WAIT || 183 14396 : state_ == DEL_DEFER_DEL_ACK || 184 43190 : state_ == DEL_DEFER_SYNC || 185 28794 : state_ == DEL_DEFER_REF); }; 186 : 187 : // return true if an entry is actively owned some module, 188 : // i.e., explicit Create was triggered for this entry and it 189 : // is not deleted yet by the Creator. 190 : // this entry however may still be still in unresolved state. 191 : bool IsActive() { return (state_ != TEMP && !IsDeleted()); } 192 : 193 23 : void set_del_add_pending(bool pending) {del_add_pending_ = pending;} 194 30286 : void RecordTransition(KSyncState from, KSyncState to, KSyncEvent event) { 195 30286 : t_history_.RecordTransition(from, to, event); 196 30285 : } 197 : 198 : protected: 199 : void SetIndex(size_t index) {index_ = index;}; 200 30672 : void SetState(KSyncState state) {state_ = state;}; 201 : private: 202 : friend void intrusive_ptr_add_ref(KSyncEntry *p); 203 : friend void intrusive_ptr_release(KSyncEntry *p); 204 : friend class KSyncSock; 205 : friend class KSyncObject; 206 : 207 : boost::intrusive::set_member_hook<> node_; 208 : 209 : size_t index_; 210 : KSyncState state_; 211 : std::atomic<int> refcount_; 212 : bool seen_; 213 : 214 : // Stale Entry flag indicates an entry as stale, which will be 215 : // removed once stale entry timer cleanup gets triggered. 216 : bool stale_; 217 : 218 : // flag to indicate a pending DelAdd operation on entry 219 : // this is set to true when Delete Add operation cannot go 220 : // through as entry is waiting of Ack for previous operation 221 : bool del_add_pending_; 222 : 223 : struct KSyncEntryTransition { 224 : KSyncState from_; 225 : KSyncState to_; 226 : KSyncEvent event_; 227 : }; 228 : class KSyncEntryTransHistory { 229 : public: 230 48331 : KSyncEntryTransHistory() { 231 48331 : idx_ = 0; 232 289986 : for (int i = 0; i < size_; i++) { 233 241655 : history_[i].event_ = INVALID; 234 : } 235 48331 : } 236 : 237 30286 : void RecordTransition(KSyncState from, KSyncState to, 238 : KSyncEvent event) { 239 30286 : history_[idx_].from_ = from; 240 30286 : history_[idx_].to_ = to; 241 30286 : history_[idx_].event_ = event; 242 30286 : idx_ = (idx_+1) % size_; 243 30286 : } 244 : private: 245 : static const int size_ = 5; 246 : int idx_; 247 : struct KSyncEntryTransition history_[size_]; 248 : }; 249 : KSyncEntryTransHistory t_history_; 250 : 251 : DISALLOW_COPY_AND_ASSIGN(KSyncEntry); 252 : }; 253 : 254 : // Implementation of KSyncEntry with with DBTable. Must be used along 255 : // with KSyncDBObject. 256 : // Registers with DBTable and drives state-machine based on DBTable 257 : // notifications 258 : // Applications are not needed to generate any events to the state-machine 259 : class KSyncDBEntry : public KSyncEntry, public DBState { 260 : public: 261 : typedef std::list<DBEntry *> DupEntryList; 262 : 263 91 : KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; }; 264 37185 : KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; }; 265 37276 : virtual ~KSyncDBEntry() { assert(dup_entry_list_.empty()); } 266 : 267 : // Check if object is in-sync with kernel. 268 : // Return true if object needs sync. Else return false 269 : virtual bool Sync(DBEntry *entry) = 0; 270 : 271 8886 : void SetDBEntry(DBEntry *db_entry) { db_entry_ = db_entry; } 272 18386 : DBEntry * GetDBEntry() { return db_entry_; } 273 : 274 : private: 275 : friend class KSyncDBObject; 276 : 277 : DBEntry *db_entry_; 278 : DupEntryList dup_entry_list_; 279 : DISALLOW_COPY_AND_ASSIGN(KSyncDBEntry); 280 : }; 281 : 282 : #endif // ctrlplane_ksync_entry_h