[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[UNIKRAFT PATCH v5 08/10] plat/xen/drivers/net: Start netfront device



Starting the device implies establishing the connection between netfront and
netback. The connection is set up after a negociation between the two end
points. After configuring the device queues, the netfront publishes via
Xenstore the information associated with the queues which will be used by the
backend to connect.

Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx>
Signed-off-by: Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx>
Reviewed-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
---
 plat/xen/drivers/net/netfront.c    |  18 ++
 plat/xen/drivers/net/netfront_xb.h |   3 +
 plat/xen/drivers/net/netfront_xs.c | 308 +++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+)

diff --git a/plat/xen/drivers/net/netfront.c b/plat/xen/drivers/net/netfront.c
index 7d1cb16e..48b7c02f 100644
--- a/plat/xen/drivers/net/netfront.c
+++ b/plat/xen/drivers/net/netfront.c
@@ -475,6 +475,23 @@ out:
        return rc;
 }
 
+static int netfront_start(struct uk_netdev *n)
+{
+       struct netfront_dev *nfdev;
+       int rc;
+
+       UK_ASSERT(n != NULL);
+       nfdev = to_netfront_dev(n);
+
+       rc = netfront_xb_connect(nfdev);
+       if (rc) {
+               uk_pr_err("Error connecting to backend: %d\n", rc);
+               return rc;
+       }
+
+       return rc;
+}
+
 static void netfront_info_get(struct uk_netdev *n,
                struct uk_netdev_info *dev_info)
 {
@@ -545,6 +562,7 @@ static unsigned int netfront_promisc_get(struct uk_netdev 
*n)
 
 static const struct uk_netdev_ops netfront_ops = {
        .configure = netfront_configure,
+       .start = netfront_start,
        .txq_configure = netfront_txq_setup,
        .rxq_configure = netfront_rxq_setup,
        .rxq_intr_enable = netfront_rx_intr_enable,
diff --git a/plat/xen/drivers/net/netfront_xb.h 
b/plat/xen/drivers/net/netfront_xb.h
index 6332cf71..07dde171 100644
--- a/plat/xen/drivers/net/netfront_xb.h
+++ b/plat/xen/drivers/net/netfront_xb.h
@@ -40,4 +40,7 @@
 int  netfront_xb_init(struct netfront_dev *netdev, struct uk_alloc *a);
 void netfront_xb_fini(struct netfront_dev *netdev, struct uk_alloc *a);
 
+int netfront_xb_connect(struct netfront_dev *netdev);
+int netfront_xb_disconnect(struct netfront_dev *netdev);
+
 #endif /* __NETFRONT_XB_H__ */
diff --git a/plat/xen/drivers/net/netfront_xs.c 
b/plat/xen/drivers/net/netfront_xs.c
index a2a60e97..0a9eb0d3 100644
--- a/plat/xen/drivers/net/netfront_xs.c
+++ b/plat/xen/drivers/net/netfront_xs.c
@@ -31,6 +31,7 @@
  *
  * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
  */
+#define _GNU_SOURCE
 #include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
@@ -38,9 +39,14 @@
 #include <uk/print.h>
 #include <uk/assert.h>
 #include <xenbus/xs.h>
+#include <xenbus/client.h>
 #include "netfront_xb.h"
 
 
+static int netfront_xb_wait_be_connect(struct netfront_dev *nfdev);
+static int netfront_xb_wait_be_disconnect(struct netfront_dev *nfdev);
+
+
 static int xs_read_backend_id(const char *nodename, domid_t *domid)
 {
        char path[strlen(nodename) + sizeof("/backend-id")];
@@ -218,3 +224,305 @@ void netfront_xb_fini(struct netfront_dev *nfdev, struct 
uk_alloc *a)
                xendev->otherend = NULL;
        }
 }
+
+static int xs_write_queue(struct netfront_dev *nfdev, uint16_t queue_id,
+               xenbus_transaction_t xbt, int write_hierarchical)
+{
+       struct xenbus_device *xendev = nfdev->xendev;
+       struct uk_netdev_tx_queue *txq = &nfdev->txqs[queue_id];
+       struct uk_netdev_rx_queue *rxq = &nfdev->rxqs[queue_id];
+       char *path;
+       int rc;
+
+       if (write_hierarchical) {
+               rc = asprintf(&path, "%s/queue-%u", xendev->nodename, queue_id);
+               if (rc < 0)
+                       goto out;
+       } else
+               path = xendev->nodename;
+
+       rc = xs_printf(xbt, path, "tx-ring-ref", "%u", txq->ring_ref);
+       if (rc < 0)
+               goto out_path;
+
+       rc = xs_printf(xbt, path, "rx-ring-ref", "%u", rxq->ring_ref);
+       if (rc < 0)
+               goto out_path;
+
+       if (nfdev->split_evtchn) {
+               /* split event channels */
+               rc = xs_printf(xbt, path, "event-channel-tx", "%u",
+                       txq->evtchn);
+               if (rc < 0)
+                       goto out_path;
+
+               rc = xs_printf(xbt, path, "event-channel-rx", "%u",
+                       rxq->evtchn);
+               if (rc < 0)
+                       goto out_path;
+       } else {
+               /* shared event channel */
+               rc = xs_printf(xbt, path, "event-channel", "%u",
+                       txq->evtchn);
+               if (rc < 0)
+                       goto out_path;
+       }
+
+       rc = 0;
+
+out_path:
+       if (write_hierarchical)
+               free(path);
+out:
+       return rc;
+}
+
+static void xs_delete_queue(struct netfront_dev *nfdev, uint16_t queue_id,
+               xenbus_transaction_t xbt, int write_hierarchical)
+{
+       struct xenbus_device *xendev = nfdev->xendev;
+       char *dir, *path;
+       int rc;
+
+       if (write_hierarchical) {
+               rc = asprintf(&dir, "%s/queue-%u", xendev->nodename, queue_id);
+               if (rc < 0)
+                       return;
+       } else
+               dir = xendev->nodename;
+
+       rc = asprintf(&path, "%s/tx-ring-ref", dir);
+       if (rc < 0)
+               goto out;
+       xs_rm(xbt, path);
+       free(path);
+
+       rc = asprintf(&path, "%s/rx-ring-ref", dir);
+       if (rc < 0)
+               goto out;
+       xs_rm(xbt, path);
+       free(path);
+
+       if (nfdev->split_evtchn) {
+               /* split event channels */
+               rc = asprintf(&path, "%s/event-channel-tx", dir);
+               if (rc < 0)
+                       goto out;
+               xs_rm(xbt, path);
+               free(path);
+               rc = asprintf(&path, "%s/event-channel-rx", dir);
+               if (rc < 0)
+                       goto out;
+               xs_rm(xbt, path);
+               free(path);
+       } else {
+               /* shared event channel */
+               rc = asprintf(&path, "%s/event-channel", dir);
+               if (rc < 0)
+                       goto out;
+               xs_rm(xbt, path);
+               free(path);
+       }
+
+out:
+       if (write_hierarchical)
+               free(dir);
+}
+
+static int netfront_xb_front_init(struct netfront_dev *nfdev,
+               xenbus_transaction_t xbt)
+{
+       struct xenbus_device *xendev = nfdev->xendev;
+       int rc, i;
+
+       rc = xs_printf(xbt, xendev->nodename, "multi-queue-num-queues",
+                       "%u", nfdev->rxqs_num);
+       if (rc < 0)
+               goto out;
+
+       if (nfdev->rxqs_num == 1) {
+               rc = xs_write_queue(nfdev, 0, xbt, 0);
+               if (rc)
+                       goto out;
+       } else {
+               for (i = 0; i < nfdev->rxqs_num; i++) {
+                       rc = xs_write_queue(nfdev, i, xbt, 1);
+                       if (rc)
+                               goto out;
+               }
+       }
+
+       rc = xs_printf(xbt, xendev->nodename, "request-rx-copy", "%u", 1);
+       if (rc < 0)
+               goto out;
+
+       rc = 0;
+
+out:
+       return rc;
+}
+
+static void netfront_xb_front_fini(struct netfront_dev *nfdev,
+               xenbus_transaction_t xbt)
+{
+       int i;
+
+       if (nfdev->rxqs_num == 1)
+               xs_delete_queue(nfdev, 0, xbt, 0);
+       else {
+               for (i = 0; i < nfdev->rxqs_num; i++)
+                       xs_delete_queue(nfdev, i, xbt, 1);
+       }
+}
+
+int netfront_xb_connect(struct netfront_dev *nfdev)
+{
+       struct xenbus_device *xendev;
+       xenbus_transaction_t xbt;
+       int rc;
+
+       UK_ASSERT(nfdev != NULL);
+
+       xendev = nfdev->xendev;
+       UK_ASSERT(xendev != NULL);
+
+again:
+       rc = xs_transaction_start(&xbt);
+       if (rc)
+               goto abort_transaction;
+
+       rc = netfront_xb_front_init(nfdev, xbt);
+       if (rc)
+               goto abort_transaction;
+
+       rc = xenbus_switch_state(xbt, xendev, XenbusStateConnected);
+       if (rc)
+               goto abort_transaction;
+
+       rc = xs_transaction_end(xbt, 0);
+       if (rc == -EAGAIN)
+               goto again;
+
+       rc = netfront_xb_wait_be_connect(nfdev);
+       if (rc)
+               netfront_xb_front_fini(nfdev, xbt);
+
+       return rc;
+
+abort_transaction:
+       xs_transaction_end(xbt, 1);
+
+       return rc;
+}
+
+int netfront_xb_disconnect(struct netfront_dev *nfdev)
+{
+       struct xenbus_device *xendev;
+       int rc;
+
+       UK_ASSERT(nfdev != NULL);
+
+       xendev = nfdev->xendev;
+       UK_ASSERT(xendev != NULL);
+
+       uk_pr_debug("Close network: backend at %s\n", xendev->otherend);
+
+       rc = xenbus_switch_state(XBT_NIL, xendev, XenbusStateClosing);
+       if (rc)
+               goto out;
+
+       rc = netfront_xb_wait_be_disconnect(nfdev);
+       if (rc)
+               goto out;
+
+       netfront_xb_front_fini(nfdev, XBT_NIL);
+
+out:
+       return rc;
+}
+
+static int be_watch_start(struct xenbus_device *xendev, const char *path)
+{
+       struct xenbus_watch *watch;
+
+       watch = xs_watch_path(XBT_NIL, path);
+       if (PTRISERR(watch))
+               return PTR2ERR(watch);
+
+       xendev->otherend_watch = watch;
+
+       return 0;
+}
+
+static int be_watch_stop(struct xenbus_device *xendev)
+{
+       return xs_unwatch(XBT_NIL, xendev->otherend_watch);
+}
+
+#define WAIT_BE_STATE_CHANGE_WHILE_COND(state_cond) \
+       do { \
+               rc = xs_read_integer(XBT_NIL, be_state_path, \
+                       (int *) &be_state); \
+               if (rc) \
+                       goto out; \
+               while (!rc && (state_cond)) \
+                       rc = xenbus_wait_for_state_change(be_state_path, \
+                               &be_state, xendev->otherend_watch); \
+               if (rc) \
+                       goto out; \
+       } while (0)
+
+static int netfront_xb_wait_be_connect(struct netfront_dev *nfdev)
+{
+       struct xenbus_device *xendev = nfdev->xendev;
+       char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
+       XenbusState be_state;
+       int rc;
+
+       sprintf(be_state_path, "%s/state", xendev->otherend);
+
+       rc = be_watch_start(xendev, be_state_path);
+       if (rc)
+               goto out;
+
+       WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateConnected);
+
+       if (be_state != XenbusStateConnected) {
+               uk_pr_err("Backend not available, state=%s\n",
+                               xenbus_state_to_str(be_state));
+               be_watch_stop(xendev);
+       }
+
+out:
+       return rc;
+}
+
+static int netfront_xb_wait_be_disconnect(struct netfront_dev *nfdev)
+{
+       struct xenbus_device *xendev = nfdev->xendev;
+       char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
+       XenbusState be_state;
+       int rc;
+
+       sprintf(be_state_path, "%s/state", xendev->otherend);
+
+       WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateClosing);
+
+       rc = xenbus_switch_state(XBT_NIL, xendev, XenbusStateClosed);
+       if (rc)
+               goto out;
+
+       WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateClosed);
+
+       rc = xenbus_switch_state(XBT_NIL, xendev, XenbusStateInitialising);
+       if (rc)
+               goto out;
+
+       WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateInitWait ||
+                       be_state >= XenbusStateClosed);
+
+       be_watch_stop(xendev);
+
+out:
+       return rc;
+}
-- 
2.20.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.