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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
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>
24 static_always_inline uword
25 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,
29 if (txq->shared_queue)
31 if (clib_spinlock_trylock (&txq_vring->lockp))
33 if (virtio_txq_is_scheduled (txq_vring))
36 vnet_gro_flow_table_schedule_node_on_dispatcher (
37 vm, txq, txq_vring->flow_table);
38 else if (packet_buffering)
39 virtio_vring_buffering_schedule_node_on_dispatcher (
40 vm, txq, txq_vring->buffering);
41 virtio_txq_set_scheduled (txq_vring);
43 clib_spinlock_unlock (&txq_vring->lockp);
49 vnet_gro_flow_table_schedule_node_on_dispatcher (
50 vm, txq, txq_vring->flow_table);
51 else if (packet_buffering)
52 virtio_vring_buffering_schedule_node_on_dispatcher (
53 vm, txq, txq_vring->buffering);
59 virtio_pre_input (vlib_main_t *vm, vlib_node_runtime_t *node,
62 virtio_main_t *vim = &virtio_main;
63 vnet_main_t *vnm = vnet_get_main ();
66 pool_foreach (vif, vim->interfaces)
68 if (vif->packet_coalesce || vif->packet_buffering)
70 vnet_virtio_vring_t *txq_vring;
71 vec_foreach (txq_vring, vif->txq_vrings)
73 vnet_hw_if_tx_queue_t *txq =
74 vnet_hw_if_get_tx_queue (vnm, txq_vring->queue_index);
75 if (clib_bitmap_get (txq->threads, vm->thread_index) == 1)
76 virtio_pre_input_inline (vm, txq_vring, txq,
78 vif->packet_buffering);
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.
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.
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.
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
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.
110 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,
118 virtio_pre_input_node_enable (vlib_main_t *vm, virtio_if_t *vif)
120 virtio_main_t *vim = &virtio_main;
121 if (vif->packet_coalesce || vif->packet_buffering)
123 vim->gro_or_buffering_if_count++;
124 if (vim->gro_or_buffering_if_count == 1)
128 vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
129 VLIB_NODE_STATE_POLLING);
136 virtio_pre_input_node_disable (vlib_main_t *vm, virtio_if_t *vif)
138 virtio_main_t *vim = &virtio_main;
139 if (vif->packet_coalesce || vif->packet_buffering)
141 if (vim->gro_or_buffering_if_count > 0)
142 vim->gro_or_buffering_if_count--;
143 if (vim->gro_or_buffering_if_count == 0)
147 vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
148 VLIB_NODE_STATE_DISABLED);
155 * fd.io coding-style-patch-verification: ON
158 * eval: (c-set-style "gnu")