+sub bandwidth_monitor {
+ while (1) {
+ # See if a new day has started for bandwidth monitoring
+ chomp($now = `date -u +%D`);
+ if (-e $daily_stamp) {
+ chomp($stamp = `cat $daily_stamp`);
+ }
+ if (! defined($stamp) || !($stamp =~ $now)) {
+ open (STAMP, ">$daily_stamp") ||
+ die "Can't open file $daily_stamp for writing: $!\n";
+ print STAMP "$now\n";
+ close STAMP;
+ unlink ($daily_log);
+
+ # Could save the list of capped slices in a file in order to
+ # avoid re-sending mails if the daemon restarts.
+ # Also may want a list of slices that are exempt from capping.
+ if (defined(%Start)) { undef %Start; }
+ if (defined(%Now)) { undef %Now; }
+ if (defined(%Cap)) { undef %Cap; }
+
+ reset_bandwidth_caps();
+
+ syslog("info", "pl_mom: Beginning bandwidth monitoring for $now");
+ }
+
+ get_slice_names();
+ get_baseline_counts();
+ get_slice_limits();
+
+ foreach $slice ( sort (keys %Start) ) {
+ if (defined $Now{$slice}) {
+ $today = $Now{$slice} - $Start{$slice};
+ if (! (defined ($Cutoff{$slice})||$bwcap_default =~ /off/)) {
+ $Cutoff{$slice} = $cutoff_default;
+ $Maxrate{$slice} = $bwcap_default;
+ }
+ if ($debug) {
+ if ($today) {
+ $cutoff = defined($Cutoff{$slice})
+ ? $Cutoff{$slice} : "<none>";
+ print "Slice $slice sent $today bytes; ".
+ "cutoff $cutoff\n";
+ }
+ }
+ if (defined ($Cutoff{$slice}) &&
+ $today >= $Cutoff{$slice} &&
+ ! defined($Cap{$slice})) {
+ $Cap{$slice} = "sent";
+ bw_cap_mail($slice);
+ if (! $debug) {
+ log_bandwidth_cap($slice, $Maxrate{$slice});
+ cap_bandwidth($slice, $Maxrate{$slice});
+ }
+ }
+ } else {
+ # Token bucket for this slice is gone!
+ }
+ }
+
+ sleep($bwmon_sleep);
+ }
+}
+
+sub read_config_file {
+ if (-e $configfile) {
+ open (CONFIG, "<$configfile") ||
+ print "Cannot open $configfile; $!\n";
+ while (<CONFIG>) {
+ if (m/^(.*)=(.*)$/) {
+ ${$1} = $2;
+ if ($debug) {
+ print "read_config_file: $1 = ${$1}\n";
+ }
+ }
+ }
+ close CONFIG;
+ }
+}
+
+sub get_slice_names {
+ # Read slice names from /etc/passwd
+ if (defined (%Name)) { undef %Name; }
+ open (PASSWD, "</etc/passwd") ||
+ print "Cannot open /etc/passwd; $!\n";
+ while (<PASSWD>) {
+ my ($slicename, $passwd, $sliceid) = split(/:/);
+ $Name{$sliceid} = $slicename;
+ }
+ close PASSWD;
+}
+
+sub get_baseline_counts {
+ `touch $daily_log`;
+ open (BASE, "+<$daily_log") ||
+ print "Cannot open $daily_log; $!\n";
+ while (<BASE>) {
+ my ($slice, $bytecount) = split(/ /);
+ $Start{$slice} = $bytecount;
+ }
+
+ my $status = `tc -s -d qdisc show`;
+ my $sliceid = "9999";
+ @Lines = split(/\n/, $status);
+ foreach $line ( @Lines ) {
+ if ($line =~ /qdisc pfifo (.*): dev/) {
+ $sliceid = $1;
+ } else {
+ if ($line =~ /Sent (.*) bytes/) {
+ my $bytes = $1;
+ if ($sliceid != 9999) {
+ my $slice = $Name{$sliceid};
+ if ($debug && $bytes) {
+ print "Slice: $slice ($sliceid), bytes $bytes\n";
+ }
+ if (! defined($Start{$slice})) {
+ print BASE "$slice $bytes\n";
+ $Start{$slice} = $bytes;
+ }
+ $Now{$slice} = $bytes;
+ }
+ }
+ }
+ }
+ close (BASE);
+}
+
+sub get_slice_limits {
+ if (defined %Maxrate) { undef %Maxrate; }
+ if (defined %Cutoff) { undef %Cutoff; }
+ if (-e $vservers) {
+ my $result = `grep -H "^BWMAXRATE" $vservers/*.conf`;
+ chomp ($result);
+ my @Lines = split(/\n/,$result);
+ foreach $line ( @Lines ) {
+ if ($line =~ /\/([^\/]*).conf:BWMAXRATE=(.*)[Mm]bit/) {
+ $slice = $1;
+ $limit = $2."Mbit";
+ $cutoff = ($2 * 1000000 * 86400)/8;
+ } else {
+ if ($line =~ /\/([^\/]*).conf:BWMAXRATE=(.*)[Kk]bit/) {
+ $slice = $1;
+ $limit = $2."Kbit";
+ $cutoff = ($2 * 1000 * 86400)/8;
+ } else {
+ die "Could not parse line $line";
+ }
+ }
+ $Maxrate{$slice} = $limit;
+ $Cutoff{$slice} = $cutoff;
+ if ($debug) {
+ print "Slice $slice, maxrate $Maxrate{$slice}, ".
+ "cutoff $Cutoff{$slice}\n";
+ }
+ }
+ }
+}
+
+sub reset_bandwidth_caps {
+ if (-e $capfile) {
+ open(CAP, "<$capfile") or die "Cannot open $capfile: $!";
+ while (<CAP>) {
+ chomp();
+ ($slicename, $oldcap) = split(/ /);
+ syslog("info", "pl_mom: Restoring bandwidth cap of $oldcap ".
+ "to $slicename");
+ cap_bandwidth ($slicename, $oldcap);
+ }
+ close CAP;
+ unlink($capfile);
+ }
+}
+
+sub log_bandwidth_cap {
+ ($slicename, $cap) = @_;
+ syslog("warning", "pl_mom: Capping bandwidth of slice ".
+ "$slicename at $cap until midnight GMT.");
+ # Save current cap to $capfile
+ system("echo $slicename `bwlimit getcap $slicename` >> $capfile");
+}
+
+sub send_mail {
+ # Arg 0: recipient addresses, comma-separated string
+ # Arg 1: subject line
+ # Arg 2: body of message
+ my $to = "To: $_[0]\n";
+ my $from = "From: $from_addr\n";
+ my $subject = "Subject: $_[1]\n";
+ my $msg = $_[2];