direct-io.hg

changeset 2507:03bd2991dbd4

bitkeeper revision 1.1159.1.164 (41503abcmVn6L0phzf-BOxlxa3zgxw)

Add support for reconfiguring an existing device,
including support for changing the bridge of a vif.
Treat bridge "null" as meaning no bridge.
author mjw@wray-m-3.hpl.hp.com
date Tue Sep 21 14:29:16 2004 +0000 (2004-09-21)
parents c7b0154dff73
children fbfc2497d55e
files tools/examples/network tools/examples/vif-bridge tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/sxp.py
line diff
     1.1 --- a/tools/examples/network	Tue Sep 21 08:53:13 2004 +0000
     1.2 +++ b/tools/examples/network	Tue Sep 21 14:29:16 2004 +0000
     1.3 @@ -139,31 +139,44 @@ show_status () {
     1.4      echo '============================================================'
     1.5  }
     1.6  
     1.7 +op_start () {
     1.8 +    if [ "${bridge}" == "null" ] ; then
     1.9 +        return
    1.10 +    fi
    1.11 +    # Create the bridge and give it the interface IP addresses.
    1.12 +    # Move the interface routes onto the bridge.
    1.13 +    create_bridge ${netdev} ${bridge}
    1.14 +    transfer_addrs ${netdev} ${bridge}
    1.15 +    transfer_routes ${netdev} ${bridge}
    1.16 +    # Don't add $dev to $bridge if it's already on a bridge.
    1.17 +    if ! brctl show | grep -q ${netdev} ; then
    1.18 +        brctl addif ${bridge} ${netdev}
    1.19 +    fi
    1.20 +    
    1.21 +    if [ ${antispoof} == 'yes' ] ; then
    1.22 +        antispoofing ${netdev} ${bridge}
    1.23 +    fi
    1.24 +}
    1.25 +
    1.26 +op_stop () {
    1.27 +    if [ "${bridge}" == "null" ] ; then
    1.28 +        return
    1.29 +    fi
    1.30 +    # Remove the interface from the bridge.
    1.31 +    # Move the routes back to the interface.
    1.32 +    brctl delif ${bridge} ${netdev}
    1.33 +    transfer_routes ${bridge} ${netdev}
    1.34 +
    1.35 +    # It's not our place to be enabling forwarding...
    1.36 +}
    1.37 +
    1.38  case ${OP} in
    1.39      start)
    1.40 -        # Create the bridge and give it the interface IP addresses.
    1.41 -        # Move the interface routes onto the bridge.
    1.42 -        create_bridge ${netdev} ${bridge}
    1.43 -        transfer_addrs ${netdev} ${bridge}
    1.44 -        transfer_routes ${netdev} ${bridge}
    1.45 -	# Don't add $dev to $bridge if it's already on a bridge.
    1.46 -	if ! brctl show | grep -q ${netdev} ; then
    1.47 -	    brctl addif ${bridge} ${netdev}
    1.48 -	fi
    1.49 -        
    1.50 -        if [ ${antispoof} == 'yes' ] ; then
    1.51 -            antispoofing ${netdev} ${bridge}
    1.52 -        fi
    1.53 -        
    1.54 +        op_start
    1.55          ;;
    1.56      
    1.57      stop)
    1.58 -        # Remove the interface from the bridge.
    1.59 -        # Move the routes back to the interface.
    1.60 -        brctl delif ${bridge} ${netdev}
    1.61 -        transfer_routes ${bridge} ${netdev}
    1.62 -
    1.63 -        # It's not our place to be enabling forwarding...
    1.64 +        op_stop
    1.65          ;;
    1.66  
    1.67      status)
     2.1 --- a/tools/examples/vif-bridge	Tue Sep 21 08:53:13 2004 +0000
     2.2 +++ b/tools/examples/vif-bridge	Tue Sep 21 14:29:16 2004 +0000
     2.3 @@ -69,6 +69,11 @@ case $OP in
     2.4          ;;
     2.5  esac
     2.6  
     2.7 +# Don't do anything if the bridge is "null".
     2.8 +if [ "${bridge}" == "null" ] ; then
     2.9 +    exit
    2.10 +fi
    2.11 +
    2.12  # Add/remove vif to/from bridge.
    2.13  brctl ${brcmd} ${bridge} ${vif}
    2.14  
     3.1 --- a/tools/python/xen/xend/XendClient.py	Tue Sep 21 08:53:13 2004 +0000
     3.2 +++ b/tools/python/xen/xend/XendClient.py	Tue Sep 21 14:29:16 2004 +0000
     3.3 @@ -550,6 +550,12 @@ class Xend:
     3.4                                'type'    : type,
     3.5                                'idx'     : idx })
     3.6  
     3.7 +    def xend_domain_device_configure(self, id, config, idx):
     3.8 +        return self.xendPost(self.domainurl(id),
     3.9 +                             {'op'      : 'device_configure',
    3.10 +                              'idx'     : idx,
    3.11 +                              'config'  : fileof(config) })
    3.12 +
    3.13      def xend_consoles(self):
    3.14          return self.xendGet(self.consoleurl())
    3.15  
     4.1 --- a/tools/python/xen/xend/XendDomain.py	Tue Sep 21 08:53:13 2004 +0000
     4.2 +++ b/tools/python/xen/xend/XendDomain.py	Tue Sep 21 14:29:16 2004 +0000
     4.3 @@ -684,12 +684,27 @@ class XendDomain:
     4.4          self.update_domain(dominfo.id)
     4.5          return val
     4.6  
     4.7 +    def domain_device_configure(self, id, devconfig, idx):
     4.8 +        """Configure an existing device for a domain.
     4.9 +
    4.10 +        @param id:   domain id
    4.11 +        @param devconfig: device configuration
    4.12 +        @param idx:  device index
    4.13 +        @return: updated device configuration
    4.14 +        """
    4.15 +        dominfo = self.domain_lookup(id)
    4.16 +        self.refresh_schedule()
    4.17 +        val = dominfo.device_configure(devconfig, idx)
    4.18 +        self.update_domain(dominfo.id)
    4.19 +        return val
    4.20 +    
    4.21 +
    4.22      def domain_device_destroy(self, id, type, idx):
    4.23          """Destroy a device.
    4.24  
    4.25          @param id:  domain id
    4.26 +        @param idx:  device index
    4.27          @param type: device type
    4.28 -        @param idx:  device index
    4.29          """
    4.30          dominfo = self.domain_lookup(id)
    4.31          self.refresh_schedule()
    4.32 @@ -706,7 +721,6 @@ class XendDomain:
    4.33          """
    4.34          dominfo = self.domain_lookup(id)
    4.35          devs = dominfo.get_devices(type)
    4.36 -        #return range(0, len(devs))
    4.37          return devs
    4.38  
    4.39      def domain_devtype_get(self, id, type, idx):
     5.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Tue Sep 21 08:53:13 2004 +0000
     5.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Tue Sep 21 14:29:16 2004 +0000
     5.3 @@ -825,6 +825,30 @@ class XendDomainInfo:
     5.4          d = dev_handler(self, dev_config, dev_index, change=1)
     5.5          return d
     5.6  
     5.7 +    def device_configure(self, dev_config, idx):
     5.8 +        """Configure an existing device.
     5.9 +
    5.10 +        @param dev_config: device configuration
    5.11 +        @param idx:  device index
    5.12 +        """
    5.13 +        type = sxp.name(dev_config)
    5.14 +        dev = self.get_device_by_index(type, idx)
    5.15 +        if not dev:
    5.16 +            raise VmError('invalid device: %s %s' % (type, idx))
    5.17 +        new_config = dev.configure(dev_config, change=1)
    5.18 +        devs = self.devices.get(type)
    5.19 +        index = devs.index(dev)
    5.20 +        # Patch new config into device configs.
    5.21 +        dev_configs = self.config_devices(type)
    5.22 +        old_config = dev_configs[index]
    5.23 +        dev_configs[index] = new_config
    5.24 +        # Patch new config into vm config.
    5.25 +        new_full_config = ['device', new_config]
    5.26 +        old_full_config = ['device', old_config]
    5.27 +        old_index = self.config.index(old_full_config)
    5.28 +        self.config[old_index] = new_full_config
    5.29 +        return new_config
    5.30 +        
    5.31      def device_destroy(self, type, idx):
    5.32          """Destroy a device.
    5.33  
     6.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Tue Sep 21 08:53:13 2004 +0000
     6.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Tue Sep 21 14:29:16 2004 +0000
     6.3 @@ -164,6 +164,14 @@ class SrvDomain(SrvDir):
     6.4          val = fn(req.args, {'dom': self.dom.id})
     6.5          return val
     6.6                  
     6.7 +    def op_device_configure(self, op, req):
     6.8 +        fn = FormFn(self.xd.domain_device_configure,
     6.9 +                    [['dom', 'str'],
    6.10 +                     ['config', 'sxpr'],
    6.11 +                     ['idx', 'str']])
    6.12 +        d = fn(req.args, {'dom': self.dom.id})
    6.13 +        return d
    6.14 +
    6.15      def op_vifs(self, op, req):
    6.16          devs = self.xd.domain_vif_ls(self.dom.id)
    6.17          return [ dev.sxpr() for dev in devs ]
     7.1 --- a/tools/python/xen/xend/server/controller.py	Tue Sep 21 08:53:13 2004 +0000
     7.2 +++ b/tools/python/xen/xend/server/controller.py	Tue Sep 21 14:29:16 2004 +0000
     7.3 @@ -617,6 +617,9 @@ class Dev:
     7.4          """
     7.5          raise NotImplementedError()
     7.6  
     7.7 +    def configure(self, config, change=0):
     7.8 +        raise NotImplementedError()
     7.9 +
    7.10  class SplitDev(Dev):
    7.11  
    7.12      def __init__(self, idx, controller):
     8.1 --- a/tools/python/xen/xend/server/netif.py	Tue Sep 21 08:53:13 2004 +0000
     8.2 +++ b/tools/python/xen/xend/server/netif.py	Tue Sep 21 14:29:16 2004 +0000
     8.3 @@ -104,31 +104,82 @@ class NetDev(controller.SplitDev):
     8.4          self.evtchn = None
     8.5          self.configure(config)
     8.6  
     8.7 -    def configure(self, config):
     8.8 +    def _get_config_mac(self, config):
     8.9 +        vmac = sxp.child_value(config, 'mac')
    8.10 +        if not vmac: return None
    8.11 +        mac = [ int(x, 16) for x in vmac.split(':') ]
    8.12 +        if len(mac) != 6: raise XendError("invalid mac")
    8.13 +        return mac
    8.14 +
    8.15 +    def _get_config_ipaddr(self, config):
    8.16 +        ips = sxp.children(config, elt='ip')
    8.17 +        if ips:
    8.18 +            val = []
    8.19 +            for ipaddr in ips:
    8.20 +                val.append(sxp.child0(ipaddr))
    8.21 +        else:
    8.22 +            val = None
    8.23 +        return val
    8.24 +
    8.25 +    def configure(self, config, change=0):
    8.26 +        if change:
    8.27 +            return self.reconfigure(config)
    8.28          self.config = config
    8.29          self.mac = None
    8.30          self.bridge = None
    8.31          self.script = None
    8.32          self.ipaddr = []
    8.33 -        
    8.34 -        vmac = sxp.child_value(config, 'mac')
    8.35 -        if not vmac: raise XendError("invalid mac")
    8.36 -        mac = [ int(x, 16) for x in vmac.split(':') ]
    8.37 -        if len(mac) != 6: raise XendError("invalid mac")
    8.38 +
    8.39 +        mac = self._get_config_mac(config)
    8.40 +        if mac is None:
    8.41 +            raise XendError("invalid mac")
    8.42          self.mac = mac
    8.43 -
    8.44          self.bridge = sxp.child_value(config, 'bridge')
    8.45          self.script = sxp.child_value(config, 'script')
    8.46 -
    8.47 -        ipaddrs = sxp.children(config, elt='ip')
    8.48 -        for ipaddr in ipaddrs:
    8.49 -            self.ipaddr.append(sxp.child0(ipaddr))
    8.50 +        self.ipaddr = self._get_config_ipaddr(config) or []
    8.51          
    8.52          try:
    8.53              self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
    8.54          except:
    8.55              raise XendError('invalid backend domain')
    8.56  
    8.57 +    def reconfigure(self, config):
    8.58 +        """Reconfigure the interface with new values.
    8.59 +        Not all configuration parameters can be changed:
    8.60 +        bridge, script and ip addresses can,
    8.61 +        backend and mac cannot.
    8.62 +
    8.63 +        To leave a parameter unchanged, omit it from the changes.
    8.64 +
    8.65 +        @param config configuration changes
    8.66 +        @return updated interface configuration
    8.67 +        @raise XendError on errors
    8.68 +        """
    8.69 +        changes = {}
    8.70 +        mac = self._get_config_mac(config)
    8.71 +        bridge = sxp.child_value(config, 'bridge')
    8.72 +        script = sxp.child_value(config, 'script')
    8.73 +        ipaddr = self._get_config_ipaddr(config)
    8.74 +        backendDomain = sxp.child_value(config, 'backend', '0')
    8.75 +        if (mac is not None) and (mac != self.mac):
    8.76 +            raise XendError("cannot change mac")
    8.77 +        if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
    8.78 +            raise XendError("cannot change backend")
    8.79 +        if (bridge is not None) and (bridge != self.bridge):
    8.80 +            changes['bridge'] = bridge
    8.81 +        if (script is not None) and (script != self.script):
    8.82 +            changes['script'] = script
    8.83 +        if (ipaddr is not None) and (ipaddr != self.ipaddr):
    8.84 +            changes['ipaddr'] = ipaddr
    8.85 +
    8.86 +        if changes:
    8.87 +            self.vifctl("down")
    8.88 +            for (k, v) in changes.items():
    8.89 +                setattr(self, k, v)
    8.90 +            self.config = sxp.merge(config, self.config)
    8.91 +            self.vifctl("up")
    8.92 +        return self.config
    8.93 +
    8.94      def sxpr(self):
    8.95          vif = str(self.vif)
    8.96          mac = self.get_mac()
     9.1 --- a/tools/python/xen/xend/sxp.py	Tue Sep 21 08:53:13 2004 +0000
     9.2 +++ b/tools/python/xen/xend/sxp.py	Tue Sep 21 14:29:16 2004 +0000
     9.3 @@ -41,7 +41,8 @@ from StringIO import StringIO
     9.4      "has_id", 
     9.5      "with_id", 
     9.6      "child_with_id", 
     9.7 -    "elements", 
     9.8 +    "elements",
     9.9 +    "merge",
    9.10      "to_string",
    9.11      "from_string",
    9.12      "all_from_string",
    9.13 @@ -595,6 +596,77 @@ def elements(sxpr, ctxt=None):
    9.14                  yield v
    9.15          i += 1
    9.16  
    9.17 +def merge(s1, s2):
    9.18 +    """Merge sxprs s1 and s2.
    9.19 +    Returns an sxpr containing all the fields from s1 and s2, with
    9.20 +    entries in s1 overriding s2. Recursively merges fields.
    9.21 +
    9.22 +    @param s1 sxpr
    9.23 +    @param s2 sxpr
    9.24 +    @return merged sxpr
    9.25 +    """
    9.26 +    if s1 is None:
    9.27 +        val = s2
    9.28 +    elif s2 is None:
    9.29 +        val = s1
    9.30 +    elif elementp(s1):
    9.31 +        name1 = name(s1)
    9.32 +        (m1, v1) = child_map(s1)
    9.33 +        (m2, v2) = child_map(s2)
    9.34 +        val = [name1]
    9.35 +        for (k1, f1) in m1.items():
    9.36 +            merge_list(val, f1, m2.get(k1, []))
    9.37 +        for (k2, f2) in m2.items():
    9.38 +            if k2 in m1: continue
    9.39 +            val.extend(f2)
    9.40 +        val.extend(v1)
    9.41 +    else:
    9.42 +        val = s1
    9.43 +    return val
    9.44 +
    9.45 +def merge_list(sxpr, l1, l2):
    9.46 +    """Merge element lists l1 and l2 into sxpr.
    9.47 +    The lists l1 and l2 are all element with the same name.
    9.48 +    Values from l1 are merged with values in l2 and stored in sxpr.
    9.49 +    If one list is longer than the other the excess values are used
    9.50 +    as they are.
    9.51 +
    9.52 +    @param sxpr to merge into
    9.53 +    @param l1 sxpr list
    9.54 +    @param l2 sxpr list
    9.55 +    @return modified sxpr
    9.56 +    """
    9.57 +    n1 = len(l1)
    9.58 +    n2 = len(l2)
    9.59 +    nmin = min(n1, n2)
    9.60 +    for i in range(0, nmin):
    9.61 +        sxpr.append(merge(l1[i], l2[i]))
    9.62 +    for i in range(nmin, n1):
    9.63 +        sxpr.append(l1[i])
    9.64 +    for i in range(nmin, n2):
    9.65 +        sxpr.append(l2[i])
    9.66 +    return sxpr
    9.67 +
    9.68 +def child_map(sxpr):
    9.69 +    """Get a dict of the elements in sxpr and a list of its values.
    9.70 +    The dict maps element name to the list of elements with that name,
    9.71 +    and the list is the non-element children.
    9.72 +
    9.73 +    @param sxpr
    9.74 +    @return (dict, list)
    9.75 +    """
    9.76 +    m = {}
    9.77 +    v = []
    9.78 +    for x in children(sxpr):
    9.79 +        if elementp(x):
    9.80 +            n = name(x)
    9.81 +            l = m.get(n, [])
    9.82 +            l.append(x)
    9.83 +            m[n] = l
    9.84 +        else:
    9.85 +            v.append(x)
    9.86 +    return (m, v)
    9.87 +
    9.88  def to_string(sxpr):
    9.89      """Convert an sxpr to a string.
    9.90