package Agent::BROCADE;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

#  $Name: bld21_017 $ 
#  $Id: BROCADE.pm,v 1.10 2005/03/01 18:32:29 mckenney Exp $

use strict;
use Agent::SWITCH_Parent;
use base 'Agent::SWITCH_Parent';
use Net::Telnet;
use Util;
use Tests;
use System;

# Report::CAT_BROCADE

sub isSelectable {"Brocade Silkworm"}

sub revision {'$Revision: 1.10 $'}
sub new {
  my($self) = Agent->new();

  bless ($self, 'Agent::BROCADE');
  return $self;
}
use vars qw($ERR);

sub HEALTH {
  my($agent, $new_rep) = @_;
  require Health::Brocade;
  Health::Brocade->all_logic($new_rep);
}


sub getWWN {
  my($class, $ip, $host, $TO) = @_;
  my $rc;
  $ERR = undef;
  if ($host) {
      $rc = Util::Http->getCommand($host, "Agent::BROCADE::WWN&ip=$ip&HTTP=1", $TO);
      if ($rc =~ /ERR/) {
         $ERR = $rc;
         return undef;
      } else {
         return substr($rc,4);
      }
  } else {
      return get_WWN({ip => $ip});
  }
}

sub get_WWN {
  my($q) = @_;
  my $ip = $q->{ip};
  my ($name, $wwn);
  my $DIR = System->get_home();
  my $MIBDIR = System->get_home() . "/snmp/share/snmp/mibs";
  my $renv = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 40;
  my $public = $renv->{'snmp.community'} || "public";
  my $OPT = "-v1 -c$public -r1 -t$TO -Os";

  my $mymodel = Agent::BROCADE->getModel($ip); 

  my $comm;
  if(($mymodel =~ /1200/) || ($mymodel =~ /24000/) || ($mymodel =~ /3800/) || ($mymodel =~ /3850/) ||($mymodel =~ /3900/) || ($mymodel =~ /3200/) || ($mymodel =~ /12000/) ){
     $comm = "$DIR/snmp/bin/snmpwalk $OPT -m$MIBDIR/v4/V4_0FE.mib $ip fcFeElementName";
  }
  else{
     $comm = "$DIR/snmp/bin/snmpwalk $OPT -M$MIBDIR -mall $ip fcElementName";
  }
  my($err,$id) = Util->run_command($comm, "getWWN", 2*$TO+5);

  ($name, $wwn) = split(/ *= */, $id->[0]);
  $wwn = lc($wwn);
  $wwn =~ s/hex://; 
  $wwn =~ s/[ "]//g;



  if ($q->{HTTP}) {
    if ($wwn) {
      print "\nOK $wwn";
    } else {
      print "\nERR $err";
    }
  } elsif (wantarray) {
    return ($wwn, $mymodel);
  } else {
    return $wwn;
  }
}


sub getDevStatus {
  my($class, $dev) = @_;
  my %R;
  my $renv   = System->get_renv();

  $ENV{LD_LIBRARY_PATH} = System->get_home() . "/bin/lib";

  my $public = $renv->{'snmp.community'} || "public";
  my $MIBDIR = System->get_home() . "/snmp/share/snmp/mibs";
  my $TO     = $renv->{'timeout.snmp'};

  my $OPT    = "-v1 -c$public -r1 -t$TO -M$MIBDIR -mall " . System->snmpopt();

  my $ip = $dev->{ipno};

  $ERR = $class->getStatusLinks($OPT, $dev, \%R);
  return ($ERR, \%R);
}

sub getStatusLinks {
  my($class, $OPT, $dev, $R) = @_;
  my($x, $err, $ports, $rem, $portids);
  my $DIR  = System->get_home() . "/snmp/bin";
  my $MIBDIR  = System->get_home() . "/snmp/share/snmp/mibs";
  my $renv  = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 10;
  my $public = $renv->{'snmp.community'} || "public";
  
  my $mymodel = Agent::BROCADE->getModel($dev->{ipno}); 
  if(($mymodel =~ /12000/) || ($mymodel =~ /24000/)){
     # The 12000 brocade takes longer to complete because there is more information.
     # Increase timeout by 15
     $TO = $TO + 15;
  }
 
  $OPT .= "e";

  ($err,$ports) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} swFCPortCapacity", 
                 "sanbox_version.txt", 2*$TO+5);

  my($l)  = $ports->[0];
  my(@a) = split(/ +\= */, $l);
  $R->{"port.count"} = $a[1];

  ($err,$rem) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} swNbEntry", 
                 "sanbox_version.txt", 2*$TO+5);

  my ($curr, @index_array, $mycount, $remindex, $wwnindex);
  $mycount = 1;
  $remindex = 1;
  $wwnindex = 1;
  foreach my $l (@$rem) {
     if ($l =~ /swNbMyPort.\d+ = (\d+)/) {
       $curr = $1 - 1;
       $index_array[$mycount] = $curr;
       $mycount +=  1;

     } elsif ($l =~ /swNbRemPort\.\d = (\d+)/) {
       $R->{"port.$index_array[$remindex].link_port"} = $1 - 1;
       $remindex += 1;

     } elsif ($l =~ /swNbRemPortName\.\d =  Hex: (.*)/) {
       my $wwn = lc($1);
       $wwn =~ s/ //g;
       #$R->{"port.$index_array[$wwnindex].link_wwn"} = "1000" . substr($wwn,4);
       $R->{"port.$index_array[$wwnindex].link_wwn"} = $wwn;
       $wwnindex += 1;

     }
  }


  # get WWN of devices attached to port

  # first get an array of ports and there id's
  my (@port_array);

  ($err,$portids) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} swNsPortID", 
                 "sanbox_version.txt", 2*$TO+5);

  foreach my $l (@$portids) {
      my($f, $entry, $wwn) = split(/[=\.]+/, $l);

      $wwn =~ s/Hex://;
      my($f0, $col, $zone, $port, $alpa) = split(/ +/, $wwn);
      my $realport;
      if($R->{"port.count"} > 16){
         $realport = $port;
      }else{
         #Entry now contains the port plus compatibility mode
         # only want the last digit.
         $realport = substr($port,1) ; 
      }
      $port_array[$entry] = hex($realport);

  }
  # now get attached WWN's 
  ($err,$portids) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} swNsPortName", 
                 "sanbox_version.txt", 2*$TO+5);

  foreach my $l (@$portids) {
      my($f, $entry, $wwn) = split(/[=\.]+/, $l);
      $wwn =~ s/Hex://;
      $wwn =~ s/ //g;

      if (!$R->{"port.$port_array[$entry].link_wwn"}) {
        $R->{"port.$port_array[$entry].link_wwn"} = lc($wwn);
      }

  }

  $OPT = "-v1 -c$public -t$TO -r1 -M$MIBDIR -mall " . System->snmpopt();

  foreach my $el ('Type','State','Status','Speed') {

    my($err,$rem) = Util->run_command(
                 "$DIR/snmpwalk $OPT $dev->{ipno} connUnitPort$el", 
                 "sanbox_version.txt", 2*$TO+5);

    foreach my $l (@$rem) {
      my($f1, $f2) = split(/ = /, $l);
      my $ix = rindex($f1, ".");
      my $port = substr($f1,$ix+1) - 1;
      $ix = index($f2,"(");
      my $type = $f2;
      $type = substr($f2,0,$ix) if ($ix >0);
      $R->{"port.$port." . lc($el)} = $type;
    }
  }
}

#./snmpwalk -m all  -t 30 -Os -M /opt/stade21/snmp/mibs 172.20.67.167 connUnitPortT>
#connUnitPortType.'...`i ..........'.1 = g-port(10)
#connUnitPortType.'...`i ..........'.2 = f-port(8)
#connUnitPortType.'...`i ..........'.3 = g-port(10)
#connUnitPortType.'...`i ..........'.4 = e-port(9)
#connUnitPortType.'...`i ..........'.5 = g-port(10)
#connUnitPortType.'...`i ..........'.6 = other(2)
#connUnitPortType.'...`i ..........'.7 = f-port(8)
#connUnitPortType.'...`i ..........'.8 = fl-port(7)


# 1 = nport (hba (F_Port)), 2=nlport (storage (L_Port))
# s2s = E_Port

#./snmpwalk -m all  -Ose -M /opt/ras22/snmp/mibs 
#                   172.20.67.167 public  swNsLocalTable
# swNsEntryIndex.1 = 1
# swNsPortID.1 =  Hex: 00 01 11 00
# swNsPortType.1 = 1
# swNsPortName.1 =  Hex: 21 01 00 E0 8B 23 61 F
# swNsPortSymb.3 = "SUN     SENA            1.09"
# swNsNodeName.1 =  Hex: 20 01 00 E0 8B 23 61 F9


# HBA and A5K
#./snmpwalk -m all  -Ose -M /opt/ras22/snmp/mibs 
#                   172.20.67.167 public fcFxPortNxPortName
#fcFxPortNxPortName.1.2.1 =  Hex: 21 01 00 E0 8B 23 61 F9 
#fcFxPortNxPortName.1.7.1 =  Hex: 21 00 00 E0 8B 00 B5 06 
#fcFxPortNxPortName.1.8.2 =  Hex: 50 80 02 00 00 03 25 12 
#fcFxPortNxPortName.1.8.9 =  Hex: 21 00 00 20 37 04 98 B2 
#fcFxPortNxPortName.1.8.12 =  Hex: 21 00 00 20 37 04 9A D1 
#fcFxPortNxPortName.1.8.15 =  Hex: 21 00 00 20 37 0E FA 09 
#fcFxPortNxPortName.1.8.18 =  Hex: 50 80 02 00 00 03 25 11 
#fcFxPortNxPortName.1.8.25 =  Hex: 21 00 00 20 37 04 98 06 
#fcFxPortNxPortName.1.8.26 =  Hex: 21 00 00 20 37 04 9B C0 
#fcFxPortNxPortName.1.8.27 =  Hex: 21 00 00 20 37 04 9F 7A 
#fcFxPortNxPortName.1.8.28 =  Hex: 21 00 00 20 37 04 97 6F 
#fcFxPortNxPortName.1.8.29 =  Hex: 21 00 00 20 37 04 98 26 
#fcFxPortNxPortName.1.8.30 =  Hex: 21 00 00 20 37 04 98 C6 
#fcFxPortNxPortName.1.8.31 =  Hex: 21 00 00 20 37 04 98 1A 

# Switch2Switch
#./snmpwalk -m all  -Ose -M /opt/ras22/snmp/mibs 172.20.67.167  public swNbEntry
#swNbIndex.1 = 1
#swNbMyPort.1 = 4
#swNbRemDomain.1 = 3
#swNbRemPort.1 = 5
#swNbBaudRate.1 = 16
#swNbIslState.1 = 5
#swNbIslCost.1 = 1000
#swNbRemPortName.1 =  Hex: 20 04 00 60 69 10 71 25 


# T3
#./snmpwalk -m all  -Ose -M /opt/ras22/snmp/mibs 172.20.67.164 
#                           public fcFxPortNxPortName
#fcFxPortNxPortName.1.7.125 =  Hex: 50 02 0F 23 00 00 3D 2C 


sub getStats {
  my($class, $OPT, $ip, $R, $dev) = @_;

  my $DIR  = System->get_home() . "/snmp/bin";
  my $MIBDIR  = System->get_home() . "/snmp/share/snmp/mibs";

  my $renv  = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 60;
  my $public = $renv->{'snmp.community'} || "public";

  if(($dev->{userLabel} =~ /12000/) || ($dev->{userLabel} =~ /24000/) ){
     $TO = $TO+60;
  }
 
  my($err4,$ports) = Util->run_command(
             "$DIR/snmpwalk $OPT $ip fcSwitch.sw.swFCport", 
             "sanbox_version.txt", 2*$TO+5);

  if ($err4) {
     Debug->print2("snmpwalk $ip: $err4");
     return undef;
  }

  my($l)  = $ports->[0];
  my(@a) = split(/ +\= */, $l);
  my($size) = $a[1];
  $R->{"port.count"} = $size;
  my($ERR_LIST) = ",RxTooLongs,LipOuts,RxBadEofs,RxBadOs,McastTimedOuts,LipIns,C3Discards,RxEncInFrs,RxCrcs,RxTruncs";
  my($po_index);
  my($x, $port, $name);
  for ($x=1; $x <= $#$ports; $x++) {
     if($ports->[$x] =~ /swFCPortIndex.(.+) = (.+)/){
	my $mp = $2;
	my $pi = $1;
	if($mp =~ /.+\((.+)\)/){
	   $mp = $1;
	}
	$po_index->{$pi} = $mp - 1;
     }else{
     my(@a) = split(/ +\= */, $ports->[$x]);
     $a[1] = substr($a[1],1,-1) if (substr($a[1],0,1) eq "\"");
     my($ix) = rindex($a[0], ".");
     $port = substr($a[0],$ix+1);
     $name = substr($a[0], 8);
     $ix = index($name, ".");
     $name = substr($name, 0, $ix);
     $a[1] =~ s/Counter\d\d\://;
     if (index(",AdmStatus,LinkState,PhyState,OpStatus,", ",$name,") >= 0) {
        $R->{"port.$po_index->{$port}.state.$name"} =  $a[1];

     } elsif (index($ERR_LIST, ",$name,") >= 0) {
        $R->{"port.$po_index->{$port}.error.$name"} =  $a[1];

     } else {
        $R->{"port.$po_index->{$port}.stats.$name"} =  $a[1];
     }
     }
  }
}


# snmpwalk  -O s -m all -M /opt/ras22/snmp/mibs 172.20.67.167 public swFirmwareVersion 

sub getVersion {
  my($agent, $ip) = @_;

  my $DIR  = System->get_home() . "/snmp/bin";
  my $renv  = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 10;
  my $public = $renv->{'snmp.community'} || "public";

  my $MIBDIR  = System->get_home() . "/snmp/share/snmp/mibs";
  $ENV{LD_LIBRARY_PATH} = System->get_home() . "/bin/lib";
  my $OPT  = "-v1 -c$public -r1 -t$TO -M$MIBDIR -mall " . System->snmpopt();
  my $v = ".iso.3.6.1.4.1.1588.2.1.1.1.1.6.0";

  my($err0,$version) = Util->run_command("$DIR/snmpget $OPT $ip $v", 
                      "sanbox_version.txt", 2*$TO + 5);
  if ($err0) {
     $ERR = $err0;
     return undef;
  } else {
     my ($x, $y) = split(/\s*=\s*/, "@$version");
     if (substr($y,0,1) eq "\"") {
        $y = substr($y,1,-1);
     }
     return $y;
  }
}
sub getNumPorts {
  my($agent, $ip) = @_;
 

  ##### NOTE ####################################
  # 
  # This only works for 3900 and 12000 switches.
  #
  ################################################
  my $DIR  = System->get_home() . "/snmp/bin";
  my $renv  = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 10;
  my $public = $renv->{'snmp.community'} || "public";

  my $MIBDIR  = System->get_home() . "/snmp/share/snmp/mibs";
  my $OPT  = "-v1 -c$public -r1 -t$TO -m$MIBDIR/v4/V4_0FE.mib " . System->snmpopt() . "b";
  my $v = "fcFeModuleFxPortCapacity.1";

  my($err0,$ostring) = Util->run_command("$DIR/snmpwalk $OPT $ip $v", 
                      "sanbox_version.txt", 2*$TO + 5);

  my($l)  = $ostring->[0];;
  if ($err0) {
     # Assume 32 port switch
     return 32;
  } else {
     if($l =~ /fcFeModuleFxPortCapacity.1 = .*: (\d*)/){
        return $1;
     }
  }
  # If here, assume 32
  return 32;

}

sub getModel {
  my($agent, $ip) = @_;

  my $DIR  = System->get_home() . "/snmp/bin";
  my $MIBDIR  = System->get_home() . "/snmp/share/snmp/mibs";
  my $renv  = System->get_renv();
  my $TO  = $renv->{'timeout.snmp'} || 10;
  my $public = $renv->{'snmp.community'} || "public";

  my $OPT  = "-v1 -c$public -r1 -t$TO -M$MIBDIR -mall " . System->snmpopt() . "b";

  my($err0,$version) = Util->run_command("$DIR/snmpwalk $OPT $ip connUnitRevsTable", 
                      "sanbox_version.txt", 2*$TO + 5);
  if ($err0) {
     return "Brocade";
  } 
  my $val_array;
  my $revindex = 0;
  foreach my $x (@$version) {

     if($x =~ /connUnitRevs(\w+).+\.(\d) = (.+)/){
	my $type = $1;
	my $pindex = $2;
	my $val = $3;

	$val_array->{"$type$pindex"} = $val;
	if($x =~ /Hardware ver/){
	  $revindex = $pindex;
	}
     }
  }
  if(!$revindex){
    return "Brocade";
  }

  my $model = $val_array->{"RevId$revindex"};
  $model =~ s/"//g;
  if($model =~ /(.+)\..+/){
    $model = $1;
  }

  if($model eq "1"){
     # => Brocade Silkworm 1000 family
     return "1000 Brocade";
  }

  if($model eq "2"){
     # => Brocade Silkworm 2800 (16 port 1 Gbit/sec)
     return "2800 Brocade";
  }

  if($model eq "3"){
    # => Brocade Silkworm 2400, 2100 (8 port 1 Gbit/sec)
    return "2x00 Brocade";
  }

  if($model eq "4"){
    # => Brocade Silkworm 2010, 2040, 2050 (20X0) (8 port 1 Gbit/sec)
    return "20x0 Brocade";
  }

  if($model eq "5"){
    # => Brocade Silkworm 2210, 2240, 2250 (22X0) (16 port 1 Gbit/sec)
    return "22x0 Brocade";
  }

  if($model eq "6"){
    # => Also a SilkWorm 2800 (16 port 1 Gbit/sec)
    return "2800 Brocade";
  }

  if($model eq "9"){
    # => Brocade Silkworm 3800 (16 port 1 Gbit/sec and 2 Gbit/sec)
    return "3800 Brocade";
  }

  if($model eq "10"){
    #"=> Brocade Silkworm 12000 (64/128 port 1 Gbit/sec and 2 Gbit/sec)
    return "12000 Brocade";
  }

  if($model eq "12"){
    #"=> Brocade Silkworm 3900 (32 port 1 Gbit/sec and 2 Gbit/sec)
    return "3900 Brocade";
  }

  if($model eq "16"){
    #"=> Brocade Silkworm 3200 (8 port 1 Gbit/sec and
    return "3200 Brocade";
  }

  if($model eq "21"){
     return "24000 Brocade";
  }

  if($model eq "26"){
     return "3850 Brocade";
  }

  if($model eq "27"){
    return "3250 Brocade";
  }

  return "Brocade";
}

sub INSTRUMENTATION {
  my($agent, $device) = @_;
  my(@s, %dev, $in, %info);
  my($connect_err, %C);
  my($port,  $config, $err4);
  return Report->readTest($device) if (System->get_testMode());

  my(%R);
  my($ip)    = $device->{ip};
  my(@counts, @stats, $stat, $x);
  my $DIR    = System->get_home() . "/snmp/bin";
  my $renv   = System->get_renv();
  my $TO     = $renv->{'timeout.snmp'};
  my $public = $renv->{'snmp.community'} || "public";

  my $MIBDIR = System->get_home() . "/snmp/share/snmp/mibs";
  $ENV{LD_LIBRARY_PATH} = System->get_home() . "/bin/lib";

  if(($device->{userLabel} =~ /12000/) || ($device->{userLabel}  =~ /24000/)){
     $TO = $TO + 700;
  }

  my $OPT    = "-v1 -c$public -r3 -t$TO -M$MIBDIR -mall " . System->snmpopt();
  Timelapse->startDev( $device);

  my($err0,$system);
  ($err0,$system) = Util->run_command("$DIR/snmpwalk $OPT $ip ", 
                      "sanbox_version.txt", 3*$TO+5);


  if ($err0) {
     $R{'rc.error'} = $err0;
     return \%R;

  } elsif ($#$system < 0) {
     $R{'rc.error'} = "No answer from switch at $ip";
     return \%R;

  } elsif ("@$system" =~ /Timeout:/) {
     $R{'rc.error'} = "@$system";
     return \%R;
  }

  my $mymodel = Agent::BROCADE->getModel($ip); 
  if(($mymodel =~ /12000/) || ($mymodel =~ /24000/)){
     # The 12000 brocade takes longer to complete because there is more information.
     $TO = $TO + 300;
  }

  my($err3,$swsystem) = Util->run_command("$DIR/snmpwalk $OPT $ip fcSwitch.sw.swSystem",
                       "sanbox_version.txt", 2*$TO +5);



  my($err6,$san1) = Util->run_command("$DIR/snmpwalk $OPT $ip fcFxPortNxPortName", 
                       "sanbox_version.txt", 2*$TO+5);

  my($err8,$uptime) = Util->run_command("$DIR/snmpwalk $OPT $ip sysuptime ", 
                       "sanbox_version.txt", 2*$TO+5);



  if ($err0 || $err3 || $err4 || $err6  || $err8) {
    Debug->err(SNMP => "Cannot run snmp on $ip:$err0$err3$err4$err6$err8");
    $R{'rc.error'} = "$err0$err3$err4$err6$err8";
    return \%R;
  }
# fcFxPortNxPortName.1.1.2 =  Hex: 21 00 00 E0 8B 03 09 26 

  
  foreach my $x (@$san1) {
     my(@a) = split(/ +\= */, $x);
     my(@b) = split(/\./, $a[0]);
     $port = $b[2] - 1;
     $R{"port.$port.attach.$b[3]"} =  $a[1];
  }

  foreach my $x (@$system) {
     my(@a) = split(/ +\= */, $x);
     $a[1] = substr($a[1],1,-1) if (substr($a[1],0,1) eq "\"");
     $a[0] = substr($a[0],0,-2) if (substr($a[0], -2) eq ".0");
     $a[1] =~ s/Counter\d\d\://;
     $R{"system.$a[0]"} =  $a[1];
  }

  my($sensor,  $name);
  my($max) = 0;
  my(@SENS, %CNT);
  foreach my $x (@$swsystem) {
     my(@a) = split(/ +\= */, $x);
     $a[1] = substr($a[1],1,-1) if (substr($a[1],0,1) eq "\"");
     $a[1] =~ s/Counter\d\d\://;
     if ($a[0] =~ /^swSensor/) {
        my($ix) = rindex($a[0], ".");
        $sensor = substr($a[0],$ix+1) + 0;
        $max = $sensor if ($sensor > $max);
        $name = substr($a[0], 0, $ix);
        $name = substr($name, 8);
        my $val = $a[1]; $val =~ s/\(\d+\)$//;
        if ($name eq "Type") {
            $CNT{$val}++;
            $SENS[$sensor] = "$val.$CNT{$val}";
        } elsif ($SENS[$sensor]) {
	    if (($SENS[$sensor] =~ /power-supply/) && $val =~ ("-2147483648") ) 
	    { 
	       # -2147483648 is really 0x80000000 which is okay
	       #$R{"sensor.$SENS[$sensor]." . lc($name)} = "N/A";
	       #Don't save this field since it doesn't tell the user anything
	    }
	    elsif (($SENS[$sensor] =~ /fan/) && $val =~ ("-2147483648") ) 
	    { 
	       # If the value for the fan is the -2..., it means that
	       # the fan isn't installed and this value has no meaning.
	       #$R{"sensor.$SENS[$sensor]." . lc($name)} = "N/A";

	       #Don't save this field since it doesn't tell the user anything

	    }
	    elsif (($SENS[$sensor] =~ /temperature/) && $val =~ ("-2147483648") ) 
	    { 
	       # If the value for the temperature is the -2..., it means that
	       # the temp isn't installed and this value has no meaning.
	       #$R{"sensor.$SENS[$sensor]." . lc($name)} = "N/A";

	       #Don't save this field since it doesn't tell the user anything

	    }
	    else{
               $R{"sensor.$SENS[$sensor]." . lc($name)} = $val;
	    }
        }
       
     } else {
       $a[0] = substr($a[0],0,-2) if (substr($a[0], -2) eq ".0");
       $R{"swSystem.$a[0]"} =  $a[1];
     }
  }

  $R{"sensor.count"} = $max;

  # Save system uptime
  foreach my $x (@$uptime) {
     my(@a) = split(/\(/, $x);
     my(@b) = split(/\)/, $a[1]);
     $R{"system.uptime"} =  $b[0];
  }


  
  $agent->getStats($OPT, $ip, \%R, $device);
  $agent->getStatusLinks($OPT, $device, \%R);

  if (index("|$renv->{categories}|", "|san|") >= 0 &&
            $device->isMineToMonitor() ) {
     $R{"FC_COUNTERS"} = $agent->FCfromDevice($device);
  }

  $agent->addIdentification(\%R);

  $R{"id.wwn"} = $agent->getWWN($ip);

  if($R{"swSystem.swFirmwareVersion"} =~ /v2/){
     $R{"id.switch_type"} = "1 Gig Switch";
  }else{
     $R{"id.switch_type"} = "2 Gig Switch";
  }
  Timelapse->stopDev( $device);

  $R{'rc.key'} = $R{"id.wwn"};
  return \%R;
}


sub FCfromDevice {
  my($class, $dev) = @_;
  my (%X, @R, $x);
  my $renv = System->get_renv();
  my $DIR = System->get_home() . "/snmp/bin";

  my $TO     = $renv->{'timeout.snmp'};
  my $public = $renv->{'snmp.community'} || "public";

  my $MIBDIR = System->get_home() . "/snmp/share/snmp/mibs";
  my $OPT    = "-v1 -c$public -r1 -t$TO -M$MIBDIR -mall " . System->snmpopt();
  my $ip = $dev->{ipno} || $dev->{ip};
  my ($inframes, $outframes);
  
  my $mymodel = Agent::BROCADE->getModel($ip); 
  if(($mymodel =~ /12000/) || ($mymodel =~ /24000/)){
     # The 12000 brocade takes longer to complete because there is more information.
     # Increase timeout by 15
     $TO = $TO + 15;
  }
  my $max = 8;
  my($err5,$errors) = Util->run_command(
      "$DIR/snmpwalk $OPT $ip swFCPortRxCrcs",
      "sanbox_version.txt", 2*$TO+5, {cache => 0} );
  my @CRC;
  my $port;
  for ($x=0; $x <= $#$errors; $x++) {
     next if($errors->[$x] =~ /End of MIB/);
     my(@a) = split(/ +\= */, $errors->[$x]);
     if($a[0] =~ /portNum/){
        my $ix = index($a[0], "portNum");
        $port = substr($a[0],$ix+8);
     }else{
       my (@b) = split(/\./, $a[0]);
       $port = $b[1] - 1;
     }
     $a[1] =~ s/Counter\d\d\://;
     $port = 1 if($port < 0);
     $CRC[$port] = $a[1];
     $max = $port if ($port > $max);
  }

  ($err5,$errors) = Util->run_command(
      "$DIR/snmpwalk $OPT $ip fibreChannel.fcFabric.fcFe.fcFeError", 
      "sanbox_version.txt", 2*$TO+5, {cache => 0});

  ($err5,$inframes ) = Util->run_command(
      "$DIR/snmpwalk $OPT $ip swFCPortRxFrames", "sanbox_version.txt", 2*$TO+5, {cache => 0});

  ($err5,$outframes ) = Util->run_command(
      "$DIR/snmpwalk $OPT $ip swFCPortTxFrames", "sanbox_version.txt", 2*$TO+5, {cache => 0});

  for ($x=0; $x <= $#$inframes; $x++) {
     my(@a) = split(/ +\= */, $inframes->[$x]);
     my $ix = rindex($a[0],"-");
     my $port = substr($a[0],$ix+1); 
     $a[1] =~ s/Counter\d\d\://;
     $R[$port]{Inframes} =  $a[1] + 0;
  }

  for ($x=0; $x <= $#$outframes; $x++) {
     my(@a) = split(/ +\= */, $outframes->[$x]);
     my $ix = rindex($a[0],"-");
     my $port = substr($a[0],$ix+1);
     $a[1] =~ s/Counter\d\d\://;
     $R[$port]{Outframes} =  $a[1] + 0;
  }

  

  for ($x=1; $x <= $#$errors; $x++) {
     my(@a) = split(/ +\= */, $errors->[$x]);
     my $ix = rindex($a[0],".");
     my $port = substr($a[0],$ix+1) - 1;
     $a[1] =~ s/Counter\d\d\://;
     my $a0 = substr($a[0],0,$ix);
     $a0 =~ s/\./-/g;
     $R[$port]{$a0} =  $a[1] + 0;
     
  }

  for ($x=0; $x <= $max; $x++) {
      my $key = "|$dev->{key}|port.$x|switch";
      next if (!defined($CRC[$x]));
      my $t = time;

      $X{$key} = ($R[$x]{'fcFxPortLinkFailures-1'}+0) . "\t" .
                 ($R[$x]{'fcFxPortSigLosses-1'}+0)    . "\t".
                 ($R[$x]{'fcFxPortPrimSeqProtoErrors-1'}+0) . "\t".
                 ($CRC[$x]+0) . "\t" .            #   $R[$x]{'fcFxPortInvalidCrcs-1'}  . "\t".
                 ($R[$x]{'fcFxPortSyncLosses-1'}+0)     . "\t".
                 ($R[$x]{'fcFxPortInvalidTxWords-1'}+0) . "\t" .
                 ($R[$x]{'Inframes'}+0)                 . "\t" .
                 ($R[$x]{'Outframes'}+0) ;

  }
  return {enc => {$dev->{wwn} => $dev->{name}} , data => \%X};
}

