[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v2 10/12] plat/xen/drivers/net: Start netfront device
On device start netfront connects with backend. Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx> Signed-off-by: Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx> --- plat/xen/drivers/net/netfront.c | 20 +++ plat/xen/drivers/net/netfront_xb.h | 3 + plat/xen/drivers/net/netfront_xs.c | 303 +++++++++++++++++++++++++++++++++++++ 3 files changed, 326 insertions(+) diff --git a/plat/xen/drivers/net/netfront.c b/plat/xen/drivers/net/netfront.c index fc256501..d7610748 100644 --- a/plat/xen/drivers/net/netfront.c +++ b/plat/xen/drivers/net/netfront.c @@ -472,6 +472,25 @@ 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; + } + + uk_pr_info(DRIVER_NAME": %"__PRIu16" started\n", nfdev->uid); + + return rc; +} + static void netfront_info_get(struct uk_netdev *n, struct uk_netdev_info *dev_info) { @@ -541,6 +560,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 013c0e3c..5cc8f500 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 df675b79..84762739 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_info("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.11.0 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |