Index: usr.sbin/bhyve/net_backends.c =================================================================== --- usr.sbin/bhyve/net_backends.c +++ usr.sbin/bhyve/net_backends.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #define NETMAP_WITH_LIBS @@ -158,14 +159,97 @@ #define WPRINTF(params) printf params +/* + * The virtio-net features supported by the tap and netmap + * backends. + */ +#define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \ + VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \ + VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \ + VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO | \ + VIRTIO_NET_F_MRG_RXBUF) +#define TAP_FEATURES NETMAP_FEATURES + /* * The tap backend */ struct tap_priv { + char ifname[IFNAMSIZ]; struct mevent *mevp; }; +#define TAP_VHDR_IFCAPS (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 \ + | IFCAP_VLAN_HWCSUM | IFCAP_TSO \ + | IFCAP_LRO | IFCAP_VLAN_HWTSO) + +static int +tap_set_vnet_hdr_len(struct net_backend *be, unsigned vnet_hdr_len) +{ + struct tap_priv *priv = (struct tap_priv *)be->opaque; + int ival = vnet_hdr_len; + struct ifreq ifreq; + int ret; + int s; + + /* + * Configure the virtio-net header length, using the tap(4) character + * device interface. + */ + ret = ioctl(be->fd, TAPSVNETHDR, &ival); + if (ret) { + WPRINTF(("ioctl(TAPSVNETHDR) failed: %s\n", + strerror(errno))); + return (ret); + } + + /* + * Open a socket to run ioctl() commands on the tap(4) network + * interface. + */ + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s < 0) { + WPRINTF(("socket(AF_LOCAL) failed: %s\n", strerror(errno))); + return (s); + } + + /* + * Get interface capabilities: enabled capabilities are stored + * in ifreq.ifr_curcap, while supported ones are stored in + * ifreq.ifr_reqcap. + */ + memset(&ifreq, 0, sizeof(ifreq)); + strlcpy(ifreq.ifr_name, priv->ifname, sizeof(ifreq.ifr_name)); + + ret = ioctl(s, SIOCGIFCAP, &ifreq); + if (ret) { + WPRINTF(("ioctl(SIOCGIFCAP) failed: %s\n", strerror(errno))); + close(s); + return (ret); + } + + /* + * Enable or disable tap(4) capabilities for TX/RX checksum and + * TSO/LRO. + */ + if (vnet_hdr_len != 0) { + assert((ifreq.ifr_reqcap & TAP_VHDR_IFCAPS) == TAP_VHDR_IFCAPS); + ifreq.ifr_reqcap = ifreq.ifr_curcap | TAP_VHDR_IFCAPS; + } else { + ifreq.ifr_reqcap = ifreq.ifr_curcap & (~TAP_VHDR_IFCAPS); + } + ret = ioctl(s, SIOCSIFCAP, &ifreq); + if (ret) { + WPRINTF(("ioctl(SIOCSIFCAP) failed: %s\n", strerror(errno))); + close(s); + return (ret); + } + + close(s); + + return (0); +} + static void tap_cleanup(struct net_backend *be) { @@ -196,6 +280,11 @@ return (-1); } + if (strlcpy(priv->ifname, devname, sizeof(priv->ifname)) >= + sizeof(priv->ifname)) { + WPRINTF(("TAP device name too long\n")); + return (-1); + } strcpy(tbuf, "/dev/"); strlcat(tbuf, devname, sizeof(tbuf)); @@ -215,7 +304,7 @@ } #ifndef WITHOUT_CAPSICUM - cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE); + cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE, CAP_IOCTL); if (caph_rights_limit(be->fd, &rights) == -1) errx(EX_OSERR, "Unable to apply rights for sandbox"); #endif @@ -278,16 +367,35 @@ static uint64_t tap_get_cap(struct net_backend *be) { + int ret; - return (0); /* no capabilities for now */ + /* + * Check if we are able to set the virtio net header. + * If we are not, we tell the caller that we do not support + * any offload. + */ + if (tap_set_vnet_hdr_len(be, sizeof(struct virtio_net_rxhdr))) { + return (0); + } + + ret = tap_set_vnet_hdr_len(be, 0); + assert(ret == 0); + + return (TAP_FEATURES); } static int tap_set_cap(struct net_backend *be, uint64_t features, unsigned vnet_hdr_len) { + int ret; - return ((features || vnet_hdr_len) ? -1 : 0); + ret = tap_set_vnet_hdr_len(be, vnet_hdr_len); + assert(ret == 0); + + be->be_vnet_hdr_len = vnet_hdr_len; + + return 0; } static struct net_backend tap_backend = { @@ -324,13 +432,6 @@ * The netmap backend */ -/* The virtio-net features supported by netmap. */ -#define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \ - VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \ - VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \ - VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO | \ - VIRTIO_NET_F_MRG_RXBUF) - struct netmap_priv { char ifname[IFNAMSIZ]; struct nm_desc *nmd; @@ -415,8 +516,11 @@ { struct netmap_priv *priv = (struct netmap_priv *)be->opaque; - strlcpy(priv->ifname, devname, sizeof(priv->ifname)); - priv->ifname[sizeof(priv->ifname) - 1] = '\0'; + if (strlcpy(priv->ifname, devname, sizeof(priv->ifname)) >= + sizeof(priv->ifname)) { + WPRINTF(("netmap interface name too long\n")); + return (-1); + } priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL); if (priv->nmd == NULL) {