libvir-list-bounces@redhat.com wrote on 03/08/2010
07:29:59 PM:
> [image removed]
>
> [libvirt] [RFC][PATCH v2 2/2] Automatically recreate macvtap
> interface and reconnect to qemu
>
> Ed Swierk
>
> to:
>
> libvir-list
>
> 03/08/2010 07:45 PM
>
> Sent by:
>
> libvir-list-bounces@redhat.com
>
> (See the PATCH 0 email for further discussion.)
>
> ---
> The libvirt qemu driver creates a macvtap interface for each defined
> "direct" network interface, but unlike a tap interface that
is owned
> by the process that creates it, a macvtap interface vanishes when
the
> underlying network device goes away. When this happens, qemu
is left
> holding a file descriptor for a nonexistent tap interface.
>
> This patch implements dynamically recreating a macvtap interface when
> the underlying network device reappears, and reconnecting it to the
> still-running qemu process.
>
> It's a total hack job: after starting qemu, it spawns a thread
hehe :-)
> that wakes up once per second and attempts to create a new macvtap
> interface for each defined direct interface. If the macvtap
What if you collected all macvtap devices' names,
MAC addresses and whatever else is needed to recreate the devices in a
map/dictionary/list (using virHashMap for example) where
- the map entry gets added upon creation of the macvtap
device
- the map entry gets delete upon destruction of the
macvtap device
- the thread walks the list of macvtap device names
and reads and compares for example their MAC addresses using an ioctl and
if the ioctl fails tries to recreate them until successful?
Stefan
> interface already exists (because it never disappeared) or can't
> be created (because the underlying network device doesn't exist),
> this is a no-op. Only when the underlying network device reappears
> does the reconnection complete.
>
> At minimum, this should be done without the once-per-second polling.
>
> Index: libvirt-0.7.7/src/qemu/qemu_driver.c
> ===================================================================
> --- libvirt-0.7.7.orig/src/qemu/qemu_driver.c
> +++ libvirt-0.7.7/src/qemu/qemu_driver.c
> @@ -83,6 +83,7 @@
> #include "xml.h"
> #include "cpu/cpu.h"
> #include "macvtap.h"
> +#include "threads.h"
>
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
> @@ -107,6 +108,8 @@ struct _qemuDomainObjPrivate {
>
> qemuDomainPCIAddressSetPtr pciaddrs;
> int persistentAddrs;
> +
> + pthread_t reconnectNetBackendsThread;
> };
>
> static int qemudShutdown(void);
> @@ -151,6 +154,8 @@ static int qemudDomainDisconnectNetBacke
>
virDomainObjPtr vm,
>
virDomainNetDefPtr net);
>
> +static void *qemudDomainReconnectNetBackends(void *opaque);
> +
> static struct qemud_driver *qemu_driver = NULL;
>
>
> @@ -2697,6 +2702,7 @@ static int qemudStartVMDaemon(virConnect
> char *pidfile = NULL;
> int logfile;
> qemuDomainObjPrivatePtr priv = vm->privateData;
> + pthread_attr_t threadAttr;
>
> struct qemudHookData hookData;
> hookData.conn = conn;
> @@ -2950,6 +2956,15 @@ static int qemudStartVMDaemon(virConnect
> if (virDomainSaveStatus(driver->caps, driver->stateDir,
vm) < 0)
> goto abort;
>
> + pthread_attr_init(&threadAttr);
> + pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
> + if (pthread_create(&priv->reconnectNetBackendsThread,
&threadAttr,
> +
qemudDomainReconnectNetBackends, vm->def->uuid)) {
> + pthread_attr_destroy(&threadAttr);
> + goto abort;
> + }
> + pthread_attr_destroy(&threadAttr);
> +
> return 0;
>
> cleanup:
> @@ -6248,7 +6263,7 @@ static int qemudDomainConnectNetBackend(
>
unsigned
long long qemuCmdFlags)
> {
> qemuDomainObjPrivatePtr priv = vm->privateData;
> - char *tapfd_name = NULL;
> + char *hostnet_name = NULL;
> int tapfd = -1;
> char *netstr = NULL;
> int ret = -1;
> @@ -6286,27 +6301,30 @@ static int qemudDomainConnectNetBackend(
> if (tapfd < 0)
> return -1;
>
> - if (virAsprintf(&tapfd_name, "fd-%s",
net->info.alias) < 0) {
> + if (virAsprintf(&hostnet_name, "host%s",
net->info.alias) < 0) {
> virReportOOMError();
> close(tapfd);
> return -1;
> }
>
> if (!(netstr = qemuBuildHostNetStr(net, ' ',
> -
vlan, tapfd_name)))
{
> - VIR_FREE(tapfd_name);
> +
vlan, hostnet_name)))
{
> + VIR_FREE(hostnet_name);
> close(tapfd);
> return -1;
> }
>
> qemuDomainObjEnterMonitorWithDriver(driver, vm);
>
> - if (qemuMonitorSendFileHandle(priv->mon, tapfd_name,
tapfd) < 0)
> + if (qemuMonitorRemoveHostNetwork(priv->mon, vlan,
hostnet_name) < 0)
> + VIR_INFO0("Did not remove existing
host network");
> +
> + if (qemuMonitorSendFileHandle(priv->mon, hostnet_name,
tapfd) < 0)
> goto out;
>
> if (qemuMonitorAddHostNetwork(priv->mon, netstr)
< 0) {
> - if (qemuMonitorCloseFileHandle(priv->mon,
tapfd_name) < 0)
> - VIR_WARN(_("Failed
to close tapfd with '%s'"), tapfd_name);
> + if (qemuMonitorCloseFileHandle(priv->mon,
hostnet_name) < 0)
> + VIR_WARN(_("Failed
to close tapfd with '%s'"), hostnet_name);
> goto out;
> }
>
> @@ -6315,7 +6333,7 @@ static int qemudDomainConnectNetBackend(
> out:
> qemuDomainObjExitMonitorWithDriver(driver, vm);
> VIR_FREE(netstr);
> - VIR_FREE(tapfd_name);
> + VIR_FREE(hostnet_name);
> close(tapfd);
> return ret;
> }
> @@ -9339,6 +9357,73 @@ out:
> return ret;
> }
>
> +static void *qemudDomainReconnectNetBackends(void *opaque)
> +{
> + virConnectPtr conn = virConnectOpen("qemu:///system");
> + struct qemud_driver *driver = conn->privateData;
> + const unsigned char *uuid = opaque;
> +
> + while (1) {
> + virDomainObjPtr vm;
> + unsigned long long qemuCmdFlags;
> + int i;
> +
> + usleep(1000000);
> +
> + VIR_DEBUG(_("qemuDomainReconnectNetBackends
(%p %p)"),
> + conn,
driver);
> +
> + qemuDriverLock(driver);
> + vm = virDomainFindByUUID(&driver->domains,
uuid);
> + if (!vm) {
> + VIR_DEBUG0("qemuDomainReconnectNetBackends
done");
> + qemuDriverUnlock(driver);
> + break;
> + }
> +
> + VIR_DEBUG(_("qemuDomainReconnectNetBackends
(%s)"),
> + vm->def->name);
> +
> + if (qemudExtractVersionInfo(vm->def->emulator,
> +
NULL,
> +
&qemuCmdFlags)
< 0)
> + goto cleanup;
> +
> + if (qemuDomainObjBeginJobWithDriver(driver,
vm) < 0)
> + goto cleanup;
> +
> + if (!virDomainObjIsActive(vm))
> + goto endjob;
> +
> + for (i = 0 ; i < vm->def->nnets
; i++) {
> + virDomainNetDefPtr net
= vm->def->nets[i];
> +
> + if (net->type != VIR_DOMAIN_NET_TYPE_DIRECT)
> + continue;
> +
> + if (qemudDomainConnectNetBackend(conn,
driver, vm,
> +
net, qemuCmdFlags) == 0) {
> + VIR_WARN(_("Reconnected
interface %s (%s) for domain %s"),
> +
net->data.direct.linkdev, net->ifname,
> vm->def->name);
> + } else {
> + VIR_DEBUG(_("Unable
to reconnect interface %s for
> domain %s"),
> +
net->data.direct.linkdev, vm->def->name);
> + }
> + }
> +
> + endjob:
> + if (qemuDomainObjEndJob(vm) == 0)
> + vm = NULL;
> +
> + cleanup:
> + if (vm)
> + virDomainObjUnlock(vm);
> + qemuDriverUnlock(driver);
> + }
> +
> + return NULL;
> +}
> +
> static int
> qemuCPUCompare(virConnectPtr conn,
> const char
*xmlDesc,
> Index: libvirt-0.7.7/src/util/macvtap.c
> ===================================================================
> --- libvirt-0.7.7.orig/src/util/macvtap.c
> +++ libvirt-0.7.7/src/util/macvtap.c
> @@ -215,10 +215,12 @@ getIfIndex(virConnectPtr conn,
> if (ioctl(fd, SIOCGIFINDEX, &ifreq) >=
0)
> *idx = ifreq.ifr_ifindex;
> else {
> +#if 0
> if (conn)
> ReportError(conn,
VIR_ERR_INTERNAL_ERROR,
>
_("interface %s does not exist"),
>
ifname);
> +#endif
> rc = ENODEV;
> }
>
> @@ -747,11 +749,13 @@ create_name:
>
> rc = ifUp(cr_ifname, 1);
> if (rc != 0) {
> +#if 0
> virReportSystemError(errno,
>
_("cannot 'up' interface %s --
another "
>
"macvtap device may be 'up' and
have the same "
>
"MAC address"),
>
cr_ifname);
> +#endif
> rc = -1;
> goto link_del_exit;
> }
> Index: libvirt-0.7.7/src/qemu/qemu_conf.c
> ===================================================================
> --- libvirt-0.7.7.orig/src/qemu/qemu_conf.c
> +++ libvirt-0.7.7/src/qemu/qemu_conf.c
> @@ -3854,18 +3854,21 @@ int qemudBuildCommandLine(virConnectPtr
>
net->data.direct.linkdev,
>
net->data.direct.mode,
>
qemuCmdFlags);
> - if (tapfd
< 0)
> - goto
error;
> -
> - if (VIR_REALLOC_N(*tapfds,
(*ntapfds)+1) < 0) {
> - close(tapfd);
> - goto
no_memory;
> - }
> + if (tapfd
< 0) {
> + VIR_WARN(_("Unable
to connect interface %s for
> domain %s"),
> +
net->data.direct.linkdev, def->name);
> + tapfd_name[0]
= 0;
> + } else {
> + if
(VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
> +
close(tapfd);
> +
goto no_memory;
> + }
>
> - (*tapfds)[(*ntapfds)++]
= tapfd;
> + (*tapfds)[(*ntapfds)++]
= tapfd;
>
> - if (snprintf(tapfd_name,
sizeof(tapfd_name), "%d",
> tapfd) >= sizeof(tapfd_name))
> - goto
no_memory;
> + if
(snprintf(tapfd_name, sizeof(tapfd_name), "%
> d", tapfd) >= sizeof(tapfd_name))
> +
goto no_memory;
> + }
> }
>
> /* Possible combinations:
> @@ -3876,8 +3879,9 @@ int qemudBuildCommandLine(virConnectPtr
> *
> * NB, no support
for -netdev without use of -device
> */
> - if ((qemuCmdFlags &
QEMUD_CMD_FLAG_NETDEV) &&
> - (qemuCmdFlags
& QEMUD_CMD_FLAG_DEVICE)) {
> + if ((tapfd_name[0] != 0)
&&
> + ((qemuCmdFlags
& QEMUD_CMD_FLAG_NETDEV) &&
> + (qemuCmdFlags
& QEMUD_CMD_FLAG_DEVICE))) {
> ADD_ARG_LIT("-netdev");
> if (!(host
= qemuBuildHostNetStr(net, ',',
>
vlan, tapfd_name)))
> @@ -3895,8 +3899,9 @@ int qemudBuildCommandLine(virConnectPtr
>
goto error;
> ADD_ARG(nic);
> }
> - if (!((qemuCmdFlags &
QEMUD_CMD_FLAG_NETDEV) &&
> - (qemuCmdFlags
& QEMUD_CMD_FLAG_DEVICE))) {
> + if ((tapfd_name[0] != 0)
&&
> + (!((qemuCmdFlags
& QEMUD_CMD_FLAG_NETDEV) &&
> + (qemuCmdFlags
& QEMUD_CMD_FLAG_DEVICE)))) {
> ADD_ARG_LIT("-net");
> if (!(host
= qemuBuildHostNetStr(net, ',',
>
vlan, tapfd_name)))
>
>
> --
> libvir-list mailing list
> libvir-list@redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list