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_FLOW_TABLE_H__
7 : #define __AGENT_FLOW_TABLE_H__
8 :
9 : #include <map>
10 : #include <mutex>
11 :
12 : #if defined(__GNUC__)
13 : #include "base/compiler.h"
14 : #if __GNUC_PREREQ(4, 5)
15 : #pragma GCC diagnostic push
16 : #pragma GCC diagnostic ignored "-Wunused-result"
17 : #endif
18 : #endif
19 : #include <boost/uuid/random_generator.hpp>
20 : #if defined(__GNUC__)
21 : #if __GNUC_PREREQ(4, 6)
22 : #pragma GCC diagnostic pop
23 : #endif
24 : #endif
25 :
26 : #include <boost/uuid/uuid_io.hpp>
27 : #include <boost/intrusive_ptr.hpp>
28 : #include <base/util.h>
29 : #include <base/address.h>
30 : #include <db/db_table_walker.h>
31 : #include <cmn/agent_cmn.h>
32 : #include <oper/mirror_table.h>
33 : #include <filter/traffic_action.h>
34 : #include <filter/acl_entry.h>
35 : #include <filter/acl.h>
36 : #include <pkt/pkt_types.h>
37 : #include <pkt/pkt_handler.h>
38 : #include <pkt/pkt_init.h>
39 : #include <pkt/pkt_flow_info.h>
40 : #include <pkt/flow_entry.h>
41 : #include <sandesh/sandesh_trace.h>
42 : #include <oper/vn.h>
43 : #include <oper/vm.h>
44 : #include <oper/interface_common.h>
45 : #include <oper/nexthop.h>
46 : #include <oper/route_common.h>
47 : #include <oper/sg.h>
48 : #include <oper/vrf.h>
49 : #include <filter/acl.h>
50 : #include <sandesh/common/flow_types.h>
51 :
52 : class FlowStatsCollector;
53 : class PktSandeshFlow;
54 : class FetchFlowRecord;
55 : class FlowEntry;
56 : class FlowTable;
57 : class FlowTableKSyncEntry;
58 : class FlowTableKSyncObject;
59 : class FlowEvent;
60 : class FlowEventKSync;
61 :
62 : #define FLOW_LOCK(flow, rflow, flow_event) \
63 : bool is_flow_rflow_key_same = false; \
64 : if (flow == rflow) { \
65 : if (flow_event == FlowEvent::DELETE_FLOW) { \
66 : assert(0); \
67 : } \
68 : is_flow_rflow_key_same = true; \
69 : rflow = NULL; \
70 : } \
71 : std::unique_lock<std::mutex> lock1, lock2; \
72 : if (flow && rflow) { \
73 : auto l1 = std::unique_lock<std::mutex>(flow->mutex(), std::defer_lock); \
74 : lock1.swap(l1); \
75 : auto l2 = std::unique_lock<std::mutex>(rflow->mutex(), std::defer_lock); \
76 : lock2.swap(l2); \
77 : std::lock(lock1, lock2); \
78 : } else if (flow) { \
79 : auto l1 = std::unique_lock<std::mutex>(flow->mutex(), std::defer_lock); \
80 : lock1.swap(l1); \
81 : lock1.lock(); \
82 : } else if (rflow) { \
83 : auto l2 = std::unique_lock<std::mutex>(rflow->mutex(), std::defer_lock); \
84 : lock2.swap(l2); \
85 : lock2.lock(); \
86 : } \
87 : if (is_flow_rflow_key_same) { \
88 : flow->MakeShortFlow(FlowEntry::SHORT_SAME_FLOW_RFLOW_KEY); \
89 : }
90 :
91 : /////////////////////////////////////////////////////////////////////////////
92 : // Class to manage free-list of flow-entries
93 : // Flow allocation can happen from multiple threads. In scaled scenarios
94 : // allocation of flow-entries in multi-thread environment adds overheads.
95 : // The FlowEntryFreeList helps to maintain a per task free-list. Alloc/Free
96 : // can happen withou lock.
97 : //
98 : // Alloc and Free happens in a chunk. Alloc/Free are done based on thresholds
99 : // in task context of the corresponding flow-table
100 : /////////////////////////////////////////////////////////////////////////////
101 : class FlowEntryFreeList {
102 : public:
103 : static const uint32_t kInitCount = (25 * 1000);
104 : static const uint32_t kTestInitCount = (5 * 1000);
105 : static const uint32_t kGrowSize = (1 * 1000);
106 : static const uint32_t kMinThreshold = (4 * 1000);
107 : static const uint32_t kMaxThreshold = (100 * 1000);
108 :
109 : typedef boost::intrusive::member_hook<FlowEntry,
110 : boost::intrusive::list_member_hook<>,
111 : &FlowEntry::free_list_node_> Node;
112 : typedef boost::intrusive::list<FlowEntry, Node> FreeList;
113 :
114 : FlowEntryFreeList(FlowTable *table);
115 : virtual ~FlowEntryFreeList();
116 :
117 : FlowEntry *Allocate(const FlowKey &key);
118 : void Free(FlowEntry *flow);
119 : void Grow();
120 15 : uint32_t max_count() const { return max_count_; }
121 0 : uint32_t free_count() const { return free_list_.size(); }
122 : uint32_t alloc_count() const { return (max_count_ - free_list_.size()); }
123 0 : uint32_t total_alloc() const { return total_alloc_; }
124 0 : uint32_t total_free() const { return total_free_; }
125 : private:
126 : FlowTable *table_;
127 : uint32_t max_count_;
128 : bool grow_pending_;
129 : uint64_t total_alloc_;
130 : uint64_t total_free_;
131 : FreeList free_list_;
132 : DISALLOW_COPY_AND_ASSIGN(FlowEntryFreeList);
133 : };
134 :
135 : /////////////////////////////////////////////////////////////////////////////
136 : // Flow addition is a two step process.
137 : // - FlowHandler :
138 : // Flow is created in this context (file pkt_flow_info.cc).
139 : // There can potentially be multiple FlowHandler task running in parallel
140 : // - FlowTable :
141 : // This module will maintain a tree of all flows created. It is also
142 : // responsible to generate KSync events. It is run in a single task context
143 : //
144 : // Functionality of FlowTable:
145 : // 1. Manage flow_entry_map_ which contains all flows
146 : // 2. Enforce the per-VM flow limits
147 : // 3. Generate events to KSync and FlowMgmt modueles
148 : /////////////////////////////////////////////////////////////////////////////
149 : struct FlowTaskMsg : public InterTaskMsg {
150 37 : FlowTaskMsg(FlowEntry * fe) : InterTaskMsg(0), fe_ptr(fe) { }
151 74 : virtual ~FlowTaskMsg() { }
152 :
153 : FlowEntryPtr fe_ptr;
154 : };
155 :
156 : struct Inet4FlowKeyCmp {
157 6542 : bool operator()(const FlowKey &lhs, const FlowKey &rhs) const {
158 6542 : const FlowKey &lhs_base = static_cast<const FlowKey &>(lhs);
159 6542 : return lhs_base.IsLess(rhs);
160 : }
161 : };
162 :
163 : class FlowTable {
164 : public:
165 : static const uint32_t kPortNatFlowTableInstance = 0;
166 : static const uint32_t kInvalidFlowTableInstance = 0xFF;
167 :
168 : typedef std::map<FlowKey, FlowEntry *, Inet4FlowKeyCmp> FlowEntryMap;
169 : typedef std::pair<FlowKey, FlowEntry *> FlowEntryMapPair;
170 : typedef boost::function<bool(FlowEntry *flow)> FlowEntryCb;
171 : typedef std::vector<FlowEntryPtr> FlowIndexTree;
172 :
173 : struct LinkLocalFlowInfo {
174 : uint32_t flow_index;
175 : FlowKey flow_key;
176 : uint64_t timestamp;
177 :
178 0 : LinkLocalFlowInfo(uint32_t index, const FlowKey &key, uint64_t t) :
179 0 : flow_index(index), flow_key(key), timestamp(t) {}
180 : };
181 : typedef std::map<int, LinkLocalFlowInfo> LinkLocalFlowInfoMap;
182 : typedef std::pair<int, LinkLocalFlowInfo> LinkLocalFlowInfoPair;
183 :
184 : FlowTable(Agent *agent, uint16_t table_index);
185 : virtual ~FlowTable();
186 :
187 : void Init();
188 : void InitDone();
189 : void Shutdown();
190 :
191 : // Accessor routines
192 2 : void set_ksync_object(FlowTableKSyncObject *obj) { ksync_object_ = obj; }
193 956 : FlowTableKSyncObject *ksync_object() const { return ksync_object_; }
194 :
195 : // Table managment routines
196 : FlowEntry *Locate(FlowEntry *flow, uint64_t t);
197 : FlowEntry *Find(const FlowKey &key);
198 : void Add(FlowEntry *flow, FlowEntry *rflow);
199 : void Update(FlowEntry *flow, FlowEntry *rflow);
200 : //bool Delete(const FlowKey &flow_key);
201 : bool Delete(const FlowKey &key, bool del_reverse_flow);
202 : void DeleteAll();
203 : // Test code only used method
204 : void DeleteFlow(const AclDBEntry *acl, const FlowKey &key,
205 : AclEntryIDList &id_list);
206 :
207 : // Accessor routines
208 3323 : Agent *agent() const { return agent_; }
209 2203 : uint16_t table_index() const { return table_index_; }
210 69 : size_t Size() { return flow_entry_map_.size(); }
211 0 : FlowTable::FlowEntryMap::iterator begin() {
212 0 : return flow_entry_map_.begin();
213 : }
214 0 : FlowTable::FlowEntryMap::iterator end() {
215 0 : return flow_entry_map_.end();
216 : }
217 :
218 0 : const LinkLocalFlowInfoMap &linklocal_flow_info_map() {
219 0 : return linklocal_flow_info_map_;
220 : }
221 : void AddLinkLocalFlowInfo(int fd, uint32_t index, const FlowKey &key,
222 : const uint64_t timestamp);
223 : void DelLinkLocalFlowInfo(int fd);
224 :
225 : static const char *TaskName() { return kTaskFlowEvent; }
226 : // Sandesh routines
227 : void Copy(FlowEntry *lhs, FlowEntry *rhs, bool update);
228 : void SetAclFlowSandeshData(const AclDBEntry *acl, AclFlowResp &data,
229 : const int last_count);
230 : void SetAceSandeshData(const AclDBEntry *acl, AclFlowCountResp &data,
231 : int ace_id);
232 :
233 : void RecomputeFlow(FlowEntry *flow);
234 : void DeleteMessage(FlowEntry *flow);
235 :
236 : void DeleteVrf(VrfEntry *vrf);
237 :
238 : void HandleRevaluateDBEntry(const DBEntry *entry, FlowEntry *flow,
239 : bool active_flow, bool deleted_flow);
240 : void HandleKSyncError(FlowEntry *flow, FlowTableKSyncEntry *ksync_entry,
241 : int ksync_error, uint32_t flow_handle,
242 : uint32_t gen_id);
243 : boost::uuids::uuid rand_gen();
244 :
245 : void UpdateKSync(FlowEntry *flow, bool update);
246 : void DeleteKSync(FlowEntry *flow);
247 :
248 : // Free list
249 : void GrowFreeList();
250 448 : FlowEntryFreeList *free_list() { return &free_list_; }
251 :
252 : void ProcessKSyncFlowEvent(const FlowEventKSync *req, FlowEntry *flow);
253 : bool ProcessFlowEvent(const FlowEvent *req, FlowEntry *flow,
254 : FlowEntry *rflow);
255 : void PopulateFlowEntriesUsingKey(const FlowKey &key, bool reverse_flow,
256 : FlowEntry** flow, FlowEntry** rflow);
257 :
258 : // Concurrency check to ensure all flow-table and free-list manipulations
259 : // are done from FlowEvent task context only
260 : //exception: freelist free function can be accessed by flow logging task
261 : bool ConcurrencyCheck(int task_id, bool check_task_instance);
262 : bool ConcurrencyCheck(int task_id);
263 4484 : int flow_task_id() const { return flow_task_id_; }
264 : int flow_update_task_id() const { return flow_update_task_id_; }
265 0 : int flow_delete_task_id() const { return flow_delete_task_id_; }
266 410 : int flow_ksync_task_id() const { return flow_ksync_task_id_; }
267 0 : int flow_logging_task_id() const { return flow_logging_task_id_; }
268 : static void GetFlowSandeshActionParams(const FlowAction &action_info,
269 : std::string &action_str);
270 :
271 : friend class FlowStatsCollector;
272 : friend class PktSandeshFlow;
273 : friend class PktSandeshFlowStats;
274 : friend class FetchFlowRecord;
275 : friend class PktFlowInfo;
276 : friend void intrusive_ptr_release(FlowEntry *fe);
277 : private:
278 : void DisableKSyncSend(FlowEntry *flow, uint32_t evict_gen_id);
279 : bool IsEvictedFlow(const FlowKey &key);
280 :
281 : void DeleteFlowUveInfo(FlowEntry *fe);
282 :
283 : void DeleteInternal(FlowEntry *fe, uint64_t t, const RevFlowDepParams &p);
284 : void DeleteFlowInfo(FlowEntry *fe, const RevFlowDepParams ¶ms);
285 :
286 : void AddFlowInfo(FlowEntry *fe);
287 : void UpdateReverseFlow(FlowEntry *flow, FlowEntry *rflow);
288 :
289 : void UpdateUnLocked(FlowEntry *flow, FlowEntry *rflow);
290 : void AddInternal(FlowEntry *flow, FlowEntry *new_flow, FlowEntry *rflow,
291 : FlowEntry *new_rflow, bool fwd_flow_update,
292 : bool rev_flow_update);
293 : void Add(FlowEntry *flow, FlowEntry *new_flow, FlowEntry *rflow,
294 : FlowEntry *new_rflow, bool fwd_flow_update, bool rev_flow_update);
295 : void EvictFlow(FlowEntry *flow, FlowEntry *rflow, uint32_t evict_gen_id);
296 : bool DeleteFlows(FlowEntry *flow, FlowEntry *rflow);
297 : bool DeleteUnLocked(const FlowKey &key, bool del_reverse_flow);
298 : bool DeleteUnLocked(bool del_reverse_flow, FlowEntry *flow,
299 : FlowEntry *rflow);
300 : void ReleasePort(FlowEntry *flow, bool evict);
301 :
302 : Agent *agent_;
303 : boost::uuids::random_generator rand_gen_;
304 : uint16_t table_index_;
305 : FlowTableKSyncObject *ksync_object_;
306 : FlowEntryMap flow_entry_map_;
307 :
308 : FlowIndexTree flow_index_tree_;
309 : // maintain the linklocal flow info against allocated fd, debug purpose only
310 : LinkLocalFlowInfoMap linklocal_flow_info_map_;
311 : FlowEntryFreeList free_list_;
312 : std::mutex mutex_;
313 : int flow_task_id_;
314 : int flow_update_task_id_;
315 : int flow_delete_task_id_;
316 : int flow_ksync_task_id_;
317 : int flow_logging_task_id_;
318 : DISALLOW_COPY_AND_ASSIGN(FlowTable);
319 : };
320 :
321 : struct FlowEntryCmp {
322 : bool operator()(const FlowEntryPtr &l, const FlowEntryPtr &r) {
323 : FlowEntry *lhs = l.get();
324 : FlowEntry *rhs = r.get();
325 :
326 : return (lhs < rhs);
327 : }
328 : };
329 :
330 : typedef std::set<FlowEntryPtr, FlowEntryCmp> FlowEntryTree;
331 : extern SandeshTraceBufferPtr FlowTraceBuf;
332 : extern void SetActionStr(const FlowAction &, std::vector<ActionStr> &);
333 :
334 : #define FLOW_TRACE(obj, ...)\
335 : do {\
336 : Flow##obj::TraceMsg(FlowTraceBuf, __FILE__, __LINE__, ##__VA_ARGS__);\
337 : } while (false)
338 :
339 : #endif
|