[libvirt] [PATCH 0/2] Take 2 - live interface info + IPv6 interface config

This is similar to the (now deprecated) patches I sent on 9/28 and 10/04, but without the unpopular "source" attribute in the ip address. You can successfully build libvirt if you have the latest release of netcf installed, but you'll need to get the netcf source, apply the patches in the thread listed below, and build/install netcf to get correct/proper output. https://fedorahosted.org/pipermail/netcf-devel/2009-October/000289.html

From: root <root@vlap.laine.org> This patch adds the flag VIR_INTERFACE_XML_INACTIVE to virInterfaceGetXMLDesc's flags. When it is*not* set (the default), the live interface info will be returned in the XML (in particular, the IP address(es) and netmask(s) will be retrieved by querying the interface directly, rather than reporting what's in the config file). The backend of this is in netcf's ncf_if_xml_state() function. Note that you need at least netcf 0.1.2 for this to work correctly. --- include/libvirt/libvirt.h.in | 4 +++ src/conf/interface_conf.c | 56 ++++++++++++++++++++--------------------- src/interface/netcf_driver.c | 8 ++++- src/libvirt.c | 15 ++++++++--- tools/virsh.c | 10 ++++++- 5 files changed, 56 insertions(+), 37 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 60be41b..a2ec6e9 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -923,6 +923,10 @@ virInterfacePtr virInterfaceLookupByMACString (virConnectPtr conn, const char* virInterfaceGetName (virInterfacePtr iface); const char* virInterfaceGetMACString (virInterfacePtr iface); +typedef enum { + VIR_INTERFACE_XML_INACTIVE = 1 /* dump inactive interface information */ +} virInterfaceXMLFlags; + char * virInterfaceGetXMLDesc (virInterfacePtr iface, unsigned int flags); virInterfacePtr virInterfaceDefineXML (virConnectPtr conn, diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index e646351..a8f0ee0 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -282,22 +282,19 @@ virInterfaceDefParseIp(virConnectPtr conn, virInterfaceDefPtr def, static int virInterfaceDefParseProtoIPv4(virConnectPtr conn, virInterfaceDefPtr def, xmlXPathContextPtr ctxt) { - xmlNodePtr cur; - int ret; + xmlNodePtr dhcp, ip; + int ret = 0; - cur = virXPathNode(conn, "./dhcp", ctxt); - if (cur != NULL) - ret = virInterfaceDefParseDhcp(conn, def, cur, ctxt); - else { - cur = virXPathNode(conn, "./ip", ctxt); - if (cur != NULL) - ret = virInterfaceDefParseIp(conn, def, cur, ctxt); - else { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("interface miss dhcp or ip adressing")); - ret = -1; - } - } + dhcp = virXPathNode(conn, "./dhcp", ctxt); + if (dhcp != NULL) + ret = virInterfaceDefParseDhcp(conn, def, dhcp, ctxt); + + if (ret != 0) + return(ret); + + ip = virXPathNode(conn, "./ip", ctxt); + if (ip != NULL) + ret = virInterfaceDefParseIp(conn, def, ip, ctxt); return(ret); } @@ -1005,6 +1002,7 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { + char prefixStr[16]; if (def->proto.family == NULL) return(0); virBufferVSprintf(buf, " <protocol family='%s'>\n", def->proto.family); @@ -1015,20 +1013,20 @@ virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); else virBufferAddLit(buf, " <dhcp/>\n"); - } else { - /* theorically if we don't have dhcp we should have an address */ - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - virBufferVSprintf(buf, " <ip address='%s' prefix='%d'/>\n", - def->proto.address, def->proto.prefix); - else - virBufferVSprintf(buf, " <ip address='%s'/>\n", - def->proto.address); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, " <route gateway='%s'/>\n", - def->proto.gateway); - } + } + if (def->proto.address != NULL) { + if (def->proto.prefix != 0) + snprintf(prefixStr, sizeof(prefixStr), "%d", def->proto.prefix); + + virBufferVSprintf(buf, " <ip address='%s'%s%s%s%s%s%s/>\n", + def->proto.address, + def->proto.prefix ? " prefix='" : "", + def->proto.prefix ? prefixStr : "", + def->proto.prefix ? "'" : ""); + } + if (def->proto.gateway != NULL) { + virBufferVSprintf(buf, " <route gateway='%s'/>\n", + def->proto.gateway); } virBufferAddLit(buf, " </protocol>\n"); return(0); diff --git a/src/interface/netcf_driver.c b/src/interface/netcf_driver.c index ca14fb0..b5c3664 100644 --- a/src/interface/netcf_driver.c +++ b/src/interface/netcf_driver.c @@ -326,7 +326,7 @@ cleanup: } static char *interfaceGetXMLDesc(virInterfacePtr ifinfo, - unsigned int flags ATTRIBUTE_UNUSED) + unsigned int flags) { struct interface_driver *driver = ifinfo->conn->interfacePrivateData; struct netcf_if *iface = NULL; @@ -342,7 +342,11 @@ static char *interfaceGetXMLDesc(virInterfacePtr ifinfo, goto cleanup; } - xmlstr = ncf_if_xml_desc(iface); + if ((flags & VIR_INTERFACE_XML_INACTIVE)) { + xmlstr = ncf_if_xml_desc(iface); + } else { + xmlstr = ncf_if_xml_state(iface); + } if (!xmlstr) { const char *errmsg, *details; int errcode = ncf_error(driver->netcf, &errmsg, &details); diff --git a/src/libvirt.c b/src/libvirt.c index 1ed4804..fee1eae 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6050,10 +6050,17 @@ virInterfaceGetMACString(virInterfacePtr iface) /** * virInterfaceGetXMLDesc: * @iface: an interface object - * @flags: an OR'ed set of extraction flags, not used yet + * @flags: an OR'ed set of extraction flags. Current valid bits: + * + * VIR_INTERFACE_XML_INACTIVE - return the static configuration, + * suitable for use redefining the + * interface via virInterfaceDefineXML() * - * Provide an XML description of the interface. The description may be reused - * later to redefine the interface with virInterfaceDefineXML(). + * Provide an XML description of the interface. If + * VIR_INTERFACE_XML_INACTIVE is set, the description may be reused + * later to redefine the interface with virInterfaceDefineXML(). If it + * is not set, the ip address and netmask will be the current live + * setting of the interface, not the settings from the config files. * * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error. * the caller must free() the returned value. @@ -6070,7 +6077,7 @@ virInterfaceGetXMLDesc(virInterfacePtr iface, unsigned int flags) virLibInterfaceError(NULL, VIR_ERR_INVALID_INTERFACE, __FUNCTION__); return (NULL); } - if (flags != 0) { + if ((flags & ~VIR_INTERFACE_XML_INACTIVE) != 0) { virLibInterfaceError(iface, VIR_ERR_INVALID_ARG, __FUNCTION__); goto error; } diff --git a/tools/virsh.c b/tools/virsh.c index 2222269..e6abd5b 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2783,7 +2783,7 @@ cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd) char *doc = NULL; char *doc_edited = NULL; char *doc_reread = NULL; - int flags = 0; + int flags = VIR_INTERFACE_XML_INACTIVE; if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) goto cleanup; @@ -3317,6 +3317,7 @@ static const vshCmdInfo info_interface_dumpxml[] = { static const vshCmdOptDef opts_interface_dumpxml[] = { {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {"inactive", VSH_OT_BOOL, 0, gettext_noop("show inactive defined XML")}, {NULL, 0, 0, NULL} }; @@ -3326,6 +3327,11 @@ cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) virInterfacePtr iface; int ret = TRUE; char *dump; + int flags = 0; + int inactive = vshCommandOptBool(cmd, "inactive"); + + if (inactive) + flags |= VIR_INTERFACE_XML_INACTIVE; if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -3333,7 +3339,7 @@ cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) if (!(iface = vshCommandOptInterface(ctl, cmd, NULL))) return FALSE; - dump = virInterfaceGetXMLDesc(iface, 0); + dump = virInterfaceGetXMLDesc(iface, flags); if (dump != NULL) { printf("%s", dump); free(dump); -- 1.6.2.5

On Wed, Oct 07, 2009 at 10:05:40AM -0400, Laine Stump wrote:
From: root <root@vlap.laine.org>
This patch adds the flag VIR_INTERFACE_XML_INACTIVE to virInterfaceGetXMLDesc's flags. When it is*not* set (the default), the live interface info will be returned in the XML (in particular, the IP address(es) and netmask(s) will be retrieved by querying the interface directly, rather than reporting what's in the config file). The backend of this is in netcf's ncf_if_xml_state() function.
Note that you need at least netcf 0.1.2 for this to work correctly.
The configure.ac pkgconfig check for netcf should be updated to match the new minimal requirement here, otherwise people will get a compile error, rather than a clear message about required version. Similarly for the BuildRequires in libvirt.spec.in
@@ -1005,6 +1002,7 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { + char prefixStr[16]; if (def->proto.family == NULL) return(0); virBufferVSprintf(buf, " <protocol family='%s'>\n", def->proto.family); @@ -1015,20 +1013,20 @@ virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); else virBufferAddLit(buf, " <dhcp/>\n"); - } else { - /* theorically if we don't have dhcp we should have an address */ - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - virBufferVSprintf(buf, " <ip address='%s' prefix='%d'/>\n", - def->proto.address, def->proto.prefix); - else - virBufferVSprintf(buf, " <ip address='%s'/>\n", - def->proto.address); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, " <route gateway='%s'/>\n", - def->proto.gateway); - } + } + if (def->proto.address != NULL) { + if (def->proto.prefix != 0) + snprintf(prefixStr, sizeof(prefixStr), "%d", def->proto.prefix); + + virBufferVSprintf(buf, " <ip address='%s'%s%s%s%s%s%s/>\n", + def->proto.address, + def->proto.prefix ? " prefix='" : "", + def->proto.prefix ? prefixStr : "", + def->proto.prefix ? "'" : ""); + }
This is a rather unreadable way to format the XML, and has a rather redundant extra snprintf call there. I think it'd look better as virBufferVSprintf(buf, " <ip address='%s'", def->proto.address); if (def->proto.prefix) virBufferVSprintf(buf, " prefix='%d'", def->proto.prefix); virBufferVSprintf(buf, "/>\n"); But should prefix really be optional ? You really need a prefix to meaningfully interpret an address. If it is left out of the original sysconfig file in /etc/sysconfig/network-scripts, there are defined default values that should be used. IMHO, libvirt output XML should always include the prefix, otherwise applications all have to add the logic to calculate default prefix values themselves. So I'd prefer to see prefix mandatory in the XML we output, optional in the XML we accept for input. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On 10/08/2009 06:25 AM, Daniel P. Berrange wrote:
On Wed, Oct 07, 2009 at 10:05:40AM -0400, Laine Stump wrote:
From: root<root@vlap.laine.org>
This patch adds the flag VIR_INTERFACE_XML_INACTIVE to virInterfaceGetXMLDesc's flags. When it is*not* set (the default), the live interface info will be returned in the XML (in particular, the IP address(es) and netmask(s) will be retrieved by querying the interface directly, rather than reporting what's in the config file). The backend of this is in netcf's ncf_if_xml_state() function.
Note that you need at least netcf 0.1.2 for this to work correctly.
The configure.ac pkgconfig check for netcf should be updated to match the new minimal requirement here, otherwise people will get a compile error, rather than a clear message about required version. Similarly for the BuildRequires in libvirt.spec.in
And I'm not even sure why I didn't go ahead and do that :-P. I guess the netcf release wasn't done yet when I first packaged up the patches, and I didn't think to go back and do it once the release was made.
@@ -1005,6 +1002,7 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { + char prefixStr[16]; if (def->proto.family == NULL) return(0); virBufferVSprintf(buf, "<protocol family='%s'>\n", def->proto.family); @@ -1015,20 +1013,20 @@ virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferAddLit(buf, "<dhcp peerdns='yes'/>\n"); else virBufferAddLit(buf, "<dhcp/>\n"); - } else { - /* theorically if we don't have dhcp we should have an address */ - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - virBufferVSprintf(buf, "<ip address='%s' prefix='%d'/>\n", - def->proto.address, def->proto.prefix); - else - virBufferVSprintf(buf, "<ip address='%s'/>\n", - def->proto.address); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, "<route gateway='%s'/>\n", - def->proto.gateway); - } + } + if (def->proto.address != NULL) { + if (def->proto.prefix != 0) + snprintf(prefixStr, sizeof(prefixStr), "%d", def->proto.prefix); + + virBufferVSprintf(buf, "<ip address='%s'%s%s%s%s%s%s/>\n", + def->proto.address, + def->proto.prefix ? " prefix='" : "", + def->proto.prefix ? prefixStr : "", + def->proto.prefix ? "'" : ""); + }
This is a rather unreadable way to format the XML, and has a rather redundant extra snprintf call there. I think it'd look better as
virBufferVSprintf(buf, "<ip address='%s'", def->proto.address); if (def->proto.prefix) virBufferVSprintf(buf, " prefix='%d'", def->proto.prefix); virBufferVSprintf(buf, "/>\n");
Yeah, I had made the same decision and changed it to pretty much what you suggest in [PATCH 2/2], but didn't redo this first patch because it was getting immediately overridden anyway and I didn't want to deal with the merge conflict. I'll redo it in the next iteration though, so there won't be any snapshot of code available that's unsightly ;-)
But should prefix really be optional ?
Sure. RFC something-or-other-from-eons-ago-before-CIDR spells out the netmask to use when one isn't specified for any given IP address (class A, B, C). Certainly you can give ifconfig an IP with no netmask/prefix and it will do the right thing.
You really need a prefix to meaningfully interpret an address. If it is left out of the original sysconfig file in /etc/sysconfig/network-scripts, there are defined default values that should be used. IMHO, libvirt output XML should always include the prefix, otherwise applications all have to add the logic to calculate default prefix values themselves. So I'd prefer to see prefix mandatory in the XML we output, optional in the XML we accept for input.
Okay, that sounds reasonable.

