The function that parses the <forward> subelement of a network used to fail/log an error if the network definition contained both a <pf> element as well as at least one <interface> or <address> element. That check was present because the configuration of a network should have either one <pf>, one or more <interface>, or one or more <address>, but never combinations of multiple kinds. This caused a problem when libvirtd was restarted with a network already active - when a network with a <pf> element is started, the referenced PF (Physical Function of an SRIOV-capable network card) is checked for VFs (Virtual Functions), and the <forward> is filled in with a list of all VFs for that PF either in the form of their PCI addresses (a list of <address>) or their netdev names (a list of <interface>); the <pf> element is not removed though. When libvirtd is restarted, it parses the network status and finds both the original <pf> from the config, as well as the list of either <address> or <interface>, fails the parse, and the network is not added to the active list. This failure is often obscured because the network is marked as autostart so libvirt immediately restarts it. It seems odd to me that <interface> and <address> are stored in the same array rather than keeping two separate arrays, and having separate arrays would have made the check much simpler. However, changing to use two separate arrays would have required changes in more places, potentially creating more conflicts and (more importantly) more possible regressions in the event of a backport, so I chose to keep the existing data structure in order to localize the change. It appears that this problem has been in the code ever since support for <pf> was added (0.9.10), but until commit 34cc3b2f106e296df5e64309620c79d16fd76c85 (first in libvirt 1.2.4) networks with interface pools were not properly marked as active on restart anyway, so there is no point in backporting this patch any further than that. --- src/conf/network_conf.c | 10 +--------- src/network/bridge_driver.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index f947d89..dce3360 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1,7 +1,7 @@ /* * network_conf.c: network XML handling * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006-2008 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -1638,14 +1638,6 @@ virNetworkForwardDefParseXML(const char *networkName, goto cleanup; } - if (((nForwardIfs > 0) + (nForwardAddrs > 0) + (nForwardPfs > 0)) > 1) { - virReportError(VIR_ERR_XML_ERROR, - _("<address>, <interface>, and <pf> elements in <forward> " - "of network %s are mutually exclusive"), - networkName); - goto cleanup; - } - forwardDev = virXPathString("string(./@dev)", ctxt); if (forwardDev && (nForwardAddrs > 0 || nForwardPfs > 0)) { virReportError(VIR_ERR_XML_ERROR, "%s", diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2798010..af16c25 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2734,6 +2734,7 @@ networkValidate(virNetworkDefPtr def, virNetworkIpDefPtr ipdef; bool ipv4def = false, ipv6def = false; bool bandwidthAllowed = true; + bool usesInterface = false, usesAddress = false; /* check for duplicate networks */ if (virNetworkObjIsDuplicate(&driver->networks, def, check_active) < 0) @@ -2798,6 +2799,40 @@ networkValidate(virNetworkDefPtr def, bandwidthAllowed = false; } + /* we support configs with a single PF defined: + * <pf dev='eth0'/> + * or with a list of netdev names: + * <interface dev='eth9'/> + * OR a list of PCI addresses + * <address type='pci' domain='0' bus='4' slot='0' function='1'/> + * but not any combination of those. + * + * Since <interface> and <address> are for some strange reason + * stored in the same array, we need to cycle through it and check + * the type of each. + */ + for (i = 0; i < def->forward.nifs; i++) { + switch ((virNetworkForwardHostdevDeviceType) + def->forward.ifs[i].type) { + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV: + usesInterface = true; + break; + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: + usesAddress = true; + break; + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE: + case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST: + break; + } + } + if ((def->forward.npfs > 0) + usesInterface + usesAddress > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("<address>, <interface>, and <pf> elements of " + "<forward> in network %s are mutually exclusive"), + def->name); + return -1; + } + /* We only support dhcp on one IPv4 address and * on one IPv6 address per defined network */ -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list