#!/usr/local/bin/perl -w
#See https://confluence.slac.stanford.edu/display/IEPM/IEPM+Perl+Coding+Styles
#for version of perl to use.

# /*---------------------------------------------------------------*/
# /*          STANFORD UNIVERSITY NOTICES FOR SLAC SOFTWARE        */
# /*               ON WHICH COPYRIGHT IS DISCLAIMED                */
# /*                                                               */
# /* AUTHORSHIP                                                    */
# /* This software was created by <insert names>, Stanford Linear  */
# /* Accelerator Center, Stanford University.                      */
# /*                                                               */
# /* ACKNOWLEDGEMENT OF SPONSORSHIP                                */
# /* This software was produced by the Stanford Linear Accelerator */
# /* Center, Stanford University, under Contract DE-AC03-76SFO0515 */
# /* with the Department of Energy.                                */
# /*                                                               */
# /* GOVERNMENT DISCLAIMER OF LIABILITY                            */
# /* Neither the United States nor the United States Department of */
# /* Energy, nor any of their employees, makes any warranty,       */
# /* express or implied, or assumes any legal liability or         */
# /* responsibility for the accuracy, completeness, or usefulness  */
# /* of any data, apparatus, product, or process disclosed, or     */
# /* represents that its use would not infringe privately owned    */
# /* rights.                                                       */
# /*                                                               */
# /* STANFORD DISCLAIMER OF LIABILITY                              */
# /* Stanford University makes no representations or warranties,   */
# /* express or implied, nor assumes any liability for the use of  */
# /* this software.                                                */
# /*                                                               */
# /* STANFORD DISCLAIMER OF COPYRIGHT                              */
# /* Stanford University, owner of the copyright, hereby disclaims */
# /* its copyright and all other rights in this software.  Hence,  */
# /* anyone may freely use it for any purpose without restriction. */
# /*                                                               */
# /* MAINTENANCE OF NOTICES                                        */
# /* In the interest of clarity regarding the origin and status of */
# /* this SLAC software, this and all the preceding Stanford       */
# /* University notices are to remain affixed to any copy or       */
# /* derivative of this software made or distributed by the        */
# /* recipient and are to be affixed to any copy of software made  */
# /* or distributed by the recipient that contains a copy or       */
# /* derivative of this software.                                  */
# /*                                                               */
# /* SLAC Software Notices, Set 4 (OTT.002a, 2004 FEB 03)          */
# /*---------------------------------------------------------------*/
# Copyright (c) 2006, 2007
# The Board of Trustees of
# the Leland Stanford Junior University. All Rights Reserved.

#The following code is placed at the top to ensure we are able to use perl -d
#and stop things before they call other things.
my $debug; #For cronjobs use -1, for normal execution from command line use 0,
           #for debugging information use > 0, max value = 3.
if (-t STDOUT) {$debug=0;}
else           {$debug=-1;} #script executed from cronjob

use strict;
my $version="0.1, 5/13/07";
#  ....................................................................
(my $progname = $0) =~ s'^.*/'';#strip path components, if any

my $USAGE = "Usage:\t $progname [opts]
        Opts:
        -v print this USAGE information
        -D debug_level (default=$debug)
        -f filename
Examples:
 $progname
 $progname -v -D 1

Version=$version
";

#  Please send comments and/or suggestion to Les Cottrell.
#
# ****************************************************************
# Owner(s): Les Cottrell (8/31/08).
# Revision History:
# ****************************************************************
#Get some useful variables for general use in code
umask(0002);
use Sys::Hostname;
my $ipaddr=gethostbyname(hostname());
my ($hostname,$aliases, $addrtype, $length, @addrs)=gethostbyaddr($ipaddr,2);
use Date::Calc qw(Add_Delta_Days Delta_Days Delta_DHMS);
use Date::Manip qw(ParseDate UnixDate);
use Time::Local;
my $user=scalar(getpwuid($<));

##############################################################
#Process options
require "getopts.pl";
our ($opt_f, $opt_c, $opt_v, $opt_D)=("", "", "", "");
&Getopts('f:c:D:v');

if($opt_v) {
  print "$USAGE";
  exit 1;
}
if(!$opt_f) {$opt_f="/tmp/pingall.txt";}
if($opt_D)  {$debug=$opt_D;}

my $time=localtime();

# quick script to tabulate the switch by device type and vlan

my $header = 1;
my @cols = ();
my $data = {};
my $field = {};
my $swh;

while ( <> ) {    
    my ($line,$comment)=split('#',$_);
    if(defined($comment)){
      if($comment=~/node='swh-(\w+)\./) {$swh="swh-".$1;}
    }
    if($line eq "") {next;} #Skip comment
    if ( $header eq 1 ) {#Get element names from header
        #Header format (each token followed by a tab):
        #administrator   hostname        ip_address      vlan    mac_address     user    device_type     building        room    tap     port    last_seen
        $header--;
        @cols = split /\t/, $line;
        my $i=0;
        foreach my $c ( @cols ) {
            $c =~ s/\s+//g;
            chomp( $c );
            if($debug>0) {print "$c \n";}
            # map the fields to number
            $field->{$c} = $i;
            $i++;
        }
    }
    elsif ( $header eq 0 ) {#Process data line.
        #extract the device_type, the vlan, ip_address
        my @data = split(/\t/, $line);
        #my $swh = $data[$field->{node}];#Obtained from comment at start 
        #$swh =~ s/\s+//g;
        my $vlan = $data[$field->{vlan}];
        $vlan =~ s/\s+//g;
        my $device = $data[$field->{device_type}];
        $device =~ s/\s+//g;
        # group device types
        if ( $device =~ 'SRVR'
            || $device =~ /SERV/ ) {
            $device = '!SERVER';
        } 
        elsif ( $device eq 'MAC' 
            || $device eq 'PC' 
            || $device =~ /WKS/ 
            || $device eq 'LAPTOP' 
            || $device eq 'NULL' 
            || $device eq 'LAN-MISC'
            || $device eq 'PC-MISC'
            || $device eq '10BASET'
        ) {               
            $device = '!DESKTOP';
        } 
        elsif ( $device eq 'PRINTER' || $device eq 'SCANNER') { 
            $device = '!PRINTER';
        }
        # put desktops and servers together
        $device = '!DESKTOP' if $device eq '!SERVER';
        my $ip = $data[$field->{ip_address}];
        $ip =~ s/\s+//g;
        my $ip_type = 'unknown';
        # determine if it's ifz or not
        if ( $ip eq 'NULL' ) {
            # nothin
        } elsif ( $ip =~ /^134\.79\.(19|23|27|31|35|39|43|47|51|55|59|63|67|71|75|79|83|87|91|95|111|115|131|139|147|159|163|187|223|239|243)\./ 
            ) {
            $ip_type = 'IFZ';
        } 
        elsif ( $ip =~ /^172./ ) {
            $ip_type = 'PRIVATE';
        } 
        else {
            $ip_type = 'PUBLIC';
        }
        #print "\t$ip \t $ip_type \n";
        $data->{$swh}->{$vlan}->{$device}->{$ip_type}++;
    }
}

foreach my $swh ( sort keys %$data ) {    
    next unless $swh ne '';
    next if ( $swh =~ /-nw/ 
        || $swh =~ /-bp/
        || $swh =~ /-rf/ 
        || $swh =~ /core/ 
        || $swh =~ /ssrl/ 
        || $swh =~ /farm/ 
        || $swh =~ /cgb2/ 
        || $swh =~ /cgb1bd/
        || $swh =~ /serv/ 
        || $swh =~ /bbox/ 
        || $swh =~ /rtr-reg/ 
        || $swh =~ /net/ 
        || $swh =~ /iepm/ 
        || $swh =~ /mms/ 
        || $swh =~ /-b9/
        || $swh =~ /test/
    );
    print $swh . "\n";
    my $stats = {};
    my ($slash, $hosts);
    foreach my $v ( sort {$a<=>$b} keys %{$data->{$swh}} ) {
        # remove uplinks/trunks
        next if $v =~ /,/;
        # skip uninterested vlans
        next if $v eq 517;
        foreach my $d ( sort keys %{$data->{$swh}->{$v}} ) {
            foreach my $ip ( sort keys %{$data->{$swh}->{$v}->{$d}}) {
        
                $hosts = $data->{$swh}->{$v}->{$d}->{$ip};
                my $n = int( $hosts / 64 );
        
                $slash = 26 - $n;
                $slash = '/' . $slash;
        
                $stats->{$ip}->{$slash}->{number_subnets}++;
                $stats->{$ip}->{$slash}->{number_hosts} += $hosts;
                push @{$stats->{$ip}->{$slash}->{vlans}}, $v;
        
                # determine relevant size required
                print "  vlan " . sprintf("%-4s", $v) . "  device " . sprintf("%-10s",$d) . " type " . sprintf("%-7s", $ip)  . "  # " . sprintf("%-3s",$hosts) . "  " . $slash . "\n";
            }
        }
    }
    print " would require: " . "\n";    
    foreach my $ip ( sort keys %{$stats} ) {
        foreach $slash ( sort keys %{$stats->{$ip}}) {
            my $number = $stats->{$ip}->{$slash}->{number_subnets};
            $hosts = $stats->{$ip}->{$slash}->{number_hosts};
            my @vlans = @{$stats->{$ip}->{$slash}->{vlans}};
            print "  $number x " . $slash . "  " . sprintf("%-7s",$ip) . " subnets  ($hosts hosts) [vlans @vlans]\n";
        }
    }
    print "\n";
}

