func: int net_init_tap(const Netdev *netdev, const char *name,
  
                   NetClientState *peer, Error **errp)
  
  {
  
      const NetdevTapOptions *tap;
  
      int fd, vnet_hdr = 0, i = 0, queues;
  
      /* for the no-fd, no-helper case */
  
      const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */
  
      const char *downscript = NULL;
  
      Error *err = NULL;
  
      const char *vhostfdname;
  
      char ifname[128];
  
  
  
      assert(netdev->type == NET_CLIENT_DRIVER_TAP);
  
      tap = &netdev->u.tap;
  
      queues = tap->has_queues ? tap->queues : 1;
  
      vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
  
  
  
      /* QEMU vlans does not support multiqueue tap, in this case peer is set.
  
       * For -netdev, peer is always NULL. */
  
      if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
  
          error_setg(errp, "Multiqueue tap cannot be used with QEMU vlans");
  
          return -1;
  
      }
  
  
  
      if (tap->has_fd) {
  
          if (tap->has_ifname || tap->has_script || tap->has_downscript ||
  
              tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
  
              tap->has_fds || tap->has_vhostfds) {
  
              error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
  
                         "helper=, queues=, fds=, and vhostfds= "
  
                         "are invalid with fd=");
  
              return -1;
  
          }
  
  
  
          fd = monitor_fd_param(cur_mon, tap->fd, &err);
  
          if (fd == -1) {
  
              error_propagate(errp, err);
  
              return -1;
  
          }
  
  
  
          fcntl(fd, F_SETFL, O_NONBLOCK);
  
  
  
          vnet_hdr = tap_probe_vnet_hdr(fd);
  
  
  
          net_init_tap_one(tap, peer, "tap", name, NULL,
  
                           script, downscript,
  
                           vhostfdname, vnet_hdr, fd, &err);
  
          if (err) {
  
              error_propagate(errp, err);
  
              return -1;
  
          }
  
      } else if (tap->has_fds) {
  
          char **fds = g_new0(char *, MAX_TAP_QUEUES);
  
          char **vhost_fds = g_new0(char *, MAX_TAP_QUEUES);
  
          int nfds, nvhosts;
  
  
  
          if (tap->has_ifname || tap->has_script || tap->has_downscript ||
  
              tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
  
              tap->has_vhostfd) {
  
              error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
  
                         "helper=, queues=, and vhostfd= "
  
                         "are invalid with fds=");
  
              return -1;
  
          }
  
  
  
          nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
  
          if (tap->has_vhostfds) {
  
              nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
  
              if (nfds != nvhosts) {
  
                  error_setg(errp, "The number of fds passed does not match "
  
                             "the number of vhostfds passed");
  
                  goto free_fail;
  
              }
  
          }
  
  
  
          for (i = 0; i < nfds; i++) {
  
              fd = monitor_fd_param(cur_mon, fds[i], &err);
  
              if (fd == -1) {
  
                  error_propagate(errp, err);
  
                  goto free_fail;
  
              }
  
  
  
              fcntl(fd, F_SETFL, O_NONBLOCK);
  
  
  
              if (i == 0) {
  
                  vnet_hdr = tap_probe_vnet_hdr(fd);
  
              } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) {
  
                  error_setg(errp,
  
                             "vnet_hdr not consistent across given tap fds");
  
                  goto free_fail;
  
              }
  
  
  
              net_init_tap_one(tap, peer, "tap", name, ifname,
  
                               script, downscript,
  
                               tap->has_vhostfds ? vhost_fds[i] : NULL,
  
                               vnet_hdr, fd, &err);
  
              if (err) {
  
                  error_propagate(errp, err);
  
                  goto free_fail;
  
              }
  
          }
  
          g_free(fds);
  
          g_free(vhost_fds);
  
          return 0;
  
  
  
  free_fail:
  
          for (i = 0; i < nfds; i++) {
  
              g_free(fds[i]);
  
              g_free(vhost_fds[i]);
  
          }
  
          g_free(fds);
  
          g_free(vhost_fds);
  
          return -1;
  
      } else if (tap->has_helper) {
  
          if (tap->has_ifname || tap->has_script || tap->has_downscript ||
  
              tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) {
  
              error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
  
                         "queues=, and vhostfds= are invalid with helper=");
  
              return -1;
  
          }
  
  
  
          fd = net_bridge_run_helper(tap->helper,
  
                                     tap->has_br ?
  
                                     tap->br : DEFAULT_BRIDGE_INTERFACE,
  
                                     errp);
  
          if (fd == -1) {
  
              return -1;
  
          }
  
  
  
          fcntl(fd, F_SETFL, O_NONBLOCK);
  
          vnet_hdr = tap_probe_vnet_hdr(fd);
  
  
  
          net_init_tap_one(tap, peer, "bridge", name, ifname,
  
                           script, downscript, vhostfdname,
  
                           vnet_hdr, fd, &err);
  
          if (err) {
  
              error_propagate(errp, err);
  
              close(fd);
  
              return -1;
  
          }
  
      } else {
  
          if (tap->has_vhostfds) {
  
              error_setg(errp, "vhostfds= is invalid if fds= wasn't specified");
  
              return -1;
  
          }
  
          script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT;
  
          downscript = tap->has_downscript ? tap->downscript :
  
              DEFAULT_NETWORK_DOWN_SCRIPT;
  
  
  
          if (tap->has_ifname) {
  
              pstrcpy(ifname, sizeof ifname, tap->ifname);
  
          } else {
  
              ifname[0] = '\0';
  
          }
  
  
  
          for (i = 0; i < queues; i++) {
  
              fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script,
  
                                ifname, sizeof ifname, queues > 1, errp);
  
              if (fd == -1) {
  
                  return -1;
  
              }
  
  
  
              if (queues > 1 && i == 0 && !tap->has_ifname) {
  
                  if (tap_fd_get_ifname(fd, ifname)) {
  
                      error_setg(errp, "Fail to get ifname");
  
                      close(fd);
  
                      return -1;
  
                  }
  
              }
  
  
  
              net_init_tap_one(tap, peer, "tap", name, ifname,
  
                               i >= 1 ? "no" : script,
  
                               i >= 1 ? "no" : downscript,
  
                               vhostfdname, vnet_hdr, fd, &err);
  
              if (err) {
  
                  error_propagate(errp, err);
  
                  close(fd);
  
                  return -1;
  
              }
  
          }
  
      }
  
  
  
      return 0;
  
  }
  