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>
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: