root@51: #!/bin/bash root@51: #============================================================================ root@51: # Default Xen network start/stop script. root@51: # Xend calls a network script when it starts. root@51: # The script name to use is defined in /etc/xen/xend-config.sxp root@51: # in the network-script field. root@51: # root@51: # This script creates a bridge (default xenbr${vifnum}), adds a device root@51: # (default eth${vifnum}) to it, copies the IP addresses from the device root@51: # to the bridge and adjusts the routes accordingly. root@51: # root@51: # If all goes well, this should ensure that networking stays up. root@51: # However, some configurations are upset by this, especially root@51: # NFS roots. If the bridged setup does not meet your needs, root@51: # configure a different script, for example using routing instead. root@51: # root@51: # Usage: root@51: # root@51: # network-bridge (start|stop|status) {VAR=VAL}* root@51: # root@51: # Vars: root@51: # root@51: # vifnum Virtual device number to use (default 0). Numbers >=8 root@51: # require the netback driver to have nloopbacks set to a root@51: # higher value than its default of 8. root@51: # bridge The bridge to use (default xenbr${vifnum}). root@51: # netdev The interface to add to the bridge (default eth${vifnum}). root@51: # antispoof Whether to use iptables to prevent spoofing (default no). root@51: # root@51: # Internal Vars: root@51: # pdev="p${netdev}" root@51: # vdev="veth${vifnum}" root@51: # vif0="vif0.${vifnum}" root@51: # root@51: # start: root@51: # Creates the bridge root@51: # Copies the IP and MAC addresses from netdev to vdev root@51: # Renames netdev to be pdev root@51: # Renames vdev to be netdev root@51: # Enslaves pdev, vdev to bridge root@51: # root@51: # stop: root@51: # Removes netdev from the bridge root@51: # Transfers addresses, routes from netdev to pdev root@51: # Renames netdev to vdev root@51: # Renames pdev to netdev root@51: # Deletes bridge root@51: # root@51: # status: root@51: # Print addresses, interfaces, routes root@51: # root@51: #============================================================================ root@51: root@51: root@51: dir=$(dirname "$0") root@51: . "$dir/xen-script-common.sh" root@51: . "$dir/xen-network-common.sh" root@51: root@51: findCommand "$@" root@51: evalVariables "$@" root@51: root@51: modprobe netloop > /dev/null 2>&1 || true root@51: root@51: vifnum=${vifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')} root@51: vifnum=${vifnum:-0} root@51: bridge=${bridge:-xenbr${vifnum}} root@51: netdev=${netdev:-eth${vifnum}} root@51: antispoof=${antispoof:-no} root@51: root@51: pdev="p${netdev}" root@51: vdev="veth${vifnum}" root@51: vif0="vif0.${vifnum}" root@51: root@51: get_ip_info() { root@51: addr_pfx=`ip addr show dev $1 | egrep '^ *inet' | sed -e 's/ *inet //' -e 's/ .*//'` root@51: gateway=`ip route show dev $1 | fgrep default | sed 's/default via //'` root@51: } root@51: root@51: do_ifup() { root@51: if ! ifup $1 ; then root@51: if [ ${addr_pfx} ] ; then root@51: # use the info from get_ip_info() root@51: ip addr flush $1 root@51: ip addr add ${addr_pfx} dev $1 root@51: ip link set dev $1 up root@51: [ ${gateway} ] && ip route add default via ${gateway} root@51: fi root@51: fi root@51: } root@51: root@51: # Usage: transfer_addrs src dst root@51: # Copy all IP addresses (including aliases) from device $src to device $dst. root@51: transfer_addrs () { root@51: local src=$1 root@51: local dst=$2 root@51: # Don't bother if $dst already has IP addresses. root@51: if ip addr show dev ${dst} | egrep -q '^ *inet ' ; then root@51: return root@51: fi root@51: # Address lines start with 'inet' and have the device in them. root@51: # Replace 'inet' with 'ip addr add' and change the device name $src root@51: # to 'dev $src'. root@51: ip addr show dev ${src} | egrep '^ *inet ' | sed -e " root@51: s/inet/ip addr add/ root@51: s@\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/[0-9]\+\)@\1@ root@51: s/${src}/dev ${dst}/ root@51: " | sh -e root@51: # Remove automatic routes on destination device root@51: ip route list | sed -ne " root@51: /dev ${dst}\( \|$\)/ { root@51: s/^/ip route del / root@51: p root@51: }" | sh -e root@51: } root@51: root@51: # Usage: transfer_routes src dst root@51: # Get all IP routes to device $src, delete them, and root@51: # add the same routes to device $dst. root@51: # The original routes have to be deleted, otherwise adding them root@51: # for $dst fails (duplicate routes). root@51: transfer_routes () { root@51: local src=$1 root@51: local dst=$2 root@51: # List all routes and grep the ones with $src in. root@51: # Stick 'ip route del' on the front to delete. root@51: # Change $src to $dst and use 'ip route add' to add. root@51: ip route list | sed -ne " root@51: /dev ${src}\( \|$\)/ { root@51: h root@51: s/^/ip route del / root@51: P root@51: g root@51: s/${src}/${dst}/ root@51: s/^/ip route add / root@51: P root@51: d root@51: }" | sh -e root@51: } root@51: root@51: root@51: ## root@51: # link_exists interface root@51: # root@51: # Returns 0 if the interface named exists (whether up or down), 1 otherwise. root@51: # root@51: link_exists() root@51: { root@51: if ip link show "$1" >/dev/null 2>/dev/null root@51: then root@51: return 0 root@51: else root@51: return 1 root@51: fi root@51: } root@51: root@51: # Set the default forwarding policy for $dev to drop. root@51: # Allow forwarding to the bridge. root@51: antispoofing () { root@51: iptables -P FORWARD DROP root@51: iptables -F FORWARD root@51: iptables -A FORWARD -m physdev --physdev-in ${pdev} -j ACCEPT root@51: iptables -A FORWARD -m physdev --physdev-in ${vif0} -j ACCEPT root@51: } root@51: root@51: # Usage: show_status dev bridge root@51: # Print ifconfig and routes. root@51: show_status () { root@51: local dev=$1 root@51: local bridge=$2 root@51: root@51: echo '============================================================' root@51: ip addr show ${dev} root@51: ip addr show ${bridge} root@51: echo ' ' root@51: brctl show ${bridge} root@51: echo ' ' root@51: ip route list root@51: echo ' ' root@51: route -n root@51: echo '============================================================' root@51: } root@51: root@51: op_start () { root@51: if [ "${bridge}" = "null" ] ; then root@51: return root@51: fi root@51: root@51: if ! link_exists "$vdev"; then root@51: if link_exists "$pdev"; then root@51: # The device is already up. root@51: return root@51: else root@51: echo " root@51: Link $vdev is missing. root@51: This may be because you have reached the limit of the number of interfaces root@51: that the loopback driver supports. If the loopback driver is a module, you root@51: may raise this limit by passing it as a parameter (nloopbacks=); if the root@51: driver is compiled statically into the kernel, then you may set the parameter root@51: using loopback.nloopbacks= on the domain 0 kernel command line. root@51: " >&2 root@51: exit 1 root@51: fi root@51: fi root@51: root@51: create_bridge ${bridge} root@51: root@51: if link_exists "$vdev"; then root@51: mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` root@51: preiftransfer ${netdev} root@51: transfer_addrs ${netdev} ${vdev} root@51: if ! ifdown ${netdev}; then root@51: # If ifdown fails, remember the IP details. root@51: get_ip_info ${netdev} root@51: ip link set ${netdev} down root@51: ip addr flush ${netdev} root@51: fi root@51: ip link set ${netdev} name ${pdev} root@51: ip link set ${vdev} name ${netdev} root@51: root@51: setup_bridge_port ${pdev} root@51: setup_bridge_port ${vif0} root@51: ip link set ${netdev} addr ${mac} arp on root@51: root@51: ip link set ${bridge} up root@51: add_to_bridge ${bridge} ${vif0} root@51: add_to_bridge2 ${bridge} ${pdev} root@51: do_ifup ${netdev} root@51: else root@51: # old style without ${vdev} root@51: transfer_addrs ${netdev} ${bridge} root@51: transfer_routes ${netdev} ${bridge} root@51: fi root@51: root@51: if [ ${antispoof} = 'yes' ] ; then root@51: antispoofing root@51: fi root@51: } root@51: root@51: op_stop () { root@51: if [ "${bridge}" = "null" ]; then root@51: return root@51: fi root@51: if ! link_exists "$bridge"; then root@51: return root@51: fi root@51: root@51: if link_exists "$pdev"; then root@51: ip link set dev ${vif0} down root@51: mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` root@51: transfer_addrs ${netdev} ${pdev} root@51: if ! ifdown ${netdev}; then root@51: get_ip_info ${netdev} root@51: fi root@51: ip link set ${netdev} down arp off root@51: ip link set ${netdev} addr fe:ff:ff:ff:ff:ff root@51: ip link set ${pdev} down root@51: ip addr flush ${netdev} root@51: ip link set ${pdev} addr ${mac} arp on root@51: root@51: brctl delif ${bridge} ${pdev} root@51: brctl delif ${bridge} ${vif0} root@51: ip link set ${bridge} down root@51: root@51: ip link set ${netdev} name ${vdev} root@51: ip link set ${pdev} name ${netdev} root@51: do_ifup ${netdev} root@51: else root@51: transfer_routes ${bridge} ${netdev} root@51: ip link set ${bridge} down root@51: fi root@51: brctl delbr ${bridge} root@51: } root@51: root@51: # adds $dev to $bridge but waits for $dev to be in running state first root@51: add_to_bridge2() { root@51: local bridge=$1 root@51: local dev=$2 root@51: local maxtries=10 root@51: root@51: echo -n "Waiting for ${dev} to negotiate link." root@51: ip link set ${dev} up root@51: for i in `seq ${maxtries}` ; do root@51: if ifconfig ${dev} | grep -q RUNNING ; then root@51: break root@51: else root@51: echo -n '.' root@51: sleep 1 root@51: fi root@51: done root@51: root@51: if [ ${i} -eq ${maxtries} ] ; then echo '(link isnt in running state)' ; fi root@51: root@51: add_to_bridge ${bridge} ${dev} root@51: } root@51: root@51: case "$command" in root@51: start) root@51: op_start root@51: ;; root@51: root@51: stop) root@51: op_stop root@51: ;; root@51: root@51: status) root@51: show_status ${netdev} ${bridge} root@51: ;; root@51: root@51: *) root@51: echo "Unknown command: $command" >&2 root@51: echo 'Valid commands are: start, stop, status' >&2 root@51: exit 1 root@51: esac