2013-03-18 01:06:52 +04:00
#
# Copyright 2006-2009 Red Hat, Inc.
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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
import libvirt
2013-04-11 03:48:07 +04:00
from virtinst import util
from virtinst . VirtualDevice import VirtualDevice
from virtinst import XMLBuilderDomain
from virtinst . XMLBuilderDomain import _xml_property
2013-03-18 01:06:52 +04:00
2013-04-11 19:11:21 +04:00
def _compareMAC ( p , q ) :
""" Compare two MAC addresses """
pa = p . split ( " : " )
qa = q . split ( " : " )
if len ( pa ) != len ( qa ) :
if p > q :
return 1
else :
return - 1
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
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
class VirtualPort ( XMLBuilderDomain . XMLBuilderDomain ) :
2013-07-06 22:12:13 +04:00
def __init__ ( self , conn , parsexml = None , parsexmlnode = None ) :
2013-03-18 01:06:52 +04:00
XMLBuilderDomain . XMLBuilderDomain . __init__ ( self , conn , parsexml ,
2013-07-06 22:12:13 +04:00
parsexmlnode )
2013-03-18 01:06:52 +04:00
self . _type = None
self . _managerid = None
self . _typeid = None
self . _typeidversion = None
self . _instanceid = None
def get_type ( self ) :
return self . _type
def set_type ( self , val ) :
self . _type = val
type = _xml_property ( get_type , set_type ,
xpath = " ./virtualport/@type " )
def get_managerid ( self ) :
return self . _managerid
def set_managerid ( self , val ) :
self . _managerid = val
managerid = _xml_property ( get_managerid , set_managerid ,
xpath = " ./virtualport/parameters/@managerid " )
def get_typeid ( self ) :
return self . _typeid
def set_typeid ( self , val ) :
self . _typeid = val
typeid = _xml_property ( get_typeid , set_typeid ,
xpath = " ./virtualport/parameters/@typeid " )
def get_typeidversion ( self ) :
return self . _typeidversion
def set_typeidversion ( self , val ) :
self . _typeidversion = val
typeidversion = _xml_property ( get_typeidversion , set_typeidversion ,
xpath = " ./virtualport/parameters/@typeidversion " )
def get_instanceid ( self ) :
return self . _instanceid
def set_instanceid ( self , val ) :
self . _instanceid = val
instanceid = _xml_property ( get_instanceid , set_instanceid ,
xpath = " ./virtualport/parameters/@instanceid " )
def _get_xml_config ( self ) :
# FIXME: This should be implemented, currently we can only parse
return " "
2013-04-13 22:34:52 +04:00
2013-04-11 03:48:07 +04:00
class VirtualNetworkInterface ( VirtualDevice ) :
2013-03-18 01:06:52 +04:00
2013-04-11 03:48:07 +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 ]
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
get_network_type_desc = staticmethod ( get_network_type_desc )
2013-07-06 04:14:57 +04:00
def __init__ ( self , conn , macaddr = None , type = TYPE_BRIDGE , bridge = None ,
network = None , model = None ,
2013-07-06 22:12:13 +04:00
parsexml = None , parsexmlnode = None ) :
2013-04-12 17:51:26 +04:00
# pylint: disable=W0622
# Redefining built-in 'type', but it matches the XML so keep it
2013-07-06 22:12:13 +04:00
VirtualDevice . __init__ ( self , conn , parsexml , parsexmlnode )
2013-03-18 01:06:52 +04:00
self . _network = None
self . _bridge = None
self . _macaddr = None
self . _type = None
self . _model = None
self . _target_dev = None
self . _source_dev = None
self . _source_mode = " vepa "
2013-07-06 22:12:13 +04:00
self . _virtualport = VirtualPort ( conn , parsexml , parsexmlnode )
2013-03-18 01:06:52 +04:00
# Generate _random_mac
self . _random_mac = None
self . _default_bridge = None
if self . _is_parse ( ) :
return
self . type = type
self . macaddr = macaddr
self . bridge = bridge
self . source_dev = bridge
self . network = network
self . model = model
if self . type == self . TYPE_VIRTUAL :
if network is None :
raise ValueError ( _ ( " A network name was not provided " ) )
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
def _generate_random_mac ( self ) :
2013-07-06 04:14:57 +04:00
if not self . _random_mac :
2013-03-18 01:06:52 +04:00
found = False
for ignore in range ( 256 ) :
2013-07-06 04:14:57 +04:00
self . _random_mac = util . randomMAC ( self . conn )
2013-03-18 01:06:52 +04:00
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
per the network type .
"""
if self . type == self . TYPE_VIRTUAL :
return self . network
if self . type == self . TYPE_BRIDGE :
return self . bridge
if self . type == self . TYPE_ETHERNET or self . type == self . TYPE_DIRECT :
return self . source_dev
if self . type == self . TYPE_USER :
return None
return self . network or self . bridge or self . source_dev
def set_source ( self , newsource ) :
"""
Conveninece function , try to set the relevant < source > value
per the network type
"""
2013-04-13 22:34:52 +04:00
if self . type == self . TYPE_VIRTUAL :
2013-03-18 01:06:52 +04:00
self . network = newsource
elif self . type == self . TYPE_BRIDGE :
self . bridge = newsource
elif self . type == self . TYPE_ETHERNET or self . type == self . TYPE_DIRECT :
self . source_dev = newsource
return
source = property ( get_source , set_source )
def _get_virtualport ( self ) :
return self . _virtualport
virtualport = property ( _get_virtualport )
def get_type ( self ) :
return self . _type
def set_type ( self , val ) :
if val not in self . network_types :
raise ValueError ( _ ( " Unknown network type %s " ) % val )
self . _type = val
type = _xml_property ( get_type , set_type ,
xpath = " ./@type " )
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
def set_macaddr ( self , val ) :
2013-04-11 18:27:02 +04:00
util . validate_macaddr ( val )
2013-03-18 01:06:52 +04:00
self . _macaddr = val
macaddr = _xml_property ( get_macaddr , set_macaddr ,
xpath = " ./mac/@address " )
def get_network ( self ) :
return self . _network
def set_network ( self , newnet ) :
def _is_net_active ( netobj ) :
# Apparently the 'info' command was never hooked up for
# libvirt virNetwork python apis.
if not self . conn :
return True
return self . conn . listNetworks ( ) . count ( netobj . name ( ) )
if newnet is not None and self . conn :
try :
net = self . conn . networkLookupByName ( newnet )
except libvirt . libvirtError , e :
2013-04-13 22:34:52 +04:00
raise ValueError ( _ ( " Virtual network ' %s ' does not exist: %s " )
2013-03-18 01:06:52 +04:00
% ( newnet , str ( e ) ) )
if not _is_net_active ( net ) :
raise ValueError ( _ ( " Virtual network ' %s ' has not been "
" started. " ) % newnet )
self . _network = newnet
network = _xml_property ( get_network , set_network ,
xpath = " ./source/@network " )
def get_bridge ( self ) :
if ( not self . _is_parse ( ) and
not self . _bridge and
self . type == self . TYPE_BRIDGE ) :
return self . _generate_default_bridge ( )
return self . _bridge
def set_bridge ( self , val ) :
self . _bridge = val
bridge = _xml_property ( get_bridge , set_bridge ,
xpath = " ./source/@bridge " )
def get_model ( self ) :
return self . _model
def set_model ( self , val ) :
self . _model = val
model = _xml_property ( get_model , set_model ,
xpath = " ./model/@type " )
def get_target_dev ( self ) :
return self . _target_dev
def set_target_dev ( self , val ) :
self . _target_dev = val
target_dev = _xml_property ( get_target_dev , set_target_dev ,
xpath = " ./target/@dev " )
def get_source_dev ( self ) :
return self . _source_dev
def set_source_dev ( self , val ) :
self . _source_dev = val
source_dev = _xml_property ( get_source_dev , set_source_dev ,
xpath = " ./source/@dev " )
def get_source_mode ( self ) :
return self . _source_mode
def set_source_mode ( self , newmode ) :
self . _source_mode = newmode
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 " )
"""
2013-07-08 02:54:08 +04:00
searchmac = mac or self . macaddr
if searchmac is None :
2013-03-18 01:06:52 +04:00
return ( False , None )
2013-07-10 03:50:49 +04:00
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 )
2013-03-18 01:06:52 +04:00
return ( False , None )
2013-07-06 04:14:57 +04:00
def setup ( self , meter = None ) :
2013-03-18 01:06:52 +04:00
if self . macaddr :
2013-07-06 04:14:57 +04:00
ret , msg = self . is_conflict_net ( self . conn )
2013-03-18 01:06:52 +04:00
if msg is not None :
if ret is False :
logging . warning ( msg )
else :
raise RuntimeError ( msg )
def _get_xml_config ( self ) :
src_xml = " "
model_xml = " "
target_xml = " "
addr_xml = " "
if self . type == self . TYPE_BRIDGE :
src_xml = " <source bridge= ' %s ' /> \n " % self . bridge
elif self . type == self . TYPE_VIRTUAL :
src_xml = " <source network= ' %s ' /> \n " % self . network
elif self . type == self . TYPE_ETHERNET and self . source_dev :
src_xml = " <source dev= ' %s ' /> \n " % self . source_dev
elif self . type == self . TYPE_DIRECT and self . source_dev :
src_xml = " <source dev= ' %s ' mode= ' %s ' /> \n " % ( self . source_dev , self . source_mode )
if self . model :
model_xml = " <model type= ' %s ' /> \n " % self . model
if self . address :
addr_xml = self . indent ( self . address . get_xml_config ( ) , 6 )
if self . target_dev :
target_xml = " <target dev= ' %s ' /> \n " % self . target_dev
xml = " <interface type= ' %s ' > \n " % self . type
xml + = src_xml
xml + = " <mac address= ' %s ' /> \n " % self . macaddr
xml + = target_xml
xml + = model_xml
xml + = addr_xml
xml + = " </interface> "
return xml