This patch updates the xml parsing and formatting, and the associated virInterfaceDef data structure to support IPv6, along the way adding support for multiple protocols per interface, and multiple IP addresses per protocol. --- src/conf/interface_conf.c | 295 ++++++++++++++++++++++++++++++++++----------- src/conf/interface_conf.h | 19 ++- 2 files changed, 239 insertions(+), 75 deletions(-) diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index a8f0ee0..b1926c1 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -53,9 +53,31 @@ void virInterfaceBareDefFree(virInterfaceBareDefPtr def) { VIR_FREE(def); } +static +void virInterfaceIpDefFree(virInterfaceIpDefPtr def) { + if (def == NULL) + return; + VIR_FREE(def->address); +} + +static +void virInterfaceProtocolDefFree(virInterfaceProtocolDefPtr def) { + int ii; + + if (def == NULL) + return; + for (ii = 0; ii < def->nips; ii++) { + virInterfaceIpDefFree(def->ips[ii]); + } + VIR_FREE(def->ips); + VIR_FREE(def->family); + VIR_FREE(def->gateway); + VIR_FREE(def); +} + void virInterfaceDefFree(virInterfaceDefPtr def) { - int i; + int i, pp; if (def == NULL) return; @@ -89,10 +111,11 @@ void virInterfaceDefFree(virInterfaceDefPtr def) break; } - VIR_FREE(def->proto.family); - VIR_FREE(def->proto.address); - VIR_FREE(def->proto.gateway); - + /* free all protos */ + for (pp = 0; pp < def->nprotos; pp++) { + virInterfaceProtocolDefFree(def->protos[pp]); + } + VIR_FREE(def->protos); VIR_FREE(def); } @@ -225,22 +248,22 @@ virInterfaceDefParseBondArpValid(virConnectPtr conn, xmlXPathContextPtr ctxt) { } static int -virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceDefPtr def, +virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceProtocolDefPtr def, xmlNodePtr dhcp, xmlXPathContextPtr ctxt) { xmlNodePtr save; char *tmp; int ret = 0; - def->proto.dhcp = 1; + def->dhcp = 1; save = ctxt->node; ctxt->node = dhcp; /* Not much to do in the current version */ tmp = virXPathString(conn, "string(./@peerdns)", ctxt); if (tmp) { if (STREQ(tmp, "yes")) - def->proto.peerdns = 1; + def->peerdns = 1; else if (STREQ(tmp, "no")) - def->proto.peerdns = 0; + def->peerdns = 0; else { virInterfaceReportError(conn, VIR_ERR_XML_ERROR, _("unknown dhcp peerdns value %s"), tmp); @@ -248,86 +271,207 @@ virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceDefPtr def, } VIR_FREE(tmp); } else - def->proto.peerdns = -1; + def->peerdns = -1; ctxt->node = save; return(ret); } static int -virInterfaceDefParseIp(virConnectPtr conn, virInterfaceDefPtr def, - xmlNodePtr ip ATTRIBUTE_UNUSED, xmlXPathContextPtr ctxt) { +virInterfaceDefParseIp(virConnectPtr conn, virInterfaceIpDefPtr def, + xmlXPathContextPtr ctxt) { int ret = 0; char *tmp; long l; - tmp = virXPathString(conn, "string(./ip[1]/@address)", ctxt); - def->proto.address = tmp; + tmp = virXPathString(conn, "string(./@address)", ctxt); + def->address = tmp; if (tmp != NULL) { - ret = virXPathLong(conn, "string(./ip[1]/@prefix)", ctxt, &l); + ret = virXPathLong(conn, "string(./@prefix)", ctxt, &l); if (ret == 0) - def->proto.prefix = (int) l; + def->prefix = (int) l; else if (ret == -2) { virInterfaceReportError(conn, VIR_ERR_XML_ERROR, "%s", _("Invalid ip address prefix value")); return(-1); } } - tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); - def->proto.gateway = tmp; return(0); } static int -virInterfaceDefParseProtoIPv4(virConnectPtr conn, virInterfaceDefPtr def, +virInterfaceDefParseProtoIPv4(virConnectPtr conn, virInterfaceProtocolDefPtr def, xmlXPathContextPtr ctxt) { - xmlNodePtr dhcp, ip; - int ret = 0; + xmlNodePtr dhcp; + xmlNodePtr *ipNodes = NULL; + int nIpNodes, ii, ret = 0; + char *tmp; + + tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); + def->gateway = tmp; dhcp = virXPathNode(conn, "./dhcp", ctxt); if (dhcp != NULL) ret = virInterfaceDefParseDhcp(conn, def, dhcp, ctxt); + if (ret != 0) + return(ret); + + nIpNodes = virXPathNodeSet(conn, "./ip", ctxt, &ipNodes); + if (ipNodes == NULL) + return 0; + + if (VIR_ALLOC_N(def->ips, nIpNodes) < 0) { + virReportOOMError(conn); + ret = -1; + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) { + virInterfaceIpDefPtr ip; + + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + break; + } + def->ips[def->nips++] = ip; + } + +error: + VIR_FREE(ipNodes); + return(ret); +} + +static int +virInterfaceDefParseProtoIPv6(virConnectPtr conn, virInterfaceProtocolDefPtr def, + xmlXPathContextPtr ctxt) { + xmlNodePtr dhcp, autoconf; + xmlNodePtr *ipNodes = NULL; + int nIpNodes, ii, ret = 0; + char *tmp; + + tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); + def->gateway = tmp; + + autoconf = virXPathNode(conn, "./autoconf", ctxt); + if (autoconf != NULL) + def->autoconf = 1; + + dhcp = virXPathNode(conn, "./dhcp", ctxt); + if (dhcp != NULL) + ret = virInterfaceDefParseDhcp(conn, def, dhcp, ctxt); if (ret != 0) return(ret); - ip = virXPathNode(conn, "./ip", ctxt); - if (ip != NULL) - ret = virInterfaceDefParseIp(conn, def, ip, ctxt); + nIpNodes = virXPathNodeSet(conn, "./ip", ctxt, &ipNodes); + if (ipNodes == NULL) + return 0; + + if (VIR_ALLOC_N(def->ips, nIpNodes) < 0) { + virReportOOMError(conn); + ret = -1; + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) { + + virInterfaceIpDefPtr ip; + + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + break; + } + def->ips[def->nips++] = ip; + } + +error: + VIR_FREE(ipNodes); return(ret); } static int virInterfaceDefParseIfAdressing(virConnectPtr conn, virInterfaceDefPtr def, xmlXPathContextPtr ctxt) { - xmlNodePtr cur, save; - int ret; + xmlNodePtr save; + xmlNodePtr *protoNodes = NULL; + int nProtoNodes, pp, ret = 0; char *tmp; - cur = virXPathNode(conn, "./protocol[1]", ctxt); - if (cur == NULL) - return(0); save = ctxt->node; - ctxt->node = cur; - tmp = virXPathString(conn, "string(./@family)", ctxt); - if (tmp == NULL) { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("protocol misses the family attribute")); - ret = -1; - goto done; + + nProtoNodes = virXPathNodeSet(conn, "./protocol", ctxt, &protoNodes); + if (nProtoNodes <= 0) { + /* no protocols is an acceptable outcome */ + return 0; } - if (STREQ(tmp, "ipv4")) { - def->proto.family = tmp; - ret = virInterfaceDefParseProtoIPv4(conn, def, ctxt); - } else { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - _("unsupported protocol family '%s'"), tmp); + + if (VIR_ALLOC_N(def->protos, nProtoNodes) < 0) { + virReportOOMError(conn); ret = -1; - VIR_FREE(tmp); + goto error; } -done: + def->nprotos = 0; + for (pp = 0; pp < nProtoNodes; pp++) { + + virInterfaceProtocolDefPtr proto; + + if (VIR_ALLOC(proto) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = protoNodes[pp]; + tmp = virXPathString(conn, "string(./@family)", ctxt); + if (tmp == NULL) { + virInterfaceReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("protocol misses the family attribute")); + virInterfaceProtocolDefFree(proto); + ret = -1; + break; + } + proto->family = tmp; + if (STREQ(tmp, "ipv4")) { + ret = virInterfaceDefParseProtoIPv4(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + break; + } + } else if (STREQ(tmp, "ipv6")) { + ret = virInterfaceDefParseProtoIPv6(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + break; + } + } else { + virInterfaceReportError(conn, VIR_ERR_XML_ERROR, + _("unsupported protocol family '%s'"), tmp); + ret = -1; + virInterfaceProtocolDefFree(proto); + break; + } + def->protos[def->nprotos++] = proto; + } + +error: + VIR_FREE(protoNodes); ctxt->node = save; return(ret); @@ -1002,33 +1146,44 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { - char prefixStr[16]; - if (def->proto.family == NULL) - return(0); - virBufferVSprintf(buf, " <protocol family='%s'>\n", def->proto.family); - if (def->proto.dhcp) { - if (def->proto.peerdns == 0) - virBufferAddLit(buf, " <dhcp peerdns='no'/>\n"); - else if (def->proto.peerdns == 1) - virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); - else - virBufferAddLit(buf, " <dhcp/>\n"); - } - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - snprintf(prefixStr, sizeof(prefixStr), "%d", def->proto.prefix); - - virBufferVSprintf(buf, " <ip address='%s'%s%s%s%s%s%s/>\n", - def->proto.address, - def->proto.prefix ? " prefix='" : "", - def->proto.prefix ? prefixStr : "", - def->proto.prefix ? "'" : ""); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, " <route gateway='%s'/>\n", - def->proto.gateway); + int pp, ii; + + for (pp = 0; pp < def->nprotos; pp++) { + + virBufferVSprintf(buf, " <protocol family='%s'>\n", def->protos[pp]->family); + + if (def->protos[pp]->autoconf) { + virBufferAddLit(buf, " <autoconf/>\n"); + } + + if (def->protos[pp]->dhcp) { + if (def->protos[pp]->peerdns == 0) + virBufferAddLit(buf, " <dhcp peerdns='no'/>\n"); + else if (def->protos[pp]->peerdns == 1) + virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); + else + virBufferAddLit(buf, " <dhcp/>\n"); + } + + for (ii = 0; ii < def->protos[pp]->nips; ii++) { + if (def->protos[pp]->ips[ii]->address != NULL) { + + virBufferVSprintf(buf, " <ip address='%s'", + def->protos[pp]->ips[ii]->address); + if (def->protos[pp]->ips[ii]->prefix != 0) { + virBufferVSprintf(buf, " prefix='%d'", + def->protos[pp]->ips[ii]->prefix); + } + virBufferAddLit(buf, "/>\n"); + } + } + if (def->protos[pp]->gateway != NULL) { + virBufferVSprintf(buf, " <route gateway='%s'/>\n", + def->protos[pp]->gateway); + } + + virBufferAddLit(buf, " </protocol>\n"); } - virBufferAddLit(buf, " </protocol>\n"); return(0); } diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index bb9dce4..50c07c8 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -123,14 +123,23 @@ struct _virInterfaceVlanDef { char *devname; /* device name for vlan */ }; +typedef struct _virInterfaceIpDef virInterfaceIpDef; +typedef virInterfaceIpDef *virInterfaceIpDefPtr; +struct _virInterfaceIpDef { + char *address; /* ip address */ + int prefix; /* ip prefix */ +}; + + typedef struct _virInterfaceProtocolDef virInterfaceProtocolDef; typedef virInterfaceProtocolDef *virInterfaceProtocolDefPtr; struct _virInterfaceProtocolDef { - char *family; /* ipv4 only right now */ + char *family; /* ipv4 or ipv6 */ int dhcp; /* use dhcp */ int peerdns; /* dhcp peerdns ? */ - char *address; /* ip address */ - int prefix; /* ip prefix */ + int autoconf; /* only useful if family is ipv6 */ + int nips; + virInterfaceIpDefPtr *ips; /* ptr to array of ips[nips] */ char *gateway; /* route gateway */ }; @@ -151,8 +160,8 @@ struct _virInterfaceDef { virInterfaceBondDef bond; } data; - /* separated as we may allow multiple of those in the future */ - virInterfaceProtocolDef proto; + int nprotos; + virInterfaceProtocolDefPtr *protos; /* ptr to array of protos[nprotos] */ }; typedef struct _virInterfaceObj virInterfaceObj; -- 1.6.2.5

On Wed, Oct 07, 2009 at 10:05:41AM -0400, Laine Stump wrote:
This patch updates the xml parsing and formatting, and the associated virInterfaceDef data structure to support IPv6, along the way adding support for multiple protocols per interface, and multiple IP addresses per protocol. --- src/conf/interface_conf.c | 295 ++++++++++++++++++++++++++++++++++----------- src/conf/interface_conf.h | 19 ++- 2 files changed, 239 insertions(+), 75 deletions(-)
diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index a8f0ee0..b1926c1 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -53,9 +53,31 @@ void virInterfaceBareDefFree(virInterfaceBareDefPtr def) { VIR_FREE(def); }
+static +void virInterfaceIpDefFree(virInterfaceIpDefPtr def) { + if (def == NULL) + return; + VIR_FREE(def->address); +} + +static +void virInterfaceProtocolDefFree(virInterfaceProtocolDefPtr def) { + int ii; + + if (def == NULL) + return; + for (ii = 0; ii < def->nips; ii++) { + virInterfaceIpDefFree(def->ips[ii]); + } + VIR_FREE(def->ips); + VIR_FREE(def->family); + VIR_FREE(def->gateway); + VIR_FREE(def); +} + void virInterfaceDefFree(virInterfaceDefPtr def) { - int i; + int i, pp;
if (def == NULL) return; @@ -89,10 +111,11 @@ void virInterfaceDefFree(virInterfaceDefPtr def) break; }
- VIR_FREE(def->proto.family); - VIR_FREE(def->proto.address); - VIR_FREE(def->proto.gateway); - + /* free all protos */ + for (pp = 0; pp < def->nprotos; pp++) { + virInterfaceProtocolDefFree(def->protos[pp]); + } + VIR_FREE(def->protos); VIR_FREE(def); }
@@ -225,22 +248,22 @@ virInterfaceDefParseBondArpValid(virConnectPtr conn, xmlXPathContextPtr ctxt) { }
static int -virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceDefPtr def, +virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceProtocolDefPtr def, xmlNodePtr dhcp, xmlXPathContextPtr ctxt) { xmlNodePtr save; char *tmp; int ret = 0;
- def->proto.dhcp = 1; + def->dhcp = 1; save = ctxt->node; ctxt->node = dhcp; /* Not much to do in the current version */ tmp = virXPathString(conn, "string(./@peerdns)", ctxt); if (tmp) { if (STREQ(tmp, "yes")) - def->proto.peerdns = 1; + def->peerdns = 1; else if (STREQ(tmp, "no")) - def->proto.peerdns = 0; + def->peerdns = 0; else { virInterfaceReportError(conn, VIR_ERR_XML_ERROR, _("unknown dhcp peerdns value %s"), tmp); @@ -248,86 +271,207 @@ virInterfaceDefParseDhcp(virConnectPtr conn, virInterfaceDefPtr def, } VIR_FREE(tmp); } else - def->proto.peerdns = -1; + def->peerdns = -1;
ctxt->node = save; return(ret); }
static int -virInterfaceDefParseIp(virConnectPtr conn, virInterfaceDefPtr def, - xmlNodePtr ip ATTRIBUTE_UNUSED, xmlXPathContextPtr ctxt) { +virInterfaceDefParseIp(virConnectPtr conn, virInterfaceIpDefPtr def, + xmlXPathContextPtr ctxt) { int ret = 0; char *tmp; long l;
- tmp = virXPathString(conn, "string(./ip[1]/@address)", ctxt); - def->proto.address = tmp; + tmp = virXPathString(conn, "string(./@address)", ctxt); + def->address = tmp; if (tmp != NULL) { - ret = virXPathLong(conn, "string(./ip[1]/@prefix)", ctxt, &l); + ret = virXPathLong(conn, "string(./@prefix)", ctxt, &l); if (ret == 0) - def->proto.prefix = (int) l; + def->prefix = (int) l; else if (ret == -2) { virInterfaceReportError(conn, VIR_ERR_XML_ERROR, "%s", _("Invalid ip address prefix value")); return(-1); } } - tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); - def->proto.gateway = tmp;
return(0); }
static int -virInterfaceDefParseProtoIPv4(virConnectPtr conn, virInterfaceDefPtr def, +virInterfaceDefParseProtoIPv4(virConnectPtr conn, virInterfaceProtocolDefPtr def, xmlXPathContextPtr ctxt) { - xmlNodePtr dhcp, ip; - int ret = 0; + xmlNodePtr dhcp; + xmlNodePtr *ipNodes = NULL; + int nIpNodes, ii, ret = 0; + char *tmp; + + tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); + def->gateway = tmp;
dhcp = virXPathNode(conn, "./dhcp", ctxt); if (dhcp != NULL) ret = virInterfaceDefParseDhcp(conn, def, dhcp, ctxt); + if (ret != 0) + return(ret); + + nIpNodes = virXPathNodeSet(conn, "./ip", ctxt, &ipNodes); + if (ipNodes == NULL) + return 0; + + if (VIR_ALLOC_N(def->ips, nIpNodes) < 0) { + virReportOOMError(conn); + ret = -1; + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) {
+ virInterfaceIpDefPtr ip; + + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + break; + } + def->ips[def->nips++] = ip; + } + +error: + VIR_FREE(ipNodes); + return(ret); +} + +static int +virInterfaceDefParseProtoIPv6(virConnectPtr conn, virInterfaceProtocolDefPtr def, + xmlXPathContextPtr ctxt) { + xmlNodePtr dhcp, autoconf; + xmlNodePtr *ipNodes = NULL; + int nIpNodes, ii, ret = 0; + char *tmp; + + tmp = virXPathString(conn, "string(./route[1]/@gateway)", ctxt); + def->gateway = tmp; + + autoconf = virXPathNode(conn, "./autoconf", ctxt); + if (autoconf != NULL) + def->autoconf = 1; + + dhcp = virXPathNode(conn, "./dhcp", ctxt); + if (dhcp != NULL) + ret = virInterfaceDefParseDhcp(conn, def, dhcp, ctxt); if (ret != 0) return(ret);
- ip = virXPathNode(conn, "./ip", ctxt); - if (ip != NULL) - ret = virInterfaceDefParseIp(conn, def, ip, ctxt); + nIpNodes = virXPathNodeSet(conn, "./ip", ctxt, &ipNodes); + if (ipNodes == NULL) + return 0; + + if (VIR_ALLOC_N(def->ips, nIpNodes) < 0) { + virReportOOMError(conn); + ret = -1; + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) { + + virInterfaceIpDefPtr ip; + + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + break; + } + def->ips[def->nips++] = ip; + } + +error: + VIR_FREE(ipNodes); return(ret); }
static int virInterfaceDefParseIfAdressing(virConnectPtr conn, virInterfaceDefPtr def, xmlXPathContextPtr ctxt) { - xmlNodePtr cur, save; - int ret; + xmlNodePtr save; + xmlNodePtr *protoNodes = NULL; + int nProtoNodes, pp, ret = 0; char *tmp;
- cur = virXPathNode(conn, "./protocol[1]", ctxt); - if (cur == NULL) - return(0); save = ctxt->node; - ctxt->node = cur; - tmp = virXPathString(conn, "string(./@family)", ctxt); - if (tmp == NULL) { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("protocol misses the family attribute")); - ret = -1; - goto done; + + nProtoNodes = virXPathNodeSet(conn, "./protocol", ctxt, &protoNodes); + if (nProtoNodes <= 0) { + /* no protocols is an acceptable outcome */ + return 0; } - if (STREQ(tmp, "ipv4")) { - def->proto.family = tmp; - ret = virInterfaceDefParseProtoIPv4(conn, def, ctxt); - } else { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - _("unsupported protocol family '%s'"), tmp); + + if (VIR_ALLOC_N(def->protos, nProtoNodes) < 0) { + virReportOOMError(conn); ret = -1; - VIR_FREE(tmp); + goto error; }
-done: + def->nprotos = 0; + for (pp = 0; pp < nProtoNodes; pp++) { + + virInterfaceProtocolDefPtr proto; + + if (VIR_ALLOC(proto) < 0) { + virReportOOMError(conn); + break; + } + + ctxt->node = protoNodes[pp]; + tmp = virXPathString(conn, "string(./@family)", ctxt); + if (tmp == NULL) { + virInterfaceReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("protocol misses the family attribute")); + virInterfaceProtocolDefFree(proto); + ret = -1; + break; + } + proto->family = tmp; + if (STREQ(tmp, "ipv4")) { + ret = virInterfaceDefParseProtoIPv4(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + break; + } + } else if (STREQ(tmp, "ipv6")) { + ret = virInterfaceDefParseProtoIPv6(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + break; + } + } else { + virInterfaceReportError(conn, VIR_ERR_XML_ERROR, + _("unsupported protocol family '%s'"), tmp); + ret = -1; + virInterfaceProtocolDefFree(proto); + break; + } + def->protos[def->nprotos++] = proto; + } + +error: + VIR_FREE(protoNodes); ctxt->node = save; return(ret);
@@ -1002,33 +1146,44 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { - char prefixStr[16]; - if (def->proto.family == NULL) - return(0); - virBufferVSprintf(buf, " <protocol family='%s'>\n", def->proto.family); - if (def->proto.dhcp) { - if (def->proto.peerdns == 0) - virBufferAddLit(buf, " <dhcp peerdns='no'/>\n"); - else if (def->proto.peerdns == 1) - virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); - else - virBufferAddLit(buf, " <dhcp/>\n"); - } - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - snprintf(prefixStr, sizeof(prefixStr), "%d", def->proto.prefix); - - virBufferVSprintf(buf, " <ip address='%s'%s%s%s%s%s%s/>\n", - def->proto.address, - def->proto.prefix ? " prefix='" : "", - def->proto.prefix ? prefixStr : "", - def->proto.prefix ? "'" : ""); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, " <route gateway='%s'/>\n", - def->proto.gateway); + int pp, ii; + + for (pp = 0; pp < def->nprotos; pp++) { + + virBufferVSprintf(buf, " <protocol family='%s'>\n", def->protos[pp]->family); + + if (def->protos[pp]->autoconf) { + virBufferAddLit(buf, " <autoconf/>\n"); + } + + if (def->protos[pp]->dhcp) { + if (def->protos[pp]->peerdns == 0) + virBufferAddLit(buf, " <dhcp peerdns='no'/>\n"); + else if (def->protos[pp]->peerdns == 1) + virBufferAddLit(buf, " <dhcp peerdns='yes'/>\n"); + else + virBufferAddLit(buf, " <dhcp/>\n"); + } + + for (ii = 0; ii < def->protos[pp]->nips; ii++) { + if (def->protos[pp]->ips[ii]->address != NULL) { + + virBufferVSprintf(buf, " <ip address='%s'", + def->protos[pp]->ips[ii]->address); + if (def->protos[pp]->ips[ii]->prefix != 0) { + virBufferVSprintf(buf, " prefix='%d'", + def->protos[pp]->ips[ii]->prefix); + } + virBufferAddLit(buf, "/>\n"); + } + } + if (def->protos[pp]->gateway != NULL) { + virBufferVSprintf(buf, " <route gateway='%s'/>\n", + def->protos[pp]->gateway); + } + + virBufferAddLit(buf, " </protocol>\n"); } - virBufferAddLit(buf, " </protocol>\n"); return(0); }
diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index bb9dce4..50c07c8 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -123,14 +123,23 @@ struct _virInterfaceVlanDef { char *devname; /* device name for vlan */ };
+typedef struct _virInterfaceIpDef virInterfaceIpDef; +typedef virInterfaceIpDef *virInterfaceIpDefPtr; +struct _virInterfaceIpDef { + char *address; /* ip address */ + int prefix; /* ip prefix */ +}; + + typedef struct _virInterfaceProtocolDef virInterfaceProtocolDef; typedef virInterfaceProtocolDef *virInterfaceProtocolDefPtr; struct _virInterfaceProtocolDef { - char *family; /* ipv4 only right now */ + char *family; /* ipv4 or ipv6 */ int dhcp; /* use dhcp */ int peerdns; /* dhcp peerdns ? */ - char *address; /* ip address */ - int prefix; /* ip prefix */ + int autoconf; /* only useful if family is ipv6 */ + int nips; + virInterfaceIpDefPtr *ips; /* ptr to array of ips[nips] */ char *gateway; /* route gateway */ };
@@ -151,8 +160,8 @@ struct _virInterfaceDef { virInterfaceBondDef bond; } data;
- /* separated as we may allow multiple of those in the future */ - virInterfaceProtocolDef proto; + int nprotos; + virInterfaceProtocolDefPtr *protos; /* ptr to array of protos[nprotos] */ };
ACK, looks reasonable to me Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

