+ /* receive burst of packets from DPDK PMD */
+ if (PREDICT_FALSE (xd->per_interface_next_index != ~0))
+ {
+ known_next = 1;
+ next_index = xd->per_interface_next_index;
+ }
+
+ /* as all packets belong to the same interface feature arc lookup
+ can be don once and result stored in the buffer template */
+ if (PREDICT_FALSE (vnet_device_input_have_features (xd->sw_if_index)))
+ {
+ vnet_feature_start_device_input_x1 (xd->sw_if_index, &next_index, bt);
+ known_next = 1;
+ }
+
+ if (xd->flags & DPDK_DEVICE_FLAG_MAYBE_MULTISEG)
+ n_rx_bytes = dpdk_process_rx_burst (vm, ptd, n_rx_packets, 1, &or_flags);
+ else
+ n_rx_bytes = dpdk_process_rx_burst (vm, ptd, n_rx_packets, 0, &or_flags);
+
+ if (PREDICT_FALSE (known_next))
+ {
+ for (n = 0; n < n_rx_packets; n++)
+ ptd->next[n] = next_index;
+
+ vnet_buffer (bt)->feature_arc_index = 0;
+ bt->current_config_index = 0;
+ }
+ else
+ dpdk_set_next_from_etype (vm, node, ptd, n_rx_packets);
+
+ /* flow offload - process if rx flow offlaod enabled and at least one packet
+ is marked */
+ if (PREDICT_FALSE ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) &&
+ (or_flags & (1 << DPDK_RX_F_FDIR))))
+ dpdk_process_flow_offload (xd, ptd, n_rx_packets);
+
+ /* is at least one packet marked as ip4 checksum bad? */
+ if (PREDICT_FALSE (or_flags & (1 << DPDK_RX_F_CKSUM_BAD)))
+ for (n = 0; n < n_rx_packets; n++)
+ {
+ if ((ptd->flags[n] & (1 << DPDK_RX_F_CKSUM_BAD)) == 0)
+ continue;
+ if (ptd->next[n] != VNET_DEVICE_INPUT_NEXT_IP4_INPUT)
+ continue;
+
+ b0 = vlib_buffer_from_rte_mbuf (ptd->mbufs[n]);
+ b0->error = node->errors[DPDK_ERROR_IP_CHECKSUM_ERROR];
+ ptd->next[n] = VNET_DEVICE_INPUT_NEXT_DROP;
+ }
+
+ /* enqueue buffers to the next node */
+ vlib_get_buffer_indices_with_offset (vm, (void **) ptd->mbufs, ptd->buffers,
+ n_rx_packets,
+ sizeof (struct rte_mbuf));
+
+ vlib_buffer_enqueue_to_next (vm, node, ptd->buffers, ptd->next,
+ n_rx_packets);
+
+ /* packet trace if enabled */
+ if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
+ {
+ n_left = n_rx_packets;
+ buffers = ptd->buffers;
+ mb = ptd->mbufs;
+ next = ptd->next;
+ while (n_trace && n_left)
+ {
+ b0 = vlib_get_buffer (vm, buffers[0]);
+ vlib_trace_buffer (vm, node, next[0], b0, /* follow_chain */ 0);
+
+ dpdk_rx_trace_t *t0 = vlib_add_trace (vm, node, b0, sizeof t0[0]);
+ t0->queue_index = queue_id;
+ t0->device_index = xd->device_index;
+ t0->buffer_index = vlib_get_buffer_index (vm, b0);
+
+ clib_memcpy (&t0->mb, mb[0], sizeof t0->mb);
+ clib_memcpy (&t0->buffer, b0, sizeof b0[0] - sizeof b0->pre_data);
+ clib_memcpy (t0->buffer.pre_data, b0->data,
+ sizeof t0->buffer.pre_data);
+ clib_memcpy (&t0->data, mb[0]->buf_addr + mb[0]->data_off,
+ sizeof t0->data);
+ n_trace--;
+ n_left--;
+ buffers++;
+ mb++;
+ next++;
+ }
+ vlib_set_trace_count (vm, node, n_trace);
+ }
+
+ /* rx pcap capture if enabled */
+ if (PREDICT_FALSE (dm->pcap[VLIB_RX].pcap_enable))
+ {
+ u32 bi0;
+ n_left = n_rx_packets;
+ buffers = ptd->buffers;
+ while (n_left)
+ {
+ bi0 = buffers[0];
+ b0 = vlib_get_buffer (vm, bi0);
+ buffers++;
+
+ if (dm->pcap[VLIB_RX].pcap_sw_if_index == 0 ||
+ dm->pcap[VLIB_RX].pcap_sw_if_index
+ == vnet_buffer (b0)->sw_if_index[VLIB_RX])
+ {
+ struct rte_mbuf *mb;
+ i16 data_start;
+ i32 temp_advance;
+
+ /*
+ * Note: current_data will have advanced
+ * when we skip ethernet input.
+ * Temporarily back up to the original DMA
+ * target, so we capture a valid ethernet frame
+ */
+ mb = rte_mbuf_from_vlib_buffer (b0);
+
+ /* Figure out the original data_start */
+ data_start = (mb->buf_addr + mb->data_off) - (void *) b0->data;
+ /* Back up that far */
+ temp_advance = b0->current_data - data_start;
+ vlib_buffer_advance (b0, -temp_advance);
+ /* Trace the packet */
+ pcap_add_buffer (&dm->pcap[VLIB_RX].pcap_main, vm, bi0, 512);
+ /* and advance again */
+ vlib_buffer_advance (b0, temp_advance);
+ }
+ n_left--;
+ }
+ }
+
+ vlib_increment_combined_counter
+ (vnet_get_main ()->interface_main.combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_RX, thread_index, xd->sw_if_index,
+ n_rx_packets, n_rx_bytes);
+
+ vnet_device_increment_rx_packets (thread_index, n_rx_packets);
+
+ return n_rx_packets;
+}
+
+VLIB_NODE_FN (dpdk_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * f)