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, 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);
42 clib_spinlock_unlock (&txq_vring->lockp);
48 vnet_gro_flow_table_schedule_node_on_dispatcher (
49 vm, txq, txq_vring->flow_table);
50 else if (packet_buffering)
51 virtio_vring_buffering_schedule_node_on_dispatcher (
52 vm, txq, txq_vring->buffering);
58 virtio_pre_input (vlib_main_t *vm, vlib_node_runtime_t *node,
61 virtio_main_t *vim = &virtio_main;
62 vnet_main_t *vnm = vnet_get_main ();
65 pool_foreach (vif, vim->interfaces)
67 if (vif->packet_coalesce || vif->packet_buffering)
69 virtio_vring_t *txq_vring;
70 vec_foreach (txq_vring, vif->txq_vrings)
72 vnet_hw_if_tx_queue_t *txq =
73 vnet_hw_if_get_tx_queue (vnm, txq_vring->queue_index);
74 if (clib_bitmap_get (txq->threads, vm->thread_index) == 1)
75 virtio_pre_input_inline (vm, txq_vring, txq,
77 vif->packet_buffering);
86 * virtio interfaces support packet coalescing and buffering which
87 * depends on timer expiry to flush the stored packets periodically.
88 * Previously, virtio input node checked timer expiry and scheduled
89 * tx queue accordingly.
91 * In poll mode, timer expiry was handled naturally, as input node
92 * runs periodically. In interrupt mode, virtio input node was dependent
93 * on the interrupts send from backend. Stored packets could starve,
94 * if there would not be interrupts to input node.
96 * This problem had been solved through a dedicated process node which
97 * periodically sends interrupt to virtio input node given coalescing
98 * or buffering feature were enabled on an interface.
100 * But that approach worked with following limitations:
101 * 1) Each VPP thread should have (atleast) 1 rx queue of an interface
102 * (with buffering enabled). And rxqs and txqs should be placed on the
105 * New design provides solution to above problem(s) without any limitation
106 * through (dedicated) pre-input node running on each VPP thread when
107 * atleast 1 virtio interface is enabled with coalescing or buffering.
109 VLIB_REGISTER_NODE (virtio_pre_input_node) = {
110 .function = virtio_pre_input,
111 .type = VLIB_NODE_TYPE_PRE_INPUT,
112 .name = "virtio-pre-input",
113 .state = VLIB_NODE_STATE_DISABLED,
117 virtio_pre_input_node_enable (vlib_main_t *vm, virtio_if_t *vif)
119 virtio_main_t *vim = &virtio_main;
120 if (vif->packet_coalesce || vif->packet_buffering)
122 vim->gro_or_buffering_if_count++;
123 if (vim->gro_or_buffering_if_count == 1)
127 vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
128 VLIB_NODE_STATE_POLLING);
135 virtio_pre_input_node_disable (vlib_main_t *vm, virtio_if_t *vif)
137 virtio_main_t *vim = &virtio_main;
138 if (vif->packet_coalesce || vif->packet_buffering)
140 if (vim->gro_or_buffering_if_count > 0)
141 vim->gro_or_buffering_if_count--;
142 if (vim->gro_or_buffering_if_count == 0)
146 vlib_node_set_state (this_vlib_main, virtio_pre_input_node.index,
147 VLIB_NODE_STATE_DISABLED);
154 * fd.io coding-style-patch-verification: ON
157 * eval: (c-set-style "gnu")