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