Wednesday 13 May 2009

cdpinfo and cdpinfo script

Display Cisco Discovery Protocol packet information via tcpdump or snoop. This information includes the name of the network switch the network interface is connected to, plus the port number, vlan, and duplex of the port.


#!/bin/ksh
#
# C D P I N F O . K S H
#
# Script to get the CDP packet from a Cisco switch
#

cdpinfo() {
nic=$1

#
# e1000 driver, special case

IFS="$OLDIFS"

if [ "$(echo "$nic" | grep "e1000")" ]
then
driver=e1000g
instance=`echo "$nic" | sed 's/e1000g//g'`
else
# now work out the speed/duplex/link, etc
driver=`echo $nic | sed 's/\([^0-9]*\)[0-9]*/\1/'`
instance=`echo $nic | sed 's/[^0-9]*\([0-9]*\)/\1/'`
fi

if [ "$driver" != "le" -a "$driver" != "qe" ]; then
if [ "$driver" = "ge" ]; then
advnegname="adv_1000autoneg_cap"
lpnegname="lp_1000autoneg_cap"
else
advnegname="adv_autoneg_cap"
lpnegname="lp_autoneg_cap"
fi

if [ "$driver" != "dmfe" -a "$driver" != "bge" -a "$driver" != e1000g -a "$d
river" != nge ]; then
# set the instance
/usr/sbin/ndd -set /dev/$driver instance $instance

# dmfe/bge/e1000/nge cards don't support the link provider
# (lp_*_cap) variables, ce uses kstat
if [ "$driver" = "ce" ]; then
lpneg=`kstat -p -m $driver -i $instance -s lp_cap_autoneg | awk '{print
$NF}'`
else
lpneg=`/usr/sbin/ndd /dev/$driver $lpnegname`
fi
case $lpneg in
0) lpneg=none ;;
1) lpneg=auto ;;
esac
else
# use the individual instance /dev entries
olddriver=$driver
driver="$driver$instance"

# set to unknown as per above
lpneg=`/usr/sbin/ndd /dev/$driver $lpnegname`
case $lpneg in
0) lpneg=none ;;
1) lpneg=auto ;;
esac
fi

advneg=`/usr/sbin/ndd /dev/$driver $advnegname`
case $advneg in
0) advneg=none ;;
1) advneg=auto ;;
esac

if [ "$driver" = "ce" ]; then
linkstatus=`kstat -p -m $driver -i $instance -s link_up | awk '{print $NF}
'`
else
linkstatus=`/usr/sbin/ndd /dev/$driver link_status`
fi
case $linkstatus in
0) linkstatus=down ;;
1) linkstatus=up ;;
esac

if [ "$driver" = "ce" ]; then
linkspeed=`kstat -p -m $driver -i $instance -s link_speed | awk '{print $N
F}'`
else
linkspeed=`/usr/sbin/ndd /dev/$driver link_speed`
fi
case $linkspeed in
0) linkspeed=10 ;;
1) linkspeed=100 ;;
esac

if [ "$driver" = "ce" ]; then
linkmode=`kstat -p -m $driver -i $instance -s link_duplex | awk '{print $N
F}'`
elif [ "$olddriver" = "bge" ]; then
linkmode=`kstat -p -m $olddriver -i $instance -s duplex | awk '{print $NF}
'`
else
linkmode=`/usr/sbin/ndd /dev/$driver link_mode`
fi
case $linkmode in
0) linkmode=HDX ;;
1) linkmode=FDX ;;
2) linkmode=FDX ;;
full) linkmode=FDX ;;
esac
else
advneg="????"
lpneg="????"
linkstatus="????"
linkspeed=10
linkmode=HDX
fi

# this runs the snoop and extracts the hexdump of the packet,
# splits the 4 digit strings into 2 digit strings and makes the
# hex upper case
snoopcriteria="ether 01:00:0c:cc:cc:cc and ether[20:2] = 0x2000"
switchid="??????????"; port="?/??"; duplex="???"; vlan="????";

snoop -x 0 -c 1 -d $nic $snoopcriteria 2>&1 > /tmp/.cdpinfo.ksh.$$ 2>&1 &

# get the pids, kick off the alarm and wait for the command to exit
cmdpid=$!
(sleep 65; kill $cmdpid > /dev/null 2>&1) &
alarmpid=$!
wait $cmdpid > /dev/null 2>&1
kill $alarmpid > /dev/null 2>&1

