ia64/xen-unstable

changeset 14940:0bbc44c0b6e3

[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>
author Tom Wilkie <tom.wilkie@gmail.com>
date Wed Apr 25 16:17:51 2007 +0100 (2007-04-25)
parents 31f6f85778e5
children 189efb0b27f9
files tools/python/xen/xend/XendNetwork.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/XendPIF.py
line diff
     1.1 --- a/tools/python/xen/xend/XendNetwork.py	Wed Apr 25 16:16:21 2007 +0100
     1.2 +++ b/tools/python/xen/xend/XendNetwork.py	Wed Apr 25 16:17:51 2007 +0100
     1.3 @@ -24,15 +24,122 @@ import socket
     1.4  import XendDomain
     1.5  import XendNode
     1.6  from XendLogging import log
     1.7 +from xen.xend import uuid as genuuid
     1.8 +from xen.xend.XendBase import XendBase
     1.9 +from xen.xend.XendError import *
    1.10 +from xen.util import Brctl
    1.11 +from xen.xend import XendAPIStore
    1.12  
    1.13  IP_ROUTE_RE = r'^default via ([\d\.]+) dev (\w+)'
    1.14  
    1.15 -class XendNetwork:
    1.16 -    def __init__(self, uuid, record):
    1.17 -        self.uuid = uuid
    1.18 -        self.name_label = record.get('name_label', '')
    1.19 -        self.name_description = record.get('name_description', '')
    1.20 -        self.other_config = record.get('other_config', {})
    1.21 +def bridge_exists(name):
    1.22 +    return name in Brctl.get_state().keys()
    1.23 +
    1.24 +class XendNetwork(XendBase):
    1.25 +    """We're going to assert that the name_label of this
    1.26 +    network is just the name of the bridge"""
    1.27 +
    1.28 +    def getClass(self):
    1.29 +        return "network"
    1.30 +
    1.31 +    def getAttrRW(self):
    1.32 +        attrRW = ['name_label',
    1.33 +                  'name_description',
    1.34 +                  'other_config',
    1.35 +                  'default_gateway',
    1.36 +                  'default_netmask']
    1.37 +        return XendBase.getAttrRW() + attrRW
    1.38 +
    1.39 +    def getAttrRO(self):
    1.40 +        attrRO =  ['VIFs',
    1.41 +                   'PIFs']
    1.42 +        return XendBase.getAttrRO() + attrRO
    1.43 +
    1.44 +    def getAttrInst(self):
    1.45 +        return XendBase.getAttrInst() + self.getAttrRW()
    1.46 +
    1.47 +    def getMethods(self):
    1.48 +        methods = ['add_to_other_config',
    1.49 +                   'remove_from_other_config']
    1.50 +        return XendBase.getMethods() + methods
    1.51 +
    1.52 +    def getFuncs(self):
    1.53 +        funcs = ['create']
    1.54 +        return XendBase.getFuncs() + funcs
    1.55 +
    1.56 +    getClass    = classmethod(getClass)
    1.57 +    getAttrRO   = classmethod(getAttrRO)
    1.58 +    getAttrRW   = classmethod(getAttrRW)
    1.59 +    getAttrInst = classmethod(getAttrInst)
    1.60 +    getMethods  = classmethod(getMethods)
    1.61 +    getFuncs    = classmethod(getFuncs)
    1.62 +
    1.63 +    def create_phy(self, name):
    1.64 +        """
    1.65 +        Called when a new bridge is found on xend start
    1.66 +        """
    1.67 +        # Create new uuids
    1.68 +        uuid = genuuid.createString()
    1.69 +
    1.70 +        # Create instance
    1.71 +        record = {
    1.72 +                'name_label':       name,
    1.73 +                'name_description': '',
    1.74 +                'other_config':     {},
    1.75 +                'default_gateway':  '',
    1.76 +                'default_netmask':  ''
    1.77 +            }
    1.78 +        network = XendNetwork(record, uuid)
    1.79 +
    1.80 +        return uuid
    1.81 +        
    1.82 +    def recreate(self, record, uuid):
    1.83 +        """
    1.84 +        Called on xend start / restart, or machine
    1.85 +        restart, when read from saved config.
    1.86 +        Needs to check network exists, create it otherwise
    1.87 +        """
    1.88 +
    1.89 +        # Create instance (do this first, to check record)
    1.90 +        network = XendNetwork(record, uuid)
    1.91 +
    1.92 +        # Create network if it doesn't already exist
    1.93 +        if not bridge_exists(network.name_label):
    1.94 +            Brctl.bridge_create(network.name_label)
    1.95 +
    1.96 +        return uuid
    1.97 +
    1.98 +    def create(self, record):
    1.99 +        """
   1.100 +        Called from API, to create a new network
   1.101 +        """
   1.102 +        # Create new uuids
   1.103 +        uuid = genuuid.createString()
   1.104 +
   1.105 +        # Create instance (do this first, to check record)
   1.106 +        network = XendNetwork(record, uuid)
   1.107 +
   1.108 +        # Check network doesn't already exist
   1.109 +        name_label = network.name_label
   1.110 +        if bridge_exists(name_label):
   1.111 +            del network
   1.112 +            raise UniqueNameError(name_label, "network")
   1.113 +
   1.114 +        # Create the bridge
   1.115 +        Brctl.bridge_create(network.name_label)
   1.116 +
   1.117 +        return uuid
   1.118 +
   1.119 +    create_phy  = classmethod(create_phy)
   1.120 +    recreate    = classmethod(recreate)
   1.121 +    create      = classmethod(create)
   1.122 +        
   1.123 +    def __init__(self, record, uuid):       
   1.124 +        XendBase.__init__(self, uuid, record)
   1.125 +        
   1.126 +    #
   1.127 +    # XenAPI Mehtods
   1.128 +    #
   1.129  
   1.130      def get_name_label(self):
   1.131          return self.name_label
   1.132 @@ -41,9 +148,8 @@ class XendNetwork:
   1.133          return self.name_description
   1.134  
   1.135      def set_name_label(self, new_name):
   1.136 -        self.name_label = new_name
   1.137 -        XendNode.instance().save_networks()
   1.138 -
   1.139 +        pass
   1.140 +        
   1.141      def set_name_description(self, new_desc):
   1.142          self.name_description = new_desc
   1.143          XendNode.instance().save_networks()
   1.144 @@ -55,13 +161,14 @@ class XendNetwork:
   1.145              vifs = vm.get_vifs()
   1.146              for vif in vifs:
   1.147                  vif_cfg = vm.get_dev_xenapi_config('vif', vif)
   1.148 -                if vif_cfg.get('network') == self.uuid:
   1.149 +                if vif_cfg.get('network') == self.get_uuid():
   1.150                      result.append(vif)
   1.151          return result
   1.152  
   1.153      def get_PIFs(self):
   1.154 -        return [x.uuid for x in XendNode.instance().pifs.values()
   1.155 -                if x.network == self]
   1.156 +        pifs = XendAPIStore.get_all("PIF")
   1.157 +        return [pif.get_uuid() for pif in pifs
   1.158 +                if pif.get_network() == self.get_uuid()]
   1.159  
   1.160      def get_other_config(self):
   1.161          return self.other_config
   1.162 @@ -79,17 +186,16 @@ class XendNetwork:
   1.163              del self.other_config[key]
   1.164          XendNode.instance().save_networks()
   1.165  
   1.166 -    def get_record(self):
   1.167 -        return self.get_record_internal(True)
   1.168 +    def get_default_gateway(self):
   1.169 +        return self.default_gateway
   1.170 +
   1.171 +    def set_default_gateway(self, gateway):
   1.172 +        self.default_gateway = gateway
   1.173 +        XendNode.instance().save_networks()
   1.174  
   1.175 -    def get_record_internal(self, transient):
   1.176 -        result = {
   1.177 -            'uuid': self.uuid,
   1.178 -            'name_label': self.name_label,
   1.179 -            'name_description': self.name_description,
   1.180 -            'other_config' : self.other_config,
   1.181 -        }
   1.182 -        if transient:
   1.183 -            result['VIFs'] = self.get_VIFs()
   1.184 -            result['PIFs'] = self.get_PIFs()
   1.185 -        return result
   1.186 +    def get_default_netmask(self):
   1.187 +        return self.default_netmask
   1.188 +
   1.189 +    def set_default_netmask(self, netmask):
   1.190 +        self.default_netmask = netmask
   1.191 +        XendNode.instance().save_networks()
     2.1 --- a/tools/python/xen/xend/XendNode.py	Wed Apr 25 16:16:21 2007 +0100
     2.2 +++ b/tools/python/xen/xend/XendNode.py	Wed Apr 25 16:17:51 2007 +0100
     2.3 @@ -21,9 +21,10 @@ import socket
     2.4  import xen.lowlevel.xc
     2.5  
     2.6  from xen.util import Brctl
     2.7 +from xen.xend import XendAPIStore
     2.8  
     2.9  import uuid, arch
    2.10 -import XendPBD
    2.11 +from XendPBD import XendPBD
    2.12  from XendError import *
    2.13  from XendOptions import instance as xendoptions
    2.14  from XendQCoWStorageRepo import XendQCoWStorageRepo
    2.15 @@ -34,7 +35,7 @@ from XendPIFMetrics import XendPIFMetric
    2.16  from XendNetwork import *
    2.17  from XendStateStore import XendStateStore
    2.18  from XendMonitor import XendMonitor
    2.19 -
    2.20 +     
    2.21  class XendNode:
    2.22      """XendNode - Represents a Domain 0 Host."""
    2.23      
    2.24 @@ -133,70 +134,72 @@ class XendNode:
    2.25                        'features' : cpu_features,
    2.26                      })
    2.27  
    2.28 -        self.pifs = {}
    2.29 -        self.pif_metrics = {}
    2.30 -        self.networks = {}
    2.31          self.srs = {}
    2.32 -        
    2.33 -        # initialise networks
    2.34 +
    2.35 +        # Initialise networks
    2.36 +        # First configure ones off disk
    2.37          saved_networks = self.state_store.load_state('network')
    2.38          if saved_networks:
    2.39              for net_uuid, network in saved_networks.items():
    2.40 -                self.network_create(network, False, net_uuid)
    2.41 -        else:
    2.42 -            bridges = Brctl.get_state().keys()
    2.43 -            for bridge in bridges:
    2.44 -                self.network_create({'name_label' : bridge }, False)
    2.45 +                XendNetwork.recreate(network, net_uuid)
    2.46                  
    2.47 -        # Get a mapping from interface to bridge
    2.48 +        # Next discover any existing bridges and check
    2.49 +        # they are not already configured
    2.50 +        bridges = Brctl.get_state().keys()
    2.51 +        configured_bridges = [XendAPIStore.get(
    2.52 +                                  network_uuid, "network")
    2.53 +                                      .get_name_label()
    2.54 +                              for network_uuid in XendNetwork.get_all()]
    2.55 +        unconfigured_bridges = [bridge
    2.56 +                                for bridge in bridges
    2.57 +                                if bridge not in configured_bridges]
    2.58 +        for unconfigured_bridge in unconfigured_bridges:
    2.59 +            XendNetwork.create_phy(unconfigured_bridge)
    2.60  
    2.61 -        if_to_br = dict([(i,b)
    2.62 -                         for (b,ifs) in Brctl.get_state().items()
    2.63 -                         for i in ifs])
    2.64 -
    2.65 -        # initialise PIFs
    2.66 +        # Initialise PIFs
    2.67 +        # First configure ones off disk
    2.68          saved_pifs = self.state_store.load_state('pif')
    2.69          if saved_pifs:
    2.70              for pif_uuid, pif in saved_pifs.items():
    2.71 -                if pif.get('network') in self.networks:
    2.72 -                    network = self.networks[pif['network']]
    2.73 -                    try:
    2.74 -                        if 'device' not in pif and 'name' in pif:
    2.75 -                            # Compatibility hack, can go pretty soon.
    2.76 -                            pif['device'] = pif['name']
    2.77 -                        if 'metrics' not in pif:
    2.78 -                            # Compatibility hack, can go pretty soon.
    2.79 -                            pif['metrics'] = uuid.createString()
    2.80 +                XendPIF.recreate(pif, pif_uuid)
    2.81 + 
    2.82 +        # Next discover any existing PIFs and check
    2.83 +        # they are not already configured
    2.84 +        configured_pifs = [XendAPIStore.get(
    2.85 +                               pif_uuid, "PIF")
    2.86 +                                   .get_interface_name()
    2.87 +                           for pif_uuid in XendPIF.get_all()]
    2.88 +        unconfigured_pifs = [(name, mtu, mac)
    2.89 +                             for name, mtu, mac in linux_get_phy_ifaces()
    2.90 +                             if name not in configured_pifs]
    2.91  
    2.92 -                        try:
    2.93 -                            pif['VLAN'] = int(pif.get('VLAN', -1))
    2.94 -                        except (ValueError, TypeError):
    2.95 -                            pif['VLAN'] = -1
    2.96 +        # Get a mapping from interface to bridge          
    2.97 +        if_to_br = dict([(i,b)
    2.98 +                         for (b,ifs) in Brctl.get_state().items()
    2.99 +                             for i in ifs])
   2.100  
   2.101 -                        self._PIF_create(pif['device'], pif['MTU'],
   2.102 -                                         pif['VLAN'],
   2.103 -                                         pif['MAC'], network, False, pif_uuid,
   2.104 -                                         pif['metrics'])
   2.105 -                    except NetworkAlreadyConnected, exn:
   2.106 -                        log.error('Cannot load saved PIF %s, as network %s ' +
   2.107 -                                  'is already connected to PIF %s',
   2.108 -                                  pif_uuid, pif['network'], exn.pif_uuid)
   2.109 -        else:
   2.110 -            for name, mtu, mac in linux_get_phy_ifaces():
   2.111 -                bridge_name = if_to_br.get(name, None)
   2.112 -                if bridge_name is not None:
   2.113 -                    networks = [network for
   2.114 -                                network in self.networks.values()
   2.115 -                                if network.get_name_label() == bridge_name]
   2.116 -                    if len(networks) > 0:
   2.117 -                        network = networks[0]
   2.118 -                        self._PIF_create(name, mtu, -1, mac, network, False)
   2.119 -
   2.120 +        for name, mtu, mac in unconfigured_pifs:
   2.121 +            # Check PIF is on bridge
   2.122 +            # if not, ignore
   2.123 +            bridge_name = if_to_br.get(name, None)
   2.124 +            if bridge_name is not None:
   2.125 +                # Translate bridge name to network uuid
   2.126 +                for network_uuid in XendNetwork.get_all():
   2.127 +                    network = XendAPIStore.get(
   2.128 +                        network_uuid, 'network')
   2.129 +                    if network.get_name_label() == bridge_name:
   2.130 +                        XendPIF.create_phy(network_uuid, name,
   2.131 +                                           mtu, mac)
   2.132 +                        break
   2.133 +                else:
   2.134 +                    log.debug("Cannot find network for bridge %s "
   2.135 +                              "when configuring PIF %s",
   2.136 +                              (bridge_name, name))     
   2.137 +        
   2.138          # initialise storage
   2.139          saved_srs = self.state_store.load_state('sr')
   2.140          if saved_srs:
   2.141              for sr_uuid, sr_cfg in saved_srs.items():
   2.142 -                log.error("SAved SRS %s %s", sr_uuid, sr_cfg['type'])
   2.143                  if sr_cfg['type'] == 'qcow_file':
   2.144                      self.srs[sr_uuid] = XendQCoWStorageRepo(sr_uuid)
   2.145                  elif sr_cfg['type'] == 'local':
   2.146 @@ -214,69 +217,47 @@ class XendNode:
   2.147          saved_pbds = self.state_store.load_state('pbd')
   2.148          if saved_pbds:
   2.149              for pbd_uuid, pbd_cfg in saved_pbds.items():
   2.150 -                pbd_cfg['uuid'] = pbd_uuid
   2.151 -                XendPBD.XendPBD(pbd_cfg)
   2.152 -
   2.153 +                XendPBD.recreate(pbd_uuid, pbd_cfg)
   2.154  
   2.155 -    def network_create(self, record, persist = True, net_uuid = None):
   2.156 -        if net_uuid is None:
   2.157 -            net_uuid = uuid.createString()
   2.158 -        self.networks[net_uuid] = XendNetwork(net_uuid, record)
   2.159 -        if persist:
   2.160 -            self.save_networks()
   2.161 -        return net_uuid
   2.162 -
   2.163 -
   2.164 -    def network_destroy(self, net_uuid):
   2.165 -        del self.networks[net_uuid]
   2.166 -        self.save_networks()
   2.167 -
   2.168 -
   2.169 -    def get_PIF_refs(self):
   2.170 -        return self.pifs.keys()
   2.171 +##    def network_destroy(self, net_uuid):
   2.172 + ##       del self.networks[net_uuid]
   2.173 +  ##      self.save_networks()
   2.174  
   2.175  
   2.176 -    def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
   2.177 -                    pif_uuid = None, metrics_uuid = None):
   2.178 -        for pif in self.pifs.values():
   2.179 -            if pif.network == network:
   2.180 -                raise NetworkAlreadyConnected(pif.uuid)
   2.181 +##    def get_PIF_refs(self):
   2.182 +##       return self.pifs[:]
   2.183  
   2.184 -        if pif_uuid is None:
   2.185 -            pif_uuid = uuid.createString()
   2.186 -        if metrics_uuid is None:
   2.187 -            metrics_uuid = uuid.createString()
   2.188 +##   def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
   2.189 +##                     pif_uuid = None, metrics_uuid = None):
   2.190 +##         for pif in self.pifs.values():
   2.191 +##             if pif.network == network:
   2.192 +##                 raise NetworkAlreadyConnected(pif.uuid)
   2.193  
   2.194 -        metrics = XendPIFMetrics(metrics_uuid)
   2.195 -        pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
   2.196 -        metrics.set_PIF(pif)
   2.197 -
   2.198 -        self.pif_metrics[metrics_uuid] = metrics
   2.199 -        self.pifs[pif_uuid] = pif
   2.200 +##         if pif_uuid is None:
   2.201 +##             pif_uuid = uuid.createString()
   2.202 +##         if metrics_uuid is None:
   2.203 +##             metrics_uuid = uuid.createString()
   2.204  
   2.205 -        if persist:
   2.206 -            self.save_PIFs()
   2.207 -            self.refreshBridges()
   2.208 -        return pif_uuid
   2.209 +##         metrics = XendPIFMetrics(metrics_uuid)
   2.210 +##         pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
   2.211 +##         metrics.set_PIF(pif)
   2.212  
   2.213 +##         self.pif_metrics[metrics_uuid] = metrics
   2.214 +##         self.pifs[pif_uuid] = pif
   2.215  
   2.216 -    def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan):
   2.217 -        if vlan < 0 or vlan >= 4096:
   2.218 -            raise VLANTagInvalid()
   2.219 -            
   2.220 -        pif = self.pifs[pif_uuid]
   2.221 -        network = self.networks[network_uuid]
   2.222 -        return self._PIF_create(pif.device, pif.mtu, vlan, pif.mac, network)
   2.223 -
   2.224 +##         if persist:
   2.225 +##             self.save_PIFs()
   2.226 +##             self.refreshBridges()
   2.227 +##         return pif_uuid
   2.228  
   2.229 -    def PIF_destroy(self, pif_uuid):
   2.230 -        pif = self.pifs[pif_uuid]
   2.231 +##     def PIF_destroy(self, pif_uuid):
   2.232 +##         pif = self.pifs[pif_uuid]
   2.233  
   2.234 -        if pif.vlan == -1:
   2.235 -            raise PIFIsPhysical()
   2.236 +##         if pif.vlan == -1:
   2.237 +##             raise PIFIsPhysical()
   2.238  
   2.239 -        del self.pifs[pif_uuid]
   2.240 -        self.save_PIFs()
   2.241 +##         del self.pifs[pif_uuid]
   2.242 +##         self.save_PIFs()
   2.243  
   2.244  
   2.245      def save(self):
   2.246 @@ -284,7 +265,7 @@ class XendNode:
   2.247          host_record = {self.uuid: {'name_label':self.name,
   2.248                                     'name_description':self.desc,
   2.249                                     'metrics_uuid': self.host_metrics_uuid,
   2.250 -                                   'other_config': repr(self.other_config)}}
   2.251 +                                   'other_config': self.other_config}}
   2.252          self.state_store.save_state('host',host_record)
   2.253          self.state_store.save_state('cpu', self.cpus)
   2.254          self.save_PIFs()
   2.255 @@ -293,18 +274,21 @@ class XendNode:
   2.256          self.save_SRs()
   2.257  
   2.258      def save_PIFs(self):
   2.259 -        pif_records = dict([(k, v.get_record())
   2.260 -                            for k, v in self.pifs.items()])
   2.261 +        pif_records = dict([(pif_uuid, XendAPIStore.get(
   2.262 +                                 pif_uuid, "PIF").get_record())
   2.263 +                            for pif_uuid in XendPIF.get_all()])
   2.264          self.state_store.save_state('pif', pif_records)
   2.265  
   2.266      def save_networks(self):
   2.267 -        net_records = dict([(k, v.get_record_internal(False))
   2.268 -                            for k, v in self.networks.items()])
   2.269 +        net_records = dict([(network_uuid, XendAPIStore.get(
   2.270 +                                 network_uuid, "network").get_record())
   2.271 +                            for network_uuid in XendNetwork.get_all()])
   2.272          self.state_store.save_state('network', net_records)
   2.273  
   2.274      def save_PBDs(self):
   2.275 -        pbd_records = dict([(v.get_uuid(), v.get_record())
   2.276 -                            for v in XendPBD.get_all()])
   2.277 +        pbd_records = dict([(pbd_uuid, XendAPIStore.get(
   2.278 +                                 pbd_uuid, "PBD").get_record())
   2.279 +                            for pbd_uuid in XendPBD.get_all()])
   2.280          self.state_store.save_state('pbd', pbd_records)
   2.281  
   2.282      def save_SRs(self):
   2.283 @@ -331,9 +315,6 @@ class XendNode:
   2.284      def is_valid_cpu(self, cpu_ref):
   2.285          return (cpu_ref in self.cpus)
   2.286  
   2.287 -    def is_valid_network(self, network_ref):
   2.288 -        return (network_ref in self.networks)
   2.289 -
   2.290      def is_valid_sr(self, sr_ref):
   2.291          return (sr_ref in self.srs)
   2.292  
   2.293 @@ -495,12 +476,6 @@ class XendNode:
   2.294      # Network Functions
   2.295      #
   2.296      
   2.297 -    def get_network_refs(self):
   2.298 -        return self.networks.keys()
   2.299 -
   2.300 -    def get_network(self, network_ref):
   2.301 -        return self.networks[network_ref]
   2.302 -
   2.303      def bridge_to_network(self, bridge):
   2.304          """
   2.305          Determine which network a particular bridge is attached to.
   2.306 @@ -518,13 +493,12 @@ class XendNode:
   2.307                  raise Exception(
   2.308                      'Could not find default bridge, and none was specified')
   2.309  
   2.310 -        bridges = Brctl.get_state()
   2.311 -        if bridge not in bridges:
   2.312 -            raise Exception('Bridge %s is not up' % bridge)
   2.313 -        for pif in self.pifs.values():
   2.314 -            if pif.interface_name() in bridges[bridge]:
   2.315 -                return pif.network
   2.316 -        raise Exception('Bridge %s is not connected to a network' % bridge)
   2.317 +        for network_uuid in XendNetwork.get_all():
   2.318 +            network = XendAPIStore.get(network_uuid, "network")
   2.319 +            if network.get_name_label() == bridge:
   2.320 +                return network
   2.321 +        else:
   2.322 +            raise Exception('Cannot find network for bridge %s' % bridge)
   2.323  
   2.324      #
   2.325      # Debug keys.
   2.326 @@ -642,12 +616,6 @@ class XendNode:
   2.327      def info_dict(self):
   2.328          return dict(self.info())
   2.329  
   2.330 -
   2.331 -    def refreshBridges(self):
   2.332 -        for pif in self.pifs.values():
   2.333 -            pif.refresh(Brctl.get_state())
   2.334 -
   2.335 -
   2.336  def parse_proc_cpuinfo():
   2.337      cpuinfo = {}
   2.338      f = file('/proc/cpuinfo', 'r')
     3.1 --- a/tools/python/xen/xend/XendPIF.py	Wed Apr 25 16:16:21 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendPIF.py	Wed Apr 25 16:17:51 2007 +0100
     3.3 @@ -19,12 +19,15 @@ import commands
     3.4  import logging
     3.5  import os
     3.6  import re
     3.7 -
     3.8 +from xen.xend import uuid as genuuid
     3.9 +from xen.xend import XendAPIStore
    3.10 +from xen.xend.XendBase import XendBase
    3.11 +from xen.xend.XendPIFMetrics import XendPIFMetrics
    3.12 +from xen.xend.XendError import *
    3.13  
    3.14  log = logging.getLogger("xend.XendPIF")
    3.15  log.setLevel(logging.TRACE)
    3.16  
    3.17 -
    3.18  MAC_RE = re.compile(':'.join(['[0-9a-f]{2}'] * 6))
    3.19  IP_IFACE_RE = re.compile(r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)')
    3.20  
    3.21 @@ -87,106 +90,239 @@ def linux_set_mtu(iface, mtu):
    3.22      except ValueError:
    3.23          return False
    3.24  
    3.25 -class XendPIF:
    3.26 +def _create_VLAN(dev, vlan):
    3.27 +    rc, _ = commands.getstatusoutput('vconfig add %s %d' %
    3.28 +                                     (dev, vlan))
    3.29 +    return rc == 0   
    3.30 +
    3.31 +class XendPIF(XendBase):
    3.32      """Representation of a Physical Network Interface."""
    3.33 +
    3.34 +    def getClass(self):
    3.35 +        return "PIF"
    3.36 +
    3.37 +    def getAttrRO(self):
    3.38 +        attrRO = ['network',
    3.39 +                  'host',
    3.40 +                  'metrics',
    3.41 +                  'device']
    3.42 +        return XendBase.getAttrRO() + attrRO
    3.43 +    
    3.44 +    def getAttrRW(self):
    3.45 +        attrRW = ['MAC',
    3.46 +                  'MTU',
    3.47 +                  'VLAN']
    3.48 +        return XendBase.getAttrRW() + attrRW
    3.49 +
    3.50 +    def getAttrInst(self):
    3.51 +        attrInst = ['network',
    3.52 +                    'device',
    3.53 +                    'MAC',
    3.54 +                    'MTU',
    3.55 +                    'VLAN']
    3.56 +        return attrInst
    3.57 +
    3.58 +    def getMethods(self):
    3.59 +        methods = ['plug',
    3.60 +                   'unplug']
    3.61 +        return XendBase.getMethods() + methods
    3.62 +
    3.63 +    def getFuncs(self):
    3.64 +        funcs = ['create_VLAN']
    3.65 +        return XendBase.getFuncs() + funcs
    3.66 +
    3.67 +    getClass    = classmethod(getClass)
    3.68 +    getAttrRO   = classmethod(getAttrRO)
    3.69 +    getAttrRW   = classmethod(getAttrRW)
    3.70 +    getAttrInst = classmethod(getAttrInst)
    3.71 +    getMethods  = classmethod(getMethods)
    3.72 +    getFuncs    = classmethod(getFuncs)
    3.73      
    3.74 -    def __init__(self, uuid, metrics, device, mtu, vlan, mac, network,
    3.75 -                 host):
    3.76 -        self.uuid = uuid
    3.77 -        self.metrics = metrics
    3.78 -        self.device = device
    3.79 -        self.mac = mac
    3.80 -        self.mtu = mtu
    3.81 -        self.vlan = vlan
    3.82 -        self.network = network
    3.83 -        self.host = host
    3.84 +    def create_phy(self, network_uuid, device,
    3.85 +                   MAC, MTU):
    3.86 +        """
    3.87 +        Called when a new physical PIF is found
    3.88 +        Could be a VLAN...
    3.89 +        """
    3.90 +        # Create new uuids
    3.91 +        pif_uuid = genuuid.createString()
    3.92 +        metrics_uuid = genuuid.createString()
    3.93 +
    3.94 +        # Create instances
    3.95 +        metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
    3.96 +
    3.97 +        # Is this a VLAN?
    3.98 +        VLANdot = device.split(".")
    3.99 +        VLANcolon = device.split(":")
   3.100 +
   3.101 +        if len(VLANdot) > 1:
   3.102 +            VLAN = VLANdot[1]
   3.103 +            device = VLANdot[0]
   3.104 +        elif len(VLANcolon) > 1:
   3.105 +            VLAN = VLANcolon[1]
   3.106 +            device = VLANcolon[0] 
   3.107 +        else:
   3.108 +            VLAN = -1
   3.109 +            
   3.110 +        record = {
   3.111 +            'network': network_uuid,
   3.112 +            'device':  device,
   3.113 +            'MAC':     MAC,
   3.114 +            'MTU':     MTU,
   3.115 +            'VLAN':    VLAN
   3.116 +            }
   3.117 +        pif = XendPIF(record, pif_uuid, metrics_uuid)
   3.118 +
   3.119 +        return pif_uuid
   3.120 +
   3.121 +    def recreate(self, record, uuid):
   3.122 +        """Called on xend start / restart"""        
   3.123 +        pif_uuid = uuid
   3.124 +        metrics_uuid = record['metrics']
   3.125 +
   3.126 +        # Create instances
   3.127 +        metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
   3.128 +        pif = XendPIF(record, pif_uuid, metrics_uuid)
   3.129 +
   3.130 +        # If physical PIF, check exists
   3.131 +        # If VLAN, create if not exist
   3.132 +        ifs = [dev for dev, _1, _2 in linux_get_phy_ifaces()]
   3.133 +        if pif.get_VLAN() == -1:
   3.134 +            if pif.get_device() not in ifs:
   3.135 +                del pif
   3.136 +                del metrics
   3.137 +                return None
   3.138 +        else:
   3.139 +            if pif.get_interface_name() not in ifs:
   3.140 +                _create_VLAN(pif.get_device(), pif.get_VLAN())
   3.141 +
   3.142 +        return pif_uuid
   3.143  
   3.144 -    def set_device(self, new_device):
   3.145 -        self.device = new_device
   3.146 +    def create_VLAN(self, device, network_uuid, host_ref, vlan):
   3.147 +        """Exposed via API - create a new VLAN from existing VIF"""
   3.148 +        
   3.149 +        ifs = [name for name, _, _ in linux_get_phy_ifaces()]
   3.150 +
   3.151 +        vlan = int(vlan)
   3.152 +
   3.153 +        # Check VLAN tag is valid
   3.154 +        if vlan < 0 or vlan >= 4096:
   3.155 +            raise VLANTagInvalid(vlan)
   3.156 +        
   3.157 +        # Check device exists
   3.158 +        if device not in ifs:
   3.159 +            raise InvalidDeviceError(device)
   3.160 +
   3.161 +        # Check VLAN doesn't already exist
   3.162 +        if "%s.%d" % (device, vlan) in ifs:
   3.163 +            raise DeviceExistsError("%s.%d" % (device, vlan))
   3.164 +
   3.165 +        # Check network ref is valid
   3.166 +        from xen.xend import XendNode
   3.167 +        network_uuids = XendNode.instance().networks
   3.168 +        if network_uuid in network_uuids:
   3.169 +            raise InvalidHandleError("Network", network_ref)
   3.170 +
   3.171 +        # Check host_ref is this host
   3.172 +        if host_ref != XendNode.instance().get_uuid():
   3.173 +            raise InvalidHandleError("Host", host_ref)
   3.174 +
   3.175 +        # Create the VLAN
   3.176 +        _create_VLAN(device, vlan)
   3.177 +
   3.178 +        # Create new uuids
   3.179 +        pif_uuid = genuuid.createString()
   3.180 +        metrics_uuid = genuuid.createString()
   3.181 +
   3.182 +        # Create the record
   3.183 +        record = {
   3.184 +            "device":  device,
   3.185 +            "MAC":     '',
   3.186 +            "MTU":     '',
   3.187 +            "network": network_ref,
   3.188 +            "VLAN":    vlan
   3.189 +            }
   3.190 +
   3.191 +        # Create instances
   3.192 +        metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
   3.193 +        pif = XendPIF(record, pif_uuid, metrics_uuid)
   3.194 +        
   3.195 +        # Add it to list of PIFs
   3.196 +        XendNode.instance().pifs.append(pif_ref)        
   3.197 +
   3.198 +        # Add it to network
   3.199 +        network.add_pif(pif_ref)
   3.200  
   3.201 -    def set_mac(self, new_mac):
   3.202 -        success = linux_set_mac(new_mac)
   3.203 +        return pif_uuid
   3.204 +
   3.205 +    create_phy  = classmethod(create_phy)
   3.206 +    recreate    = classmethod(recreate)
   3.207 +    create_VLAN = classmethod(create_VLAN)
   3.208 +    
   3.209 +    def __init__(self, record, uuid, metrics_uuid):
   3.210 +        XendBase.__init__(self, uuid, record)
   3.211 +        self.metrics = metrics_uuid
   3.212 +
   3.213 +    def plug(self):
   3.214 +        """Plug the PIF into the network"""
   3.215 +        network = XendAPIStore.get(self.network,
   3.216 +                                   "network")
   3.217 +        bridge_name = network.get_name_label()
   3.218 +
   3.219 +        Brctl.vif_bridge_add({
   3.220 +            "bridge": bridge_name,
   3.221 +            "vif":    self.get_interface_name()
   3.222 +            })
   3.223 +
   3.224 +    def unplug(self):
   3.225 +        """Unplug the PIF from the network"""
   3.226 +        pass
   3.227 +
   3.228 +    def get_interface_name(self):
   3.229 +        if self.get_VLAN() == -1:
   3.230 +            return self.get_device()
   3.231 +        else:
   3.232 +            return "%s.%d" % (self.get_device(), self.get_VLAN())
   3.233 +        
   3.234 +    def get_device(self):
   3.235 +        """
   3.236 +        This is the base interface.
   3.237 +        For phy if (VLAN == -1) this is same as
   3.238 +        if name.
   3.239 +        For VLANs, this it the bit before the period
   3.240 +        """
   3.241 +        return self.device
   3.242 +
   3.243 +    def get_network(self):
   3.244 +        return self.network
   3.245 +
   3.246 +    def get_host(self):
   3.247 +        from xen.xend import XendNode
   3.248 +        return XendNode.instance().get_uuid()
   3.249 +
   3.250 +    def get_metrics(self):
   3.251 +        return self.metrics
   3.252 +
   3.253 +    def get_MAC(self):
   3.254 +        return self.MAC
   3.255 +
   3.256 +    def set_MAC(self, new_mac):
   3.257 +        success = linux_set_mac(self.device, new_mac)
   3.258          if success:
   3.259 -            self.mac = new_mac
   3.260 -        return success
   3.261 -
   3.262 -    def set_mtu(self, new_mtu):
   3.263 -        success = linux_set_mtu(new_mtu)
   3.264 -        if success:
   3.265 -            self.mtu = new_mtu
   3.266 +            self.MAC = new_mac
   3.267          return success
   3.268  
   3.269 -    def get_record(self):
   3.270 -        return {'uuid': self.uuid,
   3.271 -                'device': self.device,
   3.272 -                'MAC': self.mac,
   3.273 -                'MTU': self.mtu,
   3.274 -                'VLAN': self.vlan,
   3.275 -                'host': self.host.uuid,
   3.276 -                'network': self.network.uuid,
   3.277 -                'metrics': self.metrics.uuid}
   3.278 -
   3.279 -    def refresh(self, bridges):
   3.280 -        ifname = self.interface_name()
   3.281 -        rc, _ = _cmd('ip link show %s', ifname)
   3.282 -        if rc != 0:
   3.283 -            # Interface does not exist.  If it's a physical interface, then
   3.284 -            # there's nothing we can do -- this should have been set up with
   3.285 -            # the network script.  Otherwise, we can use vconfig to derive
   3.286 -            # a subinterface.
   3.287 -            if self.vlan == -1:
   3.288 -                return
   3.289 -            
   3.290 -            rc, _ = _cmd('vconfig add %s %d', self.device, self.vlan)
   3.291 -            if rc != 0:
   3.292 -                log.error('Could not refresh VLAN for interface %s', ifname)
   3.293 -                return
   3.294 -            
   3.295 -            log.info('Created network interface %s', ifname)
   3.296 -
   3.297 -        for brname, nics in bridges.items():
   3.298 -            if ifname in nics:
   3.299 -                log.debug('%s is already attached to %s', ifname, brname)
   3.300 -                return
   3.301 +    def get_MTU(self):
   3.302 +        return self.MTU
   3.303  
   3.304 -        # The interface is not attached to a bridge.  Create one, and attach
   3.305 -        # the interface to it.
   3.306 -        brname = _new_bridge_name(bridges)
   3.307 -        rc, _ = _cmd('brctl addbr %s', brname)
   3.308 -        if rc != 0:
   3.309 -            log.error('Could not create bridge %s for interface %s', brname,
   3.310 -                      ifname)
   3.311 -            return
   3.312 -        log.info('Created network bridge %s', brname)
   3.313 -        
   3.314 -        rc, _ = _cmd('brctl addif %s %s', brname, ifname)
   3.315 -        if rc != 0:
   3.316 -            log.error('Could not add %s to %s', ifname, brname)
   3.317 -            return
   3.318 -        log.info('Added network interface %s to bridge %s', ifname, brname)
   3.319 -
   3.320 +    def set_MTU(self, new_mtu):
   3.321 +        success = linux_set_mtu(self.device, new_mtu)
   3.322 +        if success:
   3.323 +            self.MTU = new_mtu
   3.324 +        return success
   3.325  
   3.326 -    def interface_name(self):
   3.327 -        if self.vlan != -1:
   3.328 -            return '%s.%d' % (self.device, self.vlan)
   3.329 -        else:
   3.330 -            return self.device
   3.331 -
   3.332 +    def get_VLAN(self):
   3.333 +        return self.VLAN
   3.334  
   3.335 -def _cmd(cmd, *args):
   3.336 -    if len(args) > 0:
   3.337 -        cmd = cmd % args
   3.338 -    rc, output = commands.getstatusoutput(cmd)
   3.339 -    if rc != 0:
   3.340 -        log.debug('%s failed with code %d' % (cmd, rc))
   3.341 -    log.trace('%s: %s' % (cmd, output))
   3.342 -    return rc, output
   3.343 -
   3.344 -
   3.345 -def _new_bridge_name(bridges):
   3.346 -    n = 0
   3.347 -    while True:
   3.348 -        brname = 'xenbr%d' % n
   3.349 -        if brname not in bridges:
   3.350 -            return brname
   3.351 -        n += 1
   3.352 +    def set_VLAN(self, VLAN):
   3.353 +        pass