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