sub FRUS {
  my($class, $r, $name) = @_;
  my($v) = $r->{_value};
  my $devtype = $r->category();
  my $model = $v->{"system.sysDescr"};
  my @FRUS;
  my $st0 = $v->{"swSystem.swAdmStatus"};
  my $st1 = $v->{"swSystem.swOperStatus"};
  $st0 =~ s/\(\d+\)//;
  $st1 =~ s/\(\d+\)//;

  my $rev = $v->{"swSystem.swFirmwareVersion"};
  my $type = lc($v->{"id.device_userLabel"});

  push(@FRUS, [$name, "switch", "switch", $type, "Brocade", $model, " N/A", $rev, "$st0-$st1"]);
  return \@FRUS;

}


# fcFxPortNxPortName.1.1.2 =  Hex: 21 00 00 E0 8B 03 09 26 
# fcFxPortNxPortName.1.4.98 =  Hex: 50 80 02 00 00 08 3C B2 
# fcFxPortNxPortName.1.4.101 =  Hex: 21 00 00 20 37 45 04 E2 
# fcFxPortNxPortName.1.4.102 =  Hex: 21 00 00 20 37 45 0D 3A 
# fcFxPortNxPortName.1.4.103 =  Hex: 21 00 00 20 37 45 07 DE 

