Statistics
| Branch: | Tag: | Revision:

root / tools / kvm-ifup-os.in @ 65b526e7

History | View | Annotate | Download (8.8 kB)

1 dc1fe8df Jose A. Lopes
#!/bin/bash
2 dc1fe8df Jose A. Lopes
#
3 dc1fe8df Jose A. Lopes
4 dc1fe8df Jose A. Lopes
# Copyright (C) 2014 Google Inc.
5 dc1fe8df Jose A. Lopes
#
6 dc1fe8df Jose A. Lopes
# This program is free software; you can redistribute it and/or modify
7 dc1fe8df Jose A. Lopes
# it under the terms of the GNU General Public License as published by
8 dc1fe8df Jose A. Lopes
# the Free Software Foundation; either version 2 of the License, or
9 dc1fe8df Jose A. Lopes
# (at your option) any later version.
10 dc1fe8df Jose A. Lopes
#
11 dc1fe8df Jose A. Lopes
# This program is distributed in the hope that it will be useful, but
12 dc1fe8df Jose A. Lopes
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 dc1fe8df Jose A. Lopes
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 dc1fe8df Jose A. Lopes
# General Public License for more details.
15 dc1fe8df Jose A. Lopes
#
16 dc1fe8df Jose A. Lopes
# You should have received a copy of the GNU General Public License
17 dc1fe8df Jose A. Lopes
# along with this program; if not, write to the Free Software
18 dc1fe8df Jose A. Lopes
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 dc1fe8df Jose A. Lopes
# 02110-1301, USA.
20 dc1fe8df Jose A. Lopes
21 dc1fe8df Jose A. Lopes
# This script is a hook called to configure new TAP network interfaces
22 dc1fe8df Jose A. Lopes
# used for instance communication, and it should be called whenever a
23 dc1fe8df Jose A. Lopes
# new instance is started.
24 dc1fe8df Jose A. Lopes
#
25 dc1fe8df Jose A. Lopes
# This script configures the new interface but it also performs
26 dc1fe8df Jose A. Lopes
# maintenance on the network interfaces that have been configured
27 dc1fe8df Jose A. Lopes
# before, by checking whether those TAP interfaces still exist, etc.
28 dc1fe8df Jose A. Lopes
#
29 dc1fe8df Jose A. Lopes
# This script also controls the DHCP server that leases IP address for
30 dc1fe8df Jose A. Lopes
# instances, i.e., the NICs inside the instances, not the TAP
31 dc1fe8df Jose A. Lopes
# interfaces.  The DHCP server is started and restarted (or reHUPed)
32 dc1fe8df Jose A. Lopes
# as necessary and always with up-to-date configuration files.
33 dc1fe8df Jose A. Lopes
#
34 dc1fe8df Jose A. Lopes
# This script expects the following environment variables
35 dc1fe8df Jose A. Lopes
#
36 dc1fe8df Jose A. Lopes
#   INTERFACE: network interface name to be configured
37 dc1fe8df Jose A. Lopes
#   MODE: networking mode for 'INTERFACE' (must be 'routed')
38 dc1fe8df Jose A. Lopes
#   MAC: MAC address for 'INTERFACE'
39 dc1fe8df Jose A. Lopes
#   IP: IP address for 'INTERFACE'
40 dc1fe8df Jose A. Lopes
41 dc1fe8df Jose A. Lopes
source @PKGLIBDIR@/net-common
42 dc1fe8df Jose A. Lopes
43 dc1fe8df Jose A. Lopes
readonly NETMASK=255.255.255.255
44 dc1fe8df Jose A. Lopes
readonly DNSMASQ_CONF=/var/run/ganeti/dnsmasq.conf
45 dc1fe8df Jose A. Lopes
readonly DNSMASQ_HOSTS=/var/run/ganeti/dnsmasq.hosts
46 dc1fe8df Jose A. Lopes
readonly DNSMASQ_PID=/var/run/ganeti/dnsmasq.pid
47 dc1fe8df Jose A. Lopes
48 dc1fe8df Jose A. Lopes
# join intercalates a sequence of arguments using the given separator
49 dc1fe8df Jose A. Lopes
function join {
50 dc1fe8df Jose A. Lopes
  local IFS="$1"
51 dc1fe8df Jose A. Lopes
  shift
52 dc1fe8df Jose A. Lopes
  echo "$*"
53 dc1fe8df Jose A. Lopes
}
54 dc1fe8df Jose A. Lopes
55 dc1fe8df Jose A. Lopes
# restart_dnsmasq restarts the DHCP server dnsmasq with the (possibly
56 dc1fe8df Jose A. Lopes
# up-to-date) configuration file.
57 dc1fe8df Jose A. Lopes
#
58 dc1fe8df Jose A. Lopes
# If all instances have been terminated, which means there are no more
59 dc1fe8df Jose A. Lopes
# TAP network interfaces to monitor or IP addresses to lease, the DHCP
60 dc1fe8df Jose A. Lopes
# server is terminated through 'SIGTERM'.
61 dc1fe8df Jose A. Lopes
#
62 dc1fe8df Jose A. Lopes
# If there are still instances running, then:
63 dc1fe8df Jose A. Lopes
#  - if the DHCP server is running, a 'SIGHUP' will be sent to the
64 dc1fe8df Jose A. Lopes
#    dnsmasq process which will cause the configuration file to be
65 dc1fe8df Jose A. Lopes
#    re-read, while keeping the process running
66 dc1fe8df Jose A. Lopes
#  - if the DHCP server is not running, it will be started, and the
67 dc1fe8df Jose A. Lopes
#    configuration file will be passed it
68 dc1fe8df Jose A. Lopes
function restart_dnsmasq {
69 dc1fe8df Jose A. Lopes
  SIGNAL=
70 dc1fe8df Jose A. Lopes
71 dc1fe8df Jose A. Lopes
  if [ -z "$ALIVE_INTERFACES" -o -z "$ALIVE_LEASES" ]
72 dc1fe8df Jose A. Lopes
  then
73 dc1fe8df Jose A. Lopes
      SIGNAL=TERM
74 dc1fe8df Jose A. Lopes
  else
75 dc1fe8df Jose A. Lopes
      SIGNAL=HUP
76 dc1fe8df Jose A. Lopes
  fi
77 dc1fe8df Jose A. Lopes
78 dc1fe8df Jose A. Lopes
  RUNNING=
79 dc1fe8df Jose A. Lopes
80 dc1fe8df Jose A. Lopes
  if [ -f "$DNSMASQ_PID" ]
81 dc1fe8df Jose A. Lopes
  then
82 dc1fe8df Jose A. Lopes
      PID=$(cat $DNSMASQ_PID)
83 dc1fe8df Jose A. Lopes
      if [ -n "$PID" ] && ps -p "$PID"
84 dc1fe8df Jose A. Lopes
      then
85 dc1fe8df Jose A. Lopes
	  RUNNING=yes
86 dc1fe8df Jose A. Lopes
      fi
87 dc1fe8df Jose A. Lopes
  fi
88 dc1fe8df Jose A. Lopes
89 dc1fe8df Jose A. Lopes
  KILLED=
90 dc1fe8df Jose A. Lopes
91 dc1fe8df Jose A. Lopes
  if [ "$RUNNING" = yes ]
92 dc1fe8df Jose A. Lopes
  then
93 dc1fe8df Jose A. Lopes
      kill -$SIGNAL $PID
94 dc1fe8df Jose A. Lopes
95 dc1fe8df Jose A. Lopes
      if [ "$SIGNAL" = TERM ]
96 dc1fe8df Jose A. Lopes
      then
97 dc1fe8df Jose A. Lopes
	  KILLED=yes
98 dc1fe8df Jose A. Lopes
      fi
99 dc1fe8df Jose A. Lopes
  fi
100 dc1fe8df Jose A. Lopes
101 dc1fe8df Jose A. Lopes
  if [ "$KILLED" = yes ]
102 dc1fe8df Jose A. Lopes
  then
103 dc1fe8df Jose A. Lopes
      rm -f $DNSMASQ_PID
104 dc1fe8df Jose A. Lopes
  fi
105 dc1fe8df Jose A. Lopes
106 dc1fe8df Jose A. Lopes
  if [ "$RUNNING" != yes -o "$KILLED" == yes ]
107 dc1fe8df Jose A. Lopes
  then
108 dc1fe8df Jose A. Lopes
      if [ -n "$ALIVE_INTERFACES" -a -n "$ALIVE_LEASES" ]
109 dc1fe8df Jose A. Lopes
      then
110 dc1fe8df Jose A. Lopes
	  dnsmasq -C $DNSMASQ_CONF
111 dc1fe8df Jose A. Lopes
      fi
112 dc1fe8df Jose A. Lopes
  fi
113 dc1fe8df Jose A. Lopes
114 dc1fe8df Jose A. Lopes
  return 0
115 dc1fe8df Jose A. Lopes
}
116 dc1fe8df Jose A. Lopes
117 dc1fe8df Jose A. Lopes
# Check that environment variable 'INTERFACE' exists.
118 dc1fe8df Jose A. Lopes
#
119 dc1fe8df Jose A. Lopes
# This environment variable holds the TAP network interface that
120 dc1fe8df Jose A. Lopes
# should be configured by this script.  Ganeti always passes it,
121 dc1fe8df Jose A. Lopes
# but... :)
122 dc1fe8df Jose A. Lopes
if [ -z "$INTERFACE" ]
123 dc1fe8df Jose A. Lopes
then
124 dc1fe8df Jose A. Lopes
  echo kvm-vif-bridge: Failed to configure communication mechanism \
125 dc1fe8df Jose A. Lopes
      interface because the \'INTERFACE\' environment variable was \
126 dc1fe8df Jose A. Lopes
      not specified to the \'kvm-vif-bridge\' script
127 dc1fe8df Jose A. Lopes
  exit 1
128 dc1fe8df Jose A. Lopes
fi
129 dc1fe8df Jose A. Lopes
130 dc1fe8df Jose A. Lopes
# Check that environment variable 'MODE' exists.
131 dc1fe8df Jose A. Lopes
#
132 dc1fe8df Jose A. Lopes
# See comment about environment variable 'INTERFACE'.
133 dc1fe8df Jose A. Lopes
if [ -z "$MODE" ]
134 dc1fe8df Jose A. Lopes
then
135 dc1fe8df Jose A. Lopes
  echo kvm-vif-bridge: Failed to configure communication mechanism \
136 dc1fe8df Jose A. Lopes
      interface because the \'MODE\' environment variable was \
137 dc1fe8df Jose A. Lopes
      not specified to the \'kvm-vif-bridge\' script
138 dc1fe8df Jose A. Lopes
  exit 1
139 dc1fe8df Jose A. Lopes
fi
140 dc1fe8df Jose A. Lopes
141 dc1fe8df Jose A. Lopes
# Check whether the interface being configured has instance
142 dc1fe8df Jose A. Lopes
# communication enabled, otherwise exit this script.
143 dc1fe8df Jose A. Lopes
if ! is_instance_communication_tap; then exit 0; fi
144 dc1fe8df Jose A. Lopes
145 dc1fe8df Jose A. Lopes
# Check that environment variable 'MAC' exists.
146 dc1fe8df Jose A. Lopes
#
147 dc1fe8df Jose A. Lopes
# See comment about environment variable 'INTERFACE'.
148 dc1fe8df Jose A. Lopes
if [ -z "$MAC" ]
149 dc1fe8df Jose A. Lopes
then
150 dc1fe8df Jose A. Lopes
  echo kvm-vif-bridge: Failed to configure communication mechanism \
151 dc1fe8df Jose A. Lopes
      interface because the \'MAC\' environment variable was \
152 dc1fe8df Jose A. Lopes
      not specified to the \'kvm-vif-bridge\' script
153 dc1fe8df Jose A. Lopes
  exit 1
154 dc1fe8df Jose A. Lopes
fi
155 dc1fe8df Jose A. Lopes
156 dc1fe8df Jose A. Lopes
# Check that environment variable 'IP' exists.
157 dc1fe8df Jose A. Lopes
#
158 dc1fe8df Jose A. Lopes
# See comment about environment variable 'INTERFACE'.
159 dc1fe8df Jose A. Lopes
if [ -z "$IP" ]
160 dc1fe8df Jose A. Lopes
then
161 dc1fe8df Jose A. Lopes
  echo kvm-vif-bridge: Failed to configure communication mechanism \
162 dc1fe8df Jose A. Lopes
      interface because the \'IP\' environment variable was \
163 dc1fe8df Jose A. Lopes
      not specified to the \'kvm-vif-bridge\' script
164 dc1fe8df Jose A. Lopes
  exit 1
165 dc1fe8df Jose A. Lopes
fi
166 dc1fe8df Jose A. Lopes
167 dc1fe8df Jose A. Lopes
# Configure the TAP interface
168 dc1fe8df Jose A. Lopes
#
169 dc1fe8df Jose A. Lopes
# Ganeti defers the configuration of instance network interfaces to
170 dc1fe8df Jose A. Lopes
# hooks, therefore, we must configure the interface's network address,
171 dc1fe8df Jose A. Lopes
# netmask, and IP address.
172 dc1fe8df Jose A. Lopes
#
173 dc1fe8df Jose A. Lopes
# The TAP network interface, which is used by the instance
174 dc1fe8df Jose A. Lopes
# communication, is part of the network 169.254.0.0/16 and has the IP
175 dc1fe8df Jose A. Lopes
# 169.254.169.254.  Because all network interfaces used in the
176 dc1fe8df Jose A. Lopes
# instance communication have the same IP, the routing table must also
177 dc1fe8df Jose A. Lopes
# be configured, and that is done at a later step.
178 dc1fe8df Jose A. Lopes
#
179 dc1fe8df Jose A. Lopes
# Note the interface must be marked as up before configuring the
180 dc1fe8df Jose A. Lopes
# routing table and before starting/restarting the DHCP server.
181 dc1fe8df Jose A. Lopes
#
182 dc1fe8df Jose A. Lopes
# Note also that we don't have to check whether the interface is
183 dc1fe8df Jose A. Lopes
# already configured because reconfiguring the interface with the same
184 dc1fe8df Jose A. Lopes
# parameters does not produce an error.
185 dc1fe8df Jose A. Lopes
ifconfig $INTERFACE 169.254.169.254 netmask $NETMASK up
186 dc1fe8df Jose A. Lopes
187 dc1fe8df Jose A. Lopes
# Configure the routing table
188 dc1fe8df Jose A. Lopes
#
189 dc1fe8df Jose A. Lopes
# Given that all TAP network interfaces in the instance communication
190 dc1fe8df Jose A. Lopes
# have the same IP address, the routing table must be configured in
191 dc1fe8df Jose A. Lopes
# order to properly route traffic from the host to the guests.
192 dc1fe8df Jose A. Lopes
#
193 dc1fe8df Jose A. Lopes
# Note that we must first check if a duplicate routing rule has
194 dc1fe8df Jose A. Lopes
# already been added to the routing table, as this operation will fail
195 dc1fe8df Jose A. Lopes
# if we try to add a routing rule that already exists.
196 dc1fe8df Jose A. Lopes
ACTIVE_IP=$(ip route | grep "dev $INTERFACE" | awk '{ print $1 }')
197 dc1fe8df Jose A. Lopes
198 dc1fe8df Jose A. Lopes
if [ -z "$ACTIVE_IP" -o "$ACTIVE_IP" != "$IP" ]
199 dc1fe8df Jose A. Lopes
then
200 dc1fe8df Jose A. Lopes
  route add -host $IP dev $INTERFACE
201 dc1fe8df Jose A. Lopes
fi
202 dc1fe8df Jose A. Lopes
203 dc1fe8df Jose A. Lopes
# Ensure the DHCP server configuration files exist
204 dc1fe8df Jose A. Lopes
touch $DNSMASQ_CONF
205 dc1fe8df Jose A. Lopes
chmod 0644 $DNSMASQ_CONF
206 dc1fe8df Jose A. Lopes
207 dc1fe8df Jose A. Lopes
touch $DNSMASQ_HOSTS
208 dc1fe8df Jose A. Lopes
chmod 0644 $DNSMASQ_HOSTS
209 dc1fe8df Jose A. Lopes
210 dc1fe8df Jose A. Lopes
# Determine dnsmasq operational mode.
211 dc1fe8df Jose A. Lopes
#
212 dc1fe8df Jose A. Lopes
# The DHCP server dnsmasq can run in different modes.  In this version
213 dc1fe8df Jose A. Lopes
# of the script, only the mode 'bind-dynamic' is supported.  Please
214 dc1fe8df Jose A. Lopes
# refer to the dnsmasq FAQ for a detailed of each mode.
215 dc1fe8df Jose A. Lopes
#
216 dc1fe8df Jose A. Lopes
# Note that dnsmasq might already be running, therefore, we don't need
217 dc1fe8df Jose A. Lopes
# to determine which modes are supported by this DHCP server.
218 dc1fe8df Jose A. Lopes
# Instead, we just read the current mode from the configuration file.
219 dc1fe8df Jose A. Lopes
DNSMASQ_MODE=$(head -n 1 $DNSMASQ_CONF)
220 dc1fe8df Jose A. Lopes
221 dc1fe8df Jose A. Lopes
if [ -z "$DNSMASQ_MODE" ]
222 dc1fe8df Jose A. Lopes
then
223 dc1fe8df Jose A. Lopes
  BIND_DYNAMIC=$(dnsmasq --help | grep -e --bind-dynamic)
224 dc1fe8df Jose A. Lopes
225 dc1fe8df Jose A. Lopes
  if [ -z "$BIND_DYNAMIC" ]
226 dc1fe8df Jose A. Lopes
  then
227 dc1fe8df Jose A. Lopes
    echo kvm-vif-bridge: dnsmasq mode \"bind-dynamic\" is not supported
228 dc1fe8df Jose A. Lopes
    exit 1
229 dc1fe8df Jose A. Lopes
  fi
230 dc1fe8df Jose A. Lopes
231 dc1fe8df Jose A. Lopes
  DNSMASQ_MODE=bind-dynamic
232 dc1fe8df Jose A. Lopes
fi
233 dc1fe8df Jose A. Lopes
234 dc1fe8df Jose A. Lopes
# Determine the interfaces that should go in the configuration file.
235 dc1fe8df Jose A. Lopes
#
236 dc1fe8df Jose A. Lopes
# The TAP network interfaces used by the instance communication are
237 dc1fe8df Jose A. Lopes
# named after the following pattern
238 dc1fe8df Jose A. Lopes
#
239 dc1fe8df Jose A. Lopes
#  gnt.com.%d
240 dc1fe8df Jose A. Lopes
#
241 dc1fe8df Jose A. Lopes
# where '%d' is a unique number within the host.  Fortunately, dnsmasq
242 dc1fe8df Jose A. Lopes
# supports binding to specific network interfaces via a pattern.
243 dc1fe8df Jose A. Lopes
ALIVE_INTERFACES=${GANETI_TAP}.*
244 dc1fe8df Jose A. Lopes
245 dc1fe8df Jose A. Lopes
# Determine which of the leases are not duplicated and should go in
246 dc1fe8df Jose A. Lopes
# the new configuration file for the DHCP server.
247 dc1fe8df Jose A. Lopes
#
248 dc1fe8df Jose A. Lopes
# Given that instances come and go, it is possible that we offer more
249 dc1fe8df Jose A. Lopes
# leases that necessary and, worse, that we have duplicate leases,
250 dc1fe8df Jose A. Lopes
# that is, the same IP address for the same/different MAC addresses.
251 dc1fe8df Jose A. Lopes
# Duplicate leases must be eliminated before being written to the
252 dc1fe8df Jose A. Lopes
# configuration file.
253 dc1fe8df Jose A. Lopes
CONF_LEASES=$(cat $DNSMASQ_HOSTS)
254 dc1fe8df Jose A. Lopes
CONF_LEASES=$(join $'\n' $CONF_LEASES | sort -u)
255 dc1fe8df Jose A. Lopes
256 dc1fe8df Jose A. Lopes
ALIVE_LEASES=( $MAC,$IP )
257 dc1fe8df Jose A. Lopes
258 dc1fe8df Jose A. Lopes
for i in $CONF_LEASES
259 dc1fe8df Jose A. Lopes
do
260 dc1fe8df Jose A. Lopes
  LEASE_MAC=$(echo $i | cut -d "," -f 1)
