xref: /qemu/hw/net/xen_nic.c (revision 25967ff69f61461cedf3289d5dafd1f6980cc894)
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