Merge ~powersj/cloud-init:add-xkvm into cloud-init:master

Proposed by Joshua Powers
Status: Merged
Merged at revision: a4c1d578070145023ae88a9f79f8517e36b52559
Proposed branch: ~powersj/cloud-init:add-xkvm
Merge into: cloud-init:master
Diff against target: 670 lines (+664/-0)
1 file modified
tools/xkvm (+664/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
cloud-init Commiters Pending
Review via email: mp+330536@code.launchpad.net

Commit message

tools: Add xkvm script, wrapper around qemu-system

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:210024716c2173249539ff9847cbca36e89555c7
https://jenkins.ubuntu.com/server/job/cloud-init-ci/282/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/282/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) :

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/tools/xkvm b/tools/xkvm
2new file mode 100755
3index 0000000..a30ba91
4--- /dev/null
5+++ b/tools/xkvm
6@@ -0,0 +1,664 @@
7+#!/bin/bash
8+
9+set -f
10+
11+VERBOSITY=0
12+KVM_PID=""
13+DRY_RUN=false
14+TEMP_D=""
15+DEF_BRIDGE="virbr0"
16+TAPDEVS=( )
17+# OVS_CLEANUP gets populated with bridge:devname pairs used with ovs
18+OVS_CLEANUP=( )
19+MAC_PREFIX="52:54:00:12:34"
20+KVM="kvm"
21+declare -A KVM_DEVOPTS
22+
23+error() { echo "$@" 1>&2; }
24+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
25+
26+bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
27+randmac() {
28+ # return random mac addr within final 3 tokens
29+ local random=""
30+ random=$(printf "%02x:%02x:%02x" \
31+ "$((${RANDOM}%256))" "$((${RANDOM}%256))" "$((${RANDOM}%256))")
32+ padmac "$random"
33+}
34+
35+cleanup() {
36+ [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
37+ [ -z "${KVM_PID}" ] || kill "$KVM_PID"
38+ if [ ${#TAPDEVS[@]} -ne 0 ]; then
39+ local name item
40+ for item in "${TAPDEVS[@]}"; do
41+ [ "${item}" = "skip" ] && continue
42+ debug 1 "removing" "$item"
43+ name="${item%:*}"
44+ if $DRY_RUN; then
45+ error ip tuntap del mode tap "$name"
46+ else
47+ ip tuntap del mode tap "$name"
48+ fi
49+ [ $? -eq 0 ] || error "failed removal of $name"
50+ done
51+ if [ ${#OVS_CLEANUP[@]} -ne 0 ]; then
52+ # with linux bridges, there seems to be no harm in just deleting
53+ # the device (not detaching from the bridge). However, with
54+ # ovs, you have to remove them from the bridge, or later it
55+ # will refuse to add the same name.
56+ error "cleaning up ovs ports: ${OVS_CLEANUP[@]}"
57+ if ${DRY_RUN}; then
58+ error sudo "$0" tap-control ovs-cleanup "${OVS_CLEANUP[@]}"
59+ else
60+ sudo "$0" tap-control ovs-cleanup "${OVS_CLEANUP[@]}"
61+ fi
62+ fi
63+ fi
64+}
65+
66+debug() {
67+ local level=${1}; shift;
68+ [ "${level}" -gt "${VERBOSITY}" ] && return
69+ error "${@}"
70+}
71+
72+Usage() {
73+ cat <<EOF
74+Usage: ${0##*/} [ options ] -- kvm-args [ ... ]
75+
76+ run kvm with a tap interface.
77+
78+ options:
79+ -n | --netdev NETDEV netdev can be 'user' or a bridge.
80+ default is to bridge to $DEF_BRIDGE
81+ -d | --disk DISK.img attach DISK.img as a disk (via virtio)
82+ --dry-run only report what would be done
83+
84+ --uefi boot with efi
85+ --uefi-nvram=FILE boot with efi, using nvram settings in FILE
86+ if FILE not present, copy from defaults.
87+
88+ NETDEV:
89+ Above, 'NETDEV' is a comma delimited string
90+ The first field must be
91+ * bridge name: (br0 or virbr0): attach a device to this bridge
92+ * literal 'user': use qemu user networking
93+
94+ Additional fields are optional, and can be anything that is acceptable
95+ to kvm either as:
96+ * '-device virtio-net-pci' option (see 'kvm -device virtio-net-pci,?')
97+ * '-net [user|tap]' option
98+
99+ Example:
100+ * xkvm --netdev br0,macaddr=:05 -- -drive file=disk.img,if=virtio -curses
101+ attach a tap device to bridge 'br0' with mac address
102+ '${MAC_PREFIX}:05'
103+
104+ * xkvm --netdev user,mac=random --netdev br1,model=e1000,mac=auto -- -curses
105+ attach virtio user networking nic with random mac address
106+ attach tap device to br1 bridge as e1000 with unspecified mac
107+
108+ * xkvm --disk disk1.img
109+EOF
110+}
111+
112+isdevopt() {
113+ local model="$1" input="${2%%=*}"
114+ local out="" opt="" opts=()
115+ if [ -z "${KVM_DEVOPTS[$model]}" ]; then
116+ out=$($KVM -device "$model,?" 2>&1) &&
117+ out=$(echo "$out" | sed -e "s,[^.]*[.],," -e 's,=.*,,') &&
118+ KVM_DEVOPTS[$model]="$out" ||
119+ { error "bad device model $model?"; exit 1; }
120+ fi
121+ opts=( ${KVM_DEVOPTS[$model]} )
122+ for opt in "${opts[@]}"; do
123+ [ "$input" = "$opt" ] && return 0
124+ done
125+ return 1
126+}
127+
128+padmac() {
129+ # return a full mac, given a subset.
130+ # assume whatever is input is the last portion to be
131+ # returned, and fill it out with entries from MAC_PREFIX
132+ local mac="$1" num="$2" prefix="${3:-$MAC_PREFIX}" itoks="" ptoks=""
133+ # if input is empty set to :$num
134+ [ -n "$mac" ] || mac=$(printf "%02x" "$num") || return
135+ itoks=( ${mac//:/ } )
136+ ptoks=( ${prefix//:/ } )
137+ rtoks=( )
138+ for r in ${ptoks[@]:0:6-${#itoks[@]}} ${itoks[@]}; do
139+ rtoks[${#rtoks[@]}]="0x$r"
140+ done
141+ _RET=$(printf "%02x:%02x:%02x:%02x:%02x:%02x" "${rtoks[@]}")
142+}
143+
144+make_nics_Usage() {
145+ cat <<EOF
146+Usage: ${0##*/} tap-control make-nics [options] bridge [bridge [..]]
147+
148+ make a tap device on each of bridges requested
149+ outputs: 'tapname:type' for each input, or 'skip' if nothing needed.
150+
151+ type is one of 'brctl' or 'ovs'
152+EOF
153+}
154+
155+make_nics() {
156+ # takes input of list of bridges to create a tap device on
157+ # and echos either 'skip' or
158+ # <tapname>:<type> for each tap created
159+ # type is one of "ovs" or "brctl"
160+ local short_opts="v"
161+ local long_opts="--verbose"
162+ local getopt_out=""
163+ getopt_out=$(getopt --name "${0##*/} make-nics" \
164+ --options "${short_opts}" --long "${long_opts}" -- "$@") &&
165+ eval set -- "${getopt_out}" || { make_nics_Usage 1>&2; return 1; }
166+
167+ local cur="" next=""
168+ while [ $# -ne 0 ]; do
169+ cur=${1}; next=${2};
170+ case "$cur" in
171+ -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
172+ --) shift; break;;
173+ esac
174+ shift;
175+ done
176+
177+ [ $# -ne 0 ] || {
178+ make_nics_Usage 1>&2; error "must give bridge";
179+ return 1;
180+ }
181+
182+ local owner="" ovsbrs="" tap="" tapnum="0" brtype="" bridge=""
183+ [ "$(id -u)" = "0" ] || { error "must be root for make-nics"; return 1; }
184+ owner="${SUDO_USER:-root}"
185+ ovsbrs=""
186+ if command -v ovs-vsctl >/dev/null 2>&1; then
187+ out=$(ovs-vsctl list-br)
188+ out=$(echo "$out" | sed "s/\n/,/")
189+ ovsbrs=",$out,"
190+ fi
191+ for bridge in "$@"; do
192+ [ "$bridge" = "user" ] && echo skip && continue
193+ [ "${ovsbrs#*,${bridge},}" != "$ovsbrs" ] &&
194+ btype="ovs" || btype="brctl"
195+ tapnum=0;
196+ while [ -e /sys/class/net/tapvm$tapnum ]; do tapnum=$(($tapnum+1)); done
197+ tap="tapvm$tapnum"
198+ debug 1 "creating $tap:$btype on $bridge" 1>&2
199+ ip tuntap add mode tap user "$owner" "$tap" ||
200+ { error "failed to create tap '$tap' for '$owner'"; return 1; }
201+ ip link set "$tap" up 1>&2 || {
202+ error "failed to bring up $tap";
203+ ip tuntap del mode tap "$tap";
204+ return 1;
205+ }
206+ if [ "$btype" = "ovs" ]; then
207+ ovs-vsctl add-port "$bridge" "$tap" 1>&2 || {
208+ error "failed: ovs-vsctl add-port $bridge $tap";
209+ ovs-vsctl del-port "$bridge" "$tap"
210+ return 1;
211+ }
212+ else
213+ ip link set "$tap" master "$bridge" 1>&2 || {
214+ error "failed to add tap '$tap' to '$bridge'"
215+ ip tuntap del mode tap "$tap";
216+ return 1
217+ }
218+ fi
219+ echo "$tap:$btype"
220+ done
221+}
222+
223+ovs_cleanup() {
224+ [ "$(id -u)" = "0" ] ||
225+ { error "must be root for ovs-cleanup"; return 1; }
226+ local item="" errors=0
227+ # TODO: if get owner (SUDO_USERNAME) and if that isn't
228+ # the owner, then do not delete.
229+ for item in "$@"; do
230+ name=${item#*:}
231+ bridge=${item%:*}
232+ ovs-vsctl del-port "$bridge" "$name" || errors=$((errors+1))
233+ done
234+ return $errors
235+}
236+
237+quote_cmd() {
238+ local quote='"' x="" vline=""
239+ for x in "$@"; do
240+ if [ "${x#* }" != "${x}" ]; then
241+ if [ "${x#*$quote}" = "${x}" ]; then
242+ x="\"$x\""
243+ else
244+ x="'$x'"
245+ fi
246+ fi
247+ vline="${vline} $x"
248+ done
249+ echo "$vline"
250+}
251+
252+get_bios_opts() {
253+ # get_bios_opts(bios, uefi, nvram)
254+ # bios is a explicit bios to boot.
255+ # uefi is boolean indicating uefi
256+ # nvram is optional and indicates that ovmf vars should be copied
257+ # to that file if it does not exist. if it exists, use it.
258+ local bios="$1" uefi="${2:-false}" nvram="$3"
259+ local ovmf_dir="/usr/share/OVMF"
260+ local bios_opts="" pflash_common="if=pflash,format=raw"
261+ unset _RET
262+ _RET=( )
263+ if [ -n "$bios" ]; then
264+ _RET=( -drive "${pflash_common},file=$bios" )
265+ return 0
266+ elif ! $uefi; then
267+ return 0
268+ fi
269+
270+ # ovmf in older releases (14.04) shipped only a single file
271+ # /usr/share/ovmf/OVMF.fd
272+ # newer ovmf ships split files
273+ # /usr/share/OVMF/OVMF_CODE.fd
274+ # /usr/share/OVMF/OVMF_VARS.fd
275+ # with single file, pass only one file and read-write
276+ # with split, pass code as readonly and vars as read-write
277+ local joined="/usr/share/ovmf/OVMF.fd"
278+ local code="/usr/share/OVMF/OVMF_CODE.fd"
279+ local vars="/usr/share/OVMF/OVMF_VARS.fd"
280+ local split="" nvram_src=""
281+ if [ -e "$code" -o -e "$vars" ]; then
282+ split=true
283+ nvram_src="$vars"
284+ elif [ -e "$joined" ]; then
285+ split=false
286+ nvram_src="$joined"
287+ elif [ -n "$nvram" -a -e "$nvram" ]; then
288+ error "WARN: nvram given, but did not find expected ovmf files."
289+ error " assuming this is code and vars (OVMF.fd)"
290+ split=false
291+ else
292+ error "uefi support requires ovmf bios: apt-get install -qy ovmf"
293+ return 1
294+ fi
295+
296+ if [ -n "$nvram" ]; then
297+ if [ ! -f "$nvram" ]; then
298+ cp "$nvram_src" "$nvram" ||
299+ { error "failed copy $nvram_src to $nvram"; return 1; }
300+ debug 1 "copied $nvram_src to $nvram"
301+ fi
302+ else
303+ debug 1 "uefi without --uefi-nvram storage." \
304+ "nvram settings likely will not persist."
305+ nvram="${nvram_src}"
306+ fi
307+
308+ if [ ! -w "$nvram" ]; then
309+ debug 1 "nvram file ${nvram} is readonly"
310+ nvram_ro="readonly"
311+ fi
312+
313+ if $split; then
314+ # to ensure bootability firmware must be first, then variables
315+ _RET=( -drive "${pflash_common},file=$code,readonly" )
316+ fi
317+ _RET=( "${_RET[@]}"
318+ -drive "${pflash_common},file=$nvram${nvram_ro:+,${nvram_ro}}" )
319+}
320+
321+main() {
322+ local short_opts="hd:n:v"
323+ local long_opts="bios:,help,dowait,disk:,dry-run,kvm:,no-dowait,netdev:,uefi,uefi-nvram:,verbose"
324+ local getopt_out=""
325+ getopt_out=$(getopt --name "${0##*/}" \
326+ --options "${short_opts}" --long "${long_opts}" -- "$@") &&
327+ eval set -- "${getopt_out}" || { bad_Usage; return 1; }
328+
329+ local bridge="$DEF_BRIDGE" oifs="$IFS"
330+ local netdevs="" need_tap="" ret="" p="" i="" pt="" cur="" conn=""
331+ local kvm="" kvmcmd="" archopts=""
332+ local def_disk_driver=${DEF_DISK_DRIVER:-"virtio-blk"}
333+ local def_netmodel=${DEF_NETMODEL:-"virtio-net-pci"}
334+ local bios="" uefi=false uefi_nvram=""
335+
336+ archopts=( )
337+ kvmcmd=( )
338+ netdevs=( )
339+ addargs=( )
340+ diskdevs=( )
341+ diskargs=( )
342+
343+ # dowait: run qemu-system with a '&' and then 'wait' on the pid.
344+ # the reason to do this or not do this has to do with interactivity
345+ # if detached with &, then user input will not go to xkvm.
346+ # if *not* detached, then signal handling is blocked until
347+ # the foreground subprocess returns. which means we can't handle
348+ # a sigterm and kill the qemu-system process.
349+ # We default to dowait=false if input and output are a terminal
350+ local dowait=""
351+ [ -t 0 -a -t 1 ] && dowait=false || dowait=true
352+ while [ $# -ne 0 ]; do
353+ cur=${1}; next=${2};
354+ case "$cur" in
355+ -h|--help) Usage; exit 0;;
356+ -d|--disk)
357+ diskdevs[${#diskdevs[@]}]="$next"; shift;;
358+ --dry-run) DRY_RUN=true;;
359+ --kvm) kvm="$next"; shift;;
360+ -n|--netdev)
361+ netdevs[${#netdevs[@]}]=$next; shift;;
362+ -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
363+ --dowait) dowait=true;;
364+ --no-dowait) dowait=false;;
365+ --bios) bios="$next"; shift;;
366+ --uefi) uefi=true;;
367+ --uefi-nvram) uefi=true; uefi_nvram="$next"; shift;;
368+ --) shift; break;;
369+ esac
370+ shift;
371+ done
372+
373+ [ ${#netdevs[@]} -eq 0 ] && netdevs=( "${DEF_BRIDGE}" )
374+ pt=( "$@" )
375+
376+ local kvm_pkg="" virtio_scsi_bus="virtio-scsi-pci"
377+ [ -n "$kvm" ] && kvm_pkg="none"
378+ case $(uname -m) in
379+ i?86)
380+ [ -n "$kvm" ] ||
381+ { kvm="qemu-system-i386"; kvm_pkg="qemu-system-x86"; }
382+ ;;
383+ x86_64)
384+ [ -n "$kvm" ] ||
385+ { kvm="qemu-system-x86_64"; kvm_pkg="qemu-system-x86"; }
386+ ;;
387+ s390x)
388+ [ -n "$kvm" ] ||
389+ { kvm="qemu-system-s390x"; kvm_pkg="qemu-system-misc"; }
390+ def_netmodel=${DEF_NETMODEL:-"virtio-net-ccw"}
391+ virtio_scsi_bus="virtio-scsi-ccw"
392+ ;;
393+ ppc64*)
394+ [ -n "$kvm" ] ||
395+ { kvm="qemu-system-ppc64"; kvm_pkg="qemu-system-ppc"; }
396+ def_netmodel="virtio-net-pci"
397+ # virtio seems functional on in 14.10, but might want scsi here
398+ #def_diskif="scsi"
399+ archopts=( "${archopts[@]}" -machine pseries,usb=off )
400+ archopts=( "${archopts[@]}" -device spapr-vscsi )
401+ ;;
402+ *) kvm=qemu-system-$(uname -m);;
403+ esac
404+ KVM="$kvm"
405+ kvmcmd=( $kvm -enable-kvm )
406+
407+ local bios_opts=""
408+ if [ -n "$bios" ] && $uefi; then
409+ error "--uefi (or --uefi-nvram) is incompatible with --bios"
410+ return 1
411+ fi
412+ get_bios_opts "$bios" "$uefi" "$uefi_nvram" ||
413+ { error "failed to get bios opts"; return 1; }
414+ bios_opts=( "${_RET[@]}" )
415+
416+ local out="" fmt="" bus="" unit="" index="" serial="" driver="" devopts=""
417+ local busorindex="" driveopts="" cur="" val="" file=""
418+ for((i=0;i<${#diskdevs[@]};i++)); do
419+ cur=${diskdevs[$i]}
420+ IFS=","; set -- $cur; IFS="$oifs"
421+ driver=""
422+ id=$(printf "disk%02d" "$i")
423+ file=""
424+ fmt=""
425+ bus=""
426+ unit=""
427+ index=""
428+ serial=""
429+ for tok in "$@"; do
430+ [ "${tok#*=}" = "${tok}" -a -f "${tok}" -a -z "$file" ] && file="$tok"
431+ val=${tok#*=}
432+ case "$tok" in
433+ driver=*) driver=$val;;
434+ if=virtio) driver=virtio-blk;;
435+ if=scsi) driver=scsi-hd;;
436+ if=pflash) driver=;;
437+ if=sd|if=mtd|floppy) fail "do not know what to do with $tok on $cur";;
438+ id=*) id=$val;;
439+ file=*) file=$val;;
440+ fmt=*|format=*) fmt=$val;;
441+ serial=*) serial=$val;;
442+ bus=*) bus=$val;;
443+ unit=*) unit=$val;;
444+ index=*) index=$val;;
445+ esac
446+ done
447+ [ -z "$file" ] && fail "did not read a file from $cur"
448+ if [ -f "$file" -a -z "$fmt" ]; then
449+ out=$(LANG=C qemu-img info "$file") &&
450+ fmt=$(echo "$out" | awk '$0 ~ /^file format:/ { print $3 }') ||
451+ { error "failed to determine format of $file"; return 1; }
452+ else
453+ fmt=raw
454+ fi
455+ if [ -z "$driver" ]; then
456+ driver="$def_disk_driver"
457+ fi
458+ if [ -z "$serial" ]; then
459+ serial="${file##*/}"
460+ fi
461+
462+ # make sure we add either bus= or index=
463+ if [ -n "$bus" -o "$unit" ] && [ -n "$index" ]; then
464+ fail "bus and index cant be specified together: $cur"
465+ elif [ -z "$bus" -a -z "$unit" -a -z "$index" ]; then
466+ index=$i
467+ elif [ -n "$bus" -a -z "$unit" ]; then
468+ unit=$i
469+ fi
470+
471+ busorindex="${bus:+bus=$bus,unit=$unit}${index:+index=${index}}"
472+ diskopts="file=${file},id=$id,if=none,format=$fmt,$busorindex"
473+ devopts="$driver,drive=$id${serial:+,serial=${serial}}"
474+ for tok in "$@"; do
475+ case "$tok" in
476+ id=*|if=*|driver=*|$file|file=*) continue;;
477+ fmt=*|format=*) continue;;
478+ serial=*|bus=*|unit=*|index=*) continue;;
479+ esac
480+ isdevopt "$driver" "$tok" && devopts="${devopts},$tok" ||
481+ diskopts="${diskopts},${tok}"
482+ done
483+
484+ diskargs=( "${diskargs[@]}" -drive "$diskopts" -device "$devopts" )
485+ done
486+
487+ local mnics_vflag=""
488+ for((i=0;i<${VERBOSITY}-1;i++)); do mnics_vflag="${mnics_vflag}v"; done
489+ [ -n "$mnics_vflag" ] && mnics_vflag="-${mnics_vflag}"
490+
491+ # now go through and split out options
492+ # -device virtio-net-pci,netdev=virtnet0,mac=52:54:31:15:63:02
493+ # -netdev type=tap,id=virtnet0,vhost=on,script=/etc/kvm/kvm-ifup.br0,downscript=no
494+ local netopts="" devopts="" id="" need_taps=0 model=""
495+ local device_args netdev_args
496+ device_args=( )
497+ netdev_args=( )
498+ connections=( )
499+ for((i=0;i<${#netdevs[@]};i++)); do
500+ id=$(printf "net%02d" "$i")
501+ netopts="";
502+ devopts=""
503+ # mac=auto is 'unspecified' (let qemu assign one)
504+ mac="auto"
505+ #vhost="off"
506+
507+ IFS=","; set -- ${netdevs[$i]}; IFS="$oifs"
508+ bridge=$1; shift;
509+ if [ "$bridge" = "user" ]; then
510+ netopts="type=user"
511+ ntype="user"
512+ connections[$i]="user"
513+ else
514+ need_taps=1
515+ ntype="tap"
516+ netopts="type=tap"
517+ connections[$i]="$bridge"
518+ fi
519+ netopts="${netopts},id=$id"
520+ [ "$ntype" = "tap" ] && netopts="${netopts},script=no,downscript=no"
521+
522+ model="${def_netmodel}"
523+ for tok in "$@"; do
524+ [ "${tok#model=}" = "${tok}" ] && continue
525+ case "${tok#model=}" in
526+ virtio) model=virtio-net-pci;;
527+ *) model=${tok#model=};;
528+ esac
529+ done
530+
531+ for tok in "$@"; do
532+ case "$tok" in
533+ mac=*) mac="${tok#mac=}"; continue;;
534+ macaddr=*) mac=${tok#macaddr=}; continue;;
535+ model=*) continue;;
536+ esac
537+
538+ isdevopt "$model" "$tok" && devopts="${devopts},$tok" ||
539+ netopts="${netopts},${tok}"
540+ done
541+ devopts=${devopts#,}
542+ netopts=${netopts#,}
543+
544+ if [ "$mac" != "auto" ]; then
545+ [ "$mac" = "random" ] && randmac && mac="$_RET"
546+ padmac "$mac" "$i"
547+ devopts="${devopts:+${devopts},}mac=$_RET"
548+ fi
549+ devopts="$model,netdev=$id${devopts:+,${devopts}}"
550+ #netopts="${netopts},vhost=${vhost}"
551+
552+ device_args[$i]="$devopts"
553+ netdev_args[$i]="$netopts"
554+ done
555+
556+ trap cleanup EXIT
557+
558+ reqs=( "$kvm" )
559+ pkgs=( "$kvm_pkg" )
560+ for((i=0;i<${#reqs[@]};i++)); do
561+ req=${reqs[$i]}
562+ pkg=${pkgs[$i]}
563+ [ "$pkg" = "none" ] && continue
564+ command -v "$req" >/dev/null || {
565+ missing="${missing:+${missing} }${req}"
566+ missing_pkgs="${missing_pkgs:+${missing_pkgs} }$pkg"
567+ }
568+ done
569+ if [ -n "$missing" ]; then
570+ local reply cmd=""
571+ cmd=( sudo apt-get --quiet install ${missing_pkgs} )
572+ error "missing prereqs: $missing";
573+ error "install them now with the following?: ${cmd[*]}"
574+ read reply && [ "$reply" = "y" -o "$reply" = "Y" ] ||
575+ { error "run: apt-get install ${missing_pkgs}"; return 1; }
576+ "${cmd[@]}" || { error "failed to install packages"; return 1; }
577+ fi
578+
579+ if [ $need_taps -ne 0 ]; then
580+ local missing="" missing_pkgs="" reqs="" req="" pkgs="" pkg=""
581+ for i in "${connections[@]}"; do
582+ [ "$i" = "user" -o -e "/sys/class/net/$i" ] ||
583+ missing="${missing} $i"
584+ done
585+ [ -z "$missing" ] || {
586+ error "cannot create connection on: ${missing# }."
587+ error "bridges do not exist.";
588+ return 1;
589+ }
590+ error "creating tap devices: ${connections[*]}"
591+ if $DRY_RUN; then
592+ error "sudo $0 tap-control make-nics" \
593+ $mnics_vflag "${connections[@]}"
594+ taps=""
595+ for((i=0;i<${#connections[@]};i++)); do
596+ if [ "${connections[$i]}" = "user" ]; then
597+ taps="${taps} skip"
598+ else
599+ taps="${taps} dryruntap$i:brctl"
600+ fi
601+ done
602+ else
603+ taps=$(sudo "$0" tap-control make-nics \
604+ ${mnics_vflag} "${connections[@]}") ||
605+ { error "$failed to make-nics ${connections[*]}"; return 1; }
606+ fi
607+ TAPDEVS=( ${taps} )
608+ for((i=0;i<${#TAPDEVS[@]};i++)); do
609+ cur=${TAPDEVS[$i]}
610+ [ "${cur#*:}" = "ovs" ] || continue
611+ conn=${connections[$i]}
612+ OVS_CLEANUP[${#OVS_CLEANUP[@]}]="${conn}:${cur%:*}"
613+ done
614+
615+ debug 2 "tapdevs='${TAPDEVS[@]}'"
616+ [ ${#OVS_CLEANUP[@]} -eq 0 ] || error "OVS_CLEANUP='${OVS_CLEANUP[*]}'"
617+
618+ for((i=0;i<${#TAPDEVS[@]};i++)); do
619+ cur=${TAPDEVS[$i]}
620+ [ "$cur" = "skip" ] && continue
621+ netdev_args[$i]="${netdev_args[$i]},ifname=${cur%:*}";
622+ done
623+ fi
624+
625+ netargs=()
626+ for((i=0;i<${#device_args[@]};i++)); do
627+ netargs=( "${netargs[@]}" -device "${device_args[$i]}"
628+ -netdev "${netdev_args[$i]}")
629+ done
630+
631+ local bus_devices
632+ bus_devices=( -device "$virtio_scsi_bus,id=virtio-scsi-xkvm" )
633+ cmd=( "${kvmcmd[@]}" "${archopts[@]}"
634+ "${bios_opts[@]}"
635+ "${bus_devices[@]}"
636+ "${netargs[@]}"
637+ "${diskargs[@]}" "${pt[@]}" )
638+ local pcmd=$(quote_cmd "${cmd[@]}")
639+ error "$pcmd"
640+ ${DRY_RUN} && return 0
641+
642+ if $dowait; then
643+ "${cmd[@]}" &
644+ KVM_PID=$!
645+ debug 1 "kvm pid=$KVM_PID. my pid=$$"
646+ wait
647+ ret=$?
648+ KVM_PID=""
649+ else
650+ "${cmd[@]}"
651+ ret=$?
652+ fi
653+ return $ret
654+}
655+
656+
657+if [ "$1" = "tap-control" ]; then
658+ shift
659+ mode=$1
660+ shift || fail "must give mode to tap-control"
661+ case "$mode" in
662+ make-nics) make_nics "$@";;
663+ ovs-cleanup) ovs_cleanup "$@";;
664+ *) fail "tap mode must be either make-nics or ovs-cleanup";;
665+ esac
666+else
667+ main "$@"
668+fi
669+
670+# vi: ts=4 expandtab

Subscribers

People subscribed via source and target branches