Perl – CatOS config via SNMP / TFTP

Below is a piece of code that I wrote a while ago when setting up a backup mechanism to automatically retrieve (and put) configuration files from (or to) Cisco Catalyst switches (running CatOS).

Usually, as a perl programmer with a new challenge, you will first do a search on CPAN and almost probably find the answer or at least a hint. But at that time I decided not to go for the Cisco::Conf module that uses telnet instead of SNMP commands and operates in writeNet mode. Today, the more recent Cisco::CopyConfig should be the module of choice, but it uses ccCopy mode and works for IOS devices only.

My example uses tftpGrp mode, a third variant, that has not yet been packed in a module.

Short explanation: Subroutine, give it your Catalyst’s hostname or IP address ($Host) and SNMP write community string ($Cty), the TFTP server’s hostname or IP address ($Server) and the filename on TFTP server ($Filename). The action ($Action) to be performed by Catalyst is given in clear text, see %Actions for allowed values. Module number ($Module) and timeout in seconds ($Timeout) are optional arguments and default to standard values if omitted. Returns result in clear text, see %Results for possible values.

Don’t forget to touch and chmod 666 file on TFTP server before transfer and remove it afterwards. Have fun!


use Convert::BER;
use Net::SNMP;

sub tftpGrp {
  my($Host,$Cty,$Server,$Filename,
     $Action,$Module,$Timeout) = @_; 
  ################################
  my %OIDs = (
   'tftpHost'   => '1.3.6.1.4.1.9.5.1.5.1.0',
   'tftpFile'   => '1.3.6.1.4.1.9.5.1.5.2.0',
   'tftpModule' => '1.3.6.1.4.1.9.5.1.5.3.0',
   'tftpAction' => '1.3.6.1.4.1.9.5.1.5.4.0',
   'tftpResult' => '1.3.6.1.4.1.9.5.1.5.5.0',
  );

  my %Actions = (
   'other'          => 1,
   'downloadConfig' => 2,
   'uploadConfig'   => 3,
   'downloadSw'     => 4,
   'uploadSw'       => 5,
   'downloadFw'     => 6,
   'uploadFw'       => 7,
  );

  my %Results = (
   1  => 'inProgress',
   2  => 'success',
   3  => 'noResponse',
   4  => 'tooManyRetries',
   5  => 'noBuffers',
   6  => 'noProcesses',
   7  => 'badChecksum',
   8  => 'badLength',
   9  => 'badFlash',
   10 => 'serverError',
   11 => 'userCanceled',
   12 => 'wrongCode',
   13 => 'fileNotFound',
   14 => 'invalidTftpHost',
   15 => 'invalidTftpModule',
   16 => 'accessViolation',
   17 => 'unknownStatus',
   18 => 'invalidStorageDevice',
   19 => 'insufficientSpaceOnStorageDevice',
   20 => 'insufficientDramSize',
   21 => 'incompatibleImage',
  );
  ################################
  $Action  = $Actions{$Action} or return(undef); 
  $Module  =  1 unless(int($Module));
  $Timeout = 10 unless(int($Timeout));

  my($Session,$Error) = Net::SNMP->session(
    -version   => 'snmpv2c',
    -hostname  => $Host,
    -community => $Cty
  );
  return($Error) unless(defined($Session));

  $Session->timeout($Timeout);

  $Session->set_request($OIDs{'tftpHost'},OCTET_STRING,$Server);
  $Session->set_request($OIDs{'tftpFile'},OCTET_STRING,$Filename);
  $Session->set_request($OIDs{'tftpModule'},INTEGER,$Module);
  $Session->set_request($OIDs{'tftpAction'},INTEGER,$Action);

  $Error = $Session->error();
  if($Error) { $Session->close(); return($Error); }

  for(my $Time = time(); time() <= $Time + $Timeout;) {
    sleep(1);
    my $Result = $Session->get_request($OIDs{'tftpResult'});
    my $Value  = $Result->{$OIDs{'tftpResult'}};
       $Error  = $Results{$Value};
    $Timeout++ if($Error eq 'inProgress');
    last       if($Error eq 'success');
  }
  $Session->close();
  return($Error);
}

Comments are closed.