diff options
Diffstat (limited to 'network-scripts/ifup-aliases')
-rwxr-xr-x | network-scripts/ifup-aliases | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/network-scripts/ifup-aliases b/network-scripts/ifup-aliases new file mode 100755 index 00000000..971ce208 --- /dev/null +++ b/network-scripts/ifup-aliases @@ -0,0 +1,370 @@ +#!/bin/bash + +# +# configures aliases of device $1 +# +# This script goes out of its way to arrive at the configuration of ip +# aliases described in the ifcfg-$DEV:* and ifcfg-$DEV-range* files from +# whatever existing configuration it may be given: existing aliases not +# specified in the configuration will be removed, netmasks and broadcast +# addrs will be updated on existing aliases, and new aliases will be setup. +# +# range specification files: +# +# One can specify ranges of alised ipaddress using ifcfg-$DEV-range* files. +# Specify multiple ranges using multiple files, such as ifcfg-eth0-range0 and +# ifcfg-eth0-range1, etc. In these files, the following configuration variables +# specify the range: +# +# IPADDR_START -- ipaddr to start range at. eg "192.168.30.1" +# IPADDR_END -- ipaddr to end range at. eg "192.168.30.254" +# CLONENUM_START -- interface clone number to start using for this range. eg "0" +# +# The above example values create the interfaces eth0:0 through eth0:253 using +# ipaddrs 192.168.30.1 through 192.168.30.254, inclusive. +# +# Other configuration variables such as NETMASK and BROADCAST may be specified +# in the range file and will apply to all of the ipaddresses in the range. Range +# files also inherit configuration from the ifcfg-$DEV file just like normal. +# +# Note that IPADDR_START and IPADR_END are required to be in the same class-c +# block. I.e. IPADDR_START=192.168.30.1 and IPADDR_END=192.168.31.255 is +# not valid. +# +# speed with large sets of interfaces: +# +# Considerable effort was spent making this script fast. It can efficiently +# handle a thousand ip aliases on one interface. +# +# With large sets of ipaddresses the NO_ALIASROUTING=yes configuration is +# highly recommended. (This can be specified in ifcfg-$DEV and inherited.) This +# prevents this script from setting up routing details for the virtual +# interfaces, which I don't think is needed, because outgoing traffic can use the +# main interface. However, make your own conclusions on what you need. +# +# My test setup of four class C address blocks on a P166 took 25 seconds of +# which 16 seconds of this was spent in the ifcconfig calls. Without the +# NO_ALIASROUTING=yes config an additional 12 seconds is spent in route calls. +# +# notes on internals: +# +# This script uses the bash "eval" command to lookup shell variables with names +# which are generated from other shell variables. This allows us to, in effect, +# create hashes using the shell variable namesspace by just including the hash +# key in the name of the variable. +# +# This script originally written by: David Harris <dharris@drh.net> +# Principal Engineer, DRH Internet +# June 30, 1999 +# +# modified by: Bill Nottingham <notting@redhat.com> + +TEXTDOMAIN=initscripts +TEXTDOMAINDIR=/etc/locale + +device=$1 +if [ "$device" = "" ]; then + echo $"usage: ifup-aliases <net-device> [<parent-config>]\n" + exit 1 +fi + +PARENTCONFIG=${2:-ifcfg-$device} +parent_device=$device + +cd /etc/sysconfig/network-scripts +. ./network-functions + +# Grab the current configuration of any running aliases, place device info +# into variables of the form: +# rdev_<index>_addr = <ip address> +# rdev_<index>_pb = <prefix>_<broadcast> +# rdevip_<ipaddress> = <index> +# Example: +# rdev_0_addr=192.168.1.1 +# rdev_0_pb=24_192.16.1.255 +# rdevip_192_168_1_1=0 +# +# A list of all the devices is created in rdev_LIST. + +eval $( ip addr show $device label $device:* | \ + awk 'BEGIN { COUNT=0;LAST_DEV="" } /inet / { + # Split IP address into address/prefix + split($2,IPADDR,"/"); + # Create A_B_C_D IP address form + IP_ADDR=IPADDR[1]; + gsub(/\./,"_",IP_ADDR); + # Split device into device:index + split($NF,DEV,":"); + # Update last device + LAST_DEV=LAST_DEV " " DEV[2]; + printf("rdev_%s_addr=%s\nrdevip_%s=%s\nrdev_%s_pb=%s_%s\nrdev_LIST=\"%s\"\n", + DEV[2],IPADDR[1],IP_ADDR,DEV[2],DEV[2],IPADDR[2],$4,LAST_DEV); + } END { + if(LAST_DEV == "") print "no_devices_are_up=yes" + }' ); + +# +# Store configuration of the parent device and network +# + +# read from the /etc/sysconfig/network +eval ` ( + . /etc/sysconfig/network; + echo network_GATEWAY=$GATEWAY\;; + echo network_GATEWAYDEV=$GATEWAYDEV\;; +) ` + +# read defaults from the parent config file +[ -f $PARENTCONFIG ] || { + net_log $"Missing config file $PARENTCONFIG." + exit 1 +} +eval ` ( + . ./$PARENTCONFIG; + echo default_PREFIX=$PREFIX\;; + echo default_NETMASK=$NETMASK\;; + echo default_BROADCAST=$BROADCAST\;; + echo default_GATEWAY=$GATEWAY\;; + echo default_NO_ALIASROUTING=$NO_ALIASROUTING\;; + echo default_ARPCHECK=$ARPCHECK\;; + echo default_ARPUPDATE=$ARPUPDATE\;; +) ` +[ -z "$default_GATEWAY" ] && default_GATEWAY=$network_GATEWAY + +function ini_env () +{ + DEVICE="" + IPADDR="" + IPV6ADDR="" + PREFIX=$default_PREFIX + NETMASK=$default_NETMASK + BROADCAST=$default_BROADCAST + GATEWAY=$default_GATEWAY + NO_ALIASROUTING=$default_NO_ALIASROUTING + ONPARENT="" + ARPCHECK=$default_ARPCHECK + ARPUPDATE=$default_ARPUPDATE +} + +function is_default_gateway () +{ + LC_ALL=C /sbin/ip route ls default scope global \ + | awk '$3 == "'"$1"'" { found = 1; } END { exit found == 0; }' +} + +# +# Read the alias configuration files and enable each aliased +# device using new_interface() +# + +function new_interface () +{ + + ipa=$IPADDR; ipb=${ipa#*.}; ipc=${ipb#*.}; + IPGLOP="${ipa%%.*}_${ipb%%.*}_${ipc%%.*}_${ipc#*.}"; + DEVNUM=${DEVICE#*:} + + MATCH='^[0-9A-Za-z_]*$' + if (LC_ALL=C; [[ ! "$DEVNUM" =~ $MATCH ]]); then + net_log $"error in $FILE: invalid alias number" + return 1 + fi + + eval " + ipseen=\$ipseen_${IPGLOP}; devseen=\$devseen_${DEVNUM}; + ipseen_${IPGLOP}=$FILE; devseen_${DEVNUM}=$FILE; + "; + + if [ -n "$ipseen" ]; then + net_log $"error in $FILE: already seen ipaddr $IPADDR in $ipseen" + return 1 + fi + + if [ -n "$devseen" ]; then + net_log $"error in $FILE: already seen device $parent_device:$DEVNUM in $devseen" + return 1 + fi + + if [ -z "$DEVICE" -o -z "$IPADDR" ]; then + if [ -n "$IPV6ADDR" -a -n "$DEVICE" ] && ! is_false "$IPV6INIT"; then + /etc/sysconfig/network-scripts/ifup-ipv6 ${DEVICE} + return $? + fi + net_log $"error in $FILE: didn't specify device or ipaddr" + return 1 + fi + + if [ -z "$NETMASK" -a -z "$PREFIX" ]; then + net_log $"error iN $FILE: didn't specify netmask or prefix" + fi + + if [ -z "$PREFIX" ]; then + eval $(/bin/ipcalc --prefix ${IPADDR} ${NETMASK}) + fi + + if [ -z "$BROADCAST" -o "$BROADCAST" = "$default_BROADCAST" ]; then + eval $(/bin/ipcalc --broadcast ${IPADDR}/${PREFIX}) + fi + + if is_true "$no_devices_are_up"; then + setup_this=yes + else + + setup_this="" + + eval " + rdev_addr=\$rdev_${DEVNUM}_addr; + rdev_pb=\$rdev_${DEVNUM}_pb; + rdev_mark=\$rdev_${DEVNUM}_mark; + rdevip=\$rdevip_${IPGLOP}; + "; + + if [ -n "$rdev_addr" ]; then + if [ "$rdev_addr" = "${IPADDR}" ]; then + newmark=keep + if [ "$rdev_pb" != "${PREFIX}_${BROADCAST}" ]; then + setup_this=freshen + else + setup_this=no + fi + else + if [ "$rdev_mark" != "remove" ]; then + /sbin/ip addr flush dev $parent_device label $parent_device:${DEVNUM} + fi + newmark=remove + setup_this=yes + fi + if [ -n "$rdev_mark" -a "$rdev_mark" != "$newmark" ]; then + net_log $"error in ifcfg-${parent_device}: files" + return 1 + fi + eval " rdev_${DEVNUM}_mark=\$newmark "; + else + setup_this=yes + fi + + if [ -n "$rdevip" -a "$rdevip" != "${DEVNUM}" ]; then + eval " mark_remove=\$rdev_${rdevip}_mark "; + if [ -n "$mark_remove" -a "$mark_remove" != "remove" ]; then + net_log $"error in ifcfg-${parent_device}: files" + return 1 + fi + if [ "$mark_remove" != "remove" ]; then + eval " rdev_${rdevip}_mark=remove "; + /sbin/ip addr flush dev $parent_device label $parent_device:$rdevip + fi + fi + + fi + + if [ "$setup_this" = "freshen" ] ; then + # we can do the freshen stuff right now + /sbin/ip addr change ${IPADDR}/${PREFIX} brd ${BROADCAST} + fi + + if is_true "$setup_this"; then + if [ "${parent_device}" != "lo" ] && ! is_false "${ARPCHECK}" && \ + is_available ${parent_device} && \ + ( grep -qswi "up" /sys/class/net/${parent_device}/operstate || grep -qswi "1" /sys/class/net/${parent_device}/carrier ) ; then + echo $"Determining if IP address ${IPADDR} is already in use for device ${parent_device}…" + ARPING=$(/sbin/arping -c 2 -w ${ARPING_WAIT:-3} -D -I ${parent_device} ${IPADDR}) + if [ $? = 1 ]; then + ARPINGMAC=$(echo $ARPING | sed -ne 's/.*\[\(.*\)\].*/\1/p') + net_log $"Error, some other host ($ARPINGMAC) already uses address ${IPADDR}." + return 1 + fi + fi + + /sbin/ip addr add ${IPADDR}/${PREFIX} brd ${BROADCAST} \ + dev ${parent_device} label ${DEVICE} + + # update ARP cache of neighboring computers: + if ! is_false "${ARPUPDATE}" && [ "${REALDEVICE}" != "lo" ]; then + /sbin/arping -q -A -c 1 -I ${parent_device} ${IPADDR} + ( sleep 2; /sbin/arping -q -U -c 1 -I ${parent_device} ${IPADDR} ) > /dev/null 2>&1 < /dev/null & + fi + + ! is_false "$IPV6INIT" && \ + /etc/sysconfig/network-scripts/ifup-ipv6 ${DEVICE} + + if ! is_true "$NO_ALIASROUTING"; then + + GATEWAYDEV=$network_GATEWAYDEV; + + if [ -n "${GATEWAY}" -a \ + \( -z "${GATEWAYDEV}" -o "${GATEWAYDEV}" = "${DEVICE}" \) ]; then + # set up default gateway, if it isn't already there + if ! is_default_gateway "$GATEWAY"; then + ip route replace default ${METRIC:+metric $METRIC} via ${GATEWAY} dev ${DEVICE} + fi + fi + + /etc/sysconfig/network-scripts/ifup-routes ${DEVICE} ${NAME} + + ifuplocal_queue="$ifuplocal_queue $DEVICE" + fi + fi +} + +if [ "$BASH_VERSINFO" ]; then + shopt -s nullglob +else + allow_null_glob_expansion=foo +fi + +for FILE in ifcfg-${parent_device}:* ; do + is_ignored_file "$FILE" && continue + ini_env + . ./$FILE + [ -z "$DEVICE" ] && DEVICE=${FILE##ifcfg-} + ! is_false "$ONPARENT" && new_interface + unset DEVICE +done + +for FILE in ifcfg-${parent_device}-range* ; do + is_ignored_file "$FILE" && continue + ini_env + . ./$FILE + + ipaddr_prefix=${IPADDR_START%.*} + ipaddr_startnum=${IPADDR_START##*.} + ipaddr_endnum=${IPADDR_END##*.} + + if [ "${IPADDR_START%.*}" != "${IPADDR_END%.*}" ]; then + net_log $"error in $FILE: IPADDR_START and IPADDR_END don't agree" + continue + fi + + if [ $ipaddr_startnum -gt $ipaddr_endnum ]; then + net_log $"error in $FILE: IPADDR_START greater than IPADDR_END" + continue + fi + + ipaddr_num=$ipaddr_startnum + ipaddr_clonenum=$CLONENUM_START + + while [ $ipaddr_num -le $ipaddr_endnum ]; do + IPADDR="$ipaddr_prefix.$ipaddr_num" + DEVICE="$parent_device:$ipaddr_clonenum" + IPV6INIT="no" + ! is_false "$ONPARENT" && new_interface + ipaddr_num=$(($ipaddr_num+1)) + ipaddr_clonenum=$(($ipaddr_clonenum+1)) + done +done + +# +# Remove any devices that should not be around +# +for DEVNUM in $rdev_LIST ; do + eval " rdev_mark=\$rdev_${DEVNUM}_mark " + if [ -z "$rdev_mark" ]; then + /sbin/ip addr flush dev $parent_device label $parent_device:${DEVNUM} + fi +done + +if [ -x /sbin/ifup-local ]; then + for DEVICE in $ifuplocal_queue ; do + /sbin/ifup-local ${DEVICE} + done +fi |