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


Greetings,

I have been trying to write a program to graph live traffic on a network interface. Tk::Graph has been very helpful to create live graphs.

The important problem, which I am not able to get through or find any good help is counting all incoming packets at a specified regular interval.

I have used Net::Pcap and Time::HiRes to write the following program to count interface traffic in 0.5 sec intervals of time.

#!/usr/bin/perl -w use strict; use English; use Net::Pcap; use Time::HiRes qw (setitimer time ITIMER_REAL); my($dev, $pcap_t, $err); $dev = Net::Pcap::lookupdev(\$err); $pcap_t = Net::Pcap::open_live($dev, 1500, 1, 0, \$err); my $count = 0; sub process_pkt { my ( $user_data, $hdr, $pkt ) = @_; $count++; $SIG{ALRM} = sub { print time, " $count\n"; $count = 0 }; setitimer(ITIMER_REAL, 0.5, 0.5); } Net::Pcap::loop( $pcap_t, 0, \&process_pkt, "argument"); Net::Pcap::close($pcap_t);

Perl 5.8 installed on my linux is not configured with threads enabled. The output, as shown below, is generated at irregular intervals of time.

1069646988.25076 3
1069647025.00529 2
1069647031.59172 121
1069647033.06818 7
1069647037.78875 66

Any help or pointers towards a good solution will be greatly appreciated.

Thanks,
Prakash.

Replies are listed 'Best First'.
Re: IP Packet count at regular intervals of time
by pg (Canon) on Nov 24, 2003 at 05:14 UTC

    As you said you are using Tk, why not give "after" a try. It allows you to sepcify ms, so 0.5 second is not a problem. For document, go "Tk", then "after".

    my Re: setting up non-gui callbacks in Perl/Tk provides one example of using "after". It appears as "repeat", which is just a different face of "after".

      Thanks for your reference. I have just checked your program. Even with 10 ms intervals, it had a very smooth and great interface. I will read the documentation for Tk to use "after" or "repeat" function. Tk::Graph was very convenient, even thought I never written any code in Tk before.

      Thanks again for your help

Re: IP Packet count at regular intervals of time
by sgifford (Prior) on Nov 24, 2003 at 05:29 UTC
    My version of Time::HiRes doesn't have setitimer, but I get fairly precise results with alarm:
    #!/usr/bin/perl -w use strict; use Time::HiRes qw (alarm time); $SIG{ALRM} = sub { printf "%16.5f\n",time; alarm(0.5); }; alarm(0.5); while(1) { select(undef,undef,undef,1); }
    produces
    1069651689.38722
    1069651689.88720
    1069651690.38720
    1069651690.88721
    1069651691.38721
    

    If you can't alarms at precise times, you can try to make up for it by printing packets/second, which should be the same even if the alarms are off by a little bit. You may also find that using 1-second intervals works better, since that's the traditional interface provided by alarm, but I'm not sure.

    This is on RedHat 7.2, kernel 2.4.20, perl 5.6.1, Time::HiRes 1.20.

      Your example on my system also produced similar results. But, using "alarm" function in my packet count program as shown below, had similar random results.

      #!/usr/bin/perl -w use strict; use English; use Net::Pcap; use Time::HiRes qw (alarm time ); my($dev, $pcap_t, $err); $dev = Net::Pcap::lookupdev(\$err); $pcap_t = Net::Pcap::open_live($dev, 1500, 1, 0, \$err); my $count = 0; sub process_pkt { my ( $user_data, $hdr, $pkt ) = @_; $count++; $SIG{ALRM} = sub { printf ("%16.5f %d\n", time, $count); $count = +0 }; # setitimer(ITIMER_REAL, 0.5, 0.5); alarm(0.5); } Net::Pcap::loop( $pcap_t, 0, \&process_pkt, "argument"); Net::Pcap::close($pcap_t);


      1069653942.70856 6
      1069653948.50819 69
      1069653949.46479 2
      1069653952.55703 4
      1069654021.47634 6
      1069654026.47576 4
      1069654147.79127 2
      1069654173.53735 6
      1069654174.43908 2

      probably, both packet capturing and alarming are too much for perl, to do it precisely the way we want.

      Can you please elaborate on "printing packets/second". Net::Pcap doesn't seem to have any function that would capture packets in regular intervals of time. Any help about how I can get "no of packets/second" will be very helpful.

      Thanks,
      prakash.

        $now=time; $packets_sec = $packets / ($now - $lasttime); $lasttime=$now;
        is what I was thinking of. It just helps make up for an irregular timer a little bit, as if the timer took longer, there will be more packets and the elapsed time will be longer, balancing things out somewhat.

        Those are really irregular. I wonder if the timer is only going off when packets are received?

        If there's some kind of bad interaction between the alarms and the packet capturing (for example, Net::Pcap; is setting its own alarms), one approach would be to split up the packet code and the monitoring code into two processes. The packet sniffing code would just listen for packets, and whenever it found one print something to its standard out. Meanwhile, the monitoring code would count the number of times the packets sniffer printed, and when the alarm went off would print the result. That would split the alarm code and packet code into two seperate processes, so they can't interfere with each other.

        Still, that sounds a bit elaborate. Perhaps somebody who knows Net::Pcap better than I do can give you better advice.

      sgifford, I don't think the problem is Time::HiRes.

      The real issue here is that, Tk affects how events get handled. In a similar context, I noticed in the past that, when you use sleep function inside Tk program, sleep just functions as a drunk person.

      The benefit to utilize Tk after is to give Tk the centralized control of periodical events.

Re: IP Packet count at regular intervals of time
by nite_man (Deacon) on Nov 24, 2003 at 08:36 UTC

    If I understand clearly you need to capture packets in the specified period. In this case, you can use module Net::PcapUtils, for example:

    #!/usr/bin/perl -w use strict; use warnings; use Net::PcapUtils; my $pk_descr = Net::PcapUtils::open(FILTER => 'ip'); my $period = 1; my $now = time; my $till = $now + (60 * $period); my ($packet, %header); while (($now = time) < $till) { ($packet, %header) = Net::PcapUtils::next($pk_descr); print "Got packet: $packet !!!"; }

    Hope it helped.

    -- Michael Stepanov