diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 8f91d07af55743d252f11738ad1718dea45eee81..dcd2ce76accc358b53a0e04e25b3fab6fe9f75e1 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1434,14 +1434,20 @@ int qemudPhysIfaceConnect(virConnectPtr conn, virDomainNetDefPtr net, char *linkdev, - int brmode) + int brmode, + unsigned long long qemuCmdFlags) { int rc; #if WITH_MACVTAP char *res_ifname = NULL; + int vnet_hdr = 0; + + if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR && + net->model && STREQ(net->model, "virtio")) + vnet_hdr = 1; rc = openMacvtapTap(conn, net->ifname, net->mac, linkdev, brmode, - &res_ifname); + &res_ifname, vnet_hdr); if (rc >= 0) { VIR_FREE(net->ifname); net->ifname = res_ifname; @@ -1451,6 +1457,7 @@ qemudPhysIfaceConnect(virConnectPtr conn, (void)net; (void)linkdev; (void)brmode; + (void)qemuCmdFlags; qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No support for macvtap device")); rc = -1; @@ -3752,7 +3759,8 @@ int qemudBuildCommandLine(virConnectPtr conn, } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) { int tapfd = qemudPhysIfaceConnect(conn, net, net->data.direct.linkdev, - net->data.direct.mode); + net->data.direct.mode, + qemuCmdFlags); if (tapfd < 0) goto error; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 4f35a9cb32f434dcbaa410b31ae643da7109aa98..b25c300d9989f57c3cbf7fb3ddc8a7a60f837064 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -253,7 +253,8 @@ int qemudNetworkIfaceConnect (virConnectPtr conn, int qemudPhysIfaceConnect(virConnectPtr conn, virDomainNetDefPtr net, char *linkdev, - int brmode); + int brmode, + unsigned long long qemuCmdFlags); int qemudProbeMachineTypes (const char *binary, virCapsGuestMachinePtr **machines, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0fb2413b1eec76b160984d614fbcc23deaaad3e9..3d121fb586c03e6c6dec003b905eee31b13f6ff8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5725,7 +5725,8 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, if ((tapfd = qemudPhysIfaceConnect(conn, net, net->data.direct.linkdev, - net->data.direct.mode)) < 0) + net->data.direct.mode, + qemuCmdFlags)) < 0) return -1; } diff --git a/src/util/macvtap.c b/src/util/macvtap.c index 88a64ceb883371ad41b63345cccdec8b85c5ad89..8c29588961aee358c4dab0f94667f9ef3ea38a58 100644 --- a/src/util/macvtap.c +++ b/src/util/macvtap.c @@ -614,6 +614,64 @@ macvtapModeFromInt(enum virDomainNetdevMacvtapType mode) } +/** + * configMacvtapTap: + * @tapfd: file descriptor of the macvtap tap + * @vnet_hdr: 1 to enable IFF_VNET_HDR, 0 to disable it + * + * Returns 0 on success, -1 in case of fatal error, error code otherwise. + * + * Turn the IFF_VNET_HDR flag, if requested and available, make sure + * it's off in the other cases. + * A fatal error is defined as the VNET_HDR flag being set but it cannot + * be turned off for some reason. This is reported with -1. Other fatal + * error is not being able to read the interface flags. In that case the + * macvtap device should not be used. + */ +static int +configMacvtapTap(int tapfd, int vnet_hdr) +{ + unsigned int features; + struct ifreq ifreq; + short new_flags = 0; + int rc_on_fail = 0; + const char *errmsg = NULL; + + memset(&ifreq, 0, sizeof(ifreq)); + + if (ioctl(tapfd, TUNGETIFF, &ifreq) < 0) { + virReportSystemError(errno, "%s", + _("cannot get interface flags on macvtap tap")); + return -1; + } + + new_flags = ifreq.ifr_flags; + + if ((ifreq.ifr_flags & IFF_VNET_HDR) && !vnet_hdr) { + new_flags = ifreq.ifr_flags & ~IFF_VNET_HDR; + rc_on_fail = -1; + errmsg = _("cannot clean IFF_VNET_HDR flag on macvtap tap"); + } else if ((ifreq.ifr_flags & IFF_VNET_HDR) == 0 && vnet_hdr) { + if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) + return errno; + if ((features & IFF_VNET_HDR)) { + new_flags = ifreq.ifr_flags | IFF_VNET_HDR; + errmsg = _("cannot set IFF_VNET_HDR flag on macvtap tap"); + } + } + + if (new_flags != ifreq.ifr_flags) { + ifreq.ifr_flags = new_flags; + if (ioctl(tapfd, TUNSETIFF, &ifreq) < 0) { + virReportSystemError(errno, "%s", errmsg); + return rc_on_fail; + } + } + + return 0; +} + + /** * openMacvtapTap: * Create an instance of a macvtap device and open its tap character @@ -640,7 +698,8 @@ openMacvtapTap(virConnectPtr conn, const unsigned char *macaddress, const char *linkdev, int mode, - char **res_ifname) + char **res_ifname, + int vnet_hdr) { const char *type = "macvtap"; int c, rc; @@ -699,9 +758,14 @@ create_name: rc = openTap(cr_ifname, 10); - if (rc >= 0) + if (rc >= 0) { + if (configMacvtapTap(rc, vnet_hdr) < 0) { + close(rc); + rc = -1; + goto link_del_exit; + } *res_ifname = strdup(cr_ifname); - else + } else goto link_del_exit; return rc; diff --git a/src/util/macvtap.h b/src/util/macvtap.h index a1a0a7a8afed25b4da88b4c06847a0d716dfef88..4c2fe8acd73c5e24c2759d00942ae9244fc06373 100644 --- a/src/util/macvtap.h +++ b/src/util/macvtap.h @@ -33,9 +33,10 @@ int openMacvtapTap(virConnectPtr conn, const unsigned char *macaddress, const char *linkdev, int mode, - char **res_ifname); + char **res_ifname, + int vnet_hdr); -void delMacvtap(const char *name); +void delMacvtap(const char *ifname); #endif /* WITH_MACVTAP */