diff mbox

[ovs-dev,v6] netdev-dpdk: add hotplug support

Message ID 1464298121-4959-1-git-send-email-mauricio.vasquezbernal@studenti.polito.it
State Superseded
Delegated to: Daniele Di Proietto
Headers show

Commit Message

Mauricio Vásquez May 26, 2016, 9:28 p.m. UTC
In order to use dpdk ports in ovs they have to be bound to a DPDK
compatible driver before ovs is started.

This patch adds the possibility to hotplug (or hot-unplug) a device
after ovs has been started. The implementation adds two appctl commands:
netdev-dpdk/port-attach and netdev-dpdk/port-detach

After the user attaches a new device, it has to be added to a bridge
using the add-port command, similarly, before detaching a device,
it has to be removed using the del-port command.

Signed-off-by: Mauricio Vasquez B <mauricio.vasquezbernal@studenti.polito.it>
Tested-by: ian.stokes@intel.com
---
v6:
 - add explicit comment about supporting VFIO
 - rebase to master
v5:
 - use two appctl commands instead of a single one
 - rebase to master
v4:
 - fix typo in commit message
 - remove unnecessary whitespace change in INSTALL.DPDK.md
v3:
 - create dpdk_port_attach and dpdk_port_detach functions
 - modify mutex locking order
v2:
 - use rte_eth_dev_is_valid_port() to check if a port is valid
 INSTALL.DPDK.md   |  25 ++++++++++++++
 NEWS              |   1 +
 lib/netdev-dpdk.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 120 insertions(+), 7 deletions(-)

Comments

Flavio Leitner May 27, 2016, 10:46 p.m. UTC | #1
On Thu, May 26, 2016 at 11:28:41PM +0200, Mauricio Vasquez B wrote:
> In order to use dpdk ports in ovs they have to be bound to a DPDK
> compatible driver before ovs is started.
> 
> This patch adds the possibility to hotplug (or hot-unplug) a device
> after ovs has been started. The implementation adds two appctl commands:
> netdev-dpdk/port-attach and netdev-dpdk/port-detach
> 
> After the user attaches a new device, it has to be added to a bridge
> using the add-port command, similarly, before detaching a device,
> it has to be removed using the del-port command.
> 
> Signed-off-by: Mauricio Vasquez B <mauricio.vasquezbernal@studenti.polito.it>
> Tested-by: ian.stokes@intel.com
> ---

Acked-by: Flavio Leitner <fbl@sysclose.org>
Ryan Moats June 22, 2016, 2:41 p.m. UTC | #2
"dev" <dev-bounces@openvswitch.org> wrote on 05/26/2016 04:28:41 PM:

> From: Mauricio Vasquez B <mauricio.vasquezbernal@studenti.polito.it>
> To: dev@openvswitch.org
> Cc: fbl@sysclose.org, kevin.traynor@intel.com
> Date: 05/26/2016 04:29 PM
> Subject: [ovs-dev] [PATCH v6] netdev-dpdk: add hotplug support
> Sent by: "dev" <dev-bounces@openvswitch.org>
>
> In order to use dpdk ports in ovs they have to be bound to a DPDK
> compatible driver before ovs is started.
>
> This patch adds the possibility to hotplug (or hot-unplug) a device
> after ovs has been started. The implementation adds two appctl commands:
> netdev-dpdk/port-attach and netdev-dpdk/port-detach
>
> After the user attaches a new device, it has to be added to a bridge
> using the add-port command, similarly, before detaching a device,
> it has to be removed using the del-port command.
>
> Signed-off-by: Mauricio Vasquez B
<mauricio.vasquezbernal@studenti.polito.it>
> Tested-by: ian.stokes@intel.com
> ---

As an FYI to whomever might try to push this, the patch to NEWS did
not apply cleanly for me as of this posting.  Since it's one line
patch, I looked and manually applying it should be simple.

Ryan
diff mbox

Patch

diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
index 68735cc..948957b 100644
--- a/INSTALL.DPDK.md
+++ b/INSTALL.DPDK.md
@@ -286,6 +286,30 @@  Using the DPDK with ovs-vswitchd:
 
    For more details regarding ingress-policer see the vswitch.xml.
 
+10. Port Hotplug
+
+   Ovs supports port hotplugging, it allows to use ports that were not bound
+   to DPDK when vswitchd was started.
+   In order to attach a port, it has to be bound to DPDK using the
+   dpdk_nic_bind.py script:
+
+   `$DPDK_DIR/tools/dpdk_nic_bind.py --bind=igb_uio 0000:01:00.0`
+
+   Then it can be attached to OVS:
+
+   `ovs-appctl netdev-dpdk/port-attach 0000:01:00.0`
+
+   At this point, the user can create a ovs port using the add-port command.
+
+   It is also possible to detach a port from ovs, the user has to remove the
+   port using the del-port command, then it can be detached using:
+
+   `ovs-appctl netdev-dpdk/port-detach dpdk0`
+
+   This feature is not supported with VFIO and could not work with some NICs,
+   please refer to the [DPDK Port Hotplug Framework] in order to get more
+   information.
+
 Performance Tuning:
 -------------------
 
@@ -1018,3 +1042,4 @@  Please report problems to bugs@openvswitch.org.
 [INSTALL.md]:INSTALL.md
 [DPDK Linux GSG]: http://www.dpdk.org/doc/guides/linux_gsg/build_dpdk.html#binding-and-unbinding-network-ports-to-from-the-igb-uioor-vfio-modules
 [DPDK Docs]: http://dpdk.org/doc
