diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 00f761d9e4a132936f53a682932cee5c0291c800..551c8dea6704fbbffdc20370ad83f17988a6fd79 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -52,6 +52,7 @@ #include "nodeinfo.h" #include "logging.h" #include "network.h" +#include "macvtap.h" #include "cpu/cpu.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -1420,6 +1421,53 @@ int qemudExtractVersion(struct qemud_driver *driver) { return 0; } +/** + * qemudPhysIfaceConnect: + * @conn: pointer to virConnect object + * @net: pointer to he VM's interface description with direct device type + * @linkdev: The name of the physical interface to link the macvtap to + * @brmode: The mode to put the macvtap device into + * + * Returns a filedescriptor on success or -1 in case of error. + */ +int +qemudPhysIfaceConnect(virConnectPtr conn, + virDomainNetDefPtr net, + char *linkdev, + int brmode) +{ + int rc; +#if WITH_MACVTAP + char *res_ifname = NULL; + int hasBusyDev = 0; + + delMacvtapByMACAddress(net->mac, &hasBusyDev); + + if (hasBusyDev) { + virReportSystemError(errno, "%s", + _("A macvtap with the same MAC address is in use")); + return -1; + } + + rc = openMacvtapTap(conn, net->ifname, net->mac, linkdev, brmode, + &res_ifname); + if (rc >= 0) { + VIR_FREE(net->ifname); + net->ifname = res_ifname; + } +#else + (void)conn; + (void)net; + (void)linkdev; + (void)brmode; + (void)conn; + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No support for macvtap device")); + rc = -1; +#endif + return rc; +} + int qemudNetworkIfaceConnect(virConnectPtr conn, @@ -2515,6 +2563,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, switch (net->type) { case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_DIRECT: virBufferAddLit(&buf, "tap"); virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd); type_sep = ','; @@ -3630,6 +3679,22 @@ int qemudBuildCommandLine(virConnectPtr conn, (*tapfds)[(*ntapfds)++] = tapfd; + if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name)) + goto no_memory; + } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) { + int tapfd = qemudPhysIfaceConnect(conn, net, + net->data.direct.linkdev, + net->data.direct.mode); + if (tapfd < 0) + goto error; + + if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) { + close(tapfd); + goto no_memory; + } + + (*tapfds)[(*ntapfds)++] = tapfd; + if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name)) goto no_memory; } diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 498f1d1051cc41ee227945034a850c31f8fd2fac..70414896addf98bb2c8c1a1981e8be4b56d2c724 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -247,6 +247,11 @@ int qemudNetworkIfaceConnect (virConnectPtr conn, unsigned long long qemuCmdFlags) ATTRIBUTE_NONNULL(1); +int qemudPhysIfaceConnect(virConnectPtr conn, + virDomainNetDefPtr net, + char *linkdev, + int brmode); + int qemudProbeMachineTypes (const char *binary, virCapsGuestMachinePtr **machines, int *nmachines); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 03feaf44be0b5d00a891f7cab90f816363beec5f..30742fc81d573ffccc1e2e746697d781f45f3e9d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -75,6 +75,7 @@ #include "libvirt_internal.h" #include "xml.h" #include "cpu/cpu.h" +#include "macvtap.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -2903,6 +2904,8 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver, int retries = 0; qemuDomainObjPrivatePtr priv = vm->privateData; virErrorPtr orig_err; + virDomainDefPtr def; + int i; if (!virDomainObjIsActive(vm)) return; @@ -2914,8 +2917,7 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver, orig_err = virSaveLastError(); if (driver->macFilter) { - int i; - virDomainDefPtr def = vm->def; + def = vm->def; for (i = 0 ; i < def->nnets ; i++) { virDomainNetDefPtr net = def->nets[i]; if (net->ifname == NULL) @@ -2929,6 +2931,17 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver, } } +#if WITH_MACVTAP + def = vm->def; + for (i = 0; i < def->nnets; i++) { + virDomainNetDefPtr net = def->nets[i]; + if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) { + int dummy; + delMacvtapByMACAddress(net->mac, &dummy); + } + } +#endif + if (virKillProcess(vm->pid, 0) == 0 && virKillProcess(vm->pid, SIGTERM) < 0) virReportSystemError(errno, @@ -5708,6 +5721,19 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0) return -1; + } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) { + if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) { + qemuReportError(VIR_ERR_NO_SUPPORT, + _("network device type '%s' cannot be attached: " + "qemu is not using a unix socket monitor"), + virDomainNetTypeToString(net->type)); + return -1; + } + + if ((tapfd = qemudPhysIfaceConnect(conn, net, + net->data.direct.linkdev, + net->data.direct.mode)) < 0) + return -1; } if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) @@ -6326,6 +6352,13 @@ qemudDomainDetachNetDevice(struct qemud_driver *driver, } qemuDomainObjExitMonitorWithDriver(driver, vm); +#if WITH_MACVTAP + if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) { + int dummy; + delMacvtapByMACAddress(detach->mac, &dummy); + } +#endif + if ((driver->macFilter) && (detach->ifname != NULL)) { if ((errno = networkDisallowMacOnPort(driver, detach->ifname,