On Wed, Feb 5, 2014 at 10:10 AM, Jose A. Lopes <[email protected]> wrote:
> The script 'tools/kvm-ifup-os' configures TAP network interfaces for
> for instances, routing, DHCP server, etc.  Note that this script only
> configures TAP network interfaces that are used by the instance
> communication, that is, network interfaces named according to the
> pattern 'gnt.com.%d', where '%d' is a number unique within a given
> node.
>
> Signed-off-by: Jose A. Lopes <[email protected]>
> ---
>  Makefile.am          |  11 ++
>  tools/kvm-ifup-os.in | 296 
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/kvm-ifup.in    |  21 +++-
>  tools/net-common.in  |  17 ++-
>  4 files changed, 335 insertions(+), 10 deletions(-)
>  create mode 100644 tools/kvm-ifup-os.in
>
> diff --git a/Makefile.am b/Makefile.am
> index e5d0594..aa631da 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -95,6 +95,7 @@ toolsdir = $(pkglibdir)/tools
>  iallocatorsdir = $(pkglibdir)/iallocators
>  pytoolsdir = $(pkgpythondir)/tools
>  docdir = $(versiondir)$(datadir)/doc/$(PACKAGE)
> +ifupdir = $(sysconfdir)/ganeti
>
>  SYMLINK_TARGET_DIRS = \
>         $(sysconfdir)/ganeti \
> @@ -258,6 +259,7 @@ CLEANFILES = \
>         $(man_MANS) \
>         $(manhtml) \
>         tools/kvm-ifup \
> +       tools/kvm-ifup-os \
>         tools/vif-ganeti \
>         tools/net-common \
>         tools/users-setup \
> @@ -320,6 +322,9 @@ BUILT_EXAMPLES = \
>         doc/examples/gnt-config-backup \
>         doc/examples/hooks/ipsec
>
> +dist_ifup_SCRIPTS = \
> +       tools/kvm-ifup-os
> +
>  nodist_pkgpython_PYTHON = \
>         $(BUILT_PYTHON_SOURCES)
>
> @@ -1131,6 +1136,7 @@ pkglib_python_basenames = \
>  myexeclib_SCRIPTS = \
>         daemons/daemon-util \
>         tools/kvm-ifup \
> +       tools/kvm-ifup-os \
>         tools/vif-ganeti \
>         tools/net-common \
>         $(HS_MYEXECLIB_PROGS)
> @@ -1169,6 +1175,7 @@ EXTRA_DIST = \
>         devel/upload \
>         devel/webserver \
>         tools/kvm-ifup.in \
> +       tools/kvm-ifup-os.in \
>         tools/vif-ganeti.in \
>         tools/net-common.in \
>         tools/vcluster-setup.in \
> @@ -1653,6 +1660,10 @@ tools/kvm-ifup: tools/kvm-ifup.in $(REPLACE_VARS_SED)
>         sed -f $(REPLACE_VARS_SED) < $< > $@
>         chmod +x $@
>
> +tools/kvm-ifup-os: tools/kvm-ifup-os.in $(REPLACE_VARS_SED)
> +       sed -f $(REPLACE_VARS_SED) < $< > $@
> +       chmod +x $@
> +
>  tools/vif-ganeti: tools/vif-ganeti.in $(REPLACE_VARS_SED)
>         sed -f $(REPLACE_VARS_SED) < $< > $@
>         chmod +x $@
> diff --git a/tools/kvm-ifup-os.in b/tools/kvm-ifup-os.in
> new file mode 100644
> index 0000000..b696da6
> --- /dev/null
> +++ b/tools/kvm-ifup-os.in
> @@ -0,0 +1,296 @@
> +#!/bin/bash
> +#
> +
> +# Copyright (C) 2014 Google Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful, but
> +# WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +# General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +# 02110-1301, USA.
> +
> +# This script is a hook called to configure new TAP network interfaces
> +# used for instance communication, and it should be called whenever a
> +# new instance is started.
> +#
> +# This script configures the new interface but it also performs
> +# maintenance on the network interfaces that have been configured
> +# before, by checking whether those TAP interfaces still exist, etc.
> +#
> +# This script also controls the DHCP server that leases IP address for
> +# instances, i.e., the NICs inside the instances, not the TAP
> +# interfaces.  The DHCP server is started and restarted (or reHUPed)
> +# as necessary and always with up-to-date configuration files.
> +#
> +# This script expects the following environment variables
> +#
> +#   INTERFACE: network interface name to be configured
> +#   MODE: networking mode for 'INTERFACE' (must be 'routed')
> +#   MAC: MAC address for 'INTERFACE'
> +#   IP: IP address for 'INTERFACE'
> +
> +source @PKGLIBDIR@/net-common
> +
> +readonly NETMASK=255.255.255.255
> +readonly DNSMASQ_CONF=/var/run/ganeti/dnsmasq.conf
> +readonly DNSMASQ_HOSTS=/var/run/ganeti/dnsmasq.hosts
> +readonly DNSMASQ_PID=/var/run/ganeti/dnsmasq.pid
> +
> +# join intercalates a sequence of arguments using the given separator
> +function join {
> +  local IFS="$1"
> +  shift
> +  echo "$*"
> +}
> +
> +# restart_dnsmasq restarts the DHCP server dnsmasq with the (possibly
> +# up-to-date) configuration file.
> +#
> +# If all instances have been terminated, which means there are no more
> +# TAP network interfaces to monitor or IP addresses to lease, the DHCP
> +# server is terminated through 'SIGTERM'.
> +#
> +# If there are still instances running, then:
> +#  - if the DHCP server is running, a 'SIGHUP' will be sent to the
> +#    dnsmasq process which will cause the configuration file to be
> +#    re-read, while keeping the process running
> +#  - if the DHCP server is not running, it will be started, and the
> +#    configuration file will be passed it
> +function restart_dnsmasq {
> +  SIGNAL=
> +
> +  if [ -z "$ALIVE_INTERFACES" -o -z "$ALIVE_LEASES" ]
> +  then
> +      SIGNAL=TERM
> +  else
> +      SIGNAL=HUP
> +  fi
> +
> +  RUNNING=
> +
> +  if [ -f "$DNSMASQ_PID" ]
> +  then
> +      PID=$(cat $DNSMASQ_PID)
> +      if [ -n "$PID" ] && ps -p "$PID"
> +      then
> +         RUNNING=yes
> +      fi
> +  fi
> +
> +  KILLED=
> +
> +  if [ "$RUNNING" = yes ]
> +  then
> +      kill -$SIGNAL $PID
> +
> +      if [ "$SIGNAL" = TERM ]
> +      then
> +         KILLED=yes
> +      fi
> +  fi
> +
> +  if [ "$KILLED" = yes ]
> +  then
> +      rm -f $DNSMASQ_PID
> +  fi
> +
> +  if [ "$RUNNING" != yes -o "$KILLED" == yes ]
> +  then
> +      if [ -n "$ALIVE_INTERFACES" -a -n "$ALIVE_LEASES" ]
> +      then
> +         dnsmasq -C $DNSMASQ_CONF
> +      fi
> +  fi
> +
> +  return 0
> +}
> +
> +# Check that environment variable 'INTERFACE' exists.
> +#
> +# This environment variable holds the TAP network interface that
> +# should be configured by this script.  Ganeti always passes it,
> +# but... :)
> +if [ -z "$INTERFACE" ]
> +then
> +  echo kvm-vif-bridge: Failed to configure communication mechanism \
> +      interface because the \'INTERFACE\' environment variable was \
> +      not specified to the \'kvm-vif-bridge\' script
> +  exit 1
> +fi
> +
> +# Check that environment variable 'MODE' exists.
> +#
> +# See comment about environment variable 'INTERFACE'.
> +if [ -z "$MODE" ]
> +then
> +  echo kvm-vif-bridge: Failed to configure communication mechanism \
> +      interface because the \'MODE\' environment variable was \
> +      not specified to the \'kvm-vif-bridge\' script
> +  exit 1
> +fi
> +
> +# Check whether the interface being configured has instance
> +# communication enabled, otherwise exit this script.
> +if ! is_instance_communication_tap; then exit 0; fi
> +
> +# Check that environment variable 'MAC' exists.
> +#
> +# See comment about environment variable 'INTERFACE'.
> +if [ -z "$MAC" ]
> +then
> +  echo kvm-vif-bridge: Failed to configure communication mechanism \
> +      interface because the \'MAC\' environment variable was \
> +      not specified to the \'kvm-vif-bridge\' script
> +  exit 1
> +fi
> +
> +# Check that environment variable 'IP' exists.
> +#
> +# See comment about environment variable 'INTERFACE'.
> +if [ -z "$IP" ]
> +then
> +  echo kvm-vif-bridge: Failed to configure communication mechanism \
> +      interface because the \'IP\' environment variable was \
> +      not specified to the \'kvm-vif-bridge\' script
> +  exit 1
> +fi
> +
> +# Configure the TAP interface
> +#
> +# Ganeti defers the configuration of instance network interfaces to
> +# hooks, therefore, we must configure the interface's network address,
> +# netmask, and IP address.
> +#
> +# The TAP network interface, which is used by the instance
> +# communication, is part of the network 169.254.0.0/16 and has the IP
> +# 169.254.169.254.  Because all network interfaces used in the
> +# instance communication have the same IP, the routing table must also
> +# be configured, and that is done at a later step.
> +#
> +# Note the interface must be marked as up before configuring the
> +# routing table and before starting/restarting the DHCP server.
> +#
> +# Note also that we don't have to check whether the interface is
> +# already configured because reconfiguring the interface with the same
> +# parameters does not produce an error.
> +ifconfig $INTERFACE 169.254.169.254 netmask $NETMASK up
> +
> +# Configure the routing table
> +#
> +# Given that all TAP network interfaces in the instance communication
> +# have the same IP address, the routing table must be configured in
> +# order to properly route traffic from the host to the guests.
> +#
> +# Note that we must first check if a duplicate routing rule has
> +# already been added to the routing table, as this operation will fail
> +# if we try to add a routing rule that already exists.
> +ACTIVE_IP=$(ip route | grep "dev $INTERFACE" | awk '{ print $1 }')
> +
> +if [ -z "$ACTIVE_IP" -o "$ACTIVE_IP" != "$IP" ]
> +then
> +  route add -host $IP dev $INTERFACE
> +fi
> +
> +# Ensure the DHCP server configuration files exist
> +touch $DNSMASQ_CONF
> +chmod 0644 $DNSMASQ_CONF
> +
> +touch $DNSMASQ_HOSTS
> +chmod 0644 $DNSMASQ_HOSTS
> +
> +# Determine dnsmasq operational mode.
> +#
> +# The DHCP server dnsmasq can run in different modes.  In this version
> +# of the script, only the mode 'bind-dynamic' is supported.  Please
> +# refer to the dnsmasq FAQ for a detailed of each mode.
> +#
> +# Note that dnsmasq might already be running, therefore, we don't need
> +# to determine which modes are supported by this DHCP server.
> +# Instead, we just read the current mode from the configuration file.
> +DNSMASQ_MODE=$(head -n 1 $DNSMASQ_CONF)
> +
> +if [ -z "$DNSMASQ_MODE" ]
> +then
> +  BIND_DYNAMIC=$(dnsmasq --help | grep -e --bind-dynamic)
> +
> +  if [ -z "$BIND_DYNAMIC" ]
> +  then
> +    echo kvm-vif-bridge: dnsmasq mode \"bind-dynamic\" is not supported
> +    exit 1
> +  fi
> +
> +  DNSMASQ_MODE=bind-dynamic
> +fi
> +
> +# Determine the interfaces that should go in the configuration file.
> +#
> +# The TAP network interfaces used by the instance communication are
> +# named after the following pattern
> +#
> +#  gnt.com.%d
> +#
> +# where '%d' is a unique number within the host.  Fortunately, dnsmasq
> +# supports binding to specific network interfaces via a pattern.
> +ALIVE_INTERFACES=${GANETI_TAP}.*
> +
> +# Determine which of the leases are not duplicated and should go in
> +# the new configuration file for the DHCP server.
> +#
> +# Given that instances come and go, it is possible that we offer more
> +# leases that necessary and, worse, that we have duplicate leases,
> +# that is, the same IP address for the same/different MAC addresses.
> +# Duplicate leases must be eliminated before being written to the
> +# configuration file.
> +CONF_LEASES=$(cat $DNSMASQ_HOSTS)
> +CONF_LEASES=$(join $'\n' $CONF_LEASES | sort -u)
> +
> +ALIVE_LEASES=( $MAC,$IP )
> +
> +for i in $CONF_LEASES
> +do
> +  LEASE_MAC=$(echo $i | cut -d "," -f 1)
> +  LEASE_IP=$(echo $i | cut -d "," -f 2)
> +  if [ "$LEASE_MAC" != "$MAC" -a "$LEASE_IP" != "$IP" ]
> +  then
> +      ALIVE_LEASES=( ${ALIVE_LEASES[@]} $i )
> +  fi
> +done
> +
> +ALIVE_LEASES=$(echo ${ALIVE_LEASES[@]} | sort -u)
> +
> +# Update dnsmasq configuration.
> +#
> +# Write the parameters we have collected before into the new dnsmasq
> +# configuration file.  Also, write the new leases into the new dnsmasq
> +# hosts file.  Finally, restart dnsmasq with the new configuration
> +# files.
> +cat > $DNSMASQ_CONF <<EOF
> +$DNSMASQ_MODE
> +dhcp-authoritative
> +dhcp-hostsfile=$DNSMASQ_HOSTS
> +dhcp-range=169.254.0.0,static,255.255.0.0
> +except-interface=eth*
> +except-interface=lo
> +leasefile-ro
> +no-hosts
> +no-ping
> +no-resolv
> +pid-file=$DNSMASQ_PID
> +port=0
> +strict-order
> +EOF
> +for i in $ALIVE_INTERFACES; do echo interface=$i >> $DNSMASQ_CONF; done
> +
> +echo -n > $DNSMASQ_HOSTS
> +for i in $ALIVE_LEASES; do echo $i >> $DNSMASQ_HOSTS; done
> +
> +restart_dnsmasq
> diff --git a/tools/kvm-ifup.in b/tools/kvm-ifup.in
> index 5a53cee..f7ce37d 100644
> --- a/tools/kvm-ifup.in
> +++ b/tools/kvm-ifup.in
> @@ -1,7 +1,7 @@
>  #!/bin/bash
>  #
>
> -# Copyright (C) 2011, 2012 Google Inc.
> +# Copyright (C) 2011, 2012, 2014 Google Inc.
>  #
>  # This program is free software; you can redistribute it and/or modify
>  # it under the terms of the GNU General Public License as published by
> @@ -20,12 +20,23 @@
>
>  source @PKGLIBDIR@/net-common
>
> +check
> +
> +# Execute the user-supplied network script, if applicable
I'd change this into something like "Execute the script for setting up
the communication with the instance os, if available"
No reference to "user-supplied" as it is user-modifiable but supplied by us.

> +#
> +# This additional hook is placed here for backwards-compatibility with
> +# the other hook below.

Without the whole discussion we had offline, this comment about
backwards-compatibility does not make much sense, so I'd just remove
it.

> +if is_instance_communication_tap && [ -x "$CONF_DIR/kvm-ifup-os" ]; then
> +  . $CONF_DIR/kvm-ifup-os
> +fi
> +
>  # Execute the user-supplied network script, if applicable
>  if [ -x "$CONF_DIR/kvm-vif-bridge" ]; then
>    exec $CONF_DIR/kvm-vif-bridge
>  fi
>
> -check
> -setup_bridge
> -setup_ovs
> -setup_route
> +if ! is_instance_communication_tap; then
> +  setup_bridge
> +  setup_ovs
> +  setup_route
> +fi
> diff --git a/tools/net-common.in b/tools/net-common.in
> index 7305875..c0d5bdf 100644
> --- a/tools/net-common.in
> +++ b/tools/net-common.in
> @@ -20,8 +20,9 @@
>
>  @SHELL_ENV_INIT@
>
> -function check {
> +readonly GANETI_TAP="gnt.com"
>
> +function check {
>    if [ -z "$INTERFACE" ]; then
>      echo "No network interface specified"
>      exit 1
> @@ -31,22 +32,29 @@ function check {
>      echo "MODE not specified"
>      exit 1
>    fi
> +}
>
> +function is_instance_communication_tap {
> +  COMMUNICATION=$(echo "$INTERFACE" | cut -d "." -f 1-2)
> +
> +  if [ "$MODE" = "routed" -a "$COMMUNICATION" = "$GANETI_TAP" ]
> +  then
> +    return 0
> +  else
> +    return 1
> +  fi
>  }
>
>  function fix_mac {
> -
>    # Fix the autogenerated MAC to have the first octet set to "fe"
>    # to discourage the bridge from using the TAP dev's MAC
>    FIXED_MAC=$(ip link show $INTERFACE | \
>      awk '{if ($1 == "link/ether") printf("fe%s",substr($2,3,15))}')
>    # in case of a vif (xen_netback device) this action is not allowed
>    ip link set $INTERFACE address $FIXED_MAC || true
> -
>  }
>
>  function setup_bridge {
> -
>    if [ "$MODE" = "bridged" ]; then
>      fix_mac
>      ip link set $INTERFACE up
> @@ -55,7 +63,6 @@ function setup_bridge {
>      # Connect the interface to the bridge
>      brctl addif $LINK $INTERFACE
>    fi
> -
>  }
>
>  function setup_ovs {
> --
> 1.9.0.rc1.175.g0b1dcb5
>

Rest LGTM, no need to resend.

Thanks,
Michele

-- 
Google Germany GmbH
Dienerstr. 12
80331 München

Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Geschäftsführer: Graham Law, Christine Elizabeth Flores

Reply via email to