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