ia64/xen-unstable
changeset 13201:a8e853aecb3e
Added network.{create,destroy}, and PIF.{create,create_VLAN,destroy}, and
a first blush at support for VLANs through Xen-API.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
a first blush at support for VLANs through Xen-API.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
author | Ewan Mellor <ewan@xensource.com> |
---|---|
date | Wed Dec 27 15:42:56 2006 +0000 (2006-12-27) |
parents | 069d1364af53 |
children | 966926d9c5cf |
files | tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/XendPIF.py tools/python/xen/xend/server/SrvServer.py |
line diff
1.1 --- a/tools/python/xen/xend/XendAPI.py Wed Dec 27 15:39:32 2006 +0000 1.2 +++ b/tools/python/xen/xend/XendAPI.py Wed Dec 27 15:42:56 2006 +0000 1.3 @@ -469,13 +469,23 @@ class XendAPI: 1.4 'default_gateway', 1.5 'default_netmask'] 1.6 1.7 + def network_create(self, _, name_label, name_description, 1.8 + default_gateway, default_netmask): 1.9 + return xen_api_success( 1.10 + XendNode.instance().network_create(name_label, name_description, 1.11 + default_gateway, 1.12 + default_netmask)) 1.13 + 1.14 + def network_destroy(self, _, ref): 1.15 + return xen_api_success(XendNode.instance().network_destroy(ref)) 1.16 + 1.17 def _get_network(self, ref): 1.18 return XendNode.instance().get_network(ref) 1.19 1.20 - def network_get_all(self, session): 1.21 + def network_get_all(self, _): 1.22 return xen_api_success(XendNode.instance().get_network_refs()) 1.23 1.24 - def network_get_record(self, session, ref): 1.25 + def network_get_record(self, _, ref): 1.26 return xen_api_success( 1.27 XendNode.instance().get_network(ref).get_record()) 1.28 1.29 @@ -524,9 +534,26 @@ class XendAPI: 1.30 1.31 PIF_attr_inst = PIF_attr_rw 1.32 1.33 + PIF_methods = ['create_VLAN'] 1.34 + 1.35 def _get_PIF(self, ref): 1.36 return XendNode.instance().pifs[ref] 1.37 1.38 + def PIF_create(self, _, name, network_uuid, host_uuid, mac, mtu, vlan): 1.39 + node = XendNode.instance() 1.40 + if host_uuid != node.uuid: 1.41 + return xen_api_error([HOST_HANDLE_INVALID, host_uuid]) 1.42 + 1.43 + elif _is_valid_ref(network_uuid, node.is_valid_network): 1.44 + network = node.get_network(network_uuid) 1.45 + return xen_api_success(node.PIF_create(name, mtu, vlan, mac, 1.46 + network)) 1.47 + else: 1.48 + return xen_api_error([NETWORK_HANDLE_INVALID, network_uuid]) 1.49 + 1.50 + def PIF_destroy(self, _, ref): 1.51 + return xen_api_success(XendNode.instance().PIF_destroy(ref)) 1.52 + 1.53 # object methods 1.54 def PIF_get_record(self, _, ref): 1.55 return xen_api_success(self._get_PIF(ref).get_record()) 1.56 @@ -534,39 +561,46 @@ class XendAPI: 1.57 def PIF_get_all(self, _): 1.58 return xen_api_success(XendNode.instance().pifs.keys()) 1.59 1.60 - def PIF_get_name(self, session, ref): 1.61 + def PIF_get_name(self, _, ref): 1.62 return xen_api_success(self._get_PIF(ref).name) 1.63 1.64 - def PIF_get_network(self, session, ref): 1.65 + def PIF_get_network(self, _, ref): 1.66 return xen_api_success(self._get_PIF(ref).network.uuid) 1.67 1.68 - def PIF_get_host(self, session, ref): 1.69 + def PIF_get_host(self, _, ref): 1.70 return xen_api_success(self._get_PIF(ref).host.uuid) 1.71 1.72 - def PIF_get_MAC(self, session, ref): 1.73 + def PIF_get_MAC(self, _, ref): 1.74 return xen_api_success(self._get_PIF(ref).mac) 1.75 1.76 - def PIF_get_MTU(self, session, ref): 1.77 + def PIF_get_MTU(self, _, ref): 1.78 return xen_api_success(self._get_PIF(ref).mtu) 1.79 1.80 - def PIF_get_VLAN(self, session, ref): 1.81 + def PIF_get_VLAN(self, _, ref): 1.82 return xen_api_success(self._get_PIF(ref).vlan) 1.83 1.84 - def PIF_get_io_read_kbs(self, session, ref): 1.85 + def PIF_get_io_read_kbs(self, _, ref): 1.86 return xen_api_success(self._get_PIF(ref).get_io_read_kbs()) 1.87 1.88 - def PIF_get_io_write_kbs(self, session, ref): 1.89 + def PIF_get_io_write_kbs(self, _, ref): 1.90 return xen_api_success(self._get_PIF(ref).get_io_write_kbs()) 1.91 1.92 def PIF_set_name(self, _, ref, name): 1.93 return xen_api_success(self._get_PIF(ref).set_name(name)) 1.94 1.95 - def PIF_set_MAC(self, session, ref, mac): 1.96 + def PIF_set_MAC(self, _, ref, mac): 1.97 return xen_api_success(self._get_PIF(ref).set_mac(name)) 1.98 1.99 - def PIF_set_MTU(self, session, ref, mtu): 1.100 + def PIF_set_MTU(self, _, ref, mtu): 1.101 return xen_api_success(self._get_PIF(ref).set_mtu(name)) 1.102 1.103 + def PIF_create_VLAN(self, _, ref, network, vlan): 1.104 + if _is_valid_ref(network, XendNode.instance().is_valid_network): 1.105 + return xen_api_success(XendNode.instance().PIF_create_VLAN( 1.106 + ref, network, vlan)) 1.107 + else: 1.108 + return xen_api_error([NETWORK_HANDLE_INVALID, network_uuid]) 1.109 + 1.110 1.111 # Xen API: Class VM 1.112 # ----------------------------------------------------------------
2.1 --- a/tools/python/xen/xend/XendNode.py Wed Dec 27 15:39:32 2006 +0000 2.2 +++ b/tools/python/xen/xend/XendNode.py Wed Dec 27 15:42:56 2006 +0000 2.3 @@ -19,6 +19,9 @@ 2.4 import os 2.5 import socket 2.6 import xen.lowlevel.xc 2.7 + 2.8 +from xen.util import Brctl 2.9 + 2.10 from xen.xend import uuid 2.11 from xen.xend.XendError import XendError 2.12 from xen.xend.XendRoot import instance as xendroot 2.13 @@ -87,16 +90,14 @@ class XendNode: 2.14 saved_networks = self.state_store.load_state('network') 2.15 if saved_networks: 2.16 for net_uuid, network in saved_networks.items(): 2.17 - self.networks[net_uuid] = XendNetwork(net_uuid, 2.18 - network.get('name_label'), 2.19 - network.get('name_description', ''), 2.20 - network.get('default_gateway', ''), 2.21 - network.get('default_netmask', '')) 2.22 + self.network_create(network.get('name_label'), 2.23 + network.get('name_description', ''), 2.24 + network.get('default_gateway', ''), 2.25 + network.get('default_netmask', ''), 2.26 + False, net_uuid) 2.27 else: 2.28 gateway, netmask = linux_get_default_network() 2.29 - net_uuid = uuid.createString() 2.30 - net = XendNetwork(net_uuid, 'net0', '', gateway, netmask) 2.31 - self.networks[net_uuid] = net 2.32 + self.network_create('net0', '', gateway, netmask, False) 2.33 2.34 # initialise PIFs 2.35 saved_pifs = self.state_store.load_state('pif') 2.36 @@ -104,19 +105,12 @@ class XendNode: 2.37 for pif_uuid, pif in saved_pifs.items(): 2.38 if pif['network'] in self.networks: 2.39 network = self.networks[pif['network']] 2.40 - self.pifs[pif_uuid] = XendPIF(pif_uuid, 2.41 - pif['name'], 2.42 - pif['MTU'], 2.43 - pif['VLAN'], 2.44 - pif['MAC'], 2.45 - network, 2.46 - self) 2.47 + self.PIF_create(pif['name'], pif['MTU'], pif['VLAN'], 2.48 + pif['MAC'], network, False, pif_uuid) 2.49 else: 2.50 for name, mtu, mac in linux_get_phy_ifaces(): 2.51 network = self.networks.values()[0] 2.52 - pif_uuid = uuid.createString() 2.53 - pif = XendPIF(pif_uuid, name, mtu, '', mac, network, self) 2.54 - self.pifs[pif_uuid] = pif 2.55 + self.PIF_create(name, mtu, '', mac, network, False) 2.56 2.57 # initialise storage 2.58 saved_sr = self.state_store.load_state('sr') 2.59 @@ -127,21 +121,66 @@ class XendNode: 2.60 sr_uuid = uuid.createString() 2.61 self.sr = XendStorageRepository(sr_uuid) 2.62 2.63 + 2.64 + def network_create(self, name_label, name_description, 2.65 + default_gateway, default_netmask, persist = True, 2.66 + net_uuid = None): 2.67 + if net_uuid is None: 2.68 + net_uuid = uuid.createString() 2.69 + self.networks[net_uuid] = XendNetwork(net_uuid, name_label, 2.70 + name_description, 2.71 + default_gateway, 2.72 + default_netmask) 2.73 + if persist: 2.74 + self.save_networks() 2.75 + return net_uuid 2.76 + 2.77 + 2.78 + def network_destroy(self, net_uuid): 2.79 + del self.networks[net_uuid] 2.80 + self.save_networks() 2.81 + 2.82 + 2.83 + def PIF_create(self, name, mtu, vlan, mac, network, persist = True, 2.84 + pif_uuid = None): 2.85 + if pif_uuid is None: 2.86 + pif_uuid = uuid.createString() 2.87 + self.pifs[pif_uuid] = XendPIF(pif_uuid, name, mtu, vlan, mac, network, 2.88 + self) 2.89 + if persist: 2.90 + self.save_PIFs() 2.91 + self.refreshBridges() 2.92 + return pif_uuid 2.93 + 2.94 + 2.95 + def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan): 2.96 + pif = self.pifs[pif_uuid] 2.97 + network = self.networks[network_uuid] 2.98 + return self.PIF_create(pif.name, pif.mtu, vlan, pif.mac, network) 2.99 + 2.100 + 2.101 + def PIF_destroy(self, pif_uuid): 2.102 + del self.pifs[pif_uuid] 2.103 + self.save_PIFs() 2.104 + 2.105 + 2.106 def save(self): 2.107 # save state 2.108 host_record = {self.uuid: {'name_label':self.name, 2.109 'name_description':self.desc}} 2.110 self.state_store.save_state('host',host_record) 2.111 self.state_store.save_state('cpu', self.cpus) 2.112 - pif_records = dict([(k, v.get_record(transient = False)) 2.113 - for k, v in self.pifs.items()]) 2.114 - self.state_store.save_state('pif', pif_records) 2.115 - 2.116 + self.save_PIFs() 2.117 self.save_networks() 2.118 2.119 sr_record = {self.sr.uuid: self.sr.get_record()} 2.120 self.state_store.save_state('sr', sr_record) 2.121 2.122 + def save_PIFs(self): 2.123 + pif_records = dict([(k, v.get_record(transient = False)) 2.124 + for k, v in self.pifs.items()]) 2.125 + self.state_store.save_state('pif', pif_records) 2.126 + 2.127 def save_networks(self): 2.128 net_records = dict([(k, v.get_record(transient = False)) 2.129 for k, v in self.networks.items()]) 2.130 @@ -326,7 +365,12 @@ class XendNode: 2.131 return dict(self.physinfo()) 2.132 def info_dict(self): 2.133 return dict(self.info()) 2.134 - 2.135 + 2.136 + 2.137 + def refreshBridges(self): 2.138 + for pif in self.pifs.values(): 2.139 + pif.refresh(Brctl.get_state()) 2.140 + 2.141 2.142 def instance(): 2.143 global inst
3.1 --- a/tools/python/xen/xend/XendPIF.py Wed Dec 27 15:39:32 2006 +0000 3.2 +++ b/tools/python/xen/xend/XendPIF.py Wed Dec 27 15:42:56 2006 +0000 3.3 @@ -15,16 +15,18 @@ 3.4 # Copyright (c) 2006 Xensource Inc. 3.5 #============================================================================ 3.6 3.7 +import commands 3.8 +import logging 3.9 import os 3.10 -import commands 3.11 import re 3.12 -import socket 3.13 + 3.14 3.15 -from xen.xend.XendRoot import instance as xendroot 3.16 -from xen.xend.XendLogging import log 3.17 +log = logging.getLogger("xend.XendPIF") 3.18 +log.setLevel(logging.TRACE) 3.19 3.20 -MAC_RE = ':'.join(['[0-9a-f]{2}'] * 6) 3.21 -IP_IFACE_RE = r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)' 3.22 + 3.23 +MAC_RE = re.compile(':'.join(['[0-9a-f]{2}'] * 6)) 3.24 +IP_IFACE_RE = re.compile(r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)') 3.25 3.26 def linux_phy_to_virt(pif_name): 3.27 return 'eth' + re.sub(r'^[a-z]+', '', pif_name) 3.28 @@ -40,7 +42,7 @@ def linux_get_phy_ifaces(): 3.29 @rtype: array of 3-element tuple (name, mtu, mac) 3.30 """ 3.31 3.32 - ip_cmd = '/sbin/ip -o link show' 3.33 + ip_cmd = 'ip -o link show' 3.34 rc, output = commands.getstatusoutput(ip_cmd) 3.35 ifaces = {} 3.36 phy_ifaces = [] 3.37 @@ -66,7 +68,7 @@ def linux_set_mac(iface, mac): 3.38 if not re.search(MAC_RE, mac): 3.39 return False 3.40 3.41 - ip_mac_cmd = '/sbin/ip link set %s addr %s' % \ 3.42 + ip_mac_cmd = 'ip link set %s addr %s' % \ 3.43 (linux_phy_to_virt(iface), mac) 3.44 rc, output = commands.getstatusoutput(ip_mac_cmd) 3.45 if rc == 0: 3.46 @@ -76,7 +78,7 @@ def linux_set_mac(iface, mac): 3.47 3.48 def linux_set_mtu(iface, mtu): 3.49 try: 3.50 - ip_mtu_cmd = '/sbin/ip link set %s mtu %d' % \ 3.51 + ip_mtu_cmd = 'ip link set %s mtu %d' % \ 3.52 (linux_phy_to_virt(iface), int(mtu)) 3.53 rc, output = commands.getstatusoutput(ip_mtu_cmd) 3.54 if rc == 0: 3.55 @@ -85,17 +87,6 @@ def linux_set_mtu(iface, mtu): 3.56 except ValueError: 3.57 return False 3.58 3.59 -def same_dir_rename(old_path, new_path): 3.60 - """Ensure that the old_path and new_path refer to files in the same 3.61 - directory.""" 3.62 - old_abs = os.path.normpath(old_path) 3.63 - new_abs = os.path.normpath(new_path) 3.64 - if os.path.dirname(old_abs) == os.path.dirname(new_abs): 3.65 - os.rename(old_abs, new_abs) 3.66 - else: 3.67 - log.warning("Unable to ensure name is new name is safe: %s" % new_abs) 3.68 - 3.69 - 3.70 class XendPIF: 3.71 """Representation of a Physical Network Interface.""" 3.72 3.73 @@ -140,3 +131,68 @@ class XendPIF: 3.74 result['io_read_kbs'] = str(self.get_io_read_kbs()) 3.75 result['io_write_kbs'] = str(self.get_io_write_kbs()) 3.76 return result 3.77 + 3.78 + 3.79 + def refresh(self, bridges): 3.80 + ifname = self._ifname() 3.81 + rc, _ = _cmd('ip link show %s', ifname) 3.82 + if rc != 0: 3.83 + # Interface does not exist. If it's a physical interface, then 3.84 + # there's nothing we can do -- this should have been set up with 3.85 + # the network script. Otherwise, we can use vconfig to derive 3.86 + # a subinterface. 3.87 + if not self.vlan: 3.88 + return 3.89 + 3.90 + rc, _ = _cmd('vconfig add %s %s', self.name, self.vlan) 3.91 + if rc != 0: 3.92 + log.error('Could not refresh %s', ifname) 3.93 + return 3.94 + log.info('Created network interface %s', ifname) 3.95 + 3.96 + for brname, nics in bridges.items(): 3.97 + if ifname in nics: 3.98 + log.debug('%s is already attached to %s', ifname, brname) 3.99 + return 3.100 + 3.101 + # The interface is not attached to a bridge. Create one, and attach 3.102 + # the interface to it. 3.103 + brname = _new_bridge_name(bridges) 3.104 + rc, _ = _cmd('brctl addbr %s', brname) 3.105 + if rc != 0: 3.106 + log.error('Could not create bridge %s for interface %s', brname, 3.107 + ifname) 3.108 + return 3.109 + log.info('Created network bridge %s', brname) 3.110 + 3.111 + rc, _ = _cmd('brctl addif %s %s', brname, ifname) 3.112 + if rc != 0: 3.113 + log.error('Could not add %s to %s', ifname, brname) 3.114 + return 3.115 + log.info('Added network interface %s to bridge %s', ifname, brname) 3.116 + 3.117 + 3.118 + def _ifname(self): 3.119 + if self.vlan: 3.120 + return '%s.%s' % (self.name, self.vlan) 3.121 + else: 3.122 + return self.name 3.123 + 3.124 + 3.125 +def _cmd(cmd, *args): 3.126 + if len(args) > 0: 3.127 + cmd = cmd % args 3.128 + rc, output = commands.getstatusoutput(cmd) 3.129 + if rc != 0: 3.130 + log.debug('%s failed with code %d' % (cmd, rc)) 3.131 + log.trace('%s: %s' % (cmd, output)) 3.132 + return rc, output 3.133 + 3.134 + 3.135 +def _new_bridge_name(bridges): 3.136 + n = 0 3.137 + while True: 3.138 + brname = 'xenbr%d' % n 3.139 + if brname not in bridges: 3.140 + return brname 3.141 + n += 1
4.1 --- a/tools/python/xen/xend/server/SrvServer.py Wed Dec 27 15:39:32 2006 +0000 4.2 +++ b/tools/python/xen/xend/server/SrvServer.py Wed Dec 27 15:42:56 2006 +0000 4.3 @@ -48,7 +48,7 @@ from threading import Thread 4.4 4.5 from xen.web.httpserver import HttpServer, UnixHttpServer 4.6 4.7 -from xen.xend import XendRoot, XendAPI 4.8 +from xen.xend import XendNode, XendRoot, XendAPI 4.9 from xen.xend import Vifctl 4.10 from xen.xend.XendLogging import log 4.11 from xen.xend.XendClient import XEN_API_SOCKET 4.12 @@ -100,6 +100,8 @@ class XendServers: 4.13 signal.signal(signal.SIGHUP, self.reloadConfig) 4.14 4.15 while True: 4.16 + XendNode.instance().refreshBridges() 4.17 + 4.18 threads = [] 4.19 for server in self.servers: 4.20 if server.ready: