misc: remove GNU Indent directives
[vpp.git] / src / plugins / af_xdp / input.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <vlib/vlib.h>
19 #include <vlib/unix/unix.h>
20 #include <vlib/pci/pci.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/devices.h>
23 #include <vnet/interface/rx_queue_funcs.h>
24 #include "af_xdp.h"
25
26 #define foreach_af_xdp_input_error                                            \
27   _ (SYSCALL_REQUIRED, "syscall required")                                    \
28   _ (SYSCALL_FAILURES, "syscall failures")
29
30 typedef enum
31 {
32 #define _(f,s) AF_XDP_INPUT_ERROR_##f,
33   foreach_af_xdp_input_error
34 #undef _
35     AF_XDP_INPUT_N_ERROR,
36 } af_xdp_input_error_t;
37
38 static __clib_unused char *af_xdp_input_error_strings[] = {
39 #define _(n,s) s,
40   foreach_af_xdp_input_error
41 #undef _
42 };
43
44 static_always_inline void
45 af_xdp_device_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
46                            u32 n_left, const u32 * bi, u32 next_index,
47                            u32 hw_if_index)
48 {
49   u32 n_trace = vlib_get_trace_count (vm, node);
50
51   if (PREDICT_TRUE (0 == n_trace))
52     return;
53
54   while (n_trace && n_left)
55     {
56       vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
57       if (PREDICT_TRUE
58           (vlib_trace_buffer (vm, node, next_index, b, /* follow_chain */ 0)))
59         {
60           af_xdp_input_trace_t *tr =
61             vlib_add_trace (vm, node, b, sizeof (*tr));
62           tr->next_index = next_index;
63           tr->hw_if_index = hw_if_index;
64           n_trace--;
65         }
66       n_left--;
67       bi++;
68     }
69
70   vlib_set_trace_count (vm, node, n_trace);
71 }
72
73 static_always_inline void
74 af_xdp_device_input_refill_db (vlib_main_t * vm,
75                                const vlib_node_runtime_t * node,
76                                af_xdp_device_t * ad, af_xdp_rxq_t * rxq,
77                                const u32 n_alloc)
78 {
79   xsk_ring_prod__submit (&rxq->fq, n_alloc);
80
81   if (AF_XDP_RXQ_MODE_INTERRUPT == rxq->mode ||
82       !xsk_ring_prod__needs_wakeup (&rxq->fq))
83     return;
84
85   if (node)
86     vlib_error_count (vm, node->node_index,
87                       AF_XDP_INPUT_ERROR_SYSCALL_REQUIRED, 1);
88
89   if (clib_spinlock_trylock_if_init (&rxq->syscall_lock))
90     {
91       int ret = recvmsg (rxq->xsk_fd, 0, MSG_DONTWAIT);
92       clib_spinlock_unlock_if_init (&rxq->syscall_lock);
93       if (PREDICT_FALSE (ret < 0))
94         {
95           /* something bad is happening */
96           if (node)
97             vlib_error_count (vm, node->node_index,
98                               AF_XDP_INPUT_ERROR_SYSCALL_FAILURES, 1);
99           af_xdp_device_error (ad, "rx poll() failed");
100         }
101     }
102 }
103
104 static_always_inline void
105 af_xdp_device_input_refill_inline (vlib_main_t *vm,
106                                    const vlib_node_runtime_t *node,
107                                    af_xdp_device_t *ad, af_xdp_rxq_t *rxq)
108 {
109   __u64 *fill;
110   const u32 size = rxq->fq.size;
111   const u32 mask = size - 1;
112   u32 bis[VLIB_FRAME_SIZE], *bi = bis;
113   u32 n_alloc, n, n_wrap;
114   u32 idx = 0;
115
116   ASSERT (mask == rxq->fq.mask);
117
118   /* do not enqueue more packet than ring space */
119   n_alloc = xsk_prod_nb_free (&rxq->fq, 16);
120   /* do not bother to allocate if too small */
121   if (n_alloc < 16)
122     return;
123
124   n_alloc = clib_min (n_alloc, ARRAY_LEN (bis));
125   n_alloc = vlib_buffer_alloc_from_pool (vm, bis, n_alloc, ad->pool);
126   n = xsk_ring_prod__reserve (&rxq->fq, n_alloc, &idx);
127   ASSERT (n == n_alloc);
128
129   fill = xsk_ring_prod__fill_addr (&rxq->fq, idx);
130   n = clib_min (n_alloc, size - (idx & mask));
131   n_wrap = n_alloc - n;
132
133 #define bi2addr(bi) ((bi) << CLIB_LOG2_CACHE_LINE_BYTES)
134
135 wrap_around:
136
137   while (n >= 8)
138     {
139 #ifdef CLIB_HAVE_VEC256
140       u64x4 b0 = u64x4_from_u32x4 (*(u32x4u *) (bi + 0));
141       u64x4 b1 = u64x4_from_u32x4 (*(u32x4u *) (bi + 4));
142       *(u64x4u *) (fill + 0) = bi2addr (b0);
143       *(u64x4u *) (fill + 4) = bi2addr (b1);
144 #else
145       fill[0] = bi2addr (bi[0]);
146       fill[1] = bi2addr (bi[1]);
147       fill[2] = bi2addr (bi[2]);
148       fill[3] = bi2addr (bi[3]);
149       fill[4] = bi2addr (bi[4]);
150       fill[5] = bi2addr (bi[5]);
151       fill[6] = bi2addr (bi[6]);
152       fill[7] = bi2addr (bi[7]);
153 #endif
154       fill += 8;
155       bi += 8;
156       n -= 8;
157     }
158
159   while (n >= 1)
160     {
161       fill[0] = bi2addr (bi[0]);
162       fill += 1;
163       bi += 1;
164       n -= 1;
165     }
166
167   if (n_wrap)
168     {
169       fill = xsk_ring_prod__fill_addr (&rxq->fq, 0);
170       n = n_wrap;
171       n_wrap = 0;
172       goto wrap_around;
173     }
174
175   af_xdp_device_input_refill_db (vm, node, ad, rxq, n_alloc);
176 }
177
178 static_always_inline void
179 af_xdp_device_input_ethernet (vlib_main_t * vm, vlib_node_runtime_t * node,
180                               const u32 next_index, const u32 sw_if_index,
181                               const u32 hw_if_index)
182 {
183   vlib_next_frame_t *nf;
184   vlib_frame_t *f;
185   ethernet_input_frame_t *ef;
186
187   if (PREDICT_FALSE (VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT != next_index))
188     return;
189
190   nf =
191     vlib_node_runtime_get_next_frame (vm, node,
192                                       VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT);
193   f = vlib_get_frame (vm, nf->frame);
194   f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
195
196   ef = vlib_frame_scalar_args (f);
197   ef->sw_if_index = sw_if_index;
198   ef->hw_if_index = hw_if_index;
199   vlib_frame_no_append (f);
200 }
201
202 static_always_inline u32
203 af_xdp_device_input_bufs (vlib_main_t *vm, const af_xdp_device_t *ad,
204                           af_xdp_rxq_t *rxq, u32 *bis, const u32 n_rx,
205                           vlib_buffer_t *bt, u32 idx)
206 {
207   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
208   u16 offs[VLIB_FRAME_SIZE], *off = offs;
209   u16 lens[VLIB_FRAME_SIZE], *len = lens;
210   const u32 mask = rxq->rx.mask;
211   u32 n = n_rx, *bi = bis, bytes = 0;
212
213 #define addr2bi(addr) ((addr) >> CLIB_LOG2_CACHE_LINE_BYTES)
214
215   while (n >= 1)
216     {
217       const struct xdp_desc *desc = xsk_ring_cons__rx_desc (&rxq->rx, idx);
218       const u64 addr = desc->addr;
219       bi[0] = addr2bi (xsk_umem__extract_addr (addr));
220       ASSERT (vlib_buffer_is_known (vm, bi[0]) ==
221               VLIB_BUFFER_KNOWN_ALLOCATED);
222       off[0] = xsk_umem__extract_offset (addr) - sizeof (vlib_buffer_t);
223       len[0] = desc->len;
224       idx = (idx + 1) & mask;
225       bi += 1;
226       off += 1;
227       len += 1;
228       n -= 1;
229     }
230
231   vlib_get_buffers (vm, bis, bufs, n_rx);
232
233   n = n_rx;
234   off = offs;
235   len = lens;
236
237   while (n >= 8)
238     {
239       vlib_prefetch_buffer_header (b[4], LOAD);
240       vlib_buffer_copy_template (b[0], bt);
241       b[0]->current_data = off[0];
242       bytes += b[0]->current_length = len[0];
243
244       vlib_prefetch_buffer_header (b[5], LOAD);
245       vlib_buffer_copy_template (b[1], bt);
246       b[1]->current_data = off[1];
247       bytes += b[1]->current_length = len[1];
248
249       vlib_prefetch_buffer_header (b[6], LOAD);
250       vlib_buffer_copy_template (b[2], bt);
251       b[2]->current_data = off[2];
252       bytes += b[2]->current_length = len[2];
253
254       vlib_prefetch_buffer_header (b[7], LOAD);
255       vlib_buffer_copy_template (b[3], bt);
256       b[3]->current_data = off[3];
257       bytes += b[3]->current_length = len[3];
258
259       b += 4;
260       off += 4;
261       len += 4;
262       n -= 4;
263     }
264
265   while (n >= 1)
266     {
267       vlib_buffer_copy_template (b[0], bt);
268       b[0]->current_data = off[0];
269       bytes += b[0]->current_length = len[0];
270       b += 1;
271       off += 1;
272       len += 1;
273       n -= 1;
274     }
275
276   xsk_ring_cons__release (&rxq->rx, n_rx);
277   return bytes;
278 }
279
280 static_always_inline uword
281 af_xdp_device_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
282                             vlib_frame_t *frame, af_xdp_device_t *ad, u16 qid)
283 {
284   vnet_main_t *vnm = vnet_get_main ();
285   af_xdp_rxq_t *rxq = vec_elt_at_index (ad->rxqs, qid);
286   vlib_buffer_t bt;
287   u32 next_index, *to_next, n_left_to_next;
288   u32 n_rx_packets, n_rx_bytes;
289   u32 idx;
290
291   n_rx_packets = xsk_ring_cons__peek (&rxq->rx, VLIB_FRAME_SIZE, &idx);
292
293   if (PREDICT_FALSE (0 == n_rx_packets))
294     goto refill;
295
296   vlib_buffer_copy_template (&bt, ad->buffer_template);
297   next_index = ad->per_interface_next_index;
298   if (PREDICT_FALSE (vnet_device_input_have_features (ad->sw_if_index)))
299     vnet_feature_start_device_input (ad->sw_if_index, &next_index, &bt);
300
301   vlib_get_new_next_frame (vm, node, next_index, to_next, n_left_to_next);
302
303   n_rx_bytes =
304     af_xdp_device_input_bufs (vm, ad, rxq, to_next, n_rx_packets, &bt, idx);
305   af_xdp_device_input_ethernet (vm, node, next_index, ad->sw_if_index,
306                                 ad->hw_if_index);
307
308   vlib_put_next_frame (vm, node, next_index, n_left_to_next - n_rx_packets);
309
310   af_xdp_device_input_trace (vm, node, n_rx_packets, to_next, next_index,
311                              ad->hw_if_index);
312
313   vlib_increment_combined_counter
314     (vnm->interface_main.combined_sw_if_counters +
315      VNET_INTERFACE_COUNTER_RX, vm->thread_index,
316      ad->hw_if_index, n_rx_packets, n_rx_bytes);
317
318 refill:
319   af_xdp_device_input_refill_inline (vm, node, ad, rxq);
320
321   return n_rx_packets;
322 }
323
324 VLIB_NODE_FN (af_xdp_input_node) (vlib_main_t * vm,
325                                   vlib_node_runtime_t * node,
326                                   vlib_frame_t * frame)
327 {
328   u32 n_rx = 0;
329   af_xdp_main_t *am = &af_xdp_main;
330   vnet_hw_if_rxq_poll_vector_t *p,
331     *pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
332
333   vec_foreach (p, pv)
334     {
335       af_xdp_device_t *ad = vec_elt_at_index (am->devices, p->dev_instance);
336       if ((ad->flags & AF_XDP_DEVICE_F_ADMIN_UP) == 0)
337         continue;
338       n_rx += af_xdp_device_input_inline (vm, node, frame, ad, p->queue_id);
339     }
340
341   return n_rx;
342 }
343
344 #ifndef CLIB_MARCH_VARIANT
345 void
346 af_xdp_device_input_refill (af_xdp_device_t *ad)
347 {
348   vlib_main_t *vm = vlib_get_main ();
349   af_xdp_rxq_t *rxq;
350   vec_foreach (rxq, ad->rxqs)
351     af_xdp_device_input_refill_inline (vm, 0, ad, rxq);
352 }
353 #endif /* CLIB_MARCH_VARIANT */
354
355 VLIB_REGISTER_NODE (af_xdp_input_node) = {
356   .name = "af_xdp-input",
357   .sibling_of = "device-input",
358   .format_trace = format_af_xdp_input_trace,
359   .type = VLIB_NODE_TYPE_INPUT,
360   .state = VLIB_NODE_STATE_DISABLED,
361   .n_errors = AF_XDP_INPUT_N_ERROR,
362   .error_strings = af_xdp_input_error_strings,
363   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
364 };
365
366 /*
367  * fd.io coding-style-patch-verification: ON
368  *
369  * Local Variables:
370  * eval: (c-set-style "gnu")
371  * End:
372  */