LCOV - code coverage report
Current view: top level - plugins/memif - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 266 744 35.8 %
Date: 2023-07-05 22:20:52 Functions: 16 33 48.5 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2016 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             : #define _GNU_SOURCE
      19             : #include <stdint.h>
      20             : #include <net/if.h>
      21             : #include <sys/ioctl.h>
      22             : #include <sys/uio.h>
      23             : 
      24             : #include <vlib/vlib.h>
      25             : #include <vlib/unix/unix.h>
      26             : #include <vnet/ethernet/ethernet.h>
      27             : #include <vnet/interface/rx_queue_funcs.h>
      28             : #include <vnet/feature/feature.h>
      29             : 
      30             : #include <memif/memif.h>
      31             : #include <memif/private.h>
      32             : 
      33             : #define MEMIF_IP_OFFSET 14
      34             : 
      35             : #define foreach_memif_input_error                                             \
      36             :   _ (BUFFER_ALLOC_FAIL, buffer_alloc, ERROR, "buffer allocation failed")      \
      37             :   _ (BAD_DESC, bad_desc, ERROR, "bad descriptor")                             \
      38             :   _ (NOT_IP, not_ip, INFO, "not ip packet")
      39             : 
      40             : typedef enum
      41             : {
      42             : #define _(f, n, s, d) MEMIF_INPUT_ERROR_##f,
      43             :   foreach_memif_input_error
      44             : #undef _
      45             :     MEMIF_INPUT_N_ERROR,
      46             : } memif_input_error_t;
      47             : 
      48             : static vlib_error_desc_t memif_input_error_counters[] = {
      49             : #define _(f, n, s, d) { #n, d, VL_COUNTER_SEVERITY_##s },
      50             :   foreach_memif_input_error
      51             : #undef _
      52             : };
      53             : 
      54             : typedef struct
      55             : {
      56             :   u32 next_index;
      57             :   u32 hw_if_index;
      58             :   u16 ring;
      59             : } memif_input_trace_t;
      60             : 
      61             : static __clib_unused u8 *
      62           0 : format_memif_input_trace (u8 * s, va_list * args)
      63             : {
      64           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      65           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      66           0 :   memif_input_trace_t *t = va_arg (*args, memif_input_trace_t *);
      67           0 :   u32 indent = format_get_indent (s);
      68             : 
      69           0 :   s = format (s, "memif: hw_if_index %d next-index %d",
      70             :               t->hw_if_index, t->next_index);
      71           0 :   s = format (s, "\n%Uslot: ring %u", format_white_space, indent + 2,
      72           0 :               t->ring);
      73           0 :   return s;
      74             : }
      75             : 
      76             : static_always_inline u32
      77           0 : memif_next_from_ip_hdr (vlib_node_runtime_t * node, vlib_buffer_t * b)
      78             : {
      79           0 :   u8 *ptr = vlib_buffer_get_current (b);
      80           0 :   u8 v = *ptr & 0xf0;
      81             : 
      82           0 :   if (PREDICT_TRUE (v == 0x40))
      83           0 :     return VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT;
      84           0 :   else if (PREDICT_TRUE (v == 0x60))
      85           0 :     return VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
      86             : 
      87           0 :   b->error = node->errors[MEMIF_INPUT_ERROR_NOT_IP];
      88           0 :   return VNET_DEVICE_INPUT_NEXT_DROP;
      89             : }
      90             : 
      91             : static_always_inline void
      92           0 : memif_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node,
      93             :                     memif_if_t * mif, vlib_buffer_t * b, u32 next, u16 qid,
      94             :                     uword * n_tracep)
      95             : {
      96           0 :   if (PREDICT_TRUE
      97             :       (b != 0 && vlib_trace_buffer (vm, node, next, b, /* follow_chain */ 0)))
      98             :     {
      99             :       memif_input_trace_t *tr;
     100           0 :       vlib_set_trace_count (vm, node, --(*n_tracep));
     101           0 :       tr = vlib_add_trace (vm, node, b, sizeof (*tr));
     102           0 :       tr->next_index = next;
     103           0 :       tr->hw_if_index = mif->hw_if_index;
     104           0 :       tr->ring = qid;
     105             :     }
     106           0 : }
     107             : 
     108             : static_always_inline void
     109           0 : memif_add_copy_op (memif_per_thread_data_t * ptd, void *data, u32 len,
     110             :                    u16 buffer_offset, u16 buffer_vec_index)
     111             : {
     112             :   memif_copy_op_t *co;
     113           0 :   vec_add2_aligned (ptd->copy_ops, co, 1, CLIB_CACHE_LINE_BYTES);
     114           0 :   co->data = data;
     115           0 :   co->data_len = len;
     116           0 :   co->buffer_offset = buffer_offset;
     117           0 :   co->buffer_vec_index = buffer_vec_index;
     118           0 : }
     119             : 
     120             : static_always_inline void
     121           0 : memif_add_to_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * buffers,
     122             :                     u32 buffer_size)
     123             : {
     124           0 :   vlib_buffer_t *seg = b;
     125           0 :   i32 bytes_left = b->current_length - buffer_size + b->current_data;
     126             : 
     127           0 :   if (PREDICT_TRUE (bytes_left <= 0))
     128           0 :     return;
     129             : 
     130           0 :   b->current_length -= bytes_left;
     131           0 :   b->total_length_not_including_first_buffer = bytes_left;
     132             : 
     133           0 :   while (bytes_left)
     134             :     {
     135           0 :       seg->flags |= VLIB_BUFFER_NEXT_PRESENT;
     136           0 :       seg->next_buffer = buffers[0];
     137           0 :       seg = vlib_get_buffer (vm, buffers[0]);
     138           0 :       buffers++;
     139           0 :       seg->current_data = 0;
     140           0 :       seg->current_length = clib_min (buffer_size, bytes_left);
     141           0 :       bytes_left -= seg->current_length;
     142             :     }
     143             : }
     144             : 
     145             : static_always_inline u16
     146          11 : memif_parse_desc (memif_per_thread_data_t *ptd, memif_if_t *mif,
     147             :                   memif_queue_t *mq, u16 next, u16 n_avail)
     148             : {
     149          11 :   memif_ring_t *ring = mq->ring;
     150          11 :   memif_desc_t *descs = ring->desc;
     151          11 :   void **desc_data = ptd->desc_data;
     152          11 :   u16 *desc_len = ptd->desc_len;
     153          11 :   memif_desc_status_t *desc_status = ptd->desc_status;
     154          11 :   u16 n_desc = 0, n_pkts = 0;
     155          11 :   u32 i = 0;
     156          11 :   u16 mask = pow2_mask (mq->log2_ring_size);
     157          11 :   memif_desc_t *d = 0;
     158          11 :   u32 slot = next;
     159             : 
     160          22 :   while (i < n_avail)
     161             :     {
     162             :       u8 flags;
     163          11 :       d = descs + (slot++ & mask);
     164          11 :       desc_data[i] = (void *) ((u64) d->region << 32 | d->offset);
     165          11 :       desc_len[i] = d->length;
     166          11 :       desc_status[i].as_u8 = flags = d->flags;
     167          11 :       i++;
     168          11 :       if (PREDICT_FALSE ((flags & MEMIF_DESC_FLAG_NEXT)) == 0)
     169             :         {
     170          11 :           n_desc = i;
     171          11 :           if (++n_pkts == MEMIF_RX_VECTOR_SZ)
     172           0 :             goto frame_full;
     173             :         }
     174             :     }
     175          11 : frame_full:
     176             : 
     177             :   /* done */
     178          11 :   ptd->n_packets = n_pkts;
     179          11 :   return n_desc;
     180             : }
     181             : 
     182             : static_always_inline void
     183           0 : memif_desc_status_set_err (memif_desc_status_t *p,
     184             :                            memif_desc_status_err_code_t e)
     185             : {
     186           0 :   memif_desc_status_t s = { .err = 1, .err_code = e };
     187           0 :   p->as_u8 |= s.as_u8;
     188           0 : }
     189             : 
     190             : static_always_inline void
     191          11 : memif_validate_desc_data (memif_per_thread_data_t *ptd, memif_if_t *mif,
     192             :                           u16 n_desc, int is_ethernet)
     193             : {
     194          11 :   void **desc_data = ptd->desc_data;
     195          11 :   u16 *desc_len = ptd->desc_len;
     196          11 :   memif_desc_status_t *desc_status = ptd->desc_status;
     197          11 :   u16 n_regions = vec_len (mif->regions);
     198          11 :   u32 n_rx_bytes = 0;
     199          11 :   u16 max_len = 0;
     200          11 :   u8 xor_status = 0;
     201             : 
     202          22 :   for (u32 i = 0; i < n_desc; i++)
     203             :     {
     204          11 :       u16 region = ((u64) desc_data[i]) >> 32;
     205          11 :       u32 offset = (u64) desc_data[i];
     206          11 :       u16 len = desc_len[i];
     207          11 :       memif_region_t *r = mif->regions + region;
     208             : 
     209          11 :       if (region >= n_regions)
     210           0 :         memif_desc_status_set_err (desc_status + i,
     211             :                                    MEMIF_DESC_STATUS_ERR_BAD_REGION);
     212          11 :       else if (offset + len > r->region_size)
     213           0 :         memif_desc_status_set_err (desc_status + i,
     214             :                                    MEMIF_DESC_STATUS_ERR_REGION_OVERRUN);
     215          11 :       else if (is_ethernet && len > ETHERNET_MAX_PACKET_BYTES)
     216           0 :         memif_desc_status_set_err (desc_status + i,
     217             :                                    MEMIF_DESC_STATUS_ERR_DATA_TOO_BIG);
     218          11 :       else if (len == 0)
     219           0 :         memif_desc_status_set_err (desc_status + i,
     220             :                                    MEMIF_DESC_STATUS_ERR_ZERO_LENGTH);
     221             :       else
     222             :         {
     223          11 :           desc_data[i] = r->shm + offset;
     224          11 :           if (len > max_len)
     225          11 :             max_len = len;
     226          11 :           n_rx_bytes += len;
     227             :         }
     228          11 :       xor_status |= desc_status[i].as_u8;
     229             :     }
     230             : 
     231          11 :   ptd->max_desc_len = max_len;
     232          11 :   ptd->xor_status = xor_status;
     233          11 :   ptd->n_rx_bytes = n_rx_bytes;
     234          11 : }
     235             : 
     236             : static_always_inline u32
     237           0 : memif_process_desc (vlib_main_t *vm, vlib_node_runtime_t *node,
     238             :                     memif_per_thread_data_t *ptd, memif_if_t *mif)
     239             : {
     240           0 :   u16 buffer_size = vlib_buffer_get_default_data_size (vm);
     241           0 :   int is_ip = mif->mode == MEMIF_INTERFACE_MODE_IP;
     242           0 :   i16 start_offset = (is_ip) ? MEMIF_IP_OFFSET : 0;
     243           0 :   memif_packet_op_t *po = ptd->packet_ops;
     244           0 :   void **desc_data = ptd->desc_data;
     245           0 :   u16 *desc_len = ptd->desc_len;
     246           0 :   memif_desc_status_t *desc_status = ptd->desc_status;
     247           0 :   u32 n_buffers = 0;
     248           0 :   u32 n_left = ptd->n_packets;
     249             :   u32 packet_len;
     250           0 :   int i = -1;
     251           0 :   int bad_packets = 0;
     252             : 
     253             :   /* construct copy and packet vector out of ring slots */
     254           0 :   while (n_left)
     255             :     {
     256             :       u32 dst_off, src_off, n_bytes_left;
     257             :       void *mb0;
     258           0 :       po->first_buffer_vec_index = n_buffers++;
     259             : 
     260           0 :       packet_len = 0;
     261           0 :       src_off = 0;
     262           0 :       dst_off = start_offset;
     263             : 
     264           0 :     next_slot:
     265           0 :       i++; /* next descriptor */
     266           0 :       n_bytes_left = desc_len[i];
     267             : 
     268           0 :       packet_len += n_bytes_left;
     269           0 :       mb0 = desc_data[i];
     270             : 
     271           0 :       if (PREDICT_FALSE (desc_status[i].err))
     272             :         {
     273           0 :           vlib_error_count (vm, node->node_index, MEMIF_INPUT_ERROR_BAD_DESC,
     274             :                             1);
     275           0 :           bad_packets++;
     276           0 :           ASSERT (n_buffers > 0);
     277           0 :           n_buffers--;
     278           0 :           goto next_packet;
     279             :         }
     280             :       else
     281             :         do
     282             :           {
     283           0 :             u32 dst_free = buffer_size - dst_off;
     284           0 :             if (dst_free == 0)
     285             :               {
     286           0 :                 dst_off = 0;
     287           0 :                 dst_free = buffer_size;
     288           0 :                 n_buffers++;
     289             :               }
     290           0 :             u32 bytes_to_copy = clib_min (dst_free, n_bytes_left);
     291           0 :             memif_add_copy_op (ptd, mb0 + src_off, bytes_to_copy, dst_off,
     292           0 :                                n_buffers - 1);
     293           0 :             n_bytes_left -= bytes_to_copy;
     294           0 :             src_off += bytes_to_copy;
     295           0 :             dst_off += bytes_to_copy;
     296             :           }
     297           0 :         while (PREDICT_FALSE (n_bytes_left));
     298             : 
     299           0 :       if (desc_status[i].next)
     300             :         {
     301           0 :           src_off = 0;
     302           0 :           goto next_slot;
     303             :         }
     304             : 
     305             :       /* update packet op */
     306           0 :       po->packet_len = packet_len;
     307           0 :       po++;
     308             : 
     309           0 :     next_packet:
     310             :       /* next packet */
     311           0 :       n_left--;
     312             :     }
     313           0 :   ASSERT (ptd->n_packets >= bad_packets);
     314           0 :   ptd->n_packets -= bad_packets;
     315           0 :   return n_buffers;
     316             : }
     317             : static_always_inline void
     318          11 : memif_fill_buffer_mdata_simple (vlib_node_runtime_t *node,
     319             :                                 memif_per_thread_data_t *ptd,
     320             :                                 vlib_buffer_t **b, u16 *next, int is_ip)
     321             : {
     322             :   vlib_buffer_t bt;
     323          11 :   u16 *dl = ptd->desc_len;
     324             :   /* process buffer metadata */
     325             : 
     326          11 :   u32 n_left = ptd->n_packets;
     327             : 
     328             :   /* copy template into local variable - will save per packet load */
     329          11 :   vlib_buffer_copy_template (&bt, &ptd->buffer_template);
     330             : 
     331          11 :   while (n_left >= 8)
     332             :     {
     333           0 :       vlib_prefetch_buffer_header (b[4], STORE);
     334           0 :       vlib_prefetch_buffer_header (b[5], STORE);
     335           0 :       vlib_prefetch_buffer_header (b[6], STORE);
     336           0 :       vlib_prefetch_buffer_header (b[7], STORE);
     337             : 
     338           0 :       vlib_buffer_copy_template (b[0], &bt);
     339           0 :       vlib_buffer_copy_template (b[1], &bt);
     340           0 :       vlib_buffer_copy_template (b[2], &bt);
     341           0 :       vlib_buffer_copy_template (b[3], &bt);
     342             : 
     343           0 :       b[0]->current_length = dl[0];
     344           0 :       b[1]->current_length = dl[1];
     345           0 :       b[2]->current_length = dl[2];
     346           0 :       b[3]->current_length = dl[3];
     347             : 
     348           0 :       if (is_ip)
     349             :         {
     350           0 :           next[0] = memif_next_from_ip_hdr (node, b[0]);
     351           0 :           next[1] = memif_next_from_ip_hdr (node, b[1]);
     352           0 :           next[2] = memif_next_from_ip_hdr (node, b[2]);
     353           0 :           next[3] = memif_next_from_ip_hdr (node, b[3]);
     354             :         }
     355             : 
     356             :       /* next */
     357           0 :       n_left -= 4;
     358           0 :       b += 4;
     359           0 :       dl += 4;
     360           0 :       next += 4;
     361             :     }
     362             : 
     363          22 :   while (n_left)
     364             :     {
     365             :       /* enqueue buffer */
     366          11 :       vlib_buffer_copy_template (b[0], &bt);
     367          11 :       b[0]->current_length = dl[0];
     368          11 :       if (is_ip)
     369           0 :         next[0] = memif_next_from_ip_hdr (node, b[0]);
     370             : 
     371             :       /* next */
     372          11 :       n_left -= 1;
     373          11 :       b += 1;
     374          11 :       dl += 1;
     375          11 :       next += 1;
     376             :     }
     377          11 : }
     378             : 
     379             : static_always_inline void
     380           0 : memif_fill_buffer_mdata (vlib_main_t *vm, vlib_node_runtime_t *node,
     381             :                          memif_per_thread_data_t *ptd, memif_if_t *mif,
     382             :                          u32 *bi, u16 *next, int is_ip)
     383             : {
     384           0 :   u16 buffer_size = vlib_buffer_get_default_data_size (vm);
     385             :   vlib_buffer_t *b0, *b1, *b2, *b3, bt;
     386             :   memif_packet_op_t *po;
     387             :   /* process buffer metadata */
     388             : 
     389           0 :   u32 n_from = ptd->n_packets;
     390           0 :   po = ptd->packet_ops;
     391             : 
     392             :   /* copy template into local variable - will save per packet load */
     393           0 :   vlib_buffer_copy_template (&bt, &ptd->buffer_template);
     394             : 
     395           0 :   while (n_from >= 8)
     396             :     {
     397           0 :       b0 = vlib_get_buffer (vm, ptd->buffers[po[4].first_buffer_vec_index]);
     398           0 :       b1 = vlib_get_buffer (vm, ptd->buffers[po[5].first_buffer_vec_index]);
     399           0 :       b2 = vlib_get_buffer (vm, ptd->buffers[po[6].first_buffer_vec_index]);
     400           0 :       b3 = vlib_get_buffer (vm, ptd->buffers[po[7].first_buffer_vec_index]);
     401             : 
     402           0 :       vlib_prefetch_buffer_header (b0, STORE);
     403           0 :       vlib_prefetch_buffer_header (b1, STORE);
     404           0 :       vlib_prefetch_buffer_header (b2, STORE);
     405           0 :       vlib_prefetch_buffer_header (b3, STORE);
     406             : 
     407             :       /* enqueue buffer */
     408             :       u32 fbvi[4];
     409           0 :       fbvi[0] = po[0].first_buffer_vec_index;
     410           0 :       fbvi[1] = po[1].first_buffer_vec_index;
     411           0 :       fbvi[2] = po[2].first_buffer_vec_index;
     412           0 :       fbvi[3] = po[3].first_buffer_vec_index;
     413             : 
     414           0 :       bi[0] = ptd->buffers[fbvi[0]];
     415           0 :       bi[1] = ptd->buffers[fbvi[1]];
     416           0 :       bi[2] = ptd->buffers[fbvi[2]];
     417           0 :       bi[3] = ptd->buffers[fbvi[3]];
     418             : 
     419           0 :       b0 = vlib_get_buffer (vm, bi[0]);
     420           0 :       b1 = vlib_get_buffer (vm, bi[1]);
     421           0 :       b2 = vlib_get_buffer (vm, bi[2]);
     422           0 :       b3 = vlib_get_buffer (vm, bi[3]);
     423             : 
     424           0 :       vlib_buffer_copy_template (b0, &bt);
     425           0 :       vlib_buffer_copy_template (b1, &bt);
     426           0 :       vlib_buffer_copy_template (b2, &bt);
     427           0 :       vlib_buffer_copy_template (b3, &bt);
     428             : 
     429           0 :       b0->current_length = po[0].packet_len;
     430           0 :       b1->current_length = po[1].packet_len;
     431           0 :       b2->current_length = po[2].packet_len;
     432           0 :       b3->current_length = po[3].packet_len;
     433             : 
     434           0 :       memif_add_to_chain (vm, b0, ptd->buffers + fbvi[0] + 1, buffer_size);
     435           0 :       memif_add_to_chain (vm, b1, ptd->buffers + fbvi[1] + 1, buffer_size);
     436           0 :       memif_add_to_chain (vm, b2, ptd->buffers + fbvi[2] + 1, buffer_size);
     437           0 :       memif_add_to_chain (vm, b3, ptd->buffers + fbvi[3] + 1, buffer_size);
     438             : 
     439           0 :       if (is_ip)
     440             :         {
     441           0 :           next[0] = memif_next_from_ip_hdr (node, b0);
     442           0 :           next[1] = memif_next_from_ip_hdr (node, b1);
     443           0 :           next[2] = memif_next_from_ip_hdr (node, b2);
     444           0 :           next[3] = memif_next_from_ip_hdr (node, b3);
     445             :         }
     446             : 
     447             :       /* next */
     448           0 :       n_from -= 4;
     449           0 :       po += 4;
     450           0 :       bi += 4;
     451           0 :       next += 4;
     452             :     }
     453           0 :   while (n_from)
     454             :     {
     455             :       u32 fbvi[1];
     456             :       /* enqueue buffer */
     457           0 :       fbvi[0] = po[0].first_buffer_vec_index;
     458           0 :       bi[0] = ptd->buffers[fbvi[0]];
     459           0 :       b0 = vlib_get_buffer (vm, bi[0]);
     460           0 :       vlib_buffer_copy_template (b0, &bt);
     461           0 :       b0->current_length = po->packet_len;
     462             : 
     463           0 :       memif_add_to_chain (vm, b0, ptd->buffers + fbvi[0] + 1, buffer_size);
     464             : 
     465           0 :       if (is_ip)
     466           0 :         next[0] = memif_next_from_ip_hdr (node, b0);
     467             : 
     468             :       /* next */
     469           0 :       n_from -= 1;
     470           0 :       po += 1;
     471           0 :       bi += 1;
     472           0 :       next += 1;
     473             :     }
     474           0 : }
     475             : 
     476             : static_always_inline void
     477          11 : memif_advance_ring (memif_ring_type_t type, memif_queue_t *mq,
     478             :                     memif_ring_t *ring, u16 cur_slot)
     479             : {
     480          11 :   if (type == MEMIF_RING_S2M)
     481             :     {
     482          11 :       __atomic_store_n (&ring->tail, cur_slot, __ATOMIC_RELEASE);
     483          11 :       mq->last_head = cur_slot;
     484             :     }
     485             :   else
     486             :     {
     487           0 :       mq->last_tail = cur_slot;
     488             :     }
     489          11 : }
     490             : 
     491             : static_always_inline uword
     492     8605830 : memif_device_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     493             :                            memif_if_t *mif, memif_ring_type_t type, u16 qid,
     494             :                            memif_interface_mode_t mode)
     495             : {
     496     8605830 :   vnet_main_t *vnm = vnet_get_main ();
     497     8605830 :   memif_main_t *mm = &memif_main;
     498             :   memif_ring_t *ring;
     499             :   memif_queue_t *mq;
     500     8605830 :   u16 buffer_size = vlib_buffer_get_default_data_size (vm);
     501             :   uword n_trace;
     502     8605830 :   u16 nexts[MEMIF_RX_VECTOR_SZ], *next = nexts;
     503     8605830 :   u32 _to_next_bufs[MEMIF_RX_VECTOR_SZ], *to_next_bufs = _to_next_bufs, *bi;
     504             :   u32 n_left_to_next;
     505     8605830 :   u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
     506             :   vlib_buffer_t *buffer_ptrs[MEMIF_RX_VECTOR_SZ];
     507     8605830 :   u32 thread_index = vm->thread_index;
     508     8605830 :   memif_per_thread_data_t *ptd =
     509     8605830 :     vec_elt_at_index (mm->per_thread_data, thread_index);
     510             :   u16 cur_slot, ring_size, n_slots, mask;
     511             :   u16 n_buffers, n_alloc, n_desc;
     512             :   i16 start_offset;
     513             :   memif_copy_op_t *co;
     514     8605830 :   int is_slave = (mif->flags & MEMIF_IF_FLAG_IS_SLAVE) != 0;
     515     8605830 :   int is_simple = 1;
     516             :   int i;
     517             : 
     518     8605830 :   mq = vec_elt_at_index (mif->rx_queues, qid);
     519     8605830 :   ring = mq->ring;
     520     8605830 :   ring_size = 1 << mq->log2_ring_size;
     521     8605830 :   mask = ring_size - 1;
     522             : 
     523     8605830 :   start_offset = (mode == MEMIF_INTERFACE_MODE_IP) ? MEMIF_IP_OFFSET : 0;
     524             : 
     525     8605830 :   if (is_slave)
     526             :     {
     527           0 :       cur_slot = mq->last_tail;
     528           0 :       n_slots = __atomic_load_n (&ring->tail, __ATOMIC_ACQUIRE) - cur_slot;
     529             :     }
     530             :   else
     531             :     {
     532     8605830 :       cur_slot = mq->last_head;
     533     8605830 :       n_slots = __atomic_load_n (&ring->head, __ATOMIC_ACQUIRE) - cur_slot;
     534             :     }
     535             : 
     536     8605830 :   if (n_slots == 0)
     537             :     {
     538     8605820 :       ptd->n_packets = 0;
     539     8605820 :       goto refill;
     540             :     }
     541             : 
     542          11 :   n_desc = memif_parse_desc (ptd, mif, mq, cur_slot, n_slots);
     543             : 
     544          11 :   if (n_desc != ptd->n_packets)
     545           0 :     is_simple = 0;
     546             : 
     547          11 :   cur_slot += n_desc;
     548             : 
     549          11 :   if (mif->mode == MEMIF_INTERFACE_MODE_ETHERNET)
     550          11 :     memif_validate_desc_data (ptd, mif, n_desc, /* is_ethernet */ 1);
     551             :   else
     552           0 :     memif_validate_desc_data (ptd, mif, n_desc, /* is_ethernet */ 0);
     553             : 
     554          11 :   if (ptd->max_desc_len > buffer_size - start_offset)
     555           0 :     is_simple = 0;
     556             : 
     557          11 :   if (ptd->xor_status != 0)
     558           0 :     is_simple = 0;
     559             : 
     560          11 :   if (is_simple)
     561          11 :     n_buffers = ptd->n_packets;
     562             :   else
     563           0 :     n_buffers = memif_process_desc (vm, node, ptd, mif);
     564             : 
     565          11 :   if (PREDICT_FALSE (n_buffers == 0))
     566             :     {
     567             :       /* All descriptors are bad. Release slots in the ring and bail */
     568           0 :       memif_advance_ring (type, mq, ring, cur_slot);
     569           0 :       goto refill;
     570             :     }
     571             : 
     572             :   /* allocate free buffers */
     573          11 :   vec_validate_aligned (ptd->buffers, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
     574          22 :   n_alloc = vlib_buffer_alloc_from_pool (vm, ptd->buffers, n_buffers,
     575          11 :                                          mq->buffer_pool_index);
     576          11 :   if (PREDICT_FALSE (n_alloc != n_buffers))
     577             :     {
     578           0 :       if (n_alloc)
     579           0 :         vlib_buffer_free (vm, ptd->buffers, n_alloc);
     580           0 :       vlib_error_count (vm, node->node_index,
     581             :                         MEMIF_INPUT_ERROR_BUFFER_ALLOC_FAIL, 1);
     582           0 :       goto refill;
     583             :     }
     584             : 
     585             :   /* copy data */
     586          11 :   if (is_simple)
     587             :     {
     588          11 :       int n_pkts = ptd->n_packets;
     589          11 :       void **desc_data = ptd->desc_data;
     590          11 :       u16 *desc_len = ptd->desc_len;
     591             : 
     592          11 :       vlib_get_buffers (vm, ptd->buffers, buffer_ptrs, n_buffers);
     593             : 
     594          11 :       for (i = 0; i + 8 < n_pkts; i++)
     595             :         {
     596           0 :           clib_prefetch_load (desc_data[i + 8]);
     597           0 :           clib_prefetch_store (buffer_ptrs[i + 8]->data);
     598           0 :           clib_memcpy_fast (buffer_ptrs[i]->data + start_offset, desc_data[i],
     599           0 :                             desc_len[i]);
     600             :         }
     601          22 :       for (; i < n_pkts; i++)
     602          11 :         clib_memcpy_fast (buffer_ptrs[i]->data + start_offset, desc_data[i],
     603          11 :                           desc_len[i]);
     604             :     }
     605             :   else
     606             :     {
     607             :       vlib_buffer_t *b;
     608           0 :       u32 n_pkts = vec_len (ptd->copy_ops);
     609           0 :       co = ptd->copy_ops;
     610             : 
     611           0 :       for (i = 0; i + 8 < n_pkts; i++)
     612             :         {
     613           0 :           clib_prefetch_load (co[i + 8].data);
     614           0 :           b = vlib_get_buffer (vm, ptd->buffers[co[i].buffer_vec_index]);
     615           0 :           clib_memcpy_fast (b->data + co[i].buffer_offset, co[i].data,
     616           0 :                             co[i].data_len);
     617             :         }
     618           0 :       for (; i < n_pkts; i++)
     619             :         {
     620           0 :           b = vlib_get_buffer (vm, ptd->buffers[co[i].buffer_vec_index]);
     621           0 :           clib_memcpy_fast (b->data + co[i].buffer_offset, co[i].data,
     622           0 :                             co[i].data_len);
     623             :         }
     624             :     }
     625             : 
     626             :   /* release slots from the ring */
     627          11 :   memif_advance_ring (type, mq, ring, cur_slot);
     628             : 
     629             :   /* prepare buffer template and next indices */
     630          11 :   vnet_buffer (&ptd->buffer_template)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     631          11 :   vnet_buffer (&ptd->buffer_template)->feature_arc_index = 0;
     632          11 :   ptd->buffer_template.current_data = start_offset;
     633          11 :   ptd->buffer_template.current_config_index = 0;
     634          11 :   ptd->buffer_template.buffer_pool_index = mq->buffer_pool_index;
     635          11 :   ptd->buffer_template.ref_count = 1;
     636             : 
     637          11 :   if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
     638             :     {
     639          11 :       next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
     640          11 :       if (mif->per_interface_next_index != ~0)
     641           0 :         next_index = mif->per_interface_next_index;
     642             :       else
     643          11 :         vnet_feature_start_device_input_x1 (mif->sw_if_index, &next_index,
     644             :                                             &ptd->buffer_template);
     645             : 
     646          11 :       vlib_get_new_next_frame (vm, node, next_index, to_next_bufs,
     647             :                                n_left_to_next);
     648          11 :       if (PREDICT_TRUE (next_index == VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT))
     649             :         {
     650             :           vlib_next_frame_t *nf;
     651             :           vlib_frame_t *f;
     652             :           ethernet_input_frame_t *ef;
     653           0 :           nf = vlib_node_runtime_get_next_frame (vm, node, next_index);
     654           0 :           f = vlib_get_frame (vm, nf->frame);
     655           0 :           f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
     656             : 
     657           0 :           ef = vlib_frame_scalar_args (f);
     658           0 :           ef->sw_if_index = mif->sw_if_index;
     659           0 :           ef->hw_if_index = mif->hw_if_index;
     660           0 :           vlib_frame_no_append (f);
     661             :         }
     662             :     }
     663             : 
     664          11 :   if (is_simple)
     665             :     {
     666          11 :       vlib_buffer_copy_indices (to_next_bufs, ptd->buffers, ptd->n_packets);
     667          11 :       if (mode == MEMIF_INTERFACE_MODE_IP)
     668           0 :         memif_fill_buffer_mdata_simple (node, ptd, buffer_ptrs, nexts, 1);
     669             :       else
     670          11 :         memif_fill_buffer_mdata_simple (node, ptd, buffer_ptrs, nexts, 0);
     671             :     }
     672             :   else
     673             :     {
     674           0 :       if (mode == MEMIF_INTERFACE_MODE_IP)
     675           0 :         memif_fill_buffer_mdata (vm, node, ptd, mif, to_next_bufs, nexts, 1);
     676             :       else
     677           0 :         memif_fill_buffer_mdata (vm, node, ptd, mif, to_next_bufs, nexts, 0);
     678             :     }
     679             : 
     680             :   /* packet trace if enabled */
     681          11 :   if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
     682             :     {
     683           0 :       u32 n_left = ptd->n_packets;
     684           0 :       bi = to_next_bufs;
     685           0 :       next = nexts;
     686           0 :       u32 ni = next_index;
     687           0 :       while (n_trace && n_left)
     688             :         {
     689             :           vlib_buffer_t *b;
     690             :           memif_input_trace_t *tr;
     691           0 :           if (mode != MEMIF_INTERFACE_MODE_ETHERNET)
     692           0 :             ni = next[0];
     693           0 :           b = vlib_get_buffer (vm, bi[0]);
     694           0 :           if (PREDICT_TRUE
     695             :               (vlib_trace_buffer (vm, node, ni, b, /* follow_chain */ 0)))
     696             :             {
     697           0 :               tr = vlib_add_trace (vm, node, b, sizeof (*tr));
     698           0 :               tr->next_index = ni;
     699           0 :               tr->hw_if_index = mif->hw_if_index;
     700           0 :               tr->ring = qid;
     701           0 :               n_trace--;
     702             :             }
     703             : 
     704             :           /* next */
     705           0 :           n_left--;
     706           0 :           bi++;
     707           0 :           next++;
     708             :         }
     709           0 :       vlib_set_trace_count (vm, node, n_trace);
     710             :     }
     711             : 
     712          11 :   if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
     713             :     {
     714          11 :       n_left_to_next -= ptd->n_packets;
     715          11 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     716             :     }
     717             :   else
     718           0 :     vlib_buffer_enqueue_to_next (vm, node, to_next_bufs, nexts,
     719           0 :                                  ptd->n_packets);
     720             : 
     721          11 :   vlib_increment_combined_counter (
     722             :     vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
     723          11 :     thread_index, mif->sw_if_index, ptd->n_packets, ptd->n_rx_bytes);
     724             : 
     725             :   /* refill ring with empty buffers */
     726     8605830 : refill:
     727     8605830 :   vec_reset_length (ptd->buffers);
     728     8605830 :   vec_reset_length (ptd->copy_ops);
     729             : 
     730     8605830 :   if (type == MEMIF_RING_M2S)
     731             :     {
     732           0 :       u16 head = ring->head;
     733           0 :       n_slots = ring_size - head + mq->last_tail;
     734             : 
     735           0 :       while (n_slots--)
     736             :         {
     737           0 :           u16 s = head++ & mask;
     738           0 :           memif_desc_t *d = &ring->desc[s];
     739           0 :           d->length = mif->run.buffer_size;
     740             :         }
     741             : 
     742           0 :       __atomic_store_n (&ring->head, head, __ATOMIC_RELEASE);
     743             :     }
     744             : 
     745     8605830 :   return ptd->n_packets;
     746             : }
     747             : 
     748             : static_always_inline uword
     749     8602760 : memif_device_input_zc_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     750             :                               memif_if_t *mif, u16 qid,
     751             :                               memif_interface_mode_t mode)
     752             : {
     753     8602760 :   vnet_main_t *vnm = vnet_get_main ();
     754     8602760 :   memif_main_t *mm = &memif_main;
     755             :   memif_ring_t *ring;
     756             :   memif_queue_t *mq;
     757             :   u32 next_index;
     758     8602760 :   uword n_trace = vlib_get_trace_count (vm, node);
     759     8602760 :   u32 n_rx_packets = 0, n_rx_bytes = 0;
     760     8602760 :   u32 *to_next = 0, *buffers;
     761             :   u32 bi0, bi1, bi2, bi3;
     762             :   u16 slot, s0;
     763             :   memif_desc_t *d0;
     764             :   vlib_buffer_t *b0, *b1, *b2, *b3;
     765     8602760 :   u32 thread_index = vm->thread_index;
     766     8602760 :   memif_per_thread_data_t *ptd = vec_elt_at_index (mm->per_thread_data,
     767             :                                                    thread_index);
     768             :   u16 cur_slot, last_slot, ring_size, n_slots, mask, head;
     769             :   i16 start_offset;
     770             :   u64 offset;
     771             :   u32 buffer_length;
     772             :   u16 n_alloc, n_from;
     773             : 
     774     8602760 :   mq = vec_elt_at_index (mif->rx_queues, qid);
     775     8602760 :   ring = mq->ring;
     776     8602760 :   ring_size = 1 << mq->log2_ring_size;
     777     8602760 :   mask = ring_size - 1;
     778             : 
     779     8602760 :   next_index = (mode == MEMIF_INTERFACE_MODE_IP) ?
     780     8602760 :     VNET_DEVICE_INPUT_NEXT_IP6_INPUT : VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
     781             : 
     782             :   /* asume that somebody will want to add ethernet header on the packet
     783             :      so start with IP header at offset 14 */
     784     8602760 :   start_offset = (mode == MEMIF_INTERFACE_MODE_IP) ? 14 : 0;
     785     8602760 :   buffer_length = vlib_buffer_get_default_data_size (vm) - start_offset;
     786             : 
     787     8602760 :   cur_slot = mq->last_tail;
     788     8602760 :   last_slot = __atomic_load_n (&ring->tail, __ATOMIC_ACQUIRE);
     789     8602760 :   if (cur_slot == last_slot)
     790     8602740 :     goto refill;
     791          12 :   n_slots = last_slot - cur_slot;
     792             : 
     793             :   /* process ring slots */
     794          12 :   vec_validate_aligned (ptd->buffers, MEMIF_RX_VECTOR_SZ,
     795             :                         CLIB_CACHE_LINE_BYTES);
     796          24 :   while (n_slots && n_rx_packets < MEMIF_RX_VECTOR_SZ)
     797             :     {
     798             :       vlib_buffer_t *hb;
     799             : 
     800          12 :       s0 = cur_slot & mask;
     801          12 :       bi0 = mq->buffers[s0];
     802          12 :       ptd->buffers[n_rx_packets++] = bi0;
     803             : 
     804          12 :       clib_prefetch_load (&ring->desc[(cur_slot + 8) & mask]);
     805          12 :       d0 = &ring->desc[s0];
     806          12 :       hb = b0 = vlib_get_buffer (vm, bi0);
     807          12 :       b0->current_data = start_offset;
     808          12 :       b0->current_length = d0->length;
     809          12 :       n_rx_bytes += d0->length;
     810             : 
     811          12 :       cur_slot++;
     812          12 :       n_slots--;
     813          12 :       if (PREDICT_FALSE ((d0->flags & MEMIF_DESC_FLAG_NEXT) && n_slots))
     814             :         {
     815           0 :           hb->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
     816           0 :           hb->total_length_not_including_first_buffer = 0;
     817           0 :         next_slot:
     818           0 :           s0 = cur_slot & mask;
     819           0 :           d0 = &ring->desc[s0];
     820           0 :           bi0 = mq->buffers[s0];
     821             : 
     822             :           /* previous buffer */
     823           0 :           b0->next_buffer = bi0;
     824           0 :           b0->flags |= VLIB_BUFFER_NEXT_PRESENT;
     825             : 
     826             :           /* current buffer */
     827           0 :           b0 = vlib_get_buffer (vm, bi0);
     828           0 :           b0->current_data = start_offset;
     829           0 :           b0->current_length = d0->length;
     830           0 :           hb->total_length_not_including_first_buffer += d0->length;
     831           0 :           n_rx_bytes += d0->length;
     832             : 
     833           0 :           cur_slot++;
     834           0 :           n_slots--;
     835           0 :           if ((d0->flags & MEMIF_DESC_FLAG_NEXT) && n_slots)
     836           0 :             goto next_slot;
     837             :         }
     838             :     }
     839             : 
     840             :   /* release slots from the ring */
     841          12 :   mq->last_tail = cur_slot;
     842             : 
     843          12 :   n_from = n_rx_packets;
     844          12 :   buffers = ptd->buffers;
     845             : 
     846          24 :   while (n_from)
     847             :     {
     848             :       u32 n_left_to_next;
     849             :       u32 next0, next1, next2, next3;
     850             : 
     851          12 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     852          12 :       while (n_from >= 8 && n_left_to_next >= 4)
     853             :         {
     854           0 :           b0 = vlib_get_buffer (vm, buffers[4]);
     855           0 :           b1 = vlib_get_buffer (vm, buffers[5]);
     856           0 :           b2 = vlib_get_buffer (vm, buffers[6]);
     857           0 :           b3 = vlib_get_buffer (vm, buffers[7]);
     858           0 :           vlib_prefetch_buffer_header (b0, STORE);
     859           0 :           vlib_prefetch_buffer_header (b1, STORE);
     860           0 :           vlib_prefetch_buffer_header (b2, STORE);
     861           0 :           vlib_prefetch_buffer_header (b3, STORE);
     862             : 
     863             :           /* enqueue buffer */
     864           0 :           to_next[0] = bi0 = buffers[0];
     865           0 :           to_next[1] = bi1 = buffers[1];
     866           0 :           to_next[2] = bi2 = buffers[2];
     867           0 :           to_next[3] = bi3 = buffers[3];
     868           0 :           to_next += 4;
     869           0 :           n_left_to_next -= 4;
     870           0 :           buffers += 4;
     871             : 
     872           0 :           b0 = vlib_get_buffer (vm, bi0);
     873           0 :           b1 = vlib_get_buffer (vm, bi1);
     874           0 :           b2 = vlib_get_buffer (vm, bi2);
     875           0 :           b3 = vlib_get_buffer (vm, bi3);
     876             : 
     877           0 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     878           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
     879           0 :           vnet_buffer (b1)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     880           0 :           vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
     881           0 :           vnet_buffer (b2)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     882           0 :           vnet_buffer (b2)->sw_if_index[VLIB_TX] = ~0;
     883           0 :           vnet_buffer (b3)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     884           0 :           vnet_buffer (b3)->sw_if_index[VLIB_TX] = ~0;
     885             : 
     886           0 :           if (mode == MEMIF_INTERFACE_MODE_IP)
     887             :             {
     888           0 :               next0 = memif_next_from_ip_hdr (node, b0);
     889           0 :               next1 = memif_next_from_ip_hdr (node, b1);
     890           0 :               next2 = memif_next_from_ip_hdr (node, b2);
     891           0 :               next3 = memif_next_from_ip_hdr (node, b3);
     892             :             }
     893           0 :           else if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
     894             :             {
     895           0 :               if (PREDICT_FALSE (mif->per_interface_next_index != ~0))
     896             :                 {
     897           0 :                   next0 = mif->per_interface_next_index;
     898           0 :                   next1 = mif->per_interface_next_index;
     899           0 :                   next2 = mif->per_interface_next_index;
     900           0 :                   next3 = mif->per_interface_next_index;
     901             :                 }
     902             :               else
     903             :                 {
     904           0 :                   next0 = next1 = next2 = next3 = next_index;
     905             :                   /* redirect if feature path enabled */
     906           0 :                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
     907             :                                                       &next0, b0);
     908           0 :                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
     909             :                                                       &next1, b1);
     910           0 :                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
     911             :                                                       &next2, b2);
     912           0 :                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
     913             :                                                       &next3, b3);
     914             :                 }
     915             :             }
     916             : 
     917             :           /* trace */
     918           0 :           if (PREDICT_FALSE (n_trace > 0))
     919             :             {
     920           0 :               memif_trace_buffer (vm, node, mif, b0, next0, qid, &n_trace);
     921           0 :               if (PREDICT_FALSE (n_trace > 0))
     922           0 :                 memif_trace_buffer (vm, node, mif, b1, next1, qid, &n_trace);
     923           0 :               if (PREDICT_FALSE (n_trace > 0))
     924           0 :                 memif_trace_buffer (vm, node, mif, b2, next2, qid, &n_trace);
     925           0 :               if (PREDICT_FALSE (n_trace > 0))
     926           0 :                 memif_trace_buffer (vm, node, mif, b3, next3, qid, &n_trace);
     927             :             }
     928             : 
     929             :           /* enqueue */
     930           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
     931             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
     932             :                                            next0, next1, next2, next3);
     933             : 
     934             :           /* next */
     935           0 :           n_from -= 4;
     936             :         }
     937          24 :       while (n_from && n_left_to_next)
     938             :         {
     939             :           /* enqueue buffer */
     940          12 :           to_next[0] = bi0 = buffers[0];
     941          12 :           to_next += 1;
     942          12 :           n_left_to_next--;
     943          12 :           buffers += 1;
     944             : 
     945          12 :           b0 = vlib_get_buffer (vm, bi0);
     946          12 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] = mif->sw_if_index;
     947          12 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
     948             : 
     949          12 :           if (mode == MEMIF_INTERFACE_MODE_IP)
     950             :             {
     951           0 :               next0 = memif_next_from_ip_hdr (node, b0);
     952             :             }
     953          12 :           else if (mode == MEMIF_INTERFACE_MODE_ETHERNET)
     954             :             {
     955          12 :               if (PREDICT_FALSE (mif->per_interface_next_index != ~0))
     956           0 :                 next0 = mif->per_interface_next_index;
     957             :               else
     958             :                 {
     959          12 :                   next0 = next_index;
     960             :                   /* redirect if feature path enabled */
     961          12 :                   vnet_feature_start_device_input_x1 (mif->sw_if_index,
     962             :                                                       &next0, b0);
     963             :                 }
     964             :             }
     965             : 
     966             :           /* trace */
     967          12 :           if (PREDICT_FALSE (n_trace > 0))
     968           0 :             memif_trace_buffer (vm, node, mif, b0, next0, qid, &n_trace);
     969             : 
     970             :           /* enqueue */
     971          12 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     972             :                                            n_left_to_next, bi0, next0);
     973             : 
     974             :           /* next */
     975          12 :           n_from--;
     976             :         }
     977          12 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     978             :     }
     979             : 
     980          12 :   vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters
     981             :                                    + VNET_INTERFACE_COUNTER_RX, thread_index,
     982             :                                    mif->sw_if_index, n_rx_packets,
     983             :                                    n_rx_bytes);
     984             : 
     985             :   /* refill ring with empty buffers */
     986     8602760 : refill:
     987     8602760 :   vec_reset_length (ptd->buffers);
     988             : 
     989     8602760 :   head = ring->head;
     990     8602760 :   n_slots = ring_size - head + mq->last_tail;
     991     8602760 :   slot = head & mask;
     992             : 
     993     8602760 :   n_slots &= ~7;
     994             : 
     995     8602760 :   if (n_slots < 32)
     996     8602750 :     goto done;
     997             : 
     998           7 :   memif_desc_t desc_template, *dt = &desc_template;
     999           7 :   clib_memset (dt, 0, sizeof (memif_desc_t));
    1000           7 :   dt->length = buffer_length;
    1001             : 
    1002          14 :   n_alloc = vlib_buffer_alloc_to_ring_from_pool (
    1003           7 :     vm, mq->buffers, slot, ring_size, n_slots, mq->buffer_pool_index);
    1004           7 :   dt->region = mq->buffer_pool_index + 1;
    1005           7 :   offset = (u64) mif->regions[dt->region].shm - start_offset;
    1006             : 
    1007           7 :   if (PREDICT_FALSE (n_alloc != n_slots))
    1008           0 :     vlib_error_count (vm, node->node_index,
    1009             :                       MEMIF_INPUT_ERROR_BUFFER_ALLOC_FAIL, 1);
    1010             : 
    1011           7 :   head += n_alloc;
    1012             : 
    1013         903 :   while (n_alloc)
    1014             :     {
    1015         896 :       memif_desc_t *d = ring->desc + slot;
    1016         896 :       u32 *bi = mq->buffers + slot;
    1017             : 
    1018         896 :       if (PREDICT_FALSE (((slot + 7 > mask) || (n_alloc < 8))))
    1019           0 :         goto one_by_one;
    1020             : 
    1021         896 :       clib_memcpy_fast (d + 0, dt, sizeof (memif_desc_t));
    1022         896 :       clib_memcpy_fast (d + 1, dt, sizeof (memif_desc_t));
    1023         896 :       clib_memcpy_fast (d + 2, dt, sizeof (memif_desc_t));
    1024         896 :       clib_memcpy_fast (d + 3, dt, sizeof (memif_desc_t));
    1025         896 :       clib_memcpy_fast (d + 4, dt, sizeof (memif_desc_t));
    1026         896 :       clib_memcpy_fast (d + 5, dt, sizeof (memif_desc_t));
    1027         896 :       clib_memcpy_fast (d + 6, dt, sizeof (memif_desc_t));
    1028         896 :       clib_memcpy_fast (d + 7, dt, sizeof (memif_desc_t));
    1029             : 
    1030         896 :       d[0].offset = (u64) vlib_get_buffer (vm, bi[0])->data - offset;
    1031         896 :       d[1].offset = (u64) vlib_get_buffer (vm, bi[1])->data - offset;
    1032         896 :       d[2].offset = (u64) vlib_get_buffer (vm, bi[2])->data - offset;
    1033         896 :       d[3].offset = (u64) vlib_get_buffer (vm, bi[3])->data - offset;
    1034         896 :       d[4].offset = (u64) vlib_get_buffer (vm, bi[4])->data - offset;
    1035         896 :       d[5].offset = (u64) vlib_get_buffer (vm, bi[5])->data - offset;
    1036         896 :       d[6].offset = (u64) vlib_get_buffer (vm, bi[6])->data - offset;
    1037         896 :       d[7].offset = (u64) vlib_get_buffer (vm, bi[7])->data - offset;
    1038             : 
    1039         896 :       slot = (slot + 8) & mask;
    1040         896 :       n_alloc -= 8;
    1041         896 :       continue;
    1042             : 
    1043           0 :     one_by_one:
    1044           0 :       clib_memcpy_fast (d, dt, sizeof (memif_desc_t));
    1045           0 :       d[0].offset = (u64) vlib_get_buffer (vm, bi[0])->data - offset;
    1046             : 
    1047           0 :       slot = (slot + 1) & mask;
    1048           0 :       n_alloc -= 1;
    1049             :     }
    1050             : 
    1051           7 :   __atomic_store_n (&ring->head, head, __ATOMIC_RELEASE);
    1052             : 
    1053     8602760 : done:
    1054     8602760 :   return n_rx_packets;
    1055             : }
    1056             : 
    1057        1677 : CLIB_MARCH_FN (memif_dma_completion_cb, void, vlib_main_t *vm,
    1058             :                vlib_dma_batch_t *b)
    1059             : {
    1060           0 :   memif_main_t *mm = &memif_main;
    1061           0 :   memif_if_t *mif = vec_elt_at_index (mm->interfaces, b->cookie >> 16);
    1062           0 :   u32 thread_index = vm->thread_index;
    1063           0 :   u32 n_left_to_next = 0;
    1064             :   u16 nexts[MEMIF_RX_VECTOR_SZ], *next;
    1065           0 :   u32 _to_next_bufs[MEMIF_RX_VECTOR_SZ], *to_next_bufs = _to_next_bufs, *bi;
    1066             :   uword n_trace;
    1067             :   memif_dma_info_t *dma_info;
    1068           0 :   u16 qid = b->cookie & 0xffff;
    1069           0 :   memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, qid);
    1070           0 :   dma_info = mq->dma_info + mq->dma_info_head;
    1071           0 :   memif_per_thread_data_t *ptd = &dma_info->data;
    1072           0 :   vnet_main_t *vnm = vnet_get_main ();
    1073             : 
    1074           0 :   u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
    1075             : 
    1076           0 :   __atomic_store_n (&mq->ring->tail, dma_info->dma_tail, __ATOMIC_RELEASE);
    1077             : 
    1078             :   /* prepare buffer template and next indices */
    1079           0 :   i16 start_offset =
    1080           0 :     (dma_info->mode == MEMIF_INTERFACE_MODE_IP) ? MEMIF_IP_OFFSET : 0;
    1081           0 :   vnet_buffer (&ptd->buffer_template)->sw_if_index[VLIB_RX] = mif->sw_if_index;
    1082           0 :   vnet_buffer (&ptd->buffer_template)->feature_arc_index = 0;
    1083           0 :   ptd->buffer_template.current_data = start_offset;
    1084           0 :   ptd->buffer_template.current_config_index = 0;
    1085           0 :   ptd->buffer_template.buffer_pool_index = mq->buffer_pool_index;
    1086           0 :   ptd->buffer_template.ref_count = 1;
    1087             : 
    1088           0 :   if (dma_info->mode == MEMIF_INTERFACE_MODE_ETHERNET)
    1089             :     {
    1090           0 :       next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
    1091           0 :       if (mif->per_interface_next_index != ~0)
    1092           0 :         next_index = mif->per_interface_next_index;
    1093             :       else
    1094           0 :         vnet_feature_start_device_input_x1 (mif->sw_if_index, &next_index,
    1095             :                                             &ptd->buffer_template);
    1096             : 
    1097           0 :       vlib_get_new_next_frame (vm, dma_info->node, next_index, to_next_bufs,
    1098             :                                n_left_to_next);
    1099           0 :       if (PREDICT_TRUE (next_index == VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT))
    1100             :         {
    1101             :           vlib_next_frame_t *nf;
    1102             :           vlib_frame_t *f;
    1103             :           ethernet_input_frame_t *ef;
    1104             :           nf =
    1105           0 :             vlib_node_runtime_get_next_frame (vm, dma_info->node, next_index);
    1106           0 :           f = vlib_get_frame (vm, nf->frame);
    1107           0 :           f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
    1108             : 
    1109           0 :           ef = vlib_frame_scalar_args (f);
    1110           0 :           ef->sw_if_index = mif->sw_if_index;
    1111           0 :           ef->hw_if_index = mif->hw_if_index;
    1112           0 :           vlib_frame_no_append (f);
    1113             :         }
    1114             :     }
    1115             : 
    1116           0 :   vec_reset_length (ptd->buffers);
    1117             : 
    1118           0 :   if (dma_info->mode == MEMIF_INTERFACE_MODE_IP)
    1119           0 :     memif_fill_buffer_mdata (vm, dma_info->node, ptd, mif, to_next_bufs, nexts,
    1120             :                              1);
    1121             :   else
    1122           0 :     memif_fill_buffer_mdata (vm, dma_info->node, ptd, mif, to_next_bufs, nexts,
    1123             :                              0);
    1124             : 
    1125             :   /* packet trace if enabled */
    1126           0 :   if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, dma_info->node))))
    1127             :     {
    1128           0 :       u32 n_left = ptd->n_packets;
    1129           0 :       bi = to_next_bufs;
    1130           0 :       next = nexts;
    1131           0 :       u32 ni = next_index;
    1132           0 :       while (n_trace && n_left)
    1133             :         {
    1134             :           vlib_buffer_t *b;
    1135             :           memif_input_trace_t *tr;
    1136           0 :           if (dma_info->mode != MEMIF_INTERFACE_MODE_ETHERNET)
    1137           0 :             ni = next[0];
    1138           0 :           b = vlib_get_buffer (vm, bi[0]);
    1139           0 :           if (PREDICT_TRUE (vlib_trace_buffer (vm, dma_info->node, ni, b,
    1140             :                                                /* follow_chain */ 0)))
    1141             :             {
    1142           0 :               tr = vlib_add_trace (vm, dma_info->node, b, sizeof (*tr));
    1143           0 :               tr->next_index = ni;
    1144           0 :               tr->hw_if_index = mif->hw_if_index;
    1145           0 :               tr->ring = qid;
    1146           0 :               n_trace--;
    1147             :             }
    1148             : 
    1149             :           /* next */
    1150           0 :           n_left--;
    1151           0 :           bi++;
    1152           0 :           next++;
    1153             :         }
    1154           0 :       vlib_set_trace_count (vm, dma_info->node, n_trace);
    1155             :     }
    1156             : 
    1157           0 :   if (dma_info->mode == MEMIF_INTERFACE_MODE_ETHERNET)
    1158             :     {
    1159           0 :       n_left_to_next -= ptd->n_packets;
    1160           0 :       vlib_put_next_frame (vm, dma_info->node, next_index, n_left_to_next);
    1161             :     }
    1162             :   else
    1163           0 :     vlib_buffer_enqueue_to_next (vm, dma_info->node, to_next_bufs, nexts,
    1164           0 :                                  ptd->n_packets);
    1165             : 
    1166           0 :   vlib_increment_combined_counter (
    1167             :     vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
    1168           0 :     thread_index, mif->sw_if_index, ptd->n_packets, ptd->n_rx_bytes);
    1169             : 
    1170           0 :   mq->dma_info_head++;
    1171           0 :   if (mq->dma_info_head == mq->dma_info_size)
    1172           0 :     mq->dma_info_head = 0;
    1173             : 
    1174           0 :   return;
    1175             : }
    1176             : 
    1177             : #ifndef CLIB_MARCH_VARIANT
    1178             : void
    1179           0 : memif_dma_completion_cb (vlib_main_t *vm, vlib_dma_batch_t *b)
    1180             : {
    1181           0 :   return CLIB_MARCH_FN_SELECT (memif_dma_completion_cb) (vm, b);
    1182             : }
    1183             : #endif
    1184             : 
    1185             : static_always_inline uword
    1186           0 : memif_device_input_inline_dma (vlib_main_t *vm, vlib_node_runtime_t *node,
    1187             :                                memif_if_t *mif, memif_ring_type_t type,
    1188             :                                u16 qid, memif_interface_mode_t mode)
    1189             : {
    1190           0 :   memif_main_t *mm = &memif_main;
    1191             :   memif_ring_t *ring;
    1192             :   memif_queue_t *mq;
    1193             :   memif_per_thread_data_t *ptd;
    1194             :   u16 cur_slot, n_slots;
    1195             :   u16 n_buffers, n_alloc, n_desc;
    1196             :   memif_copy_op_t *co;
    1197             :   memif_dma_info_t *dma_info;
    1198             : 
    1199           0 :   u16 mif_id = mif - mm->interfaces;
    1200             :   u32 i;
    1201             : 
    1202           0 :   mq = vec_elt_at_index (mif->rx_queues, qid);
    1203           0 :   ring = mq->ring;
    1204             : 
    1205           0 :   cur_slot = mq->last_head;
    1206           0 :   n_slots = __atomic_load_n (&ring->head, __ATOMIC_ACQUIRE) - cur_slot;
    1207             : 
    1208           0 :   if (n_slots == 0)
    1209           0 :     return 0;
    1210             : 
    1211           0 :   if ((mq->dma_info_tail + 1 == mq->dma_info_head) ||
    1212           0 :       ((mq->dma_info_head == mq->dma_info_size - 1) &&
    1213           0 :        (mq->dma_info_tail == 0)))
    1214           0 :     return 0;
    1215             : 
    1216             :   vlib_dma_batch_t *db;
    1217           0 :   db = vlib_dma_batch_new (vm, mif->dma_input_config);
    1218           0 :   if (!db)
    1219           0 :     return 0;
    1220             : 
    1221           0 :   dma_info = mq->dma_info + mq->dma_info_tail;
    1222           0 :   dma_info->node = node;
    1223           0 :   dma_info->mode = mode;
    1224           0 :   ptd = &dma_info->data;
    1225           0 :   vec_validate_aligned (dma_info->data.desc_len,
    1226             :                         pow2_mask (mq->log2_ring_size), CLIB_CACHE_LINE_BYTES);
    1227             : 
    1228           0 :   n_desc = memif_parse_desc (&dma_info->data, mif, mq, cur_slot, n_slots);
    1229           0 :   cur_slot += n_desc;
    1230             : 
    1231           0 :   if (mif->mode == MEMIF_INTERFACE_MODE_ETHERNET)
    1232           0 :     memif_validate_desc_data (&dma_info->data, mif, n_desc,
    1233             :                               /* is_ethernet */ 1);
    1234             :   else
    1235           0 :     memif_validate_desc_data (&dma_info->data, mif, n_desc,
    1236             :                               /* is_ethernet */ 0);
    1237             : 
    1238           0 :   n_buffers = memif_process_desc (vm, node, ptd, mif);
    1239             : 
    1240           0 :   if (PREDICT_FALSE (n_buffers == 0))
    1241             :     {
    1242             :       /* All descriptors are bad. Release slots in the ring and bail */
    1243           0 :       memif_advance_ring (type, mq, ring, cur_slot);
    1244           0 :       goto done;
    1245             :     }
    1246             : 
    1247             :   /* allocate free buffers */
    1248           0 :   vec_validate_aligned (dma_info->data.buffers, n_buffers - 1,
    1249             :                         CLIB_CACHE_LINE_BYTES);
    1250           0 :   n_alloc = vlib_buffer_alloc_from_pool (vm, dma_info->data.buffers, n_buffers,
    1251           0 :                                          mq->buffer_pool_index);
    1252           0 :   if (PREDICT_FALSE (n_alloc != n_buffers))
    1253             :     {
    1254           0 :       if (n_alloc)
    1255           0 :         vlib_buffer_free (vm, dma_info->data.buffers, n_alloc);
    1256           0 :       vlib_error_count (vm, node->node_index,
    1257             :                         MEMIF_INPUT_ERROR_BUFFER_ALLOC_FAIL, 1);
    1258           0 :       goto done;
    1259             :     }
    1260             : 
    1261           0 :   dma_info->data.n_rx_bytes = ptd->n_rx_bytes;
    1262           0 :   dma_info->data.n_packets = ptd->n_packets;
    1263             :   /* copy data */
    1264             :   vlib_buffer_t *b;
    1265           0 :   u32 n_pkts = clib_min (MEMIF_RX_VECTOR_SZ, vec_len (ptd->copy_ops));
    1266           0 :   co = ptd->copy_ops;
    1267             : 
    1268           0 :   for (i = 0; i < n_pkts; i++)
    1269             :     {
    1270           0 :       b = vlib_get_buffer (vm, ptd->buffers[co[i].buffer_vec_index]);
    1271           0 :       vlib_dma_batch_add (vm, db, b->data + co[i].buffer_offset, co[i].data,
    1272           0 :                           co[i].data_len);
    1273             :     }
    1274             : 
    1275           0 :   for (i = n_pkts; i < vec_len (ptd->copy_ops); i++)
    1276             :     {
    1277           0 :       b = vlib_get_buffer (vm, ptd->buffers[co[i].buffer_vec_index]);
    1278           0 :       vlib_dma_batch_add (vm, db, b->data + co[i].buffer_offset, co[i].data,
    1279           0 :                           co[i].data_len);
    1280             :     }
    1281             : 
    1282           0 :   dma_info->dma_tail = cur_slot;
    1283           0 :   mq->last_head = dma_info->dma_tail;
    1284           0 :   mq->dma_info_tail++;
    1285           0 :   if (mq->dma_info_tail == mq->dma_info_size)
    1286           0 :     mq->dma_info_tail = 0;
    1287             : 
    1288           0 : done:
    1289           0 :   vlib_dma_batch_set_cookie (vm, db, ((u64) mif_id << 16) | qid);
    1290           0 :   vlib_dma_batch_submit (vm, db);
    1291           0 :   vec_reset_length (ptd->copy_ops);
    1292             : 
    1293           0 :   return ptd->n_packets;
    1294             : }
    1295             : 
    1296     4991396 : VLIB_NODE_FN (memif_input_node) (vlib_main_t * vm,
    1297             :                                  vlib_node_runtime_t * node,
    1298             :                                  vlib_frame_t * frame)
    1299             : {
    1300     4989160 :   u32 n_rx = 0;
    1301     4989160 :   memif_main_t *mm = &memif_main;
    1302     4989160 :   memif_interface_mode_t mode_ip = MEMIF_INTERFACE_MODE_IP;
    1303     4989160 :   memif_interface_mode_t mode_eth = MEMIF_INTERFACE_MODE_ETHERNET;
    1304             : 
    1305             :   vnet_hw_if_rxq_poll_vector_t *pv;
    1306     4989160 :   pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
    1307    22203900 :   for (int i = 0; i < vec_len (pv); i++)
    1308             :     {
    1309             :       memif_if_t *mif;
    1310             :       u32 qid;
    1311    17214700 :       mif = vec_elt_at_index (mm->interfaces, pv[i].dev_instance);
    1312    17214700 :       qid = pv[i].queue_id;
    1313    17214700 :       if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) &&
    1314    17208600 :           (mif->flags & MEMIF_IF_FLAG_CONNECTED))
    1315             :         {
    1316    17208600 :           if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
    1317             :             {
    1318     8602760 :               if (mif->mode == MEMIF_INTERFACE_MODE_IP)
    1319           0 :                 n_rx +=
    1320           0 :                   memif_device_input_zc_inline (vm, node, mif, qid, mode_ip);
    1321             :               else
    1322     8602760 :                 n_rx +=
    1323     8602760 :                   memif_device_input_zc_inline (vm, node, mif, qid, mode_eth);
    1324             :             }
    1325     8605830 :           else if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
    1326             :             {
    1327           0 :               if (mif->mode == MEMIF_INTERFACE_MODE_IP)
    1328           0 :                 n_rx += memif_device_input_inline (
    1329             :                   vm, node, mif, MEMIF_RING_M2S, qid, mode_ip);
    1330             :               else
    1331           0 :                 n_rx += memif_device_input_inline (
    1332             :                   vm, node, mif, MEMIF_RING_M2S, qid, mode_eth);
    1333             :             }
    1334             :           else
    1335             :             {
    1336     8605830 :               if ((mif->flags & MEMIF_IF_FLAG_USE_DMA) &&
    1337           0 :                   (mif->dma_input_config >= 0))
    1338             :                 {
    1339           0 :                   if (mif->mode == MEMIF_INTERFACE_MODE_IP)
    1340           0 :                     n_rx += memif_device_input_inline_dma (
    1341             :                       vm, node, mif, MEMIF_RING_S2M, qid, mode_ip);
    1342             :                   else
    1343           0 :                     n_rx += memif_device_input_inline_dma (
    1344             :                       vm, node, mif, MEMIF_RING_S2M, qid, mode_eth);
    1345             :                 }
    1346             :               else
    1347             :                 {
    1348     8605830 :                   if (mif->mode == MEMIF_INTERFACE_MODE_IP)
    1349           0 :                     n_rx += memif_device_input_inline (
    1350             :                       vm, node, mif, MEMIF_RING_S2M, qid, mode_ip);
    1351             :                   else
    1352     8605830 :                     n_rx += memif_device_input_inline (
    1353             :                       vm, node, mif, MEMIF_RING_S2M, qid, mode_eth);
    1354             :                 }
    1355             :             }
    1356             :         }
    1357             :     }
    1358             : 
    1359     4989160 :   return n_rx;
    1360             : }
    1361             : 
    1362             : /* *INDENT-OFF* */
    1363       76184 : VLIB_REGISTER_NODE (memif_input_node) = {
    1364             :   .name = "memif-input",
    1365             :   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
    1366             :   .sibling_of = "device-input",
    1367             :   .format_trace = format_memif_input_trace,
    1368             :   .type = VLIB_NODE_TYPE_INPUT,
    1369             :   .state = VLIB_NODE_STATE_INTERRUPT,
    1370             :   .n_errors = MEMIF_INPUT_N_ERROR,
    1371             :   .error_counters = memif_input_error_counters,
    1372             : };
    1373             : 
    1374             : /* *INDENT-ON* */
    1375             : 
    1376             : 
    1377             : /*
    1378             :  * fd.io coding-style-patch-verification: ON
    1379             :  *
    1380             :  * Local Variables:
    1381             :  * eval: (c-set-style "gnu")
    1382             :  * End:
    1383             :  */

Generated by: LCOV version 1.14