(Yes, you read the subject correctly - 3 of 2!) The minimal XML returned from ncf_if_xml_state() doesn't contain these attributes, and it was preventing it from passing through the parse/format step (making my patches from earlier today unusable). Because adding an "UNSPECIFIED" value to the enums for type and startmode would have made it possible for someone to send xml with, eg, type="unspecified" (which we don't want), I've followed the convention already used for the dhcp "peerdns" attribute - if it isn't specified, the value is -1. If anyone dislikes this use of an absolute, non-self-documenting value, I'll figure out a more elegant way. This at least makes the previous set of patches usable, though ;-) --- src/conf/interface_conf.c | 38 ++++++++++++++------------------------ 1 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index b1926c1..a5aa395 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -152,11 +152,9 @@ virInterfaceDefParseStartMode(virConnectPtr conn, virInterfaceDefPtr def, tmp = virXPathString(conn, "string(./start/@mode)", ctxt); if (tmp == NULL) { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("interface misses the start mode attribute")); - return(-1); + def->startmode = -1; /* not specified */ } - if (STREQ(tmp, "onboot")) + else if (STREQ(tmp, "onboot")) def->startmode = VIR_INTERFACE_START_ONBOOT; else if (STREQ(tmp, "hotplug")) def->startmode = VIR_INTERFACE_START_HOTPLUG; @@ -741,18 +739,7 @@ virInterfaceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt) { /* check @type */ tmp = virXPathString(conn, "string(./@type)", ctxt); - if (tmp == NULL) { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("interface misses the type attribute")); - return(NULL); - } type = virInterfaceTypeFromString(tmp); - if (type == -1) { - virInterfaceReportError(conn, VIR_ERR_XML_ERROR, - _("unknown interface type %s"), tmp); - VIR_FREE(tmp); - return(NULL); - } VIR_FREE(tmp); if (VIR_ALLOC(def) < 0) { @@ -761,6 +748,7 @@ virInterfaceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt) { } def->type = type; switch (type) { + case -1: case VIR_INTERFACE_TYPE_ETHERNET: if (virInterfaceDefParseBasicAttrs(conn, def, ctxt) < 0) goto error; @@ -1202,9 +1190,7 @@ virInterfaceStartmodeDefFormat(virConnectPtr conn, virBufferPtr buf, mode = "hotplug"; break; default: - virInterfaceReportError(conn, VIR_ERR_INTERNAL_ERROR, - "%s", _("virInterfaceDefFormat unknown startmode")); - return -1; + return 0; } virBufferVSprintf(buf, " <start mode='%s'/>\n", mode); return(0); @@ -1223,18 +1209,22 @@ char *virInterfaceDefFormat(virConnectPtr conn, goto cleanup; } - if (!(type = virInterfaceTypeToString(def->type))) { - virInterfaceReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("unexpected interface type %d"), def->type); - goto cleanup; + if (def->type == -1) { + virBufferAddLit(&buf, "<interface "); + } else { + if (!(type = virInterfaceTypeToString(def->type))) { + virInterfaceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected interface type %d"), def->type); + goto cleanup; + } + virBufferVSprintf(&buf, "<interface type='%s' ", type); } - - virBufferVSprintf(&buf, "<interface type='%s' ", type); if (def->name != NULL) virBufferEscapeString(&buf, "name='%s'", def->name); virBufferAddLit(&buf, ">\n"); switch (def->type) { + case -1: case VIR_INTERFACE_TYPE_ETHERNET: virInterfaceStartmodeDefFormat(conn, &buf, def->startmode); if (def->mac != NULL) -- 1.6.2.5

