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" 2325967ff6SDavid Woodhouse #include "qemu/main-loop.h" 2425967ff6SDavid Woodhouse #include "qemu/cutils.h" 2525967ff6SDavid Woodhouse #include "qemu/log.h" 2625967ff6SDavid Woodhouse #include "qemu/qemu-print.h" 27407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h" 2825967ff6SDavid Woodhouse #include "qapi/error.h" 2925967ff6SDavid 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" 3725967ff6SDavid Woodhouse 3825967ff6SDavid Woodhouse #include "hw/xen/xen-backend.h" 3925967ff6SDavid Woodhouse #include "hw/xen/xen-bus-helper.h" 4025967ff6SDavid Woodhouse #include "hw/qdev-properties.h" 4125967ff6SDavid Woodhouse #include "hw/qdev-properties-system.h" 42e613b064Saliguori 43a3434a2dSAnthony PERARD #include "hw/xen/interface/io/netif.h" 4425967ff6SDavid Woodhouse #include "hw/xen/interface/io/xs_wire.h" 4525967ff6SDavid Woodhouse 4625967ff6SDavid Woodhouse #include "trace.h" 47b41f6719SAnthony PERARD 48e613b064Saliguori /* ------------------------------------------------------------- */ 49e613b064Saliguori 50e613b064Saliguori struct XenNetDev { 5125967ff6SDavid Woodhouse struct XenDevice xendev; /* must be first */ 5225967ff6SDavid Woodhouse XenEventChannel *event_channel; 5325967ff6SDavid Woodhouse int dev; 54e613b064Saliguori int tx_work; 5525967ff6SDavid Woodhouse unsigned int tx_ring_ref; 5625967ff6SDavid 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 6525967ff6SDavid Woodhouse typedef struct XenNetDev XenNetDev; 6625967ff6SDavid Woodhouse 6725967ff6SDavid Woodhouse #define TYPE_XEN_NET_DEVICE "xen-net-device" 6825967ff6SDavid Woodhouse OBJECT_DECLARE_SIMPLE_TYPE(XenNetDev, XEN_NET_DEVICE) 6925967ff6SDavid 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) { 9125967ff6SDavid Woodhouse xen_device_notify_event_channel(XEN_DEVICE(netdev), 9225967ff6SDavid 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 12825967ff6SDavid Woodhouse static bool net_tx_packets(struct XenNetDev *netdev) 129e613b064Saliguori { 13025967ff6SDavid Woodhouse bool done_something = false; 131e613b064Saliguori netif_tx_request_t txreq; 132e613b064Saliguori RING_IDX rc, rp; 133e613b064Saliguori void *page; 134e613b064Saliguori void *tmpbuf = NULL; 135e613b064Saliguori 136195801d7SStefan Hajnoczi assert(bql_locked()); 13725967ff6SDavid 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; 14925967ff6SDavid 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) { 15525967ff6SDavid Woodhouse qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: extra info flag\n", 15625967ff6SDavid Woodhouse netdev->dev); 157e613b064Saliguori net_tx_error(netdev, &txreq, rc); 158e613b064Saliguori continue; 159e613b064Saliguori } 160e613b064Saliguori if (txreq.flags & NETTXF_more_data) { 16125967ff6SDavid Woodhouse qemu_log_mask(LOG_UNIMP, "vif%u: FIXME: more data flag\n", 16225967ff6SDavid Woodhouse netdev->dev); 163e613b064Saliguori net_tx_error(netdev, &txreq, rc); 164e613b064Saliguori continue; 165e613b064Saliguori } 166e613b064Saliguori #endif 167e613b064Saliguori 168e613b064Saliguori if (txreq.size < 14) { 16925967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: bad packet size: %d\n", 17025967ff6SDavid 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) { 17625967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: error: page crossing\n", 17725967ff6SDavid Woodhouse netdev->dev); 178e613b064Saliguori net_tx_error(netdev, &txreq, rc); 179e613b064Saliguori continue; 180e613b064Saliguori } 181e613b064Saliguori 18225967ff6SDavid Woodhouse trace_xen_netdev_tx(netdev->dev, txreq.gref, txreq.offset, 18325967ff6SDavid 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 18925967ff6SDavid Woodhouse page = xen_device_map_grant_refs(&netdev->xendev, &txreq.gref, 1, 19025967ff6SDavid Woodhouse PROT_READ, NULL); 191e613b064Saliguori if (page == NULL) { 19225967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, 19325967ff6SDavid Woodhouse "vif%u: tx gref dereference failed (%d)\n", 19425967ff6SDavid 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 } 21125967ff6SDavid Woodhouse xen_device_unmap_grant_refs(&netdev->xendev, page, &txreq.gref, 1, 21225967ff6SDavid 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); 22125967ff6SDavid 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 24425967ff6SDavid 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) { 24925967ff6SDavid Woodhouse xen_device_notify_event_channel(XEN_DEVICE(netdev), 25025967ff6SDavid 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 263195801d7SStefan Hajnoczi assert(bql_locked()); 26425967ff6SDavid Woodhouse 26525967ff6SDavid 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) { 27725967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, "vif%u: packet too big (%lu > %ld)", 27825967ff6SDavid Woodhouse netdev->dev, (unsigned long)size, 27925967ff6SDavid 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 28625967ff6SDavid Woodhouse page = xen_device_map_grant_refs(&netdev->xendev, &rxreq.gref, 1, 28725967ff6SDavid Woodhouse PROT_WRITE, NULL); 288e613b064Saliguori if (page == NULL) { 28925967ff6SDavid Woodhouse qemu_log_mask(LOG_GUEST_ERROR, 29025967ff6SDavid Woodhouse "vif%u: rx gref dereference failed (%d)\n", 29125967ff6SDavid 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); 29625967ff6SDavid 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 31025967ff6SDavid Woodhouse static void xen_netdev_realize(XenDevice *xendev, Error **errp) 311e613b064Saliguori { 31225967ff6SDavid Woodhouse ERRP_GUARD(); 31325967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 31425967ff6SDavid Woodhouse NetClientState *nc; 315e613b064Saliguori 31625967ff6SDavid Woodhouse qemu_macaddr_default_if_unset(&netdev->conf.macaddr); 317e613b064Saliguori 31825967ff6SDavid Woodhouse xen_device_frontend_printf(xendev, "mac", "%02x:%02x:%02x:%02x:%02x:%02x", 31925967ff6SDavid Woodhouse netdev->conf.macaddr.a[0], 32025967ff6SDavid Woodhouse netdev->conf.macaddr.a[1], 32125967ff6SDavid Woodhouse netdev->conf.macaddr.a[2], 32225967ff6SDavid Woodhouse netdev->conf.macaddr.a[3], 32325967ff6SDavid Woodhouse netdev->conf.macaddr.a[4], 32425967ff6SDavid Woodhouse netdev->conf.macaddr.a[5]); 325658788c5SMark McLoughlin 326658788c5SMark McLoughlin netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, 32725967ff6SDavid Woodhouse object_get_typename(OBJECT(xendev)), 3287d0fefdfSAkihiko Odaki DEVICE(xendev)->id, 3297d0fefdfSAkihiko Odaki &xendev->qdev.mem_reentrancy_guard, netdev); 330658788c5SMark McLoughlin 33125967ff6SDavid Woodhouse nc = qemu_get_queue(netdev->nic); 33225967ff6SDavid Woodhouse qemu_format_nic_info_str(nc, netdev->conf.macaddr.a); 333e613b064Saliguori 334e613b064Saliguori /* fill info */ 33525967ff6SDavid Woodhouse xen_device_backend_printf(xendev, "feature-rx-copy", "%u", 1); 33625967ff6SDavid Woodhouse xen_device_backend_printf(xendev, "feature-rx-flip", "%u", 0); 337e613b064Saliguori 33825967ff6SDavid Woodhouse trace_xen_netdev_realize(netdev->dev, nc->info_str, nc->peer ? 33925967ff6SDavid Woodhouse nc->peer->name : "(none)"); 340e613b064Saliguori } 341e613b064Saliguori 34225967ff6SDavid Woodhouse static bool net_event(void *_xendev) 343e613b064Saliguori { 34425967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(_xendev); 34525967ff6SDavid Woodhouse bool done_something; 346e613b064Saliguori 34725967ff6SDavid Woodhouse done_something = net_tx_packets(netdev); 34825967ff6SDavid Woodhouse qemu_flush_queued_packets(qemu_get_queue(netdev->nic)); 34925967ff6SDavid Woodhouse return done_something; 350209cd7abSAnthony PERARD } 351e613b064Saliguori 35225967ff6SDavid Woodhouse static bool xen_netdev_connect(XenDevice *xendev, Error **errp) 35325967ff6SDavid Woodhouse { 3548538ceecSZhao Liu ERRP_GUARD(); 35525967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 35625967ff6SDavid Woodhouse unsigned int port, rx_copy; 35725967ff6SDavid Woodhouse 358195801d7SStefan Hajnoczi assert(bql_locked()); 35925967ff6SDavid Woodhouse 36025967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "tx-ring-ref", "%u", 36125967ff6SDavid Woodhouse &netdev->tx_ring_ref) != 1) { 36225967ff6SDavid Woodhouse error_setg(errp, "failed to read tx-ring-ref"); 36325967ff6SDavid Woodhouse return false; 36425967ff6SDavid Woodhouse } 36525967ff6SDavid Woodhouse 36625967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "rx-ring-ref", "%u", 36725967ff6SDavid Woodhouse &netdev->rx_ring_ref) != 1) { 36825967ff6SDavid Woodhouse error_setg(errp, "failed to read rx-ring-ref"); 36925967ff6SDavid Woodhouse return false; 37025967ff6SDavid Woodhouse } 37125967ff6SDavid Woodhouse 37225967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "event-channel", "%u", 37325967ff6SDavid Woodhouse &port) != 1) { 37425967ff6SDavid Woodhouse error_setg(errp, "failed to read event-channel"); 37525967ff6SDavid Woodhouse return false; 37625967ff6SDavid Woodhouse } 37725967ff6SDavid Woodhouse 37825967ff6SDavid Woodhouse if (xen_device_frontend_scanf(xendev, "request-rx-copy", "%u", 37925967ff6SDavid Woodhouse &rx_copy) != 1) { 380e613b064Saliguori rx_copy = 0; 381209cd7abSAnthony PERARD } 382e613b064Saliguori if (rx_copy == 0) { 38325967ff6SDavid Woodhouse error_setg(errp, "frontend doesn't support rx-copy"); 38425967ff6SDavid Woodhouse return false; 385e613b064Saliguori } 386e613b064Saliguori 38725967ff6SDavid Woodhouse netdev->txs = xen_device_map_grant_refs(xendev, 38825967ff6SDavid Woodhouse &netdev->tx_ring_ref, 1, 38925967ff6SDavid Woodhouse PROT_READ | PROT_WRITE, 39025967ff6SDavid Woodhouse errp); 391b4f72e31SChen Gang if (!netdev->txs) { 39225967ff6SDavid Woodhouse error_prepend(errp, "failed to map tx grant ref: "); 39325967ff6SDavid Woodhouse return false; 394b4f72e31SChen Gang } 39525967ff6SDavid Woodhouse 39625967ff6SDavid Woodhouse netdev->rxs = xen_device_map_grant_refs(xendev, 39725967ff6SDavid Woodhouse &netdev->rx_ring_ref, 1, 39825967ff6SDavid Woodhouse PROT_READ | PROT_WRITE, 39925967ff6SDavid Woodhouse errp); 400b4f72e31SChen Gang if (!netdev->rxs) { 40125967ff6SDavid Woodhouse error_prepend(errp, "failed to map rx grant ref: "); 40225967ff6SDavid Woodhouse return false; 403209cd7abSAnthony PERARD } 40425967ff6SDavid Woodhouse 405a9ae1418SDavid Woodhouse BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE); 406a9ae1418SDavid Woodhouse BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE); 407e613b064Saliguori 40825967ff6SDavid Woodhouse netdev->event_channel = xen_device_bind_event_channel(xendev, port, 40925967ff6SDavid Woodhouse net_event, 41025967ff6SDavid Woodhouse netdev, 41125967ff6SDavid Woodhouse errp); 41225967ff6SDavid Woodhouse if (!netdev->event_channel) { 41325967ff6SDavid Woodhouse return false; 414e613b064Saliguori } 415e613b064Saliguori 41625967ff6SDavid Woodhouse trace_xen_netdev_connect(netdev->dev, netdev->tx_ring_ref, 41725967ff6SDavid Woodhouse netdev->rx_ring_ref, port); 41825967ff6SDavid Woodhouse 41925967ff6SDavid Woodhouse net_tx_packets(netdev); 42025967ff6SDavid Woodhouse return true; 42125967ff6SDavid Woodhouse } 42225967ff6SDavid Woodhouse 42325967ff6SDavid Woodhouse static void xen_netdev_disconnect(XenDevice *xendev, Error **errp) 424e613b064Saliguori { 42525967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 426e613b064Saliguori 42725967ff6SDavid Woodhouse trace_xen_netdev_disconnect(netdev->dev); 428e613b064Saliguori 429195801d7SStefan Hajnoczi assert(bql_locked()); 43025967ff6SDavid Woodhouse 43125967ff6SDavid Woodhouse netdev->tx_ring.sring = NULL; 43225967ff6SDavid Woodhouse netdev->rx_ring.sring = NULL; 43325967ff6SDavid Woodhouse 43425967ff6SDavid Woodhouse if (netdev->event_channel) { 43525967ff6SDavid Woodhouse xen_device_unbind_event_channel(xendev, netdev->event_channel, 43625967ff6SDavid Woodhouse errp); 43725967ff6SDavid Woodhouse netdev->event_channel = NULL; 43825967ff6SDavid Woodhouse } 439e613b064Saliguori if (netdev->txs) { 44025967ff6SDavid Woodhouse xen_device_unmap_grant_refs(xendev, netdev->txs, 44125967ff6SDavid Woodhouse &netdev->tx_ring_ref, 1, errp); 442e613b064Saliguori netdev->txs = NULL; 443e613b064Saliguori } 444e613b064Saliguori if (netdev->rxs) { 44525967ff6SDavid Woodhouse xen_device_unmap_grant_refs(xendev, netdev->rxs, 44625967ff6SDavid Woodhouse &netdev->rx_ring_ref, 1, errp); 447e613b064Saliguori netdev->rxs = NULL; 448e613b064Saliguori } 449e613b064Saliguori } 450e613b064Saliguori 45125967ff6SDavid Woodhouse /* -------------------------------------------------------------------- */ 45225967ff6SDavid Woodhouse 45325967ff6SDavid Woodhouse 45425967ff6SDavid Woodhouse static void xen_netdev_frontend_changed(XenDevice *xendev, 45525967ff6SDavid Woodhouse enum xenbus_state frontend_state, 45625967ff6SDavid Woodhouse Error **errp) 457e613b064Saliguori { 45825967ff6SDavid Woodhouse ERRP_GUARD(); 45925967ff6SDavid Woodhouse enum xenbus_state backend_state = xen_device_backend_get_state(xendev); 46025967ff6SDavid Woodhouse 46125967ff6SDavid Woodhouse trace_xen_netdev_frontend_changed(xendev->name, frontend_state); 46225967ff6SDavid Woodhouse 46325967ff6SDavid Woodhouse switch (frontend_state) { 46425967ff6SDavid Woodhouse case XenbusStateConnected: 46525967ff6SDavid Woodhouse if (backend_state == XenbusStateConnected) { 46625967ff6SDavid Woodhouse break; 467e613b064Saliguori } 468e613b064Saliguori 46925967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, errp); 47025967ff6SDavid Woodhouse if (*errp) { 47125967ff6SDavid Woodhouse break; 47225967ff6SDavid Woodhouse } 47325967ff6SDavid Woodhouse 47425967ff6SDavid Woodhouse if (!xen_netdev_connect(xendev, errp)) { 47525967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, NULL); 47625967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosing); 47725967ff6SDavid Woodhouse break; 47825967ff6SDavid Woodhouse } 47925967ff6SDavid Woodhouse 48025967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateConnected); 48125967ff6SDavid Woodhouse break; 48225967ff6SDavid Woodhouse 48325967ff6SDavid Woodhouse case XenbusStateClosing: 48425967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosing); 48525967ff6SDavid Woodhouse break; 48625967ff6SDavid Woodhouse 48725967ff6SDavid Woodhouse case XenbusStateClosed: 48825967ff6SDavid Woodhouse case XenbusStateUnknown: 48925967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, errp); 49025967ff6SDavid Woodhouse if (*errp) { 49125967ff6SDavid Woodhouse break; 49225967ff6SDavid Woodhouse } 49325967ff6SDavid Woodhouse 49425967ff6SDavid Woodhouse xen_device_backend_set_state(xendev, XenbusStateClosed); 49525967ff6SDavid Woodhouse break; 49625967ff6SDavid Woodhouse 49725967ff6SDavid Woodhouse case XenbusStateInitialised: 49825967ff6SDavid Woodhouse /* 49925967ff6SDavid Woodhouse * Linux netback does nothing on the frontend going (back) to 50025967ff6SDavid Woodhouse * XenbusStateInitialised, so do the same here. 50125967ff6SDavid Woodhouse */ 50225967ff6SDavid Woodhouse default: 50325967ff6SDavid Woodhouse break; 50425967ff6SDavid Woodhouse } 50525967ff6SDavid Woodhouse } 50625967ff6SDavid Woodhouse 50725967ff6SDavid Woodhouse static char *xen_netdev_get_name(XenDevice *xendev, Error **errp) 508e613b064Saliguori { 50925967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 51025967ff6SDavid Woodhouse 51125967ff6SDavid Woodhouse if (netdev->dev == -1) { 51225967ff6SDavid Woodhouse XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 51325967ff6SDavid Woodhouse int idx = (xen_mode == XEN_EMULATE) ? 0 : 1; 514e4e113ecSDavid Woodhouse Error *local_err = NULL; 51525967ff6SDavid Woodhouse char *value; 51625967ff6SDavid Woodhouse 51725967ff6SDavid Woodhouse /* Theoretically we could go up to INT_MAX here but that's overkill */ 51825967ff6SDavid Woodhouse while (idx < 100) { 519e4e113ecSDavid Woodhouse value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err, 52025967ff6SDavid Woodhouse "/local/domain/%u/device/vif/%u", 52125967ff6SDavid Woodhouse xendev->frontend_id, idx); 52225967ff6SDavid Woodhouse if (!value) { 52325967ff6SDavid Woodhouse if (errno == ENOENT) { 52425967ff6SDavid Woodhouse netdev->dev = idx; 525e4e113ecSDavid Woodhouse error_free(local_err); 52625967ff6SDavid Woodhouse goto found; 52725967ff6SDavid Woodhouse } 528e4e113ecSDavid Woodhouse error_propagate(errp, local_err); 52925967ff6SDavid Woodhouse return NULL; 53025967ff6SDavid Woodhouse } 53125967ff6SDavid Woodhouse free(value); 53225967ff6SDavid Woodhouse idx++; 53325967ff6SDavid Woodhouse } 53425967ff6SDavid Woodhouse error_setg(errp, "cannot find device index for netdev device"); 53525967ff6SDavid Woodhouse return NULL; 53625967ff6SDavid Woodhouse } 53725967ff6SDavid Woodhouse found: 53825967ff6SDavid Woodhouse return g_strdup_printf("%u", netdev->dev); 53925967ff6SDavid Woodhouse } 54025967ff6SDavid Woodhouse 54125967ff6SDavid Woodhouse static void xen_netdev_unrealize(XenDevice *xendev) 54225967ff6SDavid Woodhouse { 54325967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 54425967ff6SDavid Woodhouse 54525967ff6SDavid Woodhouse trace_xen_netdev_unrealize(netdev->dev); 54625967ff6SDavid Woodhouse 54725967ff6SDavid Woodhouse /* Disconnect from the frontend in case this has not already happened */ 54825967ff6SDavid Woodhouse xen_netdev_disconnect(xendev, NULL); 549e613b064Saliguori 550d4685837SChen Gang if (netdev->nic) { 551d4685837SChen Gang qemu_del_nic(netdev->nic); 552d4685837SChen Gang } 553e613b064Saliguori } 554e613b064Saliguori 555e613b064Saliguori /* ------------------------------------------------------------- */ 556e613b064Saliguori 557e732f00fSRichard Henderson static const Property xen_netdev_properties[] = { 55825967ff6SDavid Woodhouse DEFINE_NIC_PROPERTIES(XenNetDev, conf), 55925967ff6SDavid Woodhouse DEFINE_PROP_INT32("idx", XenNetDev, dev, -1), 560e613b064Saliguori }; 56125967ff6SDavid Woodhouse 562*12d1a768SPhilippe Mathieu-Daudé static void xen_netdev_class_init(ObjectClass *class, const void *data) 56325967ff6SDavid Woodhouse { 56425967ff6SDavid Woodhouse DeviceClass *dev_class = DEVICE_CLASS(class); 56525967ff6SDavid Woodhouse XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); 56625967ff6SDavid Woodhouse 56725967ff6SDavid Woodhouse xendev_class->backend = "qnic"; 56825967ff6SDavid Woodhouse xendev_class->device = "vif"; 56925967ff6SDavid Woodhouse xendev_class->get_name = xen_netdev_get_name; 57025967ff6SDavid Woodhouse xendev_class->realize = xen_netdev_realize; 57125967ff6SDavid Woodhouse xendev_class->frontend_changed = xen_netdev_frontend_changed; 57225967ff6SDavid Woodhouse xendev_class->unrealize = xen_netdev_unrealize; 57325967ff6SDavid Woodhouse set_bit(DEVICE_CATEGORY_NETWORK, dev_class->categories); 57425967ff6SDavid Woodhouse dev_class->user_creatable = true; 57525967ff6SDavid Woodhouse 57625967ff6SDavid Woodhouse device_class_set_props(dev_class, xen_netdev_properties); 57725967ff6SDavid Woodhouse } 57825967ff6SDavid Woodhouse 57925967ff6SDavid Woodhouse static const TypeInfo xen_net_type_info = { 58025967ff6SDavid Woodhouse .name = TYPE_XEN_NET_DEVICE, 58125967ff6SDavid Woodhouse .parent = TYPE_XEN_DEVICE, 58225967ff6SDavid Woodhouse .instance_size = sizeof(XenNetDev), 58325967ff6SDavid Woodhouse .class_init = xen_netdev_class_init, 58425967ff6SDavid Woodhouse }; 58525967ff6SDavid Woodhouse 58625967ff6SDavid Woodhouse static void xen_net_register_types(void) 58725967ff6SDavid Woodhouse { 58825967ff6SDavid Woodhouse type_register_static(&xen_net_type_info); 58925967ff6SDavid Woodhouse } 59025967ff6SDavid Woodhouse 59125967ff6SDavid Woodhouse type_init(xen_net_register_types) 59225967ff6SDavid Woodhouse 59325967ff6SDavid Woodhouse /* Called to instantiate a XenNetDev when the backend is detected. */ 59425967ff6SDavid Woodhouse static void xen_net_device_create(XenBackendInstance *backend, 59525967ff6SDavid Woodhouse QDict *opts, Error **errp) 59625967ff6SDavid Woodhouse { 59725967ff6SDavid Woodhouse ERRP_GUARD(); 59825967ff6SDavid Woodhouse XenBus *xenbus = xen_backend_get_bus(backend); 59925967ff6SDavid Woodhouse const char *name = xen_backend_get_name(backend); 60025967ff6SDavid Woodhouse XenDevice *xendev = NULL; 60125967ff6SDavid Woodhouse unsigned long number; 60225967ff6SDavid Woodhouse const char *macstr; 60325967ff6SDavid Woodhouse XenNetDev *net; 60425967ff6SDavid Woodhouse MACAddr mac; 60525967ff6SDavid Woodhouse 60625967ff6SDavid Woodhouse if (qemu_strtoul(name, NULL, 10, &number) || number >= INT_MAX) { 60725967ff6SDavid Woodhouse error_setg(errp, "failed to parse name '%s'", name); 60825967ff6SDavid Woodhouse goto fail; 60925967ff6SDavid Woodhouse } 61025967ff6SDavid Woodhouse 61125967ff6SDavid Woodhouse trace_xen_netdev_create(number); 61225967ff6SDavid Woodhouse 61325967ff6SDavid Woodhouse macstr = qdict_get_try_str(opts, "mac"); 61425967ff6SDavid Woodhouse if (macstr == NULL) { 61525967ff6SDavid Woodhouse error_setg(errp, "no MAC address found"); 61625967ff6SDavid Woodhouse goto fail; 61725967ff6SDavid Woodhouse } 61825967ff6SDavid Woodhouse 61925967ff6SDavid Woodhouse if (net_parse_macaddr(mac.a, macstr) < 0) { 62025967ff6SDavid Woodhouse error_setg(errp, "failed to parse MAC address"); 62125967ff6SDavid Woodhouse goto fail; 62225967ff6SDavid Woodhouse } 62325967ff6SDavid Woodhouse 62425967ff6SDavid Woodhouse xendev = XEN_DEVICE(qdev_new(TYPE_XEN_NET_DEVICE)); 62525967ff6SDavid Woodhouse net = XEN_NET_DEVICE(xendev); 62625967ff6SDavid Woodhouse 62725967ff6SDavid Woodhouse net->dev = number; 62825967ff6SDavid Woodhouse memcpy(&net->conf.macaddr, &mac, sizeof(mac)); 62925967ff6SDavid Woodhouse 63025967ff6SDavid Woodhouse if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) { 63125967ff6SDavid Woodhouse xen_backend_set_device(backend, xendev); 63225967ff6SDavid Woodhouse return; 63325967ff6SDavid Woodhouse } 63425967ff6SDavid Woodhouse 63525967ff6SDavid Woodhouse error_prepend(errp, "realization of net device %lu failed: ", 63625967ff6SDavid Woodhouse number); 63725967ff6SDavid Woodhouse 63825967ff6SDavid Woodhouse fail: 63925967ff6SDavid Woodhouse if (xendev) { 64025967ff6SDavid Woodhouse object_unparent(OBJECT(xendev)); 64125967ff6SDavid Woodhouse } 64225967ff6SDavid Woodhouse } 64325967ff6SDavid Woodhouse 64425967ff6SDavid Woodhouse static void xen_net_device_destroy(XenBackendInstance *backend, 64525967ff6SDavid Woodhouse Error **errp) 64625967ff6SDavid Woodhouse { 64725967ff6SDavid Woodhouse ERRP_GUARD(); 64825967ff6SDavid Woodhouse XenDevice *xendev = xen_backend_get_device(backend); 64925967ff6SDavid Woodhouse XenNetDev *netdev = XEN_NET_DEVICE(xendev); 65025967ff6SDavid Woodhouse 65125967ff6SDavid Woodhouse trace_xen_netdev_destroy(netdev->dev); 65225967ff6SDavid Woodhouse 65325967ff6SDavid Woodhouse object_unparent(OBJECT(xendev)); 65425967ff6SDavid Woodhouse } 65525967ff6SDavid Woodhouse 65625967ff6SDavid Woodhouse static const XenBackendInfo xen_net_backend_info = { 65725967ff6SDavid Woodhouse .type = "qnic", 65825967ff6SDavid Woodhouse .create = xen_net_device_create, 65925967ff6SDavid Woodhouse .destroy = xen_net_device_destroy, 66025967ff6SDavid Woodhouse }; 66125967ff6SDavid Woodhouse 66225967ff6SDavid Woodhouse static void xen_net_register_backend(void) 66325967ff6SDavid Woodhouse { 66425967ff6SDavid Woodhouse xen_backend_register(&xen_net_backend_info); 66525967ff6SDavid Woodhouse } 66625967ff6SDavid Woodhouse 66725967ff6SDavid Woodhouse xen_backend_init(xen_net_register_backend); 668