[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:
Tom Wilkie committed 2007-04-25 16:17:51 +01:00
1 parent 1176bb2c6c
commit ebfb34834f
3 files changed
+459 -249

No files matched your search

+131 -25
View File
@@ -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
View File
@@ -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')
+227 -91
View File
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.