On Wed, Oct 07, 2009 at 05:04:40PM -0400, Laine Stump wrote:
(Yes, you read the subject correctly - 3 of 2!)
The minimal XML returned from ncf_if_xml_state() doesn't contain these attributes, and it was preventing it from passing through the parse/format step (making my patches from earlier today unusable).
Because adding an "UNSPECIFIED" value to the enums for type and startmode would have made it possible for someone to send xml with, eg, type="unspecified" (which we don't want), I've followed the convention already used for the dhcp "peerdns" attribute - if it isn't specified, the value is -1.
IMHO 'type' should always be a mandatory attribute. There's no reason why the live XML dump should not include it - we shouldn't make it optional merely because it hasn't been implemented fully yet. For anything which is an enum, the default value if not specified should always be 0. This is because when allocating a new object, everything will be memset to 0, so 0 should be a sensible default. When declaring the enum <-> string mapping, simply put "" as the value for that if you don't want it to be usable for incoming XML. When generating the XML output doc, you can just make it conditional on if (if->startmode), so the default value is skipped when formatting the XML Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On 10/08/2009 06:14 AM, Daniel P. Berrange wrote:
On Wed, Oct 07, 2009 at 05:04:40PM -0400, Laine Stump wrote:
(Yes, you read the subject correctly - 3 of 2!)
The minimal XML returned from ncf_if_xml_state() doesn't contain these attributes, and it was preventing it from passing through the parse/format step (making my patches from earlier today unusable).
Because adding an "UNSPECIFIED" value to the enums for type and startmode would have made it possible for someone to send xml with, eg, type="unspecified" (which we don't want), I've followed the convention already used for the dhcp "peerdns" attribute - if it isn't specified, the value is -1.
IMHO 'type' should always be a mandatory attribute. There's no reason why the live XML dump should not include it - we shouldn't make it optional merely because it hasn't been implemented fully yet.
So I need to either 1) find the proper way of getting the interface type from somewhere other than the config file, 2) use the interface type from the config file (even though we've just decided to not put any info from the config file into the live info) or 3) just insert a default type. And whatever I do, I need to do it before any of this functionality is usable. I don't like (3) - it's one thing to have default behavior that is unnamed, but something entirely different to call it, eg, "ethernet", which may imply other behavior to a person. I don't immediately have a method to do (1), so unless someone has an idea for that, I'm left with (2), which is fairly straightforward, but we'd said we didn't want to do that (or am I taking the edict of "no info from config files" too far?).

On Wed, Oct 07, 2009 at 10:05:39AM -0400, Laine Stump wrote:
This is similar to the (now deprecated) patches I sent on 9/28 and 10/04, but without the unpopular "source" attribute in the ip address.
You can successfully build libvirt if you have the latest release of netcf installed, but you'll need to get the netcf source, apply the patches in the thread listed below, and build/install netcf to get correct/proper output.
https://fedorahosted.org/pipermail/netcf-devel/2009-October/000289.html
Hum, that means we need to synchronize a release with netcf with this feature and require that version then ... Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Oct 08, 2009 at 11:36:59AM +0200, Daniel Veillard wrote:
On Wed, Oct 07, 2009 at 10:05:39AM -0400, Laine Stump wrote:
This is similar to the (now deprecated) patches I sent on 9/28 and 10/04, but without the unpopular "source" attribute in the ip address.
You can successfully build libvirt if you have the latest release of netcf installed, but you'll need to get the netcf source, apply the patches in the thread listed below, and build/install netcf to get correct/proper output.
https://fedorahosted.org/pipermail/netcf-devel/2009-October/000289.html
Hum, that means we need to synchronize a release with netcf with this feature and require that version then ...
We just need to fix the configure.ac pkgconfig version check for netcf, and the RPM BuildRequires. Given how early in development netcf is, I don't think its unreasonable to force people to upgrade, rather than trying to conditionalize compilation for older versions Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Laine Stump