1# 2# Copyright (c) 2005 XenSource Ltd. 3# 4# This library is free software; you can redistribute it and/or 5# modify it under the terms of version 2.1 of the GNU Lesser General Public 6# License as published by the Free Software Foundation. 7# 8# This library is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11# Lesser General Public License for more details. 12# 13# You should have received a copy of the GNU Lesser General Public 14# License along with this library; If not, see <http://www.gnu.org/licenses/>. 15# 16 17 18dir=$(dirname "$0") 19. "$dir/xen-hotplug-common.sh" 20. "$dir/xen-network-common.sh" 21 22findCommand "$@" 23 24if [ "$command" != "online" ] && 25 [ "$command" != "offline" ] && 26 [ "$command" != "add" ] && 27 [ "$command" != "remove" ] 28then 29 log err "Invalid command: $command" 30 exit 1 31fi 32 33 34# Parameters may be read from the environment, the command line arguments, and 35# the store, with overriding in that order. The environment is given by the 36# driver, the command line is given by the Xend global configuration, and 37# store details are given by the per-domain or per-device configuration. 38 39evalVariables "$@" 40 41# Older versions of Xen do not pass in the type as an argument, 42# so the default value is vif. 43: ${type_if:=vif} 44 45case "$type_if" in 46 vif) 47 dev=$vif 48 ;; 49 tap) 50 dev=$INTERFACE 51 ;; 52 *) 53 log err "unknown interface type $type_if" 54 exit 1 55 ;; 56esac 57 58case "$command" in 59 online | offline) 60 test "$type_if" != vif && exit 0 61 ;; 62 add | remove) 63 test "$type_if" != tap && exit 0 64 ;; 65esac 66 67rename_vif() { 68 local dev=$1 69 local vifname=$2 70 71 # if a custom vifname was chosen and a link with that desired name 72 # already exists, then stop, before messing up whatever is using 73 # that interface (e.g. another running domU) because it's likely a 74 # configuration error 75 if ip link show "$vifname" >&/dev/null 76 then 77 fatal "Cannot rename interface $dev. An interface with name $vifname already exists." 78 fi 79 do_or_die ip link set "$dev" name "$vifname" 80} 81 82if [ "$type_if" = vif ]; then 83 # Check presence of compulsory args. 84 XENBUS_PATH="${XENBUS_PATH:?}" 85 dev="${dev:?}" 86 87 vifname=$(xenstore_read_default "$XENBUS_PATH/vifname" "") 88 if [ "$vifname" ] 89 then 90 if [ "$command" == "online" ] 91 then 92 rename_vif "$dev" "$vifname" 93 fi 94 dev="$vifname" 95 fi 96elif [ "$type_if" = tap ]; then 97 # Check presence of compulsory args. 98 : ${INTERFACE:?} 99 100 # Get xenbus_path from device name. 101 # The name is built like that: "vif${domid}.${devid}-emu". 102 dev_=${dev#vif} 103 dev_=${dev_%-emu} 104 domid=${dev_%.*} 105 devid=${dev_#*.} 106 107 XENBUS_PATH="/local/domain/0/backend/vif/$domid/$devid" 108 vifname=$(xenstore_read_default "$XENBUS_PATH/vifname" "") 109 if [ "$vifname" ] 110 then 111 vifname="${vifname}-emu" 112 if [ "$command" == "add" ] 113 then 114 rename_vif "$dev" "$vifname" 115 fi 116 dev="$vifname" 117 fi 118fi 119 120ip=${ip:-} 121ip=$(xenstore_read_default "$XENBUS_PATH/ip" "$ip") 122 123IPTABLES_WAIT_RUNE="-w" 124IPTABLES_WAIT_RUNE_CHECKED=false 125 126# When iptables introduced locking, in the event of lock contention, 127# they made "fail" rather than "wait for the lock" the default 128# behavior. In order to select "wait for the lock" behavior, you have 129# to add the '-w' parameter. Unfortunately, both the locking and the 130# option were only introduced in 2013, and older versions of iptables 131# will fail if the '-w' parameter is included (since they don't 132# recognize it). So check to see if it's supported the first time we 133# use it. 134iptables_w() 135{ 136 if ! $IPTABLES_WAIT_RUNE_CHECKED ; then 137 iptables $IPTABLES_WAIT_RUNE -L -n >& /dev/null 138 if [[ $? == 0 ]] ; then 139 # If we succeed, then -w is supported; don't check again 140 IPTABLES_WAIT_RUNE_CHECKED=true 141 elif [[ $? == 2 ]] ; then 142 iptables -L -n >& /dev/null 143 if [[ $? != 2 ]] ; then 144 # If we fail with PARAMETER_PROBLEM (2) with -w and 145 # don't fail with PARAMETER_PROBLEM without it, then 146 # it's the -w option 147 IPTABLES_WAIT_RUNE_CHECKED=true 148 IPTABLES_WAIT_RUNE="" 149 fi 150 fi 151 fi 152 iptables $IPTABLES_WAIT_RUNE "$@" 153} 154 155frob_iptable() 156{ 157 if [ "$command" == "online" -o "$command" == "add" ] 158 then 159 local c="-I" 160 else 161 local c="-D" 162 fi 163 164 iptables_w "$c" FORWARD -m physdev --physdev-is-bridged --physdev-in "$dev" \ 165 "$@" -j ACCEPT 2>/dev/null && 166 iptables_w "$c" FORWARD -m physdev --physdev-is-bridged --physdev-out "$dev" \ 167 -j ACCEPT 2>/dev/null 168 169 if [ \( "$command" == "online" -o "$command" == "add" \) -a $? -ne 0 ] 170 then 171 log err "iptables setup failed. This may affect guest networking." 172 fi 173} 174 175 176## 177# Add or remove the appropriate entries in the iptables. With antispoofing 178# turned on, we have to explicitly allow packets to the interface, regardless 179# of the ip setting. If ip is set, then we additionally restrict the packets 180# to those coming from the specified networks, though we allow DHCP requests 181# as well. 182# 183handle_iptable() 184{ 185 # Check for a working iptables installation. Checking for the iptables 186 # binary is not sufficient, because the user may not have the appropriate 187 # modules installed. If iptables is not working, then there's no need to do 188 # anything with it, so we can just return. 189 if ! iptables_w -L -n >&/dev/null 190 then 191 return 192 fi 193 194 claim_lock "iptables" 195 196 if [ "$ip" != "" ] 197 then 198 local addr 199 for addr in $ip 200 do 201 frob_iptable -s "$addr" 202 done 203 204 # Always allow the domain to talk to a DHCP server. 205 frob_iptable -p udp --sport 68 --dport 67 206 else 207 # No IP addresses have been specified, so allow anything. 208 frob_iptable 209 fi 210 211 release_lock "iptables" 212} 213 214 215## 216# ip_of interface 217# 218# Print the IP address currently in use at the given interface, or nothing if 219# the interface is not up. 220# 221ip_of() 222{ 223 ip -4 -o addr show primary dev "$1" | awk '$3 == "inet" {split($4,i,"/"); print i[1]; exit}' 224} 225 226 227## 228# dom0_ip 229# 230# Print the IP address of the interface in dom0 through which we are routing. 231# This is the IP address on the interface specified as "netdev" as a parameter 232# to these scripts, or eth0 by default. This function will call fatal if no 233# such interface could be found. 234# 235dom0_ip() 236{ 237 local nd=${netdev:-eth0} 238 local result=$(ip_of "$nd") 239 if [ -z "$result" ] 240 then 241 fatal \ 242"$netdev is not up. Bring it up or specify another interface with " \ 243"netdev=<if> as a parameter to $0." 244 fi 245 echo "$result" 246} 247