1package Classes::IPFORWARDMIB::Component::RoutingSubsystem; 2our @ISA = qw(Monitoring::GLPlugin::SNMP::Item); 3use strict; 4# plugins-scripts/check_nwc_health --mode list-routes --snmpwalk walks/simon.snmpwalk 5# ipRouteTable 1.3.6.1.2.1.4.21 6# replaced by 7# ipForwardTable 1.3.6.1.2.1.4.24.2 8# deprecated by 9# ipCidrRouteTable 1.3.6.1.2.1.4.24.4 10# deprecated by the ip4/6-neutral 11# inetCidrRouteTable 1.3.6.1.2.1.4.24.7 12 13sub init { 14 my ($self) = @_; 15 $self->implements_mib('INET-ADDRESS-MIB'); 16 $self->get_snmp_tables('IP-FORWARD-MIB', [ 17 ['routes', 'ipCidrRouteTable', 'Classes::IPFORWARDMIB::Component::RoutingSubsystem::ipCidrRoute', 18 sub { 19 my ($o) = @_; 20 if ($o->opts->name && $o->opts->name =~ /\//) { 21 my ($dest, $cidr) = split(/\//, $o->opts->name); 22 my $bits = ( 2 ** (32 - $cidr) ) - 1; 23 my ($full_mask) = unpack("N", pack("C4", split(/\./, '255.255.255.255'))); 24 my $netmask = join('.', unpack("C4", pack("N", ($full_mask ^ $bits)))); 25 return defined $o->{ipCidrRouteDest} && ( 26 $o->filter_namex($dest, $o->{ipCidrRouteDest}) && 27 $o->filter_namex($netmask, $o->{ipCidrRouteMask}) && 28 $o->filter_name2($o->{ipCidrRouteNextHop}) 29 ); 30 } else { 31 return defined $o->{ipCidrRouteDest} && ( 32 $o->filter_name($o->{ipCidrRouteDest}) && 33 $o->filter_name2($o->{ipCidrRouteNextHop}) 34 ); 35 } 36 } 37 ], 38 ['routes', 'inetCidrRouteTable', 'Classes::IPFORWARDMIB::Component::RoutingSubsystem::inetCidrRoute', 39 sub { 40 my ($o) = @_; 41 if ($o->opts->name && $o->opts->name =~ /\//) { 42 my ($dest, $cidr) = split(/\//, $o->opts->name); 43 return defined $o->{inetCidrRouteDest} && ( 44 $o->filter_namex($dest, $o->{inetCidrRouteDest}) && 45 $o->filter_namex($cidr, $o->{inetCidrRoutePfxLen}) && 46 $o->filter_name2($o->{inetCidrRouteNextHop}) 47 ); 48 } else { 49 return defined $o->{inetCidrRouteDest} && ( 50 $o->filter_name($o->{inetCidrRouteDest}) && 51 $o->filter_name2($o->{inetCidrRouteNextHop}) 52 ); 53 } 54 } 55 ], 56 ]); 57 # deprecated 58 #$self->get_snmp_tables('IP-FORWARD-MIB', [ 59 # ['routes', 'ipForwardTable', 'Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route' ], 60 #]); 61 #$self->get_snmp_tables('IP-MIB', [ 62 # ['routes', 'ipRouteTable', 'Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route' ], 63 #]); 64 # 65 # Hundsglump varreckts!!!! 66 # Es gibt so Kandidaten, bei denen stecken die v6-Routen in der neuen 67 # inetCidrRouteTable (was ja korrekt ist) und die v4-Routen in der 68 # ipCidrRouteTable. Das war der Grund, weshalb beim get_snmp_tables 69 # beide abgefragt werden und nicht wie frueher ein Fallback auf von inet 70 # auf ip stattfindet, falls die inet leer ist. 71 # Korrekt waere zumindest meiner Ansicht nach, wenn sowohl v4 als auch v6 72 # in inetCidrRouteTable stuenden. Solche gibt es tatsaechlich auch. 73 # Aber dank der Hornochsen bei Cisco mit ihrer o.g. Vorgehensweise darf ich 74 # jetzt die Doubletten rausfieseln. 75 my $found = {}; 76 @{$self->{routes}} = grep { 77 if (exists $found->{$_->id()}) { 78 0; 79 } else { 80 $found->{$_->id()} = 1; 81 1; 82 } 83 } @{$self->{routes}}; 84} 85 86sub check { 87 my ($self) = @_; 88 $self->add_info('checking routes'); 89 if ($self->mode =~ /device::routes::list/) { 90 foreach (@{$self->{routes}}) { 91 $_->list(); 92 } 93 $self->add_ok("have fun"); 94 } elsif ($self->mode =~ /device::routes::count/) { 95 if (! $self->opts->name && $self->opts->name2) { 96 $self->add_info(sprintf "found %d routes via next hop %s", 97 scalar(@{$self->{routes}}), $self->opts->name2); 98 } elsif ($self->opts->name && ! $self->opts->name2) { 99 $self->add_info(sprintf "found %d routes to dest %s", 100 scalar(@{$self->{routes}}), $self->opts->name); 101 } elsif ($self->opts->name && $self->opts->name2) { 102 $self->add_info(sprintf "found %d routes to dest %s via hop %s", 103 scalar(@{$self->{routes}}), $self->opts->name, $self->opts->name2); 104 } else { 105 $self->add_info(sprintf "found %d routes", 106 scalar(@{$self->{routes}})); 107 } 108 $self->set_thresholds(warning => '1:', critical => '1:'); 109 $self->add_message($self->check_thresholds(scalar(@{$self->{routes}}))); 110 $self->add_perfdata( 111 label => 'routes', 112 value => scalar(@{$self->{routes}}), 113 ); 114 } elsif ($self->mode =~ /device::routes::exists/) { 115 # geht auch mit count-routes. irgendwann mal.... 116 $self->no_such_mode(); 117 } 118} 119 120 121package Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route; 122our @ISA = qw(Monitoring::GLPlugin::SNMP::TableItem); 123 124package Classes::IPFORWARDMIB::Component::RoutingSubsystem::ipRoute; 125our @ISA = qw(Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route); 126 127package Classes::IPFORWARDMIB::Component::RoutingSubsystem::ipCidrRoute; 128our @ISA = qw(Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route); 129 130sub finish { 131 my ($self) = @_; 132 if (! defined $self->{ipCidrRouteDest}) { 133 # we can reconstruct a few attributes from the index 134 # one customer only made ipCidrRouteStatus visible 135 $self->{ipCidrRouteDest} = join(".", map { $self->{indices}->[$_] } (0, 1, 2, 3)); 136 $self->{ipCidrRouteMask} = join(".", map { $self->{indices}->[$_] } (4, 5, 6, 7)); 137 $self->{ipCidrRouteTos} = $self->{indices}->[8]; 138 $self->{ipCidrRouteNextHop} = join(".", map { $self->{indices}->[$_] } (9, 10, 11, 12)); 139 $self->{ipCidrRouteType} = "other"; # maybe not, who cares 140 $self->{ipCidrRouteProto} = "other"; # maybe not, who cares 141 } 142} 143 144sub list { 145 my ($self) = @_; 146 printf "%16s %16s %16s %11s %7s\n", 147 $self->{ipCidrRouteDest}, $self->{ipCidrRouteMask}, 148 $self->{ipCidrRouteNextHop}, $self->{ipCidrRouteProto}, 149 $self->{ipCidrRouteType}; 150} 151 152sub id { 153 my ($self) = @_; 154 return sprintf "%s-%s", $self->{ipCidrRouteDest}, 155 $self->{ipCidrRouteNextHop}; 156} 157 158package Classes::IPFORWARDMIB::Component::RoutingSubsystem::inetCidrRoute; 159our @ISA = qw(Classes::IPFORWARDMIB::Component::RoutingSubsystem::Route); 160 161sub finish { 162 my ($self) = @_; 163 # http://www.mibdepot.com/cgi-bin/vendor_index.cgi?r=ietf_rfcs 164 # INDEX { inetCidrRouteDestType, inetCidrRouteDest, inetCidrRoutePfxLen, inetCidrRoutePolicy, inetCidrRouteNextHopType, inetCidrRouteNextHop } 165 my @tmp_indices = @{$self->{indices}}; 166 my $last_tmp = scalar(@tmp_indices) - 1; 167 # .1.3.6.1.2.1.4.24.7.1.7.1.4.0.0.0.0.32.2.0.0.1.4.10.208.143.81 = INTEGER: 25337 168 # IP-FORWARD-MIB::inetCidrRouteIfIndex.ipv4."0.0.0.0".32.2.0.0.ipv4."10.208.143.81" = INTEGER: 25337 169 # Frag mich jetzt keiner, warum dem ipv4 ein 1.4 entspricht. Ich kann 170 # jedenfalls der IP-FORWARD-MIB bzw. RFC4001 nicht entnehmen, dass fuer 171 # InetAddressType zwei Stellen des Index vorgesehen sind. Zumal nur die 172 # erste Stelle für die Textual Convention relevant ist. Aergert mich ziemlich, 173 # daß jeder bloede /usr/bin/snmpwalk das besser hinbekommt als ich. 174 # Was dazugelernt: 1=InetAddressType, 4=gehoert zur folgenden InetAddressIPv4 175 # und gibt die Laenge an. Noch mehr gelernt: wenn eine Table mit Integer und 176 # Octet String indiziert ist, dann ist die Groeße des Octet String Bestandteil 177 # der OID. Diese _kann_ weggelassen werden für den _letzten_ Index. Der ist 178 # halt dann so lang wie der Rest der OID. 179 # Mit einem IMPLIED-Keyword koennte die Laenge auch weggelassen werden. 180 181 $self->{inetCidrRouteDestType} = $self->mibs_and_oids_definition( 182 'INET-ADDRESS-MIB', 'InetAddressType', $tmp_indices[0]); 183 shift @tmp_indices; 184 185 $self->{inetCidrRouteDest} = $self->mibs_and_oids_definition( 186 'INET-ADDRESS-MIB', 'InetAddressMaker', 187 $self->{inetCidrRouteDestType}, @tmp_indices); 188 189 # laenge plus adresse weg 190 splice @tmp_indices, 0, $tmp_indices[0]+1; 191 192 $self->{inetCidrRoutePfxLen} = shift @tmp_indices; 193 $self->{inetCidrRoutePolicy} = join(".", splice @tmp_indices, 0, $tmp_indices[0]+1); 194 195 $self->{inetCidrRouteNextHopType} = $self->mibs_and_oids_definition( 196 'INET-ADDRESS-MIB', 'InetAddressType', $tmp_indices[0]); 197 shift @tmp_indices; 198 199 $self->{inetCidrRouteNextHop} = $self->mibs_and_oids_definition( 200 'INET-ADDRESS-MIB', 'InetAddressMaker', 201 $self->{inetCidrRouteNextHopType}, @tmp_indices); 202 203 if ($self->{inetCidrRouteDestType} eq "ipv4") { 204 my $bits = ( 2 ** (32 - $self->{inetCidrRoutePfxLen}) ) - 1; 205 my ($full_mask) = unpack("N", pack("C4", split(/\./, '255.255.255.255'))); 206 my $netmask = join('.', unpack("C4", pack("N", ($full_mask ^ $bits)))); 207 $self->{inetCidrRouteMask} = $netmask; 208 } 209 210} 211 212sub list { 213 my ($self) = @_; 214 printf "%16s %16s %16s %11s %7s\n", 215 $self->{inetCidrRouteDest}, $self->{inetCidrRoutePfxLen}, 216 $self->{inetCidrRouteNextHop}, $self->{inetCidrRouteProto}, 217 $self->{inetCidrRouteType}; 218} 219 220sub id { 221 my ($self) = @_; 222 return sprintf "%s-%s", $self->{inetCidrRouteDest}, 223 $self->{inetCidrRouteNextHop}; 224} 225