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"
OBJECT_DECLARE_SIMPLE_TYPE(XenNetDev,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
net_tx_error(struct XenNetDev * netdev,netif_tx_request_t * txp,RING_IDX end)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
net_tx_packets(struct XenNetDev * netdev)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
net_rx_response(struct XenNetDev * netdev,netif_rx_request_t * req,int8_t st,uint16_t offset,uint16_t size,uint16_t flags)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
net_rx_packet(NetClientState * nc,const uint8_t * buf,size_t size)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
xen_netdev_realize(XenDevice * xendev,Error ** errp)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
net_event(void * _xendev)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
xen_netdev_connect(XenDevice * xendev,Error ** errp)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
xen_netdev_disconnect(XenDevice * xendev,Error ** errp)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
xen_netdev_frontend_changed(XenDevice * xendev,enum xenbus_state frontend_state,Error ** errp)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
xen_netdev_get_name(XenDevice * xendev,Error ** errp)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
xen_netdev_unrealize(XenDevice * xendev)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
xen_netdev_class_init(ObjectClass * class,const void * data)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
xen_net_register_types(void)58625967ff6SDavid Woodhouse static void xen_net_register_types(void)
58725967ff6SDavid Woodhouse {
58825967ff6SDavid Woodhouse type_register_static(&xen_net_type_info);
58925967ff6SDavid Woodhouse }
59025967ff6SDavid Woodhouse
type_init(xen_net_register_types)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
xen_net_device_destroy(XenBackendInstance * backend,Error ** errp)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
xen_net_register_backend(void)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