1e613b064Saliguori /* 2e613b064Saliguori * xen paravirt network card backend 3e613b064Saliguori * 4e613b064Saliguori * (c) Gerd Hoffmann <kraxel@redhat.com> 5e613b064Saliguori * 6e613b064Saliguori * This program is free software; you can redistribute it and/or modify 7e613b064Saliguori * it under the terms of the GNU General Public License as published by 8e613b064Saliguori * the Free Software Foundation; under version 2 of the License. 9e613b064Saliguori * 10e613b064Saliguori * This program is distributed in the hope that it will be useful, 11e613b064Saliguori * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e613b064Saliguori * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e613b064Saliguori * GNU General Public License for more details. 14e613b064Saliguori * 15e613b064Saliguori * You should have received a copy of the GNU General Public License along 168167ee88SBlue Swirl * with this program; if not, see <http://www.gnu.org/licenses/>. 176b620ca3SPaolo Bonzini * 186b620ca3SPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the 196b620ca3SPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version. 20e613b064Saliguori */ 21e613b064Saliguori 2221cbfe5fSPeter Maydell #include "qemu/osdep.h" 23*25967ff6SDavid Woodhouse #include "qemu/main-loop.h" 24*25967ff6SDavid Woodhouse #include "qemu/cutils.h" 25*25967ff6SDavid Woodhouse #include "qemu/log.h" 26*25967ff6SDavid Woodhouse #include "qemu/qemu-print.h" 27*25967ff6SDavid Woodhouse #include "qapi/qmp/qdict.h" 28*25967ff6SDavid Woodhouse #include "qapi/error.h" 29*25967ff6SDavid Woodhouse 30e613b064Saliguori #include <sys/socket.h> 31e613b064Saliguori #include <sys/ioctl.h> 32e613b064Saliguori #include <sys/wait.h> 33e613b064Saliguori 341422e32dSPaolo Bonzini #include "net/net.h" 357200ac3cSMark McLoughlin #include "net/checksum.h" 36658788c5SMark McLoughlin #include "net/util.h" 37*25967ff6SDavid Woodhouse 38*25967ff6SDavid Woodhouse #include "hw/xen/xen-backend.h" 39*25967ff6SDavid Woodhouse #include "hw/xen/xen-bus-helper.h" 40*25967ff6SDavid Woodhouse #include "hw/qdev-properties.h" 41*25967ff6SDavid Woodhouse #include "hw/qdev-properties-system.h" 42e613b064Saliguori 43a3434a2dSAnthony PERARD #include "hw/xen/interface/io/netif.h" 44*25967ff6SDavid Woodhouse #include "hw/xen/interface/io/xs_wire.h" 45*25967ff6SDavid Woodhouse 46*25967ff6SDavid Woodhouse #include "trace.h" 47b41f6719SAnthony PERARD 48e613b064Saliguori /* ------------------------------------------------------------- */ 49e613b064Saliguori 50e613b064Saliguori struct XenNetDev { 51*25967ff6SDavid Woodhouse struct XenDevice xendev; /* must be first */ 52*25967ff6SDavid Woodhouse XenEventChannel *event_channel; 53*25967ff6SDavid Woodhouse int dev; 54e613b064Saliguori int tx_work; 55*25967ff6SDavid Woodhouse unsigned int tx_ring_ref; 56*25967ff6SDavid Woodhouse unsigned int rx_ring_ref; 57e613b064Saliguori struct netif_tx_sring *txs; 58e613b064Saliguori struct netif_rx_sring *rxs; 59e613b064Saliguori netif_tx_back_ring_t tx_ring; 60e613b064Saliguori netif_rx_back_ring_t rx_ring; 61658788c5SMark McLoughlin NICConf conf; 62658788c5SMark McLoughlin NICState *nic; 63e613b064Saliguori }; 64e613b064Saliguori 65*25967ff6SDavid Woodhouse typedef struct XenNetDev XenNetDev; 66*25967ff6SDavid Woodhouse 67*25967ff6SDavid Woodhouse #define TYPE_XEN_NET_DEVICE "xen-net-device" 68*25967ff6SDavid Woodhouse OBJECT_DECLARE_SIMPLE_TYPE(XenNetDev, XEN_NET_DEVICE) 69*25967ff6SDavid Woodhouse 70e613b064Saliguori /* ------------------------------------------------------------- */ 71e613b064Saliguori 72e613b064Saliguori static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st) 73e613b064Saliguori { 74e613b064Saliguori RING_IDX i = netdev->tx_ring.rsp_prod_pvt; 75e613b064Saliguori netif_tx_response_t *resp; 76e613b064Saliguori int notify; 77e613b064Saliguori 78e613b064Saliguori resp = RING_GET_RESPONSE(&netdev->tx_ring, i); 79e613b064Saliguori resp->id = txp->id; 80e613b064Saliguori resp->status = st; 81e613b064Saliguori 82e613b064Saliguori #if 0 83209cd7abSAnthony PERARD if (txp->flags & NETTXF_extra_info) { 84e613b064Saliguori RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL; 85209cd7abSAnthony PERARD } 86e613b064Saliguori #endif 87e613b064Saliguori 88e613b064Saliguori netdev->tx_ring.rsp_prod_pvt = ++i; 89e613b064Saliguori RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify); 90209cd7abSAnthony PERARD if (notify) { 91*25967ff6SDavid Woodhouse xen_device_notify_event_channel(XEN_DEVICE(netdev), 92*25967ff6SDavid Woodhouse netdev->event_channel, NULL); 93209cd7abSAnthony PERARD } 94e613b064Saliguori 95e613b064Saliguori if (i == netdev->tx_ring.req_cons) { 96e613b064Saliguori int more_to_do; 97e613b064Saliguori RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do); 98209cd7abSAnthony PERARD if (more_to_do) { 99e613b064Saliguori netdev->tx_work++; 100e613b064Saliguori } 101e613b064Saliguori } 102209cd7abSAnthony PERARD } 103e613b064Saliguori 104e613b064Saliguori static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end) 105e613b064Saliguori { 106e613b064Saliguori #if 0 107e613b064Saliguori /* 108e613b064Saliguori * Hmm, why netback fails everything in the ring? 109e613b064Saliguori * Should we do that even when not supporting SG and TSO? 110e613b064Saliguori */ 111e613b064Saliguori RING_IDX cons = netdev->tx_ring.req_cons; 112e613b064Saliguori 113e613b064Saliguori do { 114e613b064Saliguori make_tx_response(netif, txp, NETIF_RSP_ERROR); 115209cd7abSAnthony PERARD if (cons >= end) { 116e613b064Saliguori break; 117209cd7abSAnthony PERARD } 118e613b064Saliguori txp = RING_GET_REQUEST(&netdev->tx_ring, cons++); 119e613b064Saliguori } while (1); 120e613b064Saliguori netdev->tx_ring.req_cons = cons; 121e613b064Saliguori netif_schedule_work(netif); 122e613b064Saliguori netif_put(netif); 123e613b064Saliguori #else 124e613b064Saliguori net_tx_response(netdev, txp, NETIF_RSP_ERROR); 125e613b064Saliguori #endif 126e613b064Saliguori } 127e613b064Saliguori 128*25967ff6SDavid Woodhouse static bool net_tx_packets(struct XenNetDev *netdev) 129e613b064Saliguori { 130*25967ff6SDavid Woodhouse bool done_something = false; 131e613b064Saliguori netif_tx_request_t txreq; 132e613b064Saliguori RING_IDX rc, rp; 133e613b064Saliguori void *page; 134e613b064Saliguori void *tmpbuf = NULL; 135e613b064Saliguori 136*25967ff6SDavid Woodhouse assert(qemu_mutex_iothread_locked()); 137*25967ff6SDavid Woodhouse 138e613b064Saliguori for (;;) { 139e613b064Saliguori rc = netdev->tx_ring.req_cons; 140e613b064Saliguori rp = netdev->tx_ring.sring->req_prod; 141e613b064Saliguori xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ 142e613b064Saliguori 143e613b064Saliguori while ((rc != rp)) { 144209cd7abSAnthony PERARD if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) { 145e613b064Saliguori break; 146209cd7abSAnthony PERARD } 147e613b064Saliguori memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq)); 148e613b064Saliguori netdev->tx_ring.req_cons = ++rc; 149*25967ff6SDavid Woodhouse done_something = true; 150e613b064Saliguori 151e613b064Saliguori #if 1 152e613b064Saliguori /* should not happen in theory, we don't announce the * 153e613b064Saliguori * feature-{sg,gso,whatelse} flags in xenstore (yet?) */ 154e613b064Saliguori if (txreq.flags & NETTXF_extra_info) { 155*25967ff6SDavid Woodhouse qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: extra info flag\n", 156*25967ff6SDavid Woodhouse netdev->dev); 157e613b064Saliguori net_tx_error(netdev, &txreq, rc); 158e613b064Saliguori continue; 159e613b064Saliguori } 160e613b064Saliguori if (txreq.flags & NETTXF_more_data) { 161*25967ff6SDavid Woodhouse qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: more data flag\n", 162*25967ff6SDavid Woodhouse netdev->dev); 163e613b064Saliguori net_tx_error(netdev, &txreq, rc); 164e613b064Saliguori continue; 165e613b064Saliguori } 166e613b064Saliguori #endif 167e613b064Saliguori 168e613b064Saliguori if (txreq.size < 14) { 169*25967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: bad packet size: %d\n", 170*25967ff6SDavid Woodhouse netdev->dev, txreq.size); 171e613b064Saliguori net_tx_error(netdev, &txreq, rc); 172e613b064Saliguori continue; 173e613b064Saliguori } 174e613b064Saliguori 175a9ae1418SDavid Woodhouse if ((txreq.offset + txreq.size) > XEN_PAGE_SIZE) { 176*25967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: error: page crossing\n", 177*25967ff6SDavid Woodhouse netdev->dev); 178e613b064Saliguori net_tx_error(netdev, &txreq, rc); 179e613b064Saliguori continue; 180e613b064Saliguori } 181e613b064Saliguori 182*25967ff6SDavid Woodhouse trace_xen_netdev_tx(netdev->dev, txreq.gref, txreq.offset, 183*25967ff6SDavid Woodhouse txreq.size, txreq.flags, 184e613b064Saliguori (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "", 185e613b064Saliguori (txreq.flags & NETTXF_data_validated) ? " data_validated" : "", 186e613b064Saliguori (txreq.flags & NETTXF_more_data) ? " more_data" : "", 187e613b064Saliguori (txreq.flags & NETTXF_extra_info) ? " extra_info" : ""); 188e613b064Saliguori 189*25967ff6SDavid Woodhouse page = xen_device_map_grant_refs(&netdev->xendev, &txreq.gref, 1, 190*25967ff6SDavid Woodhouse PROT_READ, NULL); 191e613b064Saliguori if (page == NULL) { 192*25967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, 193*25967ff6SDavid Woodhouse "vif%u: tx gref dereference failed (%d)\n", 194*25967ff6SDavid Woodhouse netdev->dev, txreq.gref); 195e613b064Saliguori net_tx_error(netdev, &txreq, rc); 196e613b064Saliguori continue; 197e613b064Saliguori } 198e613b064Saliguori if (txreq.flags & NETTXF_csum_blank) { 199e613b064Saliguori /* have read-only mapping -> can't fill checksum in-place */ 200209cd7abSAnthony PERARD if (!tmpbuf) { 201a9ae1418SDavid Woodhouse tmpbuf = g_malloc(XEN_PAGE_SIZE); 202209cd7abSAnthony PERARD } 203e613b064Saliguori memcpy(tmpbuf, page + txreq.offset, txreq.size); 204f5746335SBin Meng net_checksum_calculate(tmpbuf, txreq.size, CSUM_ALL); 205b356f76dSJason Wang qemu_send_packet(qemu_get_queue(netdev->nic), tmpbuf, 206b356f76dSJason Wang txreq.size); 207e613b064Saliguori } else { 208b356f76dSJason Wang qemu_send_packet(qemu_get_queue(netdev->nic), 209b356f76dSJason Wang page + txreq.offset, txreq.size); 210e613b064Saliguori } 211*25967ff6SDavid Woodhouse xen_device_unmap_grant_refs(&netdev->xendev, page, &txreq.gref, 1, 212*25967ff6SDavid Woodhouse NULL); 213e613b064Saliguori net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); 214e613b064Saliguori } 215209cd7abSAnthony PERARD if (!netdev->tx_work) { 216e613b064Saliguori break; 217209cd7abSAnthony PERARD } 218e613b064Saliguori netdev->tx_work = 0; 219e613b064Saliguori } 2207267c094SAnthony Liguori g_free(tmpbuf); 221*25967ff6SDavid Woodhouse return done_something; 222e613b064Saliguori } 223e613b064Saliguori 224e613b064Saliguori /* ------------------------------------------------------------- */ 225e613b064Saliguori 226e613b064Saliguori static void net_rx_response(struct XenNetDev *netdev, 227e613b064Saliguori netif_rx_request_t *req, int8_t st, 228e613b064Saliguori uint16_t offset, uint16_t size, 229e613b064Saliguori uint16_t flags) 230e613b064Saliguori { 231e613b064Saliguori RING_IDX i = netdev->rx_ring.rsp_prod_pvt; 232e613b064Saliguori netif_rx_response_t *resp; 233e613b064Saliguori int notify; 234e613b064Saliguori 235e613b064Saliguori resp = RING_GET_RESPONSE(&netdev->rx_ring, i); 236e613b064Saliguori resp->offset = offset; 237e613b064Saliguori resp->flags = flags; 238e613b064Saliguori resp->id = req->id; 239e613b064Saliguori resp->status = (int16_t)size; 240209cd7abSAnthony PERARD if (st < 0) { 241e613b064Saliguori resp->status = (int16_t)st; 242209cd7abSAnthony PERARD } 243e613b064Saliguori 244*25967ff6SDavid Woodhouse trace_xen_netdev_rx(netdev->dev, i, resp->status, resp->flags); 245e613b064Saliguori 246e613b064Saliguori netdev->rx_ring.rsp_prod_pvt = ++i; 247e613b064Saliguori RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify); 248209cd7abSAnthony PERARD if (notify) { 249*25967ff6SDavid Woodhouse xen_device_notify_event_channel(XEN_DEVICE(netdev), 250*25967ff6SDavid Woodhouse netdev->event_channel, NULL); 251e613b064Saliguori } 252209cd7abSAnthony PERARD } 253e613b064Saliguori 254e613b064Saliguori #define NET_IP_ALIGN 2 255e613b064Saliguori 2564e68f7a0SStefan Hajnoczi static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size) 257e613b064Saliguori { 258cc1f0f45SJason Wang struct XenNetDev *netdev = qemu_get_nic_opaque(nc); 259e613b064Saliguori netif_rx_request_t rxreq; 260e613b064Saliguori RING_IDX rc, rp; 261e613b064Saliguori void *page; 262e613b064Saliguori 263*25967ff6SDavid Woodhouse assert(qemu_mutex_iothread_locked()); 264*25967ff6SDavid Woodhouse 265*25967ff6SDavid Woodhouse if (xen_device_backend_get_state(&netdev->xendev) != XenbusStateConnected) { 2664f1c942bSMark McLoughlin return -1; 267209cd7abSAnthony PERARD } 268e613b064Saliguori 269e613b064Saliguori rc = netdev->rx_ring.req_cons; 270e613b064Saliguori rp = netdev->rx_ring.sring->req_prod; 271e613b064Saliguori xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ 272e613b064Saliguori 273e613b064Saliguori if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { 2747bba83bfSFam Zheng return 0; 275e613b064Saliguori } 276a9ae1418SDavid Woodhouse if (size > XEN_PAGE_SIZE - NET_IP_ALIGN) { 277*25967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: packet too big (%lu > %ld)", 278*25967ff6SDavid Woodhouse netdev->dev, (unsigned long)size, 279*25967ff6SDavid Woodhouse XEN_PAGE_SIZE - NET_IP_ALIGN); 2804f1c942bSMark McLoughlin return -1; 281e613b064Saliguori } 282e613b064Saliguori 283e613b064Saliguori memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq)); 284e613b064Saliguori netdev->rx_ring.req_cons = ++rc; 285e613b064Saliguori 286*25967ff6SDavid Woodhouse page = xen_device_map_grant_refs(&netdev->xendev, &rxreq.gref, 1, 287*25967ff6SDavid Woodhouse PROT_WRITE, NULL); 288e613b064Saliguori if (page == NULL) { 289*25967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, 290*25967ff6SDavid Woodhouse "vif%u: rx gref dereference failed (%d)\n", 291*25967ff6SDavid Woodhouse netdev->dev, rxreq.gref); 292e613b064Saliguori net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0); 2934f1c942bSMark McLoughlin return -1; 294e613b064Saliguori } 295e613b064Saliguori memcpy(page + NET_IP_ALIGN, buf, size); 296*25967ff6SDavid Woodhouse xen_device_unmap_grant_refs(&netdev->xendev, page, &rxreq.gref, 1, NULL); 297e613b064Saliguori net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); 2984f1c942bSMark McLoughlin 2994f1c942bSMark McLoughlin return size; 300e613b064Saliguori } 301e613b064Saliguori 302e613b064Saliguori /* ------------------------------------------------------------- */ 303e613b064Saliguori 304658788c5SMark McLoughlin static NetClientInfo net_xen_info = { 305f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC, 306658788c5SMark McLoughlin .size = sizeof(NICState), 307658788c5SMark McLoughlin .receive = net_rx_packet, 308658788c5SMark McLoughlin }; 309658788c5SMark McLoughlin 310*25967ff6SDavid Woodhouse static void xen_netdev_realize(XenDevice *xendev, Error **errp) 311e613b064Saliguori { 312*25967ff6SDavid Woodhouse ERRP_GUARD(); 313*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 314*25967ff6SDavid Woodhouse NetClientState *nc; 315e613b064Saliguori 316*25967ff6SDavid Woodhouse qemu_macaddr_default_if_unset(&netdev->conf.macaddr); 317e613b064Saliguori 318*25967ff6SDavid Woodhouse xen_device_frontend_printf(xendev, "mac", "%02x:%02x:%02x:%02x:%02x:%02x", 319*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[0], 320*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[1], 321*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[2], 322*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[3], 323*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[4], 324*25967ff6SDavid Woodhouse netdev->conf.macaddr.a[5]); 325658788c5SMark McLoughlin 326658788c5SMark McLoughlin netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, 327*25967ff6SDavid Woodhouse object_get_typename(OBJECT(xendev)), 328*25967ff6SDavid Woodhouse DEVICE(xendev)->id, netdev); 329658788c5SMark McLoughlin 330*25967ff6SDavid Woodhouse nc = qemu_get_queue(netdev->nic); 331*25967ff6SDavid Woodhouse qemu_format_nic_info_str(nc, netdev->conf.macaddr.a); 332e613b064Saliguori 333e613b064Saliguori /* fill info */ 334*25967ff6SDavid Woodhouse xen_device_backend_printf(xendev, "feature-rx-copy", "%u", 1); 335*25967ff6SDavid Woodhouse xen_device_backend_printf(xendev, "feature-rx-flip", "%u", 0); 336e613b064Saliguori 337*25967ff6SDavid Woodhouse trace_xen_netdev_realize(netdev->dev, nc->info_str, nc->peer ? 338*25967ff6SDavid Woodhouse nc->peer->name : "(none)"); 339e613b064Saliguori } 340e613b064Saliguori 341*25967ff6SDavid Woodhouse static bool net_event(void *_xendev) 342e613b064Saliguori { 343*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(_xendev); 344*25967ff6SDavid Woodhouse bool done_something; 345e613b064Saliguori 346*25967ff6SDavid Woodhouse done_something = net_tx_packets(netdev); 347*25967ff6SDavid Woodhouse qemu_flush_queued_packets(qemu_get_queue(netdev->nic)); 348*25967ff6SDavid Woodhouse return done_something; 349209cd7abSAnthony PERARD } 350e613b064Saliguori 351*25967ff6SDavid Woodhouse static bool xen_netdev_connect(XenDevice *xendev, Error **errp) 352*25967ff6SDavid Woodhouse { 353*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 354*25967ff6SDavid Woodhouse unsigned int port, rx_copy; 355*25967ff6SDavid Woodhouse 356*25967ff6SDavid Woodhouse assert(qemu_mutex_iothread_locked()); 357*25967ff6SDavid Woodhouse 358*25967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "tx-ring-ref", "%u", 359*25967ff6SDavid Woodhouse &netdev->tx_ring_ref) != 1) { 360*25967ff6SDavid Woodhouse error_setg(errp, "failed to read tx-ring-ref"); 361*25967ff6SDavid Woodhouse return false; 362*25967ff6SDavid Woodhouse } 363*25967ff6SDavid Woodhouse 364*25967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "rx-ring-ref", "%u", 365*25967ff6SDavid Woodhouse &netdev->rx_ring_ref) != 1) { 366*25967ff6SDavid Woodhouse error_setg(errp, "failed to read rx-ring-ref"); 367*25967ff6SDavid Woodhouse return false; 368*25967ff6SDavid Woodhouse } 369*25967ff6SDavid Woodhouse 370*25967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "event-channel", "%u", 371*25967ff6SDavid Woodhouse &port) != 1) { 372*25967ff6SDavid Woodhouse error_setg(errp, "failed to read event-channel"); 373*25967ff6SDavid Woodhouse return false; 374*25967ff6SDavid Woodhouse } 375*25967ff6SDavid Woodhouse 376*25967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "request-rx-copy", "%u", 377*25967ff6SDavid Woodhouse &rx_copy) != 1) { 378e613b064Saliguori rx_copy = 0; 379209cd7abSAnthony PERARD } 380e613b064Saliguori if (rx_copy == 0) { 381*25967ff6SDavid Woodhouse error_setg(errp, "frontend doesn't support rx-copy"); 382*25967ff6SDavid Woodhouse return false; 383e613b064Saliguori } 384e613b064Saliguori 385*25967ff6SDavid Woodhouse netdev->txs = xen_device_map_grant_refs(xendev, 386*25967ff6SDavid Woodhouse &netdev->tx_ring_ref, 1, 387*25967ff6SDavid Woodhouse PROT_READ | PROT_WRITE, 388*25967ff6SDavid Woodhouse errp); 389b4f72e31SChen Gang if (!netdev->txs) { 390*25967ff6SDavid Woodhouse error_prepend(errp, "failed to map tx grant ref: "); 391*25967ff6SDavid Woodhouse return false; 392b4f72e31SChen Gang } 393*25967ff6SDavid Woodhouse 394*25967ff6SDavid Woodhouse netdev->rxs = xen_device_map_grant_refs(xendev, 395*25967ff6SDavid Woodhouse &netdev->rx_ring_ref, 1, 396*25967ff6SDavid Woodhouse PROT_READ | PROT_WRITE, 397*25967ff6SDavid Woodhouse errp); 398b4f72e31SChen Gang if (!netdev->rxs) { 399*25967ff6SDavid Woodhouse error_prepend(errp, "failed to map rx grant ref: "); 400*25967ff6SDavid Woodhouse return false; 401209cd7abSAnthony PERARD } 402*25967ff6SDavid Woodhouse 403a9ae1418SDavid Woodhouse BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE); 404a9ae1418SDavid Woodhouse BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE); 405e613b064Saliguori 406*25967ff6SDavid Woodhouse netdev->event_channel = xen_device_bind_event_channel(xendev, port, 407*25967ff6SDavid Woodhouse net_event, 408*25967ff6SDavid Woodhouse netdev, 409*25967ff6SDavid Woodhouse errp); 410*25967ff6SDavid Woodhouse if (!netdev->event_channel) { 411*25967ff6SDavid Woodhouse return false; 412e613b064Saliguori } 413e613b064Saliguori 414*25967ff6SDavid Woodhouse trace_xen_netdev_connect(netdev->dev, netdev->tx_ring_ref, 415*25967ff6SDavid Woodhouse netdev->rx_ring_ref, port); 416*25967ff6SDavid Woodhouse 417*25967ff6SDavid Woodhouse net_tx_packets(netdev); 418*25967ff6SDavid Woodhouse return true; 419*25967ff6SDavid Woodhouse } 420*25967ff6SDavid Woodhouse 421*25967ff6SDavid Woodhouse static void xen_netdev_disconnect(XenDevice *xendev, Error **errp) 422e613b064Saliguori { 423*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 424e613b064Saliguori 425*25967ff6SDavid Woodhouse trace_xen_netdev_disconnect(netdev->dev); 426e613b064Saliguori 427*25967ff6SDavid Woodhouse assert(qemu_mutex_iothread_locked()); 428*25967ff6SDavid Woodhouse 429*25967ff6SDavid Woodhouse netdev->tx_ring.sring = NULL; 430*25967ff6SDavid Woodhouse netdev->rx_ring.sring = NULL; 431*25967ff6SDavid Woodhouse 432*25967ff6SDavid Woodhouse if (netdev->event_channel) { 433*25967ff6SDavid Woodhouse xen_device_unbind_event_channel(xendev, netdev->event_channel, 434*25967ff6SDavid Woodhouse errp); 435*25967ff6SDavid Woodhouse netdev->event_channel = NULL; 436*25967ff6SDavid Woodhouse } 437e613b064Saliguori if (netdev->txs) { 438*25967ff6SDavid Woodhouse xen_device_unmap_grant_refs(xendev, netdev->txs, 439*25967ff6SDavid Woodhouse &netdev->tx_ring_ref, 1, errp); 440e613b064Saliguori netdev->txs = NULL; 441e613b064Saliguori } 442e613b064Saliguori if (netdev->rxs) { 443*25967ff6SDavid Woodhouse xen_device_unmap_grant_refs(xendev, netdev->rxs, 444*25967ff6SDavid Woodhouse &netdev->rx_ring_ref, 1, errp); 445e613b064Saliguori netdev->rxs = NULL; 446e613b064Saliguori } 447e613b064Saliguori } 448e613b064Saliguori 449*25967ff6SDavid Woodhouse /* -------------------------------------------------------------------- */ 450*25967ff6SDavid Woodhouse 451*25967ff6SDavid Woodhouse 452*25967ff6SDavid Woodhouse static void xen_netdev_frontend_changed(XenDevice *xendev, 453*25967ff6SDavid Woodhouse enum xenbus_state frontend_state, 454*25967ff6SDavid Woodhouse Error **errp) 455e613b064Saliguori { 456*25967ff6SDavid Woodhouse ERRP_GUARD(); 457*25967ff6SDavid Woodhouse enum xenbus_state backend_state = xen_device_backend_get_state(xendev); 458*25967ff6SDavid Woodhouse 459*25967ff6SDavid Woodhouse trace_xen_netdev_frontend_changed(xendev->name, frontend_state); 460*25967ff6SDavid Woodhouse 461*25967ff6SDavid Woodhouse switch (frontend_state) { 462*25967ff6SDavid Woodhouse case XenbusStateConnected: 463*25967ff6SDavid Woodhouse if (backend_state == XenbusStateConnected) { 464*25967ff6SDavid Woodhouse break; 465e613b064Saliguori } 466e613b064Saliguori 467*25967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, errp); 468*25967ff6SDavid Woodhouse if (*errp) { 469*25967ff6SDavid Woodhouse break; 470*25967ff6SDavid Woodhouse } 471*25967ff6SDavid Woodhouse 472*25967ff6SDavid Woodhouse if (!xen_netdev_connect(xendev, errp)) { 473*25967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, NULL); 474*25967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosing); 475*25967ff6SDavid Woodhouse break; 476*25967ff6SDavid Woodhouse } 477*25967ff6SDavid Woodhouse 478*25967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateConnected); 479*25967ff6SDavid Woodhouse break; 480*25967ff6SDavid Woodhouse 481*25967ff6SDavid Woodhouse case XenbusStateClosing: 482*25967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosing); 483*25967ff6SDavid Woodhouse break; 484*25967ff6SDavid Woodhouse 485*25967ff6SDavid Woodhouse case XenbusStateClosed: 486*25967ff6SDavid Woodhouse case XenbusStateUnknown: 487*25967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, errp); 488*25967ff6SDavid Woodhouse if (*errp) { 489*25967ff6SDavid Woodhouse break; 490*25967ff6SDavid Woodhouse } 491*25967ff6SDavid Woodhouse 492*25967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosed); 493*25967ff6SDavid Woodhouse break; 494*25967ff6SDavid Woodhouse 495*25967ff6SDavid Woodhouse case XenbusStateInitialised: 496*25967ff6SDavid Woodhouse /* 497*25967ff6SDavid Woodhouse * Linux netback does nothing on the frontend going (back) to 498*25967ff6SDavid Woodhouse * XenbusStateInitialised, so do the same here. 499*25967ff6SDavid Woodhouse */ 500*25967ff6SDavid Woodhouse default: 501*25967ff6SDavid Woodhouse break; 502*25967ff6SDavid Woodhouse } 503*25967ff6SDavid Woodhouse } 504*25967ff6SDavid Woodhouse 505*25967ff6SDavid Woodhouse static char *xen_netdev_get_name(XenDevice *xendev, Error **errp) 506e613b064Saliguori { 507*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 508*25967ff6SDavid Woodhouse 509*25967ff6SDavid Woodhouse if (netdev->dev == -1) { 510*25967ff6SDavid Woodhouse XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 511*25967ff6SDavid Woodhouse char fe_path[XENSTORE_ABS_PATH_MAX + 1]; 512*25967ff6SDavid Woodhouse int idx = (xen_mode == XEN_EMULATE) ? 0 : 1; 513*25967ff6SDavid Woodhouse char *value; 514*25967ff6SDavid Woodhouse 515*25967ff6SDavid Woodhouse /* Theoretically we could go up to INT_MAX here but that's overkill */ 516*25967ff6SDavid Woodhouse while (idx < 100) { 517*25967ff6SDavid Woodhouse snprintf(fe_path, sizeof(fe_path), 518*25967ff6SDavid Woodhouse "/local/domain/%u/device/vif/%u", 519*25967ff6SDavid Woodhouse xendev->frontend_id, idx); 520*25967ff6SDavid Woodhouse value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL); 521*25967ff6SDavid Woodhouse if (!value) { 522*25967ff6SDavid Woodhouse if (errno == ENOENT) { 523*25967ff6SDavid Woodhouse netdev->dev = idx; 524*25967ff6SDavid Woodhouse goto found; 525*25967ff6SDavid Woodhouse } 526*25967ff6SDavid Woodhouse error_setg(errp, "cannot read %s: %s", fe_path, 527*25967ff6SDavid Woodhouse strerror(errno)); 528*25967ff6SDavid Woodhouse return NULL; 529*25967ff6SDavid Woodhouse } 530*25967ff6SDavid Woodhouse free(value); 531*25967ff6SDavid Woodhouse idx++; 532*25967ff6SDavid Woodhouse } 533*25967ff6SDavid Woodhouse error_setg(errp, "cannot find device index for netdev device"); 534*25967ff6SDavid Woodhouse return NULL; 535*25967ff6SDavid Woodhouse } 536*25967ff6SDavid Woodhouse found: 537*25967ff6SDavid Woodhouse return g_strdup_printf("%u", netdev->dev); 538*25967ff6SDavid Woodhouse } 539*25967ff6SDavid Woodhouse 540*25967ff6SDavid Woodhouse static void xen_netdev_unrealize(XenDevice *xendev) 541*25967ff6SDavid Woodhouse { 542*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 543*25967ff6SDavid Woodhouse 544*25967ff6SDavid Woodhouse trace_xen_netdev_unrealize(netdev->dev); 545*25967ff6SDavid Woodhouse 546*25967ff6SDavid Woodhouse /* Disconnect from the frontend in case this has not already happened */ 547*25967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, NULL); 548e613b064Saliguori 549d4685837SChen Gang if (netdev->nic) { 550d4685837SChen Gang qemu_del_nic(netdev->nic); 551d4685837SChen Gang } 552e613b064Saliguori } 553e613b064Saliguori 554e613b064Saliguori /* ------------------------------------------------------------- */ 555e613b064Saliguori 556*25967ff6SDavid Woodhouse static Property xen_netdev_properties[] = { 557*25967ff6SDavid Woodhouse DEFINE_NIC_PROPERTIES(XenNetDev, conf), 558*25967ff6SDavid Woodhouse DEFINE_PROP_INT32("idx", XenNetDev, dev, -1), 559*25967ff6SDavid Woodhouse DEFINE_PROP_END_OF_LIST(), 560e613b064Saliguori }; 561*25967ff6SDavid Woodhouse 562*25967ff6SDavid Woodhouse static void xen_netdev_class_init(ObjectClass *class, void *data) 563*25967ff6SDavid Woodhouse { 564*25967ff6SDavid Woodhouse DeviceClass *dev_class = DEVICE_CLASS(class); 565*25967ff6SDavid Woodhouse XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); 566*25967ff6SDavid Woodhouse 567*25967ff6SDavid Woodhouse xendev_class->backend = "qnic"; 568*25967ff6SDavid Woodhouse xendev_class->device = "vif"; 569*25967ff6SDavid Woodhouse xendev_class->get_name = xen_netdev_get_name; 570*25967ff6SDavid Woodhouse xendev_class->realize = xen_netdev_realize; 571*25967ff6SDavid Woodhouse xendev_class->frontend_changed = xen_netdev_frontend_changed; 572*25967ff6SDavid Woodhouse xendev_class->unrealize = xen_netdev_unrealize; 573*25967ff6SDavid Woodhouse set_bit(DEVICE_CATEGORY_NETWORK, dev_class->categories); 574*25967ff6SDavid Woodhouse dev_class->user_creatable = true; 575*25967ff6SDavid Woodhouse 576*25967ff6SDavid Woodhouse device_class_set_props(dev_class, xen_netdev_properties); 577*25967ff6SDavid Woodhouse } 578*25967ff6SDavid Woodhouse 579*25967ff6SDavid Woodhouse static const TypeInfo xen_net_type_info = { 580*25967ff6SDavid Woodhouse .name = TYPE_XEN_NET_DEVICE, 581*25967ff6SDavid Woodhouse .parent = TYPE_XEN_DEVICE, 582*25967ff6SDavid Woodhouse .instance_size = sizeof(XenNetDev), 583*25967ff6SDavid Woodhouse .class_init = xen_netdev_class_init, 584*25967ff6SDavid Woodhouse }; 585*25967ff6SDavid Woodhouse 586*25967ff6SDavid Woodhouse static void xen_net_register_types(void) 587*25967ff6SDavid Woodhouse { 588*25967ff6SDavid Woodhouse type_register_static(&xen_net_type_info); 589*25967ff6SDavid Woodhouse } 590*25967ff6SDavid Woodhouse 591*25967ff6SDavid Woodhouse type_init(xen_net_register_types) 592*25967ff6SDavid Woodhouse 593*25967ff6SDavid Woodhouse /* Called to instantiate a XenNetDev when the backend is detected. */ 594*25967ff6SDavid Woodhouse static void xen_net_device_create(XenBackendInstance *backend, 595*25967ff6SDavid Woodhouse QDict *opts, Error **errp) 596*25967ff6SDavid Woodhouse { 597*25967ff6SDavid Woodhouse ERRP_GUARD(); 598*25967ff6SDavid Woodhouse XenBus *xenbus = xen_backend_get_bus(backend); 599*25967ff6SDavid Woodhouse const char *name = xen_backend_get_name(backend); 600*25967ff6SDavid Woodhouse XenDevice *xendev = NULL; 601*25967ff6SDavid Woodhouse unsigned long number; 602*25967ff6SDavid Woodhouse const char *macstr; 603*25967ff6SDavid Woodhouse XenNetDev *net; 604*25967ff6SDavid Woodhouse MACAddr mac; 605*25967ff6SDavid Woodhouse 606*25967ff6SDavid Woodhouse if (qemu_strtoul(name, NULL, 10, &number) || number >= INT_MAX) { 607*25967ff6SDavid Woodhouse error_setg(errp, "failed to parse name '%s'", name); 608*25967ff6SDavid Woodhouse goto fail; 609*25967ff6SDavid Woodhouse } 610*25967ff6SDavid Woodhouse 611*25967ff6SDavid Woodhouse trace_xen_netdev_create(number); 612*25967ff6SDavid Woodhouse 613*25967ff6SDavid Woodhouse macstr = qdict_get_try_str(opts, "mac"); 614*25967ff6SDavid Woodhouse if (macstr == NULL) { 615*25967ff6SDavid Woodhouse error_setg(errp, "no MAC address found"); 616*25967ff6SDavid Woodhouse goto fail; 617*25967ff6SDavid Woodhouse } 618*25967ff6SDavid Woodhouse 619*25967ff6SDavid Woodhouse if (net_parse_macaddr(mac.a, macstr) < 0) { 620*25967ff6SDavid Woodhouse error_setg(errp, "failed to parse MAC address"); 621*25967ff6SDavid Woodhouse goto fail; 622*25967ff6SDavid Woodhouse } 623*25967ff6SDavid Woodhouse 624*25967ff6SDavid Woodhouse xendev = XEN_DEVICE(qdev_new(TYPE_XEN_NET_DEVICE)); 625*25967ff6SDavid Woodhouse net = XEN_NET_DEVICE(xendev); 626*25967ff6SDavid Woodhouse 627*25967ff6SDavid Woodhouse net->dev = number; 628*25967ff6SDavid Woodhouse memcpy(&net->conf.macaddr, &mac, sizeof(mac)); 629*25967ff6SDavid Woodhouse 630*25967ff6SDavid Woodhouse if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) { 631*25967ff6SDavid Woodhouse xen_backend_set_device(backend, xendev); 632*25967ff6SDavid Woodhouse return; 633*25967ff6SDavid Woodhouse } 634*25967ff6SDavid Woodhouse 635*25967ff6SDavid Woodhouse error_prepend(errp, "realization of net device %lu failed: ", 636*25967ff6SDavid Woodhouse number); 637*25967ff6SDavid Woodhouse 638*25967ff6SDavid Woodhouse fail: 639*25967ff6SDavid Woodhouse if (xendev) { 640*25967ff6SDavid Woodhouse object_unparent(OBJECT(xendev)); 641*25967ff6SDavid Woodhouse } 642*25967ff6SDavid Woodhouse } 643*25967ff6SDavid Woodhouse 644*25967ff6SDavid Woodhouse static void xen_net_device_destroy(XenBackendInstance *backend, 645*25967ff6SDavid Woodhouse Error **errp) 646*25967ff6SDavid Woodhouse { 647*25967ff6SDavid Woodhouse ERRP_GUARD(); 648*25967ff6SDavid Woodhouse XenDevice *xendev = xen_backend_get_device(backend); 649*25967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 650*25967ff6SDavid Woodhouse 651*25967ff6SDavid Woodhouse trace_xen_netdev_destroy(netdev->dev); 652*25967ff6SDavid Woodhouse 653*25967ff6SDavid Woodhouse object_unparent(OBJECT(xendev)); 654*25967ff6SDavid Woodhouse } 655*25967ff6SDavid Woodhouse 656*25967ff6SDavid Woodhouse static const XenBackendInfo xen_net_backend_info = { 657*25967ff6SDavid Woodhouse .type = "qnic", 658*25967ff6SDavid Woodhouse .create = xen_net_device_create, 659*25967ff6SDavid Woodhouse .destroy = xen_net_device_destroy, 660*25967ff6SDavid Woodhouse }; 661*25967ff6SDavid Woodhouse 662*25967ff6SDavid Woodhouse static void xen_net_register_backend(void) 663*25967ff6SDavid Woodhouse { 664*25967ff6SDavid Woodhouse xen_backend_register(&xen_net_backend_info); 665*25967ff6SDavid Woodhouse } 666*25967ff6SDavid Woodhouse 667*25967ff6SDavid Woodhouse xen_backend_init(xen_net_register_backend); 668