+ vec_add1 (vif->tap_fds, tfd);
+ tap_log_dbg (vif, "open tap fd %d", tfd);
+
+ _IOCTL (tfd, TUNGETFEATURES, &tap_features);
+ tap_log_dbg (vif, "TUNGETFEATURES: features 0x%lx", tap_features);
+ if ((tap_features & IFF_VNET_HDR) == 0)
+ {
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+ args->error = clib_error_return (0, "vhost-net backend not available");
+ goto error;
+ }
+
+ if ((tap_features & IFF_MULTI_QUEUE) == 0)
+ {
+ if (vif->num_rxqs > 1)
+ {
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+ args->error = clib_error_return (0, "multiqueue not supported");
+ goto error;
+ }
+ vif->num_rxqs = vif->num_txqs = 1;
+ }
+ else
+ ifr.ifr_flags |= IFF_MULTI_QUEUE;
+
+ hdrsz = sizeof (virtio_net_hdr_v1_t);
+ if (args->tap_flags & TAP_FLAG_GSO)
+ {
+ offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
+ vif->gso_enabled = 1;
+ }
+ else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
+ {
+ offload = TUN_F_CSUM;
+ vif->csum_offload_enabled = 1;
+ }
+
+ _IOCTL (tfd, TUNSETIFF, (void *) &ifr);
+ tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", tfd,
+ ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
+
+ vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
+ tap_log_dbg (vif, "ifindex %d", vif->ifindex);
+
+ if (!args->host_if_name)
+ host_if_name = ifr.ifr_ifrn.ifrn_name;
+ else
+ host_if_name = (char *) args->host_if_name;
+
+ /*
+ * unset the persistence when attaching to existing
+ * interface
+ */
+ if (args->tap_flags & TAP_FLAG_ATTACH)
+ {
+ _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 0);
+ tap_log_dbg (vif, "TUNSETPERSIST: unset");
+ }
+
+ /* set the persistence */
+ if (args->tap_flags & TAP_FLAG_PERSIST)
+ {
+ _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 1);
+ tap_log_dbg (vif, "TUNSETPERSIST: set");
+
+ /* verify persistence is set, read the flags */
+ _IOCTL (tfd, TUNGETIFF, (void *) &get_ifr);
+ tap_log_dbg (vif, "TUNGETIFF: flags 0x%lx", get_ifr.ifr_flags);
+ if ((get_ifr.ifr_flags & IFF_PERSIST) == 0)
+ {
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+ args->error = clib_error_return (0, "persistence not supported");
+ goto error;
+ }
+ }
+
+ /* create additional queues on the linux side.
+ * we create as many linux queue pairs as we have rx queues
+ */
+ for (i = 1; i < vif->num_rxqs; i++)
+ {
+ if ((qfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
+ {
+ args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
+ args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
+ goto error;
+ }
+ _IOCTL (qfd, TUNSETIFF, (void *) &ifr);
+ tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", qfd,
+ ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
+ vec_add1 (vif->tap_fds, qfd);
+ }
+
+ for (i = 0; i < vif->num_rxqs; i++)
+ {
+ tap_log_dbg (vif, "TUNSETVNETHDRSZ: fd %d vnet_hdr_sz %u",
+ vif->tap_fds[i], hdrsz);
+ _IOCTL (vif->tap_fds[i], TUNSETVNETHDRSZ, &hdrsz);
+
+ tap_log_dbg (vif, "TUNSETSNDBUF: fd %d sndbuf %d", vif->tap_fds[i],
+ sndbuf);
+ _IOCTL (vif->tap_fds[i], TUNSETSNDBUF, &sndbuf);