LCOV - code coverage report
Current view: top level - vnet/devices/virtio - virtio_pre_input.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 35 47 74.5 %
Date: 2023-07-05 22:20:52 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2021 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 <vnet/gso/gro_func.h>
      20             : #include <vnet/interface/tx_queue_funcs.h>
      21             : #include <vnet/devices/virtio/virtio.h>
      22             : #include <vnet/devices/virtio/virtio_inline.h>
      23             : 
      24             : static_always_inline uword
      25   159937000 : virtio_pre_input_inline (vlib_main_t *vm, vnet_virtio_vring_t *txq_vring,
      26             :                          vnet_hw_if_tx_queue_t *txq, u8 packet_coalesce,
      27             :                          u8 packet_buffering)
      28             : {
      29   159937000 :   if (txq->shared_queue)
      30             :     {
      31           0 :       if (clib_spinlock_trylock (&txq_vring->lockp))
      32             :         {
      33           0 :           if (virtio_txq_is_scheduled (txq_vring))
      34           0 :             goto unlock;
      35           0 :           if (packet_coalesce)
      36           0 :             vnet_gro_flow_table_schedule_node_on_dispatcher (
      37             :               vm, txq, txq_vring->flow_table);
      38           0 :           else if (packet_buffering)
      39           0 :             virtio_vring_buffering_schedule_node_on_dispatcher (
      40             :               vm, txq, txq_vring->buffering);
      41           0 :           virtio_txq_set_scheduled (txq_vring);
      42           0 :         unlock:
      43           0 :           clib_spinlock_unlock (&txq_vring->lockp);
      44             :         }
      45             :     }
      46             :   else
      47             :     {
      48   159937000 :       if (packet_coalesce)
      49   159937000 :         vnet_gro_flow_table_schedule_node_on_dispatcher (
      50             :           vm, txq, txq_vring->flow_table);
      51           0 :       else if (packet_buffering)
      52           0 :         virtio_vring_buffering_schedule_node_on_dispatcher (
      53             :           vm, txq, txq_vring->buffering);
      54             :     }
      55   159937000 :   return 0;
      56             : }
      57             : 
      58             : static uword
      59   148663000 : virtio_pre_input (vlib_main_t *vm, vlib_node_runtime_t *node,
      60             :                   vlib_frame_t *frame)
      61             : {
      62   148663000 :   virtio_main_t *vim = &virtio_main;
      63   148663000 :   vnet_main_t *vnm = vnet_get_main ();
      64             :   virtio_if_t *vif;
      65             : 
      66   407297000 :   pool_foreach (vif, vim->interfaces)
      67             :     {
      68   258634000 :       if (vif->packet_coalesce || vif->packet_buffering)
      69             :         {
      70             :           vnet_virtio_vring_t *txq_vring;
      71   319874000 :           vec_foreach (txq_vring, vif->txq_vrings)
      72             :             {
      73             :               vnet_hw_if_tx_queue_t *txq =
      74   159937000 :                 vnet_hw_if_get_tx_queue (vnm, txq_vring->queue_index);
      75   159937000 :               if (clib_bitmap_get (txq->threads, vm->thread_index) == 1)
      76   159937000 :                 virtio_pre_input_inline (vm, txq_vring, txq,
      77   159937000 :                                          vif->packet_coalesce,
      78   159937000 :                                          vif->packet_buffering);
      79             :             }
      80             :         }
      81             :     }
      82             : 
      83   148663000 :   return 0;
      84             : }
      85             : 
      86             : /**
      87             :  * virtio interfaces support packet coalescing and buffering which
      88             :  * depends on timer expiry to flush the stored packets periodically.
      89             :  * Previously, virtio input node checked timer expiry and scheduled
      90             :  * tx queue accordingly.
      91             :  *
      92             :  * In poll mode, timer expiry was handled naturally, as input node
      93             :  * runs periodically. In interrupt mode, virtio input node was dependent
      94             :  * on the interrupts send from backend. Stored packets could starve,
      95             :  * if there would not be interrupts to input node.
      96             :  *
      97             :  * This problem had been solved through a dedicated process node which
      98             :  * periodically sends interrupt to virtio input node given coalescing
      99             :  * or buffering feature were enabled on an interface.
     100             :  *
     101             :  * But that approach worked with following limitations:
     102             :  * 1) Each VPP thread should have (atleast) 1 rx queue of an interface
     103             :  * (with buffering enabled). And rxqs and txqs should be placed on the
     104             :  * same thread.
     105             :  *
     106             :  * New design provides solution to above problem(s) without any limitation
     107             :  * through (dedicated) pre-input node running on each VPP thread when
     108             :  * atleast 1 virtio interface is enabled with coalescing or buffering.
     109             :  */
     110      178120 : VLIB_REGISTER_NODE (virtio_pre_input_node) = {
     111             :   .function = virtio_pre_input,
     112             :   .type = VLIB_NODE_TYPE_PRE_INPUT,
     113             :   .name = "virtio-pre-input",
     114             :   .state = VLIB_NODE_STATE_DISABLED,
     115             : };
     116             : 
     117             : void
     118         300 : virtio_pre_input_node_enable (vlib_main_t *vm, virtio_if_t *vif)
     119             : {
     120         300 :   virtio_main_t *vim = &virtio_main;
     121         300 :   if (vif->packet_coalesce || vif->packet_buffering)
     122             :     {
     123         108 :       vim->gro_or_buffering_if_count++;
     124         108 :       if (vim->gro_or_buffering_if_count == 1)
     125             :         {
     126         192 :           foreach_vlib_main ()
     127             :             {
     128          96 :               vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
     129             :                                    VLIB_NODE_STATE_POLLING);
     130             :             }
     131             :         }
     132             :     }
     133         300 : }
     134             : 
     135             : void
     136         300 : virtio_pre_input_node_disable (vlib_main_t *vm, virtio_if_t *vif)
     137             : {
     138         300 :   virtio_main_t *vim = &virtio_main;
     139         300 :   if (vif->packet_coalesce || vif->packet_buffering)
     140             :     {
     141         108 :       if (vim->gro_or_buffering_if_count > 0)
     142         108 :         vim->gro_or_buffering_if_count--;
     143         108 :       if (vim->gro_or_buffering_if_count == 0)
     144             :         {
     145         192 :           foreach_vlib_main ()
     146             :             {
     147          96 :               vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
     148             :                                    VLIB_NODE_STATE_DISABLED);
     149             :             }
     150             :         }
     151             :     }
     152         300 : }
     153             : 
     154             : /*
     155             :  * fd.io coding-style-patch-verification: ON
     156             :  *
     157             :  * Local Variables:
     158             :  * eval: (c-set-style "gnu")
     159             :  * End:
     160             :  */

Generated by: LCOV version 1.14