gypsy wrote: >Try setting classid to 0xffff and decrement rather than increment it. > >Pepper the script with >debug (print or echo) lines >error traps that exit the script on error. > >Is what you posted entire so that if I extract it from the message then >it should run? It's really tough for me to convey what I've done so far mainly because when I get in "Troubleshoot Mode" I really tend to forget what I've tried and the results of those efforts after I've done them. This is because if it doesn't work, I rule it out and go on to the next thing until I find out what the problem is. The reason I say this is because I didn't really tell you specifically what I've done to troubleshoot. Only that I found out where the problem was. For this, I apologize. So let me try to be as specific as possible. This is what the script does step by step: 1. Connect to the provisioning database (MySQL) 2. Define subroutines a. SelectSQL - Subroutine for placing all information from a sql query into a variable. b. SelectSingleSQL - Subroutine for placing one piece of information from a sql query into a variable. c. SimpleSQL - Subroutine for making a sql query d. Action - Subroutine for performing a system action and outputting any errors to an array for later use. 3. Remove existing root qdisc and add a new one (clears all information currently stored). 4. Create transit class and hash table/filter. 5. For creating the individual classes for each rate, we have it connect to our database and add a class for each rate located in that database. This is so it can be dynamic in case we need to add new classes down the road. 6. This is where the script grabs all the accounts from our database by modem. The modem table holds the rate for each customer. Then the script compares those modems to the public IPs assigned to that customer and adds the tc command to limit that IP based on the modem rate. 7. Take all the errors from any "Action" and output them. (This emails to me directly when there's a problem). 8. There's a bunch of stuff here for promotional rates we're running that is unimportant to the current problem I'm having. The error appears at step 6. For each modem in our database, it checks the IPs assigned to it. For each of those, it runs: tc filter add dev $dev protocol ip parent 1: u32 ht 2:$table: match ip dst $ip flowid 1:$classid I added a counter in there and an exit command in the "Action" subroutine so that when the script errors, it exits and shows me how many IPs tc has added before it produced an error. The number was 2045 and the error was RTNETLINK answers: File exists. As for your suggestion about the classid, I'm a bit confused as to what you mean about decrementing it. Could you be a little more specific on where this is in the script? I have attached the script in its entirety so you can see it and maybe figure out what is wrong. The only problem with running it would be connecting to the database. If you want, I can put up a mock database and you can connect to that for testing purposes. The problem with this is that I'd have to populate it with about 3000 entries for you to see the error I'm seeing. I have removed my traps and counters so you can see what the script was originally. I'll comment where the error occurs. Thank you all once again for your help and time. It is very much appreciated. #!/usr/bin/perl # # TC Helper Script: Written by Mike Davis & Adam Towarnyckyj # # Synchronizes data rates with MySQL server and applies hourly. # ### Configuration Section ### $dev = "eth1"; $tc = "/sbin/tc"; $mysql_host = "sql database"; $mysql_db = "databse"; $mysql_user = "user"; $mysql_pass = "password"; ### END Configuration Section ### use POSIX qw(strftime); # Database connect and define subroutines use DBI; $dsn = "DBI:mysql:database=$mysql_db;hostname=$mysql_host"; $dbh = DBI->connect($dsn, $mysql_user, $mysql_pass) || die "Can't connect to database: " . DBI->errstr; # Subroutine for placing all information from a sql query into a variable. sub SelectSQL { my($sql) = @_; my @MATCHES, $hash; $sth = $dbh->prepare("$sql"); $sth->execute(); while ($hash = $sth->fetchrow_hashref) { push @MATCHES, $hash; } return @MATCHES; } sub SelectSingleSQL { my($sql) = @_; my($gotit, $return, $hash); $sth = $dbh->prepare("$sql"); $sth->execute(); while ($hash = $sth->fetchrow_array) { unless ($gotit) { $return = $hash; $gotit++; } else { warn "got multiple SQL returns when exepecting only one"; } } return $return; } sub SimpleSQL { my($sql) = $_[0]; my $rows_affected; $rows_affected = $dbh->do($sql); return $rows_affected; } sub Action { my($action) = @_; # print"Performing: $action\n"; $warn=`$action 2>&1`; if ($warn) { chomp($warn); $prepare = "ERROR: $warn. Command was: $action"; # print"WHOOPS: $warn\n"; push @WARNING, $prepare; } } ### Ok, now we start having fun. Let's rebuild the tc tree. # Remove existing tree and add the root. Action("$tc qdisc del dev $dev root"); Action("$tc qdisc add dev $dev root handle 1:0 cbq bandwidth 200mbit avpkt 1000"); # Create 'transit class', tc hash tables, and hash filter Action("$tc class add dev $dev parent 1: classid 1:2 cbq bandwidth 200Mbit rate 200MBit allot 1514 weight 2Mbit prio 8 maxburst 20 avpkt 1000"); Action("$tc filter add dev $dev parent 1: handle 2: protocol ip u32 divisor 256"); Action("$tc filter add dev $dev protocol ip parent 1: u32 match ip dst 0.0.0.0/0 hashkey mask 0x000000ff at 16 link 2:"); # Create classes for rate groups @RATES = SelectSQL("SELECT dsrate FROM dsrate"); my $classid = 3; foreach $dsrate (@RATES) { $ds = $$dsrate{dsrate}; if ($ds == "0" || $ds == "1") { next; } Action("$tc class add dev eth1 parent 1: classid 1:$classid cbq bandwidth 200Mbit rate $$dsrate{dsrate}Kbit allot 1514 prio 5 maxburst 20 avpkt 1000 bounded"); $rates{$ds} = $classid; $classid++; } # Get our list of accounts @MODEMS = SelectSQL("SELECT mid, dsrate FROM modems"); # Figure out account IPs and put 'em in! foreach $modem (@MODEMS) { if ($$modem{dsrate} == "0" || $$modem{dsrate} == "1") { next; } my @COMPUTERS = SelectSQL("SELECT ipid FROM computers WHERE mid='$$modem{mid}'"); foreach $computer (@COMPUTERS) { my $ip = SelectSingleSQL("SELECT ipaddr FROM ips WHERE ipid='$$computer{ipid}'"); @octets = split(/\./,$ip); $table = $octets[3]; $table = sprintf("%X", $table); $classid = $rates{$$modem{dsrate}}; Action("$tc filter add dev $dev protocol ip parent 1: u32 ht 2:$table: match ip dst $ip flowid 1:$classid"); ### Here is where it errors after 2045 entries ### } } if (@WARNING) { print"WARNING: TCHELPER produced errors! See below:\n @WARNING\n"; } # # Cool, everyone is now limited. Let's do some up-keep on the promo rates. # # First we check accounts with a promo rate and no promo code, and fill it in. @PROMORATES = SelectSQL("SELECT dsrate,drpromo FROM dsrate WHERE drpromo !='0'"); $month=strftime "%m", localtime; $day=strftime "%d", localtime; $year=strftime "%Y", localtime; $today="$year" . "$month" . "$day"; foreach $rate (@PROMORATES) { ($exprate,$expdays) = split("-",$$rate{drpromo}); $expdate = $day + $expdays; $expmonth = $month; $expyear = $year; while ($expdate > "30") { $expmonth++; $expdate = $expdate - 30; } while ($expmonth > "12") { $expyear++; $expmonth = $expmonth - 12; } $absexpdate = "$expyear" . "$expmonth" . "$expdate"; @UNMARKED = SelectSQL("SELECT mid FROM modems WHERE dsrate='$$rate{dsrate}' AND promocode=''"); foreach $mark (@UNMARKED) { $query = SimpleSQL("UPDATE modems SET promocode='$exprate-$absexpdate' WHERE mid='$$mark{mid}'"); } } # Now we check for expired promo codes and reset their rate. @PROMOACCTS = SelectSQL("SELECT mid,promocode FROM modems WHERE promocode != ''"); foreach $acct (@PROMOACCTS) { ($exprate,$expdate) = split("-",$$acct{promocode}); if ($expdate <= $today) { $query = SimpleSQL("UPDATE modems SET dsrate='$exprate', promocode='' WHERE mid='$$acct{mid}'"); } } # Exit Nice and clean. $dbh->disconnect; exit(0); _______________________________________________ LARTC mailing list / LARTC@xxxxxxxxxxxxxxx http://mailman.ds9a.nl/mailman/listinfo/lartc HOWTO: http://lartc.org/