Revision dc1fe8df

b/Makefile.am
95 95
iallocatorsdir = $(pkglibdir)/iallocators
96 96
pytoolsdir = $(pkgpythondir)/tools
97 97
docdir = $(versiondir)$(datadir)/doc/$(PACKAGE)
98
ifupdir = $(sysconfdir)/ganeti
98 99

  
99 100
SYMLINK_TARGET_DIRS = \
100 101
	$(sysconfdir)/ganeti \
......
258 259
	$(man_MANS) \
259 260
	$(manhtml) \
260 261
	tools/kvm-ifup \
262
	tools/kvm-ifup-os \
261 263
	tools/vif-ganeti \
262 264
	tools/net-common \
263 265
	tools/users-setup \
......
320 322
	doc/examples/gnt-config-backup \
321 323
	doc/examples/hooks/ipsec
322 324

  
325
dist_ifup_SCRIPTS = \
326
	tools/kvm-ifup-os
327

  
323 328
nodist_pkgpython_PYTHON = \
324 329
	$(BUILT_PYTHON_SOURCES)
325 330

  
......
1131 1136
myexeclib_SCRIPTS = \
1132 1137
	daemons/daemon-util \
1133 1138
	tools/kvm-ifup \
1139
	tools/kvm-ifup-os \
1134 1140
	tools/vif-ganeti \
1135 1141
	tools/net-common \
1136 1142
	$(HS_MYEXECLIB_PROGS)
......
1169 1175
	devel/upload \
1170 1176
	devel/webserver \
1171 1177
	tools/kvm-ifup.in \
1178
	tools/kvm-ifup-os.in \
1172 1179
	tools/vif-ganeti.in \
1173 1180
	tools/net-common.in \
1174 1181
	tools/vcluster-setup.in \
......
1653 1660
	sed -f $(REPLACE_VARS_SED) < $< > $@
1654 1661
	chmod +x $@
1655 1662

  
1663
tools/kvm-ifup-os: tools/kvm-ifup-os.in $(REPLACE_VARS_SED)
1664
	sed -f $(REPLACE_VARS_SED) < $< > $@
1665
	chmod +x $@
1666

  
1656 1667
tools/vif-ganeti: tools/vif-ganeti.in $(REPLACE_VARS_SED)
1657 1668
	sed -f $(REPLACE_VARS_SED) < $< > $@
1658 1669
	chmod +x $@
b/tools/kvm-ifup-os.in
1
#!/bin/bash
2
#
3

  
4
# Copyright (C) 2014 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21
# This script is a hook called to configure new TAP network interfaces
22
# used for instance communication, and it should be called whenever a
23
# new instance is started.
24
#
25
# This script configures the new interface but it also performs
26
# maintenance on the network interfaces that have been configured
27
# before, by checking whether those TAP interfaces still exist, etc.
28
#
29
# This script also controls the DHCP server that leases IP address for
30
# instances, i.e., the NICs inside the instances, not the TAP
31
# interfaces.  The DHCP server is started and restarted (or reHUPed)
32
# as necessary and always with up-to-date configuration files.
33
#
34
# This script expects the following environment variables
35
#
36
#   INTERFACE: network interface name to be configured
37
#   MODE: networking mode for 'INTERFACE' (must be 'routed')
38
#   MAC: MAC address for 'INTERFACE'
39
#   IP: IP address for 'INTERFACE'
40

  
41
source @PKGLIBDIR@/net-common
42

  
43
readonly NETMASK=255.255.255.255
44
readonly DNSMASQ_CONF=/var/run/ganeti/dnsmasq.conf
45
readonly DNSMASQ_HOSTS=/var/run/ganeti/dnsmasq.hosts
46
readonly DNSMASQ_PID=/var/run/ganeti/dnsmasq.pid
47

  
48
# join intercalates a sequence of arguments using the given separator
49
function join {
50
  local IFS="$1"
51
  shift
52
  echo "$*"
53
}
54

  
55
# restart_dnsmasq restarts the DHCP server dnsmasq with the (possibly
56
# up-to-date) configuration file.
57
#
58
# If all instances have been terminated, which means there are no more
59
# TAP network interfaces to monitor or IP addresses to lease, the DHCP
60
# server is terminated through 'SIGTERM'.
61
#
62
# If there are still instances running, then:
63
#  - if the DHCP server is running, a 'SIGHUP' will be sent to the
64
#    dnsmasq process which will cause the configuration file to be
65
#    re-read, while keeping the process running
66
#  - if the DHCP server is not running, it will be started, and the
67
#    configuration file will be passed it
68
function restart_dnsmasq {
69
  SIGNAL=
70

  
71
  if [ -z "$ALIVE_INTERFACES" -o -z "$ALIVE_LEASES" ]
72
  then
73
      SIGNAL=TERM
74
  else
75
      SIGNAL=HUP
76
  fi
77

  
78
  RUNNING=
79

  
80
  if [ -f "$DNSMASQ_PID" ]
81
  then
82
      PID=$(cat $DNSMASQ_PID)
83
      if [ -n "$PID" ] && ps -p "$PID"
84
      then
85
	  RUNNING=yes
86
      fi
87
  fi
88

  
89
  KILLED=
90

  
91
  if [ "$RUNNING" = yes ]
92
  then
93
      kill -$SIGNAL $PID
94

  
95
      if [ "$SIGNAL" = TERM ]
96
      then
97
	  KILLED=yes
98
      fi
99
  fi
100

  
101
  if [ "$KILLED" = yes ]
102
  then
103
      rm -f $DNSMASQ_PID
104
  fi
105

  
106
  if [ "$RUNNING" != yes -o "$KILLED" == yes ]
107
  then
108
      if [ -n "$ALIVE_INTERFACES" -a -n "$ALIVE_LEASES" ]
109
      then
110
	  dnsmasq -C $DNSMASQ_CONF
111
      fi
112
  fi
113

  
114
  return 0
115
}
116

  
117
# Check that environment variable 'INTERFACE' exists.
118
#
119
# This environment variable holds the TAP network interface that
120
# should be configured by this script.  Ganeti always passes it,
121
# but... :)
122
if [ -z "$INTERFACE" ]
123
then
124
  echo kvm-vif-bridge: Failed to configure communication mechanism \
125
      interface because the \'INTERFACE\' environment variable was \
126
      not specified to the \'kvm-vif-bridge\' script
127
  exit 1
128
fi
129

  
130
# Check that environment variable 'MODE' exists.
131
#
132
# See comment about environment variable 'INTERFACE'.
133
if [ -z "$MODE" ]
134
then
135
  echo kvm-vif-bridge: Failed to configure communication mechanism \
136
      interface because the \'MODE\' environment variable was \
137
      not specified to the \'kvm-vif-bridge\' script
138
  exit 1
139
fi
140

  
141
# Check whether the interface being configured has instance
142
# communication enabled, otherwise exit this script.
143
if ! is_instance_communication_tap; then exit 0; fi
144

  
145
# Check that environment variable 'MAC' exists.
146
#
147
# See comment about environment variable 'INTERFACE'.
148
if [ -z "$MAC" ]
149
then
150
  echo kvm-vif-bridge: Failed to configure communication mechanism \
151
      interface because the \'MAC\' environment variable was \
152
      not specified to the \'kvm-vif-bridge\' script
153
  exit 1
154
fi
155

  
156
# Check that environment variable 'IP' exists.
157
#
158
# See comment about environment variable 'INTERFACE'.
159
if [ -z "$IP" ]
160
then
161
  echo kvm-vif-bridge: Failed to configure communication mechanism \
162
      interface because the \'IP\' environment variable was \
163
      not specified to the \'kvm-vif-bridge\' script
164
  exit 1
165
fi
166

  
167
# Configure the TAP interface
168
#
169
# Ganeti defers the configuration of instance network interfaces to
170
# hooks, therefore, we must configure the interface's network address,
171
# netmask, and IP address.
172
#
173
# The TAP network interface, which is used by the instance
174
# communication, is part of the network 169.254.0.0/16 and has the IP
175
# 169.254.169.254.  Because all network interfaces used in the
176
# instance communication have the same IP, the routing table must also
177
# be configured, and that is done at a later step.
178
#
179
# Note the interface must be marked as up before configuring the
180
# routing table and before starting/restarting the DHCP server.
181
#
182
# Note also that we don't have to check whether the interface is
183
# already configured because reconfiguring the interface with the same
184
# parameters does not produce an error.
185
ifconfig $INTERFACE 169.254.169.254 netmask $NETMASK up
186

  
187
# Configure the routing table
188
#
189
# Given that all TAP network interfaces in the instance communication
190
# have the same IP address, the routing table must be configured in
191
# order to properly route traffic from the host to the guests.
192
#
193
# Note that we must first check if a duplicate routing rule has
194
# already been added to the routing table, as this operation will fail
195
# if we try to add a routing rule that already exists.
196
ACTIVE_IP=$(ip route | grep "dev $INTERFACE" | awk '{ print $1 }')
197

  
198
if [ -z "$ACTIVE_IP" -o "$ACTIVE_IP" != "$IP" ]
199
then
200
  route add -host $IP dev $INTERFACE
201
fi
202

  
203
# Ensure the DHCP server configuration files exist
204
touch $DNSMASQ_CONF
205
chmod 0644 $DNSMASQ_CONF
206

  
207
touch $DNSMASQ_HOSTS
208
chmod 0644 $DNSMASQ_HOSTS
209

  
210
# Determine dnsmasq operational mode.
211
#
212
# The DHCP server dnsmasq can run in different modes.  In this version
213
# of the script, only the mode 'bind-dynamic' is supported.  Please
214
# refer to the dnsmasq FAQ for a detailed of each mode.
215
#
216
# Note that dnsmasq might already be running, therefore, we don't need
217
# to determine which modes are supported by this DHCP server.
218
# Instead, we just read the current mode from the configuration file.
219
DNSMASQ_MODE=$(head -n 1 $DNSMASQ_CONF)
220

  
221
if [ -z "$DNSMASQ_MODE" ]
222
then
223
  BIND_DYNAMIC=$(dnsmasq --help | grep -e --bind-dynamic)
224

  
225
  if [ -z "$BIND_DYNAMIC" ]
226
  then
227
    echo kvm-vif-bridge: dnsmasq mode \"bind-dynamic\" is not supported
228
    exit 1
229
  fi
230

  
231
  DNSMASQ_MODE=bind-dynamic
232
fi
233

  
234
# Determine the interfaces that should go in the configuration file.
235
#
236
# The TAP network interfaces used by the instance communication are
237
# named after the following pattern
238
#
239
#  gnt.com.%d
240
#
241
# where '%d' is a unique number within the host.  Fortunately, dnsmasq
242
# supports binding to specific network interfaces via a pattern.
243
ALIVE_INTERFACES=${GANETI_TAP}.*
244

  
245
# Determine which of the leases are not duplicated and should go in
246
# the new configuration file for the DHCP server.
247
#
248
# Given that instances come and go, it is possible that we offer more
249
# leases that necessary and, worse, that we have duplicate leases,
250
# that is, the same IP address for the same/different MAC addresses.
251
# Duplicate leases must be eliminated before being written to the
252
# configuration file.
253
CONF_LEASES=$(cat $DNSMASQ_HOSTS)
254
CONF_LEASES=$(join $'\n' $CONF_LEASES | sort -u)
255

  
256
ALIVE_LEASES=( $MAC,$IP )
257

  
258
for i in $CONF_LEASES
259
do
260
  LEASE_MAC=$(echo $i | cut -d "," -f 1)
261
  LEASE_IP=$(echo $i | cut -d "," -f 2)
262
  if [ "$LEASE_MAC" != "$MAC" -a "$LEASE_IP" != "$IP" ]
263
  then
264
      ALIVE_LEASES=( ${ALIVE_LEASES[@]} $i )
265
  fi
266
done
267

  
268
ALIVE_LEASES=$(echo ${ALIVE_LEASES[@]} | sort -u)
269

  
270
# Update dnsmasq configuration.
271
#
272
# Write the parameters we have collected before into the new dnsmasq
273
# configuration file.  Also, write the new leases into the new dnsmasq
274
# hosts file.  Finally, restart dnsmasq with the new configuration
275
# files.
276
cat > $DNSMASQ_CONF <<EOF
277
$DNSMASQ_MODE
278
dhcp-authoritative
279
dhcp-hostsfile=$DNSMASQ_HOSTS
280
dhcp-range=169.254.0.0,static,255.255.0.0
281
except-interface=eth*
282
except-interface=lo
283
leasefile-ro
284
no-hosts
285
no-ping
286
no-resolv
287
pid-file=$DNSMASQ_PID
288
port=0
289
strict-order
290
EOF
291
for i in $ALIVE_INTERFACES; do echo interface=$i >> $DNSMASQ_CONF; done
292

  
293
echo -n > $DNSMASQ_HOSTS
294
for i in $ALIVE_LEASES; do echo $i >> $DNSMASQ_HOSTS; done
295

  
296
restart_dnsmasq
b/tools/kvm-ifup.in
1 1
#!/bin/bash
2 2
#
3 3

  
4
# Copyright (C) 2011, 2012 Google Inc.
4
# Copyright (C) 2011, 2012, 2014 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
20 20

  
21 21
source @PKGLIBDIR@/net-common
22 22

  
23
check
24

  
25
# Execute the script for setting up the communication with the
26
# instance OS
27
if is_instance_communication_tap && [ -x "$CONF_DIR/kvm-ifup-os" ]; then
28
  . $CONF_DIR/kvm-ifup-os
29
fi
30

  
23 31
# Execute the user-supplied network script, if applicable
24 32
if [ -x "$CONF_DIR/kvm-vif-bridge" ]; then
25 33
  exec $CONF_DIR/kvm-vif-bridge
26 34
fi
27 35

  
28
check
29
setup_bridge
30
setup_ovs
31
setup_route
36
if ! is_instance_communication_tap; then
37
  setup_bridge
38
  setup_ovs
39
  setup_route
40
fi
b/tools/net-common.in
20 20

  
21 21
@SHELL_ENV_INIT@
22 22

  
23
function check {
23
readonly GANETI_TAP="gnt.com"
24 24

  
25
function check {
25 26
  if [ -z "$INTERFACE" ]; then
26 27
    echo "No network interface specified"
27 28
    exit 1
......
31 32
    echo "MODE not specified"
32 33
    exit 1
33 34
  fi
35
}
34 36

  
37
function is_instance_communication_tap {
38
  COMMUNICATION=$(echo "$INTERFACE" | cut -d "." -f 1-2)
39

  
40
  if [ "$MODE" = "routed" -a "$COMMUNICATION" = "$GANETI_TAP" ]
41
  then
42
    return 0
43
  else
44
    return 1
45
  fi
35 46
}
36 47

  
37 48
function fix_mac {
38

  
39 49
  # Fix the autogenerated MAC to have the first octet set to "fe"
40 50
  # to discourage the bridge from using the TAP dev's MAC
41 51
  FIXED_MAC=$(ip link show $INTERFACE | \
42 52
    awk '{if ($1 == "link/ether") printf("fe%s",substr($2,3,15))}')
43 53
  # in case of a vif (xen_netback device) this action is not allowed
44 54
  ip link set $INTERFACE address $FIXED_MAC || true
45

  
46 55
}
47 56

  
48 57
function setup_bridge {
49

  
50 58
  if [ "$MODE" = "bridged" ]; then
51 59
    fix_mac
52 60
    ip link set $INTERFACE up
......
55 63
    # Connect the interface to the bridge
56 64
    brctl addif $LINK $INTERFACE
57 65
  fi
58

  
59 66
}
60 67

  
61 68
function setup_ovs {

Also available in: Unified diff