Installing User Mode Linux on SuSE

James F. Carter <jimc@math.ucla.edu>, 2005-01-31

Starting in v9.2, SuSE includes a User Mode Linux kernel and utilities in their distro. However, the documentation is somewhat scanty. How do you make it useful?

My intention is to tell how to use SuSE UML as it is, warts and all. Several problems are discussed which could be worked around by rebuilding the UML kernel, which would be a good idea for an individual user on a home system. However, sometimes there are operational or political considerations which make it necessary or prudent to stick with the distro as-is. That's the focus of this document.

SuSE's UML will improve over time, and so where this document says certain features are inconvenient or broken, you should try again after upgrades and see if they've improved.

Version Information

These notes pertain to the SuSE Linux version 9.2 (Professional) packages with these build numbers (after online updates):

It is hard to determine exactly which version of User Mode Linux is on the SuSE 9.2 DVD, or which patches it has, since the patch archive is not in the source RPM. It is dated 2004-10-04, so patches issued up to August are most likely in the kernel. The host does have the SKAS3 patch; this is kernel 2.6.8 with SuSE hacks.

Useful Links

Reasons Why You Might Want User Mode Linux

Design Issues

Virtual CPUs don't multiply by magic; the total compute power of your machine is shared between the real instance and the various virtual machines. And each virtual machine needs a root and (often) a swap filesystem, which tend to be large.

For designing and for system administration generally, you should treat your UML machine the same as your real machines. In particular, before starting the UML installation you need to decide several items, which are the same as for a real machine and for which you'll use similar policies. More details on most of these are given further on.

Installing Software: Host and Guest

You need to install these RPMs. (*) indicates packages required by yast2-uml, which are checked for at the time of creating the UML instance and installed if needed. Knowing what I know now, I think the minimal installation is kernel-um (on both the host and the guest) and uml-utilities (host only).

First you need to create plain files in the host OS which will be the discs of the guest OS, and you need to populate these filesystems. SuSE provides a script (uml-install-suse) and a YaST2 module (yast2-uml) to assist the process, but I found that both approaches had problems. I found that the script was hard to customize, but its default behavior installed too many packages for my small UML system and overfilled the default filesystem (512 MB) by 40 MB. The YaST2 module wants to create a completely new user to run the UML as, and you have to create the root device yourself anyway. And its assumptions about how you are going to use the UML were not exactly aligned with mine. Both the script and the module were not willing to do the installation over; you had to manually find and remove all their work before trying again.

I hand-customized the uml-install-suse script, but reinventing the wheel like this was inefficient, particularly in analysing package dependencies. So I gave up that approach.

Instead, I used the Install into Directory YaST2 module, which first appeared in SuSE 9.2. Here are the steps:

Editing Configuration Files

After the installation, edit or replace important files in /etc and /root. If you have to do the job repeatedly (e.g. if you make mistakes), you will find it convenient to make a directory, let's call it preset/, with subdirectories etc and root which contain the files listed below. Then copy them all at once thusly:

(cd preset ; tar cf - .) | (cd /mnt ; tar xpf -)

Important files that I had to edit were:

etc/HOSTNAME
The machine needs a name from your own namespace, not the generic linux.site.
etc/fstab
Not provided in a directory installation; you need to create it. It needs at least the following entries. Sysfs is pre-mounted in /etc/init.d/boot and hence should not appear in fstab. If you're using hostfs (discussed with Discs), you will want it in fstab.
Device Mntpt Type Options Freq Pass
/dev/ubda / ext3 defaults 1 1
proc /proc proc defaults 0 0
devpts /dev/pts devpts defaults 0 0
/dev/ubdb swap swap defaults 0 0
Specify the filesystem type you actually made. About the ubd device names, see the discussion of these below among the kernel command line parameters. Omit the line for the swap file if you don't have one.
etc/hosts
Normally, copy from the host. It should include the fixed IP address of your UML machine, unless you use DHCP.
etc/passwd, shadow, group
Normally, copy these from the host, getting the current root password for your organization.
etc/init.d/boot.hotplug
If you're using udev you need to hack hotplug to be dependent on udev, i.e. to start after udev is initialized.
/etc/init.d/boot.udev
If you are using udev, you will thank yourself if you hack it so /sbin/udevstart is run synchronously, i.e. not as a background job, so devices are present when subsequent scripts need to open them.
etc/init.d/boot.clock
It uses hwclock to read the CMOS clock, and since there is no underlying hardware, it complains. You could jigger the script so it just exits, or add a harmless lie to etc/sysconfig/clock (q.v.)
etc/init.d/halt
The last step is to exec $command -d -f, where command = halt or reboot. At least with SuSE's UML kernel build, if you run UML as root, this will do the reboot(2) system call on the UML kernel, which will call the BIOS to halt or reboot the machine -- the host machine. Until this is fixed, if you might ever run UML as root, you should edit /etc/init.d/halt (the last command) to print a message and sleep forever. Then use the management console to give the "halt" command.
etc/inittab
The main issue is the gettys. YaST2-UML provides a startup script which assumes communication on a serial console /dev/ttyS0, and if you follow that convention, you need to start mingetty (not agetty) on that device: S0:12345:respawn:/sbin/mingetty --noclear ttyS0 xterm. Specify --noclear so the last page of console messages remain visible in the xterm. If you aren't using the virtual consoles you should also comment out their gettys; otherwise init will try to start a getty on each one and it will fail, producing a load spike and a swarm of error messages every five minutes. In short, adjust inittab to match the console and serial line arrangement that you are going to specify on the kernel command line.
etc/localtime
Symlink to the correct zone file in /usr/share/zoneinfo. Or copy from the host.
etc/nsswitch.conf
May or may not need modification. For example, if the host uses NIS but the guest isn't allowed to use it, that must be reflected in nsswitch.conf.
etc/profile.d/uml.sh
Lie about your kernel version. Insert a file in /etc/profile.d with the command export LD_ASSUME_KERNEL=2.4.21. With the default SuSE /etc/profile, it will be sourced when root logs in. If you use (t)csh on your UML, make an analogous uml.csh file that does setenv LD_ASSUME_KERNEL 2.4.21. The reason for this is discussed under Gotcha: Thread Local Storage.
etc/resolv.conf
Often you can just copy it from the host. In my setup there's a caching nameserver on the host, so I configured the guest to use it rather than figuring out the trans-net nameserver du jour.
etc/securetty
Very important if using the serial console: add ttyS0 so root can log in to it.
etc/ssh/ssh_config, sshd_config
If you've customized these (or other daemon configurations) on the host, most likely you will want to install the host versions on the guest too.
etc/ssh/ssh_host_rsa_key and friends (6 files)
If you're connecting to your guest by SSH you don't want its key changing randomly every time you revert or reinstall, so pre-generate your keys and copy them each time you reinstall. Look at /etc/init.d/sshd and imitate it, modifying the -f parameter of ssh-keygen (3 invocations) to deposit the keys in your preset directory. Of course if you have multiple UML instances, each one needs its own set of keys, and if you're using multiple COW files over a single root image, the root image must not have any keys in it, so the various machines can put their own keys in the individual COW files.
etc/sysconfig/clock
Append HOSTTYPE=s390. The IBM System/390 architecture also lacks a CMOS clock, and the whole boot.clock script is bypassed neatly.
etc/sysconfig/network/ifcfg-eth0 and routes
Once you have your UML running you can use YaST2 to configure the network card, except you will want to add by hand "LLADDR='FE:FD:C0:09:C8:C7" to set the MAC address. The convention on Ethertaps to produce a unique MAC address is to use FE:FD followed by the guest's IPv4 address with each octet represented in hex. For reversions and reinstallations, you can save yourself some work by saving and reinstalling these two files.
etc/udev/rules.d/25-my.rules, etc/udev/permissions.d/25-my.permissions
Copy from the host. This isn't a tutorial on udev, but I use rules that drastically limit how many useless devices are instantiated. Even so, device creation is a lot slower on UML than on the host. It takes 25 secs (on a 1 GHz Mobile Pentium 3) to create devices in the initrd and then 55 secs to create them again in the real system. Without the limitation it takes fully five minutes to create devices.
root/.ssh/authorized_keys, root/.ssh/known_hosts
Copy from the host, so root can get to the UML guest the same way it can get to other real machines on your network.
dev/root
This link does not appear by magic. Make it a symlink to /dev/ubda (ln -s ubda /mnt/dev/root); use whichever device you actually will have the root on.
var/adm/YaST/ProdDB/prod_00000001
Copy the current product file from the host or from another machine that has the same OS version as the guest. Old versions could still be there; get the one that corresponds to the guest's OS version. The product file is not installed in a directory installation and it's what tells the online update module what product is being updated.
Guest's network firewall
It needs to be configured. Since I use a special firewall, I can't list the filenames for common products here. If you keep your UML off the net at first, you could wait until your UML is booted the first time and then configure the firewall using the product's proper interface.
/etc/init.d/boot.d and rc3.d
You need to make symlinks so the daemons you want are started and the daemons you don't want are skipped. This does not happen automatically; only some services get started. In particular, the network is not started automatically. Use the corresponding directories on the host as a guide to what you need. One way to do this is:
chroot /mnt
insserv -d /etc/init.d/boot.proc # Etc, give full path
insserv -d /etc/init.d/network   # Do in approximate startup order
exit                             # To exit from chroot
/sbin/udev
If you are using udev, you will speed up booting greatly if you replace udev with this script. (You could rename /sbin/udev to udev.dynamic or something like that.)
#!/bin/ash
case $1 in 
    net | usb )
        :
        ;;
    * )
        export UDEV_NO_SLEEP=1
        export UDEV_NO_DEVD=1
        ;;
