debuggers.hg

view tools/python/xen/xm/create.py @ 3501:3ced9b0f4dab

bitkeeper revision 1.1159.212.23 (41ee5e8fnbA6nB8wOl_As73BmvhklQ)

Support for USB virtualisation. Adds the USB frontend / backend, update build options,
make the control tools understand USB interfaces.

One extra file from vanilla Linux is imported (linux-2.4.28-xen-sparse/drivers/usb/hcd.c)
because small changes were required to make XenU domains build with a USB frontend. This
will not be required for the revised host controller infrastructure in Linux 2.6.

To use this, set "usb = " a list of USB ports in the domain config file. Ports are
specified as a path, e.g. '1' = the first USB port on the host, '1/2' is the second port
on the hub on the first host port, etc.

Should work for most mass storage and isochronous devices. May work for some HID devices
but these are not as intelligent and may have trouble supporting virtualisation.
author mwilli2@equilibrium.research
date Wed Jan 19 13:20:15 2005 +0000 (2005-01-19)
parents 3c69b6ca4021
children bb56e77896e7 ef59b38283a5
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
3 """Domain creation.
4 """
5 import random
6 import string
7 import sys
9 from xen.xend import sxp
10 from xen.xend import PrettyPrint
11 from xen.xend.XendClient import server, XendError
13 from xen.util import console_client
15 from xen.xm.opts import *
17 gopts = Opts(use="""[options] [vars]
19 Create a domain.
21 Domain creation parameters can be set by command-line switches, from
22 a python configuration script or an SXP config file. See documentation
23 for --defconfig, --config. Configuration variables can be set using
24 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
26 """)
28 gopts.opt('help', short='h',
29 fn=set_true, default=0,
30 use="Print this help.")
32 gopts.opt('help_config',
33 fn=set_true, default=0,
34 use="Print help for the configuration script.")
36 gopts.opt('quiet', short='q',
37 fn=set_true, default=0,
38 use="Quiet.")
40 gopts.opt('path', val='PATH',
41 fn=set_value, default='.:/etc/xen',
42 use="""Search path for configuration scripts.
43 The value of PATH is a colon-separated directory list.""")
45 gopts.opt('defconfig', short='f', val='FILE',
46 fn=set_value, default='xmdefconfig',
47 use="""Use the given Python configuration script.
48 The configuration script is loaded after arguments have been processed.
49 Each command-line option sets a configuration variable named after
50 its long option name, and these variables are placed in the
51 environment of the script before it is loaded.
52 Variables for options that may be repeated have list values.
53 Other variables can be set using VAR=VAL on the command line.
55 After the script is loaded, option values that were not set on the
56 command line are replaced by the values set in the script.""")
58 gopts.default('defconfig')
60 gopts.opt('config', short='F', val='FILE',
61 fn=set_value, default=None,
62 use="""Domain configuration to use (SXP).
63 SXP is the underlying configuration format used by Xen.
64 SXP configurations can be hand-written or generated from Python configuration
65 scripts, using the -n (dryrun) option to print the configuration.""")
67 gopts.opt('load', short='L', val='FILE',
68 fn=set_value, default=None,
69 use='Domain saved state to load.')
71 gopts.opt('dryrun', short='n',
72 fn=set_true, default=0,
73 use="""Dry run - print the configuration but don't create the domain.
74 Loads the configuration script, creates the SXP configuration and prints it.""")
76 gopts.opt('paused', short='p',
77 fn=set_true, default=0,
78 use='Leave the domain paused after it is created.')
80 gopts.opt('console_autoconnect', short='c',
81 fn=set_true, default=0,
82 use="Connect to the console after the domain is created.")
84 gopts.var('name', val='NAME',
85 fn=set_value, default=None,
86 use="Domain name. Must be unique.")
88 gopts.var('kernel', val='FILE',
89 fn=set_value, default=None,
90 use="Path to kernel image.")
92 gopts.var('ramdisk', val='FILE',
93 fn=set_value, default='',
94 use="Path to ramdisk.")
96 gopts.var('builder', val='FUNCTION',
97 fn=set_value, default='linux',
98 use="Function to use to build the domain.")
100 gopts.var('memory', val='MEMORY',
101 fn=set_int, default=128,
102 use="Domain memory in MB.")
104 gopts.var('maxmem', val='MEMORY',
105 fn=set_int, default=None,
106 use="Maximum domain memory in MB.")
108 gopts.var('cpu', val='CPU',
109 fn=set_int, default=None,
110 use="CPU to run the domain on.")
112 gopts.var('vcpus', val='VCPUS',
113 fn=set_int, default=1,
114 use="# of Virtual CPUS in domain.")
116 gopts.var('cpu_weight', val='WEIGHT',
117 fn=set_float, default=None,
118 use="""Set the new domain's cpu weight.
119 WEIGHT is a float that controls the domain's share of the cpu.""")
121 gopts.var('console', val='PORT',
122 fn=set_int, default=None,
123 use="Console port to use. Default is 9600 + domain id.")
125 gopts.var('restart', val='onreboot|always|never',
126 fn=set_value, default=None,
127 use="""Whether the domain should be restarted on exit.
128 - onreboot: restart on exit with shutdown code reboot
129 - always: always restart on exit, ignore exit code
130 - never: never restart on exit, ignore exit code""")
132 gopts.var('blkif', val='no|yes',
133 fn=set_bool, default=0,
134 use="Make the domain a block device backend.")
136 gopts.var('netif', val='no|yes',
137 fn=set_bool, default=0,
138 use="Make the domain a network interface backend.")
140 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
141 fn=append_value, default=[],
142 use="""Add a disk device to a domain. The physical device is DEV,
143 which is exported to the domain as VDEV. The disk is read-only if MODE
144 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
145 backend driver domain to use for the disk.
146 The option may be repeated to add more than one disk.""")
148 gopts.var('pci', val='BUS,DEV,FUNC',
149 fn=append_value, default=[],
150 use="""Add a PCI device to a domain, using given params (in hex).
151 For example '-pci c0,02,1a'.
152 The option may be repeated to add more than one pci device.""")
154 gopts.var('usb', val='PATH',
155 fn=append_value, default=[],
156 use="""Add a physical USB port to a domain, as specified by the path
157 to that port. This option may be repeated to add more than one port.""")
159 gopts.var('ipaddr', val="IPADDR",
160 fn=append_value, default=[],
161 use="Add an IP address to the domain.")
163 gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM",
164 fn=append_value, default=[],
165 use="""Add a network interface with the given MAC address and bridge.
166 The vif is configured by calling the given configuration script.
167 If mac is not specified a random MAC address is used.
168 If bridge is not specified the default bridge is used.
169 If script is not specified the default script is used.
170 If backend is not specified the default backend driver domain is used.
171 This option may be repeated to add more than one vif.
172 Specifying vifs will increase the number of interfaces as needed.""")
174 gopts.var('nics', val="NUM",
175 fn=set_int, default=1,
176 use="""Set the number of network interfaces.
177 Use the vif option to define interface parameters, otherwise
178 defaults are used. Specifying vifs will increase the
179 number of interfaces as needed.""")
181 gopts.var('root', val='DEVICE',
182 fn=set_value, default='',
183 use="""Set the root= parameter on the kernel command line.
184 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
186 gopts.var('extra', val="ARGS",
187 fn=set_value, default='',
188 use="Set extra arguments to append to the kernel command line.")
190 gopts.var('ip', val='IPADDR',
191 fn=set_value, default='',
192 use="Set the kernel IP interface address.")
194 gopts.var('gateway', val="IPADDR",
195 fn=set_value, default='',
196 use="Set the kernel IP gateway.")
198 gopts.var('netmask', val="MASK",
199 fn=set_value, default = '',
200 use="Set the kernel IP netmask.")
202 gopts.var('hostname', val="NAME",
203 fn=set_value, default='',
204 use="Set the kernel IP hostname.")
206 gopts.var('interface', val="INTF",
207 fn=set_value, default="eth0",
208 use="Set the kernel IP interface name.")
210 gopts.var('dhcp', val="off|dhcp",
211 fn=set_value, default='off',
212 use="Set the kernel dhcp option.")
214 gopts.var('nfs_server', val="IPADDR",
215 fn=set_value, default=None,
216 use="Set the address of the NFS server for NFS root.")
218 gopts.var('nfs_root', val="PATH",
219 fn=set_value, default=None,
220 use="Set the path of the root NFS directory.")
222 gopts.var('memmap', val='FILE',
223 fn=set_value, default='',
224 use="Path to memap SXP file.")
226 gopts.var('device_model', val='FILE',
227 fn=set_value, default='',
228 use="Path to device model program.")
230 gopts.var('device_config', val='FILE',
231 fn=set_value, default='',
232 use="Path to device model configuration.")
234 def strip(pre, s):
235 """Strip prefix 'pre' if present.
236 """
237 if s.startswith(pre):
238 return s[len(pre):]
239 else:
240 return s
242 def configure_image(config, vals):
243 """Create the image config.
244 """
245 config_image = [ vals.builder ]
246 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
247 if vals.ramdisk:
248 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
249 if vals.cmdline_ip:
250 cmdline_ip = strip('ip=', vals.cmdline_ip)
251 config_image.append(['ip', cmdline_ip])
252 if vals.root:
253 cmdline_root = strip('root=', vals.root)
254 config_image.append(['root', cmdline_root])
255 if vals.extra:
256 config_image.append(['args', vals.extra])
257 if vals.vcpus:
258 config_image.append(['vcpus', vals.vcpus])
259 config.append(['image', config_image ])
262 def configure_disks(config_devs, vals):
263 """Create the config for disks (virtual block devices).
264 """
265 for (uname, dev, mode, backend) in vals.disk:
266 config_vbd = ['vbd',
267 ['uname', uname],
268 ['dev', dev ],
269 ['mode', mode ] ]
270 if backend:
271 config_vbd.append(['backend', backend])
272 config_devs.append(['device', config_vbd])
274 def configure_pci(config_devs, vals):
275 """Create the config for pci devices.
276 """
277 for (bus, dev, func) in vals.pci:
278 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
279 config_devs.append(['device', config_pci])
281 def configure_usb(config_devs, vals):
282 for path in vals.usb:
283 config_usb = ['usb', ['path', path]]
284 config_devs.append(['device', config_usb])
286 def randomMAC():
287 """Generate a random MAC address.
289 Uses OUI (Organizationally Unique Identifier) AA:00:00, an
290 unassigned one that used to belong to DEC. The OUI list is
291 available at 'standards.ieee.org'.
293 The remaining 3 fields are random, with the first bit of the first
294 random field set 0.
296 @return: MAC address string
297 """
298 random.seed()
299 mac = [ 0xaa, 0x00, 0x00,
300 random.randint(0x00, 0x7f),
301 random.randint(0x00, 0xff),
302 random.randint(0x00, 0xff) ]
303 return ':'.join(map(lambda x: "%02x" % x, mac))
305 def configure_vifs(config_devs, vals):
306 """Create the config for virtual network interfaces.
307 """
308 vifs = vals.vif
309 vifs_n = max(vals.nics, len(vifs))
311 for idx in range(0, vifs_n):
312 if idx < len(vifs):
313 d = vifs[idx]
314 mac = d.get('mac')
315 if not mac:
316 mac = randomMAC()
317 bridge = d.get('bridge')
318 script = d.get('script')
319 backend = d.get('backend')
320 ip = d.get('ip')
321 else:
322 mac = randomMAC()
323 bridge = None
324 script = None
325 backend = None
326 ip = None
327 config_vif = ['vif']
328 config_vif.append(['mac', mac])
329 if bridge:
330 config_vif.append(['bridge', bridge])
331 if script:
332 config_vif.append(['script', script])
333 if backend:
334 config_vif.append(['backend', backend])
335 if ip:
336 config_vif.append(['ip', ip])
337 config_devs.append(['device', config_vif])
339 def configure_vfr(config, vals):
340 if not vals.ipaddr: return
341 config_vfr = ['vfr']
342 idx = 0 # No way of saying which IP is for which vif?
343 for ip in vals.ipaddr:
344 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
345 config.append(config_vfr)
347 def configure_vmx(config_devs, vals):
348 """Create the config for VMX devices.
349 """
350 memmap = vals.memmap
351 device_model = vals.device_model
352 device_config = vals.device_config
353 config_devs.append(['memmap', memmap])
354 config_devs.append(['device_model', device_model])
355 config_devs.append(['device_config', device_config])
357 def make_config(vals):
358 """Create the domain configuration.
359 """
361 config = ['vm',
362 ['name', vals.name ],
363 ['memory', vals.memory ]]
364 if vals.maxmem:
365 config.append(['maxmem', vals.maxmem])
366 if vals.cpu is not None:
367 config.append(['cpu', vals.cpu])
368 if vals.cpu_weight is not None:
369 config.append(['cpu_weight', vals.cpu_weight])
370 if vals.blkif:
371 config.append(['backend', ['blkif']])
372 if vals.netif:
373 config.append(['backend', ['netif']])
374 if vals.restart:
375 config.append(['restart', vals.restart])
376 if vals.console:
377 config.append(['console', vals.console])
379 configure_image(config, vals)
380 config_devs = []
381 configure_disks(config_devs, vals)
382 configure_pci(config_devs, vals)
383 configure_vifs(config_devs, vals)
384 configure_usb(config_devs, vals)
385 configure_vmx(config_devs, vals)
386 config += config_devs
387 return config
389 def preprocess_disk(opts, vals):
390 if not vals.disk: return
391 disk = []
392 for v in vals.disk:
393 d = v.split(',')
394 n = len(d)
395 if n == 3:
396 d.append(None)
397 elif n == 4:
398 pass
399 else:
400 opts.err('Invalid disk specifier: ' + v)
401 disk.append(d)
402 vals.disk = disk
404 def preprocess_pci(opts, vals):
405 if not vals.pci: return
406 pci = []
407 for v in vals.pci:
408 d = v.split(',')
409 if len(d) != 3:
410 opts.err('Invalid pci specifier: ' + v)
411 # Components are in hex: add hex specifier.
412 hexd = map(lambda v: '0x'+v, d)
413 pci.append(hexd)
414 vals.pci = pci
416 def preprocess_vifs(opts, vals):
417 if not vals.vif: return
418 vifs = []
419 for vif in vals.vif:
420 d = {}
421 a = vif.split(',')
422 for b in a:
423 (k, v) = b.strip().split('=', 1)
424 k = k.strip()
425 v = v.strip()
426 if k not in ['mac', 'bridge', 'script', 'backend', 'ip']:
427 opts.err('Invalid vif specifier: ' + vif)
428 d[k] = v
429 vifs.append(d)
430 vals.vif = vifs
432 def preprocess_ip(opts, vals):
433 if vals.ip or vals.dhcp != 'off':
434 dummy_nfs_server = '1.2.3.4'
435 ip = (vals.ip
436 + ':' + (vals.nfs_server or dummy_nfs_server)
437 + ':' + vals.gateway
438 + ':' + vals.netmask
439 + ':' + vals.hostname
440 + ':' + vals.interface
441 + ':' + vals.dhcp)
442 else:
443 ip = ''
444 vals.cmdline_ip = ip
446 def preprocess_nfs(opts, vals):
447 if not vals.nfs_root: return
448 if not vals.nfs_server:
449 opts.err('Must set nfs root and nfs server')
450 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
451 vals.extra = nfs + ' ' + vals.extra
453 def preprocess(opts, vals):
454 if not vals.kernel:
455 opts.err("No kernel specified")
456 preprocess_disk(opts, vals)
457 preprocess_pci(opts, vals)
458 preprocess_vifs(opts, vals)
459 preprocess_ip(opts, vals)
460 preprocess_nfs(opts, vals)
462 def make_domain(opts, config):
463 """Create, build and start a domain.
465 @param opts: options
466 @param config: configuration
467 @return: domain id, console port
468 @rtype: (int, int)
469 """
471 try:
472 if opts.vals.load:
473 filename = os.path.abspath(opts.vals.load)
474 dominfo = server.xend_domain_restore(filename, config)
475 else:
476 dominfo = server.xend_domain_create(config)
477 except XendError, ex:
478 opts.err(str(ex))
480 dom = sxp.child_value(dominfo, 'name')
481 console_info = sxp.child(dominfo, 'console')
482 if console_info:
483 console_port = int(sxp.child_value(console_info, 'console_port'))
484 else:
485 console_port = None
487 if not opts.vals.paused:
488 if server.xend_domain_unpause(dom) < 0:
489 server.xend_domain_destroy(dom)
490 opts.err("Failed to unpause domain %s" % dom)
491 opts.info("Started domain %s, console on port %d"
492 % (dom, console_port))
493 return (dom, console_port)
495 def main(argv):
496 opts = gopts
497 args = opts.parse(argv)
498 if opts.vals.help:
499 opts.usage()
500 if opts.vals.help or opts.vals.help_config:
501 opts.load_defconfig(help=1)
502 if opts.vals.help or opts.vals.help_config:
503 return
504 # Process remaining args as config variables.
505 for arg in args:
506 if '=' in arg:
507 (var, val) = arg.strip().split('=', 1)
508 gopts.setvar(var.strip(), val.strip())
509 if opts.vals.config:
510 config = opts.vals.config
511 else:
512 opts.load_defconfig()
513 preprocess(opts, opts.vals)
514 if not opts.getopt('name') and opts.getopt('defconfig'):
515 opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
516 config = make_config(opts.vals)
517 if opts.vals.dryrun:
518 PrettyPrint.prettyprint(config)
519 else:
520 (dom, console) = make_domain(opts, config)
521 if opts.vals.console_autoconnect:
522 console_client.connect('localhost', console)
524 if __name__ == '__main__':
525 main(sys.argv)