Commit 9476654b authored by Paul Durrant's avatar Paul Durrant Committed by David S. Miller

xen-netback: support dynamic unbind/bind

By re-attaching RX, TX, and CTL rings during connect() rather than
assuming they are freshly allocated (i.e. assuming the counters are zero),
and avoiding forcing state to Closed in netback_remove() it is possible
for vif instances to be unbound and re-bound from and to (respectively) a
running guest.

Dynamic unbind/bind is a highly useful feature for a backend module as it
allows it to be unloaded and re-loaded (i.e. updated) without requiring
domUs to be halted.

This has been tested by running iperf as a server in the test VM and
then running a client against it in a continuous loop, whilst also
running:

while true;
  do echo vif-$DOMID-$VIF >unbind;
  echo down;
  rmmod xen-netback;
  echo unloaded;
  modprobe xen-netback;
  cd $(pwd);
  brctl addif xenbr0 vif$DOMID.$VIF;
  ip link set vif$DOMID.$VIF up;
  echo up;
  sleep 5;
  done

in dom0 from /sys/bus/xen-backend/drivers/vif to continuously unbind,
unload, re-load, re-bind and re-plumb the backend.

Clearly a performance drop was seen but no TCP connection resets were
observed during this test and moreover a parallel SSH connection into the
guest remained perfectly usable throughout.
Signed-off-by: default avatarPaul Durrant <pdurrant@amazon.com>
Reviewed-by: default avatarWei Liu <wei.liu@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8d347992
...@@ -585,6 +585,7 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref, ...@@ -585,6 +585,7 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,
struct net_device *dev = vif->dev; struct net_device *dev = vif->dev;
void *addr; void *addr;
struct xen_netif_ctrl_sring *shared; struct xen_netif_ctrl_sring *shared;
RING_IDX rsp_prod, req_prod;
int err; int err;
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
...@@ -593,7 +594,14 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref, ...@@ -593,7 +594,14 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,
goto err; goto err;
shared = (struct xen_netif_ctrl_sring *)addr; shared = (struct xen_netif_ctrl_sring *)addr;
BACK_RING_INIT(&vif->ctrl, shared, XEN_PAGE_SIZE); rsp_prod = READ_ONCE(shared->rsp_prod);
req_prod = READ_ONCE(shared->req_prod);
BACK_RING_ATTACH(&vif->ctrl, shared, rsp_prod, XEN_PAGE_SIZE);
err = -EIO;
if (req_prod - rsp_prod > RING_SIZE(&vif->ctrl))
goto err_unmap;
err = bind_interdomain_evtchn_to_irq(vif->domid, evtchn); err = bind_interdomain_evtchn_to_irq(vif->domid, evtchn);
if (err < 0) if (err < 0)
......
...@@ -1453,7 +1453,7 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue, ...@@ -1453,7 +1453,7 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
void *addr; void *addr;
struct xen_netif_tx_sring *txs; struct xen_netif_tx_sring *txs;
struct xen_netif_rx_sring *rxs; struct xen_netif_rx_sring *rxs;
RING_IDX rsp_prod, req_prod;
int err = -ENOMEM; int err = -ENOMEM;
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
...@@ -1462,7 +1462,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue, ...@@ -1462,7 +1462,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
goto err; goto err;
txs = (struct xen_netif_tx_sring *)addr; txs = (struct xen_netif_tx_sring *)addr;
BACK_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE); rsp_prod = READ_ONCE(txs->rsp_prod);
req_prod = READ_ONCE(txs->req_prod);
BACK_RING_ATTACH(&queue->tx, txs, rsp_prod, XEN_PAGE_SIZE);
err = -EIO;
if (req_prod - rsp_prod > RING_SIZE(&queue->tx))
goto err;
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
&rx_ring_ref, 1, &addr); &rx_ring_ref, 1, &addr);
...@@ -1470,7 +1477,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue, ...@@ -1470,7 +1477,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
goto err; goto err;
rxs = (struct xen_netif_rx_sring *)addr; rxs = (struct xen_netif_rx_sring *)addr;
BACK_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE); rsp_prod = READ_ONCE(rxs->rsp_prod);
req_prod = READ_ONCE(rxs->req_prod);
BACK_RING_ATTACH(&queue->rx, rxs, rsp_prod, XEN_PAGE_SIZE);
err = -EIO;
if (req_prod - rsp_prod > RING_SIZE(&queue->rx))
goto err;
return 0; return 0;
......
...@@ -954,12 +954,10 @@ static int netback_remove(struct xenbus_device *dev) ...@@ -954,12 +954,10 @@ static int netback_remove(struct xenbus_device *dev)
{ {
struct backend_info *be = dev_get_drvdata(&dev->dev); struct backend_info *be = dev_get_drvdata(&dev->dev);
set_backend_state(be, XenbusStateClosed);
unregister_hotplug_status_watch(be); unregister_hotplug_status_watch(be);
if (be->vif) { if (be->vif) {
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
xen_unregister_watchers(be->vif); backend_disconnect(be);
xenvif_free(be->vif); xenvif_free(be->vif);
be->vif = NULL; be->vif = NULL;
} }
...@@ -1131,6 +1129,7 @@ static struct xenbus_driver netback_driver = { ...@@ -1131,6 +1129,7 @@ static struct xenbus_driver netback_driver = {
.remove = netback_remove, .remove = netback_remove,
.uevent = netback_uevent, .uevent = netback_uevent,
.otherend_changed = frontend_changed, .otherend_changed = frontend_changed,
.allow_rebind = true,
}; };
int xenvif_xenbus_init(void) int xenvif_xenbus_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment