Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

How to include a variable in output for derived subnets

by stroke (Acolyte)
on Jun 22, 2013 at 14:42 UTC ( #1040273=perlquestion: print w/replies, xml ) Need Help??
stroke has asked for the wisdom of the Perl Monks concerning the following question:

First post! I have inherited a script which is working fine, but I now need to include another variable in the output the script is producing. My Perl ability is pretty basic and my main problem is understanding what some of the existing code does in order to be able to modify it to do what I need - I believe the relevant code is below

# Process a line and split out the data into variables my $function = sub { my ($arr) = @_; my ( $ipaddress, $prefix, $ripe, $interface, $device, $location, $comment ) = @$arr; s/^\s+|\s+$//g for ( $ipaddress, $prefix, $interface, $device, $location, $comment ); if ( is_ipv4($ipaddress) ) { store_subnet( $ipaddress, $prefix ) if $prefix;
# Produce IP subnets from the list of IPs sub store_subnet { my ( $ip, $len ) = @_; my $ipn = unpack "N", Socket::inet_aton $ip; $len =~ s/^\///; my $maskn = 0xFFFFFFFF << ( 32 - $len ); $ipn = $ipn & $maskn; $ip = Socket::inet_ntoa pack "N", $ipn; $subnets{"$ip,$len"} = { ipn => $ipn, maskn => $maskn }; }
# Print it out print "subnet,prefix\n"; print "$_\n" for sort { $subnets{$a}{ipn} <=> $subnets{$b}{ipn} } keys %subnets;

So, what does the script currently do - it takes an excel spreadsheet which contains IP address allocations and generates a CSV file with two outputs types, (i) All the IP address allocations, with the output using the headers: "ipaddress,prefix,interface,device_name,location,comment"; (ii) A list of subnets, derived from the IP addresses, output using the headers: "subnet,prefix".

What do I want it now to do? Include a subnet name in the subnet list output, so effectively: "subnet,prefix,name".

My thought was to grab the $comment value from the IPs and use one of these to populate the subnet name field. As there are typically multiple IPs in a subnet, I was thinking just grab the first comment that is populated and use that (not all IPs have the comment field populated). My difficulty is I don't really understand well enough the code that takes the individual IP addresses and then derives the IP subnet address for these IPs - I know it's the second code snippet above - perhaps something like below (but I know this is not checking if wev've already grabbed a defined $comment?):

sub store_subnet { my ( $ip, $len, $comment ) = @_; my $ipn = unpack "N", Socket::inet_aton $ip; $len =~ s/^\///; my $maskn = 0xFFFFFFFF << ( 32 - $len ); $ipn = $ipn & $maskn; $ip = Socket::inet_ntoa pack "N", $ipn; $subnets{"$ip,$len,$comment"} = { ipn => $ipn, maskn => $maskn, na +me => $comment }; }

I think its straight forward to carry the $comment field into the store_subnet subroutine for each IP:

store_subnet( $ipaddress, $prefix, $comment ) if $prefix;

But I'm not sure how to use the comment in the store_subnet subroutine, and effectivley assign the first populated $comment to the derived subnet address

Then, to print it out I think it's a small tweak to jsut add the "name" header:

print "subnet,prefix,name\n"; print "$_\n" for sort { $subnets{$a}{ipn} <=> $subnets{$b}{ipn} } keys %subnets;

Apologies for the ramblings - appreciate any guidance offered to give me the desired outcome for this script and also improve my Perl ability!

Replies are listed 'Best First'.
Re: How to include a variable in output for derived subnets
by poj (Monsignor) on Jun 22, 2013 at 17:16 UTC
    "My difficulty is I don't really understand well enough the code.."

    Perhaps this demo program will help you

    use strict; use Socket; my $len = '/29'; print "IP IPN Mask Subnet\n"; for my $i (1...31){ print_subnet('192.168.1.'.$i ,$len); } sub print_subnet { my ( $ip, $len ) = @_; my $ipn = unpack "N", Socket::inet_aton $ip; $len =~ s/^\///; my $maskn = 0xFFFFFFFF << ( 32 - $len ); my $subnet_ipn = $ipn & $maskn; my $subnet_ip = Socket::inet_ntoa pack "N", $subnet_ipn; printf "%-20s %s %x %s\n","$ip/$len",$ipn,$maskn,$subnet_ip; }
    It should produce a table like this. Change len values to see effect.
    IP IPN Mask Subnet 3232235777 3fffffffc 3232235778 3fffffffc 3232235779 3fffffffc 3232235780 3fffffffc 3232235781 3fffffffc 3232235782 3fffffffc 3232235783 3fffffffc 3232235784 3fffffffc 3232235785 3fffffffc etc

    You should be able to add the first comment like this

    $subnets{"$ip,$len"}{ipn} = $ipn; $subnets{"$ip,$len"}{maskn} = $maskn; if ( $subnets{"$ip,$len"}{'comment'} eq '' ){ $subnets{"$ip,$len"}{'comment'} = $comment; }

    Note : If you did this the comment would be erased by a later blank record

    $subnets{"$ip,$len"} = { ipn => $ipn, maskn => $maskn };

    To print it out use this

    print "subnet,prefix,name\n"; print "$_,$subnet{$_}{'comment'}\n" for sort { $subnets{$a}{ipn} <=> $subnets{$b}{ipn} };

      Hi poj,

      Thanks - that pretty much did the trick. I had to tweak the print code block a little as I got a compilation error, but it works a treat. Appreciate your assistance.

      As is the way - this has thrown up the next thing to fix - i found some subnet definitions don't end up with a name (the IPs have no comment), I guess I can iterate over the subnets hash and substitute any undef comments with a value. Initially, I did a find/replace in the output CSV file, but it would be nice to resolve it in the code. I'll have a look into this.

      The demo program is really useful, thanks. I need to have a proper look at it, but my initial guess as to how the original code is working out the subnets is that rather than doing any de-duplication of subets or similar, it is just populating a subnet address and prefix into the hash and if the same one already exists, it just get overwritten.

      Thanks again, appreciate your help.

Re: How to include a variable in output for derived subnets
by AnomalousMonk (Chancellor) on Jun 22, 2013 at 21:08 UTC
    ... someone just handed you this [freely downloadable] book and said "Fix this code by Friday."

    Modern Perl by chromatic.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1040273]
Approved by Happy-the-monk
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2018-04-20 00:23 GMT
Find Nodes?
    Voting Booth?