2013-03-18 01:06:52 +04:00
#
2013-10-28 00:59:46 +04:00
# Copyright 2006-2009, 2013 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
# Jeremy Katz <katzj@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
2013-10-28 00:59:47 +04:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2013-03-18 01:06:52 +04:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
import logging
2013-07-12 17:54:01 +04:00
import random
2013-04-11 03:48:07 +04:00
from virtinst import util
2013-08-09 04:47:17 +04:00
from virtinst import VirtualDevice
2013-09-11 19:47:09 +04:00
from virtinst . xmlbuilder import XMLBuilder , XMLChildProperty , XMLProperty
2013-03-18 01:06:52 +04:00
2013-04-11 19:11:21 +04:00
2013-07-12 17:54:01 +04:00
def _random_mac ( conn ) :
""" Generate a random MAC address.
00 - 16 - 3 E 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.
2013-04-11 19:11:21 +04:00
2013-07-12 17:54:01 +04:00
@return : MAC address string
"""
ouis = { ' xen ' : [ 0x00 , 0x16 , 0x3E ] , ' qemu ' : [ 0x52 , 0x54 , 0x00 ] }
2013-04-11 19:11:21 +04:00
2013-07-12 17:54:01 +04:00
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 ] )
2013-04-11 19:11:21 +04:00
2013-04-13 22:34:52 +04:00
2013-07-14 02:56:09 +04:00
class VirtualPort ( XMLBuilder ) :
2013-09-11 19:47:09 +04:00
_XML_ROOT_NAME = " virtualport "
2013-07-24 20:02:37 +04:00
2013-09-11 19:47:09 +04:00
type = XMLProperty ( " ./@type " )
managerid = XMLProperty ( " ./parameters/@managerid " , is_int = True )
typeid = XMLProperty ( " ./parameters/@typeid " , is_int = True )
typeidversion = XMLProperty ( " ./parameters/@typeidversion " , is_int = True )
instanceid = XMLProperty ( " ./parameters/@instanceid " )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-04-11 03:48:07 +04:00
class VirtualNetworkInterface ( VirtualDevice ) :
2013-07-16 17:14:37 +04:00
virtual_device_type = VirtualDevice . VIRTUAL_DEV_NET
2013-03-18 01:06:52 +04:00
TYPE_BRIDGE = " bridge "
TYPE_VIRTUAL = " network "
TYPE_USER = " user "
TYPE_ETHERNET = " ethernet "
TYPE_DIRECT = " direct "
network_types = [ TYPE_BRIDGE , TYPE_VIRTUAL , TYPE_USER , TYPE_ETHERNET ,
TYPE_DIRECT ]
2013-07-12 17:54:01 +04:00
@staticmethod
2013-03-18 01:06:52 +04:00
def get_network_type_desc ( net_type ) :
"""
Return human readable description for passed network type
"""
desc = net_type . capitalize ( )
if net_type == VirtualNetworkInterface . TYPE_BRIDGE :
desc = _ ( " Shared physical device " )
elif net_type == VirtualNetworkInterface . TYPE_VIRTUAL :
desc = _ ( " Virtual networking " )
elif net_type == VirtualNetworkInterface . TYPE_USER :
desc = _ ( " Usermode networking " )
return desc
2013-07-12 17:54:01 +04:00
@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 )
2013-03-18 01:06:52 +04:00
2013-09-11 19:47:09 +04:00
def __init__ ( self , * args , * * kwargs ) :
VirtualDevice . __init__ ( self , * args , * * kwargs )
2013-03-18 01:06:52 +04:00
self . _random_mac = None
self . _default_bridge = None
2013-09-24 18:00:01 +04:00
###############
# XML helpers #
###############
2013-03-18 01:06:52 +04:00
def _generate_default_bridge ( self ) :
ret = self . _default_bridge
if ret is None :
ret = False
2013-04-11 19:14:13 +04:00
default = util . default_bridge ( self . conn )
2013-03-18 01:06:52 +04:00
if default :
ret = default [ 1 ]
self . _default_bridge = ret
return ret or None
2013-09-24 18:00:01 +04:00
def _get_default_bridge ( self ) :
if self . type == self . TYPE_BRIDGE :
return self . _generate_default_bridge ( )
return None
def _default_source_mode ( self ) :
if self . type == self . TYPE_DIRECT :
return " vepa "
return None
def _get_default_mac ( self ) :
if not self . _random_mac :
self . _random_mac = self . generate_mac ( self . conn )
return self . _random_mac
def _validate_mac ( self , val ) :
util . validate_macaddr ( val )
return val
def _get_source ( self ) :
2013-03-18 01:06:52 +04:00
"""
Convenince function , try to return the relevant < source > value
per the network type .
"""
if self . type == self . TYPE_VIRTUAL :
2013-09-24 18:00:01 +04:00
return self . _network
2013-03-18 01:06:52 +04:00
if self . type == self . TYPE_BRIDGE :
2013-09-24 18:00:01 +04:00
return self . _bridge
2013-03-18 01:06:52 +04:00
if self . type == self . TYPE_ETHERNET or self . type == self . TYPE_DIRECT :
2013-09-24 18:00:01 +04:00
return self . _source_dev
2013-03-18 01:06:52 +04:00
if self . type == self . TYPE_USER :
return None
2013-09-24 18:00:01 +04:00
return self . _network or self . _bridge or self . _source_dev
def _set_source ( self , newsource ) :
2013-03-18 01:06:52 +04:00
"""
Conveninece function , try to set the relevant < source > value
per the network type
"""
2013-09-24 18:00:01 +04:00
self . _bridge = None
self . _network = None
self . _source_dev = None
2013-04-13 22:34:52 +04:00
if self . type == self . TYPE_VIRTUAL :
2013-09-24 18:00:01 +04:00
self . _network = newsource
2013-03-18 01:06:52 +04:00
elif self . type == self . TYPE_BRIDGE :
2013-09-24 18:00:01 +04:00
self . _bridge = newsource
2013-03-18 01:06:52 +04:00
elif self . type == self . TYPE_ETHERNET or self . type == self . TYPE_DIRECT :
2013-09-24 18:00:01 +04:00
self . _source_dev = newsource
source = property ( _get_source , _set_source )
2013-03-18 01:06:52 +04:00
2013-07-15 21:56:49 +04:00
2013-09-24 18:00:01 +04:00
##################
# XML properties #
##################
2013-07-15 21:56:49 +04:00
2013-07-16 20:48:52 +04:00
_XML_PROP_ORDER = [
2013-09-24 18:00:01 +04:00
" _bridge " , " _network " , " _source_dev " , " source_mode " ,
2013-08-28 19:36:25 +04:00
" macaddr " , " target_dev " , " model " , " virtualport " ,
" filterref " ]
2013-07-15 21:56:49 +04:00
2013-09-24 18:00:01 +04:00
_bridge = XMLProperty ( " ./source/@bridge " , default_cb = _get_default_bridge )
_network = XMLProperty ( " ./source/@network " )
_source_dev = XMLProperty ( " ./source/@dev " )
2013-09-11 19:47:09 +04:00
virtualport = XMLChildProperty ( VirtualPort , is_single = True )
2013-09-19 21:27:30 +04:00
type = XMLProperty ( " ./@type " ,
2013-07-15 22:14:05 +04:00
default_cb = lambda s : s . TYPE_BRIDGE )
2013-07-15 21:56:49 +04:00
2013-09-19 21:27:30 +04:00
macaddr = XMLProperty ( " ./mac/@address " ,
2013-07-15 21:56:49 +04:00
set_converter = _validate_mac ,
default_cb = _get_default_mac )
2013-03-18 01:06:52 +04:00
2013-09-19 21:27:30 +04:00
source_mode = XMLProperty ( " ./source/@mode " ,
2013-07-15 21:56:49 +04:00
default_cb = _default_source_mode )
2013-09-19 21:27:30 +04:00
model = XMLProperty ( " ./model/@type " )
target_dev = XMLProperty ( " ./target/@dev " )
filterref = XMLProperty ( " ./filterref/@filter " )
2013-07-24 16:46:55 +04:00
2014-02-01 16:48:04 +04:00
driver_name = XMLProperty ( " ./driver/@name " )
driver_queues = XMLProperty ( " ./driver/@queues " , is_int = True )
2013-07-24 16:46:55 +04:00
2013-09-24 18:00:01 +04:00
#############
# Build API #
#############
def setup ( self , meter = None ) :
ignore = meter
if not self . macaddr :
return
ret , msg = self . is_conflict_net ( self . conn , self . macaddr )
if msg is None :
return
if ret is False :
logging . warning ( msg )
else :
raise RuntimeError ( msg )
2014-02-06 02:45:46 +04:00
def set_default_source ( self ) :
if ( self . conn . is_qemu_session ( ) or self . conn . is_test ( ) ) :
self . type = self . TYPE_USER
else :
self . type , self . source = util . default_network ( self . conn )
2013-09-24 18:00:01 +04:00
2013-07-24 16:46:55 +04:00
VirtualNetworkInterface . register_type ( )