dpdk:fix mbuf index typo's
[vpp.git] / src / plugins / dpdk / device / node.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vnet/vnet.h>
16 #include <vppinfra/vec.h>
17 #include <vppinfra/error.h>
18 #include <vppinfra/format.h>
19 #include <vppinfra/xxhash.h>
20
21 #include <vnet/ethernet/ethernet.h>
22 #include <dpdk/device/dpdk.h>
23 #include <vnet/classify/vnet_classify.h>
24 #include <vnet/mpls/packet.h>
25 #include <vnet/handoff.h>
26 #include <vnet/devices/devices.h>
27 #include <vnet/feature/feature.h>
28
29 #include <dpdk/device/dpdk_priv.h>
30
31 #ifndef CLIB_MULTIARCH_VARIANT
32 static char *dpdk_error_strings[] = {
33 #define _(n,s) s,
34   foreach_dpdk_error
35 #undef _
36 };
37 #endif
38
39 STATIC_ASSERT (VNET_DEVICE_INPUT_NEXT_IP4_INPUT - 1 ==
40                VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT,
41                "IP4_INPUT must follow IP4_NCS_INPUT");
42
43 enum
44 {
45   DPDK_RX_F_CKSUM_GOOD = 7,
46   DPDK_RX_F_CKSUM_BAD = 4,
47   DPDK_RX_F_FDIR = 2,
48 };
49
50 /* currently we are just copying bit positions from DPDK, but that
51    might change in future, in case we strart to be interested in something
52    stored in upper bytes. Curently we store only lower byte for perf reasons */
53 STATIC_ASSERT (1 << DPDK_RX_F_CKSUM_GOOD == PKT_RX_IP_CKSUM_GOOD, "");
54 STATIC_ASSERT (1 << DPDK_RX_F_CKSUM_BAD == PKT_RX_IP_CKSUM_BAD, "");
55 STATIC_ASSERT (1 << DPDK_RX_F_FDIR == PKT_RX_FDIR, "");
56 STATIC_ASSERT ((PKT_RX_IP_CKSUM_GOOD | PKT_RX_IP_CKSUM_BAD | PKT_RX_FDIR) <
57                256, "dpdk flags not un lower byte, fix needed");
58
59 always_inline u32
60 dpdk_rx_next (vlib_node_runtime_t * node, u16 etype, u8 flags)
61 {
62   if (PREDICT_TRUE (etype == clib_host_to_net_u16 (ETHERNET_TYPE_IP4)))
63     {
64       /* keep it branchless */
65       u32 is_good = (flags >> DPDK_RX_F_CKSUM_GOOD) & 1;
66       return VNET_DEVICE_INPUT_NEXT_IP4_INPUT - is_good;
67     }
68   else if (PREDICT_TRUE (etype == clib_host_to_net_u16 (ETHERNET_TYPE_IP6)))
69     return VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
70   else if (PREDICT_TRUE (etype == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS)))
71     return VNET_DEVICE_INPUT_NEXT_MPLS_INPUT;
72   else
73     return VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
74 }
75
76 static_always_inline uword
77 dpdk_process_subseq_segs (vlib_main_t * vm, vlib_buffer_t * b,
78                           struct rte_mbuf * mb, vlib_buffer_free_list_t * fl)
79 {
80   u8 nb_seg = 1;
81   struct rte_mbuf *mb_seg = 0;
82   vlib_buffer_t *b_seg, *b_chain = 0;
83   mb_seg = mb->next;
84   b_chain = b;
85
86   if (mb->nb_segs < 2)
87     return 0;
88
89   b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
90   b->total_length_not_including_first_buffer = 0;
91
92   while (nb_seg < mb->nb_segs)
93     {
94       ASSERT (mb_seg != 0);
95
96       b_seg = vlib_buffer_from_rte_mbuf (mb_seg);
97       vlib_buffer_init_for_free_list (b_seg, fl);
98
99       ASSERT ((b_seg->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
100       ASSERT (b_seg->current_data == 0);
101
102       /*
103        * The driver (e.g. virtio) may not put the packet data at the start
104        * of the segment, so don't assume b_seg->current_data == 0 is correct.
105        */
106       b_seg->current_data =
107         (mb_seg->buf_addr + mb_seg->data_off) - (void *) b_seg->data;
108
109       b_seg->current_length = mb_seg->data_len;
110       b->total_length_not_including_first_buffer += mb_seg->data_len;
111
112       b_chain->flags |= VLIB_BUFFER_NEXT_PRESENT;
113       b_chain->next_buffer = vlib_get_buffer_index (vm, b_seg);
114
115       b_chain = b_seg;
116       mb_seg = mb_seg->next;
117       nb_seg++;
118     }
119   return b->total_length_not_including_first_buffer;
120 }
121
122 static_always_inline void
123 dpdk_prefetch_mbuf_x4 (struct rte_mbuf *mb[])
124 {
125   CLIB_PREFETCH (mb[0], CLIB_CACHE_LINE_BYTES, LOAD);
126   CLIB_PREFETCH (mb[1], CLIB_CACHE_LINE_BYTES, LOAD);
127   CLIB_PREFETCH (mb[2], CLIB_CACHE_LINE_BYTES, LOAD);
128   CLIB_PREFETCH (mb[3], CLIB_CACHE_LINE_BYTES, LOAD);
129 }
130
131 static_always_inline void
132 dpdk_prefetch_buffer_x4 (struct rte_mbuf *mb[])
133 {
134   vlib_buffer_t *b;
135   b = vlib_buffer_from_rte_mbuf (mb[0]);
136   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
137   b = vlib_buffer_from_rte_mbuf (mb[1]);
138   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
139   b = vlib_buffer_from_rte_mbuf (mb[2]);
140   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
141   b = vlib_buffer_from_rte_mbuf (mb[3]);
142   CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
143 }
144
145 static_always_inline void
146 dpdk_prefetch_buffer_data_x4 (struct rte_mbuf *mb[])
147 {
148   vlib_buffer_t *b;
149   b = vlib_buffer_from_rte_mbuf (mb[0]);
150   CLIB_PREFETCH (b->data, CLIB_CACHE_LINE_BYTES, LOAD);
151   b = vlib_buffer_from_rte_mbuf (mb[1]);
152   CLIB_PREFETCH (b->data, CLIB_CACHE_LINE_BYTES, LOAD);
153   b = vlib_buffer_from_rte_mbuf (mb[2]);
154   CLIB_PREFETCH (b->data, CLIB_CACHE_LINE_BYTES, LOAD);
155   b = vlib_buffer_from_rte_mbuf (mb[3]);
156   CLIB_PREFETCH (b->data, CLIB_CACHE_LINE_BYTES, LOAD);
157 }
158
159 static inline void
160 poll_rate_limit (dpdk_main_t * dm)
161 {
162   /* Limit the poll rate by sleeping for N msec between polls */
163   if (PREDICT_FALSE (dm->poll_sleep_usec != 0))
164     {
165       struct timespec ts, tsrem;
166
167       ts.tv_sec = 0;
168       ts.tv_nsec = 1000 * dm->poll_sleep_usec;
169
170       while (nanosleep (&ts, &tsrem) < 0)
171         {
172           ts = tsrem;
173         }
174     }
175 }
176
177 /** \brief Main DPDK input node
178     @node dpdk-input
179
180     This is the main DPDK input node: across each assigned interface,
181     call rte_eth_rx_burst(...) or similar to obtain a vector of
182     packets to process. Derive @c vlib_buffer_t metadata from
183     <code>struct rte_mbuf</code> metadata,
184     Depending on the resulting metadata: adjust <code>b->current_data,
185     b->current_length </code> and dispatch directly to
186     ip4-input-no-checksum, or ip6-input. Trace the packet if required.
187
188     @param vm   vlib_main_t corresponding to the current thread
189     @param node vlib_node_runtime_t
190     @param f    vlib_frame_t input-node, not used.
191
192     @par Graph mechanics: buffer metadata, next index usage
193
194     @em Uses:
195     - <code>struct rte_mbuf mb->ol_flags</code>
196         - PKT_RX_IP_CKSUM_BAD
197
198     @em Sets:
199     - <code>b->error</code> if the packet is to be dropped immediately
200     - <code>b->current_data, b->current_length</code>
201         - adjusted as needed to skip the L2 header in  direct-dispatch cases
202     - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
203         - rx interface sw_if_index
204     - <code>vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0</code>
205         - required by ipX-lookup
206     - <code>b->flags</code>
207         - to indicate multi-segment pkts (VLIB_BUFFER_NEXT_PRESENT), etc.
208
209     <em>Next Nodes:</em>
210     - Static arcs to: error-drop, ethernet-input,
211       ip4-input-no-checksum, ip6-input, mpls-input
212     - per-interface redirection, controlled by
213       <code>xd->per_interface_next_index</code>
214 */
215
216 static_always_inline void
217 dpdk_mbufs_to_buffer_indices (vlib_main_t * vm, struct rte_mbuf **mb,
218                               u32 * bi, uword n_left)
219 {
220 #ifdef CLIB_HAVE_VEC256
221   u32x8 mask = { 0, 2, 4, 6, 1, 3, 5, 7 };
222   u64x4 off4 = u64x4_splat (buffer_main.buffer_mem_start -
223                             sizeof (struct rte_mbuf));
224 #endif
225
226   while (n_left >= 8)
227     {
228 #ifdef CLIB_HAVE_VEC256
229       /* load 4 pointers into 256-bit register */
230       u64x4 v0 = u64x4_load_unaligned (mb);
231       u64x4 v1 = u64x4_load_unaligned (mb + 4);
232       u32x8 v2, v3;
233
234       /* calculate 4 buffer indices in parallel
235          vlib_buffer_t is straight after rte_mbuf so advance all 4
236          pointers for size of rte_mbuf */
237       v0 -= off4;
238       v1 -= off4;
239
240       v0 >>= CLIB_LOG2_CACHE_LINE_BYTES;
241       v1 >>= CLIB_LOG2_CACHE_LINE_BYTES;
242
243       /* permute 256-bit register so lower u32s of each buffer index are
244        * placed into lower 128-bits */
245       v2 = u32x8_permute ((u32x8) v0, mask);
246       v3 = u32x8_permute ((u32x8) v1, mask);
247
248       /* extract lower 128-bits and save them to the array of buffer indices */
249       u32x4_store_unaligned (u32x8_extract_lo (v2), bi);
250       u32x4_store_unaligned (u32x8_extract_lo (v3), bi + 4);
251 #else
252       /* equivalent non-nector implementation */
253       bi[0] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[0]));
254       bi[1] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[1]));
255       bi[2] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[2]));
256       bi[3] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[3]));
257       bi[4] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[4]));
258       bi[5] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[5]));
259       bi[6] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[6]));
260       bi[7] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[7]));
261 #endif
262       bi += 8;
263       mb += 8;
264       n_left -= 8;
265     }
266   while (n_left)
267     {
268       bi[0] = vlib_get_buffer_index (vm, vlib_buffer_from_rte_mbuf (mb[0]));
269       bi += 1;
270       mb += 1;
271       n_left -= 1;
272     }
273 }
274
275 static_always_inline u8
276 dpdk_ol_flags_extract (struct rte_mbuf **mb, u8 * flags, int count)
277 {
278   u8 rv = 0;
279   int i;
280   for (i = 0; i < count; i++)
281     {
282       /* all flags we are interested in are in lower 8 bits but
283          that might change */
284       flags[i] = (u8) mb[i]->ol_flags;
285       rv |= flags[i];
286     }
287   return rv;
288 }
289
290 static_always_inline uword
291 dpdk_process_rx_burst (vlib_main_t * vm, dpdk_per_thread_data_t * ptd,
292                        uword n_rx_packets, int maybe_multiseg, u8 * or_flagsp)
293 {
294   u32 n_left = n_rx_packets;
295   vlib_buffer_t *b[4];
296   vlib_buffer_free_list_t *fl;
297   struct rte_mbuf **mb = ptd->mbufs;
298   uword n_bytes = 0;
299   i16 off;
300   u8 *flags, or_flags = 0;
301   u16 *next;
302
303   fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
304
305   mb = ptd->mbufs;
306   flags = ptd->flags;
307   next = ptd->next;
308
309   while (n_left >= 8)
310     {
311       CLIB_PREFETCH (mb + 8, CLIB_CACHE_LINE_BYTES, LOAD);
312
313       dpdk_prefetch_buffer_x4 (mb + 4);
314
315       b[0] = vlib_buffer_from_rte_mbuf (mb[0]);
316       b[1] = vlib_buffer_from_rte_mbuf (mb[1]);
317       b[2] = vlib_buffer_from_rte_mbuf (mb[2]);
318       b[3] = vlib_buffer_from_rte_mbuf (mb[3]);
319
320       clib_memcpy64_x4 (b[0], b[1], b[2], b[3], &ptd->buffer_template);
321
322       dpdk_prefetch_mbuf_x4 (mb + 4);
323
324       or_flags |= dpdk_ol_flags_extract (mb, flags, 4);
325       flags += 4;
326
327       /* we temporary store relative offset of ethertype into next[x]
328          so we can prefetch and get it faster later */
329
330       off = mb[0]->data_off;
331       next[0] = off + STRUCT_OFFSET_OF (ethernet_header_t, type);
332       off -= RTE_PKTMBUF_HEADROOM;
333       vnet_buffer (b[0])->l2_hdr_offset = off;
334       b[0]->current_data = off;
335
336       off = mb[1]->data_off;
337       next[1] = off + STRUCT_OFFSET_OF (ethernet_header_t, type);
338       off -= RTE_PKTMBUF_HEADROOM;
339       vnet_buffer (b[1])->l2_hdr_offset = off;
340       b[1]->current_data = off;
341
342       off = mb[2]->data_off;
343       next[2] = off + STRUCT_OFFSET_OF (ethernet_header_t, type);
344       off -= RTE_PKTMBUF_HEADROOM;
345       vnet_buffer (b[2])->l2_hdr_offset = off;
346       b[2]->current_data = off;
347
348       off = mb[3]->data_off;
349       next[3] = off + STRUCT_OFFSET_OF (ethernet_header_t, type);
350       off -= RTE_PKTMBUF_HEADROOM;
351       vnet_buffer (b[3])->l2_hdr_offset = off;
352       b[3]->current_data = off;
353
354       b[0]->current_length = mb[0]->data_len;
355       b[1]->current_length = mb[1]->data_len;
356       b[2]->current_length = mb[2]->data_len;
357       b[3]->current_length = mb[3]->data_len;
358
359       n_bytes += mb[0]->data_len;
360       n_bytes += mb[1]->data_len;
361       n_bytes += mb[2]->data_len;
362       n_bytes += mb[3]->data_len;
363
364       if (maybe_multiseg)
365         {
366           n_bytes += dpdk_process_subseq_segs (vm, b[0], mb[0], fl);
367           n_bytes += dpdk_process_subseq_segs (vm, b[1], mb[1], fl);
368           n_bytes += dpdk_process_subseq_segs (vm, b[2], mb[2], fl);
369           n_bytes += dpdk_process_subseq_segs (vm, b[3], mb[3], fl);
370         }
371
372       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
373       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
374       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
375       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
376
377       /* next */
378       mb += 4;
379       n_left -= 4;
380       next += 4;
381     }
382
383   while (n_left)
384     {
385       b[0] = vlib_buffer_from_rte_mbuf (mb[0]);
386       clib_memcpy (b[0], &ptd->buffer_template, 64);
387       or_flags |= dpdk_ol_flags_extract (mb, flags, 1);
388       flags += 1;
389
390       off = mb[0]->data_off;
391       next[0] = off + STRUCT_OFFSET_OF (ethernet_header_t, type);
392       off -= RTE_PKTMBUF_HEADROOM;
393       vnet_buffer (b[0])->l2_hdr_offset = off;
394       b[0]->current_data = off;
395       b[0]->current_length = mb[0]->data_len;
396       n_bytes += mb[0]->data_len;
397       if (maybe_multiseg)
398         n_bytes += dpdk_process_subseq_segs (vm, b[0], mb[0], fl);
399       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
400
401       /* next */
402       mb += 1;
403       n_left -= 1;
404       next += 1;
405     }
406
407   *or_flagsp = or_flags;
408   return n_bytes;
409 }
410
411 static_always_inline void
412 dpdk_set_next_from_etype (vlib_main_t * vm, vlib_node_runtime_t * node,
413                           dpdk_per_thread_data_t * ptd, uword n_rx_packets)
414 {
415   vlib_buffer_t *b[4];
416   i16 adv[4];
417   u16 etype[4];
418   struct rte_mbuf **mb = ptd->mbufs;
419   u8 *flags = ptd->flags;
420   u16 *next = ptd->next;
421   u32 n_left = n_rx_packets;
422
423   while (n_left >= 12)
424     {
425       dpdk_prefetch_buffer_data_x4 (mb + 8);
426       dpdk_prefetch_buffer_x4 (mb + 8);
427
428       b[0] = vlib_buffer_from_rte_mbuf (mb[0]);
429       b[1] = vlib_buffer_from_rte_mbuf (mb[1]);
430       b[2] = vlib_buffer_from_rte_mbuf (mb[2]);
431       b[3] = vlib_buffer_from_rte_mbuf (mb[3]);
432       etype[0] = *(u16 *) ((u8 *) mb[0] + next[0] + sizeof (vlib_buffer_t));
433       etype[1] = *(u16 *) ((u8 *) mb[1] + next[1] + sizeof (vlib_buffer_t));
434       etype[2] = *(u16 *) ((u8 *) mb[2] + next[2] + sizeof (vlib_buffer_t));
435       etype[3] = *(u16 *) ((u8 *) mb[3] + next[3] + sizeof (vlib_buffer_t));
436       next[0] = dpdk_rx_next (node, etype[0], flags[0]);
437       next[1] = dpdk_rx_next (node, etype[1], flags[1]);
438       next[2] = dpdk_rx_next (node, etype[2], flags[2]);
439       next[3] = dpdk_rx_next (node, etype[3], flags[3]);
440       adv[0] = device_input_next_node_advance[next[0]];
441       adv[1] = device_input_next_node_advance[next[1]];
442       adv[2] = device_input_next_node_advance[next[2]];
443       adv[3] = device_input_next_node_advance[next[3]];
444       b[0]->current_data += adv[0];
445       b[1]->current_data += adv[1];
446       b[2]->current_data += adv[2];
447       b[3]->current_data += adv[3];
448       b[0]->current_length -= adv[0];
449       b[1]->current_length -= adv[1];
450       b[2]->current_length -= adv[2];
451       b[3]->current_length -= adv[3];
452
453       /* next */
454       next += 4;
455       mb += 4;
456       n_left -= 4;
457       flags += 4;
458     }
459
460   while (n_left)
461     {
462       b[0] = vlib_buffer_from_rte_mbuf (mb[0]);
463       next[0] = *(u16 *) ((u8 *) mb[0] + next[0] + sizeof (vlib_buffer_t));
464       next[0] = dpdk_rx_next (node, next[0], flags[0]);
465       adv[0] = device_input_next_node_advance[next[0]];
466       b[0]->current_data += adv[0];
467       b[0]->current_length -= adv[0];
468
469       /* next */
470       next += 1;
471       mb += 1;
472       n_left -= 1;
473       flags += 1;
474     }
475 }
476
477 static_always_inline u32
478 dpdk_device_input (vlib_main_t * vm, dpdk_main_t * dm, dpdk_device_t * xd,
479                    vlib_node_runtime_t * node, u32 thread_index, u16 queue_id)
480 {
481   uword n_rx_packets = 0, n_rx_bytes;
482   u32 n_left, n_trace;
483   u32 *buffers;
484   u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
485   struct rte_mbuf **mb;
486   vlib_buffer_t *b0;
487   int known_next = 0;
488   u16 *next;
489   u8 or_flags;
490   u32 n;
491
492   dpdk_per_thread_data_t *ptd = vec_elt_at_index (dm->per_thread_data,
493                                                   thread_index);
494   vlib_buffer_t *bt = &ptd->buffer_template;
495
496   if ((xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP) == 0)
497     return 0;
498
499   /* get up to DPDK_RX_BURST_SZ buffers from PMD */
500   while (n_rx_packets < DPDK_RX_BURST_SZ)
501     {
502       n = rte_eth_rx_burst (xd->device_index, queue_id,
503                             ptd->mbufs + n_rx_packets,
504                             DPDK_RX_BURST_SZ - n_rx_packets);
505       n_rx_packets += n;
506
507       if (n < 32)
508         break;
509     }
510
511   if (n_rx_packets == 0)
512     return 0;
513
514   /* Update buffer template */
515   vnet_buffer (bt)->sw_if_index[VLIB_RX] = xd->sw_if_index;
516   bt->error = node->errors[DPDK_ERROR_NONE];
517   /* as DPDK is allocating empty buffers from mempool provided before interface
518      start for each queue, it is safe to store this in the template */
519   bt->buffer_pool_index = xd->buffer_pool_for_queue[queue_id];
520
521   /* receive burst of packets from DPDK PMD */
522   if (PREDICT_FALSE (xd->per_interface_next_index != ~0))
523     {
524       known_next = 1;
525       next_index = xd->per_interface_next_index;
526     }
527
528   /* as all packets belong to thr same interface feature arc lookup
529      can be don once and result stored in the buffer template */
530   if (PREDICT_FALSE (vnet_device_input_have_features (xd->sw_if_index)))
531     {
532       vnet_feature_start_device_input_x1 (xd->sw_if_index, &next_index, bt);
533       known_next = 1;
534     }
535
536   if (xd->flags & DPDK_DEVICE_FLAG_MAYBE_MULTISEG)
537     n_rx_bytes = dpdk_process_rx_burst (vm, ptd, n_rx_packets, 1, &or_flags);
538   else
539     n_rx_bytes = dpdk_process_rx_burst (vm, ptd, n_rx_packets, 0, &or_flags);
540
541   if (PREDICT_FALSE (known_next))
542     {
543       for (n = 0; n < n_rx_packets; n++)
544         ptd->next[n] = next_index;
545
546       vnet_buffer (bt)->feature_arc_index = 0;
547       bt->current_config_index = 0;
548     }
549   else
550     dpdk_set_next_from_etype (vm, node, ptd, n_rx_packets);
551
552   /* is at least one packet marked as ip4 checksum bad? */
553   if (PREDICT_FALSE (or_flags & (1 << DPDK_RX_F_CKSUM_BAD)))
554     for (n = 0; n < n_rx_packets; n++)
555       {
556         if ((ptd->flags[n] & (1 << DPDK_RX_F_CKSUM_BAD)) == 0)
557           continue;
558         if (ptd->next[n] != VNET_DEVICE_INPUT_NEXT_IP4_INPUT)
559           continue;
560
561         b0 = vlib_buffer_from_rte_mbuf (ptd->mbufs[n]);
562         b0->error = node->errors[DPDK_ERROR_IP_CHECKSUM_ERROR];
563         ptd->next[n] = VNET_DEVICE_INPUT_NEXT_DROP;
564       }
565
566   /* enqueue buffers to the next node */
567   dpdk_mbufs_to_buffer_indices (vm, ptd->mbufs, ptd->buffers, n_rx_packets);
568   n_left = n_rx_packets;
569   next = ptd->next;
570   buffers = ptd->buffers;
571   mb = ptd->mbufs;
572   while (n_left)
573     {
574       u32 n_left_to_next;
575       u32 *to_next;
576       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
577 #ifdef CLIB_HAVE_VEC256
578       while (n_left >= 16 && n_left_to_next >= 16)
579         {
580           u16x16 next16 = u16x16_load_unaligned (next);
581           if (u16x16_is_all_equal (next16, next_index))
582             {
583               clib_memcpy (to_next, buffers, 16 * sizeof (u32));
584               to_next += 16;
585               n_left_to_next -= 16;
586               buffers += 16;
587               n_left -= 16;
588               next += 16;
589               mb += 16;
590             }
591           else
592             {
593               clib_memcpy (to_next, buffers, 4 * sizeof (u32));
594               to_next += 4;
595               n_left_to_next -= 4;
596
597               vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
598                                                n_left_to_next, buffers[0],
599                                                buffers[1], buffers[2],
600                                                buffers[3], next[0], next[1],
601                                                next[2], next[3]);
602               /* next */
603               buffers += 4;
604               n_left -= 4;
605               next += 4;
606               mb += 4;
607             }
608         }
609 #endif
610       while (n_left >= 4 && n_left_to_next >= 4)
611         {
612           clib_memcpy (to_next, buffers, 4 * sizeof (u32));
613           to_next += 4;
614           n_left_to_next -= 4;
615
616           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
617                                            n_left_to_next, buffers[0],
618                                            buffers[1], buffers[2], buffers[3],
619                                            next[0], next[1], next[2],
620                                            next[3]);
621           /* next */
622           buffers += 4;
623           n_left -= 4;
624           next += 4;
625           mb += 4;
626         }
627       while (n_left && n_left_to_next)
628         {
629           clib_memcpy (to_next, buffers, 1 * sizeof (u32));
630           to_next += 1;
631           n_left_to_next -= 1;
632           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
633                                            n_left_to_next, buffers[0],
634                                            next[0]);
635           /* next */
636           buffers += 1;
637           n_left -= 1;
638           next += 1;
639           mb += 1;
640         }
641       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
642     }
643
644   /* packet trace if enabled */
645   if ((n_trace = vlib_get_trace_count (vm, node)))
646     {
647       n_left = n_rx_packets;
648       buffers = ptd->buffers;
649       mb = ptd->mbufs;
650       next = ptd->next;
651       while (n_trace && n_left)
652         {
653           b0 = vlib_get_buffer (vm, buffers[0]);
654           vlib_trace_buffer (vm, node, next[0], b0, /* follow_chain */ 0);
655
656           dpdk_rx_trace_t *t0 = vlib_add_trace (vm, node, b0, sizeof t0[0]);
657           t0->queue_index = queue_id;
658           t0->device_index = xd->device_index;
659           t0->buffer_index = vlib_get_buffer_index (vm, b0);
660
661           clib_memcpy (&t0->mb, mb[0], sizeof t0->mb);
662           clib_memcpy (&t0->buffer, b0, sizeof b0[0] - sizeof b0->pre_data);
663           clib_memcpy (t0->buffer.pre_data, b0->data,
664                        sizeof t0->buffer.pre_data);
665           clib_memcpy (&t0->data, mb[0]->buf_addr + mb[0]->data_off,
666                        sizeof t0->data);
667           n_trace--;
668           n_left--;
669           buffers++;
670           mb++;
671           next++;
672         }
673       vlib_set_trace_count (vm, node, n_trace);
674     }
675
676   vlib_increment_combined_counter
677     (vnet_get_main ()->interface_main.combined_sw_if_counters
678      + VNET_INTERFACE_COUNTER_RX, thread_index, xd->sw_if_index,
679      n_rx_packets, n_rx_bytes);
680
681   vnet_device_increment_rx_packets (thread_index, n_rx_packets);
682
683   return n_rx_packets;
684 }
685
686 uword CLIB_CPU_OPTIMIZED
687 CLIB_MULTIARCH_FN (dpdk_input) (vlib_main_t * vm, vlib_node_runtime_t * node,
688                                 vlib_frame_t * f)
689 {
690   dpdk_main_t *dm = &dpdk_main;
691   dpdk_device_t *xd;
692   uword n_rx_packets = 0;
693   vnet_device_input_runtime_t *rt = (void *) node->runtime_data;
694   vnet_device_and_queue_t *dq;
695   u32 thread_index = node->thread_index;
696
697   /*
698    * Poll all devices on this cpu for input/interrupts.
699    */
700   /* *INDENT-OFF* */
701   foreach_device_and_queue (dq, rt->devices_and_queues)
702     {
703       xd = vec_elt_at_index(dm->devices, dq->dev_instance);
704       if (PREDICT_FALSE (xd->flags & DPDK_DEVICE_FLAG_BOND_SLAVE))
705         continue;       /* Do not poll slave to a bonded interface */
706       n_rx_packets += dpdk_device_input (vm, dm, xd, node, thread_index,
707                                          dq->queue_id);
708     }
709   /* *INDENT-ON* */
710
711   poll_rate_limit (dm);
712
713   return n_rx_packets;
714 }
715
716 #ifndef CLIB_MULTIARCH_VARIANT
717 /* *INDENT-OFF* */
718 VLIB_REGISTER_NODE (dpdk_input_node) = {
719   .function = dpdk_input,
720   .type = VLIB_NODE_TYPE_INPUT,
721   .name = "dpdk-input",
722   .sibling_of = "device-input",
723
724   /* Will be enabled if/when hardware is detected. */
725   .state = VLIB_NODE_STATE_DISABLED,
726
727   .format_buffer = format_ethernet_header_with_length,
728   .format_trace = format_dpdk_rx_trace,
729
730   .n_errors = DPDK_N_ERROR,
731   .error_strings = dpdk_error_strings,
732 };
733 /* *INDENT-ON* */
734
735 vlib_node_function_t __clib_weak dpdk_input_avx512;
736 vlib_node_function_t __clib_weak dpdk_input_avx2;
737
738 #if __x86_64__
739 static void __clib_constructor
740 dpdk_input_multiarch_select (void)
741 {
742   if (dpdk_input_avx512 && clib_cpu_supports_avx512f ())
743     dpdk_input_node.function = dpdk_input_avx512;
744   else if (dpdk_input_avx2 && clib_cpu_supports_avx2 ())
745     dpdk_input_node.function = dpdk_input_avx2;
746 }
747 #endif
748 #endif
749
750 /*
751  * fd.io coding-style-patch-verification: ON
752  *
753  * Local Variables:
754  * eval: (c-set-style "gnu")
755  * End:
756  */