memif: VPP-1172: Ensure memif_create reply contains sw_if_index
[vpp.git] / src / plugins / memif / node.c
index 8190441..83f1277 100644 (file)
@@ -41,7 +41,7 @@ typedef enum
     MEMIF_INPUT_N_ERROR,
 } memif_input_error_t;
 
-static char *memif_input_error_strings[] = {
+static __clib_unused char *memif_input_error_strings[] = {
 #define _(n,s) s,
   foreach_memif_input_error
 #undef _
@@ -54,7 +54,7 @@ typedef struct
   u16 ring;
 } memif_input_trace_t;
 
-static u8 *
+static __clib_unused u8 *
 format_memif_input_trace (u8 * s, va_list * args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -132,7 +132,7 @@ memif_copy_buffer_from_rx_ring (vlib_main_t * vm, memif_if_t * mif,
 
   while (*num_slots)
     {
-      data_len = ring->desc[mq->last_head].length;
+      data_len = ring->desc[mq->last_head & mask].length;
       while (data_len && (*n_free_bufs))
        {
          /* get empty buffer */
@@ -140,6 +140,9 @@ memif_copy_buffer_from_rx_ring (vlib_main_t * vm, memif_if_t * mif,
          prev_bi = *bi;
          *bi = nm->rx_buffers[thread_index][last_buf];
          b = vlib_get_buffer (vm, *bi);
+         /* Clear the error first to ensure following node forget setting it */
+         /* It will cause null-node error counter increasement instead of potential crash */
+         b->error = 0x0;
          _vec_len (nm->rx_buffers[thread_index]) = last_buf;
          (*n_free_bufs)--;
          if (PREDICT_FALSE (*n_free_bufs == 0))
@@ -161,7 +164,7 @@ memif_copy_buffer_from_rx_ring (vlib_main_t * vm, memif_if_t * mif,
          bytes_to_copy =
            data_len > n_buffer_bytes ? n_buffer_bytes : data_len;
          b->current_data = 0;
-         mb = memif_get_buffer (mif, ring, mq->last_head);
+         mb = memif_get_buffer (mif, ring, mq->last_head & mask);
          clib_memcpy (vlib_buffer_get_current (b), mb + offset,
                       CLIB_CACHE_LINE_BYTES);
          if (bytes_to_copy > CLIB_CACHE_LINE_BYTES)
@@ -191,10 +194,10 @@ memif_copy_buffer_from_rx_ring (vlib_main_t * vm, memif_if_t * mif,
        }
       last_head = mq->last_head;
       /* Advance to next descriptor */
-      mq->last_head = (mq->last_head + 1) & mask;
+      mq->last_head++;
       offset = 0;
       (*num_slots)--;
-      if ((ring->desc[last_head].flags & MEMIF_DESC_FLAG_NEXT) == 0)
+      if ((ring->desc[last_head & mask].flags & MEMIF_DESC_FLAG_NEXT) == 0)
        break;
     }
 
@@ -266,13 +269,11 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     }
 
   head = ring->head;
+  mq->last_head = ring->tail;
   if (head == mq->last_head)
     return 0;
 
-  if (head > mq->last_head)
-    num_slots = head - mq->last_head;
-  else
-    num_slots = ring_size - mq->last_head + head;
+  num_slots = head - mq->last_head;
 
   while (num_slots)
     {
@@ -283,30 +284,16 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
 
       while (num_slots > 11 && n_left_to_next > 2)
        {
-         if (PREDICT_TRUE (mq->last_head + 5 < ring_size))
-           {
-             CLIB_PREFETCH (memif_get_buffer (mif, ring, mq->last_head + 2),
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (memif_get_buffer (mif, ring, mq->last_head + 3),
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (&ring->desc[mq->last_head + 4],
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (&ring->desc[mq->last_head + 5],
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-           }
-         else
-           {
-             CLIB_PREFETCH (memif_get_buffer
-                            (mif, ring, (mq->last_head + 2) % mask),
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (memif_get_buffer
-                            (mif, ring, (mq->last_head + 3) % mask),
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (&ring->desc[(mq->last_head + 4) % mask],
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (&ring->desc[(mq->last_head + 5) % mask],
-                            CLIB_CACHE_LINE_BYTES, LOAD);
-           }
+         CLIB_PREFETCH (memif_get_buffer
+                        (mif, ring, (mq->last_head + 2) & mask),
+                        CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (memif_get_buffer
+                        (mif, ring, (mq->last_head + 3) & mask),
+                        CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (&ring->desc[(mq->last_head + 4) & mask],
+                        CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (&ring->desc[(mq->last_head + 5) & mask],
+                        CLIB_CACHE_LINE_BYTES, LOAD);
 
          vlib_buffer_t *first_b0 = 0;
          u32 bi0 = 0, first_bi0 = 0;
@@ -326,6 +313,10 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                                                     &first_bi1, &bi1,
                                                     &num_slots);
 
+         if (PREDICT_FALSE (!first_bi0 || !first_bi1))
+           {
+             goto _invalid_pkt01;
+           }
          /* enqueue buffer */
          to_next[0] = first_bi0;
          to_next[1] = first_bi1;
@@ -393,6 +384,66 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          /* next packet */
          n_rx_packets += 2;
          n_rx_bytes += b0_total + b1_total;
+
+         continue;
+       _invalid_pkt01:
+         if (!first_bi0 && !first_bi1)
+           {
+             continue;
+           }
+         if (first_bi1)
+           {
+             first_bi0 = first_bi1;
+             first_b0 = first_b1;
+             bi0 = bi1;
+             b0_total = b1_total;
+           }
+
+         if (mode == MEMIF_INTERFACE_MODE_IP)
+           {
+             next0 = memif_next_from_ip_hdr (node, first_b0);
+           }
+         else if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
+           {
+             if (PREDICT_FALSE (mif->per_interface_next_index != ~0))
+               next0 = mif->per_interface_next_index;
+             else
+               /* redirect if feature path
+                * enabled */
+               vnet_feature_start_device_input_x1 (mif->sw_if_index, &next0,
+                                                   first_b0);
+           }
+
+         /* trace */
+         VLIB_BUFFER_TRACE_TRAJECTORY_INIT (first_b0);
+
+         if (PREDICT_FALSE (n_trace > 0))
+           {
+             if (PREDICT_TRUE (first_b0 != 0))
+               {
+                 memif_input_trace_t *tr;
+                 vlib_trace_buffer (vm, node, next0, first_b0,
+                                    /* follow_chain */ 0);
+                 vlib_set_trace_count (vm, node, --n_trace);
+                 tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr));
+                 tr->next_index = next0;
+                 tr->hw_if_index = mif->hw_if_index;
+                 tr->ring = qid;
+               }
+           }
+
+         /* enqueue buffer */
+         to_next[0] = first_bi0;
+         to_next += 1;
+         n_left_to_next--;
+
+         /* enqueue */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, first_bi0, next0);
+
+         /* next packet */
+         n_rx_packets++;
+         n_rx_bytes += b0_total;
        }
       while (num_slots && n_left_to_next)
        {
@@ -404,6 +455,10 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                                                     &n_free_bufs, &first_b0,
                                                     &first_bi0, &bi0,
                                                     &num_slots);
+         if (PREDICT_FALSE (!first_bi0))
+           {
+             goto _invalid_pkt0;
+           }
 
          if (mode == MEMIF_INTERFACE_MODE_IP)
            {
@@ -450,11 +505,17 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          /* next packet */
          n_rx_packets++;
          n_rx_bytes += b0_total;
+         continue;
+       _invalid_pkt0:
+         ;
+       }
+      if (PREDICT_TRUE (n_rx_packets != 0))
+       {
+         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
        }
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
   CLIB_MEMORY_STORE_BARRIER ();
-  ring->tail = head;
+  ring->tail = mq->last_head;
 
   vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters
                                   + VNET_INTERFACE_COUNTER_RX, thread_index,
@@ -464,9 +525,10 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   return n_rx_packets;
 }
 
-static uword
-memif_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
-               vlib_frame_t * frame)
+uword
+CLIB_MULTIARCH_FN (memif_input_fn) (vlib_main_t * vm,
+                                   vlib_node_runtime_t * node,
+                                   vlib_frame_t * frame)
 {
   u32 n_rx = 0;
   memif_main_t *nm = &memif_main;
@@ -508,6 +570,7 @@ memif_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
   return n_rx;
 }
 
+#ifndef CLIB_MULTIARCH_VARIANT
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (memif_input_node) = {
   .function = memif_input_fn,
@@ -520,7 +583,21 @@ VLIB_REGISTER_NODE (memif_input_node) = {
   .error_strings = memif_input_error_strings,
 };
 
-VLIB_NODE_FUNCTION_MULTIARCH (memif_input_node, memif_input_fn)
+vlib_node_function_t __clib_weak memif_input_fn_avx512;
+vlib_node_function_t __clib_weak memif_input_fn_avx2;
+
+#if __x86_64__
+static void __clib_constructor
+memif_input_multiarch_select (void)
+{
+  if (memif_input_fn_avx512 && clib_cpu_supports_avx512f ())
+    memif_input_node.function = memif_input_fn_avx512;
+  else if (memif_input_fn_avx2 && clib_cpu_supports_avx2 ())
+    memif_input_node.function = memif_input_fn_avx2;
+}
+#endif
+#endif
+
 /* *INDENT-ON* */