next up previous contents
Next: About this document ... Up: ip-cref Previous: Example: minimal host setup   Contents


Example: ifcfg -- interface address management

This is a simplistic script replacing one option of ifconfig, namely, IP address management. It not only adds addresses, but also carries out Duplicate Address Detection [9], sends unsolicited ARP to update the caches of other hosts sharing the interface, adds some control routes and restarts Router Discovery when it is necessary.

I strongly recommend using it instead of ifconfig both on hosts and on routers.

#! /bin/bash
# Usage: ifcfg DEVICE[:ALIAS] [add|del] ADDRESS[/LENGTH] [PEER]
# Parameters:
# --Device name. It may have alias suffix, separated by colon.
# --Command: add, delete or stop.
# --IP address, optionally followed by prefix length.
# --Optional peer address for pointopoint interfaces.
# F.e. ifcfg eth0 193.233.7.90/24

# This function determines, whether it is router or host.
# It returns 0, if the host is apparently not router.
CheckForwarding () {
  local sbase fwd
  sbase=/proc/sys/net/ipv4/conf
  fwd=0
  if [ -d $sbase ]; then
    for dir in $sbase/*/forwarding; do
      fwd=$[$fwd + `cat $dir`]
    done
  else
    fwd=2
  fi
  return $fwd
}
# This function restarts Router Discovery.
RestartRDISC () {
  killall -HUP rdisc || rdisc -fs
}
# Calculate ABC "natural" mask length
# Arg: $1 = dotquad address
ABCMaskLen () {
  local class;
  class=${1%%.*}
  if [ $class -eq 0 -o $class -ge 224 ]; then return 0
  elif [ $class -ge 192 ]; then return 24
  elif [ $class -ge 128 ]; then return 16
  else  return 8 ; fi
}

# MAIN()
#
# Strip alias suffix separated by colon.
label="label $1"
ldev=$1
dev=${1%:*}
if [ "$dev" = "" -o "$1" = "help" ]; then
  echo "Usage: ifcfg DEV [[add|del [ADDR[/LEN]] [PEER] | stop]" 1>&2
  echo "       add - add new address" 1>&2
  echo "       del - delete address" 1>&2
  echo "       stop - completely disable IP" 1>&2
  exit 1
fi
shift

CheckForwarding
fwd=$?
# Parse command. If it is ``stop'', flush and exit.
deleting=0
case "$1" in
add) shift ;;
stop)
  if [ "$ldev" != "$dev" ]; then
    echo "Cannot stop alias $ldev" 1>&2
    exit 1;
  fi
  ip -4 addr flush dev $dev $label || exit 1
  if [ $fwd -eq 0 ]; then RestartRDISC; fi
  exit 0 ;;
del*)
  deleting=1; shift ;;
*)
esac
# Parse prefix, split prefix length, separated by slash.
ipaddr=
pfxlen=
if [ "$1" != "" ]; then
  ipaddr=${1%/*}
  if [ "$1" != "$ipaddr" ]; then
    pfxlen=${1#*/}
  fi
  if [ "$ipaddr" = "" ]; then
    echo "$1 is bad IP address." 1>&2
    exit 1
  fi
fi
shift
# If peer address is present, prefix length is 32.
# Otherwise, if prefix length was not given, guess it.
peer=$1
if [ "$peer" != "" ]; then
  if [ "$pfxlen" != "" -a "$pfxlen" != "32" ]; then
    echo "Peer address with non-trivial netmask." 1>&2
    exit 1
  fi
  pfx="$ipaddr peer $peer"
else
  if [ "$pfxlen" = "" ]; then
    ABCMaskLen $ipaddr
    pfxlen=$?
  fi
  pfx="$ipaddr/$pfxlen"
fi
if [ "$ldev" = "$dev" -a "$ipaddr" != "" ]; then
  label=
fi
# If deletion was requested, delete the address and restart RDISC
if [ $deleting -ne 0 ]; then
  ip addr del $pfx dev $dev $label || exit 1
  if [ $fwd -eq 0 ]; then RestartRDISC; fi
  exit 0
fi
# Start interface initialization.
#
# Step 0 -- enable device $dev
if ! ip link set up dev $dev ; then
  echo "Error: cannot enable interface $dev." 1>&2
  exit 1
fi
if [ "$ipaddr" = "" ]; then exit 0; fi
# Step 1 -- IP Duplicate Address Detection [9].
# Send two probes and wait for result for 3 seconds.
# If the interface opens slower f.e. due to long media detection,
# you want to increase the timeout.
if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
  echo "Error: some host already uses address $ipaddr on $dev." 1>&2
  exit 1
fi
# OK, the address is unique. We may add it to the interface.
#
# Step 2 -- Configure the address on the interface.
if ! ip address add $pfx brd + dev $dev $label; then
  echo "Error: failed to add $pfx on $dev." 1>&2
  exit 1
fi
# Step 3 -- Announce our presence on the link
arping -q -A -c 1 -I $dev $ipaddr
noarp=$?
( sleep 2 ;
  arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
# Step 4 (optional) -- Add some control routes.
#
# 1. Prohibit link local multicast addresses.
# 2. Prohibit link local (alias, limited) broadcast.
# 3. Add default multicast route.
ip route add unreachable 224.0.0.0/24 >& /dev/null 
ip route add unreachable 255.255.255.255 >& /dev/null
if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
  ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
fi
# Step 5 -- Add fallback default route with huge metric.
# If a proxy ARP server is present on the interface, we will be
# able to talk to all the Internet without further configuration.
# Do not make this step on router or if the device is not ARPable.
# because dead nexthop detection does not work on them.
if [ $fwd -eq 0 ]; then
  if [ $noarp -eq 0 ]; then
    ip ro append default dev $dev metric 30000 scope global
  elif [ "$peer" != "" ]; then
    if ping -q -c 2 -w 4 $peer ; then
      ip ro append default via $peer dev $dev metric 30001
    fi
  fi
  RestartRDISC
fi

exit 0
# End of MAIN()


next up previous contents
Next: About this document ... Up: ip-cref Previous: Example: minimal host setup   Contents