Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0
2 : * Copyright(c) 2021 Cisco Systems, Inc.
3 : */
4 :
5 : #include <vlib/vlib.h>
6 : #include <vnet/feature/feature.h>
7 : #include <snort/snort.h>
8 :
9 : typedef struct
10 : {
11 : u32 next_index;
12 : u32 sw_if_index;
13 : } snort_deq_trace_t;
14 :
15 : static u8 *
16 0 : format_snort_deq_trace (u8 *s, va_list *args)
17 : {
18 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
19 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
20 0 : snort_deq_trace_t *t = va_arg (*args, snort_deq_trace_t *);
21 :
22 0 : s = format (s, "snort-deq: sw_if_index %d, next index %d\n", t->sw_if_index,
23 : t->next_index);
24 :
25 0 : return s;
26 : }
27 :
28 : #define foreach_snort_deq_error \
29 : _ (BAD_DESC, "bad descriptor") \
30 : _ (BAD_DESC_INDEX, "bad descriptor index")
31 :
32 : typedef enum
33 : {
34 : #define _(sym, str) SNORT_DEQ_ERROR_##sym,
35 : foreach_snort_deq_error
36 : #undef _
37 : SNORT_DEQ_N_ERROR,
38 : } snort_deq_error_t;
39 :
40 : static char *snort_deq_error_strings[] = {
41 : #define _(sym, string) string,
42 : foreach_snort_deq_error
43 : #undef _
44 : };
45 :
46 : static_always_inline uword
47 0 : snort_deq_instance (vlib_main_t *vm, u32 instance_index, snort_qpair_t *qp,
48 : u32 *buffer_indices, u16 *nexts, u32 max_recv)
49 : {
50 0 : snort_main_t *sm = &snort_main;
51 0 : snort_per_thread_data_t *ptd =
52 0 : vec_elt_at_index (sm->per_thread_data, vm->thread_index);
53 0 : u32 mask = pow2_mask (qp->log2_queue_size);
54 0 : u32 head, next, n_recv = 0, n_left;
55 :
56 0 : head = __atomic_load_n (qp->deq_head, __ATOMIC_ACQUIRE);
57 0 : next = qp->next_desc;
58 :
59 0 : n_left = head - next;
60 :
61 0 : if (n_left == 0)
62 0 : return 0;
63 :
64 0 : if (n_left > max_recv)
65 : {
66 0 : n_left = max_recv;
67 0 : clib_interrupt_set (ptd->interrupts, instance_index);
68 0 : vlib_node_set_interrupt_pending (vm, snort_deq_node.index);
69 : }
70 :
71 0 : while (n_left)
72 : {
73 : u32 desc_index, bi;
74 : daq_vpp_desc_t *d;
75 :
76 : /* check if descriptor index taken from dequqe ring is valid */
77 0 : if ((desc_index = qp->deq_ring[next & mask]) & ~mask)
78 : {
79 0 : vlib_node_increment_counter (vm, snort_deq_node.index,
80 : SNORT_DEQ_ERROR_BAD_DESC_INDEX, 1);
81 0 : goto next;
82 : }
83 :
84 : /* check if descriptor index taken from dequeue ring points to enqueued
85 : * buffer */
86 0 : if ((bi = qp->buffer_indices[desc_index]) == ~0)
87 : {
88 0 : vlib_node_increment_counter (vm, snort_deq_node.index,
89 : SNORT_DEQ_ERROR_BAD_DESC, 1);
90 0 : goto next;
91 : }
92 :
93 : /* put descriptor back to freelist */
94 0 : vec_add1 (qp->freelist, desc_index);
95 0 : d = qp->descriptors + desc_index;
96 0 : buffer_indices++[0] = bi;
97 0 : if (d->action == DAQ_VPP_ACTION_FORWARD)
98 0 : nexts[0] = qp->next_indices[desc_index];
99 : else
100 0 : nexts[0] = SNORT_ENQ_NEXT_DROP;
101 0 : qp->buffer_indices[desc_index] = ~0;
102 0 : nexts++;
103 0 : n_recv++;
104 :
105 : /* next */
106 0 : next:
107 0 : next = next + 1;
108 0 : n_left--;
109 : }
110 :
111 0 : qp->next_desc = next;
112 :
113 0 : return n_recv;
114 : }
115 :
116 : static_always_inline u32
117 0 : snort_process_all_buffer_indices (snort_qpair_t *qp, u32 *b, u16 *nexts,
118 : u32 max_recv, u8 drop_on_disconnect)
119 : {
120 0 : u32 *bi, n_processed = 0;
121 0 : u32 desc_index = 0;
122 :
123 0 : vec_foreach (bi, qp->buffer_indices)
124 : {
125 0 : if (n_processed >= max_recv)
126 0 : break;
127 :
128 0 : if (bi[0] == ~0)
129 0 : continue;
130 :
131 0 : desc_index = bi - qp->buffer_indices;
132 :
133 0 : b[0] = bi[0];
134 0 : if (drop_on_disconnect)
135 0 : nexts[0] = SNORT_ENQ_NEXT_DROP;
136 : else
137 0 : nexts[0] = qp->next_indices[desc_index];
138 0 : qp->buffer_indices[desc_index] = ~0;
139 :
140 0 : nexts += 1;
141 0 : b += 1;
142 0 : n_processed += 1;
143 : }
144 0 : return n_processed;
145 : }
146 :
147 : static_always_inline uword
148 0 : snort_deq_instance_all_interrupt (vlib_main_t *vm, u32 instance_index,
149 : snort_qpair_t *qp, u32 *buffer_indices,
150 : u16 *nexts, u32 max_recv,
151 : u8 drop_on_disconnect)
152 : {
153 0 : snort_main_t *sm = &snort_main;
154 0 : snort_per_thread_data_t *ptd =
155 0 : vec_elt_at_index (sm->per_thread_data, vm->thread_index);
156 : u32 n_processed;
157 :
158 0 : n_processed = snort_process_all_buffer_indices (
159 : qp, buffer_indices, nexts, max_recv, drop_on_disconnect);
160 :
161 0 : if (n_processed == max_recv)
162 : {
163 0 : clib_interrupt_set (ptd->interrupts, instance_index);
164 0 : vlib_node_set_interrupt_pending (vm, snort_deq_node.index);
165 : }
166 : else
167 : {
168 0 : *qp->enq_head = *qp->deq_head = qp->next_desc = 0;
169 0 : snort_freelist_init (qp->freelist);
170 0 : __atomic_store_n (&qp->ready, 1, __ATOMIC_RELEASE);
171 : }
172 :
173 0 : return n_processed;
174 : }
175 :
176 : static u32
177 0 : snort_deq_node_interrupt (vlib_main_t *vm, vlib_node_runtime_t *node,
178 : vlib_frame_t *frame)
179 : {
180 0 : snort_main_t *sm = &snort_main;
181 0 : snort_per_thread_data_t *ptd =
182 0 : vec_elt_at_index (sm->per_thread_data, vm->thread_index);
183 0 : u32 buffer_indices[VLIB_FRAME_SIZE], *bi = buffer_indices;
184 0 : u16 next_indices[VLIB_FRAME_SIZE], *nexts = next_indices;
185 0 : u32 n_left = VLIB_FRAME_SIZE, n;
186 : snort_qpair_t *qp;
187 : snort_instance_t *si;
188 0 : int inst = -1;
189 :
190 0 : while ((inst = clib_interrupt_get_next (ptd->interrupts, inst)) != -1)
191 : {
192 0 : clib_interrupt_clear (ptd->interrupts, inst);
193 0 : si = vec_elt_at_index (sm->instances, inst);
194 0 : qp = vec_elt_at_index (si->qpairs, vm->thread_index);
195 0 : u32 ready = __atomic_load_n (&qp->ready, __ATOMIC_ACQUIRE);
196 0 : if (!ready)
197 0 : n = snort_deq_instance_all_interrupt (vm, inst, qp, bi, nexts, n_left,
198 0 : si->drop_on_disconnect);
199 : else
200 0 : n = snort_deq_instance (vm, inst, qp, bi, nexts, n_left);
201 :
202 0 : n_left -= n;
203 0 : bi += n;
204 0 : nexts += n;
205 :
206 0 : if (n_left == 0)
207 0 : goto enq;
208 : }
209 :
210 0 : if (n_left == VLIB_FRAME_SIZE)
211 0 : return 0;
212 :
213 0 : enq:
214 0 : n = VLIB_FRAME_SIZE - n_left;
215 0 : vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices, n);
216 0 : return n;
217 : }
218 :
219 : static_always_inline uword
220 0 : snort_deq_instance_poll (vlib_main_t *vm, snort_qpair_t *qp,
221 : u32 *buffer_indices, u16 *nexts, u32 max_recv)
222 : {
223 0 : u32 mask = pow2_mask (qp->log2_queue_size);
224 0 : u32 head, next, n_recv = 0, n_left;
225 :
226 0 : head = __atomic_load_n (qp->deq_head, __ATOMIC_ACQUIRE);
227 0 : next = qp->next_desc;
228 :
229 0 : n_left = head - next;
230 :
231 0 : if (n_left == 0)
232 0 : return 0;
233 :
234 0 : if (n_left > max_recv)
235 0 : n_left = max_recv;
236 :
237 0 : while (n_left)
238 : {
239 : u32 desc_index, bi;
240 : daq_vpp_desc_t *d;
241 :
242 : /* check if descriptor index taken from dequqe ring is valid */
243 0 : if ((desc_index = qp->deq_ring[next & mask]) & ~mask)
244 : {
245 0 : vlib_node_increment_counter (vm, snort_deq_node.index,
246 : SNORT_DEQ_ERROR_BAD_DESC_INDEX, 1);
247 0 : goto next;
248 : }
249 :
250 : /* check if descriptor index taken from dequeue ring points to enqueued
251 : * buffer */
252 0 : if ((bi = qp->buffer_indices[desc_index]) == ~0)
253 : {
254 0 : vlib_node_increment_counter (vm, snort_deq_node.index,
255 : SNORT_DEQ_ERROR_BAD_DESC, 1);
256 0 : goto next;
257 : }
258 :
259 : /* put descriptor back to freelist */
260 0 : vec_add1 (qp->freelist, desc_index);
261 0 : d = qp->descriptors + desc_index;
262 0 : buffer_indices++[0] = bi;
263 0 : if (d->action == DAQ_VPP_ACTION_FORWARD)
264 0 : nexts[0] = qp->next_indices[desc_index];
265 : else
266 0 : nexts[0] = SNORT_ENQ_NEXT_DROP;
267 0 : qp->buffer_indices[desc_index] = ~0;
268 0 : nexts++;
269 0 : n_recv++;
270 :
271 : /* next */
272 0 : next:
273 0 : next = next + 1;
274 0 : n_left--;
275 : }
276 :
277 0 : qp->next_desc = next;
278 :
279 0 : return n_recv;
280 : }
281 :
282 : static_always_inline uword
283 0 : snort_deq_instance_all_poll (vlib_main_t *vm, snort_qpair_t *qp,
284 : u32 *buffer_indices, u16 *nexts, u32 max_recv,
285 : u8 drop_on_disconnect)
286 : {
287 0 : u32 n_processed = snort_process_all_buffer_indices (
288 : qp, buffer_indices, nexts, max_recv, drop_on_disconnect);
289 0 : if (n_processed < max_recv)
290 : {
291 0 : *qp->enq_head = *qp->deq_head = qp->next_desc = 0;
292 0 : snort_freelist_init (qp->freelist);
293 0 : __atomic_store_n (&qp->ready, 1, __ATOMIC_RELEASE);
294 : }
295 :
296 0 : return n_processed;
297 : }
298 :
299 : static u32
300 0 : snort_deq_node_polling (vlib_main_t *vm, vlib_node_runtime_t *node,
301 : vlib_frame_t *frame)
302 : {
303 0 : snort_main_t *sm = &snort_main;
304 0 : u32 buffer_indices[VLIB_FRAME_SIZE], *bi = buffer_indices;
305 0 : u16 next_indices[VLIB_FRAME_SIZE], *nexts = next_indices;
306 0 : u32 n_left = VLIB_FRAME_SIZE, n, n_total = 0;
307 : snort_qpair_t *qp;
308 : snort_instance_t *si;
309 :
310 0 : vec_foreach (si, sm->instances)
311 : {
312 0 : qp = vec_elt_at_index (si->qpairs, vm->thread_index);
313 0 : u32 ready = __atomic_load_n (&qp->ready, __ATOMIC_ACQUIRE);
314 0 : if (!ready)
315 0 : n = snort_deq_instance_all_poll (vm, qp, bi, nexts, n_left,
316 0 : si->drop_on_disconnect);
317 : else
318 0 : n = snort_deq_instance_poll (vm, qp, bi, nexts, n_left);
319 :
320 0 : n_left -= n;
321 0 : bi += n;
322 0 : nexts += n;
323 :
324 0 : if (n_left == 0)
325 : {
326 0 : n = VLIB_FRAME_SIZE - n_left;
327 0 : vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices,
328 : n);
329 0 : n_left = VLIB_FRAME_SIZE;
330 0 : bi = buffer_indices;
331 0 : nexts = next_indices;
332 0 : n_total += n;
333 : }
334 : }
335 :
336 0 : if (n_left < VLIB_FRAME_SIZE)
337 : {
338 0 : n = VLIB_FRAME_SIZE - n_left;
339 0 : vlib_buffer_enqueue_to_next (vm, node, buffer_indices, next_indices, n);
340 0 : n_total += n;
341 : }
342 0 : return n_total;
343 : }
344 :
345 2236 : VLIB_NODE_FN (snort_deq_node)
346 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
347 : {
348 0 : snort_main_t *sm = &snort_main;
349 0 : if (sm->input_mode == VLIB_NODE_STATE_POLLING)
350 0 : return snort_deq_node_polling (vm, node, frame);
351 0 : return snort_deq_node_interrupt (vm, node, frame);
352 : }
353 :
354 41439 : VLIB_REGISTER_NODE (snort_deq_node) = {
355 : .name = "snort-deq",
356 : .vector_size = sizeof (u32),
357 : .format_trace = format_snort_deq_trace,
358 : .type = VLIB_NODE_TYPE_INPUT,
359 : .state = VLIB_NODE_STATE_DISABLED,
360 : .sibling_of = "snort-enq",
361 :
362 : .n_errors = ARRAY_LEN (snort_deq_error_strings),
363 : .error_strings = snort_deq_error_strings,
364 :
365 : .n_next_nodes = 0,
366 : };
|