steph007 has asked for the wisdom of the Perl Monks concerning the following question:

Hi There, I hope everyone is doing fine. First off , my perl is really really rusty so please don't laugh :)

Anyway , I've been tinkering on a tool to grab mac addresses with SNMP from Wireless CPE equipment on our network which I then need to write into a Mysql database. Now grabbing the data and writing it back is no issue ... well , that's if I can past understanding on how to read the information Data dumper is returning.

The original code came from a script called snmpwalk.pl which I downloaded from Cpan and then modified it to my needs. Right now it's just passing IP addresses from an array , does an snmpwalk based on a specific IOD and then passes the #hash to Datadumper for processing. Well , that's what I think happens at least :) Now this is where I get stuck , I have no idea how to properly read the processed information so I can write it back line for line into a Mysql DB.

Here's the code.

<------------code---------------->

#!/usr/bin/perl use Getopt::Std; use DBI; use Net::SNMP::Util qw(:para); use Net::SNMP::Util::OID qw(*); my @SMhosts = ('10.4.20.21', '10.4.23.218', '10.4.24.20', '10.4.25.33' +); # ---------- Data::Dumper setting ---------- # put output into hands of Data::Dumper :-) use Data::Dumper; use Storable qw(lock_nstore); foreach $unitIP (@SMhosts) { local($a,$b); $Data::Dumper::Indent = 1; $Data::Dumper::Terse = 1; $Data::Dumper::Purity = 1; $Data::Dumper::Sortkeys = sub { [ sort { # if keys are numbers, then do numerical sort return ($a =~ /^\d+$/)? ($a <=> $b): ($a cmp $b); } keys %{$_[0]} ] }; my %snmp = (); $snmp{"-version"} = "2c"; $snmp{"-community"} = "g_wireless"; $snmp{"-timeout"} = "2"; # ---------- kick function ---------- my $func = $opt{P}? 'snmpparawalk': 'snmpwalk'; my ( $result, $error ); { no strict; ( $result, $error ) = &$func( hosts => "$unitIP", oids => '1.3.6.1.4.1.161.19.3.3.4.1.1', snmp => \%snmp ); die "[ERROR] $error\n" unless defined $result; } # ---------- output result ---------- print Dumper($result); }

<//-----------------code-------------->

<-----------------results------------->

So basically the first value is the IP address of the CPE equipment followed by the Mac addresses contained in the units bridge table. This value varies on the amount of network devices connected to the LAN port of the CPE equipment. Normally , this will only be three if the customer plugged the CPE equipment directly into their routers but more values van appear if the equipment is plugged into a switch for instance. So basically what I want to do is to write each value as a separate row into Mysql but how do I extract each Mac address from the hash ?
[root@cms3 scripts]# ./snmpwalk.pl { '10.4.20.21' => { #IP Address from CPE equipment. '1' => '0x0a003edd8706', #Bridge table entry #1 '2' => '0x1a003edd8706', #Bridge table entry #2 '3' => '0xc03f0eddfb3b' #Bridge table entry #3 } } { '10.4.23.218' => { '1' => '0x0a003ea2643e', '2' => '0x1a003ea2643e', '3' => '0x000c428b8e11' } } { '10.4.24.20' => { '1' => '0x0a003e67a706', '2' => '0x1a003e67a706', '3' => '0x200cc8136ef9' } } { '10.4.25.33' => { '1' => '0x0a003eb1b2fc', '2' => '0x1a003eb1b2fc', '3' => '0xd850e6bd6330', '4' => '0x023d9d690d52', '5' => '0xec2280985442', '6' => '0x406186c1ef32', '7' => '0x0024219b0d6b', '8' => '0x00237d7cd808', '9' => '0x00272201b896', '10' => '0xf8e903e44b30', '11' => '0x52f5febdca85', '12' => '0xbe95360a4d5c', '13' => '0xac9e17b6007c', '14' => '0x000b7483457d', '15' => '0xaa069206530b', '16' => '0x000c2955956e', '17' => '0x54bef72d8cc2', '18' => '0x0000859f7d3f', '19' => '0x406186c2e658', '20' => '0x02759adcc739' } }

Replies are listed 'Best First'.
Re: Data::Dumper / write output into Mysql
by hippo (Archbishop) on Oct 06, 2015 at 19:58 UTC

    If you really just want to extract each MAC address from the hashref, this should do it:

    use strict; use warnings; my $result = { '10.4.20.21' => { #IP Address from CPE equipment. '1' => '0x0a003edd8706', #Bridge table entry #1 '2' => '0x1a003edd8706', #Bridge table entry #2 '3' => '0xc03f0eddfb3b' #Bridge table entry #3 } }; for my $mac (values %{(values %$result)[0]}) { print "Mac addr: $mac\n"; }

    Depending on your use case you may need more than this but hopefully it points you in the right direction.

      Wow , thanks hippo. This is exactly what I needed :)
      Hi hippo, The code you've helped me with works pretty well but if I understand the error correctly it seems like when the device isn't answering in time passing a value back to the script I'm getting the following error. Can't use an undefined value as a HASH reference at ./smwalker.pl line 152. ### This is basically Line 152
      for my $mac (values %{(values %$result)[0]}) { print "Mac addr: $mac\n"; }
      How do I deal with this ? Thanks in advance,

        On a modern enough perl you can use the defined-or operator // to use an empty hashref instead. eg:

        use strict; use warnings; my $result = { '10.4.20.21' => undef }; for my $mac (values %{(values %$result)[0] // {}}) { print "Mac addr: $mac\n"; }

        Of course, if your entire $result is undef then you could easily check for this separately before even hitting the for loop.

Re: Data::Dumper / write output into Mysql
by GotToBTru (Prior) on Oct 06, 2015 at 20:05 UTC

    $result appears to be an array of hashes of hashes. See References quick reference for the syntax for following the references. I will typically use the debugger as an interactive way to test the syntax to use complex structures.

    Dum Spiro Spero