Line data Source code
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 0 : 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 0 : u32 n_trace = vlib_get_trace_count (vm, node);
50 :
51 0 : if (PREDICT_TRUE (0 == n_trace))
52 0 : return;
53 :
54 0 : while (n_trace && n_left)
55 : {
56 0 : vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
57 0 : if (PREDICT_TRUE
58 : (vlib_trace_buffer (vm, node, next_index, b, /* follow_chain */ 0)))
59 : {
60 : af_xdp_input_trace_t *tr =
61 0 : vlib_add_trace (vm, node, b, sizeof (*tr));
62 0 : tr->next_index = next_index;
63 0 : tr->hw_if_index = hw_if_index;
64 0 : n_trace--;
65 : }
66 0 : n_left--;
67 0 : bi++;
68 : }
69 :
70 0 : vlib_set_trace_count (vm, node, n_trace);
71 : }
72 :
73 : static_always_inline void
74 0 : 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 0 : xsk_ring_prod__submit (&rxq->fq, n_alloc);
80 :
81 0 : if (AF_XDP_RXQ_MODE_INTERRUPT == rxq->mode ||
82 0 : !xsk_ring_prod__needs_wakeup (&rxq->fq))
83 0 : return;
84 :
85 0 : if (node)
86 0 : vlib_error_count (vm, node->node_index,
87 : AF_XDP_INPUT_ERROR_SYSCALL_REQUIRED, 1);
88 :
89 0 : if (clib_spinlock_trylock_if_init (&rxq->syscall_lock))
90 : {
91 0 : int ret = recvmsg (rxq->xsk_fd, 0, MSG_DONTWAIT);
92 0 : clib_spinlock_unlock_if_init (&rxq->syscall_lock);
93 0 : if (PREDICT_FALSE (ret < 0))
94 : {
95 : /* something bad is happening */
96 0 : if (node)
97 0 : vlib_error_count (vm, node->node_index,
98 : AF_XDP_INPUT_ERROR_SYSCALL_FAILURES, 1);
99 0 : af_xdp_device_error (ad, "rx poll() failed");
100 : }
101 : }
102 : }
103 :
104 : static_always_inline void
105 0 : 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 0 : const u32 size = rxq->fq.size;
111 0 : const u32 mask = size - 1;
112 0 : u32 bis[VLIB_FRAME_SIZE], *bi = bis;
113 : u32 n_alloc, n, n_wrap;
114 0 : u32 idx = 0;
115 :
116 0 : ASSERT (mask == rxq->fq.mask);
117 :
118 : /* do not enqueue more packet than ring space */
119 0 : n_alloc = xsk_prod_nb_free (&rxq->fq, 16);
120 : /* do not bother to allocate if too small */
121 0 : if (n_alloc < 16)
122 0 : return;
123 :
124 0 : n_alloc = clib_min (n_alloc, ARRAY_LEN (bis));
125 0 : n_alloc = vlib_buffer_alloc_from_pool (vm, bis, n_alloc, ad->pool);
126 0 : n = xsk_ring_prod__reserve (&rxq->fq, n_alloc, &idx);
127 0 : ASSERT (n == n_alloc);
128 :
129 0 : fill = xsk_ring_prod__fill_addr (&rxq->fq, idx);
130 0 : n = clib_min (n_alloc, size - (idx & mask));
131 0 : n_wrap = n_alloc - n;
132 :
133 : #define bi2addr(bi) ((bi) << CLIB_LOG2_CACHE_LINE_BYTES)
134 :
135 0 : wrap_around:
136 :
137 0 : while (n >= 8)
138 : {
139 : #ifdef CLIB_HAVE_VEC256
140 0 : u64x4 b0 = u64x4_from_u32x4 (*(u32x4u *) (bi + 0));
141 0 : u64x4 b1 = u64x4_from_u32x4 (*(u32x4u *) (bi + 4));
142 0 : *(u64x4u *) (fill + 0) = bi2addr (b0);
143 0 : *(u64x4u *) (fill + 4) = bi2addr (b1);
144 : #else
145 0 : fill[0] = bi2addr (bi[0]);
146 0 : fill[1] = bi2addr (bi[1]);
147 0 : fill[2] = bi2addr (bi[2]);
148 0 : fill[3] = bi2addr (bi[3]);
149 0 : fill[4] = bi2addr (bi[4]);
150 0 : fill[5] = bi2addr (bi[5]);
151 0 : fill[6] = bi2addr (bi[6]);
152 0 : fill[7] = bi2addr (bi[7]);
153 : #endif
154 0 : fill += 8;
155 0 : bi += 8;
156 0 : n -= 8;
157 : }
158 :
159 0 : while (n >= 1)
160 : {
161 0 : fill[0] = bi2addr (bi[0]);
162 0 : fill += 1;
163 0 : bi += 1;
164 0 : n -= 1;
165 : }
166 :
167 0 : if (n_wrap)
168 : {
169 0 : fill = xsk_ring_prod__fill_addr (&rxq->fq, 0);
170 0 : n = n_wrap;
171 0 : n_wrap = 0;
172 0 : goto wrap_around;
173 : }
174 :
175 0 : af_xdp_device_input_refill_db (vm, node, ad, rxq, n_alloc);
176 : }
177 :
178 : static_always_inline void
179 0 : 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 0 : if (PREDICT_FALSE (VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT != next_index))
188 0 : return;
189 :
190 : nf =
191 0 : vlib_node_runtime_get_next_frame (vm, node,
192 : VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT);
193 0 : f = vlib_get_frame (vm, nf->frame);
194 0 : f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
195 :
196 0 : ef = vlib_frame_scalar_args (f);
197 0 : ef->sw_if_index = sw_if_index;
198 0 : ef->hw_if_index = hw_if_index;
199 0 : vlib_frame_no_append (f);
200 : }
201 :
202 : static_always_inline u32
203 0 : 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 0 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
208 0 : u16 offs[VLIB_FRAME_SIZE], *off = offs;
209 0 : u16 lens[VLIB_FRAME_SIZE], *len = lens;
210 0 : const u32 mask = rxq->rx.mask;
211 0 : u32 n = n_rx, *bi = bis, bytes = 0;
212 :
213 : #define addr2bi(addr) ((addr) >> CLIB_LOG2_CACHE_LINE_BYTES)
214 :
215 0 : while (n >= 1)
216 : {
217 0 : const struct xdp_desc *desc = xsk_ring_cons__rx_desc (&rxq->rx, idx);
218 0 : const u64 addr = desc->addr;
219 0 : bi[0] = addr2bi (xsk_umem__extract_addr (addr));
220 0 : ASSERT (vlib_buffer_is_known (vm, bi[0]) ==
221 : VLIB_BUFFER_KNOWN_ALLOCATED);
222 0 : off[0] = xsk_umem__extract_offset (addr) - sizeof (vlib_buffer_t);
223 0 : len[0] = desc->len;
224 0 : idx = (idx + 1) & mask;
225 0 : bi += 1;
226 0 : off += 1;
227 0 : len += 1;
228 0 : n -= 1;
229 : }
230 :
231 0 : vlib_get_buffers (vm, bis, bufs, n_rx);
232 :
233 0 : n = n_rx;
234 0 : off = offs;
235 0 : len = lens;
236 :
237 0 : while (n >= 8)
238 : {
239 0 : vlib_prefetch_buffer_header (b[4], LOAD);
240 0 : vlib_buffer_copy_template (b[0], bt);
241 0 : b[0]->current_data = off[0];
242 0 : bytes += b[0]->current_length = len[0];
243 :
244 0 : vlib_prefetch_buffer_header (b[5], LOAD);
245 0 : vlib_buffer_copy_template (b[1], bt);
246 0 : b[1]->current_data = off[1];
247 0 : bytes += b[1]->current_length = len[1];
248 :
249 0 : vlib_prefetch_buffer_header (b[6], LOAD);
250 0 : vlib_buffer_copy_template (b[2], bt);
251 0 : b[2]->current_data = off[2];
252 0 : bytes += b[2]->current_length = len[2];
253 :
254 0 : vlib_prefetch_buffer_header (b[7], LOAD);
255 0 : vlib_buffer_copy_template (b[3], bt);
256 0 : b[3]->current_data = off[3];
257 0 : bytes += b[3]->current_length = len[3];
258 :
259 0 : b += 4;
260 0 : off += 4;
261 0 : len += 4;
262 0 : n -= 4;
263 : }
264 :
265 0 : while (n >= 1)
266 : {
267 0 : vlib_buffer_copy_template (b[0], bt);
268 0 : b[0]->current_data = off[0];
269 0 : bytes += b[0]->current_length = len[0];
270 0 : b += 1;
271 0 : off += 1;
272 0 : len += 1;
273 0 : n -= 1;
274 : }
275 :
276 0 : xsk_ring_cons__release (&rxq->rx, n_rx);
277 0 : return bytes;
278 : }
279 :
280 : static_always_inline uword
281 0 : 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 0 : vnet_main_t *vnm = vnet_get_main ();
285 0 : 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 0 : n_rx_packets = xsk_ring_cons__peek (&rxq->rx, VLIB_FRAME_SIZE, &idx);
292 :
293 0 : if (PREDICT_FALSE (0 == n_rx_packets))
294 0 : goto refill;
295 :
296 0 : vlib_buffer_copy_template (&bt, ad->buffer_template);
297 0 : next_index = ad->per_interface_next_index;
298 0 : if (PREDICT_FALSE (vnet_device_input_have_features (ad->sw_if_index)))
299 0 : vnet_feature_start_device_input_x1 (ad->sw_if_index, &next_index, &bt);
300 :
301 0 : vlib_get_new_next_frame (vm, node, next_index, to_next, n_left_to_next);
302 :
303 : n_rx_bytes =
304 0 : af_xdp_device_input_bufs (vm, ad, rxq, to_next, n_rx_packets, &bt, idx);
305 0 : af_xdp_device_input_ethernet (vm, node, next_index, ad->sw_if_index,
306 : ad->hw_if_index);
307 :
308 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next - n_rx_packets);
309 :
310 0 : af_xdp_device_input_trace (vm, node, n_rx_packets, to_next, next_index,
311 : ad->hw_if_index);
312 :
313 0 : 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 0 : refill:
319 0 : af_xdp_device_input_refill_inline (vm, node, ad, rxq);
320 :
321 0 : return n_rx_packets;
322 : }
323 :
324 2236 : VLIB_NODE_FN (af_xdp_input_node) (vlib_main_t * vm,
325 : vlib_node_runtime_t * node,
326 : vlib_frame_t * frame)
327 : {
328 0 : u32 n_rx = 0;
329 0 : af_xdp_main_t *am = &af_xdp_main;
330 : vnet_hw_if_rxq_poll_vector_t *p,
331 0 : *pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
332 :
333 0 : vec_foreach (p, pv)
334 : {
335 0 : af_xdp_device_t *ad = vec_elt_at_index (am->devices, p->dev_instance);
336 0 : if ((ad->flags & AF_XDP_DEVICE_F_ADMIN_UP) == 0)
337 0 : continue;
338 0 : n_rx += af_xdp_device_input_inline (vm, node, frame, ad, p->queue_id);
339 : }
340 :
341 0 : return n_rx;
342 : }
343 :
344 : #ifndef CLIB_MARCH_VARIANT
345 : void
346 0 : af_xdp_device_input_refill (af_xdp_device_t *ad)
347 : {
348 0 : vlib_main_t *vm = vlib_get_main ();
349 : af_xdp_rxq_t *rxq;
350 0 : vec_foreach (rxq, ad->rxqs)
351 0 : af_xdp_device_input_refill_inline (vm, 0, ad, rxq);
352 0 : }
353 : #endif /* CLIB_MARCH_VARIANT */
354 :
355 : /* *INDENT-OFF* */
356 166920 : VLIB_REGISTER_NODE (af_xdp_input_node) = {
357 : .name = "af_xdp-input",
358 : .sibling_of = "device-input",
359 : .format_trace = format_af_xdp_input_trace,
360 : .type = VLIB_NODE_TYPE_INPUT,
361 : .state = VLIB_NODE_STATE_DISABLED,
362 : .n_errors = AF_XDP_INPUT_N_ERROR,
363 : .error_strings = af_xdp_input_error_strings,
364 : .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
365 : };
366 : /* *INDENT-ON* */
367 :
368 : /*
369 : * fd.io coding-style-patch-verification: ON
370 : *
371 : * Local Variables:
372 : * eval: (c-set-style "gnu")
373 : * End:
374 : */
|