summaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
authorMohsin Kazmi <sykazmi@cisco.com>2020-10-12 13:01:24 +0200
committerBeno�t Ganne <bganne@cisco.com>2020-10-21 11:20:01 +0000
commita5203b53d4fa227560333b890d3e79fc220d1bfd (patch)
tree04ac639280910abbf8a12fd973b207f177b67a12 /src/vnet
parent302b25a00ed913767798d58148ef4d36092ee490 (diff)
virtio: run process to send interrupts to input nodes
Type: improvement virtio interfaces support packet coalescing and buffering which depends on timer expiry to flush the stored packets periodically. virtio input node checks timer expiry and schedules tx queue accordingly. In poll mode, timer expiry is handled naturally, as input node runs periodically. In interrupt mode, virtio input node depends on the interrupts send from backend. Stored packets could starve, if there would not be interrupts to input node. This patch implements a process node which periodically sends interrupt to virtio input node given coalescing or buffering feature is enabled on an interface. Change-Id: Ic38f749f74b001073d4d0579dca149d0a4cea039 Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Diffstat (limited to 'src/vnet')
-rw-r--r--src/vnet/CMakeLists.txt1
-rw-r--r--src/vnet/devices/virtio/device.c34
-rw-r--r--src/vnet/devices/virtio/virtio.h6
-rw-r--r--src/vnet/devices/virtio/virtio_process.c88
4 files changed, 112 insertions, 17 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index f8b034f5dfa..021e8604077 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -987,6 +987,7 @@ list(APPEND VNET_SOURCES
devices/virtio/virtio_api.c
devices/virtio/virtio_pci_legacy.c
devices/virtio/virtio_pci_modern.c
+ devices/virtio/virtio_process.c
devices/virtio/virtio_types_api.c
)
diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c
index 084be962ed7..521d76a8da4 100644
--- a/src/vnet/devices/virtio/device.c
+++ b/src/vnet/devices/virtio/device.c
@@ -761,11 +761,11 @@ static clib_error_t *
virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
vnet_hw_if_rx_mode mode)
{
+ vlib_main_t *vm = vnm->vlib_main;
virtio_main_t *mm = &virtio_main;
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
virtio_vring_t *rx_vring = vec_elt_at_index (vif->rxq_vrings, qid);
- virtio_vring_t *tx_vring = 0;
if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
{
@@ -775,32 +775,32 @@ virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
if (mode == VNET_HW_IF_RX_MODE_POLLING)
{
- vec_foreach (tx_vring, vif->txq_vrings)
- {
- /* only enable packet coalesce in poll mode */
- gro_flow_table_set_is_enable (tx_vring->flow_table, 1);
- /* only enable packet buffering in poll mode */
- virtio_vring_buffering_set_is_enable (tx_vring->buffering, 1);
- }
+ if (vif->packet_coalesce || vif->packet_buffering)
+ {
+ if (mm->interrupt_queues_count > 0)
+ mm->interrupt_queues_count--;
+ if (mm->interrupt_queues_count == 0)
+ vlib_process_signal_event (vm,
+ virtio_send_interrupt_node.index,
+ VIRTIO_EVENT_STOP_TIMER, 0);
+ }
rx_vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
}
else
{
if (vif->packet_coalesce || vif->packet_buffering)
{
- virtio_log_warning (vif,
- "interface %U is in interrupt mode, disabling packet coalescing or buffering",
- format_vnet_sw_if_index_name, vnet_get_main (),
- vif->sw_if_index);
- vec_foreach (tx_vring, vif->txq_vrings)
- {
- gro_flow_table_set_is_enable (tx_vring->flow_table, 0);
- virtio_vring_buffering_set_is_enable (tx_vring->buffering, 0);
- }
+ mm->interrupt_queues_count++;
+ if (mm->interrupt_queues_count == 1)
+ vlib_process_signal_event (vm,
+ virtio_send_interrupt_node.index,
+ VIRTIO_EVENT_START_TIMER, 0);
}
rx_vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
}
+ rx_vring->mode = mode;
+
return 0;
}
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index 1cca9f366a8..86660a1f933 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -57,6 +57,9 @@ typedef enum
#define VIRTIO_RING_FLAG_MASK_INT 1
+#define VIRTIO_EVENT_START_TIMER 1
+#define VIRTIO_EVENT_STOP_TIMER 2
+
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
@@ -84,6 +87,7 @@ typedef struct
u16 last_used_idx;
u16 last_kick_avail_idx;
u32 call_file_index;
+ vnet_hw_if_rx_mode mode;
virtio_vring_buffering_t *buffering;
gro_flow_table_t *flow_table;
} virtio_vring_t;
@@ -189,6 +193,7 @@ typedef struct
typedef struct
{
+ u32 interrupt_queues_count;
/* logging */
vlib_log_class_t log_default;
@@ -198,6 +203,7 @@ typedef struct
extern virtio_main_t virtio_main;
extern vnet_device_class_t virtio_device_class;
extern vlib_node_registration_t virtio_input_node;
+extern vlib_node_registration_t virtio_send_interrupt_node;
clib_error_t *virtio_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 idx,
u16 sz);
diff --git a/src/vnet/devices/virtio/virtio_process.c b/src/vnet/devices/virtio/virtio_process.c
new file mode 100644
index 00000000000..7a25611bb95
--- /dev/null
+++ b/src/vnet/devices/virtio/virtio_process.c
@@ -0,0 +1,88 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/devices/virtio/virtio.h>
+#include <vnet/gso/gro_func.h>
+
+static uword
+virtio_send_interrupt_process (vlib_main_t * vm,
+ vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ virtio_if_t *vif;
+ f64 timeout = 3153600000.0 /* 100 years */ ;
+ uword event_type, *event_data = 0;
+ virtio_main_t *vim = &virtio_main;
+
+ while (1)
+ {
+ vlib_process_wait_for_event_or_clock (vm, timeout);
+ event_type = vlib_process_get_events (vm, &event_data);
+ vec_reset_length (event_data);
+
+ switch (event_type)
+ {
+ case VIRTIO_EVENT_STOP_TIMER:
+ timeout = 3153600000.0;
+ break;
+
+ case VIRTIO_EVENT_START_TIMER:
+ timeout = 1e-3; /* 1 millisecond */
+ break;
+
+ case ~0:
+ /* *INDENT-OFF* */
+ pool_foreach (vif, vim->interfaces, {
+ if (vif->packet_coalesce || vif->packet_buffering)
+ {
+ virtio_vring_t *vring;
+ vec_foreach (vring, vif->rxq_vrings)
+ {
+ if (vring->mode == VNET_HW_IF_RX_MODE_INTERRUPT ||
+ vring->mode == VNET_HW_IF_RX_MODE_ADAPTIVE)
+ vnet_device_input_set_interrupt_pending (
+ vnet_get_main (), vif->hw_if_index,
+ RX_QUEUE_ACCESS (vring->queue_id));
+ }
+ }
+ });
+ /* *INDENT-ON* */
+ break;
+
+ default:
+ clib_warning ("BUG: unhandled event type %d", event_type);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (virtio_send_interrupt_node) = {
+ .function = virtio_send_interrupt_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "virtio-send-interrupt-process",
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */