https://bugzilla.redhat.com/show_bug.cgi?id=1075520 Apart from generic checks, we need to constrain netmask/prefix lenght a bit. Thing is, with current implementation QEMU needs to be able to 'assign' some IP addresses to the virtual network. For instance, the default gateway is at x.x.x.2, dns is at x.x.x.3, the default DHCP range is x.x.x.15-x.x.x.30. Since we don't expose these settings yet, it's safer to require shorter prefix to have room for the defaults. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/qemu/qemu_command.c | 22 ++++++++++ src/qemu/qemu_domain.c | 49 ++++++++++++++++++++++ .../qemuxml2argv-net-user-addr.args | 25 +++++++++++ tests/qemuxml2argvtest.c | 1 + 4 files changed, 97 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-user-addr.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d553df57f..3e1bc5fa8 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3805,6 +3805,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, virDomainNetType netType = virDomainNetGetActualType(net); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); size_t i; + char *addr = NULL; char *ret = NULL; if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) { @@ -3873,6 +3874,26 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, break; case VIR_DOMAIN_NET_TYPE_USER: + virBufferAsprintf(&buf, "user%c", type_sep); + for (i = 0; i < net->hostIP.nips; i++) { + const virNetDevIPAddr *ip = net->hostIP.ips[i]; + const char *prefix = ""; + + if (!(addr = virSocketAddrFormat(&ip->address))) + goto cleanup; + + if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) + prefix = "net="; + if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6)) + prefix = "ipv6-net"; + + virBufferAsprintf(&buf, "%s%s", prefix, addr); + if (ip->prefix) + virBufferAsprintf(&buf, "/%u", ip->prefix); + virBufferAddChar(&buf, ','); + } + break; + case VIR_DOMAIN_NET_TYPE_INTERNAL: virBufferAsprintf(&buf, "user%c", type_sep); break; @@ -3928,6 +3949,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, cleanup: virBufferFreeAndReset(&buf); virObjectUnref(cfg); + VIR_FREE(addr); return ret; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 72031893f..bf0c7300c 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3338,9 +3338,11 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev, void *opaque ATTRIBUTE_UNUSED) { int ret = -1; + size_t i; if (dev->type == VIR_DOMAIN_DEVICE_NET) { const virDomainNetDef *net = dev->data.net; + bool hasIPv4 = false, hasIPv6 = false; if (net->guestIP.nroutes || net->guestIP.nips) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -3350,6 +3352,53 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev, goto cleanup; } + if (net->type == VIR_DOMAIN_NET_TYPE_USER) { + if (net->hostIP.nroutes) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Invalid attempt to set network interface " + "guest-side IP address info, " + "not supported by QEMU")); + goto cleanup; + } + + for (i = 0; i < net->hostIP.nips; i++) { + const virNetDevIPAddr *ip = net->hostIP.ips[i]; + + if (VIR_SOCKET_ADDR_VALID(&ip->peer)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("peers are not supported by QEMU")); + goto cleanup; + } + + if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) { + if (hasIPv4) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only one IPv4 address allowed")); + goto cleanup; + } + hasIPv4 = true; + } + + if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6)) { + if (hasIPv6) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only one IPv6 address allowed")); + goto cleanup; + } + hasIPv6 = true; + } + + /* QEMU needs some space to have + * some other 'hosts' on the network. */ + if ((hasIPv4 && ip->prefix > 27) || + (hasIPv6 && ip->prefix > 120)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("prefix too long")); + goto cleanup; + } + } + } + if (STREQ_NULLABLE(net->model, "virtio")) { if (net->driver.virtio.rx_queue_size & (net->driver.virtio.rx_queue_size - 1)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-net-user-addr.args new file mode 100644 index 000000000..51aacedb3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user-addr.args @@ -0,0 +1,25 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-M pc \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-no-acpi \ +-boot c \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-device rtl8139,vlan=0,id=net0,mac=00:11:22:33:44:55,bus=pci.0,addr=0x3 \ +-net user,net=172.17.2.0/24,vlan=0,name=hostnet0 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2c040e4c0..584df017a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1159,6 +1159,7 @@ mymain(void) QEMU_CAPS_NETDEV, QEMU_CAPS_VHOSTUSER_MULTIQUEUE); DO_TEST("net-user", NONE); + DO_TEST("net-user-addr", NONE); DO_TEST("net-virtio", NONE); DO_TEST("net-virtio-device", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_TX_ALG); -- 2.13.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list