Tuesday, November 16, 2010

RedHat NIC-Bonding/Trunking

I've got, potentially, a number of RedHat Enterprise Linux 5.x systems that I need to set up NIC-trunking on. More fun, most of these systems will require that the trunks be composed of tagged-VLAN (802.1q) based NICs. Originally, our group's RedHat guy put together a script to help make this an easier task. Basically, if finds all the physical NICs on the system and then creates the requisite /etc/sysconfig/network-scripts files to configure them into a bonded interface. The script itself was serviceable, but it was strictly an interactive script. It wasn't designed to be invoked with arguments. So, you couldn't just say "bond and go" (or put it into an automated-provisioning framework.
So, wanting a tool that could be fired off from an automated systems management console, I rewrote the script. Note that I'm not claiming the below is an ideal, optimal or even a good script. I'm just putting it out there as a reference for myself (in case my laptop dies, gets stolen, whatever) and in case someone else can use it as a basis for writing their own tool (to be honest, it's also in hopes that someone finds it and posts up a "here: do this to make it better/more elegant").
Note: I am a KSH user. That means that, when I write scripts, I write them using Korn Shell sysntax and structures. Most of these should be portable to any modern, POSIX-compliant shell:

#
#!/bin/ksh
#
# Script to create "null" bonded NICs
#
# Usage:
#   ${0} <BondName> <BondMode> <NICStoBond> <IPAddress> <NetMask> <Gateway> <VLAN> <restart>

BONDNAME=${1:-bond0}
BONDMODE=${2:-4}
BONDNICS=${3:-all}
IPADDR=${4:-UNDEF}
NETMASK=${5:-UNDEF}
GATEWAY=${6:-UNDEF}
VLANID=${7:-0}
BOUNCE=${8:-UNDEF}

# Set work/save dirs
WORKDIR=/tmp/BOND
NEWSCRIPTS=${WORKDIR}/scripts
SAVEDIR=${WORKDIR}/save
CONFDIR=/etc/sysconfig/network-scripts
DATE=`date "+%Y%m%d%H%M%S"`
VERIFY="yes"

# Ensure that our work/save directories exist and are empty
WorkDirs() {
   if [ ! -d ${WORKDIR} ]
   then
      mkdir -p ${WORKDIR}
      mkdir -p ${NEWSCRIPTS}
      mkdir -p ${SAVEDIR}
   else
      mv ${WORKDIR} ${WORKDIR}.SAV-${DATE} && mkdir ${WORKDIR}
      mkdir -p ${NEWSCRIPTS}
      mkdir -p ${SAVEDIR}
   fi
}

# Make sure kernel modules defined/loaded
AddModAlias() {
   NEEDALIAS=`grep ${BONDNAME} /etc/modprobe.conf`
   if [ "${NEEDALIAS}" = "" ]
   then
      echo "alias ${BONDNAME} bonding" >> /etc/modprobe.conf
      echo "options ${BONDNAME} mode=${BONDMODE} miimon=100" >> /etc/modprobe.conf
      modprobe ${BONDNAME}
   fi
}

# Save previous config files
SaveOrig() {
   if [ -f ${CONFDIR}/ifcfg-bond? ]
   then
      cp ${CONFDIR}/ifcfg-bond?  ${SAVEDIR}
   fi

   if [ -f ${CONFDIR}/ifcfg-bond?.* ]
   then
      cp ${CONFDIR}/ifcfg-bond?.* ${SAVEDIR}
   fi

   if [ -f ${CONFDIR}/ifcfg-eth? ]
   then
      cp ${CONFDIR}/ifcfg-eth?  ${SAVEDIR}
   fi

   if [ -f ${CONFDIR}/ifcfg-eth?.* ]
   then
      cp ${CONFDIR}/ifcfg-eth?.* ${SAVEDIR}
   fi
}


###################################
# Create an iteratable list of NICs
###################################
IFlist() {
   if [ "${BONDNICS}" = "all" ] || [ "${BONDNICS}" = "ALL" ]
   then
      IFSET=`GetAllIFs`
   else
      IFSET=`ParseIFlist ${BONDNICS}`
   fi
   # Value returned by function
   echo ${IFSET}
}

  # Iterate all NICs found in "/sys/devices"
  GetAllIFs() {
     find /sys/devices -name "*eth*" | sed 's#^.*net:##' | sort
  }

  # Parse passed-list of NICs
  ParseIFlist() {
     echo ${1} | sed 's/,/ /g'
  }
#
###################################

# Generate physical NIC file contents
MkBaseIFfiles() {
   echo "# Interface config for ${1}"
   echo "DEVICE=${1}"
   echo "BOOTPROTO=none"
   echo "ONBOOT=yes"
   echo "USRCTL=no"
   echo "TYPE=Ethernet"
   echo "MASTER=${BONDNAME}"
   echo "SLAVE=yes"
}

# Generate bonded NIC file contents
MkBondIFfile() {
   echo "# Interface config for ${1}"
   if [ "${2}" = "0" ]
   then
      echo "DEVICE=${1}"
      echo 'BONDING_MODULE_OPTS="mode='${BONDMODE}' miimon=100"'
   else
      echo "DEVICE=${1}.${2}"
      echo "VLAN=yes"
   fi

   echo "BOOTPROTO=none"
   echo "ONBOOT=yes"
   echo "USRCTL=no"

   # Check to see if creating a "base" bond for a 802.1q environment
   if [ "${IPADDR}" = "NULL" ] || [ "${IPADDR}" = "null" ]
   then
      echo "IPADDR="
      echo "NETMASK="
   else
      echo "IPADDR=${IPADDR}"
      echo "NETMASK=${NETMASK}"
   fi

   # If has no default-route
   if [ "${GATEWAY}" = "NULL" ] || [ "${GATEWAY}" = "null" ]
   then
      echo "GATEWAY="
   else
      echo "GATEWAY=${GATEWAY}"
   fi
   echo "TYPE=BOND"
}


if [ "${IPADDR}" = "UNDEF" ]
then
   printf "Enter IP address: "
   read IPADDR
   echo "Entered: ${IPADDR}"
fi

if [ "${NETMASK}" = "UNDEF" ]
then
   printf "Enter netmask address: "
   read NETMASK
   echo "Entered: ${NETMASK}"
fi

if [ "${GATEWAY}" = "UNDEF" ]
then
   printf "Enter gateway address: "
   read GATEWAY
   echo "Entered: ${GATEWAY}"
fi

# Create workdirs
WorkDirs

# Update loaded modules as necessary
AddModAlias

# Save off prior configuration's files
SaveOrig

# Create base IF files
NICLIST=`IFlist`
for NIC in ${NICLIST}
do
   MkBaseIFfiles ${NIC} > ${NEWSCRIPTS}/ifcfg-${NIC}
done

# Create bonded IF files
if [ "${VLANID}" = "0" ]
then
   MkBondIFfile ${BONDNAME} ${VLANID} > ${NEWSCRIPTS}/ifcfg-${BONDNAME}
else
   MkBondIFfile ${BONDNAME} ${VLANID} > ${NEWSCRIPTS}/ifcfg-${BONDNAME}.${VLANID}
fi

# Copy new config files to system dir
cp ${NEWSCRIPTS}/* ${CONFDIR}

# Restart or just save?
if [ "${BOUNCE}" = "UNDEF" ]
then
   echo "Assuming multi-step config. Network not restarted."
else
   echo "Restart requested. Attempting Network restart."
   service network restart
fi

Please feel free to comment with optimizations or suggestions for enhancements

No comments:

Post a Comment