diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c index ad1755dd6a..b82a62f7d3 100644 --- a/src/qemu/qemu_interface.c +++ b/src/qemu/qemu_interface.c @@ -428,36 +428,53 @@ qemuInterfaceEthernetConnect(virDomainDefPtr def, if (virDomainNetIsVirtioModel(net)) tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; - if (!net->ifname || - STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) || - strchr(net->ifname, '%')) { - VIR_FREE(net->ifname); - if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_TAP_PREFIX "%d") < 0) + if (net->managed_tap == VIR_TRISTATE_BOOL_NO) { + if (!net->ifname) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("target dev must be supplied when managed='no'")); + goto cleanup; + } + if (virNetDevExists(net->ifname) != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("target managed='no' but specified dev doesn't exist")); + goto cleanup; + } + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize, + tap_create_flags) < 0) { + goto cleanup; + } + } else { + if (!net->ifname || + STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) || + strchr(net->ifname, '%')) { + VIR_FREE(net->ifname); + if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_TAP_PREFIX "%d") < 0) + goto cleanup; + /* avoid exposing vnet%d in getXMLDesc or error outputs */ + template_ifname = true; + } + if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize, + tap_create_flags) < 0) { + goto cleanup; + } + + /* The tap device's MAC address cannot match the MAC address + * used by the guest. This results in "received packet on + * vnetX with own address as source address" error logs from + * the kernel. + */ + virMacAddrSet(&tapmac, &net->mac); + if (tapmac.addr[0] == 0xFE) + tapmac.addr[0] = 0xFA; + else + tapmac.addr[0] = 0xFE; + + if (virNetDevSetMAC(net->ifname, &tapmac) < 0) + goto cleanup; + + if (virNetDevSetOnline(net->ifname, true) < 0) goto cleanup; - /* avoid exposing vnet%d in getXMLDesc or error outputs */ - template_ifname = true; } - if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize, - tap_create_flags) < 0) { - goto cleanup; - } - - /* The tap device's MAC address cannot match the MAC address - * used by the guest. This results in "received packet on - * vnetX with own address as source address" error logs from - * the kernel. - */ - virMacAddrSet(&tapmac, &net->mac); - if (tapmac.addr[0] == 0xFE) - tapmac.addr[0] = 0xFA; - else - tapmac.addr[0] = 0xFE; - - if (virNetDevSetMAC(net->ifname, &tapmac) < 0) - goto cleanup; - - if (virNetDevSetOnline(net->ifname, true) < 0) - goto cleanup; if (net->script && virNetDevRunEthernetScript(net->ifname, net->script) < 0) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6a261786f9..955ba4de4c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -7559,7 +7559,7 @@ void qemuProcessStop(virQEMUDriverPtr driver, cfg->stateDir)); break; case VIR_DOMAIN_NET_TYPE_ETHERNET: - if (net->ifname) { + if (net->managed_tap != VIR_TRISTATE_BOOL_NO && net->ifname) { ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap)); VIR_FREE(net->ifname); } diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 563b218227..6ff98487cb 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -150,7 +150,7 @@ int virNetDevSetupControl(const char *ifname, ATTRIBUTE_RETURN_CHECK; int virNetDevExists(const char *brname) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE; int virNetDevSetOnline(const char *ifname, bool online) diff --git a/tests/qemuxml2argvdata/net-eth-unmanaged-tap.args b/tests/qemuxml2argvdata/net-eth-unmanaged-tap.args new file mode 100644 index 0000000000..2bb99e96da --- /dev/null +++ b/tests/qemuxml2argvdata/net-eth-unmanaged-tap.args @@ -0,0 +1,32 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-machine pc,accel=tcg,usb=off,dump-guest-core=off \ +-m 214 \ +-realtime mlock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ +-netdev tap,fd=3,id=hostnet0,vhost=on,vhostfd=44 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=fe:11:22:33:44:55,bus=pci.0,\ +addr=0x3 diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c index 3f0c1c3fef..a386dd17be 100644 --- a/tests/qemuxml2argvmock.c +++ b/tests/qemuxml2argvmock.c @@ -149,8 +149,12 @@ virNetDevTapCreate(char **ifname, for (i = 0; i < tapfdSize; i++) tapfd[i] = STDERR_FILENO + 1 + i; - VIR_FREE(*ifname); - return VIR_STRDUP(*ifname, "vnet0"); + if (STREQ_NULLABLE(*ifname, "mytap0")) { + return 0; + } else { + VIR_FREE(*ifname); + return VIR_STRDUP(*ifname, "vnet0"); + } } int @@ -160,6 +164,14 @@ virNetDevSetMAC(const char *ifname ATTRIBUTE_UNUSED, return 0; } + +int +virNetDevExists(const char *ifname) +{ + return STREQ_NULLABLE(ifname, "mytap0"); +} + + int virNetDevIPAddrAdd(const char *ifname ATTRIBUTE_UNUSED, virSocketAddr *addr ATTRIBUTE_UNUSED, virSocketAddr *peer ATTRIBUTE_UNUSED, diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 5af74ef9be..1f2ae5958a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1318,6 +1318,7 @@ mymain(void) DO_TEST("net-eth-ifname", NONE); DO_TEST("net-eth-names", NONE); DO_TEST("net-eth-hostip", NONE); + DO_TEST("net-eth-unmanaged-tap", NONE); DO_TEST("net-client", NONE); DO_TEST("net-server", NONE); DO_TEST("net-many-models", NONE);