net/virtio-user: support LSC
authorJianfeng Tan <jianfeng.tan@intel.com>
Fri, 31 Mar 2017 19:44:58 +0000 (19:44 +0000)
committerYuanhan Liu <yuanhan.liu@linux.intel.com>
Sat, 1 Apr 2017 08:36:17 +0000 (10:36 +0200)
So far, virtio-user with vhost-user as the backend can only support
client mode. So when vhost user backend is down, i.e., unix socket
connection is broken, the connection cannot be re-connected. We will
forcely set the link state to be down.

Note: virtio-user with vhost-kernel as the backend still cannot
support lsc now as we fail to find a way to monitor the backend, tap
device, up/down events.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
doc/guides/rel_notes/release_17_05.rst
drivers/net/virtio/virtio_ethdev.c
drivers/net/virtio/virtio_ethdev.h
drivers/net/virtio/virtio_user_ethdev.c

index d7ea0df..f3e152b 100644 (file)
@@ -163,11 +163,12 @@ New Features
 
 * **Added interrupt mode support for virtio-user.**
 
-  Implemented Rxq interrupt mode support for virtio-user as a virtual
+  Implemented Rxq interrupt mode and LSC support for virtio-user as a virtual
   device. Supported cases:
 
   * Rxq interrupt for virtio-user + vhost-user as the backend.
   * Rxq interrupt for virtio-user + vhost-kernel as the backend.
+  * LSC interrupt for virtio-user + vhost-user as the backend.
 
 
 Resolved Issues
@@ -224,6 +225,11 @@ Known Issues
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* **LSC interrupt cannot work for virtio-user + vhost-kernel.**
+
+  LSC interrupt cannot be detected when setting the backend, tap device,
+  up/down as we fail to find a way to monitor such event.
+
 
 API Changes
 -----------
index d9986ab..6a9568f 100644 (file)
@@ -1205,7 +1205,7 @@ virtio_negotiate_features(struct virtio_hw *hw, uint64_t req_features)
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
  */
-static void
+void
 virtio_interrupt_handler(struct rte_intr_handle *handle,
                         void *param)
 {
index aa78adc..4009c4d 100644 (file)
@@ -113,4 +113,6 @@ uint16_t virtio_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 int eth_virtio_dev_init(struct rte_eth_dev *eth_dev);
 
+void virtio_interrupt_handler(struct rte_intr_handle *handle, void *param);
+
 #endif /* _VIRTIO_ETHDEV_H_ */
index 7da9f6f..35717f7 100644 (file)
 #include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
 #include <rte_malloc.h>
 #include <rte_kvargs.h>
 #include <rte_vdev.h>
+#include <rte_alarm.h>
 
 #include "virtio_ethdev.h"
 #include "virtio_logs.h"
 #define virtio_user_get_dev(hw) \
        ((struct virtio_user_dev *)(hw)->virtio_user_dev)
 
+static void
+virtio_user_delayed_handler(void *param)
+{
+       struct virtio_hw *hw = (struct virtio_hw *)param;
+       struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
+
+       rte_intr_callback_unregister(dev->intr_handle,
+                                    virtio_interrupt_handler,
+                                    dev);
+}
+
 static void
 virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset,
                     void *dst, int length)
@@ -63,8 +78,37 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset,
                return;
        }
 
-       if (offset == offsetof(struct virtio_net_config, status))
+       if (offset == offsetof(struct virtio_net_config, status)) {
+               char buf[128];
+
+               if (dev->vhostfd >= 0) {
+                       int r;
+                       int flags;
+
+                       flags = fcntl(dev->vhostfd, F_GETFL);
+                       fcntl(dev->vhostfd, F_SETFL, flags | O_NONBLOCK);
+                       r = recv(dev->vhostfd, buf, 128, MSG_PEEK);
+                       if (r == 0 || (r < 0 && errno != EAGAIN)) {
+                               dev->status &= (~VIRTIO_NET_S_LINK_UP);
+                               PMD_DRV_LOG(ERR, "virtio-user port %u is down",
+                                           hw->port_id);
+                               /* Only client mode is available now. Once the
+                                * connection is broken, it can never be up
+                                * again. Besides, this function could be called
+                                * in the process of interrupt handling,
+                                * callback cannot be unregistered here, set an
+                                * alarm to do it.
+                                */
+                               rte_eal_alarm_set(1,
+                                                 virtio_user_delayed_handler,
+                                                 (void *)hw);
+                       } else {
+                               dev->status |= VIRTIO_NET_S_LINK_UP;
+                       }
+                       fcntl(dev->vhostfd, F_SETFL, flags & (~O_NONBLOCK));
+               }
                *(uint16_t *)dst = dev->status;
+       }
 
        if (offset == offsetof(struct virtio_net_config, max_virtqueue_pairs))
                *(uint16_t *)dst = dev->max_queue_pairs;
@@ -325,7 +369,11 @@ virtio_user_eth_dev_alloc(const char *name)
        hw->port_id = data->port_id;
        dev->port_id = data->port_id;
        virtio_hw_internal[hw->port_id].vtpci_ops = &virtio_user_ops;
-       hw->use_msix = 0;
+       /*
+        * MSIX is required to enable LSC (see virtio_init_device).
+        * Here just pretend that we support msix.
+        */
+       hw->use_msix = 1;
        hw->modern   = 0;
        hw->use_simple_rxtx = 0;
        hw->virtio_user_dev = dev;