提交 a950dd2a 编写于 作者: L Laine Stump

Change virtual network XML parsing/formatting to support IPv6

This commit adds support for IPv6 parsing and formatting to the
virtual network XML parser, including moving around data definitions
to allow for multiple <ip> elements on a single network, but only
changes the consumers of this API to accommodate for the changes in
API/structure, not to add any actual IPv6 functionality. That will
come in a later patch - this patch attempts to maintain the same final
functionality in both drivers that use the network XML parser - vbox
and "bridge" (the Linux bridge-based driver used by the qemu
hypervisor driver).

* src/libvirt_private.syms: Add new private API functions.
* src/conf/network_conf.[ch]: Change C data structure and
  parsing/formatting.
* src/network/bridge_driver.c: Update to use new parser/formatter.
* src/vbox/vbox_tmpl.c: update to use new parser/formatter
* docs/schemas/network.rng: changes to the schema -
  * there can now be more than one <ip> element.
  * ip address is now an ip-addr (ipv4 or ipv6) rather than ipv4-addr
  * new optional "prefix" attribute that can be used in place of "netmask"
  * new optional "family" attribute - "ipv4" or "ipv6"
    (will default to ipv4)
  * define data types for the above
* tests/networkxml2xml(in|out)/nat-network.xml: add multiple <ip> elements
  (including IPv6) to a single network definition to verify they are being
  correctly parsed and formatted.
上级 008abeee
......@@ -80,15 +80,21 @@
</optional>
<!-- <ip> element -->
<optional>
<zeroOrMore>
<!-- The IP element sets up NAT'ing and an optional DHCP server
local to the host. -->
<element name="ip">
<optional>
<attribute name="address"><ref name="ipv4-addr"/></attribute>
<attribute name="address"><ref name="ip-addr"/></attribute>
</optional>
<optional>
<choice>
<attribute name="netmask"><ref name="ipv4-addr"/></attribute>
<attribute name="prefix"><ref name="ip-prefix"/></attribute>
</choice>
</optional>
<optional>
<attribute name="netmask"><ref name="ipv4-addr"/></attribute>
<attribute name="family"><ref name="addr-family"/></attribute>
</optional>
<optional>
<element name="tftp">
......@@ -123,7 +129,7 @@
</element>
</optional>
</element>
</optional>
</zeroOrMore>
</interleave>
</element>
</define>
......@@ -135,6 +141,33 @@
</data>
</define>
<!-- Based on http://blog.mes-stats.fr/2008/10/09/regex-ipv4-et-ipv6 -->
<define name='ipv6-addr'>
<data type='string'>
<!-- To understand this better, take apart the toplevel '|'s -->
<param name="pattern">(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9]))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9])))|(([0-9A-Fa-f]{1,4}:){0,5}:(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9]))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9])))|(::([0-9A-Fa-f]{1,4}:){0,5}(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9]))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9])))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:)</param>
</data>
</define>
<define name='ip-addr'>
<choice>
<ref name='ipv4-addr'/>
<ref name='ipv6-addr'/>
</choice>
</define>
<define name='ip-prefix'>
<data type='unsignedInt'>
<param name="maxInclusive">128</param>
</data>
</define>
<define name='addr-family'>
<data type='string'>
<param name="pattern">(ipv4)|(ipv6)</param>
</data>
</define>
<!-- a 6 byte MAC address in ASCII-hex format, eg "12:34:56:78:9A:BC" -->
<define name='mac-addr'>
<data type='string'>
......
......@@ -87,9 +87,26 @@ virNetworkObjPtr virNetworkFindByName(const virNetworkObjListPtr nets,
}
static void virNetworkIpDefClear(virNetworkIpDefPtr def)
{
int ii;
VIR_FREE(def->family);
VIR_FREE(def->ranges);
for (ii = 0 ; ii < def->nhosts && def->hosts ; ii++) {
VIR_FREE(def->hosts[ii].mac);
VIR_FREE(def->hosts[ii].name);
}
VIR_FREE(def->hosts);
VIR_FREE(def->tftproot);
VIR_FREE(def->bootfile);
}
void virNetworkDefFree(virNetworkDefPtr def)
{
int i;
int ii;
if (!def)
return;
......@@ -99,16 +116,10 @@ void virNetworkDefFree(virNetworkDefPtr def)
VIR_FREE(def->forwardDev);
VIR_FREE(def->domain);
VIR_FREE(def->ranges);
for (i = 0 ; i < def->nhosts && def->hosts ; i++) {
VIR_FREE(def->hosts[i].mac);
VIR_FREE(def->hosts[i].name);
for (ii = 0 ; ii < def->nips && def->ips ; ii++) {
virNetworkIpDefClear(&def->ips[ii]);
}
VIR_FREE(def->hosts);
VIR_FREE(def->tftproot);
VIR_FREE(def->bootfile);
VIR_FREE(def->ips);
VIR_FREE(def);
}
......@@ -207,21 +218,48 @@ void virNetworkRemoveInactive(virNetworkObjListPtr nets,
}
}
/* return ips[index], or NULL if there aren't enough ips */
virNetworkIpDefPtr
virNetworkDefGetIpByIndex(const virNetworkDefPtr def,
int family, size_t n)
{
int ii;
if (!def->ips || n >= def->nips)
return NULL;
if (family == AF_UNSPEC) {
return &def->ips[n];
}
/* find the nth ip of type "family" */
for (ii = 0; ii < def->nips; ii++) {
if (VIR_SOCKET_IS_FAMILY(&def->ips[ii].address, family)
&& (n-- <= 0)) {
return &def->ips[ii];
}
}
/* failed to find enough of the right family */
return NULL;
}
/* return number of 1 bits in netmask for the network's ipAddress,
* or -1 on error
*/
int virNetworkDefPrefix(const virNetworkDefPtr def)
int virNetworkIpDefPrefix(const virNetworkIpDefPtr def)
{
if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
if (def->prefix > 0) {
return def->prefix;
} else if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
return virSocketGetNumNetmaskBits(&def->netmask);
} else if (VIR_SOCKET_IS_FAMILY(&def->ipAddress, AF_INET)) {
} else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
/* Return the natural prefix for the network's ip address.
* On Linux we could use the IN_CLASSx() macros, but those
* aren't guaranteed on all platforms, so we just deal with
* the bits ourselves.
*/
unsigned char octet
= ntohl(def->ipAddress.data.inet4.sin_addr.s_addr) >> 24;
= ntohl(def->address.data.inet4.sin_addr.s_addr) >> 24;
if ((octet & 0x80) == 0) {
/* Class A network */
return 8;
......@@ -233,6 +271,8 @@ int virNetworkDefPrefix(const virNetworkDefPtr def)
return 24;
}
return -1;
} else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
return 64;
}
return -1;
}
......@@ -241,22 +281,23 @@ int virNetworkDefPrefix(const virNetworkDefPtr def)
* definition, based on either the definition's netmask, or its
* prefix. Return -1 on error (and set the netmask family to AF_UNSPEC)
*/
int virNetworkDefNetmask(const virNetworkDefPtr def,
virSocketAddrPtr netmask)
int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
virSocketAddrPtr netmask)
{
if (VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
*netmask = def->netmask;
return 0;
}
return virSocketAddrPrefixToNetmask(virNetworkDefPrefix(def), netmask,
VIR_SOCKET_FAMILY(&def->ipAddress));
return virSocketAddrPrefixToNetmask(virNetworkIpDefPrefix(def), netmask,
VIR_SOCKET_FAMILY(&def->address));
}
static int
virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
xmlNodePtr node) {
virNetworkDHCPRangeDefParseXML(virNetworkIpDefPtr def,
xmlNodePtr node)
{
xmlNodePtr cur;
......@@ -390,33 +431,147 @@ virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
}
static int
virNetworkIPParseXML(virNetworkDefPtr def,
xmlNodePtr node) {
xmlNodePtr cur;
virNetworkIPParseXML(const char *networkName,
virNetworkIpDefPtr def,
xmlNodePtr node,
xmlXPathContextPtr ctxt)
{
/*
* virNetworkIpDef object is already allocated as part of an array.
* On failure clear it out, but don't free it.
*/
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
int result = virNetworkDHCPRangeDefParseXML(def, cur);
if (result)
return result;
xmlNodePtr cur, save;
char *address = NULL, *netmask = NULL;
unsigned long prefix;
int result = -1;
save = ctxt->node;
ctxt->node = node;
/* grab raw data from XML */
def->family = virXPathString("string(./@family)", ctxt);
address = virXPathString("string(./@address)", ctxt);
if (virXPathULong("string(./@prefix)", ctxt, &prefix) < 0)
def->prefix = 0;
else
def->prefix = prefix;
netmask = virXPathString("string(./@netmask)", ctxt);
if (address) {
if (virSocketParseAddr(address, &def->address, AF_UNSPEC) < 0) {
virNetworkReportError(VIR_ERR_XML_ERROR,
_("Bad address '%s' in definition of network '%s'"),
address, networkName);
goto error;
}
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
char *root;
}
if (!(root = virXMLPropString(cur, "root"))) {
cur = cur->next;
continue;
/* validate family vs. address */
if (def->family == NULL) {
if (!(VIR_SOCKET_IS_FAMILY(&def->address, AF_INET) ||
VIR_SOCKET_IS_FAMILY(&def->address, AF_UNSPEC))) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("no family specified for non-IPv4 address address '%s' in network '%s'"),
address, networkName);
goto error;
}
} else if (STREQ(def->family, "ipv4")) {
if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("family 'ipv4' specified for non-IPv4 address '%s' in network '%s'"),
address, networkName);
goto error;
}
} else if (STREQ(def->family, "ipv6")) {
if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("family 'ipv6' specified for non-IPv6 address '%s' in network '%s'"),
address, networkName);
goto error;
}
} else {
virNetworkReportError(VIR_ERR_XML_ERROR,
_("Unrecognized family '%s' in definition of network '%s'"),
def->family, networkName);
goto error;
}
/* parse/validate netmask */
if (netmask) {
if (address == NULL) {
/* netmask is meaningless without an address */
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("netmask specified without address in network '%s'"),
networkName);
goto error;
}
if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("netmask not supported for address '%s' in network '%s' (IPv4 only)"),
address, networkName);
goto error;
}
if (def->prefix > 0) {
/* can't have both netmask and prefix at the same time */
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("network '%s' cannot have both prefix='%u' and a netmask"),
networkName, def->prefix);
goto error;
}
if (virSocketParseAddr(netmask, &def->netmask, AF_UNSPEC) < 0)
goto error;
if (!VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("network '%s' has invalid netmask '%s' for address '%s' (both must be IPv4)"),
networkName, netmask, address);
goto error;
}
}
if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
/* parse IPv4-related info */
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
result = virNetworkDHCPRangeDefParseXML(def, cur);
if (result)
goto error;
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
char *root;
if (!(root = virXMLPropString(cur, "root"))) {
cur = cur->next;
continue;
}
def->tftproot = (char *)root;
}
def->tftproot = root;
cur = cur->next;
}
}
cur = cur->next;
result = 0;
error:
if (result < 0) {
virNetworkIpDefClear(def);
}
return 0;
VIR_FREE(address);
VIR_FREE(netmask);
ctxt->node = save;
return result;
}
static virNetworkDefPtr
......@@ -424,8 +579,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
{
virNetworkDefPtr def;
char *tmp;
char *ipAddress;
char *netmask;
xmlNodePtr *ipNodes = NULL;
int nIps;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
......@@ -469,44 +624,32 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
def->delay = 0;
ipAddress = virXPathString("string(./ip[1]/@address)", ctxt);
if (ipAddress) {
xmlNodePtr ip;
if (virSocketParseAddr(ipAddress, &def->ipAddress, AF_UNSPEC) < 0)
goto error;
nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
if (nIps > 0) {
int ii;
/* XXX someday we want IPv6, so will need to relax this */
if (!VIR_SOCKET_IS_FAMILY(&def->ipAddress, AF_INET)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("Only IPv4 addresses are supported"));
/* allocate array to hold all the addrs */
if (VIR_ALLOC_N(def->ips, nIps) < 0) {
virReportOOMError();
goto error;
}
if ((ip = virXPathNode("./ip[1]", ctxt)) &&
virNetworkIPParseXML(def, ip) < 0)
goto error;
}
VIR_FREE(ipAddress);
netmask = virXPathString("string(./ip[1]/@netmask)", ctxt);
if (netmask) {
if (virSocketParseAddr(netmask, &def->netmask, AF_UNSPEC) < 0)
goto error;
/* XXX someday we want IPv6, so will need to relax this */
if (!VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("Only IPv4 addresses are supported"));
goto error;
/* parse each addr */
for (ii = 0; ii < nIps; ii++) {
int ret = virNetworkIPParseXML(def->name, &def->ips[ii],
ipNodes[ii], ctxt);
if (ret < 0)
goto error;
def->nips++;
}
}
VIR_FREE(netmask);
/* IPv4 forwarding setup */
if (virXPathBoolean("count(./forward) > 0", ctxt)) {
if (def->nips == 0) {
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Forwarding requested, but no IP address provided"));
goto error;
}
tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
if (tmp) {
if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
......@@ -585,11 +728,101 @@ cleanup:
return def;
}
static int
virNetworkIpDefFormat(virBufferPtr buf,
const virNetworkIpDefPtr def)
{
int result = -1;
virBufferAddLit(buf, " <ip");
if (def->family) {
virBufferVSprintf(buf, " family='%s'", def->family);
}
if (VIR_SOCKET_HAS_ADDR(&def->address)) {
char *addr = virSocketFormatAddr(&def->address);
if (!addr)
goto error;
virBufferVSprintf(buf, " address='%s'", addr);
VIR_FREE(addr);
}
if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
char *addr = virSocketFormatAddr(&def->netmask);
if (!addr)
goto error;
virBufferVSprintf(buf, " netmask='%s'", addr);
VIR_FREE(addr);
}
if (def->prefix > 0) {
virBufferVSprintf(buf," prefix='%u'", def->prefix);
}
virBufferAddLit(buf, ">\n");
if (def->tftproot) {
virBufferEscapeString(buf, " <tftp root='%s' />\n",
def->tftproot);
}
if ((def->nranges || def->nhosts)) {
int ii;
virBufferAddLit(buf, " <dhcp>\n");
for (ii = 0 ; ii < def->nranges ; ii++) {
char *saddr = virSocketFormatAddr(&def->ranges[ii].start);
if (!saddr)
goto error;
char *eaddr = virSocketFormatAddr(&def->ranges[ii].end);
if (!eaddr) {
VIR_FREE(saddr);
goto error;
}
virBufferVSprintf(buf, " <range start='%s' end='%s' />\n",
saddr, eaddr);
VIR_FREE(saddr);
VIR_FREE(eaddr);
}
for (ii = 0 ; ii < def->nhosts ; ii++) {
virBufferAddLit(buf, " <host ");
if (def->hosts[ii].mac)
virBufferVSprintf(buf, "mac='%s' ", def->hosts[ii].mac);
if (def->hosts[ii].name)
virBufferVSprintf(buf, "name='%s' ", def->hosts[ii].name);
if (VIR_SOCKET_HAS_ADDR(&def->hosts[ii].ip)) {
char *ipaddr = virSocketFormatAddr(&def->hosts[ii].ip);
if (!ipaddr)
goto error;
virBufferVSprintf(buf, "ip='%s' ", ipaddr);
VIR_FREE(ipaddr);
}
virBufferAddLit(buf, "/>\n");
}
if (def->bootfile) {
virBufferEscapeString(buf, " <bootp file='%s' ",
def->bootfile);
if (VIR_SOCKET_HAS_ADDR(&def->bootserver)) {
char *ipaddr = virSocketFormatAddr(&def->bootserver);
if (!ipaddr)
goto error;
virBufferEscapeString(buf, "server='%s' ", ipaddr);
VIR_FREE(ipaddr);
}
virBufferAddLit(buf, "/>\n");
}
virBufferAddLit(buf, " </dhcp>\n");
}
virBufferAddLit(buf, " </ip>\n");
result = 0;
error:
return result;
}
char *virNetworkDefFormat(const virNetworkDefPtr def)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
int ii;
virBufferAddLit(&buf, "<network>\n");
virBufferEscapeString(&buf, " <name>%s</name>\n", def->name);
......@@ -621,81 +854,9 @@ char *virNetworkDefFormat(const virNetworkDefPtr def)
if (def->domain)
virBufferVSprintf(&buf, " <domain name='%s'/>\n", def->domain);
if (VIR_SOCKET_HAS_ADDR(&def->ipAddress) ||
VIR_SOCKET_HAS_ADDR(&def->netmask)) {
virBufferAddLit(&buf, " <ip");
if (VIR_SOCKET_HAS_ADDR(&def->ipAddress)) {
char *addr = virSocketFormatAddr(&def->ipAddress);
if (!addr)
goto error;
virBufferVSprintf(&buf, " address='%s'", addr);
VIR_FREE(addr);
}
if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
char *addr = virSocketFormatAddr(&def->netmask);
if (!addr)
goto error;
virBufferVSprintf(&buf, " netmask='%s'", addr);
VIR_FREE(addr);
}
virBufferAddLit(&buf, ">\n");
if (def->tftproot) {
virBufferEscapeString(&buf, " <tftp root='%s' />\n",
def->tftproot);
}
if ((def->nranges || def->nhosts)) {
int i;
virBufferAddLit(&buf, " <dhcp>\n");
for (i = 0 ; i < def->nranges ; i++) {
char *saddr = virSocketFormatAddr(&def->ranges[i].start);
if (!saddr)
goto error;
char *eaddr = virSocketFormatAddr(&def->ranges[i].end);
if (!eaddr) {
VIR_FREE(saddr);
goto error;
}
virBufferVSprintf(&buf, " <range start='%s' end='%s' />\n",
saddr, eaddr);
VIR_FREE(saddr);
VIR_FREE(eaddr);
}
for (i = 0 ; i < def->nhosts ; i++) {
virBufferAddLit(&buf, " <host ");
if (def->hosts[i].mac)
virBufferVSprintf(&buf, "mac='%s' ", def->hosts[i].mac);
if (def->hosts[i].name)
virBufferVSprintf(&buf, "name='%s' ", def->hosts[i].name);
if (VIR_SOCKET_HAS_ADDR(&def->hosts[i].ip)) {
char *ipaddr = virSocketFormatAddr(&def->hosts[i].ip);
if (!ipaddr)
goto error;
virBufferVSprintf(&buf, "ip='%s' ", ipaddr);
VIR_FREE(ipaddr);
}
virBufferAddLit(&buf, "/>\n");
}
if (def->bootfile) {
virBufferEscapeString(&buf, " <bootp file='%s' ",
def->bootfile);
if (VIR_SOCKET_HAS_ADDR(&def->bootserver)) {
char *ipaddr = virSocketFormatAddr(&def->bootserver);
if (!ipaddr)
goto error;
virBufferEscapeString(&buf, "server='%s' ", ipaddr);
VIR_FREE(ipaddr);
}
virBufferAddLit(&buf, "/>\n");
}
virBufferAddLit(&buf, " </dhcp>\n");
}
virBufferAddLit(&buf, " </ip>\n");
for (ii = 0; ii < def->nips; ii++) {
if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
goto error;
}
virBufferAddLit(&buf, "</network>\n");
......
......@@ -56,6 +56,32 @@ struct _virNetworkDHCPHostDef {
virSocketAddr ip;
};
typedef struct _virNetworkIpDef virNetworkIpDef;
typedef virNetworkIpDef *virNetworkIpDefPtr;
struct _virNetworkIpDef {
char *family; /* ipv4 or ipv6 - default is ipv4 */
virSocketAddr address; /* Bridge IP address */
/* One or the other of the following two will be used for a given
* IP address, but never both. The parser guarantees this.
* Use virNetworkIpDefPrefix/virNetworkIpDefNetmask rather
* than accessing the data directly - these utility functions
* will convert one into the other as necessary.
*/
unsigned int prefix; /* ipv6 - only prefix allowed */
virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
unsigned int nranges; /* Zero or more dhcp ranges */
virNetworkDHCPRangeDefPtr ranges;
unsigned int nhosts; /* Zero or more dhcp hosts */
virNetworkDHCPHostDefPtr hosts;
char *tftproot;
char *bootfile;
virSocketAddr bootserver;
};
typedef struct _virNetworkDef virNetworkDef;
typedef virNetworkDef *virNetworkDefPtr;
struct _virNetworkDef {
......@@ -70,18 +96,8 @@ struct _virNetworkDef {
int forwardType; /* One of virNetworkForwardType constants */
char *forwardDev; /* Destination device for forwarding */
virSocketAddr ipAddress; /* Bridge IP address */
virSocketAddr netmask;
unsigned int nranges; /* Zero or more dhcp ranges */
virNetworkDHCPRangeDefPtr ranges;
unsigned int nhosts; /* Zero or more dhcp hosts */
virNetworkDHCPHostDefPtr hosts;
char *tftproot;
char *bootfile;
virSocketAddr bootserver;
size_t nips;
virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
};
typedef struct _virNetworkObj virNetworkObj;
......@@ -133,9 +149,12 @@ virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
char *virNetworkDefFormat(const virNetworkDefPtr def);
int virNetworkDefPrefix(const virNetworkDefPtr def);
int virNetworkDefNetmask(const virNetworkDefPtr def,
virSocketAddrPtr netmask);
virNetworkIpDefPtr
virNetworkDefGetIpByIndex(const virNetworkDefPtr def,
int family, size_t n);
int virNetworkIpDefPrefix(const virNetworkIpDefPtr def);
int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
virSocketAddrPtr netmask);
int virNetworkSaveXML(const char *configDir,
virNetworkDefPtr def,
......
......@@ -578,14 +578,15 @@ virNetworkAssignDef;
virNetworkConfigFile;
virNetworkDefFormat;
virNetworkDefFree;
virNetworkDefNetmask;
virNetworkDefGetIpByIndex;
virNetworkDefParseFile;
virNetworkDefParseNode;
virNetworkDefParseString;
virNetworkDefPrefix;
virNetworkDeleteConfig;
virNetworkFindByName;
virNetworkFindByUUID;
virNetworkIpDefNetmask;
virNetworkIpDefPrefix;
virNetworkLoadAllConfigs;
virNetworkObjIsDuplicate;
virNetworkObjListFree;
......
此差异已折叠。
......@@ -7038,9 +7038,23 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *
IHostNetworkInterface *networkInterface = NULL;
virNetworkDefPtr def = virNetworkDefParseString(xml);
virNetworkIpDefPtr ipdef;
virSocketAddr netmask;
if ( (!def)
|| (def->forwardType != VIR_NETWORK_FORWARD_NONE))
|| (def->forwardType != VIR_NETWORK_FORWARD_NONE)
|| (def->nips == 0 || !def->ips))
goto cleanup;
/* Look for the first IPv4 IP address definition and use that.
* If there weren't any IPv4 addresses, ignore the network (since it's
* required below to have an IPv4 address)
*/
ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
if (!ipdef)
goto cleanup;
if (virNetworkIpDefNetmask(ipdef, &netmask) < 0)
goto cleanup;
/* the current limitation of hostonly network is that you can't
......@@ -7096,9 +7110,9 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *
/* Currently support only one dhcp server per network
* with contigious address space from start to end
*/
if ((def->nranges >= 1) &&
VIR_SOCKET_HAS_ADDR(&def->ranges[0].start) &&
VIR_SOCKET_HAS_ADDR(&def->ranges[0].end)) {
if ((ipdef->nranges >= 1) &&
VIR_SOCKET_HAS_ADDR(&ipdef->ranges[0].start) &&
VIR_SOCKET_HAS_ADDR(&ipdef->ranges[0].end)) {
IDHCPServer *dhcpServer = NULL;
data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
......@@ -7118,10 +7132,10 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *
PRUnichar *toIPAddressUtf16 = NULL;
PRUnichar *trunkTypeUtf16 = NULL;
ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &def->ipAddress);
networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &def->netmask);
fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &def->ranges[0].start);
toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &def->ranges[0].end);
ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
......@@ -7158,13 +7172,13 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *
}
}
if ((def->nhosts >= 1) &&
VIR_SOCKET_HAS_ADDR(&def->hosts[0].ip)) {
if ((ipdef->nhosts >= 1) &&
VIR_SOCKET_HAS_ADDR(&ipdef->hosts[0].ip)) {
PRUnichar *ipAddressUtf16 = NULL;
PRUnichar *networkMaskUtf16 = NULL;
ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &def->hosts[0].ip);
networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &def->netmask);
ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
VBOX_UTF16_FREE(ipAddressUtf16);
......@@ -7385,12 +7399,19 @@ static int vboxNetworkDestroy(virNetworkPtr network) {
static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSED) {
VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
virNetworkDefPtr def = NULL;
virNetworkIpDefPtr ipdef = NULL;
char *networkNameUtf8 = NULL;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
goto cleanup;
}
if (VIR_ALLOC(ipdef) < 0) {
virReportOOMError();
goto cleanup;
}
def->ips = ipdef;
def->nips = 1;
if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
virReportOOMError();
......@@ -7427,8 +7448,8 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
networkNameUtf16,
&dhcpServer);
if (dhcpServer) {
def->nranges = 1;
if (VIR_ALLOC_N(def->ranges, def->nranges) >=0 ) {
ipdef->nranges = 1;
if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0 ) {
PRUnichar *ipAddressUtf16 = NULL;
PRUnichar *networkMaskUtf16 = NULL;
PRUnichar *fromIPAddressUtf16 = NULL;
......@@ -7443,13 +7464,13 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
* with contigious address space from start to end
*/
if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
&def->ipAddress) < 0 ||
&ipdef->address) < 0 ||
vboxSocketParseAddrUtf16(data, networkMaskUtf16,
&def->netmask) < 0 ||
&ipdef->netmask) < 0 ||
vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
&def->ranges[0].start) < 0 ||
&ipdef->ranges[0].start) < 0 ||
vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
&def->ranges[0].end) < 0) {
&ipdef->ranges[0].end) < 0) {
errorOccurred = true;
}
......@@ -7462,16 +7483,16 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
goto cleanup;
}
} else {
def->nranges = 0;
ipdef->nranges = 0;
virReportOOMError();
}
def->nhosts = 1;
if (VIR_ALLOC_N(def->hosts, def->nhosts) >=0 ) {
def->hosts[0].name = strdup(network->name);
if (def->hosts[0].name == NULL) {
VIR_FREE(def->hosts);
def->nhosts = 0;
ipdef->nhosts = 1;
if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0 ) {
ipdef->hosts[0].name = strdup(network->name);
if (ipdef->hosts[0].name == NULL) {
VIR_FREE(ipdef->hosts);
ipdef->nhosts = 0;
virReportOOMError();
} else {
PRUnichar *macAddressUtf16 = NULL;
......@@ -7481,10 +7502,10 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);
VBOX_UTF16_TO_UTF8(macAddressUtf16, &def->hosts[0].mac);
VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
&def->hosts[0].ip) < 0) {
&ipdef->hosts[0].ip) < 0) {
errorOccurred = true;
}
......@@ -7496,7 +7517,7 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
}
}
} else {
def->nhosts = 0;
ipdef->nhosts = 0;
}
VBOX_RELEASE(dhcpServer);
......@@ -7509,9 +7530,9 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSE
networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);
if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
&def->netmask) < 0 ||
&ipdef->netmask) < 0 ||
vboxSocketParseAddrUtf16(data, ipAddressUtf16,
&def->ipAddress) < 0) {
&ipdef->address) < 0) {
errorOccurred = true;
}
......
......@@ -10,4 +10,12 @@
<host mac="00:16:3e:3e:a9:1a" name="b.example.com" ip="192.168.122.11" />
</dhcp>
</ip>
<ip family="ipv4" address="192.168.123.1" netmask="255.255.255.0">
</ip>
<ip family="ipv6" address="2001:db8:ac10:fe01::1" prefix="64">
</ip>
<ip family="ipv6" address="2001:db8:ac10:fd01::1" prefix="64">
</ip>
<ip family="ipv4" address="10.24.10.1">
</ip>
</network>
......@@ -10,4 +10,12 @@
<host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
</dhcp>
</ip>
<ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
</ip>
<ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
</ip>
<ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
</ip>
<ip family='ipv4' address='10.24.10.1'>
</ip>
</network>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册