#!/bin/bash #============================================================================ # Default Xen network start/stop script. # Xend calls a network script when it starts. # The script name to use is defined in ${XEN_CONFIG_DIR}/xend-config.sxp # in the network-script field. # # This script creates a bridge (default ${netdev}), adds a device # (defaults to the device on the default gateway route) 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: # # bridge The bridge to use (default ${netdev}). # netdev The interface to add to the bridge (default gateway device). # antispoof Whether to use iptables to prevent spoofing (default no). # # Internal Vars: # pdev="p${netdev}" # tdev=tmpbridge # # start: # Creates the bridge as tdev # Copies the IP and MAC addresses from pdev to bridge # Renames netdev to be pdev # Renames tdev to bridge # Enslaves pdev to bridge # # stop: # Removes pdev from the bridge # Transfers addresses, routes from bridge to pdev # Renames bridge to tdev # Renames pdev to netdev # Deletes tdev # # status: # Print addresses, interfaces, routes # #============================================================================ dir=$(dirname "$0") . "$dir/logging.sh" . "$dir/xen-script-common.sh" . "$dir/xen-network-common.sh" . "$dir/locking.sh" findCommand "$@" evalVariables "$@" is_network_root () { local rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' /etc/mtab) local rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab) [[ "$rootfs" =~ "^nfs" ]] || [[ "$rootopts" =~ "_netdev" ]] && has_nfsroot=1 || has_nfsroot=0 if [ $has_nfsroot -eq 1 ]; then local bparms=$(cat /proc/cmdline) for p in $bparms; do local ipaddr=$(echo $p | awk /nfsroot=/'{ print substr($1,9,index($1,":")-9) }') if [ "$ipaddr" != "" ]; then local nfsdev=$(ip route get $ipaddr | awk /$ipaddr/'{ print $3 }') [[ "$nfsdev" == "$netdev" ]] && return 0 || return 1 fi done fi return 1 } find_alt_device () { local interf=$1 local prefix=${interf%[[:digit:]]} local ifs=$(ip link show | grep " $prefix" |\ awk '{ printf ("%s",substr($2,1,length($2)-1)) }' |\ sed s/$interf//) echo "$ifs" } netdev=${netdev:-$(ip route list 0.0.0.0/0 | \ sed 's/.*dev \([a-z]\+[0-9]\+\).*$/\1/')} if is_network_root ; then altdevs=$(find_alt_device $netdev) for netdev in $altdevs; do break; done if [ -z "$netdev" ]; then [ -x /usr/bin/logger ] && /usr/bin/logger "network-bridge: bridging not supported on network root; not starting" exit fi fi netdev=${netdev:-eth0} bridge=${bridge:-${netdev}} antispoof=${antispoof:-no} pdev="p${netdev}" tdev=tmpbridge get_ip_info() { addr_pfx=`ip addr show dev $1 | egrep '^ *inet' | sed -e 's/ *inet //' -e 's/ .*//'` gateway=`ip route show dev $1 | fgrep default | sed 's/default via //'` } do_ifup() { if [ $1 != "${netdev}" ] || ! ifup $1 ; then if [ -n "$addr_pfx" ] ; then # use the info from get_ip_info() ip addr flush $1 ip addr add ${addr_pfx} dev $1 fi ip link set dev $1 up [ -n "$gateway" ] && ip route add default via ${gateway} fi } # 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} label ${dst}/ s/secondary// " | 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 } # 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 [ `brctl show | wc -l` != 1 ]; then return fi if link_exists "$pdev"; then # The device is already up. return fi claim_lock "network-bridge" create_bridge ${tdev} preiftransfer ${netdev} transfer_addrs ${netdev} ${tdev} # Remember slaves for bonding interface. if [ -e /sys/class/net/${netdev}/bonding/slaves ]; then slaves=`cat /sys/class/net/${netdev}/bonding/slaves` fi # Remember the IP details for do_ifup. get_ip_info ${netdev} if ! ifdown ${netdev}; then ip link set ${netdev} down ip addr flush ${netdev} fi ip link set ${netdev} name ${pdev} ip link set ${tdev} name ${bridge} setup_physical_bridge_port ${pdev} # Restore slaves if [ -n "${slaves}" ]; then ip link set ${pdev} up ifenslave ${pdev} ${slaves} fi add_to_bridge2 ${bridge} ${pdev} do_ifup ${bridge} if [ ${antispoof} = 'yes' ] ; then antispoofing fi release_lock "network-bridge" } op_stop () { if [ "${bridge}" = "null" ]; then return fi if ! link_exists "$bridge"; then return fi if ! [ -e "/sys/class/net/${bridge}/brif/${pdev}" ]; then # $bridge is not a bridge to which pdev is enslaved return fi claim_lock "network-bridge" transfer_addrs ${bridge} ${pdev} if ! ifdown ${bridge}; then get_ip_info ${bridge} fi ip link set ${pdev} down ip addr flush ${bridge} brctl delif ${bridge} ${pdev} ip link set ${bridge} down ip link set ${bridge} name ${tdev} ip link set ${pdev} name ${netdev} do_ifup ${netdev} brctl delbr ${tdev} release_lock "network-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 -n '(link isnt in running state)' ; fi echo add_to_bridge ${bridge} ${dev} } case "$command" in start) op_start ;; stop) op_stop ;; status) show_status ${netdev} ${bridge} ;; *) echo "Unknown command: $command" >&2 echo 'Valid commands are: start, stop, status' >&2 exit 1 esac