VirtualNetworkInterface: Absord MAC generating routines

This commit is contained in:
Cole Robinson 2013-07-12 09:54:01 -04:00
parent b26fd8fa3e
commit 534e613d40
4 changed files with 76 additions and 103 deletions

View File

@ -730,7 +730,7 @@ def validate_network(err, conn, nettype, devname, macaddr, model=None):
return err.val_err(_("Error with network parameters."), e)
# Make sure there is no mac address collision
isfatal, errmsg = net.is_conflict_net(conn.get_backend())
isfatal, errmsg = net.is_conflict_net(conn.get_backend(), net.macaddr)
if isfatal:
return err.val_err(_("Mac address collision."), errmsg)
elif errmsg is not None:

View File

@ -365,14 +365,7 @@ class Cloner(object):
if self._clone_macs:
mac = self._clone_macs.pop()
else:
while 1:
mac = util.randomMAC(self.conn)
ignore, msg = self._check_mac(mac)
if msg is not None:
continue
else:
break
mac = VirtualNetworkInterface.generate_mac(self.conn)
iface.macaddr = mac
# Changing storage XML
@ -503,11 +496,6 @@ class Cloner(object):
# Private helper functions #
############################
# Check if new mac address is valid
def _check_mac(self, mac):
nic = VirtualNetworkInterface(self.conn, macaddr=mac)
return nic.is_conflict_net(self.conn)
# Parse disk paths that need to be cloned from the original guest's xml
# Return a list of VirtualDisk instances pointing to the original
# storage

View File

@ -18,6 +18,8 @@
# MA 02110-1301 USA.
import logging
import random
import libvirt
from virtinst import util
@ -26,24 +28,31 @@ from virtinst import XMLBuilderDomain
from virtinst.XMLBuilderDomain import _xml_property
def _compareMAC(p, q):
"""Compare two MAC addresses"""
pa = p.split(":")
qa = q.split(":")
def _random_mac(conn):
"""Generate a random MAC address.
if len(pa) != len(qa):
if p > q:
return 1
else:
return -1
00-16-3E allocated to xensource
52-54-00 used by qemu/kvm
for i in xrange(len(pa)):
n = int(pa[i], 0x10) - int(qa[i], 0x10)
if n > 0:
return 1
elif n < 0:
return -1
return 0
The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt.
The remaining 3 fields are random, with the first bit of the first
random field set 0.
@return: MAC address string
"""
ouis = {'xen': [0x00, 0x16, 0x3E], 'qemu': [0x52, 0x54, 0x00]}
try:
oui = ouis[conn.getType().lower()]
except KeyError:
oui = ouis['xen']
mac = oui + [
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff)]
return ':'.join(["%02x" % x for x in mac])
class VirtualPort(XMLBuilderDomain.XMLBuilderDomain):
@ -109,6 +118,7 @@ class VirtualNetworkInterface(VirtualDevice):
network_types = [TYPE_BRIDGE, TYPE_VIRTUAL, TYPE_USER, TYPE_ETHERNET,
TYPE_DIRECT]
@staticmethod
def get_network_type_desc(net_type):
"""
Return human readable description for passed network type
@ -123,7 +133,48 @@ class VirtualNetworkInterface(VirtualDevice):
desc = _("Usermode networking")
return desc
get_network_type_desc = staticmethod(get_network_type_desc)
@staticmethod
def generate_mac(conn):
"""
Generate a random MAC that doesn't conflict with any VMs on
the connection.
"""
if hasattr(conn, "_virtinst__fake_conn_predictable"):
# Testing hack
return "00:11:22:33:44:55"
for ignore in range(256):
mac = _random_mac(conn)
ret = VirtualNetworkInterface.is_conflict_net(conn, mac)
if ret[1] is None:
return mac
logging.debug("Failed to generate non-conflicting MAC")
return None
@staticmethod
def is_conflict_net(conn, searchmac):
"""
@returns: a two element tuple:
first element is True if fatal collision occured
second element is a string description of the collision.
Non fatal collisions (mac addr collides with inactive guest) will
return (False, "description of collision")
"""
if searchmac is None:
return (False, None)
vms = conn.fetch_all_guests()
for vm in vms:
for nic in vm.get_devices("interface"):
nicmac = nic.macaddr or ""
if nicmac.lower() == searchmac.lower():
return (True, _("The MAC address '%s' is in use "
"by another virtual machine.") % searchmac)
return (False, None)
def __init__(self, conn, macaddr=None, type=TYPE_BRIDGE, bridge=None,
network=None, model=None,
@ -172,21 +223,6 @@ class VirtualNetworkInterface(VirtualDevice):
self._default_bridge = ret
return ret or None
def _generate_random_mac(self):
if not self._random_mac:
found = False
for ignore in range(256):
self._random_mac = util.randomMAC(self.conn)
ret = self.is_conflict_net(self.conn, self._random_mac)
if ret[1] is not None:
continue
found = True
break
if not found:
logging.debug("Failed to generate non-conflicting MAC")
return self._random_mac
def get_source(self):
"""
Convenince function, try to return the relevant <source> value
@ -231,9 +267,11 @@ class VirtualNetworkInterface(VirtualDevice):
def get_macaddr(self):
# Don't generate a random MAC if parsing XML, since it can be slow
if not self._macaddr and not self._is_parse():
return self._generate_random_mac()
return self._macaddr
if self._macaddr or self._is_parse():
return self._macaddr
if not self._random_mac:
self._random_mac = self.generate_mac(self.conn)
return self._random_mac
def set_macaddr(self, val):
util.validate_macaddr(val)
self._macaddr = val
@ -303,31 +341,9 @@ class VirtualNetworkInterface(VirtualDevice):
source_mode = _xml_property(get_source_mode, set_source_mode,
xpath="./source/@mode")
def is_conflict_net(self, conn, mac=None):
"""
@returns: a two element tuple:
first element is True if fatal collision occured
second element is a string description of the collision.
Non fatal collisions (mac addr collides with inactive guest) will
return (False, "description of collision")
"""
searchmac = mac or self.macaddr
if searchmac is None:
return (False, None)
vms = self.conn.fetch_all_guests()
for vm in vms:
for nic in vm.get_devices("interface"):
nicmac = nic.macaddr or ""
if nicmac.lower() == searchmac.lower():
return (True, _("The MAC address '%s' is in use "
"by another virtual machine.") % searchmac)
return (False, None)
def setup(self, meter=None):
if self.macaddr:
ret, msg = self.is_conflict_net(self.conn)
ret, msg = self.is_conflict_net(self.conn, self.macaddr)
if msg is not None:
if ret is False:
logging.warning(msg)

View File

@ -360,37 +360,6 @@ def is_blktap_capable(conn):
return False
def randomMAC(conn):
"""Generate a random MAC address.
00-16-3E allocated to xensource
52-54-00 used by qemu/kvm
The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt.
The remaining 3 fields are random, with the first bit of the first
random field set 0.
@return: MAC address string
"""
if hasattr(conn, "_virtinst__fake_conn_predictable"):
# Testing hack
return "00:11:22:33:44:55"
ouis = {'xen': [0x00, 0x16, 0x3E], 'qemu': [0x52, 0x54, 0x00]}
try:
oui = ouis[conn.getType().lower()]
except KeyError:
oui = ouis['xen']
mac = oui + [
random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff)]
return ':'.join(["%02x" % x for x in mac])
def randomUUID(conn):
if hasattr(conn, "_virtinst__fake_conn_predictable"):
# Testing hack