| rev | line source | 
| root@51 | 1 #!/bin/bash | 
| root@51 | 2 #============================================================================ | 
| root@51 | 3 # Default Xen network start/stop script. | 
| root@51 | 4 # Xend calls a network script when it starts. | 
| root@51 | 5 # The script name to use is defined in /etc/xen/xend-config.sxp | 
| root@51 | 6 # in the network-script field. | 
| root@51 | 7 # | 
| root@51 | 8 # This script creates a bridge (default xenbr${vifnum}), adds a device | 
| root@51 | 9 # (default eth${vifnum}) to it, copies the IP addresses from the device | 
| root@51 | 10 # to the bridge and adjusts the routes accordingly. | 
| root@51 | 11 # | 
| root@51 | 12 # If all goes well, this should ensure that networking stays up. | 
| root@51 | 13 # However, some configurations are upset by this, especially | 
| root@51 | 14 # NFS roots. If the bridged setup does not meet your needs, | 
| root@51 | 15 # configure a different script, for example using routing instead. | 
| root@51 | 16 # | 
| root@51 | 17 # Usage: | 
| root@51 | 18 # | 
| root@51 | 19 # network-bridge (start|stop|status) {VAR=VAL}* | 
| root@51 | 20 # | 
| root@51 | 21 # Vars: | 
| root@51 | 22 # | 
| root@51 | 23 # vifnum     Virtual device number to use (default 0). Numbers >=8 | 
| root@51 | 24 #            require the netback driver to have nloopbacks set to a | 
| root@51 | 25 #            higher value than its default of 8. | 
| root@51 | 26 # bridge     The bridge to use (default xenbr${vifnum}). | 
| root@51 | 27 # netdev     The interface to add to the bridge (default eth${vifnum}). | 
| root@51 | 28 # antispoof  Whether to use iptables to prevent spoofing (default no). | 
| root@51 | 29 # | 
| root@51 | 30 # Internal Vars: | 
| root@51 | 31 # pdev="p${netdev}" | 
| root@51 | 32 # vdev="veth${vifnum}" | 
| root@51 | 33 # vif0="vif0.${vifnum}" | 
| root@51 | 34 # | 
| root@51 | 35 # start: | 
| root@51 | 36 # Creates the bridge | 
| root@51 | 37 # Copies the IP and MAC addresses from netdev to vdev | 
| root@51 | 38 # Renames netdev to be pdev | 
| root@51 | 39 # Renames vdev to be netdev | 
| root@51 | 40 # Enslaves pdev, vdev to bridge | 
| root@51 | 41 # | 
| root@51 | 42 # stop: | 
| root@51 | 43 # Removes netdev from the bridge | 
| root@51 | 44 # Transfers addresses, routes from netdev to pdev | 
| root@51 | 45 # Renames netdev to vdev | 
| root@51 | 46 # Renames pdev to netdev | 
| root@51 | 47 # Deletes bridge | 
| root@51 | 48 # | 
| root@51 | 49 # status: | 
| root@51 | 50 # Print addresses, interfaces, routes | 
| root@51 | 51 # | 
| root@51 | 52 #============================================================================ | 
| root@51 | 53 | 
| root@51 | 54 | 
| root@51 | 55 dir=$(dirname "$0") | 
| root@51 | 56 . "$dir/xen-script-common.sh" | 
| root@51 | 57 . "$dir/xen-network-common.sh" | 
| root@51 | 58 | 
| root@51 | 59 findCommand "$@" | 
| root@51 | 60 evalVariables "$@" | 
| root@51 | 61 | 
| root@51 | 62 modprobe netloop > /dev/null 2>&1 || true | 
| root@51 | 63 | 
| root@51 | 64 vifnum=${vifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')} | 
| root@51 | 65 vifnum=${vifnum:-0} | 
| root@51 | 66 bridge=${bridge:-xenbr${vifnum}} | 
| root@51 | 67 netdev=${netdev:-eth${vifnum}} | 
| root@51 | 68 antispoof=${antispoof:-no} | 
| root@51 | 69 | 
| root@51 | 70 pdev="p${netdev}" | 
| root@51 | 71 vdev="veth${vifnum}" | 
| root@51 | 72 vif0="vif0.${vifnum}" | 
| root@51 | 73 | 
| root@51 | 74 get_ip_info() { | 
| root@51 | 75     addr_pfx=`ip addr show dev $1 | egrep '^ *inet' | sed -e 's/ *inet //' -e 's/ .*//'` | 
| root@51 | 76     gateway=`ip route show dev $1 | fgrep default | sed 's/default via //'` | 
| root@51 | 77 } | 
| root@51 | 78 | 
| root@51 | 79 do_ifup() { | 
| root@51 | 80     if ! ifup $1 ; then | 
| root@51 | 81         if [ ${addr_pfx} ] ; then | 
| root@51 | 82             # use the info from get_ip_info() | 
| root@51 | 83             ip addr flush $1 | 
| root@51 | 84             ip addr add ${addr_pfx} dev $1 | 
| root@51 | 85             ip link set dev $1 up | 
| root@51 | 86             [ ${gateway} ] && ip route add default via ${gateway} | 
| root@51 | 87         fi | 
| root@51 | 88     fi | 
| root@51 | 89 } | 
| root@51 | 90 | 
| root@51 | 91 # Usage: transfer_addrs src dst | 
| root@51 | 92 # Copy all IP addresses (including aliases) from device $src to device $dst. | 
| root@51 | 93 transfer_addrs () { | 
| root@51 | 94     local src=$1 | 
| root@51 | 95     local dst=$2 | 
| root@51 | 96     # Don't bother if $dst already has IP addresses. | 
| root@51 | 97     if ip addr show dev ${dst} | egrep -q '^ *inet ' ; then | 
| root@51 | 98         return | 
| root@51 | 99     fi | 
| root@51 | 100     # Address lines start with 'inet' and have the device in them. | 
| root@51 | 101     # Replace 'inet' with 'ip addr add' and change the device name $src | 
| root@51 | 102     # to 'dev $src'. | 
| root@51 | 103     ip addr show dev ${src} | egrep '^ *inet ' | sed -e " | 
| root@51 | 104 s/inet/ip addr add/ | 
| root@51 | 105 s@\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/[0-9]\+\)@\1@ | 
| root@51 | 106 s/${src}/dev ${dst}/ | 
| root@51 | 107 " | sh -e | 
| root@51 | 108     # Remove automatic routes on destination device | 
| root@51 | 109     ip route list | sed -ne " | 
| root@51 | 110 /dev ${dst}\( \|$\)/ { | 
| root@51 | 111   s/^/ip route del / | 
| root@51 | 112   p | 
| root@51 | 113 }" | sh -e | 
| root@51 | 114 } | 
| root@51 | 115 | 
| root@51 | 116 # Usage: transfer_routes src dst | 
| root@51 | 117 # Get all IP routes to device $src, delete them, and | 
| root@51 | 118 # add the same routes to device $dst. | 
| root@51 | 119 # The original routes have to be deleted, otherwise adding them | 
| root@51 | 120 # for $dst fails (duplicate routes). | 
| root@51 | 121 transfer_routes () { | 
| root@51 | 122     local src=$1 | 
| root@51 | 123     local dst=$2 | 
| root@51 | 124     # List all routes and grep the ones with $src in. | 
| root@51 | 125     # Stick 'ip route del' on the front to delete. | 
| root@51 | 126     # Change $src to $dst and use 'ip route add' to add. | 
| root@51 | 127     ip route list | sed -ne " | 
| root@51 | 128 /dev ${src}\( \|$\)/ { | 
| root@51 | 129   h | 
| root@51 | 130   s/^/ip route del / | 
| root@51 | 131   P | 
| root@51 | 132   g | 
| root@51 | 133   s/${src}/${dst}/ | 
| root@51 | 134   s/^/ip route add / | 
| root@51 | 135   P | 
| root@51 | 136   d | 
| root@51 | 137 }" | sh -e | 
| root@51 | 138 } | 
| root@51 | 139 | 
| root@51 | 140 | 
| root@51 | 141 ## | 
| root@51 | 142 # link_exists interface | 
| root@51 | 143 # | 
| root@51 | 144 # Returns 0 if the interface named exists (whether up or down), 1 otherwise. | 
| root@51 | 145 # | 
| root@51 | 146 link_exists() | 
| root@51 | 147 { | 
| root@51 | 148     if ip link show "$1" >/dev/null 2>/dev/null | 
| root@51 | 149     then | 
| root@51 | 150         return 0 | 
| root@51 | 151     else | 
| root@51 | 152         return 1 | 
| root@51 | 153     fi | 
| root@51 | 154 } | 
| root@51 | 155 | 
| root@51 | 156 # Set the default forwarding policy for $dev to drop. | 
| root@51 | 157 # Allow forwarding to the bridge. | 
| root@51 | 158 antispoofing () { | 
| root@51 | 159     iptables -P FORWARD DROP | 
| root@51 | 160     iptables -F FORWARD | 
| root@51 | 161     iptables -A FORWARD -m physdev --physdev-in ${pdev} -j ACCEPT | 
| root@51 | 162     iptables -A FORWARD -m physdev --physdev-in ${vif0} -j ACCEPT | 
| root@51 | 163 } | 
| root@51 | 164 | 
| root@51 | 165 # Usage: show_status dev bridge | 
| root@51 | 166 # Print ifconfig and routes. | 
| root@51 | 167 show_status () { | 
| root@51 | 168     local dev=$1 | 
| root@51 | 169     local bridge=$2 | 
| root@51 | 170 | 
| root@51 | 171     echo '============================================================' | 
| root@51 | 172     ip addr show ${dev} | 
| root@51 | 173     ip addr show ${bridge} | 
| root@51 | 174     echo ' ' | 
| root@51 | 175     brctl show ${bridge} | 
| root@51 | 176     echo ' ' | 
| root@51 | 177     ip route list | 
| root@51 | 178     echo ' ' | 
| root@51 | 179     route -n | 
| root@51 | 180     echo '============================================================' | 
| root@51 | 181 } | 
| root@51 | 182 | 
| root@51 | 183 op_start () { | 
| root@51 | 184     if [ "${bridge}" = "null" ] ; then | 
| root@51 | 185 	return | 
| root@51 | 186     fi | 
| root@51 | 187 | 
| root@51 | 188     if ! link_exists "$vdev"; then | 
| root@51 | 189         if link_exists "$pdev"; then | 
| root@51 | 190             # The device is already up. | 
| root@51 | 191             return | 
| root@51 | 192         else | 
| root@51 | 193             echo " | 
| root@51 | 194 Link $vdev is missing. | 
| root@51 | 195 This may be because you have reached the limit of the number of interfaces | 
| root@51 | 196 that the loopback driver supports.  If the loopback driver is a module, you | 
| root@51 | 197 may raise this limit by passing it as a parameter (nloopbacks=<N>); if the | 
| root@51 | 198 driver is compiled statically into the kernel, then you may set the parameter | 
| root@51 | 199 using loopback.nloopbacks=<N> on the domain 0 kernel command line. | 
| root@51 | 200 " >&2 | 
| root@51 | 201             exit 1 | 
| root@51 | 202         fi | 
| root@51 | 203     fi | 
| root@51 | 204 | 
| root@51 | 205     create_bridge ${bridge} | 
| root@51 | 206 | 
| root@51 | 207     if link_exists "$vdev"; then | 
| root@51 | 208 	mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` | 
| root@51 | 209 	preiftransfer ${netdev} | 
| root@51 | 210 	transfer_addrs ${netdev} ${vdev} | 
| root@51 | 211 	if ! ifdown ${netdev}; then | 
| root@51 | 212 	    # If ifdown fails, remember the IP details. | 
| root@51 | 213 	    get_ip_info ${netdev} | 
| root@51 | 214 	    ip link set ${netdev} down | 
| root@51 | 215 	    ip addr flush ${netdev} | 
| root@51 | 216 	fi | 
| root@51 | 217 	ip link set ${netdev} name ${pdev} | 
| root@51 | 218 	ip link set ${vdev} name ${netdev} | 
| root@51 | 219 | 
| root@51 | 220 	setup_bridge_port ${pdev} | 
| root@51 | 221 	setup_bridge_port ${vif0} | 
| root@51 | 222 	ip link set ${netdev} addr ${mac} arp on | 
| root@51 | 223 | 
| root@51 | 224 	ip link set ${bridge} up | 
| root@51 | 225 	add_to_bridge  ${bridge} ${vif0} | 
| root@51 | 226 	add_to_bridge2 ${bridge} ${pdev} | 
| root@51 | 227 	do_ifup ${netdev} | 
| root@51 | 228     else | 
| root@51 | 229 	# old style without ${vdev} | 
| root@51 | 230 	transfer_addrs  ${netdev} ${bridge} | 
| root@51 | 231 	transfer_routes ${netdev} ${bridge} | 
| root@51 | 232     fi | 
| root@51 | 233 | 
| root@51 | 234     if [ ${antispoof} = 'yes' ] ; then | 
| root@51 | 235 	antispoofing | 
| root@51 | 236     fi | 
| root@51 | 237 } | 
| root@51 | 238 | 
| root@51 | 239 op_stop () { | 
| root@51 | 240     if [ "${bridge}" = "null" ]; then | 
| root@51 | 241 	return | 
| root@51 | 242     fi | 
| root@51 | 243     if ! link_exists "$bridge"; then | 
| root@51 | 244 	return | 
| root@51 | 245     fi | 
| root@51 | 246 | 
| root@51 | 247     if link_exists "$pdev"; then | 
| root@51 | 248 	ip link set dev ${vif0} down | 
| root@51 | 249 	mac=`ip link show ${netdev} | grep 'link\/ether' | sed -e 's/.*ether \(..:..:..:..:..:..\).*/\1/'` | 
| root@51 | 250 	transfer_addrs ${netdev} ${pdev} | 
| root@51 | 251 	if ! ifdown ${netdev}; then | 
| root@51 | 252 	    get_ip_info ${netdev} | 
| root@51 | 253 	fi | 
| root@51 | 254 	ip link set ${netdev} down arp off | 
| root@51 | 255 	ip link set ${netdev} addr fe:ff:ff:ff:ff:ff | 
| root@51 | 256 	ip link set ${pdev} down | 
| root@51 | 257 	ip addr flush ${netdev} | 
| root@51 | 258 	ip link set ${pdev} addr ${mac} arp on | 
| root@51 | 259 | 
| root@51 | 260 	brctl delif ${bridge} ${pdev} | 
| root@51 | 261 	brctl delif ${bridge} ${vif0} | 
| root@51 | 262 	ip link set ${bridge} down | 
| root@51 | 263 | 
| root@51 | 264 	ip link set ${netdev} name ${vdev} | 
| root@51 | 265 	ip link set ${pdev} name ${netdev} | 
| root@51 | 266 	do_ifup ${netdev} | 
| root@51 | 267     else | 
| root@51 | 268 	transfer_routes ${bridge} ${netdev} | 
| root@51 | 269 	ip link set ${bridge} down | 
| root@51 | 270     fi | 
| root@51 | 271     brctl delbr ${bridge} | 
| root@51 | 272 } | 
| root@51 | 273 | 
| root@51 | 274 # adds $dev to $bridge but waits for $dev to be in running state first | 
| root@51 | 275 add_to_bridge2() { | 
| root@51 | 276     local bridge=$1 | 
| root@51 | 277     local dev=$2 | 
| root@51 | 278     local maxtries=10 | 
| root@51 | 279 | 
| root@51 | 280     echo -n "Waiting for ${dev} to negotiate link." | 
| root@51 | 281     ip link set ${dev} up | 
| root@51 | 282     for i in `seq ${maxtries}` ; do | 
| root@51 | 283 	if ifconfig ${dev} | grep -q RUNNING ; then | 
| root@51 | 284 	    break | 
| root@51 | 285 	else | 
| root@51 | 286 	    echo -n '.' | 
| root@51 | 287 	    sleep 1 | 
| root@51 | 288 	fi | 
| root@51 | 289     done | 
| root@51 | 290 | 
| root@51 | 291     if [ ${i} -eq ${maxtries} ] ; then echo '(link isnt in running state)' ; fi | 
| root@51 | 292 | 
| root@51 | 293     add_to_bridge ${bridge} ${dev} | 
| root@51 | 294 } | 
| root@51 | 295 | 
| root@51 | 296 case "$command" in | 
| root@51 | 297     start) | 
| root@51 | 298 	op_start | 
| root@51 | 299 	;; | 
| root@51 | 300 | 
| root@51 | 301     stop) | 
| root@51 | 302 	op_stop | 
| root@51 | 303 	;; | 
| root@51 | 304 | 
| root@51 | 305     status) | 
| root@51 | 306 	show_status ${netdev} ${bridge} | 
| root@51 | 307 	;; | 
| root@51 | 308 | 
| root@51 | 309     *) | 
| root@51 | 310 	echo "Unknown command: $command" >&2 | 
| root@51 | 311 	echo 'Valid commands are: start, stop, status' >&2 | 
| root@51 | 312 	exit 1 | 
| root@51 | 313 esac |