[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [UNIKRAFT PATCH v4 09/12] 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> --- plat/xen/drivers/net/netfront.c | 18 ++ plat/xen/drivers/net/netfront_xb.h | 3 + plat/xen/drivers/net/netfront_xs.c | 303 +++++++++++++++++++++++++++++ 3 files changed, 324 insertions(+) diff --git a/plat/xen/drivers/net/netfront.c b/plat/xen/drivers/net/netfront.c index 6b708790..858d124a 100644 --- a/plat/xen/drivers/net/netfront.c +++ b/plat/xen/drivers/net/netfront.c @@ -474,6 +474,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) { @@ -542,6 +559,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 1bde44e0..618496e7 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")]; @@ -217,3 +223,300 @@ 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; + + 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |