mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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.
This commit is contained in:
1 parent
eb7bd4c6c6
commit
a23e4c0121
9 files changed
+230
-34
No files matched your search
@@ -550,6 +550,12 @@ class Xend:
|
||||
'type' : type,
|
||||
'idx' : idx })
|
||||
|
||||
def xend_domain_device_configure(self, id, config, idx):
|
||||
return self.xendPost(self.domainurl(id),
|
||||
{'op' : 'device_configure',
|
||||
'idx' : idx,
|
||||
'config' : fileof(config) })
|
||||
|
||||
def xend_consoles(self):
|
||||
return self.xendGet(self.consoleurl())
|
||||
|
||||
|
||||
@@ -684,12 +684,27 @@ class XendDomain:
|
||||
self.update_domain(dominfo.id)
|
||||
return val
|
||||
|
||||
def domain_device_configure(self, id, devconfig, idx):
|
||||
"""Configure an existing device for a domain.
|
||||
|
||||
@param id: domain id
|
||||
@param devconfig: device configuration
|
||||
@param idx: device index
|
||||
@return: updated device configuration
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
self.refresh_schedule()
|
||||
val = dominfo.device_configure(devconfig, idx)
|
||||
self.update_domain(dominfo.id)
|
||||
return val
|
||||
|
||||
|
||||
def domain_device_destroy(self, id, type, idx):
|
||||
"""Destroy a device.
|
||||
|
||||
@param id: domain id
|
||||
@param type: device type
|
||||
@param idx: device index
|
||||
@param type: device type
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
self.refresh_schedule()
|
||||
@@ -706,7 +721,6 @@ class XendDomain:
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
devs = dominfo.get_devices(type)
|
||||
#return range(0, len(devs))
|
||||
return devs
|
||||
|
||||
def domain_devtype_get(self, id, type, idx):
|
||||
|
||||
@@ -825,6 +825,30 @@ class XendDomainInfo:
|
||||
d = dev_handler(self, dev_config, dev_index, change=1)
|
||||
return d
|
||||
|
||||
def device_configure(self, dev_config, idx):
|
||||
"""Configure an existing device.
|
||||
|
||||
@param dev_config: device configuration
|
||||
@param idx: device index
|
||||
"""
|
||||
type = sxp.name(dev_config)
|
||||
dev = self.get_device_by_index(type, idx)
|
||||
if not dev:
|
||||
raise VmError('invalid device: %s %s' % (type, idx))
|
||||
new_config = dev.configure(dev_config, change=1)
|
||||
devs = self.devices.get(type)
|
||||
index = devs.index(dev)
|
||||
# Patch new config into device configs.
|
||||
dev_configs = self.config_devices(type)
|
||||
old_config = dev_configs[index]
|
||||
dev_configs[index] = new_config
|
||||
# Patch new config into vm config.
|
||||
new_full_config = ['device', new_config]
|
||||
old_full_config = ['device', old_config]
|
||||
old_index = self.config.index(old_full_config)
|
||||
self.config[old_index] = new_full_config
|
||||
return new_config
|
||||
|
||||
def device_destroy(self, type, idx):
|
||||
"""Destroy a device.
|
||||
|
||||
|
||||
@@ -164,6 +164,14 @@ class SrvDomain(SrvDir):
|
||||
val = fn(req.args, {'dom': self.dom.id})
|
||||
return val
|
||||
|
||||
def op_device_configure(self, op, req):
|
||||
fn = FormFn(self.xd.domain_device_configure,
|
||||
[['dom', 'str'],
|
||||
['config', 'sxpr'],
|
||||
['idx', 'str']])
|
||||
d = fn(req.args, {'dom': self.dom.id})
|
||||
return d
|
||||
|
||||
def op_vifs(self, op, req):
|
||||
devs = self.xd.domain_vif_ls(self.dom.id)
|
||||
return [ dev.sxpr() for dev in devs ]
|
||||
|
||||
@@ -617,6 +617,9 @@ class Dev:
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def configure(self, config, change=0):
|
||||
raise NotImplementedError()
|
||||
|
||||
class SplitDev(Dev):
|
||||
|
||||
def __init__(self, idx, controller):
|
||||
|
||||
@@ -104,31 +104,82 @@ class NetDev(controller.SplitDev):
|
||||
self.evtchn = None
|
||||
self.configure(config)
|
||||
|
||||
def configure(self, config):
|
||||
def _get_config_mac(self, config):
|
||||
vmac = sxp.child_value(config, 'mac')
|
||||
if not vmac: return None
|
||||
mac = [ int(x, 16) for x in vmac.split(':') ]
|
||||
if len(mac) != 6: raise XendError("invalid mac")
|
||||
return mac
|
||||
|
||||
def _get_config_ipaddr(self, config):
|
||||
ips = sxp.children(config, elt='ip')
|
||||
if ips:
|
||||
val = []
|
||||
for ipaddr in ips:
|
||||
val.append(sxp.child0(ipaddr))
|
||||
else:
|
||||
val = None
|
||||
return val
|
||||
|
||||
def configure(self, config, change=0):
|
||||
if change:
|
||||
return self.reconfigure(config)
|
||||
self.config = config
|
||||
self.mac = None
|
||||
self.bridge = None
|
||||
self.script = None
|
||||
self.ipaddr = []
|
||||
|
||||
vmac = sxp.child_value(config, 'mac')
|
||||
if not vmac: raise XendError("invalid mac")
|
||||
mac = [ int(x, 16) for x in vmac.split(':') ]
|
||||
if len(mac) != 6: raise XendError("invalid mac")
|
||||
self.mac = mac
|
||||
|
||||
mac = self._get_config_mac(config)
|
||||
if mac is None:
|
||||
raise XendError("invalid mac")
|
||||
self.mac = mac
|
||||
self.bridge = sxp.child_value(config, 'bridge')
|
||||
self.script = sxp.child_value(config, 'script')
|
||||
|
||||
ipaddrs = sxp.children(config, elt='ip')
|
||||
for ipaddr in ipaddrs:
|
||||
self.ipaddr.append(sxp.child0(ipaddr))
|
||||
self.ipaddr = self._get_config_ipaddr(config) or []
|
||||
|
||||
try:
|
||||
self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
|
||||
except:
|
||||
raise XendError('invalid backend domain')
|
||||
|
||||
def reconfigure(self, config):
|
||||
"""Reconfigure the interface with new values.
|
||||
Not all configuration parameters can be changed:
|
||||
bridge, script and ip addresses can,
|
||||
backend and mac cannot.
|
||||
|
||||
To leave a parameter unchanged, omit it from the changes.
|
||||
|
||||
@param config configuration changes
|
||||
@return updated interface configuration
|
||||
@raise XendError on errors
|
||||
"""
|
||||
changes = {}
|
||||
mac = self._get_config_mac(config)
|
||||
bridge = sxp.child_value(config, 'bridge')
|
||||
script = sxp.child_value(config, 'script')
|
||||
ipaddr = self._get_config_ipaddr(config)
|
||||
backendDomain = sxp.child_value(config, 'backend', '0')
|
||||
if (mac is not None) and (mac != self.mac):
|
||||
raise XendError("cannot change mac")
|
||||
if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
|
||||
raise XendError("cannot change backend")
|
||||
if (bridge is not None) and (bridge != self.bridge):
|
||||
changes['bridge'] = bridge
|
||||
if (script is not None) and (script != self.script):
|
||||
changes['script'] = script
|
||||
if (ipaddr is not None) and (ipaddr != self.ipaddr):
|
||||
changes['ipaddr'] = ipaddr
|
||||
|
||||
if changes:
|
||||
self.vifctl("down")
|
||||
for (k, v) in changes.items():
|
||||
setattr(self, k, v)
|
||||
self.config = sxp.merge(config, self.config)
|
||||
self.vifctl("up")
|
||||
return self.config
|
||||
|
||||
def sxpr(self):
|
||||
vif = str(self.vif)
|
||||
mac = self.get_mac()
|
||||
|
||||
@@ -41,7 +41,8 @@ __all__ = [
|
||||
"has_id",
|
||||
"with_id",
|
||||
"child_with_id",
|
||||
"elements",
|
||||
"elements",
|
||||
"merge",
|
||||
"to_string",
|
||||
"from_string",
|
||||
"all_from_string",
|
||||
@@ -595,6 +596,77 @@ def elements(sxpr, ctxt=None):
|
||||
yield v
|
||||
i += 1
|
||||
|
||||
def merge(s1, s2):
|
||||
"""Merge sxprs s1 and s2.
|
||||
Returns an sxpr containing all the fields from s1 and s2, with
|
||||
entries in s1 overriding s2. Recursively merges fields.
|
||||
|
||||
@param s1 sxpr
|
||||
@param s2 sxpr
|
||||
@return merged sxpr
|
||||
"""
|
||||
if s1 is None:
|
||||
val = s2
|
||||
elif s2 is None:
|
||||
val = s1
|
||||
elif elementp(s1):
|
||||
name1 = name(s1)
|
||||
(m1, v1) = child_map(s1)
|
||||
(m2, v2) = child_map(s2)
|
||||
val = [name1]
|
||||
for (k1, f1) in m1.items():
|
||||
merge_list(val, f1, m2.get(k1, []))
|
||||
for (k2, f2) in m2.items():
|
||||
if k2 in m1: continue
|
||||
val.extend(f2)
|
||||
val.extend(v1)
|
||||
else:
|
||||
val = s1
|
||||
return val
|
||||
|
||||
def merge_list(sxpr, l1, l2):
|
||||
"""Merge element lists l1 and l2 into sxpr.
|
||||
The lists l1 and l2 are all element with the same name.
|
||||
Values from l1 are merged with values in l2 and stored in sxpr.
|
||||
If one list is longer than the other the excess values are used
|
||||
as they are.
|
||||
|
||||
@param sxpr to merge into
|
||||
@param l1 sxpr list
|
||||
@param l2 sxpr list
|
||||
@return modified sxpr
|
||||
"""
|
||||
n1 = len(l1)
|
||||
n2 = len(l2)
|
||||
nmin = min(n1, n2)
|
||||
for i in range(0, nmin):
|
||||
sxpr.append(merge(l1[i], l2[i]))
|
||||
for i in range(nmin, n1):
|
||||
sxpr.append(l1[i])
|
||||
for i in range(nmin, n2):
|
||||
sxpr.append(l2[i])
|
||||
return sxpr
|
||||
|
||||
def child_map(sxpr):
|
||||
"""Get a dict of the elements in sxpr and a list of its values.
|
||||
The dict maps element name to the list of elements with that name,
|
||||
and the list is the non-element children.
|
||||
|
||||
@param sxpr
|
||||
@return (dict, list)
|
||||
"""
|
||||
m = {}
|
||||
v = []
|
||||
for x in children(sxpr):
|
||||
if elementp(x):
|
||||
n = name(x)
|
||||
l = m.get(n, [])
|
||||
l.append(x)
|
||||
m[n] = l
|
||||
else:
|
||||
v.append(x)
|
||||
return (m, v)
|
||||
|
||||
def to_string(sxpr):
|
||||
"""Convert an sxpr to a string.
|
||||
|
||||
|
||||