Project

General

Profile

NL_lclcamlist.pm

Extract MAC forwarding table from ethernet switch - Randy Reitz, 12/15/2011 08:14 AM

 
1
# -*- mode: Perl -*-
2
# Uses SNMP to extract MAC forwarding info from an ethernet switch or
3
# bridging device (preferrably Cisco), then returns only the information
4
# about locally attached nodes.
5
#
6
# Input: switchname, commstring
7
#
8
# Output (list): MACaddress switchname portname timestamp VLAN zero FdbStatus count
9
#
10
# timestamp: time this program was executed
11
# zero: used to be PortRootCost, but not used anymore
12
# count: number of MACs found on this port
13
#
14
# Darryl Wohlt, Fermilab 
15

    
16
sub lclcamlist {
17

    
18
use lib qw(/usr/lib/mrtg2);
19
use SNMP_Session "0.77";
20
use BER "0.77";
21
use SNMP_util "0.77";
22

    
23
my ($sw,$cstr) = @_;
24

    
25
$SNMP_Session::set_retries = 2;
26
$SNMP_Session::suppress_warnings = 2;
27
$SNMP_Session::set_timeout = 1;
28
$SNMP_Session::snmp_version = 2;
29

    
30
my $CISCO_VTP_MIB_vtpVlanState = "1.3.6.1.4.1.9.9.46.1.3.1.1.2";
31
my $CISCO_VLAN_MEMBERSHIP_MIB_vmMembershipSummaryMemberPorts = "1.3.6.1.4.1.9.9.68.1.2.1.1.2";
32
my $BRIDGE_MIB_dot1dTpFdbPort = "1.3.6.1.2.1.17.4.3.1.2";
33
my $BRIDGE_MIB_dot1dStpRootCost = "1.3.6.1.2.1.17.2.6.0";
34
my $BRIDGE_MIB_dot1dStpRootPort = "1.3.6.1.2.1.17.2.7.0";
35
my $BRIDGE_MIB_dot1dTpFdbStatus = "1.3.6.1.2.1.17.4.3.1.3";
36
my $BRIDGE_MIB_dot1dBasePortIfIndex = "1.3.6.1.2.1.17.1.4.1.2";
37
my $IF_MIB_ifName = "1.3.6.1.2.1.31.1.1.1.1";
38
my $CISCO_CDP_MIB_cdpCacheDeviceId = "1.3.6.1.4.1.9.9.23.1.2.1.1.6";
39
my $CISCO_CDP_MIB_cdpCachePlatform = "1.3.6.1.4.1.9.9.23.1.2.1.1.8";
40
my $IF_MIB_ifIndex = "1.3.6.1.2.1.2.2.1.1";
41
my $IF_MIB_ifPhysAddress = "1.3.6.1.2.1.2.2.1.6";
42
my $CISCO_PAGP_MIB_pagpGroupIfIndex = "1.3.6.1.4.1.9.9.98.1.1.1.1.8";
43
my $CISCO_LAG_MIB_clagAggPortListPorts = "1.3.6.1.4.1.9.9.225.1.4.1.1.1";
44
my $IEEE8023_LAG_MIB_dot3adAggPortSelectedAggID = "1.2.840.10006.300.43.1.2.1.1.12";
45
my $IEEE8023_LAG_MIB_dot3adAggPortAttachedAggID = "1.2.840.10006.300.43.1.2.1.1.13";
46
my $IEEE8023_LAG_MIB_dot3adAggAggregateOrIndividual = "1.2.840.10006.300.43.1.1.1.1.5";
47
my $CISCO_STP_EXTENSIONS_MIB_stpxFastStartOperMode = "1.3.6.1.4.1.9.9.82.1.9.5.1.3";
48
my ($ipaddr,$ipaddrlen,$p,$uptime,$vlan,$cstrg,$name,$element,$ifindex,$physaddr,$int,$string,$platform,$subindex,$ifpagp,$iflacp,$decmac,$port,$timestamp,$macprint,$j,$RootPort,$stat);
49
my (@long,@output,@array,@ifndx,@vlantab,@vlans,@macdec);
50
my (%PortName,%CDP,%AGG,%CDPphysaddr,%physaddrs,%TpFdbPort,%MACcount,%TpFdbStatus,%PortIfIndex,%discarded);
51

    
52
@output=();
53
# DNS check
54
$ipaddr = gethostbyname($sw);
55
$ipaddrlen = length($ipaddr); 
56
@long = unpack('C4',$ipaddr);
57
if ($ipaddrlen == 0) {
58
  push @output,"Unknown name\n";
59
  return(@output);
60
}
61

    
62
# SNMP/Ping check 
63
($uptime) = snmpget("$cstr\@$sw",'sysUptime'); 
64
if (!$uptime) { 
65
  $p=''; 
66
  $p = ping_check($sw); 
67
  unless ($p) { 
68
    push @output, "No Ping response\n"; 
69
    return(@output); 
70
  } else { 
71
    push @output, "No SNMP response\n"; 
72
    return(@output); 
73
  } 
74
} 
75

    
76
# Get the interface names
77
@array = snmpwalk("$cstr\@$sw",$IF_MIB_ifName); 
78
foreach $element (@array) { 
79
  ($ifindex,$name) = split(":",$element); 
80
  if ($name) {
81
    $PortName{$ifindex} = $name; 
82
  } else {
83
    $PortName{$ifindex} = $ifindex;
84
  }
85
} 
86

    
87
# Gather CDP Neighbors, mark Interface Index Numbers that have neighbors
88
# Gather aggregated ports, mark their Interface Index Numbers if their
89
#  physical interfaces have been marked
90

    
91
@array = snmpwalk("$cstr\@$sw",$IF_MIB_ifPhysAddress); 
92
foreach $element (@array) { 
93
  $ifindex = substr($element,0,index($element,":")); 
94
  $physaddr = substr($element,index($element,":")+1); 
95
  my $valueB = unpack("B1024", $physaddr); 
96
  my $valueH = bin2hex($valueB,1024); 
97
  $physaddrs{$ifindex} = $valueH;
98
} 
99

    
100
@array = snmpwalk("$cstr\@$sw",$CISCO_CDP_MIB_cdpCachePlatform);
101
foreach $element (@array) {
102
  ($int,$platform) = split(":",$element);
103
  ($ifindex,$subindex) = split(/\./,$int);
104
  unless ($platform =~ "Cisco IP Phone") {
105
    foreach $int (keys %physaddrs) {
106
      $CDP{$int} = 1 if ($physaddrs{$int} eq $physaddrs{$ifindex});
107
    }
108
  }
109
  $ifpagp = snmpget("$cstr\@$sw","$CISCO_PAGP_MIB_pagpGroupIfIndex.$ifindex");
110
  $AGG{$ifpagp} = 1 if (($ifpagp ne $ifindex)and($ifpagp > 0));
111
}
112

    
113
@array = snmpwalk("$cstr\@$sw",$IEEE8023_LAG_MIB_dot3adAggPortAttachedAggID);
114
foreach $element (@array) {
115
  ($ifindex,$subindex) = split(":",$element); # subindex is port-channel intf index
116
  $AGG{$subindex} = 1 if ($CDP{$ifindex}); # not all port-channels connect to CDP neighbors
117
}
118

    
119

    
120
# Get the VLANs (except 1001 thru 1024)
121

    
122
@vlantab = snmpwalk("$cstr\@$sw","$CISCO_VLAN_MEMBERSHIP_MIB_vmMembershipSummaryMemberPorts");
123
@vlans=();
124
foreach $element (@vlantab) {
125
     $vlan = substr($element,0,index($element,":"));
126
     push @vlans,$vlan if (($vlan<1001) || ($vlan>1024));
127
   }
128
push @vlans,"0" if ($#vlans < 0);
129

    
130
# Gather MACs and Stats in each VLAN
131
# Each VLAN has a unique set of Bridge Port Numbers
132

    
133
$cstrg = $cstr; 
134

    
135
foreach $vlan (@vlans) { 
136
  (%discarded,%TpFdbPort,%TpFdbStatus,%PortIfIndex) = ();
137
  $cstrg = $cstr."\@".$vlan unless ($vlan eq "0");
138
  $RootPort='';
139
  $RootPort = snmpget("$cstrg\@$sw",$BRIDGE_MIB_dot1dStpRootPort);
140
  @array = snmpwalk("$cstrg\@$sw",$BRIDGE_MIB_dot1dTpFdbPort);
141
  foreach $element (@array) {
142
    ($decmac,$port) = split(":",$element);
143
    $TpFdbPort{$decmac} = $port;
144
    $MACcount{$port}++;
145
  }
146
  @array = snmpwalk("$cstrg\@$sw",$BRIDGE_MIB_dot1dTpFdbStatus);
147
  foreach $element (@array) {
148
    ($decmac,$stat) = split(":",$element);
149
    $TpFdbStatus{$decmac} = $stat;
150
  }
151
  @array = snmpwalk("$cstrg\@$sw",$BRIDGE_MIB_dot1dBasePortIfIndex); 
152
  foreach $element (@array) {
153
    ($port,$ifindex) = split(":",$element);
154
    $PortIfIndex{$port} = $ifindex;
155
  }
156

    
157
# Process Discards
158
  foreach $decmac (keys %TpFdbPort) {  
159
    $discarded{$decmac}=1 if (
160
			      ($TpFdbStatus{$decmac} eq "4") or
161
			      ($TpFdbStatus{$decmac} eq "5") or 
162
			      (exists $CDP{$PortIfIndex{$TpFdbPort{$decmac}}}) or 
163
			      (exists $AGG{$PortIfIndex{$TpFdbPort{$decmac}}}) or
164
			      ($PortName{$PortIfIndex{$TpFdbPort{$decmac}}} eq '') or 
165
			      ($PortName{$PortIfIndex{$TpFdbPort{$decmac}}} eq ' ') or
166
			      ($TpFdbPort{$decmac} eq $RootPort)
167
			     ); 
168
  }
169
  $timestamp = qx(date +%Y\/%m\/%d\/%H:%M);
170
  chomp $timestamp;
171
  foreach $decmac (keys %TpFdbStatus) {
172
    unless ($discarded{$decmac}==1) {
173
      $macprint = '';
174
      @macdec = split(/\./,$decmac);
175
      for ($j=0;$j<6;$j++) {
176
        $macprint = $macprint . sprintf ("%02x",$macdec[$j]);
177
      }
178
      push @output, "$macprint $sw $PortName{$PortIfIndex{$TpFdbPort{$decmac}}} $timestamp $vlan 0 $TpFdbStatus{$decmac} $MACcount{$TpFdbPort{$decmac}}\n" unless ($PortName{$PortIfIndex{$TpFdbPort{$decmac}}} eq '');
179
    }
180
  }
181
}
182
return(@output); 
183
}
184

    
185
1;