mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
[XEND] Fully implement XenAPI network and PIF classes.
Now support creation of Networks and PIFs. Auto discover current network settings. signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
This commit is contained in:
1 parent
1176bb2c6c
commit
ebfb34834f
3 files changed
+459
-249
No files matched your search
@@ -24,15 +24,122 @@ import socket
|
||||
import XendDomain
|
||||
import XendNode
|
||||
from XendLogging import log
|
||||
from xen.xend import uuid as genuuid
|
||||
from xen.xend.XendBase import XendBase
|
||||
from xen.xend.XendError import *
|
||||
from xen.util import Brctl
|
||||
from xen.xend import XendAPIStore
|
||||
|
||||
IP_ROUTE_RE = r'^default via ([\d\.]+) dev (\w+)'
|
||||
|
||||
class XendNetwork:
|
||||
def __init__(self, uuid, record):
|
||||
self.uuid = uuid
|
||||
self.name_label = record.get('name_label', '')
|
||||
self.name_description = record.get('name_description', '')
|
||||
self.other_config = record.get('other_config', {})
|
||||
def bridge_exists(name):
|
||||
return name in Brctl.get_state().keys()
|
||||
|
||||
class XendNetwork(XendBase):
|
||||
"""We're going to assert that the name_label of this
|
||||
network is just the name of the bridge"""
|
||||
|
||||
def getClass(self):
|
||||
return "network"
|
||||
|
||||
def getAttrRW(self):
|
||||
attrRW = ['name_label',
|
||||
'name_description',
|
||||
'other_config',
|
||||
'default_gateway',
|
||||
'default_netmask']
|
||||
return XendBase.getAttrRW() + attrRW
|
||||
|
||||
def getAttrRO(self):
|
||||
attrRO = ['VIFs',
|
||||
'PIFs']
|
||||
return XendBase.getAttrRO() + attrRO
|
||||
|
||||
def getAttrInst(self):
|
||||
return XendBase.getAttrInst() + self.getAttrRW()
|
||||
|
||||
def getMethods(self):
|
||||
methods = ['add_to_other_config',
|
||||
'remove_from_other_config']
|
||||
return XendBase.getMethods() + methods
|
||||
|
||||
def getFuncs(self):
|
||||
funcs = ['create']
|
||||
return XendBase.getFuncs() + funcs
|
||||
|
||||
getClass = classmethod(getClass)
|
||||
getAttrRO = classmethod(getAttrRO)
|
||||
getAttrRW = classmethod(getAttrRW)
|
||||
getAttrInst = classmethod(getAttrInst)
|
||||
getMethods = classmethod(getMethods)
|
||||
getFuncs = classmethod(getFuncs)
|
||||
|
||||
def create_phy(self, name):
|
||||
"""
|
||||
Called when a new bridge is found on xend start
|
||||
"""
|
||||
# Create new uuids
|
||||
uuid = genuuid.createString()
|
||||
|
||||
# Create instance
|
||||
record = {
|
||||
'name_label': name,
|
||||
'name_description': '',
|
||||
'other_config': {},
|
||||
'default_gateway': '',
|
||||
'default_netmask': ''
|
||||
}
|
||||
network = XendNetwork(record, uuid)
|
||||
|
||||
return uuid
|
||||
|
||||
def recreate(self, record, uuid):
|
||||
"""
|
||||
Called on xend start / restart, or machine
|
||||
restart, when read from saved config.
|
||||
Needs to check network exists, create it otherwise
|
||||
"""
|
||||
|
||||
# Create instance (do this first, to check record)
|
||||
network = XendNetwork(record, uuid)
|
||||
|
||||
# Create network if it doesn't already exist
|
||||
if not bridge_exists(network.name_label):
|
||||
Brctl.bridge_create(network.name_label)
|
||||
|
||||
return uuid
|
||||
|
||||
def create(self, record):
|
||||
"""
|
||||
Called from API, to create a new network
|
||||
"""
|
||||
# Create new uuids
|
||||
uuid = genuuid.createString()
|
||||
|
||||
# Create instance (do this first, to check record)
|
||||
network = XendNetwork(record, uuid)
|
||||
|
||||
# Check network doesn't already exist
|
||||
name_label = network.name_label
|
||||
if bridge_exists(name_label):
|
||||
del network
|
||||
raise UniqueNameError(name_label, "network")
|
||||
|
||||
# Create the bridge
|
||||
Brctl.bridge_create(network.name_label)
|
||||
|
||||
return uuid
|
||||
|
||||
create_phy = classmethod(create_phy)
|
||||
recreate = classmethod(recreate)
|
||||
create = classmethod(create)
|
||||
|
||||
def __init__(self, record, uuid):
|
||||
XendBase.__init__(self, uuid, record)
|
||||
|
||||
#
|
||||
# XenAPI Mehtods
|
||||
#
|
||||
|
||||
def get_name_label(self):
|
||||
return self.name_label
|
||||
@@ -41,9 +148,8 @@ class XendNetwork:
|
||||
return self.name_description
|
||||
|
||||
def set_name_label(self, new_name):
|
||||
self.name_label = new_name
|
||||
XendNode.instance().save_networks()
|
||||
|
||||
pass
|
||||
|
||||
def set_name_description(self, new_desc):
|
||||
self.name_description = new_desc
|
||||
XendNode.instance().save_networks()
|
||||
@@ -55,13 +161,14 @@ class XendNetwork:
|
||||
vifs = vm.get_vifs()
|
||||
for vif in vifs:
|
||||
vif_cfg = vm.get_dev_xenapi_config('vif', vif)
|
||||
if vif_cfg.get('network') == self.uuid:
|
||||
if vif_cfg.get('network') == self.get_uuid():
|
||||
result.append(vif)
|
||||
return result
|
||||
|
||||
def get_PIFs(self):
|
||||
return [x.uuid for x in XendNode.instance().pifs.values()
|
||||
if x.network == self]
|
||||
pifs = XendAPIStore.get_all("PIF")
|
||||
return [pif.get_uuid() for pif in pifs
|
||||
if pif.get_network() == self.get_uuid()]
|
||||
|
||||
def get_other_config(self):
|
||||
return self.other_config
|
||||
@@ -79,17 +186,16 @@ class XendNetwork:
|
||||
del self.other_config[key]
|
||||
XendNode.instance().save_networks()
|
||||
|
||||
def get_record(self):
|
||||
return self.get_record_internal(True)
|
||||
def get_default_gateway(self):
|
||||
return self.default_gateway
|
||||
|
||||
def get_record_internal(self, transient):
|
||||
result = {
|
||||
'uuid': self.uuid,
|
||||
'name_label': self.name_label,
|
||||
'name_description': self.name_description,
|
||||
'other_config' : self.other_config,
|
||||
}
|
||||
if transient:
|
||||
result['VIFs'] = self.get_VIFs()
|
||||
result['PIFs'] = self.get_PIFs()
|
||||
return result
|
||||
def set_default_gateway(self, gateway):
|
||||
self.default_gateway = gateway
|
||||
XendNode.instance().save_networks()
|
||||
|
||||
def get_default_netmask(self):
|
||||
return self.default_netmask
|
||||
|
||||
def set_default_netmask(self, netmask):
|
||||
self.default_netmask = netmask
|
||||
XendNode.instance().save_networks()
|
||||
+101
-133
@@ -21,9 +21,10 @@ import socket
|
||||
import xen.lowlevel.xc
|
||||
|
||||
from xen.util import Brctl
|
||||
from xen.xend import XendAPIStore
|
||||
|
||||
import uuid, arch
|
||||
import XendPBD
|
||||
from XendPBD import XendPBD
|
||||
from XendError import *
|
||||
from XendOptions import instance as xendoptions
|
||||
from XendQCoWStorageRepo import XendQCoWStorageRepo
|
||||
@@ -34,7 +35,7 @@ from XendPIFMetrics import XendPIFMetrics
|
||||
from XendNetwork import *
|
||||
from XendStateStore import XendStateStore
|
||||
from XendMonitor import XendMonitor
|
||||
|
||||
|
||||
class XendNode:
|
||||
"""XendNode - Represents a Domain 0 Host."""
|
||||
|
||||
@@ -133,70 +134,72 @@ class XendNode:
|
||||
'features' : cpu_features,
|
||||
})
|
||||
|
||||
self.pifs = {}
|
||||
self.pif_metrics = {}
|
||||
self.networks = {}
|
||||
self.srs = {}
|
||||
|
||||
# initialise networks
|
||||
|
||||
# Initialise networks
|
||||
# First configure ones off disk
|
||||
saved_networks = self.state_store.load_state('network')
|
||||
if saved_networks:
|
||||
for net_uuid, network in saved_networks.items():
|
||||
self.network_create(network, False, net_uuid)
|
||||
else:
|
||||
bridges = Brctl.get_state().keys()
|
||||
for bridge in bridges:
|
||||
self.network_create({'name_label' : bridge }, False)
|
||||
XendNetwork.recreate(network, net_uuid)
|
||||
|
||||
# Get a mapping from interface to bridge
|
||||
# Next discover any existing bridges and check
|
||||
# they are not already configured
|
||||
bridges = Brctl.get_state().keys()
|
||||
configured_bridges = [XendAPIStore.get(
|
||||
network_uuid, "network")
|
||||
.get_name_label()
|
||||
for network_uuid in XendNetwork.get_all()]
|
||||
unconfigured_bridges = [bridge
|
||||
for bridge in bridges
|
||||
if bridge not in configured_bridges]
|
||||
for unconfigured_bridge in unconfigured_bridges:
|
||||
XendNetwork.create_phy(unconfigured_bridge)
|
||||
|
||||
if_to_br = dict([(i,b)
|
||||
for (b,ifs) in Brctl.get_state().items()
|
||||
for i in ifs])
|
||||
|
||||
# initialise PIFs
|
||||
# Initialise PIFs
|
||||
# First configure ones off disk
|
||||
saved_pifs = self.state_store.load_state('pif')
|
||||
if saved_pifs:
|
||||
for pif_uuid, pif in saved_pifs.items():
|
||||
if pif.get('network') in self.networks:
|
||||
network = self.networks[pif['network']]
|
||||
try:
|
||||
if 'device' not in pif and 'name' in pif:
|
||||
# Compatibility hack, can go pretty soon.
|
||||
pif['device'] = pif['name']
|
||||
if 'metrics' not in pif:
|
||||
# Compatibility hack, can go pretty soon.
|
||||
pif['metrics'] = uuid.createString()
|
||||
XendPIF.recreate(pif, pif_uuid)
|
||||
|
||||
# Next discover any existing PIFs and check
|
||||
# they are not already configured
|
||||
configured_pifs = [XendAPIStore.get(
|
||||
pif_uuid, "PIF")
|
||||
.get_interface_name()
|
||||
for pif_uuid in XendPIF.get_all()]
|
||||
unconfigured_pifs = [(name, mtu, mac)
|
||||
for name, mtu, mac in linux_get_phy_ifaces()
|
||||
if name not in configured_pifs]
|
||||
|
||||
try:
|
||||
pif['VLAN'] = int(pif.get('VLAN', -1))
|
||||
except (ValueError, TypeError):
|
||||
pif['VLAN'] = -1
|
||||
|
||||
self._PIF_create(pif['device'], pif['MTU'],
|
||||
pif['VLAN'],
|
||||
pif['MAC'], network, False, pif_uuid,
|
||||
pif['metrics'])
|
||||
except NetworkAlreadyConnected, exn:
|
||||
log.error('Cannot load saved PIF %s, as network %s ' +
|
||||
'is already connected to PIF %s',
|
||||
pif_uuid, pif['network'], exn.pif_uuid)
|
||||
else:
|
||||
for name, mtu, mac in linux_get_phy_ifaces():
|
||||
bridge_name = if_to_br.get(name, None)
|
||||
if bridge_name is not None:
|
||||
networks = [network for
|
||||
network in self.networks.values()
|
||||
if network.get_name_label() == bridge_name]
|
||||
if len(networks) > 0:
|
||||
network = networks[0]
|
||||
self._PIF_create(name, mtu, -1, mac, network, False)
|
||||
# Get a mapping from interface to bridge
|
||||
if_to_br = dict([(i,b)
|
||||
for (b,ifs) in Brctl.get_state().items()
|
||||
for i in ifs])
|
||||
|
||||
for name, mtu, mac in unconfigured_pifs:
|
||||
# Check PIF is on bridge
|
||||
# if not, ignore
|
||||
bridge_name = if_to_br.get(name, None)
|
||||
if bridge_name is not None:
|
||||
# Translate bridge name to network uuid
|
||||
for network_uuid in XendNetwork.get_all():
|
||||
network = XendAPIStore.get(
|
||||
network_uuid, 'network')
|
||||
if network.get_name_label() == bridge_name:
|
||||
XendPIF.create_phy(network_uuid, name,
|
||||
mtu, mac)
|
||||
break
|
||||
else:
|
||||
log.debug("Cannot find network for bridge %s "
|
||||
"when configuring PIF %s",
|
||||
(bridge_name, name))
|
||||
|
||||
# initialise storage
|
||||
saved_srs = self.state_store.load_state('sr')
|
||||
if saved_srs:
|
||||
for sr_uuid, sr_cfg in saved_srs.items():
|
||||
log.error("SAved SRS %s %s", sr_uuid, sr_cfg['type'])
|
||||
if sr_cfg['type'] == 'qcow_file':
|
||||
self.srs[sr_uuid] = XendQCoWStorageRepo(sr_uuid)
|
||||
elif sr_cfg['type'] == 'local':
|
||||
@@ -214,69 +217,47 @@ class XendNode:
|
||||
saved_pbds = self.state_store.load_state('pbd')
|
||||
if saved_pbds:
|
||||
for pbd_uuid, pbd_cfg in saved_pbds.items():
|
||||
pbd_cfg['uuid'] = pbd_uuid
|
||||
XendPBD.XendPBD(pbd_cfg)
|
||||
XendPBD.recreate(pbd_uuid, pbd_cfg)
|
||||
|
||||
## def network_destroy(self, net_uuid):
|
||||
## del self.networks[net_uuid]
|
||||
## self.save_networks()
|
||||
|
||||
|
||||
def network_create(self, record, persist = True, net_uuid = None):
|
||||
if net_uuid is None:
|
||||
net_uuid = uuid.createString()
|
||||
self.networks[net_uuid] = XendNetwork(net_uuid, record)
|
||||
if persist:
|
||||
self.save_networks()
|
||||
return net_uuid
|
||||
## def get_PIF_refs(self):
|
||||
## return self.pifs[:]
|
||||
|
||||
## def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
|
||||
## pif_uuid = None, metrics_uuid = None):
|
||||
## for pif in self.pifs.values():
|
||||
## if pif.network == network:
|
||||
## raise NetworkAlreadyConnected(pif.uuid)
|
||||
|
||||
def network_destroy(self, net_uuid):
|
||||
del self.networks[net_uuid]
|
||||
self.save_networks()
|
||||
## if pif_uuid is None:
|
||||
## pif_uuid = uuid.createString()
|
||||
## if metrics_uuid is None:
|
||||
## metrics_uuid = uuid.createString()
|
||||
|
||||
## metrics = XendPIFMetrics(metrics_uuid)
|
||||
## pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
|
||||
## metrics.set_PIF(pif)
|
||||
|
||||
def get_PIF_refs(self):
|
||||
return self.pifs.keys()
|
||||
## self.pif_metrics[metrics_uuid] = metrics
|
||||
## self.pifs[pif_uuid] = pif
|
||||
|
||||
## if persist:
|
||||
## self.save_PIFs()
|
||||
## self.refreshBridges()
|
||||
## return pif_uuid
|
||||
|
||||
def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
|
||||
pif_uuid = None, metrics_uuid = None):
|
||||
for pif in self.pifs.values():
|
||||
if pif.network == network:
|
||||
raise NetworkAlreadyConnected(pif.uuid)
|
||||
## def PIF_destroy(self, pif_uuid):
|
||||
## pif = self.pifs[pif_uuid]
|
||||
|
||||
if pif_uuid is None:
|
||||
pif_uuid = uuid.createString()
|
||||
if metrics_uuid is None:
|
||||
metrics_uuid = uuid.createString()
|
||||
## if pif.vlan == -1:
|
||||
## raise PIFIsPhysical()
|
||||
|
||||
metrics = XendPIFMetrics(metrics_uuid)
|
||||
pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
|
||||
metrics.set_PIF(pif)
|
||||
|
||||
self.pif_metrics[metrics_uuid] = metrics
|
||||
self.pifs[pif_uuid] = pif
|
||||
|
||||
if persist:
|
||||
self.save_PIFs()
|
||||
self.refreshBridges()
|
||||
return pif_uuid
|
||||
|
||||
|
||||
def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan):
|
||||
if vlan < 0 or vlan >= 4096:
|
||||
raise VLANTagInvalid()
|
||||
|
||||
pif = self.pifs[pif_uuid]
|
||||
network = self.networks[network_uuid]
|
||||
return self._PIF_create(pif.device, pif.mtu, vlan, pif.mac, network)
|
||||
|
||||
|
||||
def PIF_destroy(self, pif_uuid):
|
||||
pif = self.pifs[pif_uuid]
|
||||
|
||||
if pif.vlan == -1:
|
||||
raise PIFIsPhysical()
|
||||
|
||||
del self.pifs[pif_uuid]
|
||||
self.save_PIFs()
|
||||
## del self.pifs[pif_uuid]
|
||||
## self.save_PIFs()
|
||||
|
||||
|
||||
def save(self):
|
||||
@@ -284,7 +265,7 @@ class XendNode:
|
||||
host_record = {self.uuid: {'name_label':self.name,
|
||||
'name_description':self.desc,
|
||||
'metrics_uuid': self.host_metrics_uuid,
|
||||
'other_config': repr(self.other_config)}}
|
||||
'other_config': self.other_config}}
|
||||
self.state_store.save_state('host',host_record)
|
||||
self.state_store.save_state('cpu', self.cpus)
|
||||
self.save_PIFs()
|
||||
@@ -293,18 +274,21 @@ class XendNode:
|
||||
self.save_SRs()
|
||||
|
||||
def save_PIFs(self):
|
||||
pif_records = dict([(k, v.get_record())
|
||||
for k, v in self.pifs.items()])
|
||||
pif_records = dict([(pif_uuid, XendAPIStore.get(
|
||||
pif_uuid, "PIF").get_record())
|
||||
for pif_uuid in XendPIF.get_all()])
|
||||
self.state_store.save_state('pif', pif_records)
|
||||
|
||||
def save_networks(self):
|
||||
net_records = dict([(k, v.get_record_internal(False))
|
||||
for k, v in self.networks.items()])
|
||||
net_records = dict([(network_uuid, XendAPIStore.get(
|
||||
network_uuid, "network").get_record())
|
||||
for network_uuid in XendNetwork.get_all()])
|
||||
self.state_store.save_state('network', net_records)
|
||||
|
||||
def save_PBDs(self):
|
||||
pbd_records = dict([(v.get_uuid(), v.get_record())
|
||||
for v in XendPBD.get_all()])
|
||||
pbd_records = dict([(pbd_uuid, XendAPIStore.get(
|
||||
pbd_uuid, "PBD").get_record())
|
||||
for pbd_uuid in XendPBD.get_all()])
|
||||
self.state_store.save_state('pbd', pbd_records)
|
||||
|
||||
def save_SRs(self):
|
||||
@@ -331,9 +315,6 @@ class XendNode:
|
||||
def is_valid_cpu(self, cpu_ref):
|
||||
return (cpu_ref in self.cpus)
|
||||
|
||||
def is_valid_network(self, network_ref):
|
||||
return (network_ref in self.networks)
|
||||
|
||||
def is_valid_sr(self, sr_ref):
|
||||
return (sr_ref in self.srs)
|
||||
|
||||
@@ -495,12 +476,6 @@ class XendNode:
|
||||
# Network Functions
|
||||
#
|
||||
|
||||
def get_network_refs(self):
|
||||
return self.networks.keys()
|
||||
|
||||
def get_network(self, network_ref):
|
||||
return self.networks[network_ref]
|
||||
|
||||
def bridge_to_network(self, bridge):
|
||||
"""
|
||||
Determine which network a particular bridge is attached to.
|
||||
@@ -518,13 +493,12 @@ class XendNode:
|
||||
raise Exception(
|
||||
'Could not find default bridge, and none was specified')
|
||||
|
||||
bridges = Brctl.get_state()
|
||||
if bridge not in bridges:
|
||||
raise Exception('Bridge %s is not up' % bridge)
|
||||
for pif in self.pifs.values():
|
||||
if pif.interface_name() in bridges[bridge]:
|
||||
return pif.network
|
||||
raise Exception('Bridge %s is not connected to a network' % bridge)
|
||||
for network_uuid in XendNetwork.get_all():
|
||||
network = XendAPIStore.get(network_uuid, "network")
|
||||
if network.get_name_label() == bridge:
|
||||
return network
|
||||
else:
|
||||
raise Exception('Cannot find network for bridge %s' % bridge)
|
||||
|
||||
#
|
||||
# Debug keys.
|
||||
@@ -642,12 +616,6 @@ class XendNode:
|
||||
def info_dict(self):
|
||||
return dict(self.info())
|
||||
|
||||
|
||||
def refreshBridges(self):
|
||||
for pif in self.pifs.values():
|
||||
pif.refresh(Brctl.get_state())
|
||||
|
||||
|
||||
def parse_proc_cpuinfo():
|
||||
cpuinfo = {}
|
||||
f = file('/proc/cpuinfo', 'r')
|
||||
|
||||
@@ -19,12 +19,15 @@ import commands
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
from xen.xend import uuid as genuuid
|
||||
from xen.xend import XendAPIStore
|
||||
from xen.xend.XendBase import XendBase
|
||||
from xen.xend.XendPIFMetrics import XendPIFMetrics
|
||||
from xen.xend.XendError import *
|
||||
|
||||
log = logging.getLogger("xend.XendPIF")
|
||||
log.setLevel(logging.TRACE)
|
||||
|
||||
|
||||
MAC_RE = re.compile(':'.join(['[0-9a-f]{2}'] * 6))
|
||||
IP_IFACE_RE = re.compile(r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)')
|
||||
|
||||
@@ -87,106 +90,239 @@ def linux_set_mtu(iface, mtu):
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
class XendPIF:
|
||||
def _create_VLAN(dev, vlan):
|
||||
rc, _ = commands.getstatusoutput('vconfig add %s %d' %
|
||||
(dev, vlan))
|
||||
return rc == 0
|
||||
|
||||
class XendPIF(XendBase):
|
||||
"""Representation of a Physical Network Interface."""
|
||||
|
||||
def getClass(self):
|
||||
return "PIF"
|
||||
|
||||
def getAttrRO(self):
|
||||
attrRO = ['network',
|
||||
'host',
|
||||
'metrics',
|
||||
'device']
|
||||
return XendBase.getAttrRO() + attrRO
|
||||
|
||||
def __init__(self, uuid, metrics, device, mtu, vlan, mac, network,
|
||||
host):
|
||||
self.uuid = uuid
|
||||
self.metrics = metrics
|
||||
self.device = device
|
||||
self.mac = mac
|
||||
self.mtu = mtu
|
||||
self.vlan = vlan
|
||||
self.network = network
|
||||
self.host = host
|
||||
def getAttrRW(self):
|
||||
attrRW = ['MAC',
|
||||
'MTU',
|
||||
'VLAN']
|
||||
return XendBase.getAttrRW() + attrRW
|
||||
|
||||
def set_device(self, new_device):
|
||||
self.device = new_device
|
||||
def getAttrInst(self):
|
||||
attrInst = ['network',
|
||||
'device',
|
||||
'MAC',
|
||||
'MTU',
|
||||
'VLAN']
|
||||
return attrInst
|
||||
|
||||
def set_mac(self, new_mac):
|
||||
success = linux_set_mac(new_mac)
|
||||
if success:
|
||||
self.mac = new_mac
|
||||
return success
|
||||
def getMethods(self):
|
||||
methods = ['plug',
|
||||
'unplug']
|
||||
return XendBase.getMethods() + methods
|
||||
|
||||
def set_mtu(self, new_mtu):
|
||||
success = linux_set_mtu(new_mtu)
|
||||
if success:
|
||||
self.mtu = new_mtu
|
||||
return success
|
||||
def getFuncs(self):
|
||||
funcs = ['create_VLAN']
|
||||
return XendBase.getFuncs() + funcs
|
||||
|
||||
def get_record(self):
|
||||
return {'uuid': self.uuid,
|
||||
'device': self.device,
|
||||
'MAC': self.mac,
|
||||
'MTU': self.mtu,
|
||||
'VLAN': self.vlan,
|
||||
'host': self.host.uuid,
|
||||
'network': self.network.uuid,
|
||||
'metrics': self.metrics.uuid}
|
||||
getClass = classmethod(getClass)
|
||||
getAttrRO = classmethod(getAttrRO)
|
||||
getAttrRW = classmethod(getAttrRW)
|
||||
getAttrInst = classmethod(getAttrInst)
|
||||
getMethods = classmethod(getMethods)
|
||||
getFuncs = classmethod(getFuncs)
|
||||
|
||||
def create_phy(self, network_uuid, device,
|
||||
MAC, MTU):
|
||||
"""
|
||||
Called when a new physical PIF is found
|
||||
Could be a VLAN...
|
||||
"""
|
||||
# Create new uuids
|
||||
pif_uuid = genuuid.createString()
|
||||
metrics_uuid = genuuid.createString()
|
||||
|
||||
def refresh(self, bridges):
|
||||
ifname = self.interface_name()
|
||||
rc, _ = _cmd('ip link show %s', ifname)
|
||||
if rc != 0:
|
||||
# Interface does not exist. If it's a physical interface, then
|
||||
# there's nothing we can do -- this should have been set up with
|
||||
# the network script. Otherwise, we can use vconfig to derive
|
||||
# a subinterface.
|
||||
if self.vlan == -1:
|
||||
return
|
||||
|
||||
rc, _ = _cmd('vconfig add %s %d', self.device, self.vlan)
|
||||
if rc != 0:
|
||||
log.error('Could not refresh VLAN for interface %s', ifname)
|
||||
return
|
||||
|
||||
log.info('Created network interface %s', ifname)
|
||||
# Create instances
|
||||
metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
|
||||
|
||||
for brname, nics in bridges.items():
|
||||
if ifname in nics:
|
||||
log.debug('%s is already attached to %s', ifname, brname)
|
||||
return
|
||||
# Is this a VLAN?
|
||||
VLANdot = device.split(".")
|
||||
VLANcolon = device.split(":")
|
||||
|
||||
# The interface is not attached to a bridge. Create one, and attach
|
||||
# the interface to it.
|
||||
brname = _new_bridge_name(bridges)
|
||||
rc, _ = _cmd('brctl addbr %s', brname)
|
||||
if rc != 0:
|
||||
log.error('Could not create bridge %s for interface %s', brname,
|
||||
ifname)
|
||||
return
|
||||
log.info('Created network bridge %s', brname)
|
||||
|
||||
rc, _ = _cmd('brctl addif %s %s', brname, ifname)
|
||||
if rc != 0:
|
||||
log.error('Could not add %s to %s', ifname, brname)
|
||||
return
|
||||
log.info('Added network interface %s to bridge %s', ifname, brname)
|
||||
|
||||
|
||||
def interface_name(self):
|
||||
if self.vlan != -1:
|
||||
return '%s.%d' % (self.device, self.vlan)
|
||||
if len(VLANdot) > 1:
|
||||
VLAN = VLANdot[1]
|
||||
device = VLANdot[0]
|
||||
elif len(VLANcolon) > 1:
|
||||
VLAN = VLANcolon[1]
|
||||
device = VLANcolon[0]
|
||||
else:
|
||||
return self.device
|
||||
VLAN = -1
|
||||
|
||||
record = {
|
||||
'network': network_uuid,
|
||||
'device': device,
|
||||
'MAC': MAC,
|
||||
'MTU': MTU,
|
||||
'VLAN': VLAN
|
||||
}
|
||||
pif = XendPIF(record, pif_uuid, metrics_uuid)
|
||||
|
||||
return pif_uuid
|
||||
|
||||
def _cmd(cmd, *args):
|
||||
if len(args) > 0:
|
||||
cmd = cmd % args
|
||||
rc, output = commands.getstatusoutput(cmd)
|
||||
if rc != 0:
|
||||
log.debug('%s failed with code %d' % (cmd, rc))
|
||||
log.trace('%s: %s' % (cmd, output))
|
||||
return rc, output
|
||||
def recreate(self, record, uuid):
|
||||
"""Called on xend start / restart"""
|
||||
pif_uuid = uuid
|
||||
metrics_uuid = record['metrics']
|
||||
|
||||
# Create instances
|
||||
metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
|
||||
pif = XendPIF(record, pif_uuid, metrics_uuid)
|
||||
|
||||
def _new_bridge_name(bridges):
|
||||
n = 0
|
||||
while True:
|
||||
brname = 'xenbr%d' % n
|
||||
if brname not in bridges:
|
||||
return brname
|
||||
n += 1
|
||||
# If physical PIF, check exists
|
||||
# If VLAN, create if not exist
|
||||
ifs = [dev for dev, _1, _2 in linux_get_phy_ifaces()]
|
||||
if pif.get_VLAN() == -1:
|
||||
if pif.get_device() not in ifs:
|
||||
del pif
|
||||
del metrics
|
||||
return None
|
||||
else:
|
||||
if pif.get_interface_name() not in ifs:
|
||||
_create_VLAN(pif.get_device(), pif.get_VLAN())
|
||||
|
||||
return pif_uuid
|
||||
|
||||
def create_VLAN(self, device, network_uuid, host_ref, vlan):
|
||||
"""Exposed via API - create a new VLAN from existing VIF"""
|
||||
|
||||
ifs = [name for name, _, _ in linux_get_phy_ifaces()]
|
||||
|
||||
vlan = int(vlan)
|
||||
|
||||
# Check VLAN tag is valid
|
||||
if vlan < 0 or vlan >= 4096:
|
||||
raise VLANTagInvalid(vlan)
|
||||
|
||||
# Check device exists
|
||||
if device not in ifs:
|
||||
raise InvalidDeviceError(device)
|
||||
|
||||
# Check VLAN doesn't already exist
|
||||
if "%s.%d" % (device, vlan) in ifs:
|
||||
raise DeviceExistsError("%s.%d" % (device, vlan))
|
||||
|
||||
# Check network ref is valid
|
||||
from xen.xend import XendNode
|
||||
network_uuids = XendNode.instance().networks
|
||||
if network_uuid in network_uuids:
|
||||
raise InvalidHandleError("Network", network_ref)
|
||||
|
||||
# Check host_ref is this host
|
||||
if host_ref != XendNode.instance().get_uuid():
|
||||
raise InvalidHandleError("Host", host_ref)
|
||||
|
||||
# Create the VLAN
|
||||
_create_VLAN(device, vlan)
|
||||
|
||||
# Create new uuids
|
||||
pif_uuid = genuuid.createString()
|
||||
metrics_uuid = genuuid.createString()
|
||||
|
||||
# Create the record
|
||||
record = {
|
||||
"device": device,
|
||||
"MAC": '',
|
||||
"MTU": '',
|
||||
"network": network_ref,
|
||||
"VLAN": vlan
|
||||
}
|
||||
|
||||
# Create instances
|
||||
metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
|
||||
pif = XendPIF(record, pif_uuid, metrics_uuid)
|
||||
|
||||
# Add it to list of PIFs
|
||||
XendNode.instance().pifs.append(pif_ref)
|
||||
|
||||
# Add it to network
|
||||
network.add_pif(pif_ref)
|
||||
|
||||
return pif_uuid
|
||||
|
||||
create_phy = classmethod(create_phy)
|
||||
recreate = classmethod(recreate)
|
||||
create_VLAN = classmethod(create_VLAN)
|
||||
|
||||
def __init__(self, record, uuid, metrics_uuid):
|
||||
XendBase.__init__(self, uuid, record)
|
||||
self.metrics = metrics_uuid
|
||||
|
||||
def plug(self):
|
||||
"""Plug the PIF into the network"""
|
||||
network = XendAPIStore.get(self.network,
|
||||
"network")
|
||||
bridge_name = network.get_name_label()
|
||||
|
||||
Brctl.vif_bridge_add({
|
||||
"bridge": bridge_name,
|
||||
"vif": self.get_interface_name()
|
||||
})
|
||||
|
||||
def unplug(self):
|
||||
"""Unplug the PIF from the network"""
|
||||
pass
|
||||
|
||||
def get_interface_name(self):
|
||||
if self.get_VLAN() == -1:
|
||||
return self.get_device()
|
||||
else:
|
||||
return "%s.%d" % (self.get_device(), self.get_VLAN())
|
||||
|
||||
def get_device(self):
|
||||
"""
|
||||
This is the base interface.
|
||||
For phy if (VLAN == -1) this is same as
|
||||
if name.
|
||||
For VLANs, this it the bit before the period
|
||||
"""
|
||||
return self.device
|
||||
|
||||
def get_network(self):
|
||||
return self.network
|
||||
|
||||
def get_host(self):
|
||||
from xen.xend import XendNode
|
||||
return XendNode.instance().get_uuid()
|
||||
|
||||
def get_metrics(self):
|
||||
return self.metrics
|
||||
|
||||
def get_MAC(self):
|
||||
return self.MAC
|
||||
|
||||
def set_MAC(self, new_mac):
|
||||
success = linux_set_mac(self.device, new_mac)
|
||||
if success:
|
||||
self.MAC = new_mac
|
||||
return success
|
||||
|
||||
def get_MTU(self):
|
||||
return self.MTU
|
||||
|
||||
def set_MTU(self, new_mtu):
|
||||
success = linux_set_mtu(self.device, new_mtu)
|
||||
if success:
|
||||
self.MTU = new_mtu
|
||||
return success
|
||||
|
||||
def get_VLAN(self):
|
||||
return self.VLAN
|
||||
|
||||
def set_VLAN(self, VLAN):
|
||||
pass
|
||||