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 vnsw_agent_flow_stats_collector_h
7 : #define vnsw_agent_flow_stats_collector_h
8 :
9 : #include <atomic>
10 :
11 : #include <boost/static_assert.hpp>
12 : #include <pkt/flow_table.h>
13 : #include <cmn/agent_cmn.h>
14 : #include <cmn/index_vector.h>
15 : #include <uve/stats_collector.h>
16 : #include <uve/interface_uve_stats_table.h>
17 : #include <vrouter/ksync/flowtable_ksync.h>
18 : #include <sandesh/common/flow_types.h>
19 : #include <vrouter/flow_stats/flow_export_request.h>
20 : #include <vrouter/flow_stats/flow_export_info.h>
21 : #include <vrouter/flow_stats/flow_stats_manager.h>
22 :
23 : // Forward declaration
24 : class AgentUtXmlFlowThreshold;
25 : class AgentUtXmlFlowThresholdValidate;
26 : class FlowStatsRecordsReq;
27 : class FetchFlowStatsRecord;
28 : class FlowStatsManager;
29 :
30 : struct KFlowData {
31 : public:
32 : uint16_t underlay_src_port;
33 : uint16_t tcp_flags;
34 : uint16_t flags;
35 : };
36 :
37 : //Defines the functionality to periodically read flow stats from
38 : //shared memory (between agent and Kernel) and export this stats info to
39 : //collector. Also responsible for aging of flow entries. Runs in the context
40 : //of kTaskFlowStatsCollector which has exclusion with "db::DBTable",
41 : //
42 : // The algorithm for ageing flows,
43 : // - The complete flow-table will be scanned every 25% of ageing time
44 : // - An implication of this is, flow ageing will have accuracy of 25%
45 : // - Run timer every kFlowStatsTimerInterval msec (100 msec)
46 : // - Compute number of flow-entres to visit in kFlowStatsTimerInterval
47 : // - This is subject to constraing that complete flow table must be scanned
48 : // in 25% of ageing time
49 : // - On every timer expiry accumulate the number of entries to visit into
50 : // entries_to_visit_ variable
51 : // - Start a task (Flow AgeingTask) to scan the flow-entries
52 : // - On every run of task, visit upto kFlowsPerTask entries
53 : // If scan is not complete, continue the task
54 : // On completion of scan, stop the task
55 : //
56 : // On every visit of flow, check if flow is idle for configured ageing time and
57 : // delete the idle flows
58 : //
59 : // The flow_tree_ maintains flows sorted on flow pointer. This tree cannot be
60 : // used to scan flows for ageing since entries can be added/deleted between
61 : // ageing tasks. Alternatively, another list is maintained in the sequence
62 : // flows are added to flow ageing module.
63 : class FlowStatsCollector : public StatsCollector {
64 : public:
65 : // Default ageing time
66 : static const uint64_t FlowAgeTime = 1000000 * 180;
67 : // Default TCP ageing time
68 : static const uint64_t FlowTcpSynAgeTime = 1000000 * 180;
69 :
70 : // Time within which complete table must be scanned
71 : // Specified in terms of percentage of aging-time
72 : static const uint32_t kFlowScanTime = 25;
73 : // Flog ageing timer interval in milliseconds
74 : static const uint32_t kFlowStatsTimerInterval = 100;
75 : // Minimum flows to visit per interval
76 : static const uint32_t kMinFlowsPerTimer = 3000;
77 : // Number of flows to visit per task
78 : static const uint32_t kFlowsPerTask = 256;
79 :
80 : // Retry flow-delete after 5 second
81 : static const uint64_t kFlowDeleteRetryTime = (5 * 1000 * 1000);
82 :
83 : static const uint32_t kDefaultFlowSamplingThreshold = 500;
84 : static const uint8_t kMaxFlowMsgsPerSend = 16;
85 :
86 : typedef std::map<const FlowEntry*, FlowExportInfo> FlowEntryTree;
87 : typedef WorkQueue<boost::shared_ptr<FlowExportReq> > Queue;
88 :
89 : // Task in which the actual flow table scan happens. See description above
90 : class AgeingTask : public Task {
91 : public:
92 : AgeingTask(FlowStatsCollector *fsc);
93 : virtual ~AgeingTask();
94 : bool Run();
95 : std::string Description() const;
96 : private:
97 : FlowStatsCollector *fsc_;
98 : };
99 :
100 : FlowStatsCollector(boost::asio::io_context &io, int intvl,
101 : uint32_t flow_cache_timeout,
102 : AgentUveBase *uve, uint32_t instance_id,
103 : FlowAgingTableKey *key,
104 : FlowStatsManager *aging_module,
105 : FlowStatsCollectorObject *obj);
106 : virtual ~FlowStatsCollector();
107 :
108 0 : uint64_t flow_age_time_intvl() { return flow_age_time_intvl_; }
109 4 : void set_flow_age_time_intvl(uint64_t interval) {
110 4 : flow_age_time_intvl_ = interval;
111 4 : }
112 :
113 0 : uint32_t flow_age_time_intvl_in_secs() const {
114 0 : return flow_age_time_intvl_/(1000 * 1000);
115 : }
116 : uint64_t flow_tcp_syn_age_time() const {
117 : return flow_tcp_syn_age_time_;
118 : }
119 : void set_flow_tcp_syn_age_time(uint64_t interval) {
120 : flow_tcp_syn_age_time_ = interval;
121 : }
122 : boost::uuids::uuid rand_gen();
123 : bool Run();
124 : bool RunAgeingTask();
125 : uint32_t ProcessFlow(FlowExportInfoList::iterator &it,
126 : KSyncFlowMemory *ksync_obj,
127 : FlowExportInfo *info, uint64_t curr_time);
128 : bool AgeFlow(KSyncFlowMemory *ksync_obj, const vr_flow_entry *k_flow,
129 : const vr_flow_stats &k_stats, const KFlowData &kinfo,
130 : FlowExportInfo *info, uint64_t curr_time);
131 : bool EvictFlow(KSyncFlowMemory *ksync_obj, const vr_flow_entry *k_flow,
132 : uint16_t k_flow_flags, uint32_t flow_handle, uint16_t gen_id,
133 : FlowExportInfo *info, uint64_t curr_time);
134 : uint32_t RunAgeing(uint32_t max_count);
135 0 : void UpdateFlowAgeTime(uint64_t usecs) {
136 0 : flow_age_time_intvl_ = usecs;
137 0 : }
138 0 : void UpdateFlowAgeTimeInSecs(uint32_t secs) {
139 0 : UpdateFlowAgeTime(secs * 1000 * 1000);
140 0 : }
141 :
142 : void UpdateFloatingIpStats(const FlowExportInfo *flow, uint64_t bytes,
143 : uint64_t pkts);
144 : void UpdateStatsEvent(const FlowEntryPtr &flow, uint32_t bytes,
145 : uint32_t packets, uint32_t oflow_bytes,
146 : const boost::uuids::uuid &u);
147 : void Shutdown();
148 : void AddEvent(const FlowEntryPtr &flow);
149 : void DeleteEvent(const FlowEntryPtr &flow, const RevFlowDepParams ¶ms);
150 :
151 : bool FindFlowExportInfo(const FlowEntry *fe, FlowEntryTree::iterator &it);
152 : FlowExportInfo *FindFlowExportInfo(const FlowEntry *fe);
153 : const FlowExportInfo *FindFlowExportInfo(const FlowEntry *fe) const;
154 : static uint64_t GetFlowStats(const uint16_t &oflow_data, const uint32_t &data);
155 0 : size_t Size() const { return flow_tree_.size(); }
156 : size_t AgeTreeSize() const { return flow_export_info_list_.size(); }
157 : void NewFlow(FlowEntry *flow);
158 4 : void set_deleted(bool val) {
159 4 : deleted_ = val;
160 4 : }
161 0 : bool deleted() const {
162 0 : return deleted_;
163 : }
164 0 : const FlowAgingTableKey& flow_aging_key() const {
165 0 : return flow_aging_key_;
166 : }
167 0 : int task_id() const { return task_id_; }
168 0 : uint32_t instance_id() const { return instance_id_; }
169 0 : const Queue *queue() const { return &request_queue_; }
170 : friend class AgentUtXmlFlowThreshold;
171 : friend class AgentUtXmlFlowThresholdValidate;
172 : friend class FlowStatsRecordsReq;
173 : friend class FetchFlowStatsRecord;
174 : friend class FlowStatsManager;
175 : friend class FlowStatsCollectorObject;
176 :
177 : private:
178 : static uint64_t GetCurrentTime();
179 : uint32_t TimersPerScan();
180 : void UpdateEntriesToVisit();
181 : void EvictedFlowStatsUpdate(const FlowEntryPtr &flow, uint32_t bytes,
182 : uint32_t packets, uint32_t oflow_bytes,
183 : const boost::uuids::uuid &u);
184 : void UpdateFlowStats(FlowExportInfo *info, uint64_t teardown_time);
185 : void UpdateFlowStatsInternalLocked(FlowExportInfo *info,
186 : uint32_t bytes,
187 : uint16_t oflow_bytes,
188 : uint32_t pkts,
189 : uint16_t oflow_pkts,
190 : uint64_t time,
191 : bool teardown_time);
192 : void UpdateFlowStatsInternal(FlowExportInfo *info,
193 : uint32_t bytes,
194 : uint16_t oflow_bytes,
195 : uint32_t pkts,
196 : uint16_t oflow_pkts,
197 : uint64_t time,
198 : bool teardown_time);
199 : void FlowDeleteEnqueue(FlowExportInfo *info, uint64_t t);
200 : void FlowEvictEnqueue(FlowExportInfo *info, uint64_t t,
201 : uint32_t flow_handle, uint16_t gen_id);
202 : void UpdateThreshold(uint32_t new_value);
203 :
204 : void UpdateInterVnStats(FlowExportInfo *info,
205 : uint64_t bytes, uint64_t pkts);
206 : void UpdateVmiTagBasedStats(FlowExportInfo *info,
207 : uint64_t bytes, uint64_t pkts);
208 : bool ShouldBeAged(FlowExportInfo *info, const vr_flow_entry *k_flow,
209 : const vr_flow_stats &k_stats, uint64_t curr_time);
210 : uint64_t GetUpdatedFlowPackets(const FlowExportInfo *stats,
211 : uint64_t k_flow_pkts);
212 : uint64_t GetUpdatedFlowBytes(const FlowExportInfo *stats,
213 : uint64_t k_flow_bytes);
214 : InterfaceUveTable::FloatingIp *ReverseFlowFipEntry
215 : (const FlowExportInfo *flow);
216 : uint32_t ReverseFlowFip(const FlowExportInfo *info);
217 : VmInterfaceKey ReverseFlowFipVmi(const FlowExportInfo *info);
218 : bool RequestHandler(boost::shared_ptr<FlowExportReq> req);
219 : bool RequestHandlerEntry();
220 : void RequestHandlerExit(bool done);
221 : void AddFlow(FlowExportInfo info);
222 : void DeleteFlow(FlowEntryTree::iterator &it);
223 : void UpdateFlowIterationKey(const FlowEntry *del_flow,
224 : FlowEntryTree::iterator &tree_it);
225 : void HandleFlowStatsUpdate(const FlowKey &key, uint32_t bytes,
226 : uint32_t packets, uint32_t oflow_bytes);
227 :
228 : AgentUveBase *agent_uve_;
229 : int task_id_;
230 : boost::uuids::random_generator rand_gen_;
231 : const FlowEntry* flow_iteration_key_;
232 : uint64_t flow_age_time_intvl_;
233 : // Number of entries pending to be visited
234 : uint32_t entries_to_visit_;
235 : uint64_t flow_tcp_syn_age_time_;
236 :
237 : FlowEntryTree flow_tree_;
238 : FlowExportInfoList flow_export_info_list_;
239 : // Flag to specify if flow-delete request event must be retried
240 : // If enabled
241 : // Dont remove FlowExportInfo from list after generating delete event
242 : // Retry delete event after kFlowDeleteRetryTime
243 : // Else
244 : // Remove FlowExportInfo from list after generating delete event
245 : // FIXME : disabling is only a debug feature for now. Once we remove
246 : // from list, flow will never be aged. So, need to ensure all scenarios
247 : // are covered before disabling the fag
248 : bool retry_delete_;
249 : Queue request_queue_;
250 : std::atomic<bool> deleted_;
251 : FlowAgingTableKey flow_aging_key_;
252 : uint32_t instance_id_;
253 : FlowStatsManager *flow_stats_manager_;
254 : FlowStatsCollectorObject *parent_;
255 : AgeingTask *ageing_task_;
256 : // Number of timer fires needed to scan the flow-table once
257 : // This is based on ageing timer
258 : uint32_t timers_per_scan_;
259 : // Cached UTC Time stamp
260 : // The timestamp is taken once on FlowStatsCollector::RequestHandlerEntry()
261 : // and used for all requests in current run
262 : uint64_t current_time_;
263 : uint64_t ageing_task_starts_;
264 :
265 : // Per ageing-timer stats for debugging
266 : uint32_t flows_visited_;
267 : uint32_t flows_aged_;
268 : uint32_t flows_evicted_;
269 : DISALLOW_COPY_AND_ASSIGN(FlowStatsCollector);
270 : };
271 :
272 : class FlowStatsCollectorObject {
273 : public:
274 : static const int kMaxCollectors = 2;
275 : typedef boost::shared_ptr<FlowStatsCollector> FlowStatsCollectorPtr;
276 : FlowStatsCollectorObject(Agent *agent, FlowStatsCollectorReq *req,
277 : FlowStatsManager *mgr);
278 : FlowStatsCollector* GetCollector(uint8_t idx) const;
279 : void SetExpiryTime(int time);
280 : int GetExpiryTime() const;
281 : void MarkDelete();
282 : void ClearDelete();
283 : bool IsDeleted() const;
284 : void SetFlowAgeTime(uint64_t value);
285 : uint64_t GetFlowAgeTime() const;
286 : bool CanDelete() const;
287 : void Shutdown();
288 : FlowStatsCollector* FlowToCollector(const FlowEntry *flow);
289 : void UpdateAgeTimeInSeconds(uint32_t age_time);
290 : uint32_t GetAgeTimeInSeconds() const;
291 : size_t Size() const;
292 : private:
293 : FlowStatsCollectorPtr collectors[kMaxCollectors];
294 : DISALLOW_COPY_AND_ASSIGN(FlowStatsCollectorObject);
295 : };
296 :
297 : #endif //vnsw_agent_flow_stats_collector_h
|