diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index d46f7ac28adcf529dc750751c5a43239f6ee057d..7cb71edc9f98c10a90de86c73a1a54748a530295 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); } @@ -222,22 +245,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); @@ -245,86 +268,208 @@ 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 = -1; + 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); + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) { + + virInterfaceIpDefPtr ip; + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + goto error; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + goto error; + } + def->ips[def->nips++] = ip; + } + + ret = 0; + +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 = -1; + 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); + goto error; + } + + def->nips = 0; + for (ii = 0; ii < nIpNodes; ii++) { + + virInterfaceIpDefPtr ip; + + if (VIR_ALLOC(ip) < 0) { + virReportOOMError(conn); + goto error; + } + + ctxt->node = ipNodes[ii]; + ret = virInterfaceDefParseIp(conn, ip, ctxt); + if (ret != 0) { + virInterfaceIpDefFree(ip); + goto error; + } + def->ips[def->nips++] = ip; + } + + ret = 0; + +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 = -1; 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); - ret = -1; - VIR_FREE(tmp); + + if (VIR_ALLOC_N(def->protos, nProtoNodes) < 0) { + virReportOOMError(conn); + goto error; } -done: + def->nprotos = 0; + for (pp = 0; pp < nProtoNodes; pp++) { + + virInterfaceProtocolDefPtr proto; + + if (VIR_ALLOC(proto) < 0) { + virReportOOMError(conn); + goto error; + } + + 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); + goto error; + } + proto->family = tmp; + if (STREQ(tmp, "ipv4")) { + ret = virInterfaceDefParseProtoIPv4(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + goto error; + } + } else if (STREQ(tmp, "ipv6")) { + ret = virInterfaceDefParseProtoIPv6(conn, proto, ctxt); + if (ret != 0) { + virInterfaceProtocolDefFree(proto); + goto error; + } + } else { + virInterfaceReportError(conn, VIR_ERR_XML_ERROR, + _("unsupported protocol family '%s'"), tmp); + virInterfaceProtocolDefFree(proto); + goto error; + } + def->protos[def->nprotos++] = proto; + } + + ret = 0; + +error: + VIR_FREE(protoNodes); ctxt->node = save; return(ret); @@ -999,30 +1144,44 @@ virInterfaceVlanDefFormat(virConnectPtr conn, virBufferPtr buf, static int virInterfaceProtocolDefFormat(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferPtr buf, const virInterfaceDefPtr def) { - if (def->proto.family == NULL) - return(0); - virBufferVSprintf(buf, " \n", def->proto.family); - if (def->proto.dhcp) { - if (def->proto.peerdns == 0) - virBufferAddLit(buf, " \n"); - else if (def->proto.peerdns == 1) - virBufferAddLit(buf, " \n"); - else - virBufferAddLit(buf, " \n"); - } - if (def->proto.address != NULL) { - if (def->proto.prefix != 0) - virBufferVSprintf(buf, " \n", - def->proto.address, def->proto.prefix); - else - virBufferVSprintf(buf, " \n", - def->proto.address); - } - if (def->proto.gateway != NULL) { - virBufferVSprintf(buf, " \n", - def->proto.gateway); + int pp, ii; + + for (pp = 0; pp < def->nprotos; pp++) { + + virBufferVSprintf(buf, " \n", def->protos[pp]->family); + + if (def->protos[pp]->autoconf) { + virBufferAddLit(buf, " \n"); + } + + if (def->protos[pp]->dhcp) { + if (def->protos[pp]->peerdns == 0) + virBufferAddLit(buf, " \n"); + else if (def->protos[pp]->peerdns == 1) + virBufferAddLit(buf, " \n"); + else + virBufferAddLit(buf, " \n"); + } + + for (ii = 0; ii < def->protos[pp]->nips; ii++) { + if (def->protos[pp]->ips[ii]->address != NULL) { + + virBufferVSprintf(buf, " 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, " \n", + def->protos[pp]->gateway); + } + + virBufferAddLit(buf, " \n"); } - virBufferAddLit(buf, " \n"); return(0); } diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index a73136f9e920f5157e61fa97bdd74b4da08fad43..2683eeed109bf04c0bac7db91518510bff938341 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -124,14 +124,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 */ }; @@ -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;