LCOV - code coverage report
Current view: top level - plugins/af_xdp - input.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 2 170 1.2 %
Date: 2023-07-05 22:20:52 Functions: 6 17 35.3 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vlib/unix/unix.h>
      20             : #include <vlib/pci/pci.h>
      21             : #include <vnet/ethernet/ethernet.h>
      22             : #include <vnet/devices/devices.h>
      23             : #include <vnet/interface/rx_queue_funcs.h>
      24             : #include "af_xdp.h"
      25             : 
      26             : #define foreach_af_xdp_input_error                                            \
      27             :   _ (SYSCALL_REQUIRED, "syscall required")                                    \
      28             :   _ (SYSCALL_FAILURES, "syscall failures")
      29             : 
      30             : typedef enum
      31             : {
      32             : #define _(f,s) AF_XDP_INPUT_ERROR_##f,
      33             :   foreach_af_xdp_input_error
      34             : #undef _
      35             :     AF_XDP_INPUT_N_ERROR,
      36             : } af_xdp_input_error_t;
      37             : 
      38             : static __clib_unused char *af_xdp_input_error_strings[] = {
      39             : #define _(n,s) s,
      40             :   foreach_af_xdp_input_error
      41             : #undef _
      42             : };
      43             : 
      44             : static_always_inline void
      45           0 : af_xdp_device_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
      46             :                            u32 n_left, const u32 * bi, u32 next_index,
      47             :                            u32 hw_if_index)
      48             : {
      49           0 :   u32 n_trace = vlib_get_trace_count (vm, node);
      50             : 
      51           0 :   if (PREDICT_TRUE (0 == n_trace))
      52           0 :     return;
      53             : 
      54           0 :   while (n_trace && n_left)
      55             :     {
      56           0 :       vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
      57           0 :       if (PREDICT_TRUE
      58             :           (vlib_trace_buffer (vm, node, next_index, b, /* follow_chain */ 0)))
      59             :         {
      60             :           af_xdp_input_trace_t *tr =
      61           0 :             vlib_add_trace (vm, node, b, sizeof (*tr));
      62           0 :           tr->next_index = next_index;
      63           0 :           tr->hw_if_index = hw_if_index;
      64           0 :           n_trace--;
      65             :         }
      66           0 :       n_left--;
      67           0 :       bi++;
      68             :     }
      69             : 
      70           0 :   vlib_set_trace_count (vm, node, n_trace);
      71             : }
      72             : 
      73             : static_always_inline void
      74           0 : af_xdp_device_input_refill_db (vlib_main_t * vm,
      75             :                                const vlib_node_runtime_t * node,
      76             :                                af_xdp_device_t * ad, af_xdp_rxq_t * rxq,
      77             :                                const u32 n_alloc)
      78             : {
      79           0 :   xsk_ring_prod__submit (&rxq->fq, n_alloc);
      80             : 
      81           0 :   if (AF_XDP_RXQ_MODE_INTERRUPT == rxq->mode ||
      82           0 :       !xsk_ring_prod__needs_wakeup (&rxq->fq))
      83           0 :     return;
      84             : 
      85           0 :   if (node)
      86           0 :     vlib_error_count (vm, node->node_index,
      87             :                       AF_XDP_INPUT_ERROR_SYSCALL_REQUIRED, 1);
      88             : 
      89           0 :   if (clib_spinlock_trylock_if_init (&rxq->syscall_lock))
      90             :     {
      91           0 :       int ret = recvmsg (rxq->xsk_fd, 0, MSG_DONTWAIT);
      92           0 :       clib_spinlock_unlock_if_init (&rxq->syscall_lock);
      93           0 :       if (PREDICT_FALSE (ret < 0))
      94             :         {
      95             :           /* something bad is happening */
      96           0 :           if (node)
      97           0 :             vlib_error_count (vm, node->node_index,
      98             :                               AF_XDP_INPUT_ERROR_SYSCALL_FAILURES, 1);
      99           0 :           af_xdp_device_error (ad, "rx poll() failed");
     100             :         }
     101             :     }
     102             : }
     103             : 
     104             : static_always_inline void
     105           0 : af_xdp_device_input_refill_inline (vlib_main_t *vm,
     106             :                                    const vlib_node_runtime_t *node,
     107             :                                    af_xdp_device_t *ad, af_xdp_rxq_t *rxq)
     108             : {
     109             :   __u64 *fill;
     110           0 :   const u32 size = rxq->fq.size;
     111           0 :   const u32 mask = size - 1;
     112           0 :   u32 bis[VLIB_FRAME_SIZE], *bi = bis;
     113             :   u32 n_alloc, n, n_wrap;
     114           0 :   u32 idx = 0;
     115             : 
     116           0 :   ASSERT (mask == rxq->fq.mask);
     117             : 
     118             :   /* do not enqueue more packet than ring space */
     119           0 :   n_alloc = xsk_prod_nb_free (&rxq->fq, 16);
     120             :   /* do not bother to allocate if too small */
     121           0 :   if (n_alloc < 16)
     122           0 :     return;
     123             : 
     124           0 :   n_alloc = clib_min (n_alloc, ARRAY_LEN (bis));
     125           0 :   n_alloc = vlib_buffer_alloc_from_pool (vm, bis, n_alloc, ad->pool);
     126           0 :   n = xsk_ring_prod__reserve (&rxq->fq, n_alloc, &idx);
     127           0 :   ASSERT (n == n_alloc);
     128             : 
     129           0 :   fill = xsk_ring_prod__fill_addr (&rxq->fq, idx);
     130           0 :   n = clib_min (n_alloc, size - (idx & mask));
     131           0 :   n_wrap = n_alloc - n;
     132             : 
     133             : #define bi2addr(bi) ((bi) << CLIB_LOG2_CACHE_LINE_BYTES)
     134             : 
     135           0 : wrap_around:
     136             : 
     137           0 :   while (n >= 8)
     138             :     {
     139             : #ifdef CLIB_HAVE_VEC256
     140           0 :       u64x4 b0 = u64x4_from_u32x4 (*(u32x4u *) (bi + 0));
     141           0 :       u64x4 b1 = u64x4_from_u32x4 (*(u32x4u *) (bi + 4));
     142           0 :       *(u64x4u *) (fill + 0) = bi2addr (b0);
     143           0 :       *(u64x4u *) (fill + 4) = bi2addr (b1);
     144             : #else
     145           0 :       fill[0] = bi2addr (bi[0]);
     146           0 :       fill[1] = bi2addr (bi[1]);
     147           0 :       fill[2] = bi2addr (bi[2]);
     148           0 :       fill[3] = bi2addr (bi[3]);
     149           0 :       fill[4] = bi2addr (bi[4]);
     150           0 :       fill[5] = bi2addr (bi[5]);
     151           0 :       fill[6] = bi2addr (bi[6]);
     152           0 :       fill[7] = bi2addr (bi[7]);
     153             : #endif
     154           0 :       fill += 8;
     155           0 :       bi += 8;
     156           0 :       n -= 8;
     157             :     }
     158             : 
     159           0 :   while (n >= 1)
     160             :     {
     161           0 :       fill[0] = bi2addr (bi[0]);
     162           0 :       fill += 1;
     163           0 :       bi += 1;
     164           0 :       n -= 1;
     165             :     }
     166             : 
     167           0 :   if (n_wrap)
     168             :     {
     169           0 :       fill = xsk_ring_prod__fill_addr (&rxq->fq, 0);
     170           0 :       n = n_wrap;
     171           0 :       n_wrap = 0;
     172           0 :       goto wrap_around;
     173             :     }
     174             : 
     175           0 :   af_xdp_device_input_refill_db (vm, node, ad, rxq, n_alloc);
     176             : }
     177             : 
     178             : static_always_inline void
     179           0 : af_xdp_device_input_ethernet (vlib_main_t * vm, vlib_node_runtime_t * node,
     180             :                               const u32 next_index, const u32 sw_if_index,
     181             :                               const u32 hw_if_index)
     182             : {
     183             :   vlib_next_frame_t *nf;
     184             :   vlib_frame_t *f;
     185             :   ethernet_input_frame_t *ef;
     186             : 
     187           0 :   if (PREDICT_FALSE (VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT != next_index))
     188           0 :     return;
     189             : 
     190             :   nf =
     191           0 :     vlib_node_runtime_get_next_frame (vm, node,
     192             :                                       VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT);
     193           0 :   f = vlib_get_frame (vm, nf->frame);
     194           0 :   f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
     195             : 
     196           0 :   ef = vlib_frame_scalar_args (f);
     197           0 :   ef->sw_if_index = sw_if_index;
     198           0 :   ef->hw_if_index = hw_if_index;
     199           0 :   vlib_frame_no_append (f);
     200             : }
     201             : 
     202             : static_always_inline u32
     203           0 : af_xdp_device_input_bufs (vlib_main_t *vm, const af_xdp_device_t *ad,
     204             :                           af_xdp_rxq_t *rxq, u32 *bis, const u32 n_rx,
     205             :                           vlib_buffer_t *bt, u32 idx)
     206             : {
     207           0 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     208           0 :   u16 offs[VLIB_FRAME_SIZE], *off = offs;
     209           0 :   u16 lens[VLIB_FRAME_SIZE], *len = lens;
     210           0 :   const u32 mask = rxq->rx.mask;
     211           0 :   u32 n = n_rx, *bi = bis, bytes = 0;
     212             : 
     213             : #define addr2bi(addr) ((addr) >> CLIB_LOG2_CACHE_LINE_BYTES)
     214             : 
     215           0 :   while (n >= 1)
     216             :     {
     217           0 :       const struct xdp_desc *desc = xsk_ring_cons__rx_desc (&rxq->rx, idx);
     218           0 :       const u64 addr = desc->addr;
     219           0 :       bi[0] = addr2bi (xsk_umem__extract_addr (addr));
     220           0 :       ASSERT (vlib_buffer_is_known (vm, bi[0]) ==
     221             :               VLIB_BUFFER_KNOWN_ALLOCATED);
     222           0 :       off[0] = xsk_umem__extract_offset (addr) - sizeof (vlib_buffer_t);
     223           0 :       len[0] = desc->len;
     224           0 :       idx = (idx + 1) & mask;
     225           0 :       bi += 1;
     226           0 :       off += 1;
     227           0 :       len += 1;
     228           0 :       n -= 1;
     229             :     }
     230             : 
     231           0 :   vlib_get_buffers (vm, bis, bufs, n_rx);
     232             : 
     233           0 :   n = n_rx;
     234           0 :   off = offs;
     235           0 :   len = lens;
     236             : 
     237           0 :   while (n >= 8)
     238             :     {
     239           0 :       vlib_prefetch_buffer_header (b[4], LOAD);
     240           0 :       vlib_buffer_copy_template (b[0], bt);
     241           0 :       b[0]->current_data = off[0];
     242           0 :       bytes += b[0]->current_length = len[0];
     243             : 
     244           0 :       vlib_prefetch_buffer_header (b[5], LOAD);
     245           0 :       vlib_buffer_copy_template (b[1], bt);
     246           0 :       b[1]->current_data = off[1];
     247           0 :       bytes += b[1]->current_length = len[1];
     248             : 
     249           0 :       vlib_prefetch_buffer_header (b[6], LOAD);
     250           0 :       vlib_buffer_copy_template (b[2], bt);
     251           0 :       b[2]->current_data = off[2];
     252           0 :       bytes += b[2]->current_length = len[2];
     253             : 
     254           0 :       vlib_prefetch_buffer_header (b[7], LOAD);
     255           0 :       vlib_buffer_copy_template (b[3], bt);
     256           0 :       b[3]->current_data = off[3];
     257           0 :       bytes += b[3]->current_length = len[3];
     258             : 
     259           0 :       b += 4;
     260           0 :       off += 4;
     261           0 :       len += 4;
     262           0 :       n -= 4;
     263             :     }
     264             : 
     265           0 :   while (n >= 1)
     266             :     {
     267           0 :       vlib_buffer_copy_template (b[0], bt);
     268           0 :       b[0]->current_data = off[0];
     269           0 :       bytes += b[0]->current_length = len[0];
     270           0 :       b += 1;
     271           0 :       off += 1;
     272           0 :       len += 1;
     273           0 :       n -= 1;
     274             :     }
     275             : 
     276           0 :   xsk_ring_cons__release (&rxq->rx, n_rx);
     277           0 :   return bytes;
     278             : }
     279             : 
     280             : static_always_inline uword
     281           0 : af_xdp_device_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     282             :                             vlib_frame_t *frame, af_xdp_device_t *ad, u16 qid)
     283             : {
     284           0 :   vnet_main_t *vnm = vnet_get_main ();
     285           0 :   af_xdp_rxq_t *rxq = vec_elt_at_index (ad->rxqs, qid);
     286             :   vlib_buffer_t bt;
     287             :   u32 next_index, *to_next, n_left_to_next;
     288             :   u32 n_rx_packets, n_rx_bytes;
     289             :   u32 idx;
     290             : 
     291           0 :   n_rx_packets = xsk_ring_cons__peek (&rxq->rx, VLIB_FRAME_SIZE, &idx);
     292             : 
     293           0 :   if (PREDICT_FALSE (0 == n_rx_packets))
     294           0 :     goto refill;
     295             : 
     296           0 :   vlib_buffer_copy_template (&bt, ad->buffer_template);
     297           0 :   next_index = ad->per_interface_next_index;
     298           0 :   if (PREDICT_FALSE (vnet_device_input_have_features (ad->sw_if_index)))
     299           0 :     vnet_feature_start_device_input_x1 (ad->sw_if_index, &next_index, &bt);
     300             : 
     301           0 :   vlib_get_new_next_frame (vm, node, next_index, to_next, n_left_to_next);
     302             : 
     303             :   n_rx_bytes =
     304           0 :     af_xdp_device_input_bufs (vm, ad, rxq, to_next, n_rx_packets, &bt, idx);
     305           0 :   af_xdp_device_input_ethernet (vm, node, next_index, ad->sw_if_index,
     306             :                                 ad->hw_if_index);
     307             : 
     308           0 :   vlib_put_next_frame (vm, node, next_index, n_left_to_next - n_rx_packets);
     309             : 
     310           0 :   af_xdp_device_input_trace (vm, node, n_rx_packets, to_next, next_index,
     311             :                              ad->hw_if_index);
     312             : 
     313           0 :   vlib_increment_combined_counter
     314             :     (vnm->interface_main.combined_sw_if_counters +
     315             :      VNET_INTERFACE_COUNTER_RX, vm->thread_index,
     316             :      ad->hw_if_index, n_rx_packets, n_rx_bytes);
     317             : 
     318           0 : refill:
     319           0 :   af_xdp_device_input_refill_inline (vm, node, ad, rxq);
     320             : 
     321           0 :   return n_rx_packets;
     322             : }
     323             : 
     324        2236 : VLIB_NODE_FN (af_xdp_input_node) (vlib_main_t * vm,
     325             :                                   vlib_node_runtime_t * node,
     326             :                                   vlib_frame_t * frame)
     327             : {
     328           0 :   u32 n_rx = 0;
     329           0 :   af_xdp_main_t *am = &af_xdp_main;
     330             :   vnet_hw_if_rxq_poll_vector_t *p,
     331           0 :     *pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
     332             : 
     333           0 :   vec_foreach (p, pv)
     334             :     {
     335           0 :       af_xdp_device_t *ad = vec_elt_at_index (am->devices, p->dev_instance);
     336           0 :       if ((ad->flags & AF_XDP_DEVICE_F_ADMIN_UP) == 0)
     337           0 :         continue;
     338           0 :       n_rx += af_xdp_device_input_inline (vm, node, frame, ad, p->queue_id);
     339             :     }
     340             : 
     341           0 :   return n_rx;
     342             : }
     343             : 
     344             : #ifndef CLIB_MARCH_VARIANT
     345             : void
     346           0 : af_xdp_device_input_refill (af_xdp_device_t *ad)
     347             : {
     348           0 :   vlib_main_t *vm = vlib_get_main ();
     349             :   af_xdp_rxq_t *rxq;
     350           0 :   vec_foreach (rxq, ad->rxqs)
     351           0 :     af_xdp_device_input_refill_inline (vm, 0, ad, rxq);
     352           0 : }
     353             : #endif /* CLIB_MARCH_VARIANT */
     354             : 
     355             : /* *INDENT-OFF* */
     356      166920 : VLIB_REGISTER_NODE (af_xdp_input_node) = {
     357             :   .name = "af_xdp-input",
     358             :   .sibling_of = "device-input",
     359             :   .format_trace = format_af_xdp_input_trace,
     360             :   .type = VLIB_NODE_TYPE_INPUT,
     361             :   .state = VLIB_NODE_STATE_DISABLED,
     362             :   .n_errors = AF_XDP_INPUT_N_ERROR,
     363             :   .error_strings = af_xdp_input_error_strings,
     364             :   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
     365             : };
     366             : /* *INDENT-ON* */
     367             : 
     368             : /*
     369             :  * fd.io coding-style-patch-verification: ON
     370             :  *
     371             :  * Local Variables:
     372             :  * eval: (c-set-style "gnu")
     373             :  * End:
     374             :  */

Generated by: LCOV version 1.14