<h3><a name="elementsAddress">Addressing</a></h3>
<p>
- The final set of elements define the IPv4 address range available,
- and optionally enable DHCP sevices.
+ The final set of elements define the addresses (IPv4 and/or
+ IPv6, as well as MAC) to be assigned to the bridge device
+ associated with the virtual network, and optionally enable DHCP
+ services.
</p>
<pre>
...
+ <mac address='00:16:3E:5D:C7:9E'/>
<ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.122.100" end="192.168.122.254" />
</network></pre>
<dl>
+ <dt><code>mac</code></dt>
+ <dd>The <code>address</code> attribute defines a MAC
+ (hardware) address formatted as 6 groups of 2-digit
+ hexadecimal numbers, the groups separated by colons
+ (eg, <code>"52:54:00:1C:DA:2F"</code>). This MAC address is
+ assigned to the bridge device when it is created. Generally
+ it is best to not specify a MAC address when creating a
+ network - in this case, if a defined MAC address is needed for
+ proper operation, libvirt will automatically generate a random
+ MAC address and save it in the config. Allowing libvirt to
+ generate the MAC address will assure that it is compatible
+ with the idiosyncrasies of the platform where libvirt is
+ running. <span class="since">Since 0.8.8</span>
+ </dd>
<dt><code>ip</code></dt>
<dd>The <code>address</code> attribute defines an IPv4 address in
dotted-decimal format, or an IPv6 address in standard
</element>
</optional>
+ <!-- <mac> element -->
+ <optional>
+ <element name="mac">
+ <attribute name="address"><ref name="mac-addr"/></attribute>
+ <empty/>
+ </element>
+ </optional>
+
<!-- <forward> element -->
<optional>
<!-- The device through which the bridge is connected to the
> %{_sysconfdir}/libvirt/qemu/networks/default.xml
ln -s ../default.xml %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
fi
+
+# All newly defined networks will have a mac address for the bridge
+# auto-generated, but networks already existing at the time of upgrade
+# will not. We need to go through all the network configs, look for
+# those that don't have a mac address, and add one.
+
+network_files=$( (cd %{_localstatedir}/lib/libvirt/network && \
+ grep -L "mac address" *.xml; \
+ cd %{_sysconfdir}/libvirt/qemu/networks && \
+ grep -L "mac address" *.xml) 2>/dev/null \
+ | sort -u)
+
+for file in $network_files
+do
+ # each file exists in either the config or state directory (or both) and
+ # does not have a mac address specified in either. We add the same mac
+ # address to both files (or just one, if the other isn't there)
+
+ mac4=`printf '%X' $(($RANDOM % 256))`
+ mac5=`printf '%X' $(($RANDOM % 256))`
+ mac6=`printf '%X' $(($RANDOM % 256))`
+ for dir in %{_localstatedir}/lib/libvirt/network \
+ %{_sysconfdir}/libvirt/qemu/networks
+ do
+ if test -f $dir/$file
+ then
+ sed -i.orig -e \
+ "s|\(<bridge.*$\)|\0\n <mac address='52:54:00:$mac4:$mac5:$mac6'/>|" \
+ $dir/$file
+ if test $? != 0
+ then
+ echo "failed to add <mac address='52:54:00:$mac4:$mac5:$mac6'/>" \
+ "to $dir/$file"
+ mv -f $dir/$file.orig $dir/$file
+ else
+ rm -f $dir/$file.orig
+ fi
+ fi
+ done
+done
%endif
%if %{with_cgconfig}
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
def->delay = 0;
+ tmp = virXPathString("string(./mac[1]/@address)", ctxt);
+ if (tmp) {
+ if (virParseMacAddr(tmp, def->mac) < 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Invalid bridge mac address '%s' in network '%s'"),
+ tmp, def->name);
+ VIR_FREE(tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ def->mac_specified = true;
+ }
+
nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
if (nIps > 0) {
int ii;
virBufferVSprintf(&buf, " stp='%s' delay='%ld' />\n",
def->stp ? "on" : "off",
def->delay);
+ if (def->mac_specified) {
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+ virFormatMacAddr(def->mac, macaddr);
+ virBufferVSprintf(&buf, " <mac address='%s'/>\n", macaddr);
+ }
if (def->domain)
virBufferVSprintf(&buf, " <domain name='%s'/>\n", def->domain);
}
+void virNetworkSetBridgeMacAddr(virNetworkDefPtr def)
+{
+ if (!def->mac_specified) {
+ /* if the bridge doesn't have a mac address explicitly defined,
+ * autogenerate a random one.
+ */
+ virGenerateMacAddr((unsigned char[]){ 0x52, 0x54, 0 },
+ def->mac);
+ def->mac_specified = true;
+ }
+}
+
/*
* virNetworkObjIsDuplicate:
* @doms : virNetworkObjListPtr to search
# include "internal.h"
# include "threads.h"
# include "network.h"
+# include "util.h"
/* 2 possible types of forwarding */
enum virNetworkForwardType {
char *domain;
unsigned long delay; /* Bridge forward delay (ms) */
unsigned int stp :1; /* Spanning tree protocol */
+ unsigned char mac[VIR_MAC_BUFLEN]; /* mac address of bridge device */
+ bool mac_specified;
int forwardType; /* One of virNetworkForwardType constants */
char *forwardDev; /* Destination device for forwarding */
virNetworkDefPtr def,
int check_collision);
+void virNetworkSetBridgeMacAddr(virNetworkDefPtr def);
+
int virNetworkObjIsDuplicate(virNetworkObjListPtr doms,
virNetworkDefPtr def,
unsigned int check_active);
virNetworkObjUnlock;
virNetworkRemoveInactive;
virNetworkSaveConfig;
+virNetworkSetBridgeMacAddr;
virNetworkSetBridgeName;
virFindFileInPath;
virFork;
virFormatMacAddr;
+virGenerateMacAddr;
virGetGroupID;
virGetHostname;
virGetUserDirectory;
return configfile;
}
+static char *
+networkBridgeDummyNicName(const char *brname)
+{
+ char *nicname;
+
+ virAsprintf(&nicname, "%s-nic", brname);
+ return nicname;
+}
+
static void
networkFindActiveConfigs(struct network_driver *driver) {
unsigned int i;
bool v4present = false, v6present = false;
virErrorPtr save_err = NULL;
virNetworkIpDefPtr ipdef;
+ char *macTapIfName;
if (virNetworkObjIsActive(network)) {
networkReportError(VIR_ERR_OPERATION_INVALID,
return -1;
}
+ if (network->def->mac_specified) {
+ /* To set a mac for the bridge, we need to define a dummy tap
+ * device, set its mac, then attach it to the bridge. As long
+ * as its mac address is lower than any other interface that
+ * gets attached, the bridge will always maintain this mac
+ * address.
+ */
+ macTapIfName = networkBridgeDummyNicName(network->def->bridge);
+ if (!macTapIfName) {
+ virReportOOMError();
+ goto err0;
+ }
+ if ((err = brAddTap(driver->brctl, network->def->bridge,
+ &macTapIfName, network->def->mac, 0, false, NULL))) {
+ virReportSystemError(err,
+ _("cannot create dummy tap device '%s' to set mac"
+ " address on bridge '%s'"),
+ macTapIfName, network->def->bridge);
+ VIR_FREE(macTapIfName);
+ goto err0;
+ }
+ VIR_FREE(macTapIfName);
+ }
+
/* Set bridge options */
if (brSetForwardDelay(driver->brctl, network->def->bridge,
network->def->delay)) {
networkRemoveIptablesRules(driver, network);
err1:
+ if (!save_err)
+ save_err = virSaveLastError();
+
+ if ((err = brDeleteTap(driver->brctl, macTapIfName))) {
+ char ebuf[1024];
+ VIR_WARN("Failed to delete dummy tap device '%s' on bridge '%s' : %s",
+ macTapIfName, network->def->bridge,
+ virStrerror(err, ebuf, sizeof ebuf));
+ }
+
+ err0:
if (!save_err)
save_err = virSaveLastError();
if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
{
int err;
char *stateFile;
+ char *macTapIfName;
VIR_INFO(_("Shutting down network '%s'"), network->def->name);
kill(network->dnsmasqPid, SIGTERM);
char ebuf[1024];
+
+ if (network->def->mac_specified) {
+ macTapIfName = networkBridgeDummyNicName(network->def->bridge);
+ if (!macTapIfName) {
+ virReportOOMError();
+ } else {
+ if ((err = brDeleteTap(driver->brctl, macTapIfName))) {
+ VIR_WARN("Failed to delete dummy tap device '%s' on bridge '%s' : %s",
+ macTapIfName, network->def->bridge,
+ virStrerror(err, ebuf, sizeof ebuf));
+ }
+ VIR_FREE(macTapIfName);
+ }
+ }
+
if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
VIR_WARN("Failed to bring down bridge '%s' : %s",
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
if (virNetworkSetBridgeName(&driver->networks, def, 1))
goto cleanup;
+ virNetworkSetBridgeMacAddr(def);
+
if (!(network = virNetworkAssignDef(&driver->networks,
def)))
goto cleanup;
if (virNetworkSetBridgeName(&driver->networks, def, 1))
goto cleanup;
+ virNetworkSetBridgeMacAddr(def);
+
if (!(network = virNetworkAssignDef(&driver->networks,
def)))
goto cleanup;
<name>private</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
<bridge name="virbr2" />
+ <mac address='52:54:00:17:3F:37'/>
<ip address="192.168.152.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.152.2" end="192.168.152.254" />
<name>local</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
<bridge name="virbr1" />
+ <mac address='12:34:56:78:9A:BC'/>
<forward mode="route" dev="eth1"/>
<ip address="192.168.122.1" netmask="255.255.255.0">
</ip>
<name>private</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
<bridge name='virbr2' stp='on' delay='0' />
+ <mac address='52:54:00:17:3F:37'/>
<ip address='192.168.152.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.152.2' end='192.168.152.254' />
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
<forward dev='eth1' mode='route'/>
<bridge name='virbr1' stp='on' delay='0' />
+ <mac address='12:34:56:78:9A:BC'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
</network>