Until now at least one <tag> subelement was required for a <vlan> element. An optional trunk='yes' attribute can be used to indicate trunking of the given tags. This is not how VLAN tagging works with ESX. One can either specify a single VLAN tag per virtual network or enable trunking for all possible VLAN tags. It is not possible to limit trunking to a subset of tags. This cannot be represented properly with the current network config format. This patch removes the requirement for at least on tag per <vlan> element and adapts all related code to deal with the new situation. --- docs/formatnetwork.html.in | 8 +++- docs/schemas/networkcommon.rng | 4 +- src/conf/domain_conf.c | 6 ++- src/conf/netdev_vlan_conf.c | 58 ++++++++++++++++++++--------------- src/network/bridge_driver.c | 28 +++++++++++++++++ src/util/virnetdevopenvswitch.c | 9 ++++- src/util/virnetdevvlan.c | 8 ++++- tests/networkxml2xmlin/esx-net.xml | 15 +++++++++ tests/networkxml2xmlout/esx-net.xml | 15 +++++++++ tests/networkxml2xmltest.c | 1 + 10 files changed, 118 insertions(+), 34 deletions(-) create mode 100644 tests/networkxml2xmlin/esx-net.xml create mode 100644 tests/networkxml2xmlout/esx-net.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 49206dd..5d601e1 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -398,7 +398,7 @@ transparent to the guest, an optional <code><vlan></code> element can specify one or more vlan tags to apply to the traffic of all guests using this - network <span class="since">Since 0.10.0</span>. (openvswitch + network <span class="since">since 0.10.0</span>. (openvswitch and type='hostdev' SR-IOV networks do support transparent vlan tagging of guest traffic; everything else, including standard linux bridges and libvirt's own virtual networks, <b>do not</b> @@ -410,7 +410,11 @@ assumed that the user wants to do VLAN trunking using all the specified tags. In the case that vlan trunking with a single tag is desired, the optional attribute <code>trunk='yes'</code> can - be added to the vlan element. + be added to the vlan element. <span class="since">Since 0.10.3</span> + <code>trunk='yes'</code> can be set while specifing no + <code><vlan></code> elements at all to indicate trunking of all + available vlan tags. This is supported by ESX only and is the only + trunking mode that ESX supports. </p> <p> <code><vlan></code> elements can also be specified in diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng index c7749e7..70cdcbb 100644 --- a/docs/schemas/networkcommon.rng +++ b/docs/schemas/networkcommon.rng @@ -192,7 +192,7 @@ <value>yes</value> </attribute> </optional> - <oneOrMore> + <zeroOrMore> <element name="tag"> <attribute name="id"> <data type="unsignedInt"> @@ -201,7 +201,7 @@ </attribute> <empty/> </element> - </oneOrMore> + </zeroOrMore> </element> </define> </grammar> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 33e1e7f..65a201c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -14897,9 +14897,11 @@ virDomainNetGetActualVlan(virDomainNetDefPtr iface) { if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK && iface->data.network.actual && - iface->data.network.actual->vlan.nTags > 0) + (iface->data.network.actual->vlan.nTags > 0 || + iface->data.network.actual->vlan.trunk)) return &iface->data.network.actual->vlan; - if (iface->vlan.nTags > 0) + if (iface->vlan.nTags > 0 || + iface->vlan.trunk) return &iface->vlan; return 0; } diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c index 6a0511a..8f9aa04 100644 --- a/src/conf/netdev_vlan_conf.c +++ b/src/conf/netdev_vlan_conf.c @@ -42,33 +42,28 @@ virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr ctxt, virNetDevVlanPtr de if (nTags < 0) goto error; - if (nTags == 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing tag id - each <vlan> must have " - "at least one <tag id='n'/> subelement")); - goto error; - } - - if (VIR_ALLOC_N(def->tag, nTags) < 0) { - virReportOOMError(); - goto error; - } - - for (ii = 0; ii < nTags; ii++) { - unsigned long id; - - ctxt->node = tagNodes[ii]; - if (virXPathULong("string(./@id)", ctxt, &id) < 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing or invalid vlan tag id attribute")); + if (nTags > 0) { + if (VIR_ALLOC_N(def->tag, nTags) < 0) { + virReportOOMError(); goto error; } - if (id > 4095) { - virReportError(VIR_ERR_XML_ERROR, - _("vlan tag id %lu too large (maximum 4095)"), id); - goto error; + + for (ii = 0; ii < nTags; ii++) { + unsigned long id; + + ctxt->node = tagNodes[ii]; + if (virXPathULong("string(./@id)", ctxt, &id) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid vlan tag id attribute")); + goto error; + } + if (id > 4095) { + virReportError(VIR_ERR_XML_ERROR, + _("vlan tag id %lu too large (maximum 4095)"), id); + goto error; + } + def->tag[ii] = id; } - def->tag[ii] = id; } def->nTags = nTags; @@ -99,6 +94,14 @@ virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr ctxt, virNetDevVlanPtr de } } + /* only in trunk mode the tag subelements can be omitted */ + if (!def->trunk && nTags == 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid element - each <vlan> must have at least " + "one <tag id='n'/> subelement and/or \"trunk='yes'\"")); + goto error; + } + ret = 0; error: ctxt->node = save; @@ -113,8 +116,13 @@ virNetDevVlanFormat(virNetDevVlanPtr def, virBufferPtr buf) { int ii; - if (def->nTags == 0) + if (def->nTags == 0) { + if (def->trunk) { + virBufferAddLit(buf, "<vlan trunk='yes'/>\n"); + } + return 0; + } if (!def->tag) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index e1846ee..37ddb07 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2616,6 +2616,14 @@ networkValidate(virNetworkDefPtr def) int ii; bool vlanUsed, vlanAllowed; + if (def->vlan.nTags == 0 && def->vlan.trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("<vlan> element specified for network %s is missing at " + "least one <tag> subelement required for trunk mode"), + def->name); + return -1; + } + /* The only type of networks that currently support transparent * vlan configuration are those using hostdev sr-iov devices from * a pool, and those using an Open vSwitch bridge. @@ -2627,6 +2635,13 @@ networkValidate(virNetworkDefPtr def) vlanUsed = def->vlan.nTags > 0; for (ii = 0; ii < def->nPortGroups && !(vlanUsed && vlanAllowed); ii++) { + if (def->portGroups[ii].vlan.nTags == 0 && def->portGroups[ii].vlan.trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("<vlan> element specified for portgroup %s of network %s " + "is missing at least one <tag> subelement required for trunk mode"), + def->portGroups[ii].name, def->name); + return -1; + } if (def->portGroups[ii].vlan.nTags > 0) vlanUsed = true; if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE && @@ -3352,6 +3367,8 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) /* it's handy to have this initialized if we skip directly to validate */ if (iface->vlan.nTags > 0) vlan = &iface->vlan; + else if (iface->vlan.trunk) + goto trunk_error; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) goto validate; @@ -3627,10 +3644,16 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) /* copy appropriate vlan info to actualNet */ if (iface->vlan.nTags > 0) vlan = &iface->vlan; + else if (iface->vlan.trunk) + goto trunk_error; else if (portgroup && portgroup->vlan.nTags > 0) vlan = &portgroup->vlan; + else if (portgroup && portgroup->vlan.trunk) + goto trunk_error; else if (netdef && netdef->vlan.nTags > 0) vlan = &netdef->vlan; + else if (netdef && netdef->vlan.trunk) + goto trunk_error; if (virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0) goto error; @@ -3699,6 +3722,11 @@ error: iface->data.network.actual = NULL; } goto cleanup; + +trunk_error: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vlan trunk mode without a tag is not supported")); + goto cleanup; } /* networkNotifyActualDevice: diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index a6993b6..3b29dcc 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -80,14 +80,19 @@ int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname, goto out_of_memory; } - if (virtVlan && virtVlan->nTags > 0) { + if (virtVlan && (virtVlan->nTags > 0 || virtVlan->trunk)) { + if (virtVlan->nTags == 0 && virtVlan->trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vlan trunk mode without a tag is not supported")); + goto cleanup; + } /* Trunk port first */ if (virtVlan->trunk) { virBufferAddLit(&buf, "trunk="); /* - * Trunk ports have at least one VLAN. Do the first one + * Trunk ports must have at least one VLAN. Do the first one * outside the "for" loop so we can put a "," at the * start of the for loop if there are more than one VLANs * on this trunk port. diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c index 7a6ff9b..4cf95dc 100644 --- a/src/util/virnetdevvlan.c +++ b/src/util/virnetdevvlan.c @@ -31,6 +31,7 @@ void virNetDevVlanClear(virNetDevVlanPtr vlan) { + vlan->trunk = false; VIR_FREE(vlan->tag); vlan->nTags = 0; } @@ -79,9 +80,14 @@ virNetDevVlanEqual(const virNetDevVlanPtr a, const virNetDevVlanPtr b) int virNetDevVlanCopy(virNetDevVlanPtr dst, const virNetDevVlanPtr src) { - if (!src || src->nTags == 0) + if (!src) return 0; + if (src->nTags == 0) { + dst->trunk = src->trunk; + return 0; + } + if (VIR_ALLOC_N(dst->tag, src->nTags) < 0) { virReportOOMError(); return -1; diff --git a/tests/networkxml2xmlin/esx-net.xml b/tests/networkxml2xmlin/esx-net.xml new file mode 100644 index 0000000..546c634 --- /dev/null +++ b/tests/networkxml2xmlin/esx-net.xml @@ -0,0 +1,15 @@ +<network> + <name>vSwitch0</name> + <uuid>2f467347-8b4e-8655-e7d6-c4c3fb968009</uuid> + <forward dev='vmnic0' mode='bridge'> + <interface dev='vmnic0'/> + </forward> + <portgroup name='Network1'> + <vlan trunk='yes'/> + </portgroup> + <portgroup name='Network2'> + <vlan> + <tag id='536'/> + </vlan> + </portgroup> +</network> diff --git a/tests/networkxml2xmlout/esx-net.xml b/tests/networkxml2xmlout/esx-net.xml new file mode 100644 index 0000000..546c634 --- /dev/null +++ b/tests/networkxml2xmlout/esx-net.xml @@ -0,0 +1,15 @@ +<network> + <name>vSwitch0</name> + <uuid>2f467347-8b4e-8655-e7d6-c4c3fb968009</uuid> + <forward dev='vmnic0' mode='bridge'> + <interface dev='vmnic0'/> + </forward> + <portgroup name='Network1'> + <vlan trunk='yes'/> + </portgroup> + <portgroup name='Network2'> + <vlan> + <tag id='536'/> + </vlan> + </portgroup> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index e57d190..426c541 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST_FULL("passthrough-pf", VIR_NETWORK_XML_INACTIVE); DO_TEST("hostdev"); DO_TEST_FULL("hostdev-pf", VIR_NETWORK_XML_INACTIVE); + DO_TEST("esx-net"); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.4.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list