1#!/usr/bin/perl 2# 3# Copyright (c) IBM Corp. 2009, 2010, All Rights Reserved 4# 5# Author(s): Vasileios Pappas <vpappas@us.ibm.com> 6# Jens Osterkamp <jens@linux.vnet.ibm.com> 7# 8# Permission is hereby granted, free of charge, to any person obtaining a copy 9# of this software and associated documentation files (the "Software"), to 10# deal 11# in the Software without restriction, including without limitation the rights 12# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13# copies of the Software, and to permit persons to whom the Software is 14# furnished to do so, subject to the following conditions: 15# 16# The above copyright notice and this permission notice shall be included in 17# all copies or substantial portions of the Software. 18# 19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24# FROM, 25# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26# THE SOFTWARE. 27 28use NetSNMP::OID (':all'); 29use NetSNMP::ASN (':all'); 30use NetSNMP::agent (':all'); 31 32sub STP_PROP_VALUE() { 0x01} 33sub STP_PROP_FILE() { 0x02} 34sub STP_PROP_DEC() { 0x04} 35sub STP_PROP_HEX() { 0x08} 36 37sub FDB_STATUS_OTHER { 1 } 38sub FDB_STATUS_INVALID { 2 } 39sub FDB_STATUS_LEARNED { 3 } 40sub FDB_STATUS_SELF { 4 } 41sub FDB_STATUS_MGMT { 5 } 42 43my %oid_value; 44my %oid_type; 45my %oid_next; 46my (%indexes, %interfaces, %macs, %ages, %locals, %vlans, %tagged); 47my $oid; 48 49$subagent=0; 50my $netdir="/sys/class/net/"; 51my $targetbridge; 52 53$cache_timout=60; 54$last_populated=0; 55 56my $regoid = ".1.3.6.1.2.1.17"; 57# are we running embedded ? If not, register as subagent 58if (!$agent) { 59 $agent = new NetSNMP::agent('Name' => 'dot1qbridge', 60 'AgentX' => 1); 61 $subagent = 1; 62 if ( $#ARGV != 0) { 63 usage($0); 64 exit(); 65 } 66 $targetbridge = $ARGV[0]; 67} else { 68 if (!defined($bridge)) { 69 usage($0); 70 exit(); 71 } 72 $targetbridge = $bridge; 73} 74 75$agent->register("dot1qbridge", ".1.3.6.1.2.1.17", \&request_handler) or die "registration of handler failed !\n"; 76 77if ($subagent) { 78 # register handler for graceful shutdown 79 $SIG{'INT'} = \&shutdown; 80 $SIG{'QUIT'} = \&shutdown; 81 $running = 1; 82 83 while($running) { 84 $agent->agent_check_and_process(1); 85 } 86 87 $agent->shutdown(); 88} 89 90sub usage { 91 my $name = shift; 92 if ($subagent) { 93 print $name."\n\n"; 94 print "usage: \t$name <bridge> start snmp bridge module". 95 " for bridge <bridge>\n\n"; 96 print "arguments: bridge name of the Linux bridge". 97 " which you want to provide info via snmp for.\n\n"; 98 } else { 99 print 'usage in snmpd.conf: perl $bridge="br0"; perl do <path to $name>\n'; 100 } 101 print "number of arguments given $#ARGV\n\n"; 102} 103 104sub request_handler { 105 my ($handler, $registration_info, $request_info, $requests)=@_; 106 my $request; 107 108 populate_mib($targetbridge); 109 110 for($request = $requests; $request; $request = $request->next()) { 111 if($request_info->getMode() == MODE_GET) { 112 mode_get($request); 113 } elsif($request_info->getMode() == MODE_GETNEXT) { 114 mode_get_next($request); 115 } else { 116 print STDERR "mode not implemented.\n"; 117 } 118 } 119} 120 121sub mode_get{ 122 my ($request)=@_; 123 my $oid=$request->getOID(); 124 125 $SNMP::use_numeric = 1; 126 my $noid=SNMP::translateObj($oid); 127 128 reply($request, $noid) if (exists $oid_value{$noid}); 129} 130 131sub find_next{ 132 my ($noid) = @_; 133 my $nextoid = $oid_next{$noid}; 134 if(!defined($nextoid) || !defined($oid_value{$nextoid})) { 135 # find the lowest OID whis is higher than $noid 136 $prev = ".1.3.6.1.2.1.18"; 137 $prev_oid = new NetSNMP::OID($prev); 138 $noid_oid = new NetSNMP::OID($noid); 139 #print "looking for next of $noid\n"; 140 for my $candidate (keys %oid_value) { 141 #print "evaluating $candidate\n"; 142 $candidate_oid = new NetSNMP::OID($candidate); 143 if ($noid_oid < $candidate_oid && $prev_oid > $candidate_oid) { 144 #print "found candidate $candidate\n"; 145 $prev = $candidate; 146 $prev_oid = $candidate_oid; 147 } 148 } 149 if ($prev eq ".1.3.6.1.2.1.18") { 150 return; # no OID higher than $noid found 151 } 152 $nextoid = $prev; 153 } 154 return $nextoid; 155} 156 157sub mode_get_next{ 158 my ($request)=@_; 159 my $oid=$request->getOID(); 160 $SNMP::use_numeric = 1; 161 my $noid=SNMP::translateObj($oid); 162 my $nextoid = find_next($noid); 163 #print "found $nextoid\n"; 164 if(defined($nextoid)) { 165 my $type = $oid_type{$nextoid}; 166 my $value = $oid_value{$nextoid}; 167 if (defined($type) and defined($value)) { 168 reply($request, $nextoid); 169 } 170 } 171} 172 173sub reply{ 174 my ($request, $oid)=@_; 175 176 my $type=$oid_type{$oid}; 177 my $value=$oid_value{$oid}; 178 179 $request->setOID(new NetSNMP::OID($oid)); 180 $request->setValue($type, $value); 181} 182 183# Populated MIB OID 184# 185## dot1dBasePort: 1.3.6.1.2.1.17.1.4.1.1.<dot1dBasePort> 186# INTEGER32 187# 188# dot1dBasePortIfIndex: 1.3.6.1.2.1.17.1.4.1.2.<dot1dBasePort> 189# INTEGER32 190# 191# dot1dStp*: 1.3.6.1.2.1.17.2.<1-14> 192# INTEGER, OCTET STRING 193# 194# dot1dTpFdbAddress: 1.3.6.1.2.1.17.4.3.1.1.<dot1dTpFdbAddress> 195# OCTET STRING (SIZE (6)) 196# 197# dot1dTpFdbPort: 1.3.6.1.2.1.17.4.3.1.2.<dot1dTpFdbAddress> 198# INTEGER32 199# 200# dot1dTpFdbStatus: 1.3.6.1.2.1.17.4.3.1.3.<dot1dTpFdbAddress> 201# INTEGER 202# 1 : other 203# 2 : invalid 204# 3 : learned 205# 4 : self 206# 5 : mgmt 207# 208 209sub populate_mib { 210 my $now; 211 my $bridge = shift; 212 my $seconds_passed; 213 $ports=0; 214 $oid=""; 215 216 $now=time(); 217 $seconds_passed=$now-$last_populated; 218 return if($seconds_passed <= $cache_timout); 219 $last_populated=$now; 220 221 %oid_value=(); 222 %oid_type=(); 223 %oid_next=(); 224 %indexes=(); 225 %interfaces=(); 226 %macs=(); 227 %ages=(); 228 %locals=(); 229 %vlans=(); 230 %tagged=(); 231 232 # first populated oid 233 $oid_next{".1.3.6.1.2.1.17"}=".1.3.6.1.2.1.17.1.1"; 234 235 createbaseinfo($bridge); 236 237 readindexes($bridge); 238 readforwards($bridge); 239 readvlans($bridge); 240 241 createports($bridge); 242 243 stpproperties($bridge); 244 245 stpportproperties($bridge); 246 247 dot1dTpproperties(); 248 249 my $prevoid = $oid; 250 my $curroid = createmacs($bridge); 251 $oid_next{$prevoid} = $curroid; 252 253 portproperties($bridge); 254 255 256 dot1qbase($bridge); 257 258 dot1qfdb($bridge); 259 260 dot1qcurrentvlans($bridge); 261 262 return 0; 263} 264 265sub findbridges() 266{ 267 my @bridges; 268 269 opendir(DIR, $netdir) or die "unable to open $netdir !\n"; 270 271 while(my $br=readdir(DIR)){ 272 next if $br eq "."; 273 next if $br eq ".."; 274 next unless -d $netdir.$br."/bridge"; 275 push @bridges, $br; 276 } 277 278 close(DIR); 279 280 return @bridges; 281} 282 283sub createbaseinfo() 284{ 285 my $bridge = shift; 286 287 $oid=".1.3.6.1.2.1.17.1.1"; 288 $oid_value{$oid}=mac2hex(readfile($netdir.$bridge."/address", 0)); 289 $oid_type{$oid}=ASN_OCTET_STR; 290 $oid_next{$oid}=".1.3.6.1.2.1.17.1.2"; 291 292 opendir(DIR, $netdir.$bridge."/brif/") or die "Could not open ".$netdir.$bridge."brif !\n"; 293 294 foreach $entry (readdir(DIR)) { 295 next if $entry eq "."; 296 next if $entry eq ".."; 297 # only count non-vlan interfaces 298 next if $entry =~ /\.[0-9]*/; 299 $ports++; 300 } 301 302 closedir(DIR); 303 304 $oid=".1.3.6.1.2.1.17.1.2"; 305 $oid_value{$oid}=$ports; 306 $oid_type{$oid}=ASN_INTEGER; 307 $oid_next{$oid}=".1.3.6.1.2.1.17.1.3"; 308 309 $oid=".1.3.6.1.2.1.17.1.3"; 310 $oid_value{$oid}="2"; # transparent only 311 $oid_type{$oid}=ASN_INTEGER; 312 $oid_next{$oid}=".1.3.6.1.2.1.17.1.4.1.1.1"; 313 314} 315 316sub createmacs() 317{ 318 my $bridge = shift; 319 my $start_oid = $oid = ".1.3.6.1.2.1.17.4.3.1"; 320 321 foreach my $mac (sort {$a cmp $b} keys %macs) { 322 my $mac_oid=mac2oid($mac); 323 unless(defined($first_mac_oid)){ 324 $first_mac_oid=$mac_oid; 325 $oid_next{$oid.".1"}=$oid.".1".$mac_oid; 326 $oid_next{$oid.".2"}=$oid.".2".$mac_oid; 327 $oid_next{$oid.".3"}=$oid.".3".$mac_oid; 328 } 329 my $port=$macs{$mac}{$bridge}; 330 my $baseport=$baseports{$bridge}{$port}; 331 my $status=$locals{$mac}{$bridge}; 332 my $age=$ages{$mac}{$bridge}; 333 334 $oid_value{$oid.".1".$mac_oid}=mac2hex($mac); 335 $oid_type{$oid.".1".$mac_oid}=ASN_OCTET_STR; 336 if(defined($prv_mac_oid)){ 337 $oid_next{$oid.".1".$prv_mac_oid}= 338 $oid.".1".$mac_oid; 339 } 340 341 $oid_value{$oid.".2".$mac_oid}=$baseport; 342 $oid_type{$oid.".2".$mac_oid}=ASN_INTEGER; 343 if(defined($prv_mac_oid)){ 344 $oid_next{$oid.".2".$prv_mac_oid}= 345 $oid.".2".$mac_oid; 346 } 347 348 $oid_value{$oid.".3".$mac_oid}=$status; 349 $oid_type{$oid.".3".$mac_oid}=ASN_INTEGER; 350 if(defined($prv_mac_oid)){ 351 $oid_next{$oid.".3".$prv_mac_oid}= 352 $oid.".3".$mac_oid; 353 } 354 355 $prv_mac_oid=$mac_oid; 356 } 357 358 if ($prv_mac_oid and $first_mac_oid) { 359 $oid_next{$oid.".1".$prv_mac_oid}=$oid.".2".$first_mac_oid; 360 $oid_next{$oid.".2".$prv_mac_oid}=$oid.".3".$first_mac_oid; 361 $oid_next{$oid.".3".$prv_mac_oid}=".1.3.6.1.2.1.17.4.4.1.1.1"; 362 } 363 364 undef $prv_mac_oid; 365 undef $first_mac_oid; 366 367 return $start_oid.".1".$first_mac_oid; 368} 369 370# TODO: is this sequence complete ? 371sub createports() 372{ 373 my $bridge = shift; 374 my ($baseport, $prev_baseport, $first_baseport); 375 $baseport=1; 376 my $oid= '.1.3.6.1.2.1.17.1.4.1'; 377 378 foreach my $port (keys %{$interfaces{$bridge}}) { 379 unless(defined($first_baseport)){ 380 $first_baseport=$baseport; 381 $oid_next{$oid.".1"}=$oid.".1.".$baseport; 382 $oid_next{$oid.".2"}=$oid.".2.".$baseport; 383 } 384 my $index=$indexes{$bridge}{$port}; 385 $baseports{$bridge}{$port}=$baseport; 386 387 $oid_value{$oid.".1.".$baseport}=$baseport; 388 $oid_type{$oid.".1.".$baseport}=ASN_INTEGER; 389 if(defined($prv_baseport)){ 390 $oid_next{$oid.".1.".$prv_baseport}= 391 $oid.".1.".$baseport; 392 } 393 394 $oid_value{$oid.".2.".$baseport}=$index; 395 $oid_type{$oid.".2.".$baseport}=ASN_INTEGER; 396 if(defined($prv_baseport)){ 397 $oid_next{$oid.".2.".$prv_baseport}= 398 $oid.".2.".$baseport; 399 } 400 401 $prv_baseport=$baseport; 402 $baseport++; 403 } 404 405 if ( $prv_baseport and $first_baseport ) { 406 $oid_next{$oid.".1.".$prv_baseport}=$oid.".2.".$first_baseport; 407 $oid_next{$oid.".2.".$prv_baseport}=".1.3.6.1.2.1.17.2.1"; 408 } 409 410 undef $prv_baseport; 411 undef $first_baseport; 412 413} 414 415sub stpproperties() 416{ 417 my $bridge = shift; 418 my $dir = $netdir.$bridge."/bridge/"; 419 420 @stpprops = ( { oid => ".1.3.6.1.2.1.17.2.1", 421 flags => STP_PROP_VALUE, 422 value => "3", 423 type => ASN_INTEGER, 424 nextoid => ".1.3.6.1.2.1.17.2.2" }, 425 { oid => ".1.3.6.1.2.1.17.2.2", 426 flags => STP_PROP_FILE | STP_PROP_DEC, 427 value => $dir."priority", 428 type => ASN_INTEGER, 429 nextoid => ".1.3.6.1.2.1.17.2.3" }, 430 { oid => ".1.3.6.1.2.1.17.2.3", 431 flags => STP_PROP_FILE | STP_PROP_DEC, 432 value => $dir."topology_change_timer", 433 type => ASN_TIMETICKS, 434 nextoid => ".1.3.6.1.2.1.17.2.4" }, 435 { oid => ".1.3.6.1.2.1.17.2.4", 436 flags => STP_PROP_FILE | STP_PROP_DEC, 437 value => $dir."topology_change", 438 type => ASN_COUNTER, 439 nextoid => ".1.3.6.1.2.1.17.2.5" }, 440 { oid => ".1.3.6.1.2.1.17.2.5", 441 flags => STP_PROP_FILE | STP_PROP_DEC, 442 value => $dir."root_id", 443 type => ASN_OCTET_STR, 444 nextoid => ".1.3.6.1.2.1.17.2.6" }, 445 { oid => ".1.3.6.1.2.1.17.2.6", 446 flags => STP_PROP_FILE | STP_PROP_DEC, 447 value => $dir."root_path_cost", 448 type => ASN_INTEGER, 449 nextoid => ".1.3.6.1.2.1.17.2.7" }, 450 { oid => ".1.3.6.1.2.1.17.2.7", 451 flags => STP_PROP_FILE | STP_PROP_DEC, 452 value => $dir."root_port", 453 type => ASN_INTEGER, 454 nextoid => ".1.3.6.1.2.1.17.2.8" }, 455 { oid => ".1.3.6.1.2.1.17.2.8", 456 flags => STP_PROP_FILE | STP_PROP_DEC, 457 value => $dir."max_age", 458 type => ASN_INTEGER, 459 nextoid => ".1.3.6.1.2.1.17.2.9" }, 460 { oid => ".1.3.6.1.2.1.17.2.9", 461 flags => STP_PROP_FILE | STP_PROP_DEC, 462 value => $dir."hello_time", 463 type => ASN_INTEGER, 464 nextoid => ".1.3.6.1.2.1.17.2.11" }, 465 # TODO ...17.2.10 466 { oid => ".1.3.6.1.2.1.17.2.11", 467 flags => STP_PROP_FILE | STP_PROP_DEC, 468 value => $dir."forward_delay", 469 type => ASN_INTEGER, 470 nextoid => ".1.3.6.1.2.1.17.2.12" }, 471 { oid => ".1.3.6.1.2.1.17.2.12", 472 flags => STP_PROP_FILE | STP_PROP_DEC, 473 value => $dir."max_age", 474 type => ASN_INTEGER, 475 nextoid => ".1.3.6.1.2.1.17.2.13" }, 476 { oid => ".1.3.6.1.2.1.17.2.13", 477 flags => STP_PROP_FILE | STP_PROP_DEC, 478 value => $dir."hello_time", 479 type => ASN_INTEGER, 480 nextoid => ".1.3.6.1.2.1.17.2.14" }, 481 { oid => ".1.3.6.1.2.1.17.2.14", 482 flags => STP_PROP_FILE | STP_PROP_DEC, 483 value => $dir."forward_delay", 484 type => ASN_INTEGER, 485 nextoid => ".1.3.6.1.2.1.17.2.15.1.1.1" }, 486 ); 487 488 for ($i=0; $i <= $#stpprops; $i++) { 489 my %props = %{$stpprops[$i]}; 490 $oid = $props{'oid'}; 491 if ( $props{'flags'} & STP_PROP_VALUE,) { 492 $oid_value{$oid} = $props{'value'}; 493 } 494 if ( $props{'flags'} & STP_PROP_FILE,) { 495 $oid_value{$oid} = 496 readfile($props{'value'}, 497 $props{'flags'}); 498 } 499 $oid_type{$oid} = $props{'type'}; 500 $oid_next{$oid} = $props{'nextoid'}; 501 } 502} 503 504sub stpportproperties 505{ 506 my $bridge = shift; 507 my $brifdir = $netdir.$bridge."/brif/"; 508 my ($baseport, $first_baseport, $prev_baseport); 509 510 $oid='.1.3.6.1.2.1.17.2.15.1'; 511 512 foreach my $port (keys %{$interfaces{$bridge}}) { 513 $baseport = $baseports{$bridge}{$port}; 514 515 unless(defined($first_baseport)){ 516 $first_baseport=$baseport; 517 $oid_next{$oid.".1"}=$oid.".1.".$baseport; 518 $oid_next{$oid.".2"}=$oid.".2.".$baseport; 519 } 520 521 my $interface = $interfaces{$bridge}{$port}; 522 my $ifdir = $brifdir.$interface; 523 524 # dot1dStpPort 525 $oid_value{$oid.".1.".$baseport}=$baseport; 526 $oid_type{$oid.".1.".$baseport}=ASN_INTEGER; 527 if(defined($prev_baseport)){ 528 $oid_next{$oid.".1.".$prev_baseport}= 529 $oid.".1.".$baseport; 530 } 531 532 # dot1dStpPortPriority 533 $oid_value{$oid.".2.".$baseport}=readfile($ifdir."/priority", 0); 534 $oid_type{$oid.".2.".$baseport}=ASN_INTEGER; 535 if(defined($prev_baseport)){ 536 $oid_next{$oid.".2.".$prev_baseport}= 537 $oid.".2.".$baseport; 538 } 539 540 # dot1dStpPortState 541 my @translation = (1, 3, 4, 5, 2); 542 my $state = readfile($ifdir."/state", 0); 543 $oid_value{$oid.".3.".$baseport}=$translation[$state]; 544 $oid_type{$oid.".3.".$baseport}=ASN_INTEGER; 545 if(defined($prev_baseport)){ 546 $oid_next{$oid.".3.".$prev_baseport}= 547 $oid.".3.".$baseport; 548 } 549 550 # dot1dStpPortEnable 551 @translation = (2, 1, 1, 1, 1); 552 $oid_value{$oid.".4.".$baseport}=$translation[$state]; 553 $oid_type{$oid.".4.".$baseport}=ASN_INTEGER; 554 if(defined($prev_baseport)){ 555 $oid_next{$oid.".4.".$prev_baseport}= 556 $oid.".4.".$baseport; 557 } 558 559 # dot1dStpPortPathCost 560 $oid_value{$oid.".5.".$baseport}=readfile($ifdir."/path_cost", 0); 561 $oid_type{$oid.".5.".$baseport}=ASN_INTEGER; 562 if(defined($prev_baseport)){ 563 $oid_next{$oid.".5.".$prev_baseport}= 564 $oid.".5.".$baseport; 565 } 566 567 # dot1dStpPortDesignatedRoot 568 $oid_value{$oid.".6.".$baseport}=readfile($ifdir."/designated_root", 0); 569 $oid_type{$oid.".6.".$baseport}=ASN_OCTET_STR; 570 if(defined($prev_baseport)){ 571 $oid_next{$oid.".6.".$prev_baseport}= 572 $oid.".6.".$baseport; 573 } 574 575 # dot1dStpPortDesignatedCost 576 $oid_value{$oid.".7.".$baseport}=readfile($ifdir."/designated_cost", 0); 577 $oid_type{$oid.".7.".$baseport}=ASN_INTEGER; 578 if(defined($prev_baseport)){ 579 $oid_next{$oid.".7.".$prev_baseport}= 580 $oid.".7.".$baseport; 581 } 582 583 # dot1dStpPortDesignatedBridge 584 $oid_value{$oid.".8.".$baseport}=readfile($ifdir."/designated_bridge", 0); 585 $oid_type{$oid.".8.".$baseport}=ASN_OCTET_STR; 586 if(defined($prev_baseport)){ 587 $oid_next{$oid.".8.".$prev_baseport}= 588 $oid.".8.".$baseport; 589 } 590 591 # dot1dStpPortDesignatedPort 592 $oid_value{$oid.".9.".$baseport}=readfile($ifdir."/designated_port", 0); 593 $oid_type{$oid.".9.".$baseport}=ASN_OCTET_STR; 594 if(defined($prev_baseport)){ 595 $oid_next{$oid.".9.".$prev_baseport}= 596 $oid.".9.".$baseport; 597 } 598 599 # dot1dStpPortForwardTransitions (no value in bridge module) 600 601 # dot1dStpPortPathCost32 602 $oid_value{$oid.".11.".$baseport}=readfile($ifdir."/path_cost", 0); 603 $oid_type{$oid.".11.".$baseport}=ASN_INTEGER; 604 if(defined($prev_baseport)){ 605 $oid_next{$oid.".11.".$prev_baseport}= 606 $oid.".11.".$baseport; 607 } 608 609 610 $prev_baseport=$baseport; 611 } 612 613 if ( $prev_baseport and $first_baseport ) { 614 $oid_next{$oid.".1.".$prev_baseport}=$oid.".2.".$first_baseport; 615 $oid_next{$oid.".2.".$prev_baseport}=$oid.".3.".$first_baseport; 616 $oid_next{$oid.".3.".$prev_baseport}=$oid.".4.".$first_baseport; 617 $oid_next{$oid.".4.".$prev_baseport}=$oid.".5.".$first_baseport; 618 $oid_next{$oid.".5.".$prev_baseport}=$oid.".6.".$first_baseport; 619 $oid_next{$oid.".6.".$prev_baseport}=$oid.".7.".$first_baseport; 620 $oid_next{$oid.".7.".$prev_baseport}=$oid.".8.".$first_baseport; 621 $oid_next{$oid.".8.".$prev_baseport}=$oid.".9.".$first_baseport; 622 $oid_next{$oid.".9.".$prev_baseport}=$oid.".11.".$first_baseport; 623 $oid_next{$oid.".11.".$prev_baseport}=".1.3.6.1.2.1.17.4.1"; 624 } 625 626 $oid = $oid.".11.".$prev_baseport; 627 628 undef $prev_baseport; 629 undef $first_baseport; 630 631} 632 633sub dot1dTpproperties() 634{ 635 @stpprops = ( { oid => ".1.3.6.1.2.1.17.4.1", 636 flags => STP_PROP_VALUE, 637 value => "0", 638 type => ASN_COUNTER, 639 nextoid => ".1.3.6.1.2.1.17.4.2" }, 640 { oid => ".1.3.6.1.2.1.17.4.2", 641 flags => STP_PROP_VALUE, 642 value => "300", 643 type => ASN_INTEGER, 644 nextoid => ".1.3.6.1.2.1.17.4.3" }, 645 ); 646 647 for ($i=0; $i <= $#stpprops; $i++) { 648 my %props = %{$stpprops[$i]}; 649 $oid = $props{'oid'}; 650 if ( $props{'flags'} & STP_PROP_VALUE,) { 651 $oid_value{$oid} = $props{'value'}; 652 } 653 if ( $props{'flags'} & STP_PROP_FILE,) { 654 $oid_value{$oid} = 655 readfile($props{'value'}, 656 $props{'flags'}); 657 } 658 $oid_type{$oid} = $props{'type'}; 659 $oid_next{$oid} = $props{'nextoid'}; 660 } 661} 662 663sub portproperties 664{ 665 my $bridge = shift; 666 my ($baseport, $first_baseport, $prev_baseport); 667 668 $oid='.1.3.6.1.2.1.17.4.4.1'; 669 670 foreach my $port (keys %{$interfaces{$bridge}}) { 671 $baseport = $baseports{$bridge}{$port}; 672 673 unless(defined($first_baseport)){ 674 $first_baseport=$baseport; 675 $oid_next{$oid.".1"}=$oid.".1.".$baseport; 676 $oid_next{$oid.".2"}=$oid.".2.".$baseport; 677 } 678 679 my $interface = $interfaces{$bridge}{$port}; 680 my $ifdir = $netdir.$interface; 681 682 # dot1dTpPort 683 $oid_value{$oid.".1.".$baseport}=$baseport; 684 $oid_type{$oid.".1.".$baseport}=ASN_INTEGER; 685 if(defined($prev_baseport)){ 686 $oid_next{$oid.".1.".$prev_baseport}= 687 $oid.".1.".$baseport; 688 } 689 690 # dot1dTpPortMaxInfo 691 $oid_value{$oid.".2.".$baseport}=readfile($ifdir."/mtu", 0); 692 $oid_type{$oid.".2.".$baseport}=ASN_INTEGER; 693 if(defined($prev_baseport)){ 694 $oid_next{$oid.".2.".$prev_baseport}= 695 $oid.".2.".$baseport; 696 } 697 698 # dot1dTpPortInFrames 699 $oid_value{$oid.".3.".$baseport}=readfile($ifdir."/statistics/rx_packets", 0); 700 $oid_type{$oid.".3.".$baseport}=ASN_COUNTER; 701 if(defined($prev_baseport)){ 702 $oid_next{$oid.".3.".$prev_baseport}= 703 $oid.".3.".$baseport; 704 } 705 706 # dot1dTpPortOutFrames 707 $oid_value{$oid.".4.".$baseport}=readfile($ifdir."/statistics/tx_packets", 0); 708 $oid_type{$oid.".4.".$baseport}=ASN_COUNTER; 709 if(defined($prev_baseport)){ 710 $oid_next{$oid.".4.".$prev_baseport}= 711 $oid.".4.".$baseport; 712 } 713 714 # dot1dTpPortInDiscards 715 $oid_value{$oid.".5.".$baseport}=readfile($ifdir."/statistics/rx_dropped", 0); 716 $oid_type{$oid.".5.".$baseport}=ASN_COUNTER; 717 if(defined($prev_baseport)){ 718 $oid_next{$oid.".5.".$prev_baseport}= 719 $oid.".5.".$baseport; 720 } 721 722 $prev_baseport=$baseport; 723 } 724 725 if ( $prev_baseport and $first_baseport ) { 726 $oid_next{$oid.".1.".$prev_baseport}=$oid.".2.".$first_baseport; 727 $oid_next{$oid.".2.".$prev_baseport}=$oid.".3.".$first_baseport; 728 $oid_next{$oid.".3.".$prev_baseport}=$oid.".4.".$first_baseport; 729 $oid_next{$oid.".4.".$prev_baseport}=$oid.".5.".$first_baseport; 730 $oid_next{$oid.".5.".$prev_baseport}=".1.3.6.1.2.1.17.5.1"; 731 } 732 733 $oid = $oid.".5.".$prev_baseport; 734 735 undef $prev_baseport; 736 undef $first_baseport; 737} 738 739sub dot1qbase() 740{ 741 my $bridge = shift; 742 743 my $oid=".1.3.6.1.2.1.17.7.1.1"; 744 $oid_next{".1.3.6.1.2.1.17.7"}=$oid.".1"; 745 $oid_next{".1.3.6.1.2.1.17.7.1"}=$oid.".1"; 746 747 $oid_value{$oid.".1"}=1; 748 $oid_type{$oid.".1"}=ASN_INTEGER; 749 $oid_next{$oid.".1"}=$oid.".2"; 750 751 $oid_value{$oid.".2"}=4094; 752 $oid_type{$oid.".2"}=ASN_UNSIGNED; 753 $oid_next{$oid.".2"}=$oid.".3"; 754 755 $oid_value{$oid.".3"}=4094; 756 $oid_type{$oid.".3"}=ASN_UNSIGNED; 757 $oid_next{$oid.".3"}=$oid.".4"; 758 759 $oid_value{$oid.".4"}=0; # filled in by currentvlans 760 $oid_type{$oid.".4"}=ASN_UNSIGNED; 761 $oid_next{$oid.".4"}=$oid.".5"; 762 763 $oid_value{$oid.".5"}=2; 764 $oid_type{$oid.".5"}=ASN_INTEGER; 765 $oid_next{$oid.".5"}=0; # filled in by dot1qfdb 766 767} 768 769sub dot1qfdb() 770{ 771 my $bridge = shift; 772 773 my $oid=".1.3.6.1.2.1.17.7.1.2"; 774 foreach my $vlan (sort {$a<=>$b} keys %vlans){ 775 unless(defined($first_vlan)){ 776 $first_vlan=$vlan; 777 $oid_next{".1.3.6.1.2.1.17.7.1.1.5"}=$oid.".1.1.".$vlan; 778 $oid_next{$oid}=$oid.".1.1.".$vlan; 779 $oid_next{$oid.".1"}=$oid.".1.1.".$vlan; 780 $oid_next{$oid.".1.1"}=$oid.".1.1.".$vlan; 781 $oid_next{$oid.".1.2"}=$oid.".1.2.".$vlan; 782 } 783 784 $oid_value{$oid.".1.1.".$vlan}=$vlan; 785 $oid_type{$oid.".1.1.".$vlan}=ASN_UNSIGNED; 786 if(defined($prv_vlan)){ 787 $oid_next{$oid.".1.1.".$prv_vlan}=$oid.".1.1.".$vlan; 788 } 789 790 $oid_value{$oid.".1.2.".$vlan}=0; # to be filled later 791 $oid_type{$oid.".1.2.".$vlan}=ASN_COUNTER; 792 if(defined($prv_vlan)){ 793 $oid_next{$oid.".1.2.".$prv_vlan}=$oid.".1.2.".$vlan; 794 } 795 796 $prv_vlan=$vlan; 797 } 798 if($prv_vlan and $first_vlan){ 799 $oid_next{$oid.".1.1.".$prv_vlan}=$oid.".1.2.".$first_vlan; 800 $oid_next{$oid.".1.2.".$prv_vlan}=0; # to be filled later 801 } 802 803 my %macvlan=(); 804 my %vlanmac=(); 805 806 foreach my $vlan (sort {$a<=>$b} keys %vlans){ 807 my $count=0; 808 foreach my $mac (sort {$a cmp $b} keys %macs) { 809 my $vbridge=$bridge."_vlan".$vlan; 810 next unless(defined($macs{$mac}{$vbridge})); 811 $count++; 812 my $mac_oid=mac2oid($mac); 813 $macvlan{$vlan.$mac_oid}=$mac; 814 $vlanmac{$vlan.$mac_oid}=$vlan; 815 } 816 $oid_value{$oid.".1.2.".$vlan}=$count; 817 } 818 819 foreach my $vmac_oid (sort {$a cmp $b} keys %vlanmac){ 820 my $mac=$macvlan{$vmac_oid}; 821 my $vlan=$vlanmac{$vmac_oid}; 822 823 #print "VMAC: $vmac_oid ($vlan:$mac)\n"; 824 unless(defined($first_vmac_oid)){ 825 $first_vmac_oid=$vmac_oid; 826 $oid_next{$oid.".1.2.".$prv_vlan}=$oid.".2.1.".$vmac_oid; 827 $oid_next{$oid.".2"}=$oid.".2.1.".$vmac_oid; 828 $oid_next{$oid.".2.1"}=$oid.".2.1.".$vmac_oid; 829 $oid_next{$oid.".2.2"}=$oid.".2.2.".$vmac_oid; 830 $oid_next{$oid.".2.3"}=$oid.".2.3.".$vmac_oid; 831 } 832 833 my $port=$macs{$mac}{$bridge}; 834 my $baseport=$baseports{$bridge}{$port}; 835 my $status=$locals{$mac}{$bridge}; 836 my $age=$ages{$mac}{$bridge}; 837 838 print "VLAN $vlan: $mac -> $port:$baseport ($status, $age)\n"; 839 840 $oid_value{$oid.".2.1.".$vmac_oid}=mac2hex($mac); 841 $oid_type{$oid.".2.1.".$vmac_oid}=ASN_OCTET_STR; 842 if(defined($prv_vmac_oid)){ 843 $oid_next{$oid.".2.1.".$prv_vmac_oid}=$oid.".2.1.".$vmac_oid; 844 } 845 846 $oid_value{$oid.".2.2.".$vmac_oid}=$baseport; 847 $oid_type{$oid.".2.2.".$vmac_oid}=ASN_INTEGER; 848 if(defined($prv_vmac_oid)){ 849 $oid_next{$oid.".2.2.".$prv_vmac_oid}=$oid.".2.2.".$vmac_oid; 850 } 851 852 $oid_value{$oid.".2.3.".$vmac_oid}=$status; 853 $oid_type{$oid.".2.3.".$vmac_oid}=ASN_INTEGER; 854 if(defined($prv_vmac_oid)){ 855 $oid_next{$oid.".2.3.".$prv_vmac_oid}=$oid.".2.3.".$vmac_oid; 856 } 857 $prv_vmac_oid=$vmac_oid; 858 } 859 860 if ($prv_vmac_oid and $first_vmac_oid) { 861 $oid_next{$oid.".2.1.".$prv_vmac_oid}=$oid.".2.2.".$first_vmac_oid; 862 $oid_next{$oid.".2.2.".$prv_vmac_oid}=$oid.".2.3.".$first_vmac_oid; 863 $oid_next{$oid.".2.3.".$prv_vmac_oid}=".1.3.6.1.2.1.17.7.1.4.1"; 864 } 865 866 undef $first_vmac_oid; 867 undef $prv_vmac_oid; 868 869 undef $first_vlan; 870 undef $prv_vlan; 871} 872 873sub dot1qcurrentvlans() 874{ 875 my $bridge = shift; 876 877 878 my $oid=".1.3.6.1.2.1.17.7.1.4.1"; 879 $oid_next{".1.3.6.1.2.1.17.7.1.4"}=$oid; 880 881 $oid_value{$oid}=0; # can't keep track of this info 882 $oid_type{$oid}=ASN_COUNTER; 883 884 my $count=0; 885 $oid=".1.3.6.1.2.1.17.7.1.4.2"; 886 foreach my $vlan (sort {$a<=>$b} keys %vlans){ 887 $count++; 888 my @allports=(); 889 my @untaggedports=(); 890 foreach my $port (keys %{$vlans{$vlan}}){ 891 $baseport=$baseports{$bridge}{$port}; 892 push @allports, $baseport; 893 push @untaggedports, $baseport 894 unless($tagged{$vlan}{$port}); 895 } 896 #print "ADDING: vlan $vlan (@allports, @untaggedports)\n"; 897 unless(defined($first_vlan)){ 898 $first_vlan=$vlan; 899 $oid_next{".1.3.6.1.2.1.17.7.1.4.1"}=$oid.".1.0.".$vlan; 900 $oid_next{$oid}=$oid.".1.0.".$vlan; 901 $oid_next{$oid.".1"}=$oid.".1.0.".$vlan; 902 $oid_next{$oid.".2"}=$oid.".2.0.".$vlan; 903 $oid_next{$oid.".3"}=$oid.".3.0.".$vlan; 904 $oid_next{$oid.".4"}=$oid.".4.0.".$vlan; 905 $oid_next{$oid.".5"}=$oid.".5.0.".$vlan; 906 $oid_next{$oid.".6"}=$oid.".6.0.".$vlan; 907 $oid_next{$oid.".7"}=$oid.".7.0.".$vlan; 908 } 909 910 $oid_value{$oid.".1.0.".$vlan}=0; # can't keep track of this 911 $oid_type{$oid.".1.0.".$vlan}=ASN_TIMETICKS; 912 if(defined($prv_vlan)){ 913 $oid_next{$oid.".1.0.".$prv_vlan}=$oid.".1.0.".$vlan; 914 } 915 916 $oid_value{$oid.".2.0.".$vlan}=$vlan; 917 $oid_type{$oid.".2.0.".$vlan}=ASN_UNSIGNED; 918 if(defined($prv_vlan)){ 919 $oid_next{$oid.".2.0.".$prv_vlan}=$oid.".2.0.".$vlan; 920 } 921 922 $oid_value{$oid.".3.0.".$vlan}=$vlan; 923 $oid_type{$oid.".3.0.".$vlan}=ASN_UNSIGNED; 924 if(defined($prv_vlan)){ 925 $oid_next{$oid.".3.0.".$prv_vlan}=$oid.".3.0.".$vlan; 926 } 927 928 $oid_value{$oid.".4.0.".$vlan}=getportlist(@allports); 929 $oid_type{$oid.".4.0.".$vlan}=ASN_OCTET_STR; 930 if(defined($prv_vlan)){ 931 $oid_next{$oid.".4.0.".$prv_vlan}=$oid.".4.0.".$vlan; 932 } 933 934 $oid_value{$oid.".5.0.".$vlan}=getportlist(@untaggedports); 935 $oid_type{$oid.".5.0.".$vlan}=ASN_OCTET_STR; 936 if(defined($prv_vlan)){ 937 $oid_next{$oid.".5.0.".$prv_vlan}=$oid.".5.0.".$vlan; 938 } 939 940 $oid_value{$oid.".6.0.".$vlan}=1; 941 $oid_type{$oid.".6.0.".$vlan}=ASN_INTEGER; 942 if(defined($prv_vlan)){ 943 $oid_next{$oid.".6.0.".$prv_vlan}=$oid.".6.0.".$vlan; 944 } 945 946 $oid_value{$oid.".7.0.".$vlan}=0; 947 $oid_type{$oid.".7.0.".$vlan}=ASN_TIMETICKS; 948 if(defined($prv_vlan)){ 949 $oid_next{$oid.".7.0.".$prv_vlan}=$oid.".7.0.".$vlan; 950 } 951 $prv_vlan=$vlan; 952 } 953 954 $oid_value{".1.3.6.1.2.1.17.7.1.1.4"}=$count; 955 if($prv_vlan and $first_vlan){ 956 $oid_next{$oid.".1.0.".$prv_vlan}=$oid.".2.0.".$first_vlan; 957 $oid_next{$oid.".2.0.".$prv_vlan}=$oid.".3.0.".$first_vlan; 958 $oid_next{$oid.".3.0.".$prv_vlan}=$oid.".4.0.".$first_vlan; 959 $oid_next{$oid.".4.0.".$prv_vlan}=$oid.".5.0.".$first_vlan; 960 $oid_next{$oid.".5.0.".$prv_vlan}=$oid.".6.0.".$first_vlan; 961 $oid_next{$oid.".6.0.".$prv_vlan}=$oid.".7.0.".$first_vlan; 962 $oid_next{$oid.".7.0.".$prv_vlan}=".1.3.6.1.2.1.17.7.1.4.3"; 963 } 964 965 undef $prv_vlan; 966 undef $first_vlan; 967 968} 969 970sub readforwards() 971{ 972 my $bridge = shift; 973 my $fdb=$netdir.$bridge."/brforward"; 974 975 open(FWD, $fdb) or return -1; 976 while(sysread(FWD, $data, 20)){ 977 my $mac; 978 my ($b1,$b2,$b3,$b4,$b5,$b6,$port,$local,$age,$hi)= 979 unpack("C6 C C L C x3", $data); 980 $mac=sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 981 $b1,$b2,$b3,$b4,$b5,$b6); 982 $age=$age/100; 983 $macs{$mac}{$bridge}=$port; 984 $ages{$mac}{$bridge}=$age; 985 $locals{$mac}{$bridge}=FDB_STATUS_LEARNED; 986 next if ($local); 987 $macs{$mac}{$bridge}=$bridge; 988 $locals{$mac}{$bridge}=FDB_STATUS_SELF; 989 } 990 close(FWD); 991} 992 993sub readindexes() 994{ 995 my $bridge = shift; 996 997 my $brifdir=$netdir.$bridge."/brif/"; 998 999 opendir(DIR, $brifdir) or return -1; 1000 my @interfaces = readdir(DIR); 1001 next if ($#interfaces lt 2); 1002 foreach my $if (@interfaces) { 1003 next if $if eq "."; 1004 next if $if eq ".."; 1005 1006 my $port=hex(readfile($brifdir.$if."/port_no", 0)); 1007 my $index=readfile($netdir.$if."/ifindex", 0); 1008 1009 $indexes{$bridge}{$port}=$index; 1010 $interfaces{$bridge}{$port}=$if; 1011 } 1012 1013 $indexes{$bridge}{$bridge}=readfile($netdir.$bridge."/ifindex", 0); 1014 1015 close(DIR); 1016} 1017 1018sub readvlans() 1019{ 1020 my $bridge = shift; 1021 my $brifdir = $netdir.$bridge."/brif/"; 1022 my %ifs; 1023 1024 opendir(DIR, $brifdir) or return -1; 1025 my @interfaces = readdir(DIR); 1026 return if ($#interfaces < 2); 1027 foreach my $if (@interfaces) { 1028 next if $if eq "."; 1029 next if $if eq ".."; 1030 $ifs{$if}=1; 1031 } 1032 close(DIR); 1033 1034 opendir(DIR, $netdir) or return -1; 1035 @interfaces = readdir(DIR); 1036 return 0 if ($#interfaces < 2); 1037 foreach my $if (@interfaces) { 1038 next if $if eq "."; 1039 next if $if eq ".."; 1040 next unless($if=~/^(.*)\.(\d+)$/); 1041 my $pif=$1; 1042 my $vlan=$2; 1043 next unless(defined($ifs{$pif})); 1044 tracevlan($vlan, $if, $bridge); 1045 } 1046 close(DIR); 1047} 1048 1049sub tracevlan{ 1050 my ($vlan, $interface, $bridge)=@_; 1051 1052 my $brifdir=$netdir.$interface."/brport/bridge/brif/"; 1053 1054 opendir(DIR, $brifdir) or return -1; 1055 my @interfaces = readdir(DIR); 1056 return if ($#interfaces < 2); 1057 foreach my $if (@interfaces) { 1058 next if $if eq "."; 1059 next if $if eq ".."; 1060 my $port; 1061 my $index; 1062 if($if=~/^(.*)\.(\d+)$/){ 1063 my $pif=$1; 1064 $brifdir=$netdir.$pif."/brport/bridge/brif/"; 1065 $port=hex(readfile($brifdir.$pif."/port_no", 0)); 1066 $index=readfile($netdir.$pif."/ifindex", 0); 1067 #$indexes{$bridge}{$port}=$index; 1068 #$interfaces{$bridge}{$port}=$if; 1069 $tagged{$vlan}{$port}=1; 1070 }else{ 1071 my $brid=readfile($netdir.$if."/brport/bridge/ifindex", 0); 1072 $brifdir=$netdir.$if."/brport/bridge/brif/"; 1073 $port=hex(readfile($brifdir.$if."/port_no", 0)); 1074 $port=$brid*1000+$port; #create a unique port number 1075 $index=readfile($netdir.$if."/ifindex", 0); 1076 $indexes{$bridge}{$port}=$index; 1077 $interfaces{$bridge}{$port}=$if; 1078 $tagged{$vlan}{$port}=0; 1079 } 1080 $vlans{$vlan}{$port}=1; 1081 #print "VLAN: $vlan -> $if ($port <-> $index)\n"; 1082 } 1083 close(DIR); 1084 1085 my $brid=readfile($netdir.$interface."/brport/bridge/ifindex", 0); 1086 my $fdb=$netdir.$interface."/brport/bridge/brforward"; 1087 1088 my $vbridge=$bridge."_vlan".$vlan; 1089 open(FWD, $fdb) or return -1; 1090 while(sysread(FWD, $data, 20)){ 1091 my $mac; 1092 my ($b1,$b2,$b3,$b4,$b5,$b6,$port,$local,$age,$hi)= 1093 unpack("C6 C C L C x3", $data); 1094 $mac=sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 1095 $b1,$b2,$b3,$b4,$b5,$b6); 1096 $port=$brid*1000+$port unless(defined($indexes{$bridge}{$port})); #create a unique port number 1097 $age=$age/100; 1098 #$macs{$mac}{$bridge}=$port; 1099 $macs{$mac}{$vbridge}=$port; 1100 #$ages{$mac}{$bridge}=$age; 1101 $ages{$mac}{$vbridge}=$age; 1102 #$locals{$mac}{$bridge}=FDB_STATUS_LEARNED; 1103 $locals{$mac}{$vbridge}=FDB_STATUS_LEARNED; 1104 next if ($local); 1105 #$macs{$mac}{$bridge}=$bridge; 1106 $macs{$mac}{$vbridge}=$bridge; 1107 #$locals{$mac}{$bridge}=FDB_STATUS_SELF; 1108 $locals{$mac}{$vbridge}=FDB_STATUS_SELF; 1109 } 1110 close(FWD); 1111} 1112 1113sub readfile() 1114{ 1115 my $file = shift; 1116 my $flags = shift; 1117 1118 open(FILE, $file) or print "Could not open file $file !\n"; 1119 my $value=<FILE>; 1120 chomp $value; 1121 close(FILE); 1122 1123 if ($flags & STP_PROP_HEX) { 1124 return hex($value); 1125 } 1126 1127 return $value; 1128} 1129 1130sub getportlist{ 1131 my @ports=@_; 1132 my $portlist=""; 1133 1134 @ports=sort {$a <=> $b} @ports; 1135 my $last=1; 1136 foreach my $port (@ports){ 1137 for(my $i=$last; $i<$port; $i++){ 1138 $portlist=$portlist."0"; 1139 } 1140 $portlist=$portlist."1"; 1141 $last=$port+1; 1142 } 1143 return pack('B*',$portlist); 1144} 1145 1146sub mac2oid{ 1147 my ($mac)=@_; 1148 my @octets=split(/:/,$mac); 1149 1150 $mac=""; 1151 foreach my $octet (@octets){ 1152 $mac=$mac.".".hex($octet); 1153 } 1154 return $mac; 1155} 1156 1157sub mac2hex{ 1158 my ($mac)=@_; 1159 my @decimals; 1160 my @octets=split(/:/,$mac); 1161 1162 foreach my $octet (@octets){ 1163 push @decimals, hex($octet); 1164 } 1165 return pack("CCCCCC", @decimals); 1166} 1167 1168sub shutdown { 1169 $running = 0; 1170} 1171