Domain conf: allow more than one IP address for net devices

Add the possibility to have more than one IP address configured for a
domain network interface. IP addresses can also have a prefix to define
the corresponding netmask.
This commit is contained in:
Cédric Bosdonnat 2014-07-22 11:09:48 +02:00
parent c9ebdf9b7f
commit aa2cc72100
17 changed files with 240 additions and 59 deletions

View File

@ -4321,6 +4321,29 @@ qemu-kvm -net nic,model=? /dev/null
<span class="since">Since 0.9.5</span>
</p>
<h5><a name="ipconfig">IP configuration</a></h5>
<pre>
...
&lt;devices&gt;
&lt;interface type='network'&gt;
&lt;source network='default'/&gt;
&lt;target dev='vnet0'/&gt;
<b>&lt;ip family='ipv4' address='192.168.122.5' prefix='24'/&gt;</b>
&lt;/interface&gt;
&lt;/devices&gt;
...
</pre>
<p>
<span class="since">Since 1.2.12</span> the network devices and host devices
with network capabilities can be provided zero or more IP addresses to set
on the target device. Note that some hypervisors or network device types
will simply ignore them or only use the first one. The <code>family</code>
attribute can be set to either <code>ipv4</code> or <code>ipv6</code>, the
<code>address</code> attribute holds the IP address. The <code>prefix</code>
is not mandatory since some hypervisors do not handle it.
</p>
<h5><a name="elementVhostuser">vhost-user interface</a></h5>
<p>

View File

@ -2311,14 +2311,24 @@
<empty/>
</element>
</optional>
<optional>
<zeroOrMore>
<element name="ip">
<attribute name="address">
<ref name="ipv4Addr"/>
<ref name="ipAddr"/>
</attribute>
<optional>
<attribute name="family">
<ref name="addr-family"/>
</attribute>
</optional>
<optional>
<attribute name="prefix">
<ref name="ipPrefix"/>
</attribute>
</optional>
<empty/>
</element>
</optional>
</zeroOrMore>
<optional>
<element name="script">
<attribute name="path">

View File

@ -1414,6 +1414,8 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
void virDomainNetDefFree(virDomainNetDefPtr def)
{
size_t i;
if (!def)
return;
@ -1422,7 +1424,6 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_ETHERNET:
VIR_FREE(def->data.ethernet.dev);
VIR_FREE(def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
@ -1443,7 +1444,6 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
case VIR_DOMAIN_NET_TYPE_BRIDGE:
VIR_FREE(def->data.bridge.brname);
VIR_FREE(def->data.bridge.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
@ -1471,6 +1471,10 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
VIR_FREE(def->ifname_guest);
VIR_FREE(def->ifname_guest_actual);
for (i = 0; i < def->nips; i++)
VIR_FREE(def->ips[i]);
VIR_FREE(def->ips);
virDomainDeviceInfoClear(&def->info);
VIR_FREE(def->filter);
@ -4770,6 +4774,58 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
return ret;
}
static virDomainNetIpDefPtr
virDomainNetIpParseXML(xmlNodePtr node)
{
/* Parse the prefix in every case */
virDomainNetIpDefPtr ip = NULL;
char *prefixStr = NULL;
unsigned int prefixValue = 0;
char *familyStr = NULL;
int family = AF_UNSPEC;
char *address = NULL;
if (!(prefixStr = virXMLPropString(node, "prefix")) ||
(virStrToLong_ui(prefixStr, NULL, 10, &prefixValue) < 0)) {
// Don't shout, as some old config may not have a prefix
VIR_DEBUG("Missing or invalid network prefix");
}
if (!(address = virXMLPropString(node, "address"))) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("Missing network address"));
goto error;
}
familyStr = virXMLPropString(node, "family");
if (familyStr && STREQ(familyStr, "ipv4"))
family = AF_INET;
else if (familyStr && STREQ(familyStr, "ipv6"))
family = AF_INET6;
else
family = virSocketAddrNumericFamily(address);
if (VIR_ALLOC(ip) < 0)
goto error;
if (virSocketAddrParse(&ip->address, address, family) < 0) {
virReportError(VIR_ERR_INVALID_ARG,
_("Failed to parse IP address: '%s'"),
address);
goto error;
}
ip->prefix = prefixValue;
return ip;
error:
VIR_FREE(prefixStr);
VIR_FREE(familyStr);
VIR_FREE(address);
VIR_FREE(ip);
return NULL;
}
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
xmlXPathContextPtr ctxt,
@ -7208,6 +7264,31 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
#define NET_MODEL_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
int
virDomainNetAppendIpAddress(virDomainNetDefPtr def,
const char *address,
int family,
unsigned int prefix)
{
virDomainNetIpDefPtr ipDef = NULL;
if (VIR_ALLOC(ipDef) < 0)
return -1;
if (virSocketAddrParse(&ipDef->address, address, family) < 0)
goto error;
ipDef->prefix = prefix;
if (VIR_APPEND_ELEMENT(def->ips, def->nips, ipDef) < 0)
goto error;
return 0;
error:
VIR_FREE(ipDef);
return -1;
}
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
* @return 0 on success, -1 on failure
@ -7255,6 +7336,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
virDomainActualNetDefPtr actual = NULL;
xmlNodePtr oldnode = ctxt->node;
int ret, val;
size_t i;
size_t nips = 0;
virDomainNetIpDefPtr *ips = NULL;
if (VIR_ALLOC(def) < 0)
return NULL;
@ -7343,11 +7427,14 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlStrEqual(cur->name, BAD_CAST "source")) {
address = virXMLPropString(cur, "address");
port = virXMLPropString(cur, "port");
} else if (!address &&
(def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
xmlStrEqual(cur->name, BAD_CAST "ip")) {
address = virXMLPropString(cur, "address");
} else if (xmlStrEqual(cur->name, BAD_CAST "ip")) {
virDomainNetIpDefPtr ip = NULL;
if (!(ip = virDomainNetIpParseXML(cur)))
goto error;
if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
goto error;
} else if (!ifname &&
xmlStrEqual(cur->name, BAD_CAST "target")) {
ifname = virXMLPropString(cur, "dev");
@ -7547,10 +7634,6 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
def->data.ethernet.dev = dev;
dev = NULL;
}
if (address != NULL) {
def->data.ethernet.ipaddr = address;
address = NULL;
}
break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
@ -7562,10 +7645,6 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
}
def->data.bridge.brname = bridge;
bridge = NULL;
if (address != NULL) {
def->data.bridge.ipaddr = address;
address = NULL;
}
break;
case VIR_DOMAIN_NET_TYPE_CLIENT:
@ -7662,6 +7741,11 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
break;
}
for (i = 0; i < nips; i++) {
if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
goto error;
}
if (script != NULL) {
def->script = script;
script = NULL;
@ -7924,6 +8008,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
VIR_FREE(linkstate);
VIR_FREE(addrtype);
VIR_FREE(trustGuestRxFilters);
VIR_FREE(ips);
virNWFilterHashTableFree(filterparams);
return def;
@ -17042,6 +17127,30 @@ virDomainFSDefFormat(virBufferPtr buf,
return 0;
}
static void
virDomainNetIpsFormat(virBufferPtr buf, virDomainNetIpDefPtr *ips, size_t nips)
{
size_t i;
/* Output IP addresses */
for (i = 0; i < nips; i++) {
virSocketAddrPtr address = &ips[i]->address;
char *ipStr = virSocketAddrFormat(address);
const char *familyStr = NULL;
if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET6))
familyStr = "ipv6";
else if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET))
familyStr = "ipv4";
virBufferAsprintf(buf, "<ip address='%s'",
ipStr);
if (familyStr)
virBufferAsprintf(buf, " family='%s'", familyStr);
if (ips[i]->prefix != 0)
virBufferAsprintf(buf, " prefix='%u'", ips[i]->prefix);
virBufferAddLit(buf, "/>\n");
}
}
static int
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
virDomainHostdevDefPtr def,
@ -17274,7 +17383,6 @@ virDomainActualNetDefContentsFormat(virBufferPtr buf,
return 0;
}
/* virDomainActualNetDefFormat() - format the ActualNetDef
* info inside an <actual> element, as required for internal storage
* of domain status
@ -17511,9 +17619,6 @@ virDomainNetDefFormat(virBufferPtr buf,
case VIR_DOMAIN_NET_TYPE_ETHERNET:
virBufferEscapeString(buf, "<source dev='%s'/>\n",
def->data.ethernet.dev);
if (def->data.ethernet.ipaddr)
virBufferAsprintf(buf, "<ip address='%s'/>\n",
def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
@ -17531,10 +17636,6 @@ virDomainNetDefFormat(virBufferPtr buf,
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferEscapeString(buf, "<source bridge='%s'/>\n",
def->data.bridge.brname);
if (def->data.bridge.ipaddr) {
virBufferAsprintf(buf, "<ip address='%s'/>\n",
def->data.bridge.ipaddr);
}
break;
case VIR_DOMAIN_NET_TYPE_SERVER:
@ -17582,6 +17683,8 @@ virDomainNetDefFormat(virBufferPtr buf,
return -1;
}
virDomainNetIpsFormat(buf, def->ips, def->nips);
virBufferEscapeString(buf, "<script path='%s'/>\n",
def->script);
if (def->ifname &&

View File

@ -478,6 +478,13 @@ typedef enum {
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST
} virDomainHostdevCapsType;
typedef struct _virDomainNetIpDef virDomainNetIpDef;
typedef virDomainNetIpDef *virDomainNetIpDefPtr;
struct _virDomainNetIpDef {
virSocketAddr address; /* ipv4 or ipv6 address */
unsigned int prefix; /* number of 1 bits in the net mask */
};
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
struct _virDomainHostdevCaps {
@ -941,7 +948,6 @@ struct _virDomainNetDef {
union {
struct {
char *dev;
char *ipaddr;
} ethernet;
virDomainChrSourceDefPtr vhostuser;
struct {
@ -963,7 +969,6 @@ struct _virDomainNetDef {
} network;
struct {
char *brname;
char *ipaddr;
} bridge;
struct {
char *name;
@ -993,6 +998,8 @@ struct _virDomainNetDef {
virNetDevVlan vlan;
int trustGuestRxFilters; /* enum virTristateBool */
int linkstate;
size_t nips;
virDomainNetIpDefPtr *ips;
};
/* Used for prefix of ifname of any network name generated dynamically
@ -2554,6 +2561,10 @@ virNetDevBandwidthPtr
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);
virNetDevVlanPtr virDomainNetGetActualVlan(virDomainNetDefPtr iface);
bool virDomainNetGetActualTrustGuestRxFilters(virDomainNetDefPtr iface);
int virDomainNetAppendIpAddress(virDomainNetDefPtr def,
const char *address,
int family,
unsigned int prefix);
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller)

View File

@ -322,6 +322,7 @@ virDomainLockFailureTypeFromString;
virDomainLockFailureTypeToString;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainNetAppendIpAddress;
virDomainNetDefFormat;
virDomainNetDefFree;
virDomainNetFind;

View File

@ -230,7 +230,7 @@ openvzReadNetworkConf(virDomainDefPtr def,
goto error;
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
if (VIR_STRDUP(net->data.ethernet.ipaddr, token) < 0)
if (virDomainNetAppendIpAddress(net, token, AF_UNSPEC, 0) < 0)
goto error;
if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)

View File

@ -853,7 +853,7 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
(net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
net->data.ethernet.ipaddr == NULL)) {
net->nips == 0)) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
int veid = openvzGetVEID(vpsid);
@ -904,9 +904,10 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
virCommandAddArg(cmd, "--netif_add");
virCommandAddArgBuffer(cmd, &buf);
} else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
net->data.ethernet.ipaddr != NULL) {
net->nips > 0) {
/* --ipadd ip */
virCommandAddArgList(cmd, "--ipadd", net->data.ethernet.ipaddr, NULL);
char *ipStr = virSocketAddrFormat(&net->ips[0]->address);
virCommandAddArgList(cmd, "--ipadd", ipStr, NULL);
}
/* TODO: processing NAT and physical device */

View File

@ -6345,6 +6345,8 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
(brname = virDomainNetGetActualBridgeName(net))) {
char *brnamecopy;
size_t j;
if (VIR_STRDUP(brnamecopy, brname) < 0)
goto cleanup;
@ -6355,20 +6357,29 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = brnamecopy;
net->data.ethernet.ipaddr = NULL;
for (j = 0; j < net->nips; j++)
VIR_FREE(net->ips[j]);
VIR_FREE(net->ips);
net->nips = 0;
} else {
/* actualType is either NETWORK or DIRECT. In either
* case, the best we can do is NULL everything out.
*/
size_t j;
virDomainActualNetDefFree(net->data.network.actual);
memset(net, 0, sizeof(*net));
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = NULL;
net->data.ethernet.ipaddr = NULL;
for (j = 0; j < net->nips; j++)
VIR_FREE(net->ips[j]);
VIR_FREE(net->ips);
net->nips = 0;
}
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
size_t j;
VIR_FREE(net->data.direct.linkdev);
memset(net, 0, sizeof(*net));
@ -6376,18 +6387,23 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = NULL;
net->data.ethernet.ipaddr = NULL;
for (j = 0; j < net->nips; j++)
VIR_FREE(net->ips[j]);
VIR_FREE(net->ips);
net->nips = 0;
} else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
char *script = net->script;
char *brname = net->data.bridge.brname;
char *ipaddr = net->data.bridge.ipaddr;
size_t nips = net->nips;
virDomainNetIpDefPtr *ips = net->ips;
memset(net, 0, sizeof(*net));
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = script;
net->data.ethernet.dev = brname;
net->data.ethernet.ipaddr = ipaddr;
net->nips = nips;
net->ips = ips;
}
VIR_FREE(net->virtPortProfile);

View File

@ -2043,8 +2043,9 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (STRNEQ_NULLABLE(olddev->data.ethernet.dev,
newdev->data.ethernet.dev) ||
STRNEQ_NULLABLE(olddev->data.ethernet.ipaddr,
newdev->data.ethernet.ipaddr)) {
olddev->nips == 0 || newdev->nips == 0 ||
!virSocketAddrEqual(&olddev->ips[0]->address,
&newdev->ips[0]->address)) {
needReconnect = true;
}
break;

View File

@ -174,7 +174,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
virBufferAddLit(&buf, "tuntap,");
if (def->ifname)
virBufferAdd(&buf, def->ifname, -1);
if (def->data.ethernet.ipaddr) {
if (def->nips > 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("IP address not supported for ethernet interface"));
goto error;

View File

@ -1306,7 +1306,11 @@ vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
VIR_DEBUG("NIC(%zu): brname: %s", i, def->nets[i]->data.bridge.brname);
VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
VIR_DEBUG("NIC(%zu): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
if (def->nets[i]->nips > 0) {
char *ipStr = virSocketAddrFormat(&def->nets[i]->ips[0]->address);
VIR_DEBUG("NIC(%zu): ipaddr: %s", i, ipStr);
VIR_FREE(ipStr);
}
}
gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter);

View File

@ -920,12 +920,9 @@ xenParseVif(virConfPtr conf, virDomainDefPtr def)
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (bridge[0] && VIR_STRDUP(net->data.bridge.brname, bridge) < 0)
goto cleanup;
if (ip[0] && VIR_STRDUP(net->data.bridge.ipaddr, ip) < 0)
goto cleanup;
} else {
if (ip[0] && VIR_STRDUP(net->data.ethernet.ipaddr, ip) < 0)
goto cleanup;
}
if (ip[0] && virDomainNetAppendIpAddress(net, ip, AF_INET, 0) < 0)
goto cleanup;
if (script && script[0] &&
VIR_STRDUP(net->script, script) < 0)
@ -1223,16 +1220,22 @@ xenFormatNet(virConnectPtr conn,
switch (net->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferAsprintf(&buf, ",bridge=%s", net->data.bridge.brname);
if (net->data.bridge.ipaddr)
virBufferAsprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
if (net->nips > 0) {
char *ipStr = virSocketAddrFormat(&net->ips[0]->address);
virBufferAsprintf(&buf, ",ip=%s", ipStr);
VIR_FREE(ipStr);
}
virBufferAsprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (net->script)
virBufferAsprintf(&buf, ",script=%s", net->script);
if (net->data.ethernet.ipaddr)
virBufferAsprintf(&buf, ",ip=%s", net->data.ethernet.ipaddr);
if (net->nips > 0) {
char *ipStr = virSocketAddrFormat(&net->ips[0]->address);
virBufferAsprintf(&buf, ",ip=%s", ipStr);
VIR_FREE(ipStr);
}
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:

View File

@ -565,14 +565,14 @@ xenParseSxprNets(virDomainDefPtr def,
VIR_STRDUP(net->script, tmp2) < 0)
goto cleanup;
tmp = sexpr_node(node, "device/vif/ip");
if (VIR_STRDUP(net->data.bridge.ipaddr, tmp) < 0)
if (tmp && virDomainNetAppendIpAddress(net, tmp, AF_UNSPEC, 0) < 0)
goto cleanup;
} else {
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
if (VIR_STRDUP(net->script, tmp2) < 0)
goto cleanup;
tmp = sexpr_node(node, "device/vif/ip");
if (VIR_STRDUP(net->data.ethernet.ipaddr, tmp) < 0)
if (tmp && virDomainNetAppendIpAddress(net, tmp, AF_UNSPEC, 0) < 0)
goto cleanup;
}
@ -1898,8 +1898,11 @@ xenFormatSxprNet(virConnectPtr conn,
script = def->script;
virBufferEscapeSexpr(buf, "(script '%s')", script);
if (def->data.bridge.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.bridge.ipaddr);
if (def->nips > 0) {
char *ipStr = virSocketAddrFormat(&def->ips[0]->address);
virBufferEscapeSexpr(buf, "(ip '%s')", ipStr);
VIR_FREE(ipStr);
}
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
@ -1932,8 +1935,11 @@ xenFormatSxprNet(virConnectPtr conn,
if (def->script)
virBufferEscapeSexpr(buf, "(script '%s')",
def->script);
if (def->data.ethernet.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr);
if (def->nips > 0) {
char *ipStr = virSocketAddrFormat(&def->ips[0]->address);
virBufferEscapeSexpr(buf, "(ip '%s')", ipStr);
VIR_FREE(ipStr);
}
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:

View File

@ -28,6 +28,8 @@
<interface type='bridge'>
<mac address='00:16:3e:0f:ef:8a'/>
<source bridge='bri0'/>
<ip address='192.168.122.12' family='ipv4' prefix='24'/>
<ip address='192.168.122.13' family='ipv4' prefix='24'/>
<target dev='veth0'/>
<guest dev='eth2'/>
</interface>

View File

@ -93,7 +93,7 @@ testReadNetworkConf(const void *data ATTRIBUTE_UNUSED)
" <devices>\n"
" <interface type='ethernet'>\n"
" <mac address='00:00:00:00:00:00'/>\n"
" <ip address='194.44.18.88'/>\n"
" <ip address='194.44.18.88' family='ipv4'/>\n"
" </interface>\n"
" <interface type='bridge'>\n"
" <mac address='00:18:51:c1:05:ee'/>\n"

View File

@ -24,7 +24,7 @@
<interface type='bridge'>
<mac address='00:11:22:33:44:55'/>
<source bridge='xenbr2'/>
<ip address='192.0.2.1'/>
<ip address='192.0.2.1' family='ipv4'/>
<script path='vif-bridge'/>
<target dev='vif6.0'/>
</interface>

View File

@ -23,7 +23,7 @@
</disk>
<interface type='ethernet'>
<mac address='00:11:22:33:44:55'/>
<ip address='172.14.5.6'/>
<ip address='172.14.5.6' family='ipv4'/>
<script path='vif-routed'/>
<target dev='vif6.0'/>
</interface>