+[DPDK Port Hotplug Framework]: http://dpdk.org/doc/guides/prog_guide/port_hotplug_framework.html
diff --git a/NEWS b/NEWS
index ba201cf..4018836 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,7 @@  Post-v2.5.0
        arguments. Additional arguments can be passed via the dpdk-extra
        entry.
      * Add ingress policing functionality.
+     * Port Hotplug is now supported.
    - ovs-benchmark: This utility has been removed due to lack of use and
      bitrot.
    - ovs-appctl:
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 6cae930..f5a8678 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -649,7 +649,7 @@  dpdk_eth_dev_init(struct netdev_dpdk *dev) OVS_REQUIRES(dpdk_mutex)
     int diag;
     int n_rxq, n_txq;
 
-    if (dev->port_id < 0 || dev->port_id >= rte_eth_dev_count()) {
+    if (!rte_eth_dev_is_valid_port(dev->port_id)) {
         return ENODEV;
     }
 
@@ -2231,6 +2231,83 @@  netdev_dpdk_set_admin_state(struct unixctl_conn *conn, int argc,
     unixctl_command_reply(conn, "OK");
 }
 
+static void
+netdev_dpdk_port_attach(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                        const char *argv[], void *aux OVS_UNUSED)
+{
+    int ret;
+    char response[128];
+    uint8_t port_id;
+
+    ovs_mutex_lock(&dpdk_mutex);
+
+    ret = rte_eth_dev_attach(argv[1], &port_id);
+    if (ret < 0) {
+        snprintf(response, sizeof(response),
+                 "Error attaching device '%s'", argv[1]);
+        ovs_mutex_unlock(&dpdk_mutex);
+        unixctl_command_reply_error(conn, response);
+        return;
+    }
+
+    snprintf(response, sizeof(response),
+             "Device '%s' has been attached as 'dpdk%d'", argv[1], port_id);
+
+    ovs_mutex_unlock(&dpdk_mutex);
+    unixctl_command_reply(conn, response);
+}
+
+static void
+netdev_dpdk_port_detach(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                        const char *argv[], void *aux OVS_UNUSED)
+{
+    int ret;
+    char response[128];
+    unsigned int parsed_port;
+    uint8_t port_id;
+    char devname[RTE_ETH_NAME_MAX_LEN];
+
+    ovs_mutex_lock(&dpdk_mutex);
+
+    ret = dpdk_dev_parse_name(argv[1], "dpdk", &parsed_port);
+    if (ret) {
+        snprintf(response, sizeof(response),
+                 "'%s' is not a valid port", argv[1]);
+        goto error;
+    }
+
+    port_id = parsed_port;
+
+    struct netdev *netdev = netdev_from_name(argv[1]);
+    if (netdev) {
+        netdev_close(netdev);
+        snprintf(response, sizeof(response),
+                 "Port '%s' is being used. Remove it before detaching",
+                 argv[1]);
+        goto error;
+    }
+
+    rte_eth_dev_close(port_id);
+
+    ret = rte_eth_dev_detach(port_id, devname);
+    if (ret < 0) {
+        snprintf(response, sizeof(response),
+                 "Port '%s' can not be detached", argv[1]);
+        goto error;
+    }
+
+    snprintf(response, sizeof(response),
+             "Port '%s' has been detached", argv[1]);
+
+    ovs_mutex_unlock(&dpdk_mutex);
+    unixctl_command_reply(conn, response);
+    return;
+
+error:
+    ovs_mutex_unlock(&dpdk_mutex);
+    unixctl_command_reply_error(conn, response);
+}
+
 /*
  * Set virtqueue flags so that we do not receive interrupts.
  */
@@ -2523,6 +2600,15 @@  dpdk_common_init(void)
                              "[netdev] up|down", 1, 2,
                              netdev_dpdk_set_admin_state, NULL);
 
+    unixctl_command_register("netdev-dpdk/port-attach",
+                             "pci address of device", 1, 1,
+                             netdev_dpdk_port_attach, NULL);
+
+    unixctl_command_register("netdev-dpdk/port-detach",
+                             "port", 1, 1,
+                             netdev_dpdk_port_detach, NULL);
+
+    ovs_thread_create("dpdk_watchdog", dpdk_watchdog, NULL);
 }
 
 /* Client Rings */
@@ -2533,7 +2619,7 @@  dpdk_ring_create(const char dev_name[], unsigned int port_no,
 {
     struct dpdk_ring *ivshmem;
     char ring_name[RTE_RING_NAMESIZE];
-    int err;
+    int err, port_id;
 
     ivshmem = dpdk_rte_mzalloc(sizeof *ivshmem);
     if (ivshmem == NULL) {
@@ -2567,19 +2653,20 @@  dpdk_ring_create(const char dev_name[], unsigned int port_no,
         return ENOMEM;
     }
 
-    err = rte_eth_from_rings(dev_name, &ivshmem->cring_rx, 1,
-                             &ivshmem->cring_tx, 1, SOCKET0);
+    port_id = rte_eth_from_rings(dev_name, &ivshmem->cring_rx, 1,
+                                 &ivshmem->cring_tx, 1, SOCKET0);
 
-    if (err < 0) {
+    if (port_id < 0) {
         rte_free(ivshmem);
         return ENODEV;
     }
 
     ivshmem->user_port_id = port_no;
-    ivshmem->eth_port_id = rte_eth_dev_count() - 1;
+    ivshmem->eth_port_id = port_id;
+    *eth_port_id = port_id;
+
     ovs_list_push_back(&dpdk_ring_list, &ivshmem->list_node);
 
-    *eth_port_id = ivshmem->eth_port_id;
     return 0;
 }