esac
exec /sbin/udev.static $*

Don't forget, unmount the filesystem now.

Additional Setup

Now the root filesystem is set up, but you also need to arrange for networking (if used), and you need to set up console access. These will be reflected in the kernel command line parameters, and there are several miscellaneous parameters that will be necessary.

Networking

A key decision on the network is whether you will have a fixed IP address, or whether you will have to use DHCP. If DHCP, you will need to create an Ethernet bridge on the host so the guest's broadcasts can reach the DHCP server. I bypassed this complication by using a fixed IP address. If you need bridging, see Rusty Russell's HOWTO for a good description.

There are several ways to handle networking. In the descriptions below it's assumed that you are configuring the UML's eth0, but you can use any eth number and you can have arbitrarily many differently configured ethernet interfaces. You will also have to configure your host's and guest's firewall; this is discussed briefly later. These are the currently supported networking transport types:

tuntap

Packets are injected directly to the host's packet bus. This is by far the simplest and the highest in performance. A forerunner of TUN/TAP in kernel 2.2.x was called Ethertap.

On the kernel command line you will specify eth0=tuntap,,,ipaddr, e.g. eth0=tuntap,,,192.168.1.1. The IP address is for the host side of the tap, and usually is the assigned IP address of the host, but if that is inconvenient, it works just as well with a random address, but not copying the IP address of the UML guest. The omitted parameters are the name of the tap device (you're letting UML obtain one) and its MAC address (some random number).

It relies on a setUID helper uml_net to set up the tap device. Note: for security reasons SuSE does not install it setUID; you need to do it yourself and add an entry to /etc/permissions.local to make sure the setUID bit stays set. On a public server, a hostile user can assign any IP address he wants so as to make his UML impersonate other machines such as your authentication server. If your security policy forbids such a possibility, root can preconfigure the tap device, in which case you would put on the kernel command line eth0=tuntap,tap0 (substituting the tap device that you got). See the HOWTO for details of how to pre-configure the tap device.

Another note: if you use udev, it has a compulsion to run the if-up (interface initialization) script on /dev/net/tun, even though it is not a configured (or configurable) interface, and it takes fully 12 seconds, so the helper will time out. So root should do this ahead of time, for example loading that module at boot. Add tun to the space-separated list in MODULES_LOADED_ON_BOOT in the host's /etc/sysconfig/kernel.

The tuntap transport works reliably provided you do these items:

Configuration issues: If the guest is going to communicate off-site, e.g. for DNS, NIS or web access, or for offering services, someone will need to configure the host to act as a router. /usr/bin/uml_net takes care of this and the proxy_arp item, but if you preconfigure the tap device you need to do these yourself:

echo 1 > /proc/sys/net/ipv4/ip_forward
If systems other than the host need to be able to originate connections to the guest, the easiest way is to turn on proxy ARP: if the tap device is tap0:
echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp
Then assign the guest a unique IP address on the same subnet as the host, and the host will attract guest packets to itself when outsiders send an ARP broadcast. But a networking purist would want you to assign the UML guest an IP address in a separate subnet, and to set up proper routes through the host on all machines needing access.

An alternative to proxy ARP is to use the masquerade feature of iptables, for connections originated by the guest, or DNAT for connections from outside to the host, which are to be handed off to the guest. In any case, the host's firewall will need to allow thru traffic (on selected ports that are actually important to your mission) from the guest to the outside world, and vice versa if you're offering net services, neither of which it would have needed to do before UML.

slirp

It uses a userspace helper, not setUID root, to masquerade IP packets from the UML as if they were coming from the host system. On the kernel command line specify eth0=slirp,,/usr/bin/slirp, giving the full path name of the userspace helper (or wrapper script). If you want to use all the features (see the HOWTO) you may need to write a simple wrapper script that execs the helper with the desired command line options. Unfortunately SuSE doesn't include the man page for slirp and so you'll have to read it from the web.

Firewall issues are limited to letting in the types of packets important to your mission, but since all packets are coming from and going to the slirp helper on the host, the firewall does not need to take into account the existence of the UML.

mcast (Multicast)

Use this to let multiple UMLs on one ethernet segment to talk to each other. But it can't communicate with machines not so configured: specifically, it can't talk to the host itself. It's sufficient if each UML has eth0=mcast on the kernel command line. See the HOWTO for additional possibilities.

For within-host communication, only a very aggressive firewall would even see the packets, but for transport between hosts the host firewall would have to be configured to let the multicast packets through.

Switch daemon

This is another way for multiple UMLs on one host to talk to each other. Performance is said to be better than with multicast, and you can optionally tie into a TUN/TAP device for offsite comunication (but if you do that, you might as well use TUN/TAP directly). See the HOWTO for details on the switch daemon. There are no firewall issues with the switch daemon.

Slip

Using the SLIP protocol into your UML is supported but is obsolete, being more trouble than it's worth.

pcap

Special for intrusion detection machines, its purpose is to monitor packet traffic on the host system. Firewall issues are the same as if the sniffer were used directly on the host, i.e. you need to let in the packets that you expect to sniff.

Consoles and Serial Lines

As with networking, you can have multiple virtual terminals (consoles) and serial lines on your UML, connected to the host by various transports. con1 is the device identifier for virtual terminal number one, generally accessible on the UML as /dev/tty1, and so on for any number. con without the number is used to configure all consoles except those explicitly listed. Similarly, ssl is the generic designator for serial lines, whereas ssl0 will refer to /dev/ttyS0. In the examples we'll be configuring con1. Remember that for most of these to be useful, you need a getty running on the guest's tty, normally configured in /etc/inittab, and if root is going to log in, the tty basename (e.g. ttyS0) must appear in /etc/securettys.

Unfortunately, in this kernel build the con (console tty) devices are broken. You will need to use serial lines (ssl) exclusively until it is fixed.

Here are the available transports:

con1=xterm

Xterm will be executed with the appropriate arguments to attach to the UML's console or line. It is assumed that the user executing UML can use X-Windows. This is by far the easiest way to handle the main console.

con1=port:<number>

(Example: con1=port:9000) If you telnet to that port of the host (even from off-site), you will be connected to the guest UML's console or serial line. For this to work, the telnet-server package must be installed on the guest, and you should not have a getty running on the guest's tty. There is no requirement that the network be configured on the guest. You're allowed to attach multiple devices to the same port, like all of them: ssl=port:9000. Each connection will get a separate telnet session and tty until all devices are in use, after which connections will hang. Remember that telnet is not encrypted and plain-text passwords will be visible if it is used across the net. Ssh is more secure.

con0=fd:0,fd:1

You can direct particular devices to the file descriptors of the host's UML process. The assignment shown here is present by default, and con0 is used as the main console unless overridden. For all transports you can list the input, comma, then the output device, but that's useful only for fd transport.

con1=null

The device is directed to /dev/null, i.e. output is thrown out and it blocks if you try to read it.

con1=none

The device disappears completely. With devfs or udev the device inode is not even created; with a conventional /dev the device cannot be opened. You should not configure a getty on a none device.

con1=pty or con1=pts

UML will allocate an available pseudo-tty (/dev/ttyxx in the first case, or /dev/pts/n in the second, depending on which the host is configured to support). The kernel messages at boot will announce which pseudo-tty goes with which console or serial line. You then attach to it with a terminal program such as minicom or kermit.

con1=tty:/dev/ttyn

UML will attach to the designated real tty. This is most useful when attaching to one of the host's virtual terminals (that doesn't already have a host's getty on it). You can connect to the slave (tty) end of a pty/tty pair provided a terminal program is already connected to the master.

My project involves a lot of use of YaST2 to create installation scripts. One way to run it is to slogin -X name_of_uml (as root), assuming you have installed the yast2-qt package and that you have set up openssh to allow root to get in. If you prefer to use a text console for reasons of security or UML disc space, the different console and serial line transports have more or less limitations. Let's discuss how to control YaST2 in text mode, using the help function on the start screen as an example. Its label has H highlighted as a hotkey, so various key combinations involving H will activate it.

For all transports, escape-H and F1 are recognized, or if all else fails, hit tab or shift-tab enought times until the label is highlighted and hit return. On the host console with gpm (mouse daemon) running, you can click on a label with the mouse, but as far as I can tell, none of the UML transports have access to the mouse. On the host console and when a UML serial line is attached to a host virtual console (e.g. ssl1=tty:/dev/tty8), alt-H will be recognized, but alt is useless for other transports; also for slogin without -X or a local xterm. (con1=tty could not be tested; probably it will also recognize alt.)

Discs on UML

The discs of UML are referred to as ubd (User Block Device) followed by a disc letter and possiby a partition number. On the kernel command line you would typically write ubda=root.img, designating the first disc and giving the name of the root image file, or ubdb=swap.img to put the swap image on the second disc. If you are doing copy on write, you list the COW file first, e.g. ubda=root.cow,root.img. In the guest you would mount /dev/ubda on the root.

In principle you can put your image on a real disc partition or a whole hard disc, but this is rarely done.

There is currently some confusion about the device names. Formerly ubd0 to ubd7 were preferred, but the driver now advertises ubda to ubdh, which will be the names created by udev. The kernel recognizes either name set on the command line, but uml_mconsole only recognizes the ones with numbers. The default SuSE /dev provides ubda through ubdd.

The kernel will complain that the block device has a foreign partition table, and will proceed to treat the whole file as a single partition. However, you can create multiple partitions on your disc, same as on a real one, after which you can mount /dev/udba1, /dev/udba2, etc. If you use the YaST2 partitioner (System category) from within the guest, it will signal the driver to re-read the partition table, something will create the device inodes (udev? yast?), yast will create the mount points you specify, add them to /etc/fstab, and mount the new partitions on them.

Note that even if you have udev, you will need to pre-create the /dev inodes for your root and swap devices, and the /dev/root symlink, since SuSE's /etc/init.d/boot.udev runs after swap is turned on and the root fsck occurs. (It's feasible to run it first thing if you mount a RAM-based filesystem over /dev, like devfs did, but SuSE doesn't get that aggressive.) udev will create inodes for only the devices listed on the kernel command line. If you do need to create the inodes by hand, the major number is 98 and the minor number is 16*disc number plus the partition number if any:

mknod /mnt/dev/ubda b 98 0
mknod /mnt/dev/ubda2 b 98 2
mknod /mnt/dev/ubdb b 98 16
etc.

If you append r to the device name, e.g. ubdar, the disc becomes readonly. If you append s, writing is synchronous, i.e. the file is opened with O_SYNC and the guest will block until the data is actually sent to the underlying hardware: taking a big performance hit for some protection if the host crashes. You specify r or s on the kernel command line only; everywhere else you give the unmodified device name.

Here is how to directly access one host directory on the guest. This happens as the user running UML. Although ls reports the owner and mode of files same as if run on the host, suggesting that root can write on lots of files, you will get permission denied.

UML kernel parameter
hostfs=/directory
If this isn't specified on the command line, the default directory is the host's root.
Mount command on guest
mount -t hostfs arbitrary_name /mountpoint
To mount a subdirectory
mount -t hostfs -o /subdir arbitrary_name /mountpoint
(the subdir is relative to the directory on the kernel command line.)
The same in the guest's /etc/fstab
arbitrary_name /mountpoint hostfs defaults 0 0
arbitrary_name /mountpoint hostfs /subdir 0 0

It is possible to make a hostfs directory the guest's root and boot from it. For details see the HOWTO.

Additional Kernel Parameters

In your kernel command line you will need some miscellaneous parameters:

umid=itsname

It's very helpful to give the UML guest a name, which you can use with the management console. The UML's hostname is easy to remember. If this parameter is missing, a default of random letters will be provided.

selinux=0

Unless you've configured it properly, you should make sure selinux (the high security feature) is turned off, at least on a SuSE kernel.

stderr=0

Set this to 1 to see all kernel messages on stderr immediately (for kernel debugging). But if this is your only console, init will fail to recognize the console as being a tty and will give nasty messages. It's supposed to be off by default, but evidently SuSE turned it on.

mem=256m

The amount of simulated physical memory on the guest, in bytes, but units of k or m may be appended.

It's recommended to stick the RAM image in a tmpfs filesystem. This is a ramdisc that can grow or shrink as needed and which the host can push off to its swap space, whereas if the RAM image is put on a file in /tmp, the host has a compulsion to keep the disc file up to date, which detracts from performance. /dev/shm (a directory, not a device, even though bogusly in /dev) is a good candidate on SuSE 9.2. To make this happen, export TMPDIR=/dev/shm when starting UML.

Tmpfs is bounded in size; the default is half of physical RAM. If the UML RAM image is bigger than this, you need to mount (or remount) /dev/shm with a bigger limit (in bytes): mount -t tmpfs -o size=268435456,mode=1777 tmpfs /dev/shm or the equivalent in fstab.

If the guest(s) use more memory than is on the host, the host's swap space will be used, same as with any other process, and performance will go way down. But if the memory is not actually used, there is no performance penalty. If the guest has too little memory for the processes it is running, it will use its own swap file (if provided), again with a performance penalty. Think about swap issues when allocating tasks to UMLs.

If UML needs over 256 MB ram, take the memory size in bytes and divide by 4096, rounding up. As root, echo that number (or more) into /proc/sys/vm/max_map_count, whose default is 65536 (2^16). This is a denial-of-service resistance feature, which unfortunately interacts badly with how UML manages memory. The map limit is per process, i.e. separate for each guest.

initrd=filename

Specifies the filename of a compressed initrd image. I was not able to boot without an initrd.

root=/dev/ubda

Which device has the root filesystem. The default is hardwired as /dev/ubda.

console=con1

Which device is the main console. The default is the first con device listed on the command line. You may put the console on a serial line. You may have several console= parameters to send console messages to multiple devices. It's common to say stderr=1 console=stderr in addition to your other console assignment, to get kernel messages on stderr of the UML kernel itself.

--help

To get the kernel to print all the command line parameters.

Gotcha: Thread Local Storage (TLS)

A multi-threaded process like UML needs someplace to put its writeable static data, separate for each thread. Different kernels have different styles of mapping this memory. The 2.6.x kernel allocates one of the memory management registers for this purpose. But the UML kernel has no access to the underlying hardware. Libc is able to fall back to older styles if necessary, but the decision is made per the kernel version, not on whether the kernel can actually get the required register. (This is a crock.)

Therefore, when you run UML on a 2.6 kernel it will start the boot process, abuse the TLS, and give itself a mysterious stop signal. To make the library fall back to a feasible TLS style, do this:

export LD_ASSUME_KERNEL=2.4.1
(SuSE uses 2.4.21 TLS style, which seems to be effective.)

Also, once you've logged in to UML you need to do the same thing; otherwise any system utilities that are multi-threaded will segfault: network utilities in particular. In the section on configuration files a suggestion was made to set this in a file in /etc/profile.d.

Executing Your UML Machine

At last we're ready to start the UML machine. Here is the script that I'm using (minus comments):

#!/bin/sh
export LD_ASSUME_KERNEL=2.4.1
export TMPDIR=/dev/shm
exec /boot/linux \
	umid=petra \
	selinux=0 \
	mem=256m \
	initrd=initrd.img \
	ubda=root.cow.img,root.img \
	ubdb=swap.img \
	eth0=tuntap,,FE:FD:C0:09:C8:C3,192.9.200.195 \
	stderr=1 \
	console=stderr \
	con=none \
	ssl=none \
	ssl0=xterm \
	console=ttyS0

You need to substitute your own values for several parameters: the umid (instance name), memory size, image filenames, and the tap's ether and IP addresses.

On my 1 GHz laptop, with this configuration, it writes boot messages on stderr, due to the kernel parameter of stderr=1, and within a second or two it starts an xterm as the main console which also shows the boot messages. (The advantage of stderr=1 is that you still see the boot messages if the xterm cannot be started.) Since I am using udev, it churns for about 25 secs creating devices for the initrd, and then takes almost 60 secs to create more devices in the real root. (The latter step takes about 300 secs if udev rules allow all registered devices to be created (550 totally useless pseudo-ttys). The initrd always uses udev, but if the main system doesn't use it, the latter delay will not happen.) If, however, you replace /sbin/udev as detailed previously, device creation in the real root takes five seconds flat.

Watch the kernel messages for signs of problems. If the console xterm fails to start, watch the system load; when it drops, the boot process is over and you may (or may not) be able to get in using slogin and/or the management console.

You can now log in on the console xterm (as any user with a password in the guest's /etc/shadow or network authentication), or you can use slogin to connect if you configured it. If the console driver were not broken and if you had a getty on tty0, you could also log in to stdin-stdout of the UML process itself. This document of course does not cover how to accomplish useful work on your UML machine: basically, treat it like a real machine.

The correct way to shut down UML is to do shutdown -h now or /sbin/halt or telinit 0 (all nearly equivalent), or to give the cad (control-alt-delete) command from the management console, which signals init to do the ctrlaltdel action, which on a SuSE system runs shutdown. All of these end with a UML kernel panic, which is disconcerting but is not really harmful if it happens after the discs have been unmounted. If you just kill it from the outside, it's like pulling the plug on a real machine: the disc will not be synced and data likely will be lost.

For UML there is no difference between reboot and halt; both kill the UML process. Basically the same is true for a real machine: the kernel terminates by jumping into the BIOS for the reboot.

UML catches a number of signals, but none of them terminate it gracefully. I tested SIGTERM, SIGINT and SIGUSR1 (didn't test USR2). All of them produce a UML kernel panic. With INT, UML just exits after the panic. With TERM it gets a segfault. With USR1 it spews random bytes on stderr before dying. I tested each signal only once, and the behaviors might vary randomly according to data in memory.

The Management Console

When UML starts up, it deposits in $HOME/.uml/$UMID (the latter being the value of the kernel parameter umid) a PID file and a socket. If you execute uml_mconsole $UMID you can give commands over this socket.

cad
Invokes the control-alt-delete action. By a roundabout route this shuts down the UML gracefully.
halt
Halts the UML immediately (without syncing discs), producing a UML kernel panic but no segfault or other antisocial behavior.
sysrq
Emulates the magic sysrq key on a real machine, e.g. to sync the discs, unmount everything, or reboot, except that the provided kernel lacks sysrq (unlike the SuSE kernel for the host).
config
Lets you display or alter device configurations, as if on the kernel command line.
help
Prints a one-page summary of all the commands.

Suggestions for Improvement

User Mode Linux
Udev and Kernel

I'm a firm believer in udev, which is why I'm putting it in my real and UML machines before my distro does, but the UML application apparently shows udev in its worst light. In SuSE 9.1 and 9.2 the initrd invariably uses udev to obtain an inode for the real root device, which in important cases may be on a RAID device that ought to be modular in a distro kernel.

SuSE Distro