Results 1 to 5 of 5

Thread: vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

  1. #1

    Default vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

    Code:
    #! /bin/bash
    #: Title       : vm-bridge
    #: Date Created: Sat Jan 15 13:09:51 PST 2011 
    #: Last Edit   : Fri Feb  4 21:12:47 PST 2011
    #: Author      : please_try_again 
    #: Version     : 1.0 BETA!
    #: Description : create/delete bridges and set up kvm virtual
    #:             : machines to bridge or revert to nat 
    #:             : THIS SCRIPT WORKS ON LOCAL KVM HYPERVISOR ONLY!!!
    #: usage       : vm-bridge -b|-n <virtualMachine>
    #:             : bridge2nat [virtualMachine]
    #:             : nat2bridge [virtualMachine]
    #: options:    : -i  --interface <ethX>         : use given network device
    #:             : -b  --bridge <brX>             : set up vm to bridge 
    #:             : -n  --nat <brX>                : set up vm to nat 
    #:             : -m  --mac <52:54:00:xx:xx:xx>  : change MAC address
    #
    #: Copy and paste this text into a text file and save it in /usr/local/bin as the file vm-bridge
    #: change onwership to root and make it executable for the owner (root) and readable by all users.
    #: You have to be root to run this script!
    #:
    #: As root, create the hardlinks bridge2nat and nat2bridge: 
    #: ln /usr/local/bin/{vm-bridge,bridge2nat}
    #: ln /usr/local/bin/{vm-bridge,nat2bridge}
    #:
    #: Then you can setup a vm to bridge or revert to nat with the command: 
    #: nat2bridge <vm>
    #: bridge2nat <vm>
    #:
    #: If no vm is provide as argument, bridge2nat will remove a bridge (if it is not used anymore) and
    #: nat2bridge will create one with the device specified in the --interface option or with the
    #: default device (eth0 or the one defined in the DEFAULT_ETH variable below)
    #:
    
    # ~~~~
    # variables you have to change
    # set your gateway here in case it can not be found with route (unlikable!)
    GW=192.168.101.1 		# your gateway (unless set in the environment varilable GATEWAY) 
    
    # variables you may change
    DEFAULT_BRIDGE=br0 		# default bridge
    DEFAULT_ETH=eth0 		# default nic
    netmask=0xffffff00		# should be fine for a class C network
    LOCALBIN=/usr/local/bat # path where you put the script (/usr/local/bin is fine)
    HYP="qemu:///system"    # default hypervisor
    # ~~~~
    # Don't change anything below that point. 
    
    prg=`basename $0`
    ver='1.0'
    
    # ~~~~
    function syntax {
    cat << EOFSYNTAX
    usage:
       $prg [ -i interface ] -b|-n [ bridge] [ virtualMachine ]
    options:
       -i --interface    : network interface
       -b --bridge       : set up vm to use bridge / create a bridge
       -n --nat          : set up vm to use nat / delete a bridge 
       -m --mac          : mac adresse
    EOFSYNTAX
    exit
    }
    # ~~~~
    
    # use the popup library if found
    which popup &>/dev/null && source $(which popup)
    
    # use popup functions if available
    function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
    function Warn  { declare -F | grep -q warn  && warn  "$*" || echo "Warning: $*" ;}
    
    # ~~~~
    
    function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ; }
    
    # ~~~~
    
    pathmunge () {
    	if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
    		[ -d $1 ] && PATH=$1:$PATH
    	fi
    }
    
    function chkMAC {
    	chkarg $1
    	MAC=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
    	# check if MAC address is a valid Xen or QEMU address
    	[ "$MAC" == "00:16:3e:" -o  "$MAC" == "52:54:00:" ] || Error "Invalid MAC address: $1".
    	[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid MAC address: $1"
    	a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
    	[ ${#a} -eq 6 ] || Error "invalid MAC address: $1"
    }
    
    function createBridge {
    	echo " - creating bridge $1"
    	brctl show | grep -q $2 && Error "$2 is already attached to a bridge"
    	brctl addbr $1
    	ifconfig $2 0.0.0.0 promisc
    	brctl addif $1 $2
    	ifconfig $1 inet $3 netmask $netmask
    	brctl stp $1 on
    	route add default gw $gw 2>/dev/null
    }
    
    function deleteBridge {
    	echo " - deleting bridge $1"
    	brctl delif $1 $2
    	ifconfig $1 down
    	brctl delbr $1 
    	ifconfig $2 inet $3 netmask $netmask -promisc
    	route add default gw $gw 2>/dev/null
    }
    
    function setBridge {
    	echo " - assigning bridge $2 to $1"
    	virsh -c $HYP "start $1 --paused" || Error "doamin $1 cannot be started"
    	mac=$(virsh -c $HYP dumpxml $1 | sed -n "s|.*<mac address='\(.*\)'/>|\1|p")
    	mod=$(virsh -c $HYP dumpxml $1 | sed -n "/<interface type='network'>/,/<\/interface>/s|.*model type='\(.*\)'/>|\1|p")
    	[ "$mod" ] && model=" --model $mod"	
    	virsh -c $HYP "attach-interface $1 bridge $2 --mac $mac $model ; detach-interface $1 network --mac $mac" 
    	virsh -c $HYP dumpxml $1 > /tmp/$1.xml 
    	virsh -c $HYP "destroy $1 ; undefine $1"
    	virsh define /tmp/$1.xml
    }
    
    function setNat {
    	echo " - reverting $1 to nat"
    	virsh -c $HYP "start $1 --paused" || Error "doamin $1 cannot be started"
    	mac=$(virsh -c $HYP dumpxml $1 | sed -n "s|.*<mac address='\(.*\)'/>|\1|p")
    	mod=$(virsh -c $HYP dumpxml $1 | sed -n "/<interface type='bridge'>/,/<\/interface>/s|.*model type='\(.*\)'/>|\1|p")
    	[ "$mod" ] && model=" --model $mod"	
    	virsh -c $HYP "attach-interface $1 network default --mac $mac $model ; detach-interface $1 bridge --mac $mac"
    	virsh -c $HYP dumpxml $1 > /tmp/$1.xml 
    	virsh -c $HYP "destroy $1 ; undefine $1"
    	virsh define /tmp/$1.xml
    }
    # ~~~~~
    
    # ~~~~~
    # Main Script - BEGIN
    # ~~~~~
    
    # added this path for sudo users
    pathmunge $LOCALBIN
    
    # make sure a valid gateway is defined, either in the variable GW at the top of this script
    # or in the environment varilable GATEWAY. GATEWAY is evaluated first.
    # Notice that if you define this variable before running the script with sudo, it won't be in
    # the root environment. 
    
    gw=$(route -nee | awk '/UG/ {print $2}')
    [ "x$gw" == "x" ] && gw=${GATEWAY:-$GW}
    [ "x$gw" == "x" ] && Error "no gateway defined"
    /bin/ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
    
    # check if virsh is installed
    which virsh &> /dev/null || Error "virsh not found"
    
    flag=0
    
    # evaluate arguments
    args=`getopt -qu -o i:b::n::m: -l interface:,bridge::,nat:: -- "$@"`
    
    set -- $args
    
    for i; do
    	case "$i" in
    		-i|--interface) shift; chkarg $1 ; nic=$1; shift ;;
        	-b|--bridge) flag=$(($flag | 1)) ; shift ;;
    		-n|--nat) flag=$(($flag | 2)) ; shift ;;
    		-m|--mac) shift; chkMAC $1 ; mac=$1 ; shift ;;
    		br*) br=$1 ; shift ;;
    		--) shift ;;
    	esac
    done
    
    vm=$1
    
    # use alternate names bridge2nat and nat2bridge
    [ "$prg" == "nat2bridge" ] && flag=$(($flag | 1))
    [ "$prg" == "bridge2nat" ] && flag=$(($flag | 2)) 
    [ $flag -ge 3 ] && Error "options --bridge and --nat are mutually exclusive"
    [ "$?" == "0" -o $flag -eq 0 ] && syntax
    
    # if network interface not given, take the value of DEFAULT_ETH
    nic=${nic:-$DEFAULT_ETH}
    
    # if bridge not given take the value of DEFAULT_BRIDGE if defined.
    # otherwise take br + eth number.
    br=${br:-$DEFAULT_BRIDGE}
    [ "$br" ] || br=${nic/eth/br}
    
    ifconfig $nic &>/dev/null || Error "invalid network device"
    
    if [ "$vm" ] ; then
    	virsh -c $HYP list --all | grep -q " $vm " || Error "virtual machine $vm not found"
    	[ "$(virsh -c $HYP domstate $vm)" == "shut off" ] || Error "virtual machine $vm is active"
    	[ "x$(virsh -c $HYP net-list | awk '/default/ { print $2 }')" == "xactive" ] || virsh -c $HYP net-start default
    fi
    
    case $flag in
    	# nat to bridge
    	1)
    		if [ "$vm" ] ; then
    			virsh -c $HYP dumpxml $vm | grep -q 'source bridge' && Error "virtual machine $vm is already in bridge mode"  
    		fi
    
    		net=$(ifconfig $nic 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    		ifconfig $br &>/dev/null && Warn "bridge $br already set" || createBridge $br $nic $net 
    
    		[ "$vm" ] && setBridge $vm $br 
    		;;
    	# bridge to nat
    	2)
    		if [ "$vm" ] ; then
    			br=$(virsh dumpxml $vm | sed -n "s|.*<source bridge='\(.*\)'/>|\1|p")
    			[ "x$br" == "x" ] && Error "virtual machine $vm is not in bridge mode" || {
    				ifconfig $br &>/dev/null || createBridge $br $nic $(ifconfig $nic 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    			 	setNat $vm
    			} 
    		fi
    
    		ifconfig $br &>/dev/null || Error "bridge $br doesn't exist"
    		net=$(ifconfig $br 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    
    		vms=$(virsh -c $HYP list | awk '/running|paused/ { print $2 }')
    	
    		if [ "$vms" ] ; then
    			for VM in $vms ; do
    				virsh -c $HYP dumpxml $VM | grep -q "source bridge='$br'" && Error "bridge $br is still used by vm $VM"
    			done	
    		fi
    
    		nic=$(brctl show | grep "^$br[ 	]" | awk '{ print $NF }')
    		deleteBridge $br $nic $net
    		;;
    esac
    
    # ~~~~
    # Main Script - END
    # ~~~~
    vm-bridge is a script to convert qemu virtual machines from bridge to nat or vice versa. It only works on kvm local hypervisor. Withouth a virtual machine given as argument, it can also be used to create/delete bridges.

    nat2bridge is an alias for vm-bridge -n (or vm-bridge --nat)
    bridge2nat is an alias for vm-bridge -b (or vm-bridge --bridge)

    Provided those files exist and are hard or soft links of vm-bridge

    The option -b (or --bridge) can have a bridge name as optional argument. Without argument, the value of DEFAULT_BRIDGE (br0) will be used if defined. You can change this value or comment out the variable. In this case the default bridge will be named after the corresponding eth device (eth0 -> br0, eth1 -> br1, etc).

    You can specify the network device (eth0, eth1) with the option -i (or --interface) which requires an argument. If you don't, the value of DEFAULT_ETH will be used.

    The following commands are equivalent and all create the bridge br0 with the device eth0:

    Code:
    nat2bridge
    vm-bridge -b
    vm-bridge -b br0
    vm-bridge -i eth0 -b
    vm-bridge -i eth0 -b br0
    To convert a virtual machine from NAT to bridge, just append the name of the virtual machine to one of the above commands. The bridge will be created if it doesn't already exist, then the virtual machine will be set to use it. The MAC address will be preserved unless you specify another MAC address with the option -m (or --mac).

    The following commands are equivalent and all remove the bridge br0 from device eth0:

    Code:
    bridge2nat
    vm-bridge -n
    vm-bridge -i eth0 -n
    To convert a virtual machine from bridge to NAT, just append the name of the virtual machine to one of the above commands. The virtual machine will be reset to NAT. Then the bridge will be removed if no running virtual machine is using it. The MAC address will be preserved unless you specify another MAC address with the option -m (or --mac).

    You cannot remove a bridge which is still used by a running virtual machine. However you can remove a bridge as soon as it is not used any more. But then - unless you converted all your virtual machines to NAT - you'll have to recreate the bridge *BEFORE* booting any virtual machine which needs it. So don't remove bridges unless you have a reason.

    non fatal errors

    When you convert a virtual-machine from bridge to NAT, the script will attempt to remove the bridge as well. It will fail and output an error if the bridge is still used by another machine. However, at this point, your first virtual machine would already have been converted to NAT. This is a fatal error for the rest of the script but the conversion succeeded (hopefully).

    When you convert a virtual-machine from bridge to NAT, the script will display a warning if the bridge already exists and will not attempt to create it. This is just a warning. You should say "yes" to the dialog/kdialog/zenity message if you're using the script with the popup library. To disable the popup libray for this script, just comment out this line:

    Code:
    which popup &>/dev/null && source $(which popup)
    fatal errors

    Sometimes a domain can not be started for various reasons, like if you installed it from a networked pool which doesn't exist anymore and the iso image is still attached to the vm. In that case the script will abort with an error message. You might be able to identify the problem from the standard error output and fix it with virt-manager.

    Another reason it might fail is that the domain is still locked by a previous API. There is not much to do in this case. Restarting the libvirt daemon doesn't help.
    Re: [libvirt-users] cannot acquire state change lock

    I noticed that it takes some time for the default route to respond after a change. So if you're doing nat2bridge followed by bridge2nat within a couple seconds, the script may abort with an error message saying that the gateway can not be reached. Just wait few more seconds.

    Why would you need this script

    • if you create NAT based vms (this is the default) and want to convert them later to bridge. It can also be done with virt-manager - the GUI interface - but one of the advantages of scripts is to avoid clicking buttons. Also the script will create/delete bridges when needed, while virt-manager won't.
    • if you want to switch a vm to bridge and back to NAT for various reasons, such as for security reasons (NAT is not accessible from outside)
    • if you want to preserve your vm MAC address (with virt-manager, you would have to write it down first and enter it manually while creating the new device)
    • if you don't want to use bridges permanently. Bridges created with this script won't survive a reboot.


    Why you might NOT use this script
    • If you need bridges permanently, like if you have bridged guests starting/restarting automatically at host reboot, you MUST set up the bridges with the OS network configuration tools (i.e with YaST under openSUSE). Otherwise your virtual machines won't start.
    • This script is not meant for beginners and hasn't been tested much yet. I strongly encourage you to make copies of you vm definition files under /etc/libvirt/qemu before using it and save them somewhere else. The script does NOT backup definition files for you.
    • The script doesn't write any permanent system change except in your vm definition files. IMHO the worst that could happen while creating bridges on the fly is that wour local IP and default route momentarily get messed up. If you're finding yourself in such a situation, just use ifconfig and route to reset your IP and gateway or dhclient to get it bach from your router/dhcp server if you have one... or simply reboot.
    • That makes me think that I have no idea whether it will play well with network manager ... (?)


    caveats

    The script hasn't been tested very much to switch virtual machines. I use it mostly without arguments - as nat2bridge and bridge2nat to create/remove bridges.

  2. #2
    Join Date
    Jul 2009
    Location
    Montreal, Québec
    Posts
    833

    Default Re : vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

    Wow! You're on fire please_try_again.

    Thanks, I keep this one in my (full) pocket.

  3. #3

    Default Re: Re : vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

    My thanks also. I'll keep it in mind.
    Box 1: OpenSuse 11.1/Win7 | Linux 2.6.27 Gnome | AMD 64 X2 6000+ | nVidia 8600GT | 2GB RAM
    Box 2: OpenSuse 11.2 | Linux 2.6.31 Gnome | AMD 64 3000+ | ATI X800 Pro | 1GB RAM
    Box 3: Win7 Premium Home | Intel P4 3.0Gz | ATI AIW 2006 | 2GB RAM

  4. #4
    Join Date
    Jul 2010
    Location
    Adelaide, Australia
    Posts
    963

    Default Re: Re : vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

    Thanks from me as well
    Desktop: Gigabyte GA-Z270-HD3 - Core i7 7700K - openSUSE Leap 42.2 KDE
    Laptop: HP EliteBook 8770W - Core i7 3940XM - openSUSE Leap 42.2 KDE

  5. #5

    Default Re: Re : vm-bridge : convert virtual machines from NAT to bridge or bridge to NAT

    I just applied a minor change to this stable version to read the default network interface from route output rather than taking eth0 by default - for compatibility with bios names now used on Fedora (Features/ConsistentNetworkDeviceNaming - FedoraProject).

    Code:
    #! /bin/bash
    #: Title       : vm-bridge
    #: Date Created: Sat Jan 15 13:09:51 PST 2011 
    #: Last Edit   : Thu Sep 15 16:48:38 PDT 2011
    #: Author      : please_try_again 
    #: Version     : 1.0
    #: Description : create/delete bridges and set up kvm virtual
    #:             : machines to bridge or revert to nat 
    #:             : THIS SCRIPT WORKS ON LOCAL KVM HYPERVISOR ONLY!!!
    #: usage       : vm-bridge -b|-n <virtualMachine>
    #:             : bridge2nat [virtualMachine]
    #:             : nat2bridge [virtualMachine]
    #: options:    : -i  --interface <ethX>         : use given network device
    #:             : -b  --bridge <brX>             : set up vm to bridge 
    #:             : -n  --nat <brX>                : set up vm to nat 
    #:             : -m  --mac <52:54:00:xx:xx:xx>  : change MAC address
    #
    #: Copy and paste this text into a text file and save it in /usr/local/bin as the file vm-bridge
    #: change onwership to root and make it executable for the owner (root) and readable by all users.
    #: You have to be root to run this script!
    #:
    #: As root, create the hardlinks bridge2nat and nat2bridge: 
    #: ln /usr/local/bin/{vm-bridge,bridge2nat}
    #: ln /usr/local/bin/{vm-bridge,nat2bridge}
    #:
    #: Then you can setup a vm to bridge or revert to nat with the command: 
    #: nat2bridge <vm>
    #: bridge2nat <vm>
    #:
    #: If no vm is provide as argument, bridge2nat will remove a bridge (if it is not used anymore) and
    #: nat2bridge will create one with the device specified in the --interface option or with the
    #: default device (eth0 or the one defined in the DEFAULT_ETH variable below)
    #:
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # variables you have to change
    # set your gateway here in case it can not be found with route (unlikable!)
    GW=192.168.101.1 		# your gateway (unless set in the environment varilable GATEWAY) 
    
    # variables you may change
    DEFAULT_BRIDGE=br0 		# default bridge
    DEFAULT_ETH=eth0 		# default nic
    netmask=0xffffff00		# should be fine for a class C network
    LOCALBIN=/usr/local/bat # path where you put the script (/usr/local/bin is fine)
    HYP="qemu:///system"    # default hypervisor
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Don't change anything below that point. 
    
    prg=`basename $0`
    ver='1.0'
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function syntax {
    cat << EOFSYNTAX
    usage:
       $prg [ -i interface ] -b|-n [ bridge] [ virtualMachine ]
    options:
       -i --interface    : network interface
       -b --bridge       : set up vm to use bridge / create a bridge
       -n --nat          : set up vm to use nat / delete a bridge 
       -m --mac          : mac adresse
    EOFSYNTAX
    exit
    }
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    # use the popup library if found
    which popup &>/dev/null && source $(which popup)
    
    # use popup functions if available
    function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
    function Warn  { declare -F | grep -q warn  && warn  "$*" || echo "Warning: $*" ;}
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ; }
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    pathmunge () {
    	if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
    		[ -d $1 ] && PATH=$1:$PATH
    	fi
    }
    
    function chkMAC {
    	chkarg $1
    	MAC=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
    	# check if MAC address is a valid Xen or QEMU address
    	[ "$MAC" == "00:16:3e:" -o  "$MAC" == "52:54:00:" ] || Error "Invalid MAC address: $1".
    	[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid MAC address: $1"
    	a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
    	[ ${#a} -eq 6 ] || Error "invalid MAC address: $1"
    }
    
    function createBridge {
    	echo " - creating bridge $1"
    	brctl show | grep -q $2 && Error "$2 is already attached to a bridge"
    	brctl addbr $1
    	ifconfig $2 0.0.0.0 promisc
    	brctl addif $1 $2
    	ifconfig $1 inet $3 netmask $netmask
    	brctl stp $1 on
    	route add default gw $gw 2>/dev/null
    }
    
    function deleteBridge {
    	echo " - deleting bridge $1"
    	brctl delif $1 $2
    	ifconfig $1 down
    	brctl delbr $1 
    	ifconfig $2 inet $3 netmask $netmask -promisc
    	route add default gw $gw 2>/dev/null
    }
    
    function setBridge {
    	echo " - assigning bridge $2 to $1"
    	virsh -c $HYP "start $1 --paused" || Error "doamin $1 cannot be started"
    	mac=$(virsh -c $HYP dumpxml $1 | sed -n "s|.*<mac address='\(.*\)'/>|\1|p")
    	mod=$(virsh -c $HYP dumpxml $1 | sed -n "/<interface type='network'>/,/<\/interface>/s|.*model type='\(.*\)'/>|\1|p")
    	[ "$mod" ] && model=" --model $mod"	
    	virsh -c $HYP "attach-interface $1 bridge $2 --mac $mac $model ; detach-interface $1 network --mac $mac" 
    	virsh -c $HYP dumpxml $1 > /tmp/$1.xml 
    	virsh -c $HYP "destroy $1 ; undefine $1"
    	virsh define /tmp/$1.xml
    }
    
    function setNat {
    	echo " - reverting $1 to nat"
    	virsh -c $HYP "start $1 --paused" || Error "doamin $1 cannot be started"
    	mac=$(virsh -c $HYP dumpxml $1 | sed -n "s|.*<mac address='\(.*\)'/>|\1|p")
    	mod=$(virsh -c $HYP dumpxml $1 | sed -n "/<interface type='bridge'>/,/<\/interface>/s|.*model type='\(.*\)'/>|\1|p")
    	[ "$mod" ] && model=" --model $mod"	
    	virsh -c $HYP "attach-interface $1 network default --mac $mac $model ; detach-interface $1 bridge --mac $mac"
    	virsh -c $HYP dumpxml $1 > /tmp/$1.xml 
    	virsh -c $HYP "destroy $1 ; undefine $1"
    	virsh define /tmp/$1.xml
    }
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Main Script - BEGIN
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    # added this path for sudo users
    pathmunge $LOCALBIN
    
    # make sure a valid gateway is defined, either in the variable GW at the top of this script
    # or in the environment varilable GATEWAY. GATEWAY is evaluated first.
    # Notice that if you define this variable before running the script with sudo, it won't be in
    # the root environment. 
    
    gw=$(route -nee | awk '/UG/ {print $2}')
    [ "x$gw" == "x" ] && gw=${GATEWAY:-$GW}
    [ "x$gw" == "x" ] && Error "no gateway defined"
    /bin/ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
    
    # check if virsh is installed
    which virsh &> /dev/null || Error "virsh not found"
    
    flag=0
    
    # evaluate arguments
    args=`getopt -qu -o i:b::n::m: -l interface:,bridge::,nat:: -- "$@"`
    
    set -- $args
    
    for i; do
    	case "$i" in
    		-i|--interface) shift; chkarg $1 ; nic=$1; shift ;;
        	-b|--bridge) flag=$(($flag | 1)) ; shift ;;
    		-n|--nat) flag=$(($flag | 2)) ; shift ;;
    		-m|--mac) shift; chkMAC $1 ; mac=$1 ; shift ;;
    		br*) br=$1 ; shift ;;
    		--) shift ;;
    	esac
    done
    
    vm=$1
    
    # use alternate names bridge2nat and nat2bridge
    [ "$prg" == "nat2bridge" ] && flag=$(($flag | 1))
    [ "$prg" == "bridge2nat" ] && flag=$(($flag | 2)) 
    [ $flag -ge 3 ] && Error "options --bridge and --nat are mutually exclusive"
    [ "$?" == "0" -o $flag -eq 0 ] && syntax
    
    # if network interface not given, take the value of DEFAULT_ETH
    nic=$(route | awk '/default/{ print $NF}' | head -1)
    nic=${nic:-$DEFAULT_ETH}
    
    # if bridge not given take the value of DEFAULT_BRIDGE if defined.
    # otherwise take br + eth number.
    br=${br:-$DEFAULT_BRIDGE}
    [ "$br" ] || br=${nic/eth/br}
    
    ifconfig $nic &>/dev/null || Error "invalid network device"
    
    if [ "$vm" ] ; then
    	virsh -c $HYP list --all | grep -q " $vm " || Error "virtual machine $vm not found"
    	[ "$(virsh -c $HYP domstate $vm)" == "shut off" ] || Error "virtual machine $vm is active"
    	[ "x$(virsh -c $HYP net-list | awk '/default/ { print $2 }')" == "xactive" ] || virsh -c $HYP net-start default
    fi
    
    case $flag in
    	# nat to bridge
    	1)
    		if [ "$vm" ] ; then
    			virsh -c $HYP dumpxml $vm | grep -q 'source bridge' && Error "virtual machine $vm is already in bridge mode"  
    		fi
    
    		net=$(ifconfig $nic 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    		ifconfig $br &>/dev/null && Warn "bridge $br already set" || createBridge $br $nic $net 
    
    		[ "$vm" ] && setBridge $vm $br 
    		;;
    	# bridge to nat
    	2)
    		if [ "$vm" ] ; then
    			br=$(virsh dumpxml $vm | sed -n "s|.*<source bridge='\(.*\)'/>|\1|p")
    			[ "x$br" == "x" ] && Error "virtual machine $vm is not in bridge mode" || {
    				ifconfig $br &>/dev/null || createBridge $br $nic $(ifconfig $nic 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    			 	setNat $vm
    			} 
    		fi
    
    		ifconfig $br &>/dev/null || Error "bridge $br doesn't exist"
    		net=$(ifconfig $br 2>/dev/null | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
    
    		vms=$(virsh -c $HYP list | awk '/running|paused/ { print $2 }')
    	
    		if [ "$vms" ] ; then
    			for VM in $vms ; do
    				virsh -c $HYP dumpxml $VM | grep -q "source bridge='$br'" && Error "bridge $br is still used by vm $VM"
    			done	
    		fi
    
    		nic=$(brctl show | grep "^$br[ 	]" | awk '{ print $NF }')
    		deleteBridge $br $nic $net
    		;;
    esac
    
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Main Script - END
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •