Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #ifndef __AGENT_FLOW_EVENT_H__
6 : #define __AGENT_FLOW_EVENT_H__
7 :
8 : #include <sys/resource.h>
9 : #include <ksync/ksync_entry.h>
10 : #include "flow_table.h"
11 :
12 : class FlowTokenPool;
13 :
14 : ////////////////////////////////////////////////////////////////////////////
15 : // Control events for flow management
16 : ////////////////////////////////////////////////////////////////////////////
17 : class FlowEvent {
18 : public:
19 : enum Event {
20 : INVALID,
21 : // Flow add message from VRouter
22 : VROUTER_FLOW_MSG,
23 : // Message to update a flow
24 : FLOW_MESSAGE,
25 : // Event to delete a flow entry
26 : DELETE_FLOW,
27 : // Event by audit module to delete a flow
28 : AUDIT_FLOW,
29 : // In agent, flow is evicted if index is allocated for another flow
30 : // We delete the flow on eviction. There is a corner case where evicted
31 : // flow is added in parallel with different index. In that case
32 : // we ignore the operation
33 : EVICT_FLOW,
34 : // Revaluate flow due to deletion of a DBEntry. Other than for INET
35 : // routes, delete of a DBEntry will result in deletion of flows using
36 : // the DBEntry
37 : DELETE_DBENTRY,
38 : // Revaluate route due to change in a DBEntry. This event is used to
39 : // revaluate a flow on add/change of interface, vm, vn etc...
40 : // The action typically invovles only re-evaluating ACL lookup actions
41 : REVALUATE_DBENTRY,
42 : // Add/Delete of route can result in flow using a next higher/lower
43 : // prefix. The event will recompute the complete flow due to change
44 : // in route used for flow
45 : RECOMPUTE_FLOW,
46 : // Flow entry should be freed from kTaskFlowEvent task context.
47 : // Event to ensure flow entry is freed from right context
48 : FREE_FLOW_REF,
49 : // A DBEntry should be freed from kTaskFlowEvent task context.
50 : // Event to ensure DBEntry entry reference is freed from right context
51 : FREE_DBENTRY,
52 : // Grow the free-list entries for flow and ksync
53 : GROW_FREE_LIST,
54 : // Generate KSync event for the flow
55 : KSYNC_EVENT,
56 : // Pkt is re-entering processing in new partition
57 : REENTRANT,
58 : // Need to resolve the Flow entry whic is depending on Mirror entry
59 : UNRESOLVED_FLOW_ENTRY,
60 : };
61 :
62 : FlowEvent() :
63 : event_(INVALID), flow_(NULL), pkt_info_(), db_entry_(NULL),
64 : gen_id_(0), evict_gen_id_(0),
65 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(0) {
66 : }
67 :
68 : FlowEvent(Event event) :
69 : event_(event), flow_(NULL), pkt_info_(), db_entry_(NULL),
70 : gen_id_(0), evict_gen_id_(0), table_index_(0) {
71 : }
72 :
73 144 : FlowEvent(Event event, FlowEntry *flow) :
74 144 : event_(event), flow_(flow), pkt_info_(), db_entry_(NULL),
75 288 : table_index_(0) {
76 144 : }
77 :
78 0 : FlowEvent(Event event, uint32_t table_index) :
79 0 : event_(event), flow_(NULL), pkt_info_(), db_entry_(NULL),
80 0 : gen_id_(0), evict_gen_id_(0),
81 0 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(table_index) {
82 0 : }
83 :
84 418 : FlowEvent(Event event, FlowEntry *flow, uint32_t flow_handle,
85 418 : uint8_t gen_id) :
86 418 : event_(event), flow_(flow), pkt_info_(), db_entry_(NULL),
87 836 : gen_id_(gen_id), evict_gen_id_(0), flow_handle_(flow_handle),
88 836 : table_index_(0) {
89 418 : }
90 :
91 32 : FlowEvent(Event event, FlowEntry *flow, uint32_t flow_handle,
92 32 : uint8_t gen_id, uint8_t evict_gen_id) :
93 32 : event_(event), flow_(flow), pkt_info_(), db_entry_(NULL),
94 64 : gen_id_(gen_id), evict_gen_id_(evict_gen_id), flow_handle_(flow_handle),
95 64 : table_index_(0) {
96 32 : }
97 :
98 201 : FlowEvent(Event event, FlowEntry *flow, const DBEntry *db_entry) :
99 201 : event_(event), flow_(flow), pkt_info_(), db_entry_(db_entry),
100 201 : gen_id_(0), evict_gen_id_(0),
101 402 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(0) {
102 201 : }
103 :
104 : FlowEvent(Event event, const DBEntry *db_entry, uint32_t gen_id) :
105 : event_(event), flow_(NULL), pkt_info_(), db_entry_(db_entry),
106 : gen_id_(gen_id), evict_gen_id_(0),
107 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(0) {
108 : }
109 :
110 3494 : FlowEvent(Event event, uint16_t table_index, const DBEntry *db_entry,
111 3494 : uint32_t gen_id) :
112 3494 : event_(event), flow_(NULL), pkt_info_(), db_entry_(db_entry),
113 3494 : gen_id_(gen_id), evict_gen_id_(0),
114 6988 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(table_index) {
115 3494 : }
116 :
117 : FlowEvent(Event event, const FlowKey &key) :
118 : event_(event), flow_(NULL), pkt_info_(), db_entry_(NULL),
119 : gen_id_(0), evict_gen_id_(0), flow_key_(key),
120 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(0) {
121 : }
122 :
123 0 : FlowEvent(Event event, const FlowKey &key, uint32_t flow_handle,
124 0 : uint8_t gen_id) :
125 0 : event_(event), flow_(NULL), pkt_info_(), db_entry_(NULL),
126 0 : gen_id_(gen_id), evict_gen_id_(0), flow_key_(key),
127 0 : flow_handle_(flow_handle), table_index_(0) {
128 0 : }
129 :
130 75 : FlowEvent(Event event, PktInfoPtr pkt_info, FlowEntry *flow,
131 75 : uint32_t table_index) :
132 75 : event_(event), flow_(flow), pkt_info_(pkt_info), db_entry_(NULL),
133 75 : gen_id_(0), evict_gen_id_(0), flow_key_(),
134 75 : flow_handle_(FlowEntry::kInvalidFlowHandle), table_index_(table_index) {
135 75 : }
136 :
137 : FlowEvent(const FlowEvent &rhs) :
138 : event_(rhs.event_), flow_(rhs.flow()), pkt_info_(rhs.pkt_info_),
139 : db_entry_(rhs.db_entry_), gen_id_(rhs.gen_id_),
140 : evict_gen_id_(rhs.evict_gen_id_), flow_key_(rhs.flow_key_),
141 : flow_handle_(rhs.flow_handle_), table_index_(rhs.table_index_) {
142 : }
143 :
144 8350 : virtual ~FlowEvent() {
145 8350 : }
146 :
147 27312 : Event event() const { return event_; }
148 13355 : FlowEntry *flow() const { return flow_.get(); }
149 : FlowEntryPtr &flow_ref() { return flow_; }
150 201 : void set_flow(FlowEntry *flow) { flow_ = flow; }
151 3498 : const DBEntry *db_entry() const { return db_entry_; }
152 201 : void set_db_entry(const DBEntry *db_entry) { db_entry_ = db_entry; }
153 3793 : uint32_t gen_id() const { return gen_id_; }
154 32 : uint32_t evict_gen_id() const { return evict_gen_id_; }
155 0 : const FlowKey &get_flow_key() const { return flow_key_; }
156 150 : PktInfoPtr pkt_info() const { return pkt_info_; }
157 989 : uint32_t flow_handle() const { return flow_handle_; }
158 3494 : uint32_t table_index() const { return table_index_;}
159 : private:
160 : Event event_;
161 : FlowEntryPtr flow_;
162 : PktInfoPtr pkt_info_;
163 : const DBEntry *db_entry_;
164 : uint32_t gen_id_;
165 : uint32_t evict_gen_id_;
166 : FlowKey flow_key_;
167 : uint32_t flow_handle_;
168 : uint32_t table_index_;
169 : };
170 :
171 : ////////////////////////////////////////////////////////////////////////////
172 : // Event to process VRouter response for flow operation. VRouter response for
173 : // flow is made of two messages,
174 : // - vr_flow response which will contains,
175 : // - Return code for the operation
176 : // - flow-handle allocated for flow
177 : // - gen-id for he hash-entry allocated
178 : // - stats for the flow being evicted by VRouter
179 : // - vr_response
180 : // - contains ksync-event to be generated for the flow
181 : //
182 : // The event combines data from both the messages. The event-handler will
183 : // process both the vrouter response messages
184 : //
185 : // The flow-handle and gen-id are got from base class (FlowEvent)
186 : ////////////////////////////////////////////////////////////////////////////
187 : class FlowEventKSync : public FlowEvent {
188 : public:
189 378 : FlowEventKSync(const KSyncEntry::KSyncEntryPtr ksync_entry,
190 : KSyncEntry::KSyncEvent ksync_event, uint32_t flow_handle,
191 : uint32_t gen_id, int ksync_error, uint64_t evict_flow_bytes,
192 : uint64_t evict_flow_packets, uint64_t evict_flow_oflow,
193 378 : uint32_t transaction_id) :
194 : FlowEvent(KSYNC_EVENT, NULL, flow_handle, gen_id),
195 756 : ksync_entry_(ksync_entry), ksync_event_(ksync_event),
196 378 : ksync_error_(ksync_error), evict_flow_bytes_(evict_flow_bytes),
197 378 : evict_flow_packets_(evict_flow_packets),
198 378 : evict_flow_oflow_(evict_flow_oflow),
199 378 : transaction_id_(transaction_id) {
200 378 : }
201 :
202 : FlowEventKSync(const FlowEventKSync &rhs) :
203 : FlowEvent(rhs), ksync_entry_(rhs.ksync_entry_),
204 : ksync_event_(rhs.ksync_event_), ksync_error_(rhs.ksync_error_),
205 : evict_flow_bytes_(rhs.evict_flow_bytes_),
206 : evict_flow_packets_(rhs.evict_flow_packets_),
207 : evict_flow_oflow_(rhs.evict_flow_oflow_),
208 : transaction_id_(rhs.transaction_id_) {
209 : }
210 :
211 756 : virtual ~FlowEventKSync() { }
212 :
213 1510 : KSyncEntry *ksync_entry() const { return ksync_entry_.get(); }
214 756 : KSyncEntry::KSyncEvent ksync_event() const { return ksync_event_; }
215 608 : int ksync_error() const { return ksync_error_; }
216 0 : uint64_t evict_flow_bytes() const { return evict_flow_bytes_; }
217 0 : uint64_t evict_flow_packets() const { return evict_flow_packets_; }
218 0 : uint64_t evict_flow_oflow() const { return evict_flow_oflow_; }
219 230 : uint32_t transaction_id() const { return transaction_id_; }
220 : private:
221 : KSyncEntry::KSyncEntryPtr ksync_entry_;
222 : KSyncEntry::KSyncEvent ksync_event_;
223 : int ksync_error_;
224 : uint64_t evict_flow_bytes_;
225 : uint64_t evict_flow_packets_;
226 : uint64_t evict_flow_oflow_;
227 : uint32_t transaction_id_;
228 : };
229 :
230 : ////////////////////////////////////////////////////////////////////////////
231 : // FlowProto uses following queues,
232 : //
233 : // - FlowEventQueue
234 : // This queue contains events for flow add, flow eviction etc...
235 : // See FlowProto::FlowEventHandler for events handled in this queue
236 : // - KSyncFlowEventQueue
237 : // This queue contains events generated from KSync response for a flow
238 : // - DeleteFlowEventQueue
239 : // This queue contains events generated for flow-ageing
240 : // - UpdateFlowEventQueue
241 : // This queue contains events generated as result of config changes such
242 : // as add/delete/change of interface, vn, vm, acl, nh, route etc...
243 : //
244 : // All queues are defined from a base class FlowEventQueueBase.
245 : // FlowEventQueueBase implements a wrapper around the WorkQueues with following
246 : // additional functionality,
247 : //
248 : // - Rate Control using Tokens
249 : // All the queues give above can potentially add/change/delete flows in the
250 : // vrouter. So, the queues given above acts as producer and VRouter acts as
251 : // consumer. VRouter is a slow consumer of events. To provide fairness
252 : // across queues, a "token" based scheme is used. See flow_token.h for more
253 : // information
254 : //
255 : // The queue will stop the WorkQueue when it runs out of tokens. The queue
256 : // is started again after a minimum number of tokens become available
257 : //
258 : // - Time limits
259 : // Intermittently, it is observed that some of the queues take large amount
260 : // of time. Latencies in queue such as KSync queue or delete-queue can result
261 : // in flow-setup latencies. So, we want to impose an upper bound on the
262 : // amount of time taken in single run of WorkQueue.
263 : //
264 : // We take timestamp at start of queue, and check latency for every 8
265 : // events processed in the queue. If the latency goes beyond a limit, the
266 : // WorkQueue run is aborted.
267 : ////////////////////////////////////////////////////////////////////////////
268 : class FlowEventQueueBase {
269 : public:
270 : typedef WorkQueue<FlowEvent *> Queue;
271 :
272 : FlowEventQueueBase(FlowProto *proto, const std::string &name,
273 : uint32_t task_id, int task_instance,
274 : FlowTokenPool *pool, uint16_t latency_limit,
275 : uint32_t max_iterations);
276 : virtual ~FlowEventQueueBase();
277 : virtual bool HandleEvent(FlowEvent *event) = 0;
278 : virtual bool Handler(FlowEvent *event);
279 :
280 : void Shutdown();
281 : void Enqueue(FlowEvent *event);
282 : bool TokenCheck();
283 : bool TaskEntry();
284 : void TaskExit(bool done);
285 0 : void set_disable(bool val) { queue_->set_disable(val); }
286 0 : uint32_t Length() { return queue_->Length(); }
287 0 : void MayBeStartRunner() { queue_->MayBeStartRunner(); }
288 25 : Queue *queue() const { return queue_; }
289 11 : uint64_t events_processed() const { return events_processed_; }
290 : uint64_t events_enqueued() const { return queue_->NumEnqueues(); }
291 :
292 : protected:
293 : bool CanEnqueue(FlowEvent *event);
294 : bool CanProcess(FlowEvent *event);
295 : void ProcessDone(FlowEvent *event, bool update_rev_flow);
296 :
297 : Queue *queue_;
298 : FlowProto *flow_proto_;
299 : FlowTokenPool *token_pool_;
300 : uint64_t task_start_;
301 : // Number of entries processed in single run of WorkQueue
302 : uint32_t count_;
303 : // Number of events processed. Skips event that are state-compressed
304 : // due to Flow PendingActions
305 : uint64_t events_processed_;
306 : uint16_t latency_limit_;
307 : struct rusage rusage_;
308 : };
309 :
310 : class FlowEventQueue : public FlowEventQueueBase {
311 : public:
312 : FlowEventQueue(Agent *agent, FlowProto *proto, FlowTable *table,
313 : FlowTokenPool *pool, uint16_t latency_limit,
314 : uint32_t max_iterations);
315 : virtual ~FlowEventQueue();
316 :
317 : bool HandleEvent(FlowEvent *event);
318 : private:
319 : FlowTable *flow_table_;
320 : };
321 :
322 : class DeleteFlowEventQueue : public FlowEventQueueBase {
323 : public:
324 : DeleteFlowEventQueue(Agent *agent, FlowProto *proto, FlowTable *table,
325 : FlowTokenPool *pool, uint16_t latency_limit,
326 : uint32_t max_iterations);
327 : virtual ~DeleteFlowEventQueue();
328 :
329 : bool HandleEvent(FlowEvent *event);
330 : private:
331 : FlowTable *flow_table_;
332 : };
333 :
334 : class KSyncFlowEventQueue : public FlowEventQueueBase {
335 : public:
336 : KSyncFlowEventQueue(Agent *agent, FlowProto *proto, FlowTable *table,
337 : FlowTokenPool *pool, uint16_t latency_limit,
338 : uint32_t max_iterations);
339 : virtual ~KSyncFlowEventQueue();
340 :
341 : bool HandleEvent(FlowEvent *event);
342 : private:
343 : FlowTable *flow_table_;
344 : };
345 :
346 : class UpdateFlowEventQueue : public FlowEventQueueBase {
347 : public:
348 : UpdateFlowEventQueue(Agent *agent, FlowProto *proto,
349 : FlowTokenPool *pool, uint16_t latency_limit,
350 : uint32_t max_iterations);
351 : virtual ~UpdateFlowEventQueue();
352 :
353 : bool HandleEvent(FlowEvent *event);
354 : };
355 :
356 : #endif // __AGENT_FLOW_EVENT_H__
|