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