[libvirt] [PATCH] Support for IPv6 / multiple ifaces in interface_conf.[ch]
Daniel P. Berrange
berrange at redhat.com
Mon Oct 5 13:05:23 UTC 2009
On Sun, Oct 04, 2009 at 10:58:55PM -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.
>
> Note that netcf appears to not accept defining both ipv4 and ipv6 on
> the same interface, and still can't report live config of IPv6 (or
> multiple IPv4 addresses), so the usefulness of this patch is limited
> until those items are fixed in netcf.
>
> This patch applies on top of commit
> 1ceabc5a152efa8892954cb4f45b85553edfee9f, which I submitted on Sept 28.
>
> ---
> src/conf/interface_conf.c | 308 ++++++++++++++++++++++++++++++++++-----------
> src/conf/interface_conf.h | 21 +++-
> 2 files changed, 247 insertions(+), 82 deletions(-)
>
> diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c
> index b422464..24f111c 100644
> --- a/src/conf/interface_conf.c
> +++ b/src/conf/interface_conf.c
> @@ -53,9 +53,32 @@ void virInterfaceBareDefFree(virInterfaceBareDefPtr def) {
> VIR_FREE(def);
> }
>
> +static
> +void virInterfaceIpDefFree(virInterfaceIpDefPtr def) {
> + if (def == NULL)
> + return;
> + VIR_FREE(def->address);
> + VIR_FREE(def->source);
> +}
> +
> +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,11 +112,11 @@ void virInterfaceDefFree(virInterfaceDefPtr def)
> break;
> }
>
> - VIR_FREE(def->proto.family);
> - VIR_FREE(def->proto.address);
> - VIR_FREE(def->proto.gateway);
> - VIR_FREE(def->proto.source);
> -
> + /* free all protos */
> + for (pp = 0; pp < def->nprotos; pp++) {
> + virInterfaceProtocolDefFree(def->protos[pp]);
> + }
> + VIR_FREE(def->protos);
> VIR_FREE(def);
> }
>
> @@ -226,22 +249,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);
> @@ -249,88 +272,209 @@ 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(./ip[1]/@source)", ctxt);
> - def->proto.source = tmp;
> + tmp = virXPathString(conn, "string(./@source)", ctxt);
> + def->source = tmp;
> }
> - 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);
>
> @@ -1005,36 +1149,48 @@ 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 ? "'" : "",
> - def->proto.source ? " source='" : "",
> - def->proto.source ? def->proto.source : "",
> - def->proto.source ? "'" : "");
> - }
> - 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);
> + }
> + if (def->protos[pp]->ips[ii]->source != NULL) {
> + virBufferVSprintf(buf, " source='%s'",
> + def->protos[pp]->ips[ii]->source);
> + }
> + 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 df871aa..49acdd6 100644
> --- a/src/conf/interface_conf.h
> +++ b/src/conf/interface_conf.h
> @@ -123,16 +123,25 @@ 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 */
> + char *source; /* source of address - "device" or "config" (default) */
> +};
> +
> +
> 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 */
> - char *source; /* source of address - "device" or "config" (default) */
> };
>
>
> @@ -152,8 +161,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;
This looks good, with exception of the 'source' attribute I mentioned
in the review of the other patch
Regards,
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 :|
More information about the libvir-list
mailing list