xref: /openbmc/qemu/hw/net/xen_nic.c (revision f0dbe427ec7c0dd81fc95c1d0d7174b79b6e6587)
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(qemu_mutex_iothread_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(qemu_mutex_iothread_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, netdev);
329  
330      nc = qemu_get_queue(netdev->nic);
331      qemu_format_nic_info_str(nc, netdev->conf.macaddr.a);
332  
333      /* fill info */
334      xen_device_backend_printf(xendev, "feature-rx-copy", "%u", 1);
335      xen_device_backend_printf(xendev, "feature-rx-flip", "%u", 0);
336  
337      trace_xen_netdev_realize(netdev->dev, nc->info_str, nc->peer ?
338                               nc->peer->name : "(none)");
339  }
340  
341  static bool net_event(void *_xendev)
342  {
343      XenNetDev *netdev = XEN_NET_DEVICE(_xendev);
344      bool done_something;
345  
346      done_something = net_tx_packets(netdev);
347      qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
348      return done_something;
349  }
350  
351  static bool xen_netdev_connect(XenDevice *xendev, Error **errp)
352  {
353      XenNetDev *netdev = XEN_NET_DEVICE(xendev);
354      unsigned int port, rx_copy;
355  
356      assert(qemu_mutex_iothread_locked());
357  
358      if (xen_device_frontend_scanf(xendev, "tx-ring-ref", "%u",
359                                    &netdev->tx_ring_ref) != 1) {
360          error_setg(errp, "failed to read tx-ring-ref");
361          return false;
362      }
363  
364      if (xen_device_frontend_scanf(xendev, "rx-ring-ref", "%u",
365                                    &netdev->rx_ring_ref) != 1) {
366          error_setg(errp, "failed to read rx-ring-ref");
367          return false;
368      }
369  
370      if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
371                                    &port) != 1) {
372          error_setg(errp, "failed to read event-channel");
373          return false;
374      }
375  
376      if (xen_device_frontend_scanf(xendev, "request-rx-copy", "%u",
377                                    &rx_copy) != 1) {
378          rx_copy = 0;
379      }
380      if (rx_copy == 0) {
381          error_setg(errp, "frontend doesn't support rx-copy");
382          return false;
383      }
384  
385      netdev->txs = xen_device_map_grant_refs(xendev,
386                                              &netdev->tx_ring_ref, 1,
387                                              PROT_READ | PROT_WRITE,
388                                              errp);
389      if (!netdev->txs) {
390          error_prepend(errp, "failed to map tx grant ref: ");
391          return false;
392      }
393  
394      netdev->rxs = xen_device_map_grant_refs(xendev,
395                                              &netdev->rx_ring_ref, 1,
396                                              PROT_READ | PROT_WRITE,
397                                              errp);
398      if (!netdev->rxs) {
399          error_prepend(errp, "failed to map rx grant ref: ");
400          return false;
401      }
402  
403      BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE);
404      BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE);
405  
406      netdev->event_channel = xen_device_bind_event_channel(xendev, port,
407                                                            net_event,
408                                                            netdev,
409                                                            errp);
410      if (!netdev->event_channel) {
411          return false;
412      }
413  
414      trace_xen_netdev_connect(netdev->dev, netdev->tx_ring_ref,
415                               netdev->rx_ring_ref, port);
416  
417      net_tx_packets(netdev);
418      return true;
419  }
420  
421  static void xen_netdev_disconnect(XenDevice *xendev, Error **errp)
422  {
423      XenNetDev *netdev = XEN_NET_DEVICE(xendev);
424  
425      trace_xen_netdev_disconnect(netdev->dev);
426  
427      assert(qemu_mutex_iothread_locked());
428  
429      netdev->tx_ring.sring = NULL;
430      netdev->rx_ring.sring = NULL;
431  
432      if (netdev->event_channel) {
433          xen_device_unbind_event_channel(xendev, netdev->event_channel,
434                                          errp);
435          netdev->event_channel = NULL;
436      }
437      if (netdev->txs) {
438          xen_device_unmap_grant_refs(xendev, netdev->txs,
439                                      &netdev->tx_ring_ref, 1, errp);
440          netdev->txs = NULL;
441      }
442      if (netdev->rxs) {
443          xen_device_unmap_grant_refs(xendev, netdev->rxs,
444                                      &netdev->rx_ring_ref, 1, errp);
445          netdev->rxs = NULL;
446      }
447  }
448  
449  /* -------------------------------------------------------------------- */
450  
451  
452  static void xen_netdev_frontend_changed(XenDevice *xendev,
453                                         enum xenbus_state frontend_state,
454                                         Error **errp)
455  {
456      ERRP_GUARD();
457      enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
458  
459      trace_xen_netdev_frontend_changed(xendev->name, frontend_state);
460  
461      switch (frontend_state) {
462      case XenbusStateConnected:
463          if (backend_state == XenbusStateConnected) {
464              break;
465          }
466  
467          xen_netdev_disconnect(xendev, errp);
468          if (*errp) {
469              break;
470          }
471  
472          if (!xen_netdev_connect(xendev, errp)) {
473              xen_netdev_disconnect(xendev, NULL);
474              xen_device_backend_set_state(xendev, XenbusStateClosing);
475              break;
476          }
477  
478          xen_device_backend_set_state(xendev, XenbusStateConnected);
479          break;
480  
481      case XenbusStateClosing:
482          xen_device_backend_set_state(xendev, XenbusStateClosing);
483          break;
484  
485      case XenbusStateClosed:
486      case XenbusStateUnknown:
487          xen_netdev_disconnect(xendev, errp);
488          if (*errp) {
489              break;
490          }
491  
492          xen_device_backend_set_state(xendev, XenbusStateClosed);
493          break;
494  
495      case XenbusStateInitialised:
496          /*
497           * Linux netback does nothing on the frontend going (back) to
498           * XenbusStateInitialised, so do the same here.
499           */
500      default:
501          break;
502      }
503  }
504  
505  static char *xen_netdev_get_name(XenDevice *xendev, Error **errp)
506  {
507      XenNetDev *netdev = XEN_NET_DEVICE(xendev);
508  
509      if (netdev->dev == -1) {
510          XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
511          char fe_path[XENSTORE_ABS_PATH_MAX + 1];
512          int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
513          char *value;
514  
515          /* Theoretically we could go up to INT_MAX here but that's overkill */
516          while (idx < 100) {
517              snprintf(fe_path, sizeof(fe_path),
518                       "/local/domain/%u/device/vif/%u",
519                       xendev->frontend_id, idx);
520              value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
521              if (!value) {
522                  if (errno == ENOENT) {
523                      netdev->dev = idx;
524                      goto found;
525                  }
526                  error_setg(errp, "cannot read %s: %s", fe_path,
527                             strerror(errno));
528                  return NULL;
529              }
530              free(value);
531              idx++;
532          }
533          error_setg(errp, "cannot find device index for netdev device");
534          return NULL;
535      }
536   found:
537      return g_strdup_printf("%u", netdev->dev);
538  }
539  
540  static void xen_netdev_unrealize(XenDevice *xendev)
541  {
542      XenNetDev *netdev = XEN_NET_DEVICE(xendev);
543  
544      trace_xen_netdev_unrealize(netdev->dev);
545  
546      /* Disconnect from the frontend in case this has not already happened */
547      xen_netdev_disconnect(xendev, NULL);
548  
549      if (netdev->nic) {
550          qemu_del_nic(netdev->nic);
551      }
552  }
553  
554  /* ------------------------------------------------------------- */
555  
556  static Property xen_netdev_properties[] = {
557      DEFINE_NIC_PROPERTIES(XenNetDev, conf),
558      DEFINE_PROP_INT32("idx", XenNetDev, dev, -1),
559      DEFINE_PROP_END_OF_LIST(),
560  };
561  
562  static void xen_netdev_class_init(ObjectClass *class, void *data)
563  {
564      DeviceClass *dev_class = DEVICE_CLASS(class);
565      XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
566  
567      xendev_class->backend = "qnic";
568      xendev_class->device = "vif";
569      xendev_class->get_name = xen_netdev_get_name;
570      xendev_class->realize = xen_netdev_realize;
571      xendev_class->frontend_changed = xen_netdev_frontend_changed;
572      xendev_class->unrealize = xen_netdev_unrealize;
573      set_bit(DEVICE_CATEGORY_NETWORK, dev_class->categories);
574      dev_class->user_creatable = true;
575  
576      device_class_set_props(dev_class, xen_netdev_properties);
577  }
578  
579  static const TypeInfo xen_net_type_info = {
580      .name = TYPE_XEN_NET_DEVICE,
581      .parent = TYPE_XEN_DEVICE,
582      .instance_size = sizeof(XenNetDev),
583      .class_init = xen_netdev_class_init,
584  };
585  
586  static void xen_net_register_types(void)
587  {
588      type_register_static(&xen_net_type_info);
589  }
590  
591  type_init(xen_net_register_types)
592  
593  /* Called to instantiate a XenNetDev when the backend is detected. */
594  static void xen_net_device_create(XenBackendInstance *backend,
595                                    QDict *opts, Error **errp)
596  {
597      ERRP_GUARD();
598      XenBus *xenbus = xen_backend_get_bus(backend);
599      const char *name = xen_backend_get_name(backend);
600      XenDevice *xendev = NULL;
601      unsigned long number;
602      const char *macstr;
603      XenNetDev *net;
604      MACAddr mac;
605  
606      if (qemu_strtoul(name, NULL, 10, &number) || number >= INT_MAX) {
607          error_setg(errp, "failed to parse name '%s'", name);
608          goto fail;
609      }
610  
611      trace_xen_netdev_create(number);
612  
613      macstr = qdict_get_try_str(opts, "mac");
614      if (macstr == NULL) {
615          error_setg(errp, "no MAC address found");
616          goto fail;
617      }
618  
619      if (net_parse_macaddr(mac.a, macstr) < 0) {
620          error_setg(errp, "failed to parse MAC address");
621          goto fail;
622      }
623  
624      xendev = XEN_DEVICE(qdev_new(TYPE_XEN_NET_DEVICE));
625      net = XEN_NET_DEVICE(xendev);
626  
627      net->dev = number;
628      memcpy(&net->conf.macaddr, &mac, sizeof(mac));
629  
630      if (qdev_realize_and_unref(DEVICE(xendev), BUS(xenbus), errp)) {
631          xen_backend_set_device(backend, xendev);
632          return;
633      }
634  
635      error_prepend(errp, "realization of net device %lu failed: ",
636                    number);
637  
638   fail:
639      if (xendev) {
640          object_unparent(OBJECT(xendev));
641      }
642  }
643  
644  static void xen_net_device_destroy(XenBackendInstance *backend,
645                                     Error **errp)
646  {
647      ERRP_GUARD();
648      XenDevice *xendev = xen_backend_get_device(backend);
649      XenNetDev *netdev = XEN_NET_DEVICE(xendev);
650  
651      trace_xen_netdev_destroy(netdev->dev);
652  
653      object_unparent(OBJECT(xendev));
654  }
655  
656  static const XenBackendInfo xen_net_backend_info  = {
657      .type = "qnic",
658      .create = xen_net_device_create,
659      .destroy = xen_net_device_destroy,
660  };
661  
662  static void xen_net_register_backend(void)
663  {
664      xen_backend_register(&xen_net_backend_info);
665  }
666  
667  xen_backend_init(xen_net_register_backend);
668