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 __AGENT_FLOWTABLE_KSYNC_H__ 7 : #define __AGENT_FLOWTABLE_KSYNC_H__ 8 : 9 : #include <boost/asio.hpp> 10 : #include <boost/bind/bind.hpp> 11 : 12 : #include <db/db_entry.h> 13 : #include <db/db_table.h> 14 : #include <db/db_table_partition.h> 15 : #include <ksync/ksync_index.h> 16 : #include <ksync/ksync_entry.h> 17 : #include <ksync/ksync_object.h> 18 : #include <ksync/ksync_netlink.h> 19 : #include <vrouter/ksync/agent_ksync_types.h> 20 : #include <vrouter/ksync/ksync_flow_memory.h> 21 : #include <pkt/flow_proto.h> 22 : #include <pkt/flow_table.h> 23 : #include <vr_types.h> 24 : #include <vr_flow.h> 25 : 26 : using namespace boost::placeholders; 27 : 28 : class FlowTableKSyncObject; 29 : class KSyncFlowIndexManager; 30 : 31 : struct FlowKSyncResponseInfo { 32 : int ksync_error_; 33 : uint32_t flow_handle_; 34 : uint8_t gen_id_; 35 : uint64_t evict_flow_bytes_; 36 : uint64_t evict_flow_packets_; 37 : int32_t evict_flow_oflow_; 38 : 39 20822 : void Reset() { 40 20822 : ksync_error_ = 0; 41 20822 : flow_handle_ = FlowEntry::kInvalidFlowHandle; 42 20822 : gen_id_ = 0; 43 20822 : evict_flow_bytes_ = 0; 44 20822 : evict_flow_packets_ = 0; 45 20822 : evict_flow_oflow_ = 0; 46 20822 : } 47 10148 : FlowKSyncResponseInfo() { 48 10148 : Reset(); 49 10148 : } 50 : }; 51 : 52 : class FlowTableKSyncEntry : public KSyncNetlinkEntry { 53 : public: 54 : FlowTableKSyncEntry(FlowTableKSyncObject *obj); 55 : FlowTableKSyncEntry(FlowTableKSyncObject *obj, FlowEntry *flow, 56 : uint32_t hash_id); 57 : virtual ~FlowTableKSyncEntry(); 58 : 59 : void Reset(); 60 : void Reset(FlowEntry *flow, uint32_t hash_id); 61 : 62 1045 : FlowEntryPtr flow_entry() const {return flow_entry_;} 63 1884 : uint32_t hash_id() const {return hash_id_;} 64 77 : void set_hash_id(uint32_t hash_id) { 65 77 : hash_id_ = hash_id; 66 77 : } 67 : int Encode(sandesh_op::type op, char *buf, int buf_len); 68 : KSyncObject *GetObject() const; 69 : 70 : std::string ToString() const; 71 : bool IsLess(const KSyncEntry &rhs) const; 72 : int AddMsg(char *buf, int buf_len); 73 : int ChangeMsg(char *buf, int buf_len); 74 : int DeleteMsg(char *buf, int buf_len); 75 : void SetPcapData(FlowEntryPtr fe, std::vector<int8_t> &data); 76 : // For flows allocate buffers in ksync-sock context 77 378 : virtual bool pre_alloc_rx_buffer() const { return true; } 78 : // KSync flow responses must be processed in multiple ksync response queues 79 : // to support scaling. Distribute the flows based on flow-table index 80 : virtual uint32_t GetTableIndex() const; 81 : virtual bool Sync(); 82 : virtual KSyncEntry *UnresolvedReference(); 83 230 : virtual bool ShouldReEvalBackReference() const { 84 : // no need to re-eval unresolved reference for flow entries, as they 85 : // do not depend on anything 86 230 : return false; 87 : } 88 0 : bool AllowDeleteStateComp() {return false;} 89 : virtual void ErrorHandler(int, uint32_t, KSyncEvent) const; 90 : virtual std::string VrouterError(uint32_t error) const; 91 64 : uint8_t gen_id() { return gen_id_; } 92 384 : void set_gen_id(uint8_t gen_id) { gen_id_ = gen_id; } 93 : uint8_t evict_gen_id() { return evict_gen_id_; } 94 744 : void set_evict_gen_id(uint8_t gen_id) { evict_gen_id_ = gen_id; } 95 153 : uint8_t vrouter_gen_id() { return vrouter_gen_id_; } 96 230 : uint32_t vrouter_hash_id() const { return vrouter_hash_id_; } 97 : FlowEvent::Event last_event() const { return last_event_; } 98 : void ReleaseToken(); 99 378 : void ResetKSyncResponseInfo() { 100 378 : ksync_response_info_.Reset(); 101 378 : } 102 230 : void SetKSyncResponseInfo(int ksync_error, uint32_t flow_handle, 103 : uint8_t gen_id, uint64_t evict_flow_bytes, 104 : uint64_t evict_flow_packets, 105 : int32_t evict_flow_oflow) { 106 230 : ksync_response_info_.ksync_error_ = ksync_error; 107 230 : ksync_response_info_.flow_handle_ = flow_handle; 108 230 : ksync_response_info_.gen_id_ = gen_id; 109 230 : ksync_response_info_.evict_flow_bytes_ = evict_flow_bytes; 110 230 : ksync_response_info_.evict_flow_packets_ = evict_flow_packets; 111 230 : ksync_response_info_.evict_flow_oflow_ = evict_flow_oflow; 112 230 : } 113 378 : const FlowKSyncResponseInfo *ksync_response_info() const { 114 378 : return &ksync_response_info_; 115 : } 116 : 117 0 : int ksync_response_error() const { 118 0 : return ksync_response_info_.ksync_error_; 119 : } 120 : 121 1 : uint32_t old_first_mirror_index() { 122 1 : return old_first_mirror_index_; 123 : } 124 148 : void set_transaction_id(uint32_t transaction_id) { 125 148 : transaction_id_ = transaction_id; 126 148 : } 127 378 : uint32_t get_transaction_id() const { return transaction_id_;}; 128 : 129 : private: 130 : friend class KSyncFlowEntryFreeList; 131 : friend class KSyncFlowIndexManager; 132 : 133 : FlowEntryPtr flow_entry_; 134 : uint8_t gen_id_; // contains the last propagated genid from flow module 135 : uint8_t evict_gen_id_; // contains current active gen-id in vrouter 136 : uint8_t vrouter_gen_id_; // Used to identify the last genid sent to vrouter 137 : 138 : // used to identify last flow index sent to vrouter 139 : // helps in knowing whether the vrouter response is index 140 : // allocation or not 141 : uint32_t vrouter_hash_id_; 142 : 143 : uint32_t hash_id_; 144 : uint32_t old_reverse_flow_id_; 145 : uint32_t old_action_; 146 : uint32_t old_component_nh_idx_; 147 : uint32_t old_first_mirror_index_; 148 : uint32_t old_second_mirror_index_; 149 : bool trap_flow_; 150 : uint16_t old_drop_reason_; 151 : bool ecmp_; 152 : bool enable_rpf_; 153 : uint32_t src_nh_id_; 154 : FlowEvent::Event last_event_; 155 : boost::shared_ptr<Token> token_; 156 : FlowKSyncResponseInfo ksync_response_info_; 157 : FlowTableKSyncObject *ksync_obj_; 158 : boost::intrusive::list_member_hook<> free_list_node_; 159 : uint32_t qos_config_idx; 160 : uint32_t transaction_id_; 161 : uint8_t underlay_gw_index; 162 : DISALLOW_COPY_AND_ASSIGN(FlowTableKSyncEntry); 163 : }; 164 : 165 : ///////////////////////////////////////////////////////////////////////////// 166 : // Class to manage free-list of flow ksync entries 167 : // Flow allocation can happen from multiple threads. In scaled scenarios 168 : // allocation of flow-entries in multi-thread environment adds overheads. 169 : // The KSyncFlowEntryFreeList helps to maintain a per task free-list. Alloc/Free 170 : // can happen without lock. 171 : // 172 : // Alloc and Free happens in a chunk. Alloc/Free are done based on thresholds 173 : // in task context of the corresponding flow-table 174 : ///////////////////////////////////////////////////////////////////////////// 175 : class KSyncFlowEntryFreeList { 176 : public: 177 : static const uint32_t kInitCount = (25 * 1000); 178 : static const uint32_t kTestInitCount = (5 * 1000); 179 : static const uint32_t kGrowSize = (1 * 1000); 180 : static const uint32_t kMinThreshold = (4 * 1000); 181 : static const uint32_t kMaxThreshold = (100 * 1000); 182 : 183 : typedef boost::intrusive::member_hook<FlowTableKSyncEntry, 184 : boost::intrusive::list_member_hook<>, 185 : &FlowTableKSyncEntry::free_list_node_> Node; 186 : typedef boost::intrusive::list<FlowTableKSyncEntry, Node> FreeList; 187 : 188 : KSyncFlowEntryFreeList(FlowTableKSyncObject *object); 189 : KSyncFlowEntryFreeList(FlowTableKSyncObject *object, FlowEntry *flow, 190 : uint32_t hash_id); 191 : virtual ~KSyncFlowEntryFreeList(); 192 : 193 : void Reset(); 194 : void Reset(FlowEntryPtr fe, uint32_t hash_id); 195 : 196 : FlowTableKSyncEntry *Allocate(const KSyncEntry *key); 197 : void Free(FlowTableKSyncEntry *flow); 198 : void Grow(); 199 5 : uint32_t max_count() const { return max_count_; } 200 : uint32_t free_count() const { return free_list_.size(); } 201 : uint32_t alloc_count() const { return (max_count_ - free_list_.size()); } 202 7 : uint32_t total_alloc() const { return total_alloc_; } 203 7 : uint32_t total_free() const { return total_free_; } 204 : 205 : private: 206 : FlowTableKSyncObject *object_; 207 : uint32_t max_count_; 208 : bool grow_pending_; 209 : uint64_t total_alloc_; 210 : uint64_t total_free_; 211 : FreeList free_list_; 212 : DISALLOW_COPY_AND_ASSIGN(KSyncFlowEntryFreeList); 213 : }; 214 : 215 : class FlowTableKSyncObject : public KSyncObject { 216 : public: 217 : // flow dependency timer on mirror entry in msec 218 : static const uint32_t kFlowDepSyncTimeout = 1000; 219 : static const uint32_t KFlowUnresolvedListYield = 32; 220 : FlowTableKSyncObject(KSync *ksync); 221 : FlowTableKSyncObject(KSync *ksync, int max_index); 222 : virtual ~FlowTableKSyncObject(); 223 : 224 : void Init(); 225 : void Shutdown() { } 226 : 227 : KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); 228 : void Free(KSyncEntry *key); 229 981 : bool DoEventTrace(void) { return false; } 230 : FlowTableKSyncEntry *Find(FlowEntry *key); 231 : 232 378 : vr_flow_req &flow_req() { return flow_req_; } 233 1065 : KSync *ksync() const { return ksync_; } 234 2 : void set_flow_table(FlowTable *table) { flow_table_ = table; } 235 756 : FlowTable *flow_table() const { return flow_table_; } 236 : void UpdateFlowHandle(FlowTableKSyncEntry *entry, uint32_t flow_handle); 237 : void UpdateKey(KSyncEntry *entry, uint32_t flow_handle); 238 : uint32_t GetKey(KSyncEntry *entry); 239 : 240 : void GrowFreeList(); 241 5 : KSyncFlowEntryFreeList *free_list() { return &free_list_; } 242 : 243 : void NetlinkAck(KSyncEntry *entry, KSyncEntry::KSyncEvent event); 244 : void GenerateKSyncEvent(FlowTableKSyncEntry *entry, 245 : KSyncEntry::KSyncEvent event); 246 : void StartTimer(); 247 : bool TimerExpiry(); 248 : void UpdateUnresolvedFlowEntry(FlowEntryPtr flowptr); 249 : private: 250 : friend class KSyncSandeshContext; 251 : friend class FlowTable; 252 : KSync *ksync_; 253 : FlowTable *flow_table_; 254 : vr_flow_req flow_req_; 255 : KSyncFlowEntryFreeList free_list_; 256 : std::list<FlowEntryPtr> unresolved_flow_list_; 257 : Timer * timer_; 258 : DISALLOW_COPY_AND_ASSIGN(FlowTableKSyncObject); 259 : }; 260 : 261 : #endif /* __AGENT_FLOWTABLE_KSYNC_H__ */