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