Initial commit
This commit is contained in:
		
							
								
								
									
										340
									
								
								scripts/qemustart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										340
									
								
								scripts/qemustart
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| SELF="$0" | ||||
|  | ||||
| # Linux bridge for connecting lan and wan network of guest machines | ||||
| BR_LAN="${BR_LAN:-br-lan}" | ||||
| BR_WAN="${BR_WAN:-br-wan}" | ||||
|  | ||||
| # Host network interface providing internet access for guest machines | ||||
| IF_INET="${IF_INET:-eth0}" | ||||
|  | ||||
| # qemu-bridge-helper does two things here | ||||
| # | ||||
| # - create tap interface | ||||
| # - add the tap interface to bridge | ||||
| # | ||||
| # as such it requires CAP_NET_ADMIN to do its job.  It will be convenient to | ||||
| # have it as a root setuid program.  Be aware of the security risks implied | ||||
| # | ||||
| # the helper has an acl list which defaults to deny all bridge.  we need to add | ||||
| # $BR_LAN and $BR_WAN to its allow list | ||||
| # | ||||
| #	# sudo vim /etc/qemu/bridge.conf | ||||
| #	allow br-lan | ||||
| #	allow br-wan | ||||
| # | ||||
| # Other allowed directives can be 'allow all', 'deny all', 'include xxx',  See | ||||
| # qemu-bridge-helper.c of qemu source code for details. | ||||
| # | ||||
| # The helper can be provided by package qemu-system-common on debian, or | ||||
| # qemu-kvm-common on rhel | ||||
| # | ||||
| HELPER="${HELPER:-/usr/libexec/qemu-bridge-helper}" | ||||
|  | ||||
| ### end of global settings | ||||
|  | ||||
| __errmsg() { | ||||
| 	echo "$*" >&2 | ||||
| } | ||||
|  | ||||
| do_setup() { | ||||
| 	# setup bridge for LAN network | ||||
| 	sudo ip link add dev "$BR_LAN" type bridge | ||||
| 	sudo ip link set dev "$BR_LAN" up | ||||
| 	sudo ip addr add 192.168.1.3/24 dev "$BR_LAN" | ||||
|  | ||||
| 	# setup bridge for WAN network | ||||
| 	# | ||||
| 	# minimal dnsmasq config for configuring guest wan network with dhcp | ||||
| 	# | ||||
| 	#	# sudo apt-get install dnsmasq | ||||
| 	#	# sudo vi /etc/dnsmasq.conf | ||||
| 	#	interface=br-wan | ||||
| 	#	dhcp-range=192.168.7.50,192.168.7.150,255.255.255.0,30m | ||||
| 	# | ||||
| 	sudo ip link add dev "$BR_WAN" type bridge | ||||
| 	sudo ip link set dev "$BR_WAN" up | ||||
| 	sudo ip addr add 192.168.7.1/24 dev "$BR_WAN" | ||||
|  | ||||
| 	# guest internet access | ||||
| 	sudo sysctl -w "net.ipv4.ip_forward=1" | ||||
| 	sudo sysctl -w "net.ipv4.conf.$BR_WAN.proxy_arp=1" | ||||
| 	while sudo iptables -t nat -D POSTROUTING -o "$IF_INET" -j MASQUERADE 2>/dev/null; do true; done | ||||
| 	      sudo iptables -t nat -A POSTROUTING -o "$IF_INET" -j MASQUERADE | ||||
| } | ||||
|  | ||||
| check_setup_() { | ||||
| 	ip link show "$BR_LAN" >/dev/null || return 1 | ||||
| 	ip link show "$BR_WAN" >/dev/null || return 1 | ||||
| 	[ -x "$HELPER" ] || { | ||||
| 		__errmsg "helper $HELPER is not an executable" | ||||
| 		return 1 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| check_setup() { | ||||
| 	[ -n "$o_network" ] || return 0 | ||||
| 	check_setup_ || { | ||||
| 		__errmsg "please check the script content to see the environment requirement" | ||||
| 		return 1 | ||||
| 	} | ||||
| } | ||||
| #do_setup; check_setup; exit $? | ||||
|  | ||||
| usage() { | ||||
| 	cat >&2 <<EOF | ||||
| Usage: $SELF [-h|--help] | ||||
|        $SELF <target> | ||||
|          [<subtarget> [<extra-qemu-options>]] | ||||
|          [--kernel <kernel>] | ||||
|          [--rootfs <rootfs>] | ||||
|          [--machine <machine>] | ||||
|          [-n|--network] | ||||
|  | ||||
| <subtarget> will default to "generic" and must be specified if | ||||
| <extra-qemu-options> are present | ||||
|  | ||||
| e.g. <subtarget> for malta can be le, be, le64, be64, le-glibc, le64-glibc, etc | ||||
|  | ||||
| <kernel>, <rootfs> can be required or optional arguments to qemu depending on | ||||
| the actual <target> in use.  They will default to files under bin/targets/ | ||||
|  | ||||
| Examples | ||||
|  | ||||
|   $SELF x86 64 | ||||
|   $SELF x86 64 --machine q35,accel=kvm -device virtio-balloon-pci | ||||
|   $SELF x86 64 -incoming tcp:0:4444 | ||||
|   $SELF x86 64-glibc | ||||
|   $SELF malta be -m 64 | ||||
|   $SELF malta le64 | ||||
|   $SELF malta be-glibc | ||||
|   $SELF armvirt 32 \\ | ||||
|                 --machine virt,highmem=off \\ | ||||
|                 --kernel bin/targets/armvirt/32/openwrt-armvirt-32-zImage \\ | ||||
|                 --rootfs bin/targets/armvirt/32/openwrt-armvirt-32-root.ext4 | ||||
| EOF | ||||
| } | ||||
|  | ||||
| rand_mac() { | ||||
| 	hexdump -n 3 -e '"52:54:00" 3/1 ":%02x"' /dev/urandom | ||||
| } | ||||
|  | ||||
| parse_args() { | ||||
| 	o_network= | ||||
| 	o_qemu_extra=() | ||||
| 	while [ "$#" -gt 0 ]; do | ||||
| 		# Cmdline options for the script itself SHOULD try to be | ||||
| 		# prefixed with two dashes to distinguish them from those for | ||||
| 		# qemu executables. | ||||
| 		# | ||||
| 		# Also note that qemu accepts both --opt and -opt | ||||
| 		case "$1" in | ||||
| 			--kernel) o_kernel="$2"; shift 2 ;; | ||||
| 			--rootfs) o_rootfs="$2"; shift 2 ;; | ||||
| 			--machine|-machine|-M) o_mach="$2"; shift 2 ;; | ||||
| 			--network|-n) o_network=1; shift ;; | ||||
| 			--help|-h) | ||||
| 				usage | ||||
| 				exit 0 | ||||
| 				;; | ||||
| 			*) | ||||
| 				if [ -z "$o_target" ]; then | ||||
| 					o_target="$1" | ||||
| 				elif [ -z "$o_subtarget" ]; then | ||||
| 					o_subtarget="$1" | ||||
| 				else | ||||
| 					o_qemu_extra+=("$1") | ||||
| 				fi | ||||
| 				shift | ||||
| 				;; | ||||
| 		esac | ||||
| 	done | ||||
|  | ||||
| 	MAC_LAN="$(rand_mac)" | ||||
| 	MAC_WAN="$(rand_mac)" | ||||
| 	[ -n "$o_target" ] || { | ||||
| 		usage | ||||
| 		return 1 | ||||
| 	} | ||||
| 	[ -n "$o_subtarget" ] || o_subtarget="generic" | ||||
| 	o_bindir="bin/targets/$o_target/$o_subtarget" | ||||
| } | ||||
|  | ||||
| start_qemu_armvirt() { | ||||
| 	local kernel="$o_kernel" | ||||
| 	local rootfs="$o_rootfs" | ||||
| 	local mach="${o_mach:-virt}" | ||||
| 	local cpu | ||||
| 	local qemu_exe | ||||
|  | ||||
| 	case "${o_subtarget%-*}" in | ||||
| 		32) | ||||
| 			qemu_exe="qemu-system-arm" | ||||
| 			cpu="cortex-a15" | ||||
| 			[ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-zImage-initramfs" | ||||
| 			;; | ||||
| 		64) | ||||
| 			qemu_exe="qemu-system-aarch64" | ||||
| 			cpu="cortex-a57" | ||||
| 			[ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-Image-initramfs" | ||||
| 			;; | ||||
| 		*) | ||||
| 			__errmsg "target $o_target: unknown subtarget $o_subtarget" | ||||
| 			return 1 | ||||
| 			;; | ||||
| 	esac | ||||
| 	[ -z "$rootfs" ] || { | ||||
| 		if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then | ||||
| 			gunzip "$rootfs.gz" | ||||
| 		fi | ||||
| 		o_qemu_extra+=( \ | ||||
| 			"-drive" "file=$rootfs,format=raw,if=virtio" \ | ||||
| 			"-append" "root=/dev/vda rootwait" \ | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	[ -z "$o_network" ] || { | ||||
| 		o_qemu_extra+=( \ | ||||
| 			"-netdev" "bridge,id=lan,br=$BR_LAN,helper=$HELPER" \ | ||||
| 			    "-device" "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN" \ | ||||
| 			"-netdev" "bridge,id=wan,br=$BR_WAN,helper=$HELPER" "-device" \ | ||||
| 			    "virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN" \ | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	"$qemu_exe" -machine "$mach" -cpu "$cpu" -nographic \ | ||||
| 		-kernel "$kernel" \ | ||||
| 		"${o_qemu_extra[@]}" | ||||
| } | ||||
|  | ||||
| start_qemu_malta() { | ||||
| 	local is64 | ||||
| 	local isel | ||||
| 	local qemu_exe | ||||
| 	local rootfs="$o_rootfs" | ||||
| 	local kernel="$o_kernel" | ||||
| 	local mach="${o_mach:-malta}" | ||||
|  | ||||
| 	# o_subtarget can be le, be, le64, be64, le-glibc, le64-glibc, etc.. | ||||
| 	is64="$(echo $o_subtarget | grep -o 64)" | ||||
| 	[ "$(echo "$o_subtarget" | grep -o '^..')" = "le" ] && isel="el" | ||||
| 	qemu_exe="qemu-system-mips$is64$isel" | ||||
|  | ||||
| 	[ -n "$kernel" ] || kernel="$o_bindir/openwrt-malta-${o_subtarget%-*}-vmlinux-initramfs.elf" | ||||
|  | ||||
| 	[ -z "$rootfs" ] || { | ||||
| 		if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then | ||||
| 			gunzip "$rootfs.gz" | ||||
| 		fi | ||||
| 		o_qemu_extra+=( \ | ||||
| 			"-drive" "file=$rootfs,format=raw" \ | ||||
| 			"-append" "root=/dev/sda rootwait" \ | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	# NOTE: order of wan, lan -device arguments matters as it will affect which | ||||
| 	# one will be actually used as the wan, lan network interface inside the | ||||
| 	# guest machine | ||||
| 	[ -z "$o_network" ] || { | ||||
| 		o_qemu_extra+=( | ||||
| 			-netdev bridge,id=wan,br="$BR_WAN,helper=$HELPER" -device pcnet,netdev=wan,mac="$MAC_WAN" | ||||
| 			-netdev bridge,id=lan,br="$BR_LAN,helper=$HELPER" -device pcnet,netdev=lan,mac="$MAC_LAN" | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	"$qemu_exe" -machine "$mach" -nographic \ | ||||
| 		-kernel "$kernel" \ | ||||
| 		"${o_qemu_extra[@]}" | ||||
| } | ||||
|  | ||||
| start_qemu_x86() { | ||||
| 	local qemu_exe | ||||
| 	local kernel="$o_kernel" | ||||
| 	local rootfs="$o_rootfs" | ||||
| 	local mach="${o_mach:-pc}" | ||||
|  | ||||
| 	[ -n "$rootfs" ] || { | ||||
| 		rootfs="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-combined-ext4.img" | ||||
| 		if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then | ||||
| 			gunzip "$rootfs.gz" | ||||
| 		fi | ||||
| 	} | ||||
| 	# | ||||
| 	# generic: 32-bit, pentium4 (CONFIG_MPENTIUM4), kvm guest, virtio | ||||
| 	# legacy: 32-bit, i486 (CONFIG_M486) | ||||
| 	# 64: 64-bit, kvm guest, virtio | ||||
| 	# | ||||
| 	case "${o_subtarget%-*}" in | ||||
| 		legacy)			qemu_exe="qemu-system-i386"	;; | ||||
| 		generic|64)		qemu_exe="qemu-system-x86_64"	;; | ||||
| 		*) | ||||
| 			__errmsg "target $o_target: unknown subtarget $o_subtarget" | ||||
| 			return 1 | ||||
| 			;; | ||||
| 	esac | ||||
|  | ||||
| 	[ -n "$kernel" ] && { | ||||
| 	    o_qemu_extra+=( \ | ||||
| 		"-kernel" "$kernel" \ | ||||
| 		"-append" "root=/dev/vda console=ttyS0 rootwait" \ | ||||
| 	    ) | ||||
| 	} | ||||
|  | ||||
| 	[ -z "$o_network" ] || { | ||||
| 		case "${o_subtarget%-*}" in | ||||
| 			legacy) | ||||
| 				o_qemu_extra+=( | ||||
| 					-netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "e1000,id=devlan,netdev=lan,mac=$MAC_LAN" | ||||
| 					-netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "e1000,id=devwan,netdev=wan,mac=$MAC_WAN" | ||||
| 				) | ||||
| 				;; | ||||
| 			generic|64) | ||||
| 				o_qemu_extra+=( | ||||
| 					-netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN" | ||||
| 					-netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN" | ||||
| 				) | ||||
| 				;; | ||||
| 		esac | ||||
| 	} | ||||
|  | ||||
| 	case "${o_subtarget%-*}" in | ||||
| 		legacy) | ||||
| 			# use IDE (PATA) disk instead of AHCI (SATA).  Refer to link | ||||
| 			# [1] for related discussions | ||||
| 			# | ||||
| 			# To use AHCI interface | ||||
| 			# | ||||
| 			#	-device ich9-ahci,id=ahci \ | ||||
| 			#	-device ide-drive,drive=drv0,bus=ahci.0 \ | ||||
| 			#	-drive "file=$rootfs,format=raw,id=drv0,if=none" \ | ||||
| 			# | ||||
| 			# [1] https://dev.openwrt.org/ticket/17947 | ||||
| 			"$qemu_exe" -machine "$mach" -nographic \ | ||||
| 				-device ide-drive,drive=drv0 \ | ||||
| 				-drive "file=$rootfs,format=raw,id=drv0,if=none" \ | ||||
| 				"${o_qemu_extra[@]}" | ||||
| 			;; | ||||
| 		generic|64) | ||||
| 			"$qemu_exe" -machine "$mach" -nographic \ | ||||
| 				-drive "file=$rootfs,format=raw,if=virtio" \ | ||||
| 				"${o_qemu_extra[@]}" | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
|  | ||||
| start_qemu() { | ||||
| 	case "$o_target" in | ||||
| 		armvirt)	start_qemu_armvirt	;; | ||||
| 		malta)		start_qemu_malta	;; | ||||
| 		x86)		start_qemu_x86		;; | ||||
| 		*) | ||||
| 			__errmsg "target $o_target is not supported yet" | ||||
| 			return 1 | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
|  | ||||
| parse_args "$@" \ | ||||
| 	&& check_setup \ | ||||
| 	&& start_qemu | ||||
		Reference in New Issue
	
	Block a user
	 domenico
					domenico