Device connected to CISCO CDP enabled switch can sniff CDP packets and gather inflormation about port like switch name, trunk and VLAN IDs, port number like Gi1/5.
VMware support it by default and it can be seen in GUI in networking tab.
AIX / VIOS doesn't support that by default but it can be gathered by script using tcpdump.
Script for CDP on AIX can be downloaded here:
http://the-welters.com/professional/scripts/
Here is the script:
#!/usr/bin/perl
#
# Listen for Cisco Discovery Protocol (CDP) packets
# and print out key values such as switch, port, vlan, and duplex.
#
# This script depends on either "snoop" (Solaris) or
# "tcpdump" (AIX, and others). Both of those programs generally
# must be run as root.
#
# It has been tested on Solaris 10 and AIX 5.3.
#
# Andy Welter
# Version 1.1
# July 2007
# Support timeout values while waiting on the cdp packet.
# Version 1.0
# December 2006
# Initial Version.
#
#
$usage="cdpinfo -i [-t timeoutvalue] [-v]\n-i use the enX device name for the interface to watch\n-t timeout value in seconds. Don't wait for a cdp packet longer than this. default is 60 seconds. zero means no limit.\n-v verbose output\n";
use Getopt::Std;
if ( getopts ('i:t:v') == 0) {
print "$usage";
exit 1;
};
$idev=$opt_i;
if ($opt_i) {
$iface="-i $opt_i";
};
$verbose=$opt_v;
$timeout=$opt_t;
#
# convert string data to hex characters.
#
sub hexprint {
my ($string)=@_;
my $hex="";
my $ii,$len;
$len=length ($string);
$ii=0;
@bytes=unpack "C*",$string;
foreach $byte (@bytes) {
$hex=$hex . sprintf "%02x ",$byte;
$ii++;
};
return $hex;
};
#
# Parse TCP dump output to acquire a CDP packet
sub tcpdump {
my ($cmd)=@_;
# tcpdump omits the first 14 bytes of a packet in the hex dump
# so put some filler in the packet string
my $packet="01234567890123";
open (GETPACKET, "$cmd") || die "cannot open $cmd\n";
while ( $_ = ) {
chomp;
#
# look a line that starts with white space, followed by at least
# 2 hex characters
if (m/^\s+([\da-fA-F]+ )/) {
s/^\s+//;
@data=split /\s+/,$_,8;
foreach $bytes (@data) {
$verbose && print "$bytes ";
$packet=$packet . pack "H4", $bytes;
};
$verbose && print "\n";
} ;
};
close GETPACKET;
return $packet;
};
#
# Parse "snoop" output for the packet
sub snoop {
my ($cmd)=@_;
my $packet="";
open (GETPACKET, "$cmd") || die "cannot open $cmd\n";
while ( $_ = ) {
chomp;
print "-- $_\n";
if (/^\s+\d+:/) {
s/^\s+//;
@data=split /\s+/,$_,10;
shift @data;
pop @data;
foreach $bytes (@data) {
$packet=$packet . pack "H4", $bytes;
};
};
};
close GETPACKET;
return $packet;
};
#
# Parse the acquired CDP packet for key values.
#
sub decodePacket {
my ($packet)=@_;
my $plen,$string,$ii,$flength,$switchName,$switchPort,$ftype,$vlan,$duplex;
# decode the packet
# ethernet layout:
# 0-7 8 byte preamble
# 8-13 6 byte dest mac addr
# 14-19 6 byte source mac addr
# 20-21 2 byte type field
# 22-23 2 byte check sum
# 24-25 2 byte ???
# 26-27 2 byte first CDP data field
# 28-29 2 byte field length (including field type and length)
# 30-- Variable data.
# 4 byte CRC field.
#
# Field type indicators
# Device-ID => 0x01
# Version-String => 0x05
# Platform => 0x06
# Address => 0x02
# Port-ID => 0x03
# Capability => 0x04
# VTP-Domain => 0x09
# VLAN-ID => 0x0a
# Duplex => 0x0b
# AVVID-Trust => 0x12
# AVVID-CoS => 0x13);
$verbose && printf "packet len=%d\n",length($packet);
#
# The CDP packet data starts at offset 26
$ii=26;
$plen=length ($packet);
while ( $ii < $plen-4) {
$ftype=unpack "S", substr ($packet, $ii, 2);
$flength=unpack "S", substr ($packet, $ii+2, 2);
if ( $ftype == 1 ) {
$switchName=substr ($packet,$ii+4,$flength-4);
} elsif ( $ftype == 3 ) {
$switchPort=substr ($packet,$ii+4,$flength-4);
} elsif ( $ftype == 10 ) {
$vlan=unpack "s",substr ($packet,$ii+4,$flength-4);
} elsif ( $ftype == 11 ) {
$duplex=unpack "c",substr ($packet,$ii+4,$flength-4);
};
$string=substr ($packet,$ii+4,$flength-4);
$fvalue=hexprint ($string);
$string=~s/\W/./g;
$verbose && printf "\noffset=%d, type 0x%04x, length 0x%04x\nHex Value:\n%s\nASCII value:\n%s\n\n",
$ii,$ftype, $flength-4,$fvalue,$string;
if ($flength == 0 ) {
$ii=$plen;
};
$ii=$ii+$flength;
};
return sprintf "\"%s\",\"%s\",\"%d\",\"0x%02x\"",
$switchName,$switchPort,$vlan,$duplex;
};
#
# MAIN ROUTINE
#
# determine whether we are a snoop or tcpdump kinda system
$cmd=`which tcpdump`;
chomp $cmd;
if ( $cmd ne "" ) {
$cmd= "$cmd $iface -s 1500 -x -c 1 'ether [20:2] = 0x2000' 2>/dev/null |";
} else {
$cmd=`which snoop`;
chomp $cmd;
if ( $cmd ne "" ) {
$cmd="$cmd $iface -s 1500 -x0 -c 1 'ether[20:2] = 0x2000' 2>/dev/null |";
} else {
print "ERROR: neither snoop nor tcpdump in my path\n";
exit 1;
};
};
sub timeout {
die "TIMEOUT";
};
$SIG{ALRM}=\&timeout;
eval {
alarm ($timeout);
#
# use tcpdump or snoop to get a CDP packet
if ( $cmd=~m/snoop/ ) {
$packet=snoop ($cmd);
} elsif ( $cmd=~m/tcpdump/ ) {
$packet=tcpdump($cmd);
} else {
print "ERROR: snoop or tcpdump not found\n";
exit 1;
};
alarm(0);
};
if ($@ =~ "TIMEOUT") {
$packet="";
};
#
# Decode the acquired packet and print the results.
print '"' . $idev . '",' . decodePacket ($packet) . "\n";
Here also nice tool for CDP
ReplyDeletehttp://www.perzl.org/aix/index.php?n=Main.Cdpr
Thanks, seems to be useful as well :)
ReplyDelete