# otherwise, go ahead and parse the cdp packet
set -A rawpacket ` \
grep '^[ ][ ]*[0-9][0-9]*' /tmp/.cdpinfo.ksh.$$ | \
cut -c8-46 | \
sed 's/\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)/\1 \2/g' | \
tr '[a-f]' '[A-F]'`

typeset -i arraylength=${#rawpacket[*]}
typeset -i i=0 id=0 len=0 subi=0 boolean=0 num=0

# grab the CDP version
typeset -i cdpver=${rawpacket[$(echo "ibase=16; 16" | bc)]}

# skip to location 1A in the packet
i=$(echo "ibase=16; 1A"|bc)
while [ $i -lt $arraylength ]; do
id=$(echo "ibase=16; ${rawpacket[$i]}*100+${rawpacket[$i+1]}" | bc)
len=$(echo "ibase=16; ${rawpacket[$i+2]}*100+${rawpacket[$i+3]}" | bc)
string=""

case $id in
1) subi=4
while [ $subi -lt $len ]; do
char=$(echo "ibase=16; obase=8; ${rawpacket[$i+$subi]}" | bc)
string="${string}\0${char}"
subi=$subi+1
done

switchid=$(print $string)
switchid=$(echo $switchid | sed 's/[^(]*[(]\([^)]*\)[)]/\1/' | sed s'/G
igabitEthernet//g')
;;
3) subi=4
while [ $subi -lt $len ]; do
char=$(echo "ibase=16; obase=8; ${rawpacket[$i+$subi]}" | bc)
string="${string}\0${char}"
subi=$subi+1
done

port=$(print $string | sed s'/GigabitEthernet//g')
;;
10) subi=4; num=0
while [ $subi -lt $len ]; do
num=$(echo "ibase=16; $num*100+${rawpacket[$i+$subi]}" | bc)
subi=$subi+1
done

vlan=$num
;;
11) boolean=$(echo "ibase=16; ${rawpacket[$i+4]}" | bc)
if [ $boolean == 0 ]; then
duplex="HDX"
else
duplex="FDX"
fi
esac
i=$i+$len
done

# cdp version 1 doesn't tell you the duplex
if [ $cdpver = 1 ]; then
duplex="???"
fi

# remove the tempfile
rm -f /tmp/.cdpinfo.ksh.$$
}

#
# MAIN
#

# print header
echo "NIC IP_ADDR SWITCHID PORT VLAN LINK SPEED SWITCH_N/D HOST_N/D" | awk '{pri
ntf("%-8s %-13s %-34s %-8s %-8s %-8s %-10s %-13s %-13s\n", $1, $2, $3, $4, $5, $
6, $7, $8, $9)}'
echo "--------------------------------------------------------------------------
--------------------------------------------"
echo

#
# The old version assumes it needs to be plumbed up

#if [ $# = 0 ]; then
# nics=`ifconfig -a|grep '^[a-z][a-z]*[0-9]' \
# | grep -v lo0 \
# | egrep -v ':[0-9]: ' \
# | grep UP \
# | cut -d: -f1`
#else
# nics=$@
#fi

NIC_DATA=$(/usr/bin/kstat -p -c net | egrep -v "lpfc|streams|lo0|dls|ip|ipsec|tc
p|udp" | egrep "link_up|duplex" | grep -v link_duplex | awk -F: '{ printf("%s%s
%s\n",$1,$2,$4)}' | sort -u | sed -e s'/link_up//g' -e s'/duplex//g')

OLDIFS="$IFS"

IFS='
'
# now, cycle through the nics
for LINE in `echo "$NIC_DATA"`
do
NIC=`echo "$LINE" | awk '{print($1)}'`
LINK=`echo "$LINE" | awk '{print($2)}'`

#echo "NIC = $NIC"
#echo "LINK = $LINK"
if [ "$LINK" != "1" ] && [ "$LINK" != "full" ]
then
echo "$NIC LINK_DOWN" | awk '{printf("%-8s %-13s\n", $1, $2)}'
continue
else
cdpinfo ${NIC}
IFCONFIG=`ifconfig ${NIC} 2> /dev/null | grep inet | awk '{print($2)}'`
if [ ! "$IFCONFIG" ]
then
IFCONFIG="NOT_PLUMBED"
fi
echo "$NIC $IFCONFIG ${switchid} ${port} ${vlan} ${linkstatus} ${linkspeed
} ${lpneg}/${duplex} ${advneg}/${linkmode}" | awk '{printf("%-8s %-13s %-34s %-8
s %-8s %-8s %-10s %-13s %-13s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9)}'
fi

done

No comments: