1package Classes::IFMIB::Component::InterfaceSubsystem; 2our @ISA = qw(Monitoring::GLPlugin::SNMP::Item); 3use strict; 4use JSON; 5use File::Slurp qw(read_file); 6 7sub init { 8 my ($self) = @_; 9 $self->{interfaces} = []; 10 $self->{etherstats} = []; 11 #$self->session_translate(['-octetstring' => 1]); 12 my @iftable_columns = qw(ifDescr ifAlias ifName); 13 my @ethertable_columns = qw(); 14 my @ethertablehc_columns = qw(); 15 my @rmontable_columns = qw(); 16 my @ipaddress_columns = qw(); 17 18 my @iftable_traffic_columns = qw(ifInOctets ifOutOctets ifSpeed); 19 my @iftable_traffic_hc_columns = qw(ifHCInOctets ifHCOutOctets ifHighSpeed); 20 my @iftable_status_columns = qw(ifOperStatus ifAdminStatus); 21 my @iftable_packets_columns = qw(ifInUcastPkts ifOutUcastPkts 22 ifInMulticastPkts ifOutMulticastPkts 23 ifInBroadcastPkts ifOutBroadcastPkts); 24 my @iftable_packets_hc_columns = qw(ifHCInUcastPkts ifHCOutUcastPkts 25 ifHCInMulticastPkts ifHCOutMulticastPkts 26 ifHCInBroadcastPkts ifHCOutBroadcastPkts); 27 my @iftable_error_columns = qw(ifInErrors ifOutErrors); 28 my @iftable_discard_columns = qw(ifInDiscards ifOutDiscards); 29 30 $self->implements_mib('INET-ADDRESS-MIB'); 31 if ($self->mode =~ /device::interfaces::list/) { 32 } elsif ($self->mode =~ /device::interfaces::complete/) { 33 push(@iftable_columns, @iftable_status_columns); 34 push(@iftable_columns, @iftable_traffic_columns); 35 push(@iftable_columns, @iftable_packets_columns); 36 push(@iftable_columns, @iftable_traffic_hc_columns); 37 push(@iftable_columns, @iftable_packets_hc_columns); 38 push(@iftable_columns, @iftable_error_columns); 39 push(@iftable_columns, @iftable_discard_columns); 40 # kostenpflichtiges feature # push(@ethertable_columns, qw( 41 # dot3StatsDuplexStatus 42 #)); 43 } elsif ($self->mode =~ /device::interfaces::usage/) { 44 push(@iftable_columns, @iftable_status_columns); 45 push(@iftable_columns, @iftable_traffic_columns); 46 push(@iftable_columns, @iftable_traffic_hc_columns); 47 } elsif ($self->mode =~ /device::interfaces::errors/) { 48 push(@iftable_columns, @iftable_status_columns); 49 push(@iftable_columns, @iftable_traffic_columns); 50 push(@iftable_columns, @iftable_packets_columns); 51 push(@iftable_columns, @iftable_traffic_hc_columns); 52 push(@iftable_columns, @iftable_packets_hc_columns); 53 push(@iftable_columns, @iftable_error_columns); 54 } elsif ($self->mode =~ /device::interfaces::discards/) { 55 push(@iftable_columns, @iftable_status_columns); 56 push(@iftable_columns, @iftable_traffic_columns); 57 push(@iftable_columns, @iftable_packets_columns); 58 push(@iftable_columns, @iftable_traffic_hc_columns); 59 push(@iftable_columns, @iftable_packets_hc_columns); 60 push(@iftable_columns, @iftable_discard_columns); 61 } elsif ($self->mode =~ /device::interfaces::broadcast/) { 62 push(@iftable_columns, @iftable_status_columns); 63 push(@iftable_columns, @iftable_traffic_columns); 64 push(@iftable_columns, @iftable_packets_columns); 65 push(@iftable_columns, @iftable_traffic_hc_columns); 66 push(@iftable_columns, @iftable_packets_hc_columns); 67 } elsif ($self->mode =~ /device::interfaces::operstatus/) { 68 push(@iftable_columns, @iftable_status_columns); 69 } elsif ($self->mode =~ /device::interfaces::availability/) { 70 push(@iftable_columns, qw( 71 ifType ifOperStatus ifAdminStatus 72 ifLastChange ifHighSpeed ifSpeed 73 )); 74 } elsif ($self->mode =~ /device::interfaces::etherstats/) { 75 push(@iftable_columns, @iftable_status_columns); 76 push(@iftable_columns, @iftable_packets_columns); 77 push(@iftable_columns, @iftable_packets_hc_columns); 78 push(@ethertable_columns, qw( 79 dot3StatsAlignmentErrors dot3StatsFCSErrors 80 dot3StatsSingleCollisionFrames dot3StatsMultipleCollisionFrames 81 dot3StatsSQETestErrors dot3StatsDeferredTransmissions 82 dot3StatsLateCollisions dot3StatsExcessiveCollisions 83 dot3StatsInternalMacTransmitErrors dot3StatsCarrierSenseErrors 84 dot3StatsFrameTooLongs dot3StatsInternalMacReceiveErrors 85 )); 86 push(@ethertablehc_columns, qw( 87 dot3HCStatsFCSErrors 88 )); 89 push(@rmontable_columns, qw( 90 etherStatsCRCAlignErrors 91 )); 92 if ($self->opts->report !~ /^(long|short|html)$/) { 93 my @reports = split(',', $self->opts->report); 94 @ethertable_columns = grep { 95 my $ec = $_; 96 grep { 97 $ec eq $_; 98 } @reports; 99 } @ethertable_columns; 100 @ethertablehc_columns = grep { 101 my $ec = $_; 102 grep { 103 $ec eq $_; 104 } @reports; 105 } @ethertablehc_columns; 106 @rmontable_columns = grep { 107 my $ec = $_; 108 grep { 109 $ec eq $_; 110 } @reports; 111 } @rmontable_columns; 112 } 113 if (grep /dot3HCStatsFCSErrors/, @ethertablehc_columns) { 114 # wenn ifSpeed == 4294967295, dann 10GBit, dann dot3HCStatsFCSErrors 115 push(@iftable_columns, qw( 116 ifSpeed 117 )); 118 } 119 if (@rmontable_columns) { 120 push(@rmontable_columns, qw( 121 etherStatsIndex 122 etherStatsDataSource 123 )); 124 } 125 } elsif ($self->mode =~ /device::interfaces::duplex/) { 126 push(@iftable_columns, qw( 127 ifType ifSpeed ifOperStatus ifAdminStatus ifHighSpeed 128 )); 129 push(@ethertable_columns, qw( 130 dot3StatsDuplexStatus 131 )); 132 } elsif ($self->mode =~ /device::interfaces::uptime/) { 133 push(@iftable_columns, qw( 134 ifLastChange 135 )); 136 } else { 137 @iftable_columns = (); 138 } 139 if ($self->mode =~ /device::interfaces::list/) { 140 $self->update_interface_cache(1); 141 my @indices = $self->get_interface_indices(); 142 foreach my $ifIndex (map { $_->[0] } @indices) { 143 my $ifDescr = $self->{interface_cache}->{$ifIndex}->{ifDescr}; 144 my $ifName = $self->{interface_cache}->{$ifIndex}->{ifName} || '________'; 145 my $ifAlias = $self->{interface_cache}->{$ifIndex}->{ifAlias} || '________'; 146 my $interface_class = ref($self)."::Interface"; 147 my $interface = $interface_class->new( 148 ifIndex => $ifIndex, 149 ifDescr => $ifDescr, 150 ifName => $ifName, 151 ifAlias => $ifAlias, 152 indices => [$ifIndex], 153 flat_indices => $ifIndex, 154 ); 155 $self->enrich_interface_attributes($interface); 156 push(@{$self->{interfaces}}, $interface); 157 } 158 # die sind mit etherStatsDataSource verknuepft 159 } elsif ($self->mode =~ /device::interfaces/) { 160 my $if_has_changed = $self->update_interface_cache(0); 161 my $only_admin_up = 162 $self->opts->name && $self->opts->name eq '_adminup_' ? 1 : 0; 163 my $only_oper_up = 164 $self->opts->name && $self->opts->name eq '_operup_' ? 1 : 0; 165 # --name '(lan|wan|_adminup_)' 166 # alle mit match auf lan|wan, und davon dann die mit admin up 167 my $plus_admin_up = 168 $self->opts->name && ! $only_admin_up && 169 $self->opts->name =~ /_adminup_/ ? 1 : 0; 170 my $plus_oper_up = 171 $self->opts->name && ! $only_oper_up && 172 $self->opts->name =~ /_operup_/ ? 1 : 0; 173 if ($only_admin_up || $only_oper_up) { 174 $self->override_opt('name', undef); 175 $self->override_opt('drecksptkdb', undef); 176 } 177 my @indices = $self->get_interface_indices(); 178 my @all_indices = @indices; 179 my @selected_indices = (); 180 if (! $self->opts->name && ! $self->opts->name3) { 181 # get_table erzwingen 182 @indices = (); 183 $self->bulk_is_baeh(10); 184 } 185 @iftable_columns = do { my %seen; grep { !$seen{$_}++ } @iftable_columns }; # uniq 186 if ((! $self->opts->name && ! $self->opts->name3) || scalar(@indices) > 0) { 187 my @save_indices = @indices; # die werden in get_snmp_table_objects geshiftet 188 if ($plus_admin_up || $plus_oper_up) { 189 # mit minimalen columns schnell vorfiltern -> @indices evt. reduzieren 190 # nicht fuer only_admin/oper_up, sonst wird aus @indices = () 191 # eine riesige liste, deren abarbeitung laenger dauert als 192 # ein get_table bei @indices = () 193 my @up_indices = (); 194 foreach ($self->get_snmp_table_objects( 195 'IFMIB', 'ifTable+ifXTable', \@indices, \@iftable_status_columns)) { 196 next if $plus_admin_up && $_->{ifAdminStatus} ne 'up'; 197 next if $plus_oper_up && $_->{ifOperStatus} ne 'up'; 198 push(@up_indices, [$_->{indices}->[0]]); 199 } 200 @indices = @up_indices; 201 } 202 foreach ($self->get_snmp_table_objects( 203 'IFMIB', 'ifTable+ifXTable', \@indices, \@iftable_columns)) { 204 next if $only_admin_up && $_->{ifAdminStatus} ne 'up'; 205 next if $only_oper_up && $_->{ifOperStatus} ne 'up'; 206 $self->make_ifdescr_unique($_); 207 $self->enrich_interface_attributes($_); 208 my $interface_class = ref($self)."::Interface"; 209 my $interface = $interface_class->new(%{$_}); 210 $interface->{columns} = [@iftable_columns]; 211 push(@{$self->{interfaces}}, $interface); 212 } 213 # kostenpflichtiges feature # if ($self->mode =~ /device::interfaces::(duplex|etherstats|complete)/) { 214 if ($self->mode =~ /device::interfaces::(duplex|etherstats)/) { 215 @indices = @save_indices; 216 my @etherindices = (); 217 my @etherhcindices = (); 218 foreach my $interface (@{$self->{interfaces}}) { 219 push(@selected_indices, [$interface->{ifIndex}]); 220 if (@ethertablehc_columns && $interface->{ifSpeed} == 4294967295) { 221 push(@etherhcindices, [$interface->{ifIndex}]); 222 } 223 push(@etherindices, [$interface->{ifIndex}]); 224 } 225 $self->debug( 226 sprintf 'all_interfaces %d, selected %d, ether %d, etherhc %d', 227 scalar(@all_indices), scalar(@selected_indices), 228 scalar(@etherindices), scalar(@etherhcindices)); 229 my @rmonpatterns = map { 230 '([\.]*1.3.6.1.2.1.2.2.1.1.'.$_.')'; 231 } map { 232 $_->[0]; 233 } @selected_indices; 234 if ($only_admin_up || $only_oper_up) { 235 if (scalar(@etherindices) > scalar(@all_indices) * 0.70) { 236 $self->bulk_is_baeh(20); 237 @etherindices = (); 238 } 239 if (scalar(@etherhcindices) > scalar(@all_indices) * 0.70) { 240 $self->bulk_is_baeh(20); 241 @etherhcindices = (); 242 } 243 if (scalar(@rmonpatterns) > scalar(@all_indices) * 0.70) { 244 $self->bulk_is_baeh(20); 245 @rmonpatterns = (); 246 } 247 } elsif (! @indices) { 248 $self->bulk_is_baeh(20); 249 @etherindices = (); 250 if (scalar(@etherhcindices) > scalar(@all_indices) * 0.70) { 251 @etherhcindices = (); 252 } 253 @rmonpatterns = (); 254 } 255 if (@ethertable_columns) { 256 # es gibt interfaces mit ifSpeed == 4294967295 257 # aber nix in dot3HCStatsTable. also dann dot3StatsTable fuer alle 258 if ($self->implements_mib('EtherLike-MIB', 'dot3StatsTable')) { 259 foreach my $etherstat ($self->get_snmp_table_objects( 260 'EtherLike-MIB', 'dot3StatsTable', \@etherindices, \@ethertable_columns)) { 261 foreach my $interface (@{$self->{interfaces}}) { 262 if ($interface->{ifIndex} == $etherstat->{flat_indices}) { 263 foreach my $key (grep /^dot3/, keys %{$etherstat}) { 264 $interface->{$key} = $etherstat->{$key}; 265 push(@{$interface->{columns}}, $key); 266 } 267 last; 268 } 269 } 270 } 271 } 272 } 273 if (@ethertablehc_columns && scalar(@etherhcindices)) { 274 if ($self->implements_mib('EtherLike-MIB', 'dot3HCStatsTable')) { 275 foreach my $etherstat ($self->get_snmp_table_objects( 276 'EtherLike-MIB', 'dot3HCStatsTable', \@etherhcindices, \@ethertablehc_columns)) { 277 foreach my $interface (@{$self->{interfaces}}) { 278 if ($interface->{ifIndex} == $etherstat->{flat_indices}) { 279 foreach my $key (grep /^dot3/, keys %{$etherstat}) { 280 $interface->{$key} = $etherstat->{$key}; 281 push(@{$interface->{columns}}, $key); 282 } 283 if (grep /^dot3HCStatsFCSErrors/, @{$interface->{columns}}) { 284 @{$interface->{columns}} = grep { 285 $_ if $_ ne 'dot3StatsFCSErrors'; 286 } @{$interface->{columns}}; 287 } 288 last; 289 } 290 } 291 } 292 } 293 } 294 if (@rmontable_columns) { 295 if ($self->opts->name) { 296 $self->override_opt('drecksptkdb', '^('.join('|', @rmonpatterns).')$'); 297 $self->override_opt('name', '^('.join('|', @rmonpatterns).')$'); 298 $self->override_opt('regexp', 1); 299 } 300 # Value von etherStatsDataSource entspricht ifIndex 1.3.6.1.2.1.2.2.1.1.idx 301 if ($self->implements_mib('RMON-MIB', 'etherStatsTable')) { 302 foreach my $etherstat ($self->get_snmp_table_objects_with_cache( 303 'RMON-MIB', 'etherStatsTable', 'etherStatsDataSource', \@rmontable_columns, $if_has_changed ? 1 : -1)) { 304 $etherstat->{etherStatsDataSource} =~ s/^\.//g; 305 foreach my $interface (@{$self->{interfaces}}) { 306 if ('1.3.6.1.2.1.2.2.1.1.'.$interface->{ifIndex} eq $etherstat->{etherStatsDataSource}) { 307 foreach my $key (grep /^etherStats/, keys %{$etherstat}) { 308 $interface->{$key} = $etherstat->{$key}; 309 push(@{$interface->{columns}}, $key); 310 } 311 last; 312 } 313 } 314 } 315 } 316 } 317 # @{$self->{interfaces}} haben ein ->{columns} 318 # alle ausfiltern, die _keine_ der gewuenschten oids haben 319 @{$self->{interfaces}} = grep { 320 # check (@ethertable_columns, @rmontable_columns) 321 my $found = undef; 322 foreach my $oid (@ethertable_columns, @rmontable_columns) { 323 if (grep { $oid eq $_ } @{$_->{columns}}) { 324 $found = 1; 325 } 326 } 327 $found; 328 } @{$self->{interfaces}}; 329 foreach my $interface (@{$self->{interfaces}}) { 330 delete $interface->{dot3StatsIndex}; 331 delete $interface->{etherStatsIndex}; 332 delete $interface->{etherStatsDataSource}; 333 @{$interface->{columns}} = grep { 334 $_ !~ /^(dot3StatsIndex|etherStatsIndex|etherStatsDataSource)$/; 335 } @{$interface->{columns}}; 336 $interface->init_etherstats; 337 } 338 if (scalar(@{$self->{interfaces}}) == 0) { 339 $self->add_unknown('device probably has no RMON-MIB or EtherLike-MIB'); 340 } 341 } 342 } 343 } 344 if ($self->opts->report =~ /^(\w+)\+address/) { 345 $self->override_opt('report', $1); 346 # flat_indices, weil die Schluesselelemente ipAddressAddrType+ipAddressAddr 347 # not-accessible sind und im Index stecken. 348 if (scalar(@{$self->{interfaces}}) > 0) { 349 my $interfaces_by_index = {}; 350 map { 351 $interfaces_by_index->{$_->{ifIndex}} = $_; 352 } @{$self->{interfaces}}; 353 my $indexpattern = join('|', map { 354 $_->{ifIndex} 355 } @{$self->{interfaces}}); 356 $self->override_opt('name', '^('.$indexpattern.')$'); 357 $self->override_opt('drecksptkdb', '^('.$indexpattern.')$'); 358 $self->override_opt('regexp', 1); 359 360 $self->get_snmp_objects('IP-MIB', qw(ipv4InterfaceTableLastChange ipv6InterfaceTableLastChange)); 361 $self->{ipv4InterfaceTableLastChange} ||= 0; 362 $self->{ipv6InterfaceTableLastChange} ||= 0; 363 $self->{ipv46InterfaceTableLastChange} = 364 $self->{ipv4InterfaceTableLastChange} > $self->{ipv6InterfaceTableLastChange} ? 365 $self->{ipv4InterfaceTableLastChange} : $self->{ipv6InterfaceTableLastChange}; 366 $self->{bootTime} = time - $self->uptime(); 367 $self->{ipAddressTableLastChange} = $self->{bootTime} + $self->timeticks($self->{ipv46InterfaceTableLastChange} / 100); 368 369 $self->update_entry_cache(0, 'IP-MIB', 'ipAddressTable', 'ipAddressIfIndex', $self->{ipAddressTableLastChange}); 370 my @address_indices = $self->get_cache_indices('IP-MIB', 'ipAddressTable', 'ipAddressIfIndex'); 371 $self->{addresses} = []; 372 if (@address_indices) { 373 # es gibt adressen zu den ausgewaehlten interfaces 374 foreach ($self->get_snmp_table_objects_with_cache( 375 'IP-MIB', 'ipAddressTable', 'ipAddressIfIndex', ['ipAddressIfIndex'], 0)) { 376 my $address = Classes::IFMIB::Component::InterfaceSubsystem::Address->new(%{$_}); 377 push(@{$self->{addresses}}, $address); 378 if (exists $interfaces_by_index->{$address->{ipAddressIfIndex}}) { 379 if (exists $interfaces_by_index->{$address->{ipAddressIfIndex}}->{ifAddresses}) { 380 push(@{$interfaces_by_index->{$address->{ipAddressIfIndex}}->{ifAddresses}}, $address->{ipAddressAddr}); 381 } else { 382 $interfaces_by_index->{$address->{ipAddressIfIndex}}->{ifAddresses} = [$address->{ipAddressAddr}]; 383 } 384 } 385 } 386 } 387 foreach (@{$self->{interfaces}}) { 388 $_->{ifAddresses} = exists $_->{ifAddresses} ? join(", ", @{$_->{ifAddresses}}) : ""; 389 } 390 } 391 } 392} 393 394sub check { 395 my ($self) = @_; 396 $self->add_info('checking interfaces'); 397 if (scalar(@{$self->{interfaces}}) == 0) { 398 $self->add_unknown('no interfaces'); 399 return; 400 } 401 if ($self->mode =~ /device::interfaces::list/) { 402 foreach (sort {$a->{ifIndex} <=> $b->{ifIndex}} @{$self->{interfaces}}) { 403 #foreach (sort @{$self->{interfaces}}) { 404 $_->list(); 405 } 406 $self->add_ok("have fun"); 407 } elsif ($self->mode =~ /device::interfaces::availability/) { 408 foreach (@{$self->{interfaces}}) { 409 $_->check(); 410 } 411 my $num_interfaces = scalar(@{$self->{interfaces}}); 412 my $up_interfaces = 413 scalar(grep { $_->{ifAdminStatus} eq "up" } @{$self->{interfaces}}); 414 my $available_interfaces = 415 scalar(grep { $_->{ifAvailable} eq "true" } @{$self->{interfaces}}); 416 $self->add_info(sprintf "%d of %d (%d adm. up) interfaces are available", 417 $available_interfaces, $num_interfaces, $up_interfaces); 418 $self->set_thresholds(warning => "3:", critical => "2:"); 419 $self->add_message($self->check_thresholds($available_interfaces)); 420 $self->add_perfdata( 421 label => 'num_interfaces', 422 value => $num_interfaces, 423 thresholds => 0, 424 ); 425 $self->add_perfdata( 426 label => 'available_interfaces', 427 value => $available_interfaces, 428 ); 429 430 printf "%s\n", $self->{info}; 431 printf "<table style=\"border-collapse:collapse; border: 1px solid black;\">"; 432 printf "<tr>"; 433 foreach (qw(Index Descr Type Speed AdminStatus OperStatus Duration Available)) { 434 printf "<th style=\"text-align: right; padding-left: 4px; padding-right: 6px;\">%s</th>", $_; 435 } 436 printf "</tr>"; 437 foreach (sort {$a->{ifIndex} <=> $b->{ifIndex}} @{$self->{interfaces}}) { 438 printf "<tr>"; 439 printf "<tr style=\"border: 1px solid black;\">"; 440 foreach my $attr (qw(ifIndex ifDescr ifType ifSpeedText ifAdminStatus ifOperStatus ifStatusDuration ifAvailable)) { 441 if ($_->{ifAvailable} eq "false") { 442 printf "<td style=\"text-align: right; padding-left: 4px; padding-right: 6px;\">%s</td>", $_->{$attr}; 443 } else { 444 printf "<td style=\"text-align: right; padding-left: 4px; padding-right: 6px; background-color: #00ff33;\">%s</td>", $_->{$attr}; 445 } 446 } 447 printf "</tr>"; 448 } 449 printf "</table>\n"; 450 printf "<!--\nASCII_NOTIFICATION_START\n"; 451 my $column_length = {}; 452 foreach (qw(ifIndex ifDescr ifType ifSpeed ifAdminStatus ifOperStatus Duration ifAvailable ifSpeedText ifStatusDuration)) { 453 $column_length->{$_} = length($_); 454 } 455 foreach (sort {$a->{ifIndex} <=> $b->{ifIndex}} @{$self->{interfaces}}) { 456 foreach my $attr (qw(ifIndex ifDescr ifType ifSpeedText ifAdminStatus ifOperStatus ifStatusDuration ifAvailable)) { 457 if (length($_->{$attr}) > $column_length->{$attr}) { 458 $column_length->{$attr} = length($_->{$attr}); 459 } 460 } 461 } 462 foreach (qw(ifIndex ifDescr ifType ifSpeed ifAdminStatus ifOperStatus Duration ifStatusDuration ifAvailable ifSpeedText)) { 463 $column_length->{$_} = "%".($column_length->{$_} + 3)."s I"; 464 } 465 $column_length->{ifSpeed} = $column_length->{ifSpeedText}; 466 $column_length->{Duration} = $column_length->{ifStatusDuration}; 467 foreach (qw(ifIndex ifDescr ifType ifSpeed ifAdminStatus ifOperStatus Duration ifAvailable)) { 468 printf $column_length->{$_}, $_; 469 } 470 printf "\n"; 471 foreach (sort {$a->{ifIndex} <=> $b->{ifIndex}} @{$self->{interfaces}}) { 472 foreach my $attr (qw(ifIndex ifDescr ifType ifSpeedText ifAdminStatus ifOperStatus ifStatusDuration ifAvailable)) { 473 printf $column_length->{$attr}, $_->{$attr}; 474 } 475 printf "\n"; 476 } 477 printf "ASCII_NOTIFICATION_END\n-->\n"; 478 } else { 479 if (scalar (@{$self->{interfaces}}) == 0) { 480 } else { 481 foreach (sort {$a->{ifIndex} <=> $b->{ifIndex}} @{$self->{interfaces}}) { 482 $_->check(); 483 } 484 if ($self->opts->report =~ /^short/) { 485 $self->clear_ok(); 486 $self->add_ok('no problems') if ! $self->check_messages(); 487 } 488 } 489 } 490} 491 492sub update_interface_cache { 493 my ($self, $force) = @_; 494 my $statefile = $self->create_interface_cache_file(); 495 $self->bulk_is_baeh(10); 496 $self->get_snmp_objects('IFMIB', qw(ifTableLastChange)); 497 # "The value of sysUpTime at the time of the last creation or 498 # deletion of an entry in the ifTable. If the number of 499 # entries has been unchanged since the last re-initialization 500 # of the local network management subsystem, then this object 501 # contains a zero value." 502 $self->{ifTableLastChange} ||= 0; 503 $self->{ifCacheLastChange} = -f $statefile ? (stat $statefile)[9] : 0; 504 $self->{bootTime} = time - $self->uptime(); 505 $self->debug(sprintf 'boot time was %s', scalar localtime $self->{bootTime}); 506 $self->debug(sprintf 'if last change is %s', scalar localtime $self->{ifTableLastChange}); 507 $self->{ifTableLastChange} = $self->{bootTime} + $self->timeticks($self->{ifTableLastChange}); 508 $self->debug(sprintf 'if last change is %s', scalar localtime $self->{ifTableLastChange}); 509 my $update_deadline = time - 3600; 510 my $must_update = 0; 511 if ($self->{ifCacheLastChange} < $update_deadline) { 512 # file older than 1h or file does not exist 513 $must_update = 1; 514 $self->debug(sprintf 'interface cache is older than 1h (%s < %s)', 515 scalar localtime $self->{ifCacheLastChange}, scalar localtime $update_deadline); 516 } 517 if ($self->{ifTableLastChange} >= $self->{ifCacheLastChange}) { 518 $must_update = 1; 519 $self->debug(sprintf 'interface table changes newer than cache file (%s >= %s)', 520 scalar localtime $self->{ifTableLastChange}, scalar localtime $self->{ifCacheLastChange}); 521 } 522 if ($force) { 523 $must_update = 1; 524 $self->debug(sprintf 'interface table update forced'); 525 } 526 if ($must_update) { 527 $self->debug('update of interface cache'); 528 $self->{interface_cache} = {}; 529 foreach ($self->get_snmp_table_objects('MINI-IFMIB', 'ifTable+ifXTable', [-1], ['ifDescr', 'ifName', 'ifAlias'])) { 530 # auch hier explizit ifIndex vermeiden, sonst fliegen dem Rattabratha Singh die Nexus um die Ohren 531 # neuerdings index+descr, weil die drecksscheiss allied telesyn ports 532 # alle gleich heissen 533 # und noch so ein hirnbrand: --mode list-interfaces 534 # 000003 Adaptive Security Appliance 'GigabitEthernet0/0' interface 535 # .... 536 # der ASA-schlonz ist ueberfluessig, also brauchen wir eine hintertuer 537 # um die namen auszuputzen 538 if ($self->opts->name2 && $self->opts->name2 =~ /\(\.\*\?*\)/) { 539 if ($_->{ifDescr} =~ $self->opts->name2) { 540 $_->{ifDescr} = $1; 541 } 542 } 543 $self->{interface_cache}->{$_->{flat_indices}}->{ifDescr} = unpack("Z*", $_->{ifDescr}); 544 $self->{interface_cache}->{$_->{flat_indices}}->{ifName} = unpack("Z*", $_->{ifName}) if exists $_->{ifName}; 545 $self->{interface_cache}->{$_->{flat_indices}}->{ifAlias} = unpack("Z*", $_->{ifAlias}) if exists $_->{ifAlias}; 546 } 547 $self->enrich_interface_cache(); 548 $self->save_interface_cache(); 549 } 550 $self->load_interface_cache(); 551 $self->{duplicates} = {}; 552 foreach my $index (keys %{$self->{interface_cache}}) { 553 my $ifDescr = $self->{interface_cache}->{$index}->{ifDescr}; 554 if (! exists $self->{duplicates}->{$ifDescr}) { 555 $self->{duplicates}->{$ifDescr} = 1; 556 } else { 557 $self->{duplicates}->{$ifDescr}++; 558 } 559 } 560 foreach my $index (keys %{$self->{interface_cache}}) { 561 $self->{interface_cache}->{$index}->{flat_indices} = $index; 562 $self->make_ifdescr_unique($self->{interface_cache}->{$index}); 563 } 564 return $must_update; 565} 566 567sub enrich_interface_cache { 568 my ($self) = @_; 569 # a dummy method. it can be used in Classes::XY::Component::InterfaceSubsystem 570 # to add for example vendor-specific port names to the interface cache 571 # which has been collected by get_snmp_tables(vendor-mib, tablexy, xyPortName 572} 573 574sub save_interface_cache { 575 my ($self) = @_; 576 $self->create_statefilesdir(); 577 my $statefile = $self->create_interface_cache_file(); 578 my $tmpfile = $self->statefilesdir().'/check_nwc_health_tmp_'.$$; 579 my $fh = IO::File->new(); 580 if ($fh->open($tmpfile, "w")) { 581 my $coder = JSON::XS->new->ascii->pretty->allow_nonref; 582 my $jsonscalar = $coder->encode($self->{interface_cache}); 583 $fh->print($jsonscalar); 584 $fh->flush(); 585 $fh->close(); 586 } 587 rename $tmpfile, $statefile; 588 $self->debug(sprintf "saved %s to %s", 589 Data::Dumper::Dumper($self->{interface_cache}), $statefile); 590} 591 592sub load_interface_cache { 593 my ($self) = @_; 594 my $statefile = $self->create_interface_cache_file(); 595 if ( -f $statefile) { 596 my $jsonscalar = read_file($statefile); 597 our $VAR1; 598 eval { 599 my $coder = JSON::XS->new->ascii->pretty->allow_nonref; 600 $VAR1 = $coder->decode($jsonscalar); 601 }; 602 if($@) { 603 $self->debug(sprintf "json load from %s failed. fallback", $statefile); 604 delete $INC{$statefile} if exists $INC{$statefile}; # else unit tests fail 605 eval "$jsonscalar"; 606 if($@) { 607 printf "FATAL: Could not load interface cache in perl format!\n"; 608 $self->debug(sprintf "fallback perl load from %s failed", $statefile); 609 } 610 } 611 $self->debug(sprintf "load %s", Data::Dumper::Dumper($VAR1)); 612 $self->{interface_cache} = $VAR1; 613 } 614} 615 616sub make_ifdescr_unique { 617 my ($self, $if) = @_; 618 $if->{ifDescr} = $if->{ifDescr}.' '.$if->{flat_indices} if $self->{duplicates}->{$if->{ifDescr}} > 1; 619} 620 621sub get_interface_indices { 622 my ($self) = @_; 623 my @indices = (); 624 foreach my $ifIndex (keys %{$self->{interface_cache}}) { 625 my $ifDescr = $self->{interface_cache}->{$ifIndex}->{ifDescr}; 626 my $ifUniqDescr = $self->{interface_cache}->{$ifIndex}->{ifUniqDescr}; 627 my $ifAlias = $self->{interface_cache}->{$ifIndex}->{ifAlias} || '________'; 628 # Check ifDescr (using --name) 629 if ($self->opts->name) { 630 if ($self->opts->regexp) { 631 my $pattern = $self->opts->name; 632 if ($ifDescr =~ /$pattern/i) { 633 push(@indices, [$ifIndex]); 634 } 635 } else { 636 if ($self->opts->name =~ /^\d+$/) { 637 if ($ifIndex == 1 * $self->opts->name) { 638 push(@indices, [1 * $self->opts->name]); 639 } 640 } else { 641 if (lc $ifDescr eq lc $self->opts->name) { 642 push(@indices, [$ifIndex]); 643 } 644 } 645 } 646 # Check ifAlias (using --name3) 647 } elsif ($self->opts->name3) { 648 if ($self->opts->regexp) { 649 my $pattern = $self->opts->name3; 650 if ($ifAlias =~ /$pattern/i) { 651 push(@indices, [$ifIndex]); 652 } 653 } else { 654 if (lc $ifAlias eq lc $self->opts->name3) { 655 push(@indices, [$ifIndex]); 656 } 657 } 658 # take all interfaces 659 } else { 660 push(@indices, [$ifIndex]); 661 } 662 } 663 return @indices; 664} 665 666sub enrich_interface_attributes { 667 my ($self, $interface) = @_; 668 # can be used by vendor-specific InterfaceSubsystem to add extra 669 # attributes 670} 671 672 673package Classes::IFMIB::Component::InterfaceSubsystem::Interface; 674our @ISA = qw(Monitoring::GLPlugin::SNMP::TableItem); 675use strict; 676use Digest::MD5 qw(md5_hex); 677 678sub finish { 679 my ($self) = @_; 680 foreach my $key (keys %{$self}) { 681 next if $key !~ /^if/; 682 $self->{$key} = 0 if ! defined $self->{$key}; 683 } 684 # Nexus 5k/6k - Memory leak in pfstat process causing hap reset CSCur11599 685 # Nexus 6.x crashen, wenn man ifIndex abfragt. Kein Kommentar 686 $self->{ifIndex} = $self->{flat_indices} if ! exists $self->{ifIndex}; 687 $self->{ifDescr} = unpack("Z*", $self->{ifDescr}); # windows has trailing nulls 688 if ($self->opts->name2 && $self->opts->name2 =~ /\(\.\*\?*\)/) { 689 if ($self->{ifDescr} =~ $self->opts->name2) { 690 $self->{ifDescr} = $1; 691 } 692 } 693 if ($self->mode =~ /device::interfaces::duplex/) { 694 } elsif ($self->mode =~ /device::interfaces::uptime/) { 695 $self->{sysUptime} = $self->get_snmp_object('MIB-2-MIB', 'sysUpTime', 0) / 100; 696 $self->{sysUptime64} = $self->uptime(); 697 } else { 698 # Manche Stinkstiefel haben ifName, ifHighSpeed und z.b. ifInMulticastPkts, 699 # aber keine ifHC*Octets. Gesehen bei Cisco Switch Interface Nul0 o.ae. 700 if ($self->{ifName} && defined $self->{ifHCInOctets} && 701 defined $self->{ifHCOutOctets} && $self->{ifHCInOctets} ne "noSuchObject") { 702 $self->{ifAlias} ||= $self->{ifName}; 703 $self->{ifName} = unpack("Z*", $self->{ifName}); 704 $self->{ifAlias} = unpack("Z*", $self->{ifAlias}); 705 $self->{ifAlias} =~ s/\|/!/g if $self->{ifAlias}; 706 bless $self, 'Classes::IFMIB::Component::InterfaceSubsystem::Interface::64bit'; 707 } 708 if ($self->mode =~ /device::interfaces::(broadcast|complete)/ && 709 ! exists $self->{ifInErrors} && ! exists $self->{ifOutErrors} && 710 ! exists $self->{ifInDiscards} && ! exists $self->{ifOutDiscards} && 711 $self->{ifDescr} =~ /.*Ethernet[\/\d]+\.\d+$/) { 712 # Urspruenglich wies sowas klar auf so Pseudo-bundle-channel-sonstwas hin. 713 # Aber dann tauchte im Schwaebischen ein TenGigabitEthernet auf, bei dem 714 # Errors und Discards fehlten. Erst dachte ich, die haetten sich gesagt: 715 # "Mir naehmet desch guenschtigere Modell ohne Counter", dann dachte ich, 716 # die haben billigen Chinaschrott gekauft, weil ifHighSpeed statt 10000 717 # bei den drei in Frage kommenden Interfaces nur 275, 1000 und 25 anzeigt. 718 # Aber anscheinend hat das alles seine Richtigkeit in einem Szenario wie 719 # 1 Haupt-Interface mit 3 VRFs mit jeweils eigenen VLANs 720 # also TenGigabitEthernet0/0/0.10, TenGigabitEthernet0/0/0.20 und 721 # TenGigabitEthernet0/0/0.30 unter TenGigabitEthernet0/0/0, laut 722 # ifAlias so MPLS mit Vodafone. 723 $self->{ifInErrors} = 0; 724 $self->{ifOutErrors} = 0; 725 $self->{ifInDiscards} = 0; 726 $self->{ifOutDiscards} = 0; 727 } elsif ((! exists $self->{ifInOctets} && ! exists $self->{ifOutOctets} && 728 $self->mode =~ /device::interfaces::(usage|complete)/) || 729 (! exists $self->{ifInErrors} && ! exists $self->{ifOutErrors} && 730 $self->mode =~ /device::interfaces::(errors|complete)/) || 731 (! exists $self->{ifInDiscards} && ! exists $self->{ifOutDiscards} && 732 $self->mode =~ /device::interfaces::(discards|complete)/) || 733 (! exists $self->{ifInUcastPkts} && ! exists $self->{ifOutUcastPkts} && 734 $self->mode =~ /device::interfaces::(broadcast|complete)/)) { 735 bless $self, 'Classes::IFMIB::Component::InterfaceSubsystem::Interface::StackSub'; 736 } 737 if ($self->{ifPhysAddress}) { 738 $self->{ifPhysAddress} = join(':', unpack('(H2)*', $self->{ifPhysAddress})); 739 } 740 } 741 $self->init(); 742} 743 744sub calc_usage { 745 my ($self) = @_; 746 $self->valdiff({name => $self->{ifIndex}.'#'.$self->{ifDescr}}, qw(ifInOctets ifOutOctets)); 747 $self->{delta_ifInBits} = $self->{delta_ifInOctets} * 8; 748 $self->{delta_ifOutBits} = $self->{delta_ifOutOctets} * 8; 749 if ($self->{ifSpeed} == 0) { 750 # vlan graffl 751 $self->{inputUtilization} = 0; 752 $self->{outputUtilization} = 0; 753 $self->{maxInputRate} = 0; 754 $self->{maxOutputRate} = 0; 755 } else { 756 $self->{inputUtilization} = 100 * $self->{delta_ifInBits} / 757 ($self->{delta_timestamp} * $self->{ifSpeed}); 758 $self->{outputUtilization} = 100 * $self->{delta_ifOutBits} / 759 ($self->{delta_timestamp} * $self->{ifSpeed}); 760 $self->{maxInputRate} = $self->{ifSpeed}; 761 $self->{maxOutputRate} = $self->{ifSpeed}; 762 } 763 if (defined $self->opts->ifspeed) { 764 $self->override_opt('ifspeedin', $self->opts->ifspeed); 765 $self->override_opt('ifspeedout', $self->opts->ifspeed); 766 } 767 if (defined $self->opts->ifspeedin) { 768 $self->{inputUtilization} = 100 * $self->{delta_ifInBits} / 769 ($self->{delta_timestamp} * $self->opts->ifspeedin); 770 $self->{maxInputRate} = $self->opts->ifspeedin; 771 } 772 if (defined $self->opts->ifspeedout) { 773 $self->{outputUtilization} = 100 * $self->{delta_ifOutBits} / 774 ($self->{delta_timestamp} * $self->opts->ifspeedout); 775 $self->{maxOutputRate} = $self->opts->ifspeedout; 776 } 777 $self->{inputRate} = $self->{delta_ifInBits} / $self->{delta_timestamp}; 778 $self->{outputRate} = $self->{delta_ifOutBits} / $self->{delta_timestamp}; 779 $self->override_opt("units", "bit") if ! $self->opts->units; 780 $self->{inputRate} /= $self->number_of_bits($self->opts->units); 781 $self->{outputRate} /= $self->number_of_bits($self->opts->units); 782 $self->{maxInputRate} /= $self->number_of_bits($self->opts->units); 783 $self->{maxOutputRate} /= $self->number_of_bits($self->opts->units); 784 if ($self->{ifOperStatus} eq 'down') { 785 $self->{inputUtilization} = 0; 786 $self->{outputUtilization} = 0; 787 $self->{inputRate} = 0; 788 $self->{outputRate} = 0; 789 $self->{maxInputRate} = 0; 790 $self->{maxOutputRate} = 0; 791 } 792} 793 794sub get_mub_pkts { 795 my ($self) = @_; 796 foreach my $key (qw(ifInUcastPkts 797 ifInMulticastPkts ifInBroadcastPkts ifOutUcastPkts 798 ifOutMulticastPkts ifOutBroadcastPkts)) { 799 $self->{$key} = 0 if (! exists $self->{$key} || ! defined $self->{$key}); 800 } 801 $self->valdiff({name => 'mub_'.$self->{ifDescr}}, qw(ifInUcastPkts 802 ifInMulticastPkts ifInBroadcastPkts ifOutUcastPkts 803 ifOutMulticastPkts ifOutBroadcastPkts)); 804 $self->{delta_ifInPkts} = $self->{delta_ifInUcastPkts} + 805 $self->{delta_ifInMulticastPkts} + 806 $self->{delta_ifInBroadcastPkts}; 807 $self->{delta_ifOutPkts} = $self->{delta_ifOutUcastPkts} + 808 $self->{delta_ifOutMulticastPkts} + 809 $self->{delta_ifOutBroadcastPkts}; 810} 811 812sub init { 813 my ($self) = @_; 814 if ($self->mode =~ /device::interfaces::complete/) { 815 # uglatto, but $self->mode is an lvalue 816 $Monitoring::GLPlugin::mode = "device::interfaces::operstatus"; 817 $self->init(); 818 if ($self->{ifOperStatus} eq "up") { 819 foreach my $mode (qw(device::interfaces::usage 820 device::interfaces::errors device::interfaces::discards 821 device::interfaces::broadcasts)) { 822 $Monitoring::GLPlugin::mode = $mode; 823 $self->init(); 824 } 825 } 826 $Monitoring::GLPlugin::mode = "device::interfaces::complete"; 827 } elsif ($self->mode =~ /device::interfaces::usage/) { 828 $self->calc_usage(); 829 } elsif ($self->mode =~ /device::interfaces::errors/) { 830 $self->calc_usage() if ! defined $self->{inputUtilization}; 831 $self->get_mub_pkts() if ! defined $self->{delta_ifOutPkts}; 832 $self->valdiff({name => $self->{ifDescr}}, qw(ifInErrors ifOutErrors)); 833 $self->{inputErrorsPercent} = $self->{delta_ifInPkts} == 0 ? 0 : 834 100 * $self->{delta_ifInErrors} / $self->{delta_ifInPkts}; 835 $self->{outputErrorsPercent} = $self->{delta_ifOutPkts} == 0 ? 0 : 836 100 * $self->{delta_ifOutErrors} / $self->{delta_ifOutPkts}; 837 $self->{inputErrorRate} = $self->{delta_ifInErrors} 838 / $self->{delta_timestamp}; 839 $self->{outputErrorRate} = $self->{delta_ifOutErrors} 840 / $self->{delta_timestamp}; 841 } elsif ($self->mode =~ /device::interfaces::discards/) { 842 $self->calc_usage() if ! defined $self->{inputUtilization}; 843 $self->get_mub_pkts() if ! defined $self->{delta_ifOutPkts}; 844 $self->valdiff({name => $self->{ifDescr}}, qw(ifInDiscards ifOutDiscards)); 845 $self->{inputDiscardsPercent} = $self->{delta_ifInPkts} == 0 ? 0 : 846 100 * $self->{delta_ifInDiscards} / $self->{delta_ifInPkts}; 847 $self->{outputDiscardsPercent} = $self->{delta_ifOutPkts} == 0 ? 0 : 848 100 * $self->{delta_ifOutDiscards} / $self->{delta_ifOutPkts}; 849 $self->{inputDiscardRate} = $self->{delta_ifInDiscards} 850 / $self->{delta_timestamp}; 851 $self->{outputDiscardRate} = $self->{delta_ifOutDiscards} 852 / $self->{delta_timestamp}; 853 } elsif ($self->mode =~ /device::interfaces::broadcasts/) { 854 $self->calc_usage() if ! defined $self->{inputUtilization}; 855 $self->get_mub_pkts() if ! defined $self->{delta_ifOutPkts}; 856 $self->{inputBroadcastPercent} = $self->{delta_ifInPkts} == 0 ? 0 : 857 100 * $self->{delta_ifInBroadcastPkts} / $self->{delta_ifInPkts}; 858 $self->{outputBroadcastPercent} = $self->{delta_ifOutPkts} == 0 ? 0 : 859 100 * $self->{delta_ifOutBroadcastPkts} / $self->{delta_ifOutPkts}; 860 $self->{inputBroadcastUtilizationPercent} = $self->{inputBroadcastPercent} 861 * $self->{inputUtilization} / 100; 862 $self->{outputBroadcastUtilizationPercent} = $self->{outputBroadcastPercent} 863 * $self->{outputUtilization} / 100; 864 } elsif ($self->mode =~ /device::interfaces::operstatus/) { 865 } elsif ($self->mode =~ /device::interfaces::availability/) { 866 $self->{ifStatusDuration} = 867 $self->uptime() - $self->timeticks($self->{ifLastChange}); 868 $self->opts->override_opt('lookback', 1800) if ! $self->opts->lookback; 869 if ($self->{ifAdminStatus} eq "down") { 870 $self->{ifAvailable} = "true"; 871 } elsif ($self->{ifAdminStatus} eq "up" && $self->{ifOperStatus} ne "up" && 872 $self->{ifStatusDuration} > $self->opts->lookback) { 873 # and ifLastChange schon ein wenig laenger her 874 $self->{ifAvailable} = "true"; 875 } else { 876 $self->{ifAvailable} = "false"; 877 } 878 my $gb = 1000 * 1000 * 1000; 879 my $mb = 1000 * 1000; 880 my $kb = 1000; 881 my $speed = $self->{ifHighSpeed} ? 882 ($self->{ifHighSpeed} * $mb) : $self->{ifSpeed}; 883 if ($speed >= $gb) { 884 $self->{ifSpeedText} = sprintf "%.2fGB", $speed / $gb; 885 } elsif ($speed >= $mb) { 886 $self->{ifSpeedText} = sprintf "%.2fMB", $speed / $mb; 887 } elsif ($speed >= $kb) { 888 $self->{ifSpeedText} = sprintf "%.2fKB", $speed / $kb; 889 } else { 890 $self->{ifSpeedText} = sprintf "%.2fB", $speed; 891 } 892 $self->{ifSpeedText} =~ s/\.00//g; 893 } elsif ($self->mode =~ /device::interfaces::uptime/) { 894 $self->{ifLastChangeRaw} = $self->{ifLastChange}; 895 $self->{ifLastChange} = time - 896 $self->ago_sysuptime($self->{ifLastChange}); 897 # Alter Text: 898 # Wenn sysUptime ueberlaeuft, dann wird's schwammig. Denn dann kann 899 # ich nicht sagen, ob ein ifLastChange ganz am Anfang passiert ist, 900 # unmittelbar nach dem Booten, oder grad eben vor drei Minuten, als 901 # der Ueberlauf stattfand. Ergo ist dieser Mode nach einer Uptime von 902 # 497 Tagen nicht mehr brauchbar. 903 # Und tatsaechlich gibt es Typen die lassen ihre Switche in den 904 # Filialen ueber ein Jahr durchlaufen und machen dann reihenweise Tickets auf. 905 # boot ifchange1 overflow ifchange2 906 # | | | | 907 # |---------------------------------^---------------------------------^----- 908 # | 909 # check 910 # Zum Zeitpunkt des Checks ist ifchange1 groesser als die sysUptime 911 # Damit wird ifLastChange negativ. 912 # Eine Chance gibts dann noch, man geht davon aus, dass das der 913 # einzige Overflow war (tatsaechlich koennten ja mehrere passiert sein) 914 # Also: max(32bit) - ifchange1 + sysUptime 915 # ago_sysuptime fackelt das ganz gut ab. 916 $self->{ifLastChangeHuman} = scalar localtime $self->{ifLastChange}; 917 $self->{ifDuration} = time - $self->{ifLastChange}; 918 $self->{ifDurationMinutes} = $self->{ifDuration} / 60; # minutes 919 } 920 return $self; 921} 922 923sub init_etherstats { 924 my ($self) = @_; 925 if ($self->mode =~ /device::interfaces::etherstats/) { 926 $Monitoring::GLPlugin::mode = "device::interfaces::broadcasts"; 927 $self->init(); 928 $Monitoring::GLPlugin::mode = "device::interfaces::etherstats"; 929 # in the beginning we start 32/64bit-unaware, so columns contain 930 # also ifHC-names, but there are no such attributes in the interface object 931 @{$self->{columns}} = grep { 932 ! /^ifHC(In|Out).*castPkts$/ 933 } grep { 934 ! /^(ifOperStatus|ifAdminStatus|ifIndex|ifDescr|ifAlias|ifName)$/ 935 } @{$self->{columns}}; 936 # z.b. Serial2/3/2 in Singapore, broadcastet nicht 937 my $ident = $self->{ifDescr}.md5_hex(join('_', @{$self->{columns}})); 938 $self->valdiff({name => $ident}, @{$self->{columns}}); 939 $self->{delta_InPkts} = $self->{delta_ifInUcastPkts} + 940 $self->{delta_ifInMulticastPkts} + $self->{delta_ifInBroadcastPkts}; 941 $self->{delta_OutPkts} = $self->{delta_ifOutUcastPkts} + 942 $self->{delta_ifOutMulticastPkts} + $self->{delta_ifOutBroadcastPkts}; 943 for my $stat (grep { /^(dot3|etherStats)/ } @{$self->{columns}}) { 944 next if ! defined $self->{'delta_'.$stat}; 945 $self->{$stat.'Percent'} = $self->{delta_InPkts} + $self->{delta_OutPkts} ? 946 100 * $self->{'delta_'.$stat} / 947 ($self->{delta_InPkts} + $self->{delta_OutPkts}) : 0; 948 } 949 } elsif ($self->mode =~ /device::interfaces::duplex/) { 950 if (defined $self->{dot3StatsDuplexStatus}) { 951 } elsif (! defined $self->{dot3StatsDuplexStatus} && $self->{ifType} !~ /ether/i) { 952 $self->{dot3StatsDuplexStatus} = "notApplicable"; 953 } elsif (! defined $self->{dot3StatsDuplexStatus} && $self->implements_mib('EtherLike-MIB')) { 954 if (defined $self->opts->mitigation() && 955 $self->opts->mitigation() eq 'ok') { 956 $self->{dot3StatsDuplexStatus} = "fullDuplex"; 957 } else { 958 $self->{dot3StatsDuplexStatus} = "unknown"; 959 } 960 } else { 961 $self->{dot3StatsDuplexStatus} = "unknown"; 962 } 963 } 964 return $self; 965} 966 967sub check { 968 my ($self) = @_; 969 my $full_descr = sprintf "%s%s%s", 970 $self->{ifDescr}, 971 $self->{ifAlias} && $self->{ifAlias} ne $self->{ifDescr} ? 972 " (alias ".$self->{ifAlias}.")" : "", 973 $self->{ifAddresses} ? " (addresses ".$self->{ifAddresses}.")" : ""; 974 if ($self->mode =~ /device::interfaces::complete/) { 975 # uglatto, but $self->mode is an lvalue 976 $Monitoring::GLPlugin::mode = "device::interfaces::operstatus"; 977 $self->check(); 978 if ($self->{ifOperStatus} eq "up") { 979 # kostenpflichtiges feature # device::interfaces::duplex 980 foreach my $mode (qw(device::interfaces::usage 981 device::interfaces::errors device::interfaces::discards 982 device::interfaces::broadcast)) { 983 $Monitoring::GLPlugin::mode = $mode; 984 $self->check(); 985 } 986 } 987 $Monitoring::GLPlugin::mode = "device::interfaces::complete"; 988 } elsif ($self->mode =~ /device::interfaces::usage/) { 989 $self->add_info(sprintf 'interface %s usage is in:%.2f%% (%s) out:%.2f%% (%s)%s', 990 $full_descr, 991 $self->{inputUtilization}, 992 sprintf("%.2f%s/s", $self->{inputRate}, $self->opts->units), 993 $self->{outputUtilization}, 994 sprintf("%.2f%s/s", $self->{outputRate}, $self->opts->units), 995 $self->{ifOperStatus} eq 'down' ? ' (down)' : ''); 996 $self->set_thresholds( 997 metric => $self->{ifDescr}.'_usage_in', 998 warning => 80, 999 critical => 90 1000 ); 1001 my $in = $self->check_thresholds( 1002 metric => $self->{ifDescr}.'_usage_in', 1003 value => $self->{inputUtilization} 1004 ); 1005 $self->set_thresholds( 1006 metric => $self->{ifDescr}.'_usage_out', 1007 warning => 80, 1008 critical => 90 1009 ); 1010 my $out = $self->check_thresholds( 1011 metric => $self->{ifDescr}.'_usage_out', 1012 value => $self->{outputUtilization} 1013 ); 1014 my $level = ($in > $out) ? $in : ($out > $in) ? $out : $in; 1015 $self->add_message($level); 1016 $self->add_perfdata( 1017 label => $self->{ifDescr}.'_usage_in', 1018 value => $self->{inputUtilization}, 1019 uom => '%', 1020 ); 1021 $self->add_perfdata( 1022 label => $self->{ifDescr}.'_usage_out', 1023 value => $self->{outputUtilization}, 1024 uom => '%', 1025 ); 1026 my ($inwarning, $incritical) = $self->get_thresholds( 1027 metric => $self->{ifDescr}.'_usage_in', 1028 ); 1029 $self->set_thresholds( 1030 metric => $self->{ifDescr}.'_traffic_in', 1031 warning => $self->{maxInputRate} / 100 * $inwarning, 1032 critical => $self->{maxInputRate} / 100 * $incritical 1033 ); 1034 $self->add_perfdata( 1035 label => $self->{ifDescr}.'_traffic_in', 1036 value => $self->{inputRate}, 1037 uom => $self->opts->units =~ /^(B|KB|MB|GB|TB)$/ ? $self->opts->units : undef, 1038 places => 2, 1039 min => 0, 1040 max => $self->{maxInputRate}, 1041 ); 1042 my ($outwarning, $outcritical) = $self->get_thresholds( 1043 metric => $self->{ifDescr}.'_usage_out', 1044 ); 1045 $self->set_thresholds( 1046 metric => $self->{ifDescr}.'_traffic_out', 1047 warning => $self->{maxOutputRate} / 100 * $outwarning, 1048 critical => $self->{maxOutputRate} / 100 * $outcritical, 1049 ); 1050 $self->add_perfdata( 1051 label => $self->{ifDescr}.'_traffic_out', 1052 value => $self->{outputRate}, 1053 uom => $self->opts->units =~ /^(B|KB|MB|GB|TB)$/ ? $self->opts->units : undef, 1054 places => 2, 1055 min => 0, 1056 max => $self->{maxOutputRate}, 1057 ); 1058 } elsif ($self->mode =~ /device::interfaces::errors/) { 1059 $self->add_info(sprintf 'interface %s errors in:%.2f%% out:%.2f%% ', 1060 $full_descr, 1061 $self->{inputErrorsPercent} , $self->{outputErrorsPercent}); 1062 $self->set_thresholds( 1063 metric => $self->{ifDescr}.'_errors_in', 1064 warning => 1, 1065 critical => 10, 1066 ); 1067 my $in = $self->check_thresholds( 1068 metric => $self->{ifDescr}.'_errors_in', 1069 value => $self->{inputErrorsPercent} 1070 ); 1071 $self->set_thresholds( 1072 metric => $self->{ifDescr}.'_errors_out', 1073 warning => 1, 1074 critical => 10, 1075 ); 1076 my $out = $self->check_thresholds( 1077 metric => $self->{ifDescr}.'_errors_out', 1078 value => $self->{outputErrorsPercent} 1079 ); 1080 my $level = ($in > $out) ? $in : ($out > $in) ? $out : $in; 1081 $self->add_message($level); 1082 $self->add_perfdata( 1083 label => $self->{ifDescr}.'_errors_in', 1084 value => $self->{inputErrorsPercent}, 1085 uom => '%', 1086 ); 1087 $self->add_perfdata( 1088 label => $self->{ifDescr}.'_errors_out', 1089 value => $self->{outputErrorsPercent}, 1090 uom => '%', 1091 ); 1092 } elsif ($self->mode =~ /device::interfaces::discards/) { 1093 $self->add_info(sprintf 'interface %s discards in:%.2f%% out:%.2f%% ', 1094 $full_descr, 1095 $self->{inputDiscardsPercent} , $self->{outputDiscardsPercent}); 1096 $self->set_thresholds( 1097 metric => $self->{ifDescr}.'_discards_in', 1098 warning => 5, 1099 critical => 10, 1100 ); 1101 my $in = $self->check_thresholds( 1102 metric => $self->{ifDescr}.'_discards_in', 1103 value => $self->{inputDiscardsPercent} 1104 ); 1105 $self->set_thresholds( 1106 metric => $self->{ifDescr}.'_discards_out', 1107 warning => 5, 1108 critical => 10, 1109 ); 1110 my $out = $self->check_thresholds( 1111 metric => $self->{ifDescr}.'_discards_out', 1112 value => $self->{outputDiscardsPercent} 1113 ); 1114 my $level = ($in > $out) ? $in : ($out > $in) ? $out : $in; 1115 $self->add_message($level); 1116 $self->add_perfdata( 1117 label => $self->{ifDescr}.'_discards_in', 1118 value => $self->{inputDiscardsPercent}, 1119 uom => '%', 1120 ); 1121 $self->add_perfdata( 1122 label => $self->{ifDescr}.'_discards_out', 1123 value => $self->{outputDiscardsPercent}, 1124 uom => '%', 1125 ); 1126 } elsif ($self->mode =~ /device::interfaces::broadcast/) { 1127 # BroadcastPercent 1128 # -> TenGigabitEthernet0/0/0.10_broadcast_in 1129 # wieviel % der ein/ausgehenden Pakete sind Broadcasts? 1130 # das kann bei standby-Firewall-Interfaces sehr hoch sein, wenn regulaerer 1131 # Traffic nicht stattfindet, aber viel Clustergeschwaetz. 1132 # BroadcastUtilizationPercent = wieviel % der verfuegbaren Bandbreite 1133 # -> TenGigabitEthernet0/0/0.10_broadcast_usage_in 1134 # nehmen die Broadcasts ein? 1135 # Der Schwellwert ist hoch eingestellt, wenn der gerissen wird, dann ist 1136 # definitiv was faul. 1137 $self->add_info(sprintf 'interface %s broadcast in:%.2f%% out:%.2f%% (%% of traffic) in:%.2f%% out:%.2f%% (%% of bandwidth)', 1138 $full_descr, 1139 $self->{inputBroadcastPercent} , $self->{outputBroadcastPercent}, 1140 $self->{inputBroadcastUtilizationPercent} , $self->{outputBroadcastUtilizationPercent}); 1141 $self->set_thresholds( 1142 metric => $self->{ifDescr}.'_broadcast_in', 1143 warning => 10, 1144 critical => 20 1145 ); 1146 my $uin = $self->check_thresholds( 1147 metric => $self->{ifDescr}.'_broadcast_in', 1148 value => $self->{inputBroadcastPercent} 1149 ); 1150 $self->set_thresholds( 1151 metric => $self->{ifDescr}.'_broadcast_out', 1152 warning => 10, 1153 critical => 20 1154 ); 1155 my $uout = $self->check_thresholds( 1156 metric => $self->{ifDescr}.'_broadcast_out', 1157 value => $self->{outputBroadcastPercent} 1158 ); 1159 $self->add_perfdata( 1160 label => $self->{ifDescr}.'_broadcast_in', 1161 value => $self->{inputBroadcastPercent}, 1162 uom => '%', 1163 ); 1164 $self->add_perfdata( 1165 label => $self->{ifDescr}.'_broadcast_out', 1166 value => $self->{outputBroadcastPercent}, 1167 uom => '%', 1168 ); 1169 my $ulevel = ($uin > $uout) ? $uin : ($uout > $uin) ? $uout : $uin; 1170 $self->set_thresholds( 1171 metric => $self->{ifDescr}.'_broadcast_usage_in', 1172 warning => 10, 1173 critical => 20 1174 ); 1175 my $bin = $self->check_thresholds( 1176 metric => $self->{ifDescr}.'_broadcast_usage_in', 1177 value => $self->{inputBroadcastUtilizationPercent} 1178 ); 1179 $self->set_thresholds( 1180 metric => $self->{ifDescr}.'_broadcast_usage_out', 1181 warning => 10, 1182 critical => 20 1183 ); 1184 my $bout = $self->check_thresholds( 1185 metric => $self->{ifDescr}.'_broadcast_usage_out', 1186 value => $self->{outputBroadcastUtilizationPercent} 1187 ); 1188 $self->add_perfdata( 1189 label => $self->{ifDescr}.'_broadcast_usage_in', 1190 value => $self->{inputBroadcastUtilizationPercent}, 1191 uom => '%', 1192 ); 1193 $self->add_perfdata( 1194 label => $self->{ifDescr}.'_broadcast_usage_out', 1195 value => $self->{outputBroadcastUtilizationPercent}, 1196 uom => '%', 1197 ); 1198 my $blevel = ($bin > $bout) ? $bin : ($bout > $bin) ? $bout : $bin; 1199 $self->add_message(($blevel > $ulevel) ? $blevel : $ulevel); 1200 } elsif ($self->mode =~ /device::interfaces::operstatus/) { 1201 #rfc2863 1202 #(1) if ifAdminStatus is not down and ifOperStatus is down then a 1203 # fault condition is presumed to exist on the interface. 1204 #(2) if ifAdminStatus is down, then ifOperStatus will normally also 1205 # be down (or notPresent) i.e., there is not (necessarily) a 1206 # fault condition on the interface. 1207 # --warning onu,anu 1208 # Admin: admindown,admin 1209 # Admin: --warning 1210 # --critical admindown 1211 # !ad+od ad+!(od*on) 1212 # warn & warnbitfield 1213# if ($self->opts->critical) { 1214# if ($self->opts->critical =~ /^u/) { 1215# } elsif ($self->opts->critical =~ /^u/) { 1216# } 1217# } 1218# if ($self->{ifOperStatus} ne 'up') { 1219# } 1220# } 1221 $self->add_info(sprintf '%s is %s/%s', 1222 $full_descr, 1223 $self->{ifOperStatus}, $self->{ifAdminStatus}); 1224 $self->add_ok(); 1225 if ($self->{ifOperStatus} eq 'down' && $self->{ifAdminStatus} ne 'down') { 1226 $self->add_critical( 1227 sprintf 'fault condition is presumed to exist on %s', 1228 $full_descr); 1229 } 1230 if ($self->{ifAdminStatus} eq 'down') { 1231 $self->add_message( 1232 defined $self->opts->mitigation() ? $self->opts->mitigation() : 2, 1233 sprintf '%s is admin down', $full_descr); 1234 } 1235 } elsif ($self->mode =~ /device::interfaces::availability/) { 1236 $self->{ifStatusDuration} = 1237 $self->human_timeticks($self->{ifStatusDuration}); 1238 $self->add_info(sprintf '%s is %savailable (%s/%s, since %s)', 1239 $self->{ifDescr}, ($self->{ifAvailable} eq "true" ? "" : "un"), 1240 $self->{ifOperStatus}, $self->{ifAdminStatus}, 1241 $self->{ifStatusDuration}); 1242 } elsif ($self->mode =~ /device::interfaces::etherstats/) { 1243 for my $stat (grep { /^(dot3|etherStats)/ } @{$self->{columns}}) { 1244 next if ! defined $self->{$stat.'Percent'}; 1245 my $label = $stat.'Percent'; 1246 $label =~ s/^(dot3Stats|etherStats)//g; 1247 $label =~ s/(?:\b|(?<=([a-z])))([A-Z][a-z]+)/(defined($1) ? "_" : "") . lc($2)/eg; 1248 $label = $self->{ifDescr}.'_'.$label; 1249 $self->add_info(sprintf 'interface %s %s is %.2f%%', 1250 $full_descr, $stat.'Percent', $self->{$stat.'Percent'}); 1251 $self->set_thresholds( 1252 metric => $label, 1253 warning => 1, 1254 critical => 10 1255 ); 1256 $self->add_message( 1257 $self->check_thresholds(metric => $label, value => $self->{$stat.'Percent'})); 1258 $self->add_perfdata( 1259 label => $label, 1260 value => $self->{$stat.'Percent'}, 1261 uom => '%', 1262 ); 1263 } 1264 } elsif ($self->mode =~ /device::interfaces::duplex/) { 1265 $self->add_info(sprintf "%s duplex status is %s", 1266 $self->{ifDescr}, $self->{dot3StatsDuplexStatus} 1267 ); 1268 if ($self->{ifOperStatus} ne "up") { 1269 $self->annotate_info(sprintf "oper %s", $self->{ifOperStatus}); 1270 $self->add_ok(); 1271 } elsif ($self->{dot3StatsDuplexStatus} eq "notApplicable") { 1272 $self->add_ok(); 1273 } else { 1274 if ($self->{dot3StatsDuplexStatus} eq "unknown") { 1275 $self->add_unknown(); 1276 } elsif ($self->{dot3StatsDuplexStatus} eq "fullDuplex") { 1277 $self->add_ok(); 1278 } else { 1279 # kein critical, weil so irgendwie funktionierts ja 1280 $self->add_warning(); 1281 } 1282 } 1283 } elsif ($self->mode =~ /device::interfaces::uptime/) { 1284 $self->add_info(sprintf "%s was changed %s ago", 1285 $full_descr, $self->human_timeticks($self->{ifDuration})); 1286 $self->set_thresholds(metric => $self->{ifDescr}."_duration", 1287 warning => "15:", critical => "5:"); 1288 $self->add_message($self->check_thresholds( 1289 metric => $self->{ifDescr}."_duration", 1290 value => $self->{ifDurationMinutes})); 1291 $self->add_perfdata( 1292 label => $self->{ifDescr}."_duration", 1293 value => $self->{ifDurationMinutes}, 1294 ); 1295 } 1296} 1297 1298sub list { 1299 my ($self) = @_; 1300 if ($self->mode =~ /device::interfaces::listdetail/) { 1301 my $cL2L3IfModeOper = $self->get_snmp_object('CISCO-L2L3-INTERFACE-CONFIG-MIB', 'cL2L3IfModeOper', $self->{ifIndex}) || "unknown"; 1302 my $vlanTrunkPortDynamicStatus = $self->get_snmp_object('CISCO-VTP-MIB', 'vlanTrunkPortDynamicStatus', $self->{ifIndex}) || "unknown"; 1303 printf "%06d %s %s %s %s\n", $self->{ifIndex}, $self->{ifDescr}, $self->{ifAlias}, 1304 $cL2L3IfModeOper, $vlanTrunkPortDynamicStatus; 1305 } else { 1306 printf "%06d %s\n", $self->{ifIndex}, $self->{ifDescr}; 1307 } 1308} 1309 1310 1311package Classes::IFMIB::Component::InterfaceSubsystem::Interface::64bit; 1312our @ISA = qw(Classes::IFMIB::Component::InterfaceSubsystem::Interface); 1313use strict; 1314use Digest::MD5 qw(md5_hex); 1315 1316sub calc_usage { 1317 my ($self) = @_; 1318 $self->valdiff({name => $self->{ifIndex}.'#'.$self->{ifDescr}}, qw(ifHCInOctets ifHCOutOctets)); 1319 $self->{delta_ifInBits} = $self->{delta_ifHCInOctets} * 8; 1320 $self->{delta_ifOutBits} = $self->{delta_ifHCOutOctets} * 8; 1321 # ifSpeed = Bits/sec 1322 # ifHighSpeed = 1000000Bits/sec 1323 if ($self->{ifSpeed} == 0) { 1324 # vlan graffl 1325 $self->{inputUtilization} = 0; 1326 $self->{outputUtilization} = 0; 1327 $self->{maxInputRate} = 0; 1328 $self->{maxOutputRate} = 0; 1329 } elsif ($self->{ifSpeed} == 4294967295) { 1330 $self->{maxInputRate} = $self->{ifHighSpeed} * 1000000; 1331 $self->{maxOutputRate} = $self->{ifHighSpeed} * 1000000; 1332 $self->{inputUtilization} = 100 * $self->{delta_ifInBits} / 1333 ($self->{delta_timestamp} * $self->{maxInputRate}); 1334 $self->{outputUtilization} = 100 * $self->{delta_ifOutBits} / 1335 ($self->{delta_timestamp} * $self->{maxOutputRate}); 1336 } else { 1337 $self->{maxInputRate} = $self->{ifSpeed}; 1338 $self->{maxOutputRate} = $self->{ifSpeed}; 1339 $self->{inputUtilization} = 100 * $self->{delta_ifInBits} / 1340 ($self->{delta_timestamp} * $self->{maxInputRate}); 1341 $self->{outputUtilization} = 100 * $self->{delta_ifOutBits} / 1342 ($self->{delta_timestamp} * $self->{maxOutputRate}); 1343 } 1344 if (defined $self->opts->ifspeed) { 1345 $self->override_opt('ifspeedin', $self->opts->ifspeed); 1346 $self->override_opt('ifspeedout', $self->opts->ifspeed); 1347 } 1348 if (defined $self->opts->ifspeedin) { 1349 $self->{inputUtilization} = 100 * $self->{delta_ifInBits} / 1350 ($self->{delta_timestamp} * $self->opts->ifspeedin); 1351 $self->{maxInputRate} = $self->opts->ifspeedin; 1352 } 1353 if (defined $self->opts->ifspeedout) { 1354 $self->{outputUtilization} = 100 * $self->{delta_ifOutBits} / 1355 ($self->{delta_timestamp} * $self->opts->ifspeedout); 1356 $self->{maxOutputRate} = $self->opts->ifspeedout; 1357 } 1358 $self->{inputRate} = $self->{delta_ifInBits} / $self->{delta_timestamp}; 1359 $self->{outputRate} = $self->{delta_ifOutBits} / $self->{delta_timestamp}; 1360 $self->override_opt("units", "bit") if ! $self->opts->units; 1361 $self->{inputRate} /= $self->number_of_bits($self->opts->units); 1362 $self->{outputRate} /= $self->number_of_bits($self->opts->units); 1363 $self->{maxInputRate} /= $self->number_of_bits($self->opts->units); 1364 $self->{maxOutputRate} /= $self->number_of_bits($self->opts->units); 1365 if ($self->{ifOperStatus} eq 'down') { 1366 $self->{inputUtilization} = 0; 1367 $self->{outputUtilization} = 0; 1368 $self->{inputRate} = 0; 1369 $self->{outputRate} = 0; 1370 $self->{maxInputRate} = 0; 1371 $self->{maxOutputRate} = 0; 1372 } 1373} 1374 1375sub get_mub_pkts { 1376 my ($self) = @_; 1377 foreach my $key (qw( 1378 ifHCInUcastPkts ifHCInMulticastPkts ifHCInBroadcastPkts 1379 ifHCOutUcastPkts ifHCOutMulticastPkts ifHCOutBroadcastPkts)) { 1380 $self->{$key} = 0 if (! exists $self->{$key} || ! defined $self->{$key}); 1381 } 1382 $self->valdiff({name => 'mub_'.$self->{ifDescr}}, qw( 1383 ifHCInUcastPkts ifHCInMulticastPkts ifHCInBroadcastPkts 1384 ifHCOutUcastPkts ifHCOutMulticastPkts ifHCOutBroadcastPkts)); 1385 $self->{delta_ifInPkts} = $self->{delta_ifHCInUcastPkts} + 1386 $self->{delta_ifHCInMulticastPkts} + 1387 $self->{delta_ifHCInBroadcastPkts}; 1388 $self->{delta_ifOutPkts} = $self->{delta_ifHCOutUcastPkts} + 1389 $self->{delta_ifHCOutMulticastPkts} + 1390 $self->{delta_ifHCOutBroadcastPkts}; 1391} 1392 1393sub init { 1394 my ($self) = @_; 1395 if ($self->mode =~ /device::interfaces::usage/) { 1396 $self->calc_usage(); 1397 } elsif ($self->mode =~ /device::interfaces::broadcasts/) { 1398 $self->calc_usage() if ! defined $self->{inputUtilization}; 1399 $self->get_mub_pkts() if ! defined $self->{delta_ifOutPkts}; 1400 $self->{inputBroadcastPercent} = $self->{delta_ifInPkts} == 0 ? 0 : 1401 100 * $self->{delta_ifHCInBroadcastPkts} / $self->{delta_ifInPkts}; 1402 $self->{outputBroadcastPercent} = $self->{delta_ifOutPkts} == 0 ? 0 : 1403 100 * $self->{delta_ifHCOutBroadcastPkts} / $self->{delta_ifOutPkts}; 1404 $self->{inputBroadcastUtilizationPercent} = $self->{inputBroadcastPercent} 1405 * $self->{inputUtilization} / 100; 1406 $self->{outputBroadcastUtilizationPercent} = $self->{outputBroadcastPercent} 1407 * $self->{inputUtilization} / 100; 1408 } else { 1409 $self->SUPER::init(); 1410 } 1411 return $self; 1412} 1413 1414sub init_etherstats { 1415 my ($self) = @_; 1416 if ($self->mode =~ /device::interfaces::etherstats/) { 1417 $Monitoring::GLPlugin::mode = "device::interfaces::broadcasts"; 1418 $self->init(); 1419 $Monitoring::GLPlugin::mode = "device::interfaces::etherstats"; 1420 # 32bit-cast ausputzen. es gibt welche, die haben nur 64bit 1421 @{$self->{columns}} = grep { 1422 ! /^if(In|Out).*castPkts$/ 1423 } grep { 1424 ! /^(ifOperStatus|ifAdminStatus|ifIndex|ifDescr|ifAlias|ifName)$/ 1425 } @{$self->{columns}}; 1426 my $ident = $self->{ifDescr}.md5_hex(join('_', @{$self->{columns}})); 1427 $self->valdiff({name => $ident}, @{$self->{columns}}); 1428 $self->{delta_InPkts} = $self->{delta_ifHCInUcastPkts} + 1429 $self->{delta_ifHCInMulticastPkts} + $self->{delta_ifHCInBroadcastPkts}; 1430 $self->{delta_OutPkts} = $self->{delta_ifHCOutUcastPkts} + 1431 $self->{delta_ifHCOutMulticastPkts} + $self->{delta_ifHCOutBroadcastPkts}; 1432 for my $stat (grep { /^(dot3|etherStats)/ } @{$self->{columns}}) { 1433 next if ! defined $self->{'delta_'.$stat}; 1434 $self->{$stat.'Percent'} = $self->{delta_InPkts} + $self->{delta_OutPkts} ? 1435 100 * $self->{'delta_'.$stat} / 1436 ($self->{delta_InPkts} + $self->{delta_OutPkts}) : 0; 1437 } 1438 } 1439 return $self; 1440} 1441 1442package Classes::IFMIB::Component::InterfaceSubsystem::Interface::StackSub; 1443our @ISA = qw(Classes::IFMIB::Component::InterfaceSubsystem::Interface); 1444use strict; 1445 1446sub init { 1447 my ($self) = @_; 1448} 1449 1450sub init_etherstats { 1451 my ($self) = @_; 1452 # hat sowieso keine broadcastcounter, ist sinnlos 1453} 1454 1455sub check { 1456 my ($self) = @_; 1457 my $full_descr = sprintf "%s%s%s", 1458 $self->{ifDescr}, 1459 $self->{ifAlias} && $self->{ifAlias} ne $self->{ifDescr} ? 1460 " (alias ".$self->{ifAlias}.")" : "", 1461 $self->{ifAddresses} ? " (addresses ".$self->{ifAddresses}.")" : ""; 1462 if ($self->mode =~ /device::interfaces::operstatus/) { 1463 $self->SUPER::check(); 1464 } elsif ($self->mode =~ /device::interfaces::duplex/) { 1465 $self->SUPER::check(); 1466 } else { 1467 $self->add_ok(sprintf '%s has no traffic', $full_descr); 1468 } 1469} 1470 1471 1472package Classes::IFMIB::Component::InterfaceSubsystem::Address; 1473our @ISA = qw(Monitoring::GLPlugin::SNMP::TableItem); 1474use strict; 1475 1476sub finish { 1477 my ($self) = @_; 1478 # INDEX { ipAddressAddrType, ipAddressAddr } 1479 my @tmp_indices = @{$self->{indices}}; 1480 my $last_tmp = scalar(@tmp_indices) - 1; 1481 # .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 1482 # IP-FORWARD-MIB::inetCidrRouteIfIndex.ipv4."0.0.0.0".32.2.0.0.ipv4."10.208.143.81" = INTEGER: 25337 1483 # Frag mich jetzt keiner, warum dem ipv4 ein 1.4 entspricht. Ich kann 1484 # jedenfalls der IP-FORWARD-MIB bzw. RFC4001 nicht entnehmen, dass fuer 1485 # InetAddressType zwei Stellen des Index vorgesehen sind. Zumal nur die 1486 # erste Stelle für die Textual Convention relevant ist. Aergert mich ziemlich, 1487 # daß jeder bloede /usr/bin/snmpwalk das besser hinbekommt als ich. 1488 # Was dazugelernt: 1=InetAddressType, 4=gehoert zur folgenden InetAddressIPv4 1489 # und gibt die Laenge an. Noch mehr gelernt: wenn eine Table mit Integer und 1490 # Octet String indiziert ist, dann ist die Groeße des Octet String Bestandteil 1491 # der OID. Diese _kann_ weggelassen werden für den _letzten_ Index. Der ist 1492 # halt dann so lang wie der Rest der OID. 1493 # Mit einem IMPLIED-Keyword koennte die Laenge auch weggelassen werden. 1494 1495 $self->{ipAddressAddrType} = $self->mibs_and_oids_definition( 1496 'INET-ADDRESS-MIB', 'InetAddressType', $tmp_indices[0]); 1497 shift @tmp_indices; 1498 1499 $self->{ipAddressAddr} = $self->mibs_and_oids_definition( 1500 'INET-ADDRESS-MIB', 'InetAddressMaker', 1501 $self->{ipAddressAddrType}, @tmp_indices); 1502} 1503 1504