Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    1 WAN, 2 "LAN"

    Scheduled Pinned Locked Moved Traffic Shaping
    28 Posts 4 Posters 15.0k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      Numbski
      last edited by

      In reality, I have 1 WAN, 1 LAN, and 1 OPT.  I have two clients in one building sharing a firewall.  One is on the LAN, the other is on OPT1.

      I create a bunch of standard rules using the shaper wizard, then go back and create a duplicate parent queue for the opt1 interface, a duplicate def queue, and a few other misc queues, then set rules to use those queues. I called the interface CL.

      When, upon attempting a reload I get errors like this:

      
      a:1:{i:1156286665;a:5:{s:2:"id";s:11:"filter_load";s:6:"notice";s:605:"There were error(s) loading the rules: /tmp/rules.debug:25: syntax error
      /tmp/rules.debug:29: queue qCLRoot has no parent
      /tmp/rules.debug:29: errors in queue definition
      /tmp/rules.debug:32: queue qCLdef has no parent
      /tmp/rules.debug:32: errors in queue definition
      /tmp/rules.debug:35: queue qCLacks has no parent
      /tmp/rules.debug:35: errors in queue definition
      /tmp/rules.debug:37: queue qVOIPDown has no parent
      /tmp/rules.debug:37: errors in queue definition
      pfctl: Syntax error in config file: pf rules not loaded The line in question reads [25]: altq on em2 hfsc bandwidth  queue { qlanRoot qCLRoot }";s:3:"url";s:0:"";s:8:"category";s:13:"Filter Reload";s:8:"priority";i:1;}}
      
      

      lines 22-25 looks like this:

      
      scrub all random-id  fragment reassemble
      altq on em0 hfsc bandwidth 8000Kb queue { qwanRoot }
      altq on em1 hfsc bandwidth 8000Kb queue { qlanRoot }
      altq on em2 hfsc bandwidth  queue { qlanRoot qCLRoot }
      
      

      So far as I can tell, this is completely wrong, and not what I entered into the UI.  It should be this on 25:

      altq on em2 hfsc bandwidth 8000Kb queue { qCLRoot }

      Once I manually fix up line 25, and manually do pfctl -f /tmp/rules.debug, it loads up fine.  I'm presuming this is an XML parser error of some sort, but if I'm misconfiguring via the UI, please let me know.  Here's the relevant section of config.xml.  Just in case it comes up, yes there is a qCLdef, and it uses qCLRoot as the parent.:

      
              <shaper><schedulertype>hfsc</schedulertype>
                      <queue><name>qwanRoot</name>
                              <associatedrule>0</associatedrule>
                              <priority>0</priority>
                              <parentqueue>on</parentqueue>
                              <bandwidth>8000</bandwidth>
                              <bandwidthtype>Kb</bandwidthtype></queue> 
                      <queue><name>qlanRoot</name>
                              <associatedrule>0</associatedrule>
                              <priority>0</priority>
                              <parentqueue>on</parentqueue>
                              <bandwidth>8000</bandwidth>
                              <bandwidthtype>Kb</bandwidthtype></queue> 
                      <queue><schedulertype><bandwidth>8000</bandwidth>
                              <bandwidthtype>Kb</bandwidthtype>
                              <priority>0</priority>
                              <name>qCLRoot</name>
                              <borrow><linkshare><linkshare3><linkshare2><linkshare1><realtime><realtime3><realtime2><realtime1><upperlimit><upperlimit3><upperlimit2><upperlimit1><parentqueue>on</parentqueue>
                              <attachtoqueue><associatedrule><rio><red><ecn><defaultqueue></defaultqueue></ecn></red></rio></associatedrule></attachtoqueue></upperlimit1></upperlimit2></upperlimit3></upperlimit></realtime1></realtime2></realtime3></realtime></linkshare1></linkshare2></linkshare3></linkshare></borrow></schedulertype></queue> 
                      <queue><name>qwandef</name>
                              <attachtoqueue>qwanRoot</attachtoqueue>
                              <associatedrule>0</associatedrule>
                              <defaultqueue>true</defaultqueue>
                              <priority>3</priority>
                              <realtime>on</realtime>
                              <realtime3>1%</realtime3>
                              <bandwidth>1</bandwidth>
                              <bandwidthtype>%</bandwidthtype>
                              <qlimit>500</qlimit></queue> 
                      <queue><name>qlandef</name>
                              <priority>3</priority>
                              <attachtoqueue>qlanRoot</attachtoqueue>
                              <associatedrule>0</associatedrule>
                              <defaultqueue>true</defaultqueue>
                              <realtime>on</realtime>
                              <realtime3>1%</realtime3>
                              <bandwidth>1</bandwidth>
                              <bandwidthtype>%</bandwidthtype>
                              <qlimit>500</qlimit></queue> 
                      <queue><schedulertype><bandwidth>1</bandwidth>
                              <bandwidthtype>%</bandwidthtype>
                              <priority>3</priority>
                              <name>qCLdef</name>
                              <borrow><linkshare><linkshare3><linkshare2><linkshare1><realtime>on</realtime>
                              <realtime3>1%</realtime3>
                              <realtime2><realtime1><upperlimit><upperlimit3><upperlimit2><upperlimit1><parentqueue><attachtoqueue>qCLRoot</attachtoqueue>
                              <associatedrule><rio><red><ecn><defaultqueue>on</defaultqueue></ecn></red></rio></associatedrule></parentqueue></upperlimit1></upperlimit2></upperlimit3></upperlimit></realtime1></realtime2></linkshare1></linkshare2></linkshare3></linkshare></borrow></schedulertype></queue> 
      
      --snip--</shaper> 
      
      1 Reply Last reply Reply Quote 0
      • N
        Numbski
        last edited by

        ???

        Any chance someone might point me in the right direction here?  I'm looking in config.inc and xmlparse.inc, and I'm just not seeing any references to altq, which is (theoretically) where I would find the rules being written to for load into pf.  The other option is that xmlparse.inc is creating a multi-dimensional array and somehow is mistakenly leaving the LAN queue in the array and simply tagging on my CL queue, thus printing it wrong.  That doesn't explain why bandwidth is being left null though. :\

        If someone can theorize where the breakage is, I am looking into it.  Just be gentle.  Perl coder here, not PHP. :D

        (EDIT: Then Numbski grew a brain and ran grep altq /etc/inc.  Low and behold….shaper.inc.  Digging into it now.  Just from a pseudo-code standpoing, I think my theory above is probably closer to the truth.  It's probably not the print statements that write the file that's at fault, but rather the parser improperly placing data into the multi-dimensional array.  We'll see.  Thoughts on this are most appreciated!)

        1 Reply Last reply Reply Quote 0
        • N
          Numbski
          last edited by

          (I feel it is worth noting here that I'm not showing a lack of gratitude.  I want to see pfSense grow, and have even donated to the project.  Every firewall I sell I am donating a portion of that money back to the pfSense project.  I just haven't sold many recently due to being tied up on a single project.)

          Upon further inspection, I think I need to head back to the drawing board.  Comparing the three root queues:

          
           <queue><name>qwanRoot</name>
                                  <associatedrule>0</associatedrule>
                                  <priority>0</priority>
                                  <parentqueue>on</parentqueue>
                                  <bandwidth>8000</bandwidth>
                                  <bandwidthtype>Kb</bandwidthtype></queue> 
                          <queue><name>qlanRoot</name>
                                  <associatedrule>0</associatedrule>
                                  <priority>0</priority>
                                  <parentqueue>on</parentqueue>
                                  <bandwidth>8000</bandwidth>
                                  <bandwidthtype>Kb</bandwidthtype></queue> 
                          <queue><schedulertype><bandwidth>8000</bandwidth>
                                  <bandwidthtype>Kb</bandwidthtype>
                                  <priority>0</priority>
                                  <name>qCLRoot</name>
                                  <borrow><linkshare><linkshare3><linkshare2><linkshare1><realtime><realtime3><realtime2><realtime1><upperlimit><upperlimit3><upperlimit2><upperlimit1><parentqueue>on</parentqueue>
                                  <attachtoqueue><associatedrule><rio><red><ecn><defaultqueue></defaultqueue></ecn></red></rio></associatedrule></attachtoqueue></upperlimit1></upperlimit2></upperlimit3></upperlimit></realtime1></realtime2></realtime3></realtime></linkshare1></linkshare2></linkshare3></linkshare></borrow></schedulertype></queue> 
          
          

          The two "default" root queues have the following values set - associatedrule=0, priority=0, parentqueue=on, bandwidth (I have them set identically for now), and bandwidthtype=Kb.

          Looking at my CL root queue, there's something doesn't line up, specifically that  associatedrule is set to null, as opposed to 0 for the other two root queues.  I'm not seeing a place in the UI to manually set associatedrule to zero.  I'm betting that somewhere in the XML parser, there's a test that states that if associatedrule is null, pass it over, but the rule-writing routine has data that it writes out since the array is partially defined.  (Speculating wildly, and out loud at that here…)

          1 Reply Last reply Reply Quote 0
          • N
            Numbski
            last edited by

            Just confirmed that associatedrule=0 makes no difference.  The XML parser still mis-writes that line.  I am still having difficulties locating where in the code I would find the routine that interprets the shaper section of the xml, and writes rules.debug.  Anyone at all able to point me in the right direction?

            1 Reply Last reply Reply Quote 0
            • N
              Numbski
              last edited by

              Just looking over the part that gets malformed in rules.debug:

              altq on em2 hfsc bandwidth queue { qlanRoot qCLRoot }

              The problem here appears to stem from values in the multi-dimensional array that is created in xmlparse.inc, and gets written back out using altq_class.inc.

              The structure appears to be $data[array1][array2].  So in this case, what I suspect is happening is after the last queue name is read in by xmlparse.inc, it is not initializing the value of $data['queue'][].  When the next one gets written in, it is appending the value of the next read.  Within my config.xml, you have the XML block for qlanRoot, then qCLRoot.  So literally, on my install, if you were to get a list of root queues, it would list them like this:

              qwanRoot
              qlanRoot
              qlanRoot qCLRoot

              I've made this coding error hundreds of times myself in an iterating loop.  The fix is usually something like this:

              [code]
              foreach(@array){
              do something to or with the current value;
              clear the current value going into the next iteration;
              }

              In perl, that "current value" gets referenced by $_ by default.  Where I get into trouble is when I would store that value out into another variable, either because $_ was already in use, or I wanted to be super clear about what value I was messing with.  $_ gets cleared and re-read in on each iteration by default, however any home-grown variables will carry into the next iteration unless I manually init it.  I see areas all over the xmlparse.inc file that isn't just storing a value to a variable, but (ie `$variable = 'newvalue'), but appending ($variable .= 'newvalue').  I'm simply not familiar enough with the codebase or the language to properly debug this.  I've spent several days on it hoping that I would be able to obviate it and either post it here or fix it and post a patch.  Nothing doing.

              Sorry guys.

              1 Reply Last reply Reply Quote 0
              • J
                jeroen234
                last edited by

                will this help ?
                $variable='none'
                $variable = 'newvalue'
                $variable is now newvalue the old variable is lost

                now the other one
                $variable='first'
                $variable .= 'last'
                $variable is now firstlast
                the dot is making that the old value is glued to the new variable

                1 Reply Last reply Reply Quote 0
                • N
                  Numbski
                  last edited by

                  Right I get that.  PHP and perl are syntatically identical in that regard.  I just can't find where it's happening.  That's where I'm looking for help.

                  (begs the question how we're getting a space between qlanRoot and qCLRoot though…perhaps it's an array and not a string, but php is being nice and returning it as a space-seperated string?)

                  1 Reply Last reply Reply Quote 0
                  • N
                    Numbski
                    last edited by

                    Just confirming that this bug remains in RC2g.  Just tested, since it appears parser changes were made.

                    1 Reply Last reply Reply Quote 0
                    • S
                      sullrich
                      last edited by

                      Traffic shaping is only supported on 2 interfaces.

                      1 Reply Last reply Reply Quote 0
                      • N
                        Numbski
                        last edited by

                        My apologies for any attempted hijackings.  Since the filter fails to reload with my current config, the upgrade scripts failed until I disabled the pfctl calls.

                        Anyhoo.  I understand that it isn't supported, I'm just trying to fix it is all. :)

                        Any chance you might point me where in the code this iteration failure might be occuring?  My first guess was /etc/inc/xmlparse.inc, but I'm not seeing at what point rules.debug gets generated. :\

                        1 Reply Last reply Reply Quote 0
                        • S
                          sullrich
                          last edited by

                          If you get it fixed, we'll glady wil commit changes.  We are taking a break from the shaper as it really kicked our ass in the last 1.5 years.

                          1 Reply Last reply Reply Quote 0
                          • N
                            Numbski
                            last edited by

                            Now you're following me. :D

                            I was only trying to find as polite a way to ask as I could where this happens:

                            Read in config.xml (in particular, the shaper config)
                            Iterate through each queue to put it into the multi-dimensional array.
                            Write out rules.debug.

                            As posted above, if I find where the iterations occur, I'll fix the bug.  I just can't find where in the code this occurs. :)

                            1 Reply Last reply Reply Quote 0
                            • N
                              Numbski
                              last edited by

                              Well, after several hours of screwing around, I have a debug script.  Please try not to laugh at my shoddy php.  It's not my language:

                              
                              require ("shaper.inc");
                              require ("xmlparse.inc");
                              /* include all configuration functions */
                              require_once("globals.inc");
                              require_once("pkg-utils.inc");
                              require_once("notices.inc");
                              require_once ("config.inc");
                              require_once("functions.inc");
                              
                              global $config;
                              $config = parse_config(true);
                              
                              if (!is_array($config['shaper']['rule'])) {
                                      print "Huh, not an array.\n";
                              }
                              else {
                                      print "An array! w00t!\n";
                              }
                              
                              foreach ($config['shaper']['queue'] as $rule){
                                              $name = $rule['name'];
                                              $bandwidth = $rule['bandwidth'];
                                              $units = $rule['bandwidthtype'];
                                              $priority = $rule['priority'];
                                              $limit = $rule['qlimit'];
                              
                                              print "Name - $name\n";
                                              print "Bandwidth - $bandwidth$units\n";
                                              print "Priority - $priority\n";
                                              print "Limit - $limit\n";
                                              print "----------------\n\n";
                              
                              }
                              ?>
                              
                              

                              I won't dump the entire output, but here's the three lines of interest:

                              Name - qwanRoot
                              Bandwidth - 8000Kb
                              Priority - 0
                              Limit -
                              –--------------

                              Name - qlanRoot
                              Bandwidth - 8000Kb
                              Priority - 0
                              Limit -

                              Name - qCLRoot
                              Bandwidth - 8000Kb
                              Priority - 0
                              Limit -

                              This leaves me with some serious head scratching, because that means the XML parser functions are correct, and that it's the rule writing routines that are really at fault.  Grr.....so several hours down the drain.  Now I get to find the routine that writes rules.debug and see if I can hack that up a bit.

                              1 Reply Last reply Reply Quote 0
                              • S
                                sullrich
                                last edited by

                                Welcome to the hell that we spent 1.0+ year on!

                                1 Reply Last reply Reply Quote 0
                                • N
                                  Numbski
                                  last edited by

                                  Thanks for the warm welcome.  ::)

                                  I think I have narrowed it down to the faulty block of code.  Unfortunately it uses an iteration structure totally different than perl.

                                  The faulty block starts on line 63 of altq_class.inc.  The iteration structure goes like this:

                                  for ($i = '1'; $i < count($rules); $i++)

                                  So we start with 1, count the number of elements in the array $rules (that really screwed me up for a while, btw.  in perl that would be @rules), and on each iteration, increment i we'll keep doing it so long as $i is less than the number of elements in $rules.

                                  Wordy, but accurate.  I think.

                                  So we go

                                  switch ($rules[$i])

                                  ???  Don't know what this does.  On the first iteration is is $rules[1].  Unless switch means take the $i element, which would be the first element of $rules?

                                  (I'm still thinking this loop through.  Saving and coming back to it…)

                                  1 Reply Last reply Reply Quote 0
                                  • S
                                    sullrich
                                    last edited by

                                    We don't use altq_class.inc!

                                    All code is in /etc/inc/filter.inc and /etc/inc/shaper.inc.

                                    1 Reply Last reply Reply Quote 0
                                    • B
                                      billm
                                      last edited by

                                      @Numbski:

                                      Thanks for the warm welcome.  ::)

                                      I think I have narrowed it down to the faulty block of code.  Unfortunately it uses an iteration structure totally different than perl.

                                      The faulty block starts on line 63 of altq_class.inc.  The iteration structure goes like this:

                                      for ($i = '1'; $i < count($rules); $i++)

                                      So we start with 1, count the number of elements in the array $rules (that really screwed me up for a while, btw.  in perl that would be @rules), and on each iteration, increment i we'll keep doing it so long as $i is less than the number of elements in $rules.

                                      Wordy, but accurate.  I think.

                                      So we go

                                      switch ($rules[$i])

                                      ???  Don't know what this does.  On the first iteration is is $rules[1].  Unless switch means take the $i element, which would be the first element of $rules?

                                      (I'm still thinking this loop through.  Saving and coming back to it…)

                                      altq_class.inc is a wild goose chase.  You really want shaper.inc and filter.inc.  FWIW, altq_class.inc isn't in releng_1 - it was removed a while back (although you may still have it in your inc directory if you have an old install that's been upgraded ).

                                      –Bill

                                      pfSense core developer
                                      blog - http://www.ucsecurity.com/
                                      twitter - billmarquette

                                      1 Reply Last reply Reply Quote 0
                                      • N
                                        Numbski
                                        last edited by

                                        Thanks for saving me there. :)

                                        What send me there is that I did a grep hfsc /etc/inc, and that was the only file that returned a match.

                                        Presuming that whatever was generating the broken line had to either assign it to a variable or print it outright, seemed like a logical place to look.

                                        I'll go ahead and delete that file so it doesn't throw me off any further…

                                        1 Reply Last reply Reply Quote 0
                                        • N
                                          Numbski
                                          last edited by

                                          Hey, he done good!  We have progress!

                                          New debug script:

                                          
                                          /* include all configuration functions */
                                          require_once("globals.inc");
                                          require_once("pkg-utils.inc");
                                          require_once("notices.inc");
                                          require_once ("xmlparse.inc");
                                          require_once ("config.inc");
                                          require_once("functions.inc");
                                          require_once ("shaper.inc");
                                          
                                          global $config;
                                          $config = parse_config(true);
                                          $altq_rules  = "";
                                          $queue_names = "";
                                          $is_first = "";
                                          
                                          if(!is_array($config['shaper']['queue'])) {
                                                  print "Huh, not an array.\n";
                                          }
                                          else {
                                                  print "An array! w00t!\n";
                                          }
                                          
                                          $ifdescrs = array('wan', 'lan');
                                          
                                          for ($j = 1; isset($config['interfaces']['opt' . $j]); $j++) {
                                                  $ifdescrs[] = "opt" . $j;
                                          }
                                          
                                          foreach ($ifdescrs as $ifdescr => $ifname) {
                                                  $queue_names = "";
                                                  $is_first = "";
                                          
                                                  print "Evaluating interface $ifname...\n";
                                          
                                                  $queue_names = find_root_queue($ifname);
                                          
                                                  print "$queue_names\n";
                                          
                                                  if($queue_names <> ""){
                                                          $altq_rules .= "altq on {$config['interfaces'][$ifname]['if']} ";
                                                          $bandwidth_arr = get_queue_bandwidth($queue_names);
                                                          $bandwidth = "bandwidth {$bandwidth_arr['bandwidth']}{$bandwidth_arr['bandwidthtype']}";
                                                          $altq_rules .= "{$config['shaper']['schedulertype']}  {$bandwidth} ";
                                                          $altq_rules .= "queue { {$queue_names} }";
                                                  }
                                                  $altq_rules .= "\n";
                                          
                                          }
                                          return $altq_rules;
                                          
                                          ?>
                                          
                                          

                                          Output is:

                                          
                                          # php test.php
                                          X-Powered-By: PHP/4.4.4
                                          Content-type: text/html
                                          
                                          An array! w00t!
                                          Evaluating interface wan...
                                          qwanRoot
                                          Evaluating interface lan...
                                          qlanRoot
                                          Evaluating interface opt1...
                                          qlanRoot qCLRoot
                                          Evaluating interface opt2...
                                          
                                          

                                          We have a winner!  So our failure is in the find_root_queue() command.  Back to digging…

                                          1 Reply Last reply Reply Quote 0
                                          • N
                                            Numbski
                                            last edited by

                                            Oops.  We get into that command, only to find another failure.

                                            This time, it is in is_subqueue_used_on_interface

                                            Debug script below:

                                            
                                            /* include all configuration functions */
                                            require_once("globals.inc");
                                            require_once("pkg-utils.inc");
                                            require_once("notices.inc");
                                            require_once ("xmlparse.inc");
                                            require_once ("config.inc");
                                            require_once("functions.inc");
                                            require_once ("shaper.inc");
                                            
                                            global $config;
                                            $config = parse_config(true);
                                            $altq_rules  = "";
                                            $queue_names = "";
                                            $is_first = "";
                                            
                                            // Begin pasting find_root_queue function below.
                                            $queue_names = "";
                                            
                                            // Add all interfaces you wish to test to this list.
                                            $interfaces = array("wan", "lan", "opt1");
                                                    foreach ($interfaces as $ifname){
                                                            $queue_names = "";
                                            
                                                    foreach ($config['shaper']['queue'] as $queue) {
                                                            $rule_interface = "";
                                                            $q = $queue;
                                            
                                                            $name = $q['name'];
                                                            $parentqueue = $q['parentqueue'];
                                            
                                                            /* if we're a parentqueue and aren't attached to another queue we're probably a root */
                                                            if ((isset($q['parentqueue']) && $q['parentqueue'] <> "") && (!isset($q['attachtoqueue']) || $q['attachtoqueue'] == "")) {
                                                                    /* Confirm that this is a valid queue for this interface */
                                                                    $rule_interface = is_subqueue_used_on_interface($q['name'], $ifname);
                                            
                                                                    if ($rule_interface == 1) {
                                                                            // Count the number of characters in $queue_names.
                                                                            if (strlen($queue_names) > 0) {
                                                                                    /* If it was greater than 0, it means that $queue_names 
                                                                                     had a value set from a previous iteration and we 
                                                                                     need to append $q['name'] this time around with a space
                                                                                    in front of it. This is due to output from 
                                                                                    is_subqueue_used_on_interface. */
                                                                                    $queue_names .= " ";
                                                                            }
                                                                            $queue_names .= $q['name'];
                                                                    }
                                                            }
                                                            $queue_number++;
                                                    }
                                                    print "$ifname: $queue_names\n\n";
                                            }
                                            return $queue_names;         
                                            
                                            ?>
                                            
                                            

                                            Outuput is below:

                                            
                                            X-Powered-By: PHP/4.4.4
                                            Content-type: text/html
                                            
                                            wan: qwanRoot
                                            
                                            lan: qlanRoot
                                            
                                            opt1: qlanRoot qCLRoot
                                            
                                            

                                            Getting closer…

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.