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>
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-03-18 01:06:52 +04:00
import logging
2016-08-24 23:14:33 +03:00
import os
2013-07-12 17:54:01 +04:00
import random
2018-03-20 19:27:37 +03:00
from . . import util
2018-03-20 19:18:35 +03:00
from . device import Device
2018-03-20 19:27:37 +03:00
from . . 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
2018-04-30 15:56:53 +03:00
The OUI list is available at https : / / standards . ieee . org / regauth / oui / oui . txt .
2013-07-12 17:54:01 +04:00
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
"""
2013-04-11 19:11:21 +04:00
2014-09-12 17:36:35 +04:00
if conn . is_qemu ( ) :
oui = [ 0x52 , 0x54 , 0x00 ]
else :
# Xen
oui = [ 0x00 , 0x16 , 0x3E ]
2013-07-12 17:54:01 +04:00
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
2016-08-24 23:14:33 +03:00
def _default_route ( ) :
route_file = " /proc/net/route "
if not os . path . exists ( route_file ) :
logging . debug ( " route_file= %s does not exist " , route_file )
return None
2017-05-05 21:19:54 +03:00
for line in open ( route_file ) :
2016-08-24 23:14:33 +03:00
info = line . split ( )
if len ( info ) != 11 :
logging . debug ( " Unexpected field count= %s when parsing %s " ,
len ( info ) , route_file )
break
try :
route = int ( info [ 1 ] , 16 )
if route == 0 :
return info [ 0 ]
except ValueError :
continue
return None
def _default_bridge ( conn ) :
if " VIRTINST_TEST_SUITE " in os . environ :
return " eth0 "
if conn . is_remote ( ) :
return None
dev = _default_route ( )
if not dev :
return None
# New style peth0 == phys dev, eth0 == bridge, eth0 == default route
if os . path . exists ( " /sys/class/net/ %s /bridge " % dev ) :
return dev
# Old style, peth0 == phys dev, eth0 == netloop, xenbr0 == bridge,
# vif0.0 == netloop enslaved, eth0 == default route
try :
defn = int ( dev [ - 1 ] )
2017-07-24 11:26:48 +03:00
except Exception :
2016-08-24 23:14:33 +03:00
defn = - 1
if ( defn > = 0 and
os . path . exists ( " /sys/class/net/peth %d /brport " % defn ) and
os . path . exists ( " /sys/class/net/xenbr %d /bridge " % defn ) ) :
return " xenbr %d "
return None
def _default_network ( conn ) :
ret = _default_bridge ( conn )
if ret :
return [ " bridge " , ret ]
return [ " network " , " default " ]
2018-03-20 19:18:35 +03:00
class _VirtualPort ( XMLBuilder ) :
2018-03-21 17:53:34 +03:00
XML_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 " )
2015-08-28 14:12:49 +03:00
profileid = XMLProperty ( " ./parameters/@profileid " )
interfaceid = XMLProperty ( " ./parameters/@interfaceid " )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2018-03-20 19:18:35 +03:00
class DeviceInterface ( Device ) :
2018-03-21 17:53:34 +03:00
XML_NAME = " interface "
2013-03-18 01:06:52 +04:00
TYPE_BRIDGE = " bridge "
TYPE_VIRTUAL = " network "
TYPE_USER = " user "
2016-08-27 08:41:38 +03:00
TYPE_VHOSTUSER = " vhostuser "
2013-03-18 01:06:52 +04:00
TYPE_ETHERNET = " ethernet "
TYPE_DIRECT = " direct "
2018-09-02 03:36:53 +03:00
@staticmethod
def get_models ( guest ) :
if not guest . os . is_hvm ( ) :
return [ ]
ret = [ ]
if guest . type in [ " kvm " , " qemu " , " vz " , " test " ] :
ret . append ( " virtio " )
if guest . os . is_x86 ( ) :
if guest . os . is_q35 ( ) :
ret . append ( " e1000e " )
else :
ret . append ( " rtl8139 " )
ret . append ( " e1000 " )
if guest . type in [ " xen " , " test " ] :
ret . append ( " netfront " )
ret . sort ( )
return ret
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 ( )
2018-03-20 19:18:35 +03:00
if net_type == DeviceInterface . TYPE_BRIDGE :
2013-03-18 01:06:52 +04:00
desc = _ ( " Shared physical device " )
2018-03-20 19:18:35 +03:00
elif net_type == DeviceInterface . TYPE_VIRTUAL :
2013-03-18 01:06:52 +04:00
desc = _ ( " Virtual networking " )
2018-03-20 19:18:35 +03:00
elif net_type == DeviceInterface . TYPE_USER :
2013-03-18 01:06:52 +04:00
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 .
"""
2015-09-06 17:36:17 +03:00
if conn . fake_conn_predictable ( ) :
2013-07-12 17:54:01 +04:00
# Testing hack
return " 00:11:22:33:44:55 "
for ignore in range ( 256 ) :
mac = _random_mac ( conn )
2018-09-03 23:54:23 +03:00
try :
DeviceInterface . is_conflict_net ( conn , mac )
2013-07-12 17:54:01 +04:00
return mac
2018-09-03 23:54:23 +03:00
except RuntimeError :
continue
2013-07-12 17:54:01 +04:00
logging . debug ( " Failed to generate non-conflicting MAC " )
return None
@staticmethod
def is_conflict_net ( conn , searchmac ) :
"""
2018-09-03 23:54:23 +03:00
Raise RuntimeError if the passed mac conflicts with a defined VM
2013-07-12 17:54:01 +04:00
"""
2018-08-31 22:20:50 +03:00
vms = conn . fetch_all_domains ( )
2013-07-12 17:54:01 +04:00
for vm in vms :
2018-03-21 00:23:34 +03:00
for nic in vm . devices . interface :
2013-07-12 17:54:01 +04:00
nicmac = nic . macaddr or " "
if nicmac . lower ( ) == searchmac . lower ( ) :
2018-09-03 23:54:23 +03:00
raise RuntimeError (
_ ( " The MAC address ' %s ' is in use "
" by another virtual machine. " ) % searchmac )
2013-07-12 17:54:01 +04:00
2013-03-18 01:06:52 +04:00
2013-09-24 18:00:01 +04:00
###############
# XML helpers #
###############
def _get_source ( self ) :
2013-03-18 01:06:52 +04:00
"""
2015-06-02 15:41:21 +03:00
Convenience function , try to return the relevant < source > value
2013-03-18 01:06:52 +04:00
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
2016-07-08 18:58:28 +03:00
if self . type == self . TYPE_DIRECT :
2013-09-24 18:00:01 +04:00
return self . _source_dev
2016-07-08 18:58:28 +03:00
if self . type == self . TYPE_USER or self . type == self . TYPE_ETHERNET :
2013-03-18 01:06:52 +04:00
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
"""
2015-06-02 15:41:21 +03:00
Convenience function , try to set the relevant < source > value
2013-03-18 01:06:52 +04:00
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
2016-07-08 18:58:28 +03:00
elif 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 = [
2016-08-27 08:41:38 +03:00
" _bridge " , " _network " , " _source_dev " , " source_type " , " source_path " ,
" source_mode " , " portgroup " , " macaddr " , " target_dev " , " model " ,
2018-06-06 17:07:46 +03:00
" virtualport " , " filterref " , " rom_bar " , " rom_file " , " mtu_size " ]
2013-07-15 21:56:49 +04:00
2018-09-02 03:22:47 +03:00
_bridge = XMLProperty ( " ./source/@bridge " )
2013-09-24 18:00:01 +04:00
_network = XMLProperty ( " ./source/@network " )
_source_dev = XMLProperty ( " ./source/@dev " )
2018-03-20 19:18:35 +03:00
virtualport = XMLChildProperty ( _VirtualPort , is_single = True )
2018-09-02 03:22:47 +03:00
type = XMLProperty ( " ./@type " )
2017-03-05 22:43:31 +03:00
trustGuestRxFilters = XMLProperty ( " ./@trustGuestRxFilters " , is_yesno = True )
2013-07-15 21:56:49 +04:00
2018-09-03 23:44:18 +03:00
macaddr = XMLProperty ( " ./mac/@address " )
2013-03-18 01:06:52 +04:00
2016-08-27 08:41:38 +03:00
source_type = XMLProperty ( " ./source/@type " )
source_path = XMLProperty ( " ./source/@path " )
2018-09-02 03:22:47 +03:00
source_mode = XMLProperty ( " ./source/@mode " )
2014-05-31 22:30:07 +04:00
portgroup = XMLProperty ( " ./source/@portgroup " )
2013-09-19 21:27:30 +04:00
model = XMLProperty ( " ./model/@type " )
target_dev = XMLProperty ( " ./target/@dev " )
filterref = XMLProperty ( " ./filterref/@filter " )
2015-11-18 21:59:15 +03:00
link_state = XMLProperty ( " ./link/@state " )
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
2016-01-20 18:53:23 +03:00
rom_bar = XMLProperty ( " ./rom/@bar " , is_onoff = True )
rom_file = XMLProperty ( " ./rom/@file " )
2018-06-06 17:07:46 +03:00
mtu_size = XMLProperty ( " ./mtu/@size " , is_int = True )
2016-01-20 18:53:23 +03:00
2013-09-24 18:00:01 +04:00
#############
# Build API #
#############
2018-09-03 23:44:18 +03:00
def validate ( self ) :
2013-09-24 18:00:01 +04:00
if not self . macaddr :
return
2018-09-03 23:44:18 +03:00
util . validate_macaddr ( self . macaddr )
2018-09-03 23:54:23 +03:00
self . is_conflict_net ( self . conn , self . macaddr )
2013-09-24 18:00:01 +04:00
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 :
2016-08-24 23:14:33 +03:00
self . type , self . source = _default_network ( self . conn )
2018-09-02 03:22:47 +03:00
##################
# Default config #
##################
@staticmethod
2018-09-02 03:36:53 +03:00
def default_model ( guest ) :
2018-09-02 03:22:47 +03:00
if not guest . os . is_hvm ( ) :
return None
if guest . supports_virtionet ( ) :
return " virtio "
if guest . os . is_q35 ( ) :
return " e1000e "
2018-09-29 21:31:55 +03:00
if not guest . os . is_x86 ( ) :
return None
2018-09-02 03:22:47 +03:00
prefs = [ " e1000 " , " rtl8139 " , " ne2k_pci " , " pcnet " ]
supported_models = guest . osinfo . supported_netmodels ( )
for pref in prefs :
if pref in supported_models :
return pref
2018-09-29 21:31:55 +03:00
return " e1000 "
2018-09-02 03:22:47 +03:00
def set_defaults ( self , guest ) :
if not self . type :
self . type = self . TYPE_BRIDGE
if not self . macaddr :
self . macaddr = self . generate_mac ( self . conn )
if self . type == self . TYPE_BRIDGE and not self . _bridge :
self . _bridge = _default_bridge ( self . conn )
if self . type == self . TYPE_DIRECT and not self . source_mode :
self . source_mode = " vepa "
if not self . model :
2018-09-02 03:36:53 +03:00
self . model = self . default_model ( guest )