KVM on Linux

I've been using some shell scripts to start and stop KVM based virtual machines on my Gentoo Linux box. Maybe someone finds this stuff useful.

Installation

  1. Create a directory hierarchy containing subdirectories named bin, disks, lib, and tmp, e.g:
    $ mkdir -p ~/kvm/{bin,disks,lib,tmp}
    
  2. Download kvmlib.sh and put it into ~/kvm/lib/
  3. Download taputil, put it into ~/kvm/bin/, make it executable, and create /etc/sudoers.d/kvm (assuming that your user is member of the kvm group on your system):
    %kvm	ALL=(ALL) NOPASSWD: YOUR_HOME_DIRECTORY/kvm/bin/taputil
    
    Obsolete as of 2016-10-03: Create tap interfaces, i.e. if each of your 4 virtual machines gets 2 interfaces, then create tap00, tap01, tap02, tap03, tap10, tap11, tap12, and tap13. On Gentoo put something like this to /etc/conf.d/net (replace YOUR_USER_NAME with, well, your username):
    config_eno1="null"
    
    #interfaces="br0 tap00 tap01 tap02 tap03 br1 tap10 tap11 tap12 tap13"
    
    #bridge_br0="eno1 tap00 tap01 tap02 tap03"
    bridge_br0="eno1"
    
    config_br0="192.168.0.10/24"
    routes_br0="default via 192.168.0.1"
    
    #depend_br0() {
    #	need net.eno1
    #	need net.tap00
    #	need net.tap01
    #	need net.tap02
    #	need net.tap03
    #}
    
    #bridge_br1="tap10 tap11 tap12 tap13"
    bridge_br1=""
    
    config_br1="null"
    
    #depend_br1() {
    #	need net.tap10
    #	need net.tap11
    #	need net.tap12
    #	need net.tap13
    #}
    
    tuntap_tap00="tap"
    tunctl_tap00="-u YOUR_USER_NAME"
    config_tap00="null"
    carrier_timeout_tap00=0
    bridge_add_tap00="br0"
    
    tuntap_tap01="tap"
    tunctl_tap01="-u YOUR_USER_NAME"
    config_tap01="null"
    carrier_timeout_tap01=0
    bridge_add_tap01="br0"
    
    tuntap_tap02="tap"
    tunctl_tap02="-u YOUR_USER_NAME"
    config_tap02="null"
    carrier_timeout_tap02=0
    bridge_add_tap02="br0"
    
    tuntap_tap03="tap"
    tunctl_tap03="-u YOUR_USER_NAME"
    config_tap03="null"
    carrier_timeout_tap03=0
    bridge_add_tap03="br0"
    
    tuntap_tap10="tap"
    tunctl_tap10="-u YOUR_USER_NAME"
    config_tap10="null"
    carrier_timeout_tap10=0
    bridge_add_tap10="br1"
    
    tuntap_tap11="tap"
    tunctl_tap11="-u YOUR_USER_NAME"
    config_tap11="null"
    carrier_timeout_tap11=0
    bridge_add_tap11="br1"
    
    tuntap_tap12="tap"
    tunctl_tap12="-u YOUR_USER_NAME"
    config_tap12="null"
    carrier_timeout_tap12=0
    bridge_add_tap12="br1"
    
    tuntap_tap13="tap"
    tunctl_tap13="-u YOUR_USER_NAME"
    config_tap13="null"
    carrier_timeout_tap13=0
    bridge_add_tap13="br1"
    
  4. Create a harddisk sparse image for your virtual machine, e.g. a 10 GB image (the trailing .raw is important):
    $ dd if=/dev/zero of=~/kvm/disks/some.host.name.raw bs=1 count=0 seek=10G
    
    Alternatively, download my shell script mkdisk, put it into ~/kvm/bin/, make it executable, and call
    $ ~/kvm/bin/mkdisk some.host.name 10
    
  5. For each virtual machine create a shell script named after the disk image. Put that shell script into ~/kvm/bin/, and it make executable if you want the virtual machine to be started when your host system boots. The filename of that script is important. A leading digit denotes its start/stop order and its VNC display number. A minimum script, e.g. ~/kvm/bin/0some.host.name.sh looks like this:
    #!/bin/sh
    
    . "`dirname "$0"`/../lib/kvmlib.sh"
    
    You may set any variable defined in kvmlib.sh which starts with VM_, e.g.:
    #!/bin/sh
    
    # give this vm 2 instead of 1 cpu
    VM_CPUS=2
    # give this vm 4 instead of 1 gig ram
    VM_MEM=4096
    
    . "`dirname "$0"`/../lib/kvmlib.sh"
    
  6. Start that virtual machine:
    $ ~/kvm/bin/0some.host.name.sh start
    
    To stop it:
    $ ~/kvm/bin/0some.host.name.sh stop
    
    Any additional parameters are directly passed to qemu-kvm:
    $ ~/kvm/bin/0some.host.name.sh start -cdrom /data/isos/freebsd.iso
    
  7. To connect to that virtual machine's console:
    $ vncviewer :0
    
  8. To change a cdrom:
    $ telnet localhost 6666
    (qemu) change ide1-cd0 /data/isos/netbsd.iso
    
    To eject it:
    (qemu) eject ide1-cd0
    
  9. To start and stop virtual machines during system boot or shutdown, save the following script as ~/kvm/bin/kvm:
    #!/bin/sh
    
    kvm_stop ()
    {
      local vm
      vm="$1"
      [ -z "$vm" ] && return
      [ ! -f "$vm" ] && return
      shift
      kvm_stop "$@"
      sh "./$vm" "stop" &
    }
    
    myself=`readlink "$0"`
    if [ -z "$myself" ]; then
      myself="$0"
    fi
    
    cd "`dirname "$myself"`/../bin" || exit 1
    
    action="$1"
    
    case "$action" in
      start|stop)
        ;;
      *)
        action="${0##*.}"
        ;;
    esac
    
    case "$action" in
      start)
        for vm in *.sh; do
          [ -x "$vm" ] && "./$vm" "$action" &
        done
        ;;
      stop)
        kvm_stop *.sh
        ;;
      *)
        echo "usage: $0 <start | stop>"
        exit 1
        ;;
    esac
    
    wait
    
    Then symlink the above script as /etc/local.d/kvm.start and /etc/local.d/kvm.stop. That way, any running virtual machine will be shut down when your host system reboots.
  10. If your virtual machine experiences problems with IPv6 or multicast, then disable multicast snooping on all bridge interfaces, e.g. either add the following line to /etc/udev/rules.d/99-local.rules:
    SUBSYSTEM=="net",ACTION=="add",KERNEL=="br*",ATTR{bridge/multicast_snooping}="0"
    
    and do a udevadm trigger (or reboot your host). Or create /etc/local.d/nobrsnoop.start (don't forget to make it executable):
    #!/bin/sh
    for f in /sys/class/net/*/bridge/multicast_snooping; do
      [ -f "$f" ] && echo 0 > "$f"
    done
    
    Then run it once or reboot your host.

Files

kvmlib.sh

taputil