#!/usr/bin/perl # # Copyright (c) 2016, Peter Haag # Copyright (c) 2009, Peter Haag # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The names of its contributors must not be used to endorse or promote # products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # use strict; use warnings; my $need_tags = 1; my $in_block = 0; my $in_summary = 0; my $block_no = 0; my $line_no = 0; my @data_blocks; my %summary; my @tags; # # The cvs output format consists of one or more output blocks and one summary block. # Each output block starts with a cvs index line followed by the cvs record lines. # The index lines describes the order, how each following record is composed. # # Example: # Index line: ts,te,td,sa,da,sp,dp,pr,... # Record line: 2004-07-11 10:30:00,2004-07-11 10:30:10,10.010,172.16.1.66,192.168.170.100,1024,25,TCP,.. # # All records are in ASCII readable form. Numbers are not scaled, so each line can easly # be parsed. # # Below you find the list off all indices, defined by nfdump 1.6. The perl script # automatically parses a cvs output format and stores the record into a data stucture # which can be used for further processing. This type of representation is very flexible # as the leading cvs index line describes the following block. This makes the format also # compatible with furture versions of nfdump. # # Indices used in nfdump 1.6 # ts,te,td time records: t-start, t-end, duration # sa,da src dst address # sp,dp src, dst port # pr protocol # flg flags # fwd forwarding status # stos src tos # ipkt,ibyt input packets/bytes # opkt,obyt output packets, bytes # in,out input/output interface SNMP number # sas,das src, dst AS # smk,dmk src, dst mask # dtos dst tos # dir direction # nh,nhb nethop IP address, bgp next hop IP # svln,dvln src, dst vlan id # ismc,odmc input src, output dst MAC # idmc,osmc input dst, output src MAC # mpls1,mpls2,mpls3,mpls4,mpls5,mpls6,mpls7,mpls8,mpls9,mpls10 MPLS label 1-10 # cl,sl,al client server application latency (nfpcapd,nprobe) # ra router IP # eng router engine type/id # exid exporter SysID # # usage: ./nfdump -r ... -o csv | ./parse_csv.pl # # Start parsing the cvs blocks while (<>) { chomp; if ( $_ =~ /^$/ ) { # empty line $block_no++; $line_no = 0; $need_tags = 1; next; } if ( $_ =~ /^Summary/ ) { $in_summary = 1; $need_tags = 1; $in_block = 0; next; } if ( $need_tags ) { @tags = split /,/, $_; $need_tags = 0; $in_block = 1; next; } if ( $in_summary ) { my @vals = split /,/, $_; @summary{@tags} = @vals; } elsif ( $in_block ) { my @vals = split /,/, $_; my %a; @a{@tags} = @vals; $data_blocks[$block_no][$line_no++] = \%a; next; } } # Everything parsed # Insert your code here. # # As an example, for post processing print each record. for (my $i=0; $i<=$block_no; $i++ ) { my $lines = $data_blocks[$i]; print "Start of output block\n"; foreach my $line ( @$lines ) { print " Start : $$line{'ts'} End : $$line{'te'} Duration : $$line{'td'} Src Addr : $$line{'sa'} Dst Addr : $$line{'da'} Src Port : $$line{'sp'} Dst Port : $$line{'dp'} Protocol : $$line{'pr'} Flags : $$line{'flg'} FWD Status : $$line{'fwd'} Direction : $$line{'dir'} Src TOS : $$line{'stos'} Dst TOS : $$line{'dtos'} Input IF : $$line{'in'} Output IF : $$line{'out'} Src VLAN : $$line{'svln'} Dst VLAN : $$line{'dvln'} Next Hop IP : $$line{'nh'} BGP Next IP : $$line{'nhb'} Src AS : $$line{'sas'} Dst AS : $$line{'das'} Src Mask : $$line{'smk'} Dst Mask : $$line{'dmk'} Input Pack : $$line{'ipkt'} Output Pack : $$line{'opkt'} Input Bytes : $$line{'ibyt'} Output Bytes : $$line{'obyt'} In Src MAC : $$line{'ismc'} Out Dst MAC : $$line{'odmc'} In Dst MAC : $$line{'idmc'} Out Src MAC : $$line{'osmc'} MPLS 1 : $$line{'mpls1'} MPLS 2 : $$line{'mpls2'} MPLS 3 : $$line{'mpls3'} MPLS 4 : $$line{'mpls4'} MPLS 5 : $$line{'mpls5'} MPLS 6 : $$line{'mpls6'} MPLS 7 : $$line{'mpls7'} MPLS 8 : $$line{'mpls8'} MPLS 8 : $$line{'mpls8'} MPLS 10 : $$line{'mpls10'} Client latency : $$line{'cl'} Server latency : $$line{'sl'} Appl. latency : $$line{'al'} Router IP : $$line{'ra'} Engine type/id : $$line{'eng'} Exporter SysID : $$line{'exid'} \n"; } print "\n"; } # # Summary lines print "\nSummary:\n"; print "Number of Flows : $summary{'flows'}\n"; print "Number of Packets : $summary{'packets'}\n"; print "Number of Bytes : $summary{'bytes'}\n"; print "Average pps : $summary{'avg_pps'}\n"; print "Average bps : $summary{'avg_bps'}\n"; print "Average bpp : $summary{'avg_bpp'}\n"; # To view the raw records for debugging purpose, uncomment the lines below # use Data::Dumper; # print Dumper(@data_blocks); # print Dumper(%summary);