261 dc1fe8df Jose A. Lopes
  LEASE_IP=$(echo $i | cut -d "," -f 2)
262 dc1fe8df Jose A. Lopes
  if [ "$LEASE_MAC" != "$MAC" -a "$LEASE_IP" != "$IP" ]
263 dc1fe8df Jose A. Lopes
  then
264 dc1fe8df Jose A. Lopes
      ALIVE_LEASES=( ${ALIVE_LEASES[@]} $i )
265 dc1fe8df Jose A. Lopes
  fi
266 dc1fe8df Jose A. Lopes
done
267 dc1fe8df Jose A. Lopes
268 dc1fe8df Jose A. Lopes
ALIVE_LEASES=$(echo ${ALIVE_LEASES[@]} | sort -u)
269 dc1fe8df Jose A. Lopes
270 dc1fe8df Jose A. Lopes
# Update dnsmasq configuration.
271 dc1fe8df Jose A. Lopes
#
272 dc1fe8df Jose A. Lopes
# Write the parameters we have collected before into the new dnsmasq
273 dc1fe8df Jose A. Lopes
# configuration file.  Also, write the new leases into the new dnsmasq
274 dc1fe8df Jose A. Lopes
# hosts file.  Finally, restart dnsmasq with the new configuration
275 dc1fe8df Jose A. Lopes
# files.
276 dc1fe8df Jose A. Lopes
cat > $DNSMASQ_CONF <<EOF
277 dc1fe8df Jose A. Lopes
$DNSMASQ_MODE
278 dc1fe8df Jose A. Lopes
dhcp-authoritative
279 dc1fe8df Jose A. Lopes
dhcp-hostsfile=$DNSMASQ_HOSTS
280 dc1fe8df Jose A. Lopes
dhcp-range=169.254.0.0,static,255.255.0.0
281 dc1fe8df Jose A. Lopes
except-interface=eth*
282 dc1fe8df Jose A. Lopes
except-interface=lo
283 dc1fe8df Jose A. Lopes
leasefile-ro
284 dc1fe8df Jose A. Lopes
no-hosts
285 dc1fe8df Jose A. Lopes
no-ping
286 dc1fe8df Jose A. Lopes
no-resolv
287 dc1fe8df Jose A. Lopes
pid-file=$DNSMASQ_PID
288 dc1fe8df Jose A. Lopes
port=0
289 dc1fe8df Jose A. Lopes
strict-order
290 dc1fe8df Jose A. Lopes
EOF
291 dc1fe8df Jose A. Lopes
for i in $ALIVE_INTERFACES; do echo interface=$i >> $DNSMASQ_CONF; done
292 dc1fe8df Jose A. Lopes
293 dc1fe8df Jose A. Lopes
echo -n > $DNSMASQ_HOSTS
294 dc1fe8df Jose A. Lopes
for i in $ALIVE_LEASES; do echo $i >> $DNSMASQ_HOSTS; done
295 dc1fe8df Jose A. Lopes
296 dc1fe8df Jose A. Lopes
restart_dnsmasq