# swNsPortSymb.2 = "SUN     SENA            1.09"
# swNsPortSymb.3 = "SEAGATE ST39103FCSUN9.0G034A"

sub REPORT {
  my($class, $host, $r, $arg) = @_;

  my($out);
  my($v) = $r->{_value};

  my $last;
  $out = $class->reportHead("Brocade", $r, undef, $v->{"id.connect_errs"});

  my $port;
  $out .= <<EOF;
     <tr><td colspan=3>
       <table border=0 cellspacing=1 cellpadding=1 width=100%>
       <tr> <td align=right bgcolor=$Style::LIGHT>Name:</td>
         <td>$v->{"id.device_name"}</td>
         <td align=right bgcolor=$Style::LIGHT>WWN:</td>
         <td>$v->{"id.device_key"}</td>
       <tr> <td align=right bgcolor=$Style::LIGHT>IP:</td>
         <td>$v->{"id.device_ipno"}</td>
         <td align=right bgcolor=$Style::LIGHT>Label:</td>
         <td>$v->{"id.device_userLabel"}</td>
       <tr> <td align=right bgcolor=$Style::LIGHT>Revision:</td>
         <td>$v->{"swSystem.swFirmwareVersion"}</td>
         <td align=right bgcolor=$Style::LIGHT>Status:</td>
         <td>Adm=$v->{"swSystem.swAdmStatus"}, Oper=$v->{"swSystem.swOperStatus"}</td>
       </table>
     
     <tr bgcolor=$Style::LIGHT><th>Port</th><th>Admin State</th><th>Port State</th><th>Speed</th>
EOF
     for ($port=0; $port < $v->{"port.count"}; $port++) {
        my ($admstat, $state);
	if($v->{"port.$port.state.AdmStatus"}){
           $admstat = $v->{"port.$port.state.AdmStatus"};
           $state = $v->{"port.$port.state"};
	 }else{
	    $admstat = "Not Installed";
	    $state = "Not Installed";
	 }
	 my $speed =  $v->{"port.$port.speed"};
	 my $show_speed = "2Gb";
	 if($speed =~ /^1/){
	   $show_speed = "1Gb";
	 }

        my $bg = ($state eq "online")? "":"bgcolor=#FFFFD0";

        $out .= "<tr><td>&nbsp;$port</td><td>&nbsp;$admstat</td><td $bg>&nbsp;$state</td><td>&nbsp;$show_speed</td>";
     }
  $out .= "</table>&nbsp;
  <table border=1 cellpadding=1 cellspacing=0 width=95% bgcolor=white>";

  foreach my $el (sort keys %$v) {
     if($el =~ /id.device_telnet/){
        #skip displaying password
        next;
     }
     if($el =~ /port\./){
      next;
     }
     if($el =~ /FC_COUNTERS/){
       #skip fc counter hash table
       next;
     }
     if($el =~ /rc.key/){
        next;
     }
     my($a, $b) = split(/\./, $el);
     if ($a ne $last) {
        $out .= "<tr bgcolor=$Style::LIGHT><td colspan=2>&nbsp;<b>$a</td>\n" if ($a);
        $last = $a;
     }

     $out .= "<tr><td>&nbsp;$el<td>&nbsp;$v->{$el}</td>";
  }
  $out .= "</table>";
  return $out;

}

sub getZones {
  my($class, $DIR, $s_ip, $TO, $V, $dev) = @_;
  my($err);
  my $totzones;
  $totzones = -1;
  my $password =  System->getDevicePassword($dev, "brocade");
  my($err1,$info) = Util->run_command("$DIR/brocadezone $s_ip $password", "sanbox_status.txt", 
                     2*$TO);
  if($err1){
     $err = "$err1 in Agent::Brocade->getZones brocadezone IP ($s_ip)\n";
  }

  foreach my $l (@$info) {

     if ($l =~ /Zone Name = (.*)/) {
        my $zone_name = $1;
        $totzones++;
        $V->{"zone.hd_name.$totzones.name"} = $zone_name;
     } elsif ($l =~ /Port = (\d+)/) {
        my $po = $1;
      
        $V->{"zone.hd.$totzones.members"} .= "$po ";
     }
     elsif( $l =~ /ERROR/)
     {
        $err .= "$l " ;
     }
        
  }
  $V->{"zone.total"} = $totzones;
  return $err;

}

1;
