#!/bin/sh #============================================================================ # Default Xen network start/stop script. # Xend calls a network script when it starts. # The script name to use is defined in /etc/xen/xend-config.sxp # in the network-script field. # # This script creates a bridge (default xenbr${vifnum}), adds a device # (default eth${vifnum}) to it, copies the IP addresses from the device # to the bridge and adjusts the routes accordingly. # # If all goes well, this should ensure that networking stays up. # However, some configurations are upset by this, especially # NFS roots. If the bridged setup does not meet your needs, # configure a different script, for example using routing instead. # # Usage: # # network-bridge (start|stop|status) {VAR=VAL}* # # Vars: # # vifnum Virtual device number to use (default 0). Numbers >=8 # require the netback driver to have nloopbacks set to a # higher value than its default of 8. # bridge The bridge to use (default xenbr${vifnum}). # netdev The interface to add to the bridge (default eth${vifnum}). # antispoof Whether to use iptables to prevent spoofing (default no). # # Internal Vars: # pdev="p${netdev}" # vdev="veth${vifnum}" # vif0="vif0.${vifnum}" # # start: # Creates the bridge # Copies the IP and MAC addresses from netdev to vdev # Renames netdev to be pdev # Renames vdev to be netdev # Enslaves pdev, vdev to bridge # # stop: # Removes netdev from the bridge # Transfers addresses, routes from netdev to pdev # Renames netdev to vdev # Renames pdev to netdev # Deletes bridge # # status: # Print addresses, interfaces, routes # #============================================================================ # # 2007-07-31 - Ron Terry # - bridge is now created correctly when using bonded interfaces # dir=$(dirname "$0") . "$dir/xen-script-common.sh" . "$dir/xen-network-common.sh" findCommand "$@" evalVariables "$@" vifnum=${vifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')} vifnum=${vifnum:-0} bridge=${bridge:-xenbr${vifnum}} #if [ -e /etc/sysconfig/network/ifcfg-bond* ] #then # netdev=${netdev:-bond${vifnum}} #else netdev=${netdev:-eth${vifnum}} #fi antispoof=${antispoof:-no} pdev="p${netdev}" vdev="veth${vifnum}" vif0="vif0.${vifnum}" # Usage: transfer_addrs src dst # Copy all IP addresses (including aliases) from device $src to device $dst. transfer_addrs () { local src=$1 local dst=$2 # Don't bother if $dst already has IP addresses. if ip addr show dev ${dst} | egrep -q '^ *inet ' ; then return fi # Address lines start with 'inet' and have the device in them. # Replace 'inet' with 'ip addr add' and change the device name $src # to 'dev $src'. ip addr show dev ${src} | egrep '^ *inet ' | sed -e " s/inet/ip addr add/ s@\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/[0-9]\+\)@\1@ s/${src}/dev ${dst}/ " | sh -e # Remove automatic routes on destination device ip route list | sed -ne " /dev ${dst}\( \|$\)/ { s/^/ip route del / p }" | sh -e } # Usage: transfer_routes src dst # Get all IP routes to device $src, delete them, and # add the same routes to device $dst. # The original routes have to be deleted, otherwise adding them # for $dst fails (duplicate routes). transfer_routes () { local src=$1 local dst=$2 # List all routes and grep the ones with $src in. # Stick 'ip route del' on the front to delete. # Change $src to $dst and use 'ip route add' to add. ip route list | sed -ne " /dev ${src}\( \|$\)/ { h s/^/ip route del / P g s/${src}/${dst}/ s/^/ip route add / P d }" | sh -e } ## # link_exists interface # # Returns 0 if the interface named exists (whether up or down), 1 otherwise. # link_exists() { if ip link show "$1" >/dev/null 2>/dev/null then return 0 else return 1 fi } # Set the default forwarding policy for $dev to drop. # Allow forwarding to the bridge. antispoofing () { iptables -P FORWARD DROP iptables -F FORWARD iptables -A FORWARD -m physdev --physdev-in ${pdev} -j ACCEPT iptables -A FORWARD -m physdev --physdev-in ${vif0} -j ACCEPT } # Find the netdev that is associated with the bridge by matching MAC addresses. find_bridged_netdev () { local bridge=$1 bmac=`ip link show ${bridge} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` for i in `ls /sys/class/net/${bridge}/brif` ; do mac=`ip link show ${i} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` if [ "${bmac}" = "${mac}" ] && [ ! "${bridge}" = "${i}" ] ; then netdev=${i} return 0 fi done return 1 } # Usage: show_status dev bridge # Print ifconfig and routes. show_status () { local dev=$1 local bridge=$2 echo '============================================================' ip addr show ${dev} ip addr show ${bridge} echo ' ' brctl show ${bridge} echo ' ' ip route list echo ' ' route -n echo '============================================================' } op_start () { if [ "${bridge}" = "null" ] ; then return fi if ! link_exists "$vdev"; then if link_exists "$pdev"; then # The device is already up. return else echo " Link $vdev is missing. This may be because you have reached the limit of the number of interfaces that the loopback driver supports. If the loopback driver is a module, you may raise this limit by passing it as a parameter (nloopbacks=); if the driver is compiled statically into the kernel, then you may set the parameter using loopback.nloopbacks= on the domain 0 kernel command line. " >&2 exit 1 fi fi create_bridge ${bridge} preiftransfer . /etc/sysconfig/network/ifcfg-${hwddev} if [ ! "$BONDING_MASTER" = yes ] && link_exists "$vdev"; then ############################################################# # Configure bridge for non-bonded interfaces ############################################################# mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` ifup ${netdev} # To ensure there is an IP to transfer transfer_addrs ${netdev} ${vdev} ifdown ${netdev} ip link set ${netdev} name ${pdev} ip link set ${vdev} name ${netdev} setup_bridge_port ${pdev} setup_bridge_port ${vif0} ip link set ${netdev} addr ${mac} arp on ip link set ${bridge} up add_to_bridge ${bridge} ${vif0} add_to_bridge2 ${bridge} ${pdev} ip link set ${netdev} up ifup ${hwddev} elif [ "$BONDING_MASTER" = yes ]; then ############################################################# # Configure bridge for bonded interfaces ############################################################# # set variables local netdev_ip=`ip addr show dev ${netdev}|egrep '^ *inet '|sed "s/^ *inet //"|cut -d " " -f 1` local bondslave_list=`ifstatus ${netdev}|egrep -i "slave interface"|cut -d ":" -f 2|sed "s/ //"` local mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` local BRIDGE_NUM=${netdev##${netdev%%[0-9]*}} pdev=eth${BRIDGE_NUM} new_netdev=eth${BRIDGE_NUM} #echo "netdev = ${netdev}" #echo "netdev_ip = ${netdev_ip}" #echo "bondslave_list = $bondslave_list" #echo "mac = $mac" #echo "BRIDGE_NUM = $BRIDGE_NUM" #echo "new_netdev = $new_netdev" #echo "vdev = $vdev" #echo "pdev = $pdev" #echo "bridge = $bridge" #echo "vif0 = $vif0" #read #ip link set ${bridge} arp on ##### We must reconfigure the bonded interface first ##### #echo "bring bonded interface ${netdev} down";read ip link set ${netdev} down #echo "clean up ${netdev} (arp off, change MAC, flush IP address, etc.)";read ip link set ${netdev} arp off ip link set ${netdev} multicast off ip link set ${netdev} addr fe:ff:ff:ff:ff:ff ip addr flush ${netdev} #echo "rename the bondslave interfaces";read for DEV in $bondslave_list do #echo "renaming ${DEV} to p${DEV}";read ip link set ${DEV} name p${DEV} done #echo "bring ${netdev} back up with new bondslave names";read ifup ${netdev} #ip link set ${netdev} arp on #ip link set ${netdev} multicast on ##### Here is where we attach the bridge ports to the bridge ##### #echo "bring up the bridge ${bridge}";read ip link set ${bridge} up #echo "add ${netdev} to bridge as a bridge port";read add_to_bridge2 ${bridge} ${netdev} #echo "add ${vif0} to bridge as a ${bridge} port";read add_to_bridge ${bridge} ${vif0} #echo "clean up ${vif0} (arp off, change MAC, flush IP address, etc.)";read setup_bridge_port ${vif0} #echo "bring ${vif0} up";read ip link set ${vif0} up ##### Next we must configure the new interface for Dom0 ##### #echo "make sure the ${vdev} interface is down";read ip link set ${vdev} down #echo "rename ${vdev} to ${pdev}";read ip link set ${vdev} name ${pdev} #echo "transfer ${netdev}'s MAC address to ${pdev} and turn arp on";read ip link set ${pdev} addr ${mac} arp on #echo "bring new ${pdev} interface up";read ip link set ${pdev} up #echo "transfer ${netdev}'s IP address to ${pdev}";read ip addr add dev ${pdev} ${netdev_ip} brd + #echo "transfer ${netdev}'s routes to ${pdev}";read transfer_routes ${netdev} ${pdev} else # old style without ${vdev} transfer_addrs ${netdev} ${bridge} transfer_routes ${netdev} ${bridge} fi if [ ${antispoof} = 'yes' ] ; then antispoofing fi } op_stop () { if [ "${bridge}" = "null" ]; then return fi if ! link_exists "$bridge"; then return fi preiftransfer . /etc/sysconfig/network/ifcfg-${hwddev} if [ ! "$BONDING_MASTER" = yes ] && link_exists "$pdev"; then ############################################################# # Remove bridge for non-bonded interfaces ############################################################# ip link set dev ${vif0} down mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` transfer_addrs ${netdev} ${pdev} ifdown ${netdev} ip link set ${netdev} down arp off ip link set ${netdev} addr fe:ff:ff:ff:ff:ff ip link set ${pdev} down ip addr flush ${netdev} ip link set ${pdev} addr ${mac} arp on brctl delif ${bridge} ${pdev} brctl delif ${bridge} ${vif0} ip link set ${bridge} down ip link set ${netdev} name ${vdev} ip link set ${pdev} name ${netdev} ifup ${netdev} elif [ "$BONDING_MASTER" = yes ]; then ############################################################# # Remove bridge for bonded interfaces ############################################################# local BRIDGE_NUM=${netdev##${netdev%%[0-9]*}} local pdev=eth${BRIDGE_NUM} local new_netdev=eth${BRIDGE_NUM} local netdev_ip=`ip addr show dev ${pdev}|egrep '^ *inet '|sed "s/^ *inet //"|cut -d " " -f 1` local bondslave_list=`ifstatus ${netdev}|egrep -i "slave interface"|cut -d ":" -f 2|sed "s/ //"` local mac=`ip link show ${pdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` #echo "netdev = ${netdev}" #echo "netdev_ip = ${netdev_ip}" #echo "bondslave_list = $bondslave_list" #echo "mac = $mac" #echo "BRIDGE_NUM = $BRIDGE_NUM" #echo "new_netdev = $new_netdev" #echo "vdev = $vdev" #echo "pdev = $pdev" #echo "bridge = $bridge" #echo "vif0 = $vif0" #read ##### First we reset the virtual interface ${pdev} ##### #echo "bring ${pdev} down";read ifdown ${pdev} ip link set ${pdev} down arp off ip link set ${pdev} addr fe:ff:ff:ff:ff:ff ip addr flush ${pdev} ##### Then we reset the bridge port ${vif0} ##### #echo "bring ${vif0} down";read ip link set dev ${vif0} down ##### Then we reset the bonded interface ${netdev} ##### #echo "bring the bonded interface ${netdev} down";read ip link set ${netdev} down #ip link set ${netdev} down arp off #ip link set ${netdev} addr fe:ff:ff:ff:ff:ff ip addr flush ${netdev} ##### Then we remove the bridge port interfaces from the bridge ##### #echo "removing ${netdev} from ${bridge}";read brctl delif ${bridge} ${netdev} #echo "removing ${vif0} from ${bridge}";read brctl delif ${bridge} ${vif0} ##### Then we rename the virtual interface back to its original name ##### #echo "rename ${pdev} to ${vdev}";read ip link set ${pdev} name ${vdev} ##### Then we reset the renamed bond slave interface ${pdev} for DEV in $bondslave_list do local OLD_DEV=`echo ${DEV}|sed "s/p//"` #echo "bring the bond slave ${DEV} down";read ip link set ${DEV} down #echo "rename the bond slave ${DEV} to ${OLD_DEV}";read ip link set ${DEV} name ${OLD_DEV} done ##### And then we restart the bonded interface ##### #echo "bring bonded interface back up";read ifup ${netdev} ##### Then we bring the bridge ${bridge} down ##### #echo "bring the bridge ${bridge} down";read ip link set ${bridge} down else if [ ${netdev} = ${bridge} ]; then find_bridged_netdev ${bridge} fi ip link set dev ${vif0} down transfer_routes ${bridge} ${netdev} ip link set ${bridge} down fi ##### Finally we delete the bridge ##### brctl delbr ${bridge} } op_start_hostonly () { if [ "${bridge}" = "null" ] ; then return fi if link_exists "${bridge}"; then return fi create_bridge ${bridge} setup_bridge_port ${vif0} add_to_bridge ${bridge} ${vif0} } op_stop_hostonly () { if [ "${bridge}" = "null" ]; then return fi if ! link_exists "$bridge"; then return fi brctl delbr ${bridge} } # adds $dev to $bridge but waits for $dev to be in running state first add_to_bridge2() { local bridge=$1 local dev=$2 local maxtries=10 echo -n "Waiting for ${dev} to negotiate link." ip link set ${dev} up for i in `seq ${maxtries}` ; do if ifconfig ${dev} | grep -q RUNNING ; then break else echo -n '.' sleep 1 fi done if [ ${i} -eq ${maxtries} ] ; then echo '(link isnt in running state)' ; fi add_to_bridge ${bridge} ${dev} } case "$command" in start) if test "$netdev" = "none"; then op_start_hostonly else op_start fi ;; stop) if test "$netdev" = "none"; then op_stop_hostonly else op_stop fi ;; status) show_status ${netdev} ${bridge} ;; *) echo "Unknown command: $command" >&2 echo 'Valid commands are: start, stop, status' >&2 exit 1 esac