From 2841e6756d5807a4119e004bc5fb8e7d70806458 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Fri, 3 Feb 2017 11:55:20 -0500 Subject: [PATCH] qemu: propagate bridge MTU into qemu "host_mtu" option libvirt was able to set the host_mtu option when an MTU was explicitly given in the interface config (with ), set the MTU of a libvirt network in the network config (with the same named subelement), and would automatically set the MTU of any tap device to the MTU of the network. This patch ties that all together (for networks based on tap devices and either Linux host bridges or OVS bridges) by learning the MTU of the network (i.e. the bridge) during qemuInterfaceBridgeConnect(), and returning that value so that it can then be passed to qemuBuildNicDevStr(); qemuBuildNicDevStr() then sets host_mtu in the interface's commandline options. The result is that a higher MTU for all guests connecting to a particular network will be plumbed top to bottom by simply changing the MTU of the network (in libvirt's config for libvirt-managed networks, or directly on the bridge device for simple host bridges or OVS bridges managed outside of libvirt). One question I have about this - it occurred to me that in the case of migrating a guest from a host with an older libvirt to one with a newer libvirt, the guest may have *not* had the host_mtu option on the older machine, but *will* have it on the newer machine. I'm curious if this could lead to incompatibilities between source and destination (I guess it all depends on whether or not the setting of host_mtu has a practical effect on a guest that is already running - Maxime?) Likewise, we could run into problems when migrating from a newer libvirt to older libvirt - The guest would have been told of the higher MTU on the newer libvirt, then migrated to a host that didn't understand . (If this really is a problem, it would be a problem with or without the current patch). --- src/qemu/qemu_command.c | 32 ++++++++++++++++++++++---------- src/qemu/qemu_command.h | 3 ++- src/qemu/qemu_hotplug.c | 5 +++-- src/qemu/qemu_interface.c | 5 +++-- src/qemu/qemu_interface.h | 3 ++- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1396661ca9..0767c66490 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3555,7 +3555,8 @@ qemuBuildNicDevStr(virDomainDefPtr def, int vlan, unsigned int bootindex, size_t vhostfdSize, - virQEMUCapsPtr qemuCaps) + virQEMUCapsPtr qemuCaps, + unsigned int mtu) { virBuffer buf = VIR_BUFFER_INITIALIZER; const char *nic = net->model; @@ -3679,13 +3680,23 @@ qemuBuildNicDevStr(virDomainDefPtr def, virBufferAsprintf(&buf, ",rx_queue_size=%u", net->driver.virtio.rx_queue_size); } - if (usingVirtio && net->mtu) { - if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_HOST_MTU)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("setting MTU is not supported with this QEMU binary")); - goto error; + if (usingVirtio && mtu) { + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_HOST_MTU)) { + + virBufferAsprintf(&buf, ",host_mtu=%u", mtu); + + } else { + /* log an error if mtu was requested specifically for this + * interface, otherwise, if it's just what was reported by + * the attached network, ignore it. + */ + if (net->mtu) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("setting MTU is not supported with " + "this QEMU binary")); + goto error; + } } - virBufferAsprintf(&buf, ",host_mtu=%u", net->mtu); } if (vlan == -1) @@ -8042,7 +8053,7 @@ qemuBuildVhostuserCommandLine(virQEMUDriverPtr driver, VIR_FREE(netdev); if (!(nic = qemuBuildNicDevStr(def, net, -1, bootindex, - queues, qemuCaps))) { + queues, qemuCaps, net->mtu))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Error generating NIC -device string")); goto error; @@ -8088,6 +8099,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver, virDomainNetType actualType = virDomainNetGetActualType(net); virNetDevBandwidthPtr actualBandwidth; size_t i; + unsigned int mtu = net->mtu; if (!bootindex) @@ -8142,7 +8154,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver, memset(tapfd, -1, tapfdSize * sizeof(tapfd[0])); if (qemuInterfaceBridgeConnect(def, driver, net, - tapfd, &tapfdSize) < 0) + tapfd, &tapfdSize, &mtu) < 0) goto cleanup; break; @@ -8322,7 +8334,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver, } if (qemuDomainSupportsNicdev(def, net)) { if (!(nic = qemuBuildNicDevStr(def, net, vlan, bootindex, - vhostfdSize, qemuCaps))) + vhostfdSize, qemuCaps, mtu))) goto cleanup; virCommandAddArgList(cmd, "-device", nic, NULL); } else { diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 3bcfdc6e4f..69fe846139 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -101,7 +101,8 @@ char *qemuBuildNicDevStr(virDomainDefPtr def, int vlan, unsigned int bootindex, size_t vhostfdSize, - virQEMUCapsPtr qemuCaps); + virQEMUCapsPtr qemuCaps, + unsigned int mtu); char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8a4d20dba5..e272df3560 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -969,6 +969,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, bool charDevPlugged = false; bool netdevPlugged = false; bool hostPlugged = false; + unsigned int mtu = net->mtu; /* preallocate new slot for device */ if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0) @@ -1025,7 +1026,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, goto cleanup; memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize); if (qemuInterfaceBridgeConnect(vm->def, driver, net, - tapfd, &tapfdSize) < 0) + tapfd, &tapfdSize, &mtu) < 0) goto cleanup; iface_connected = true; if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps, @@ -1236,7 +1237,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, VIR_FORCE_CLOSE(vhostfd[i]); if (!(nicstr = qemuBuildNicDevStr(vm->def, net, vlan, 0, - queueSize, priv->qemuCaps))) + queueSize, priv->qemuCaps, mtu))) goto try_remove; qemuDomainObjEnterMonitor(driver, vm); diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c index ce448d2433..c5dca60f1f 100644 --- a/src/qemu/qemu_interface.c +++ b/src/qemu/qemu_interface.c @@ -503,7 +503,8 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def, virQEMUDriverPtr driver, virDomainNetDefPtr net, int *tapfd, - size_t *tapfdSize) + size_t *tapfdSize, + unsigned int *mtu) { const char *brname; int ret = -1; @@ -544,7 +545,7 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def, def->uuid, tunpath, tapfd, *tapfdSize, virDomainNetGetActualVirtPortProfile(net), virDomainNetGetActualVlan(net), - 0, NULL, + net->mtu, mtu, tap_create_flags) < 0) { virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h index a7faa0b3da..ba74ac2cfe 100644 --- a/src/qemu/qemu_interface.h +++ b/src/qemu/qemu_interface.h @@ -51,7 +51,8 @@ int qemuInterfaceBridgeConnect(virDomainDefPtr def, virQEMUDriverPtr driver, virDomainNetDefPtr net, int *tapfd, - size_t *tapfdSize) + size_t *tapfdSize, + unsigned int *mtu) ATTRIBUTE_NONNULL(2); int qemuInterfaceOpenVhostNet(virDomainDefPtr def, -- GitLab