#!/usr/bin/perl # # icmpcharger - ICMP driver trickle charger. # # This trickle charges the ICMP driver by sending a series of ICMP packets # to localhost at regular intervals. This program autodetects the hardware # type and uses appropriate values for the interval based on the wattage of # each packet. This script can be incorporated into the system startup # process as a daemon. # # The batteries in the kernel's ICMP driver can become depleted, a common # problem that causes high latency or dropped packets for any ICMP type. # RFC792 fails to specify an ICMP message for battery status, leaving # such problems difficult to identify or diagnose. This script serves as # a precaution against ICMP driver failure. # # This program also improves the performance of the ICMP driver by "priming" # the L1, L2 and TLB caches with ICMP driver entries. # # 01-Nov-2004 ver 1.00 # # USAGE: icmpcharger & # # COPYRIGHT: Copyright (c) 2004 Brendan Gregg. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # (http://www.gnu.org/copyleft/gpl.html) # # 22-Sep-2004 Brendan Gregg Created this. $RECHARGE = 1; # battery recharge percent per day $LOOPBACK = 100; # speed of loopback interface, Mbps $ENV{PATH} = "/usr/bin:/usr/sbin:/bin"; # # Determine ICMP Wattage and Power # # Fetch the server voltage, $country = $ENV{TZ}; $country =~ s:/.*::; if ($country eq "New Zealand") { $voltage = 240; } elsif ($country eq "Australia") { $voltage = 240; } elsif ($country eq "UK") { $voltage = 240; } elsif ($country eq "Germany") { $voltage = 230; } elsif ($country eq "France") { $voltage = 230; } elsif ($country eq "Russia") { $voltage = 220; } elsif ($country eq "Canada") { $voltage = 120; } elsif ($country eq "US") { $voltage = 120; } else { $voltage = 230; } # default # Fetch the current per ICMP packet, @ICMP_headers = (); &find("/usr/include",'icmp.*\.h$',\@ICMP_headers); foreach $header (@ICMP_headers) { if (open(HEADER,"$header")) { while (chomp($line =
)) { if ($line =~ /^#define ICMP_MILLIAMPS\s+(\S*)/) { $icmp_mAh = $1; } } close HEADER; } } $icmp_mAh = 30 if $icmp_mAh eq ""; # default # Calculate duration of an ICMP packet, $lo_speed = $LOOPBACK * 1024 * 1024; $packet_size = 56 * 8; $duration = $packet_size / $lo_speed; # Calculate wattage, $current = $icmp_mAh / 1000; $watts = $current * $voltage; $power = ($watts / 3600) * $duration; # # Determine Interval # $batt_mAh = 10; $num = (((($batt_mAh/1000) * $voltage) / 3600) * ($RECHARGE/100)) / $power; $rate = (24 * 60 * 60) / $num; $rate = sprintf("%.0f",$rate); # # Main Program # print "ICMP trickle charger: once per $rate secs...\n"; while (1) { system("ping localhost > /dev/null 2>&1"); sleep($rate); } # # Subroutines # # find - find pathnames that match a given RE. # sub find { my $top = shift; # top level directory my $search = shift; # search term my $parray = shift; # pointer to results array my $path; chdir "$top"; my @Paths = <*>; foreach $path (@Paths) { if (-f $path && $path =~ /$search/) { ### Save Match push(@{$parray},"$top/$path"); next; } if (-d $path && ! -l $path) { ### Recurse &find("$top/$path",$search,$parray); } } chdir ".."; }