This patch introduces the new forward mode='hostdev' along with attribute managed
Includes updates to the network RNG and new xml parser/formatter code.
Signed-off-by: Shradha Shah <sshah(a)solarflare.com>
---
docs/schemas/network.rng | 82 +++++++++++++++++++--
src/conf/network_conf.c | 126 ++++++++++++++++++++++++++++----
src/conf/network_conf.h | 29 +++++++-
src/network/bridge_driver.c | 18 ++--
tests/networkxml2xmlin/hostdev-pf.xml | 11 +++
tests/networkxml2xmlin/hostdev.xml | 10 +++
tests/networkxml2xmlout/hostdev-pf.xml | 7 ++
tests/networkxml2xmlout/hostdev.xml | 10 +++
tests/networkxml2xmltest.c | 2 +
9 files changed, 262 insertions(+), 33 deletions(-)
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 2ae879e..d1297cd 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -82,17 +82,41 @@
<value>passthrough</value>
<value>private</value>
<value>vepa</value>
+ <value>hostdev</value>
+ </choice>
+ </attribute>
+ </optional>
+
+ <optional>
+ <attribute name="managed">
+ <choice>
+ <value>yes</value>
+ <value>no</value>
</choice>
</attribute>
</optional>
<interleave>
- <zeroOrMore>
- <element name='interface'>
- <attribute name='dev'>
- <ref name='deviceName'/>
- </attribute>
- </element>
- </zeroOrMore>
+ <choice>
+ <group>
+ <zeroOrMore>
+ <element name='interface'>
+ <attribute name='dev'>
+ <ref name='deviceName'/>
+ </attribute>
+ </element>
+ </zeroOrMore>
+ </group>
+ <group>
+ <zeroOrMore>
+ <element name='address'>
+ <attribute name='type'>
+ <value>pci</value>
+ </attribute>
+ <ref name="pciaddress"/>
+ </element>
+ </zeroOrMore>
+ </group>
+ </choice>
<optional>
<element name='pf'>
<attribute name='dev'>
@@ -238,4 +262,48 @@
</interleave>
</element>
</define>
+ <define name="pciaddress">
+ <optional>
+ <attribute name="domain">
+ <ref name="pciDomain"/>
+ </attribute>
+ </optional>
+ <attribute name="bus">
+ <ref name="pciBus"/>
+ </attribute>
+ <attribute name="slot">
+ <ref name="pciSlot"/>
+ </attribute>
+ <attribute name="function">
+ <ref name="pciFunc"/>
+ </attribute>
+ <optional>
+ <attribute name="multifunction">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ </optional>
+ </define>
+ <define name="pciDomain">
+ <data type="string">
+ <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param>
+ </data>
+ </define>
+ <define name="pciBus">
+ <data type="string">
+ <param name="pattern">(0x)?[0-9a-fA-F]{1,2}</param>
+ </data>
+ </define>
+ <define name="pciSlot">
+ <data type="string">
+ <param name="pattern">(0x)?[0-1]?[0-9a-fA-F]</param>
+ </data>
+ </define>
+ <define name="pciFunc">
+ <data type="string">
+ <param name="pattern">(0x)?[0-7]</param>
+ </data>
+ </define>
</grammar>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 515bc36..be37856 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -48,10 +48,14 @@
#define VIR_FROM_THIS VIR_FROM_NETWORK
VIR_ENUM_DECL(virNetworkForward)
-
VIR_ENUM_IMPL(virNetworkForward,
VIR_NETWORK_FORWARD_LAST,
- "none", "nat", "route", "bridge",
"private", "vepa", "passthrough" )
+ "none", "nat", "route", "bridge",
"private", "vepa", "passthrough", "hostdev")
+
+VIR_ENUM_DECL(virNetworkForwardHostdevDevice)
+VIR_ENUM_IMPL(virNetworkForwardHostdevDevice,
+ VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
+ "none", "pci")
#define virNetworkReportError(code, ...) \
virReportErrorHelper(VIR_FROM_NETWORK, code, __FILE__, \
@@ -100,6 +104,12 @@ virPortGroupDefClear(virPortGroupDefPtr def)
static void
virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def)
{
+ VIR_FREE(def->device.dev);
+}
+
+static void
+virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def)
+{
VIR_FREE(def->dev);
}
@@ -163,12 +173,13 @@ void virNetworkDefFree(virNetworkDefPtr def)
VIR_FREE(def->domain);
for (ii = 0 ; ii < def->nForwardPfs && def->forwardPfs ; ii++) {
- virNetworkForwardIfDefClear(&def->forwardPfs[ii]);
+ virNetworkForwardPfDefClear(&def->forwardPfs[ii]);
}
VIR_FREE(def->forwardPfs);
for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) {
- virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
+ if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV)
+ virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
}
VIR_FREE(def->forwardIfs);
@@ -935,11 +946,14 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
xmlNodePtr *portGroupNodes = NULL;
xmlNodePtr *forwardIfNodes = NULL;
xmlNodePtr *forwardPfNodes = NULL;
+ xmlNodePtr *forwardAddrNodes = NULL;
xmlNodePtr dnsNode = NULL;
xmlNodePtr virtPortNode = NULL;
xmlNodePtr forwardNode = NULL;
- int nIps, nPortGroups, nForwardIfs, nForwardPfs;
+ int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs;
char *forwardDev = NULL;
+ char *forwardManaged = NULL;
+ char *type = NULL;
xmlNodePtr save = ctxt->node;
xmlNodePtr bandwidthNode = NULL;
@@ -1084,17 +1098,30 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
}
forwardDev = virXPathString("string(./@dev)", ctxt);
+ forwardManaged = virXPathString("string(./@managed)", ctxt);
+ if(forwardManaged != NULL) {
+ if (STREQ(forwardManaged, "yes"))
+ def->managed = 1;
+ else
+ def->managed = 0;
+ }
/* all of these modes can use a pool of physical interfaces */
nForwardIfs = virXPathNodeSet("./interface", ctxt,
&forwardIfNodes);
nForwardPfs = virXPathNodeSet("./pf", ctxt, &forwardPfNodes);
+ nForwardAddrs = virXPathNodeSet("./address", ctxt,
&forwardAddrNodes);
- if (nForwardIfs < 0 || nForwardPfs < 0) {
+ if (nForwardIfs < 0 || nForwardPfs < 0 || nForwardAddrs < 0) {
virNetworkReportError(VIR_ERR_XML_ERROR,
_("No interface pool or SRIOV physical device
given"));
goto error;
}
+ if ((nForwardIfs > 0) && (nForwardAddrs > 0)) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Address and interface attributes are mutually
exclusive"));
+ }
+
if (nForwardPfs == 1) {
if (VIR_ALLOC_N(def->forwardPfs, nForwardPfs) < 0) {
virReportOOMError();
@@ -1124,7 +1151,55 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
_("Use of more than one physical interface is not
allowed"));
goto error;
}
- if (nForwardIfs > 0 || forwardDev) {
+ if (nForwardAddrs > 0) {
+ int ii;
+
+ if (VIR_ALLOC_N(def->forwardIfs, nForwardAddrs) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (forwardDev) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("A forward Dev should not be used when using
address attribute"));
+ goto error;
+ }
+
+ for (ii = 0; ii < nForwardAddrs; ii++) {
+ type = virXMLPropString(*forwardAddrNodes, "type");
+
+ if (type) {
+ if ((def->forwardIfs[ii].type =
virNetworkForwardHostdevDeviceTypeFromString(type)) < 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("unknown address type
'%s'"), type);
+ goto error;
+ }
+ } else {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ "%s", _("No type specified for
device address"));
+ goto error;
+ }
+
+ switch (def->forwardIfs[ii].type) {
+ case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI:
+ if (virDevicePCIAddressParseXML(*forwardAddrNodes,
&(def->forwardIfs[ii].device.pci)) < 0)
+ goto error;
+ break;
+
+ /* Add USB case here */
+
+ default:
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("unknown address type
'%s'"), type);
+ goto error;
+ }
+
+ def->forwardIfs[ii].usageCount = 0;
+ type = NULL;
+ def->nForwardIfs++;
+ }
+ }
+ else if (nForwardIfs > 0 || forwardDev) {
int ii;
/* allocate array to hold all the portgroups */
@@ -1135,7 +1210,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (forwardDev) {
def->forwardIfs[0].usageCount = 0;
- def->forwardIfs[0].dev = forwardDev;
+ def->forwardIfs[0].device.dev = forwardDev;
+ def->forwardIfs[0].type = 0;
forwardDev = NULL;
def->nForwardIfs++;
}
@@ -1153,10 +1229,10 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if ((ii == 0) && (def->nForwardIfs == 1)) {
/* both forwardDev and an interface element are present.
* If they don't match, it's an error. */
- if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) {
+ if (STRNEQ(forwardDev, def->forwardIfs[0].device.dev)) {
virNetworkReportError(VIR_ERR_XML_ERROR,
_("forward dev '%s' must match
first interface element dev '%s' in network '%s'"),
- def->forwardIfs[0].dev,
+ def->forwardIfs[0].device.dev,
forwardDev, def->name);
goto error;
}
@@ -1164,16 +1240,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
continue;
}
- def->forwardIfs[ii].dev = forwardDev;
+ def->forwardIfs[ii].device.dev = forwardDev;
forwardDev = NULL;
def->forwardIfs[ii].usageCount = 0;
+ def->forwardIfs[ii].type = 0;
def->nForwardIfs++;
}
}
+ VIR_FREE(type);
VIR_FREE(forwardDev);
+ VIR_FREE(forwardManaged);
VIR_FREE(forwardPfNodes);
VIR_FREE(forwardIfNodes);
-
+ VIR_FREE(forwardAddrNodes);
switch (def->forwardType) {
case VIR_NETWORK_FORWARD_ROUTE:
case VIR_NETWORK_FORWARD_NAT:
@@ -1198,6 +1277,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
case VIR_NETWORK_FORWARD_PRIVATE:
case VIR_NETWORK_FORWARD_VEPA:
case VIR_NETWORK_FORWARD_PASSTHROUGH:
+ case VIR_NETWORK_FORWARD_HOSTDEV:
if (def->bridge) {
virNetworkReportError(VIR_ERR_XML_ERROR,
_("bridge name not allowed in %s mode (network
'%s')"),
@@ -1483,6 +1563,12 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int
flags)
}
virBufferAddLit(&buf, " <forward");
virBufferEscapeString(&buf, " dev='%s'", dev);
+ if (def->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) {
+ if (def->managed == 1)
+ virBufferAddLit(&buf, " managed='yes'");
+ else
+ virBufferAddLit(&buf, " managed='no'");
+ }
virBufferAsprintf(&buf, " mode='%s'%s>\n", mode,
(def->nForwardIfs || def->nForwardPfs) ? "" :
"/");
@@ -1494,8 +1580,20 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int
flags)
if (def->nForwardIfs &&
(!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) {
for (ii = 0; ii < def->nForwardIfs; ii++) {
- virBufferEscapeString(&buf, " <interface
dev='%s'/>\n",
- def->forwardIfs[ii].dev);
+ if (def->forwardType != VIR_NETWORK_FORWARD_HOSTDEV)
+ virBufferEscapeString(&buf, " <interface
dev='%s'/>\n",
+ def->forwardIfs[ii].device.dev);
+ else {
+ if (def->forwardIfs[ii].type ==
VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) {
+ if (virDevicePCIAddressFormat(&buf,
+ def->forwardIfs[ii].device.pci,
+ true) < 0) {
+ virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
+ _("PCI address format
failed"));
+ goto error;
+ }
+ }
+ }
}
}
if (def->nForwardPfs || def->nForwardIfs)
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 4339a69..b1a7ddd 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -36,6 +36,7 @@
# include "virnetdevbandwidth.h"
# include "virnetdevvportprofile.h"
# include "virmacaddr.h"
+# include "device_conf.h"
enum virNetworkForwardType {
VIR_NETWORK_FORWARD_NONE = 0,
@@ -45,10 +46,19 @@ enum virNetworkForwardType {
VIR_NETWORK_FORWARD_PRIVATE,
VIR_NETWORK_FORWARD_VEPA,
VIR_NETWORK_FORWARD_PASSTHROUGH,
+ VIR_NETWORK_FORWARD_HOSTDEV,
VIR_NETWORK_FORWARD_LAST,
};
+enum virNetworkForwardHostdevDeviceType {
+ VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE = 0,
+ VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI,
+ /* USB Device to be added here when supported */
+
+ VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
+};
+
typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef;
typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr;
struct _virNetworkDHCPRangeDef {
@@ -131,7 +141,19 @@ struct _virNetworkIpDef {
typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;
struct _virNetworkForwardIfDef {
- char *dev; /* name of device */
+ int type;
+ union {
+ virDevicePCIAddress pci; /*PCI Address of device */
+ /* when USB devices are supported a new variable to be added here */
+ char *dev; /* name of device */
+ }device;
+ int usageCount; /* how many guest interfaces are bound to this device? */
+};
+
+typedef struct _virNetworkForwardPfDef virNetworkForwardPfDef;
+typedef virNetworkForwardPfDef *virNetworkForwardPfDefPtr;
+struct _virNetworkForwardPfDef {
+ char *dev; /* name of device */
int usageCount; /* how many guest interfaces are bound to this device? */
};
@@ -158,12 +180,13 @@ struct _virNetworkDef {
bool mac_specified;
int forwardType; /* One of virNetworkForwardType constants */
+ int managed; /* managed attribute for hostdev mode */
/* If there are multiple forward devices (i.e. a pool of
* interfaces), they will be listed here.
*/
size_t nForwardPfs;
- virNetworkForwardIfDefPtr forwardPfs;
+ virNetworkForwardPfDefPtr forwardPfs;
size_t nForwardIfs;
virNetworkForwardIfDefPtr forwardIfs;
@@ -233,7 +256,7 @@ static inline const char *
virNetworkDefForwardIf(const virNetworkDefPtr def, size_t n)
{
return ((def->forwardIfs && (def->nForwardIfs > n))
- ? def->forwardIfs[n].dev : NULL);
+ ? def->forwardIfs[n].device.dev : NULL);
}
virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 36afa1b..230012c 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2764,8 +2764,8 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) {
netdef->nForwardIfs = num_virt_fns;
for (ii = 0; ii < netdef->nForwardIfs; ii++) {
- netdef->forwardIfs[ii].dev = strdup(vfname[ii]);
- if (!netdef->forwardIfs[ii].dev) {
+ netdef->forwardIfs[ii].device.dev = strdup(vfname[ii]);
+ if (!netdef->forwardIfs[ii].device.dev) {
virReportOOMError();
goto finish;
}
@@ -2985,7 +2985,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
netdef->name);
goto cleanup;
}
- iface->data.network.actual->data.direct.linkdev = strdup(dev->dev);
+ iface->data.network.actual->data.direct.linkdev =
strdup(dev->device.dev);
if (!iface->data.network.actual->data.direct.linkdev) {
virReportOOMError();
goto cleanup;
@@ -2993,7 +2993,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
/* we are now assured of success, so mark the allocation */
dev->usageCount++;
VIR_DEBUG("Using physical device %s, usageCount %d",
- dev->dev, dev->usageCount);
+ dev->device.dev, dev->usageCount);
}
}
@@ -3066,7 +3066,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface)
/* find the matching interface in the pool and increment its usageCount */
for (ii = 0; ii < netdef->nForwardIfs; ii++) {
- if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) {
+ if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) {
dev = &netdef->forwardIfs[ii];
break;
}
@@ -3097,7 +3097,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface)
/* we are now assured of success, so mark the allocation */
dev->usageCount++;
VIR_DEBUG("Using physical device %s, usageCount %d",
- dev->dev, dev->usageCount);
+ dev->device.dev, dev->usageCount);
}
ret = 0;
@@ -3165,7 +3165,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
virNetworkForwardIfDefPtr dev = NULL;
for (ii = 0; ii < netdef->nForwardIfs; ii++) {
- if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) {
+ if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) {
dev = &netdef->forwardIfs[ii];
break;
}
@@ -3180,7 +3180,7 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
dev->usageCount--;
VIR_DEBUG("Releasing physical device %s, usageCount %d",
- dev->dev, dev->usageCount);
+ dev->device.dev, dev->usageCount);
}
ret = 0;
@@ -3261,7 +3261,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr)
case VIR_NETWORK_FORWARD_VEPA:
case VIR_NETWORK_FORWARD_PASSTHROUGH:
if ((netdef->nForwardIfs > 0) && netdef->forwardIfs)
- dev_name = netdef->forwardIfs[0].dev;
+ dev_name = netdef->forwardIfs[0].device.dev;
if (!dev_name) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
diff --git a/tests/networkxml2xmlin/hostdev-pf.xml
b/tests/networkxml2xmlin/hostdev-pf.xml
new file mode 100644
index 0000000..e07db69
--- /dev/null
+++ b/tests/networkxml2xmlin/hostdev-pf.xml
@@ -0,0 +1,11 @@
+<network>
+ <name>hostdev</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward mode="hostdev" managed="yes">
+ <pf dev='eth2'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='1'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='2'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='3'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='4'/>
+ </forward>
+</network>
diff --git a/tests/networkxml2xmlin/hostdev.xml b/tests/networkxml2xmlin/hostdev.xml
new file mode 100644
index 0000000..0ec52d2
--- /dev/null
+++ b/tests/networkxml2xmlin/hostdev.xml
@@ -0,0 +1,10 @@
+<network>
+ <name>hostdev</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward mode="hostdev" managed="yes">
+ <address type='pci' domain='0' bus='3' slot='0'
function='1'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='2'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='3'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='4'/>
+ </forward>
+</network>
diff --git a/tests/networkxml2xmlout/hostdev-pf.xml
b/tests/networkxml2xmlout/hostdev-pf.xml
new file mode 100644
index 0000000..e955312
--- /dev/null
+++ b/tests/networkxml2xmlout/hostdev-pf.xml
@@ -0,0 +1,7 @@
+<network>
+ <name>hostdev</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward mode="hostdev" managed="yes">
+ <pf dev='eth2'/>
+ </forward>
+</network>
diff --git a/tests/networkxml2xmlout/hostdev.xml b/tests/networkxml2xmlout/hostdev.xml
new file mode 100644
index 0000000..0ec52d2
--- /dev/null
+++ b/tests/networkxml2xmlout/hostdev.xml
@@ -0,0 +1,10 @@
+<network>
+ <name>hostdev</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward mode="hostdev" managed="yes">
+ <address type='pci' domain='0' bus='3' slot='0'
function='1'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='2'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='3'/>
+ <address type='pci' domain='0' bus='3' slot='0'
function='4'/>
+ </forward>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index 8641c41..c9c8311 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -105,6 +105,8 @@ mymain(void)
DO_TEST("vepa-net");
DO_TEST("bandwidth-network");
DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE);
+ DO_TEST("hostdev");
+ DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.4.4