devices: add support for polling mode

Type: improvement

Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Change-Id: I8d84dc8b7f5c5e863c32838cfafc3d366e2a7e00
diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h
index e5dc615..940acbb 100644
--- a/src/vnet/devices/af_packet/af_packet.h
+++ b/src/vnet/devices/af_packet/af_packet.h
@@ -118,6 +118,7 @@
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
   af_packet_if_t *interfaces;
 
+  u32 polling_count;
   /* rx buffer cache */
   u32 **rx_buffers;
 
diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c
index e1eb46a..74bc1c8 100644
--- a/src/vnet/devices/af_packet/device.c
+++ b/src/vnet/devices/af_packet/device.c
@@ -632,6 +632,40 @@
   return 0;			/* no error */
 }
 
+static clib_error_t *
+af_packet_interface_rx_mode_change (vnet_main_t *vnm, u32 hw_if_index, u32 qid,
+				    vnet_hw_if_rx_mode mode)
+{
+  af_packet_main_t *apm = &af_packet_main;
+  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
+  af_packet_if_t *apif;
+
+  apif = vec_elt_at_index (apm->interfaces, hw->dev_instance);
+
+  if (mode == VNET_HW_IF_RX_MODE_ADAPTIVE)
+    {
+      vlib_log_err (apm->log_class,
+		    "af_packet_%s adaptive mode is not supported",
+		    apif->host_if_name);
+      return clib_error_return (
+	0, "af_packet_%s adaptive mode is not supported", apif->host_if_name);
+    }
+
+  af_packet_queue_t *rx_queue = vec_elt_at_index (apif->rx_queues, qid);
+
+  if (rx_queue->mode != mode)
+    {
+      rx_queue->mode = mode;
+
+      if (mode == VNET_HW_IF_RX_MODE_POLLING)
+	apm->polling_count++;
+      else if (mode == VNET_HW_IF_RX_MODE_INTERRUPT && apm->polling_count > 0)
+	apm->polling_count--;
+    }
+
+  return 0;
+}
+
 VNET_DEVICE_CLASS (af_packet_device_class) = {
   .name = "af-packet",
   .format_device_name = format_af_packet_device_name,
@@ -644,6 +678,7 @@
   .admin_up_down_function = af_packet_interface_admin_up_down,
   .subif_add_del_function = af_packet_subif_add_del_function,
   .mac_addr_change_function = af_packet_set_mac_address_function,
+  .rx_mode_change_function = af_packet_interface_rx_mode_change,
 };
 
 /*
diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c
index 1fc0619..0e522c9 100644
--- a/src/vnet/devices/af_packet/node.c
+++ b/src/vnet/devices/af_packet/node.c
@@ -504,12 +504,15 @@
 
 done:
 
-  if ((((block_desc_t *) (block_start = rx_queue->rx_ring[block]))
-	 ->hdr.bh1.block_status &
-       TP_STATUS_USER) != 0)
-    vlib_node_set_state (vm, node->node_index, VLIB_NODE_STATE_POLLING);
-  else
-    vlib_node_set_state (vm, node->node_index, VLIB_NODE_STATE_INTERRUPT);
+  if (apm->polling_count == 0)
+    {
+      if ((((block_desc_t *) (block_start = rx_queue->rx_ring[block]))
+	     ->hdr.bh1.block_status &
+	   TP_STATUS_USER) != 0)
+	vlib_node_set_state (vm, node->node_index, VLIB_NODE_STATE_POLLING);
+      else
+	vlib_node_set_state (vm, node->node_index, VLIB_NODE_STATE_INTERRUPT);
+    }
 
   vlib_error_count (vm, node->node_index, AF_PACKET_INPUT_ERROR_TOTAL_RECV_BLK,
 		    total);