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>
diff --git a/src/vnet/devices/virtio/virtio_process.c b/src/vnet/devices/virtio/virtio_process.c
new file mode 100644
index 0000000..7a25611
--- /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:
+ */