.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgment:
* "This product includes software developed by the pfSense Project
* for use in the pfSense® software distribution. (http://www.pfsense.org/).
*
* 4. The names "pfSense" and "pfSense Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* coreteam@pfsense.org.
*
* 5. Products derived from this software may not be called "pfSense"
* nor may "pfSense" appear in their names without prior written
* permission of the Electric Sheep Fencing, LLC.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
*
* "This product includes software developed by the pfSense Project
* for use in the pfSense software distribution (http://www.pfsense.org/).
*
* THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: needs some reducing on include. */
/* include all configuration functions. */
require_once("globals.inc");
require_once("functions.inc");
require_once("util.inc");
require_once("notices.inc");
/*
* I admit :) this is derived from xmlparse.inc StartElement()
*/
function &get_reference_to_me_in_config(&$mypath) {
global $config;
$ptr =& $config['shaper'];
foreach ($mypath as $indeks) {
$ptr =& $ptr['queue'][$indeks];
}
return $ptr;
}
function unset_object_by_reference(&$mypath) {
global $config;
$ptr =& $config['shaper'];
for ($i = 0; $i < count($mypath) - 1; $i++) {
$ptr =& $ptr['queue'][$mypath[$i]];
}
unset($ptr['queue'][$mypath[$i]]);
}
function &get_dn_reference_to_me_in_config(&$mypath) {
global $config;
$ptr =& $config['dnshaper'];
foreach ($mypath as $indeks) {
$ptr =& $ptr['queue'][$indeks];
}
return $ptr;
}
function unset_dn_object_by_reference(&$mypath) {
global $config;
$ptr =& $config['dnshaper'];
for ($i = 0; $i < count($mypath) - 1; $i++) {
$ptr =& $ptr['queue'][$mypath[$i]];
}
unset($ptr['queue'][$mypath[$i]]);
}
function clean_child_queues($type, $mypath) {
$ref = &get_reference_to_me_in_config($mypath);
switch ($type) {
case 'HFSC':
if (isset($ref['borrow'])) {
unset($ref['borrow']);
}
if (isset($ref['hogs'])) {
unset($ref['hogs']);
}
if (isset($ref['buckets'])) {
unset($ref['buckets']);
}
break;
case 'PRIQ':
if (isset($ref['borrow'])) {
unset($ref['borrow']);
}
if (isset($ref['bandwidth'])) {
unset($ref['bandwidth']);
}
if (isset($ref['bandwidthtype'])) {
unset($ref['bandwidthtype']);
}
/* fall through */
case 'FAIRQ':
if (isset($ref['borrow'])) {
unset($ref['borrow']);
}
/* fall through */
case 'CBQ':
if (isset($ref['realtime'])) {
unset($ref['realtime']);
}
if (isset($ref['realtime1'])) {
unset($ref['realtime1']);
}
if (isset($ref['realtime2'])) {
unset($ref['realtime2']);
}
if (isset($ref['realtime3'])) {
unset($ref['realtime3']);
}
if (isset($ref['upperlimit'])) {
unset($ref['upperlimit']);
}
if (isset($ref['upperlimit1'])) {
unset($ref['upperlimit1']);
}
if (isset($ref['upperlimit2'])) {
unset($ref['upperlimit2']);
}
if (isset($ref['upperlimit3'])) {
unset($ref['upperlimit3']);
}
if (isset($ref['linkshare'])) {
unset($ref['linkshare']);
}
if (isset($ref['linkshare1'])) {
unset($ref['linkshare1']);
}
if (isset($ref['linkshare2'])) {
unset($ref['linkshare2']);
}
if (isset($ref['linkshare3'])) {
unset($ref['linkshare3']);
}
if (isset($ref['hogs'])) {
unset($ref['hogs']);
}
if (isset($ref['buckets'])) {
unset($ref['buckets']);
}
break;
}
}
function get_bandwidthtype_scale($type) {
switch ($type) {
case "Gb":
$factor = 1024 * 1024 * 1024;
break;
case "Mb":
$factor = 1024 * 1024;
break;
case "Kb":
$factor = 1024;
break;
case "b":
default:
$factor = 1;
break;
}
return intval($factor);
}
function get_bandwidth($bw, $scale, $obj) {
$pattern= "/(b|Kb|Mb|Gb|%)/";
if (!preg_match($pattern, $scale, $match))
return 0;
switch ($match[1]) {
case '%':
$objbw = ($bw / 100) * get_queue_bandwidth($obj);
break;
default:
$objbw = $bw * get_bandwidthtype_scale($scale);
break;
}
return floatval($objbw);
}
/*
* XXX - unused
*
function get_hfsc_bandwidth($object, $bw) {
$pattern= "/[0-9]+/";
if (preg_match($pattern, $bw, $match)) {
$bw_1 = $match[1];
} else {
return 0;
}
$pattern= "/(b|Kb|Mb|Gb|%)/";
if (preg_match($pattern, $bw, $match)) {
switch ($match[1]) {
case '%':
$bw_1 = ($bw_1 / 100) * get_interface_bandwidth($object);
break;
default:
$bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
break;
}
return floatval($bw_1);
} else {
return 0;
}
}
*/
function get_queue_bandwidth($obj) {
$bw = $obj->GetBandwidth();
$scale = $obj->GetBwscale();
$pattern= "/(b|Kb|Mb|Gb|%)/";
if (!preg_match($pattern, $scale, $match))
return 0;
switch ($match[1]) {
case '%':
$objbw = ($bw / 100) * get_queue_bandwidth($obj->GetParent());
break;
default:
$objbw = $bw * get_bandwidthtype_scale($scale);
break;
}
return floatval($objbw);
}
function get_interface_bandwidth($object) {
global $altq_list_queues;
$int = $object->GetInterface();
$altq =& $altq_list_queues[$int];
if ($altq) {
$bw_3 = $altq->GetBandwidth();
$bw_3 = $bw_3 * get_bandwidthtype_scale($altq->GetBwscale());
return floatval($bw_3);
} else {
return 0;
}
}
/*
* This is duplicated here since we cannot include guiconfig.inc.
* Including it makes all stuff break.
*/
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) {
/* check for bad control characters */
foreach ($postdata as $pn => $pd) {
if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
$input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
}
}
for ($i = 0; $i < count($reqdfields); $i++) {
if ($postdata[$reqdfields[$i]] == "") {
$input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
}
}
}
function cleanup_queue_from_rules($queue) {
global $config;
foreach ($config['filter']['rule'] as $rule) {
if ($rule['defaultqueue'] == $queue) {
unset($rule['defaultqueue']);
}
if ($rule['ackqueue'] == $queue) {
unset($rule['ackqueue']);
}
}
}
function cleanup_dnqueue_from_rules($queue) {
global $config;
foreach ($config['filter']['rule'] as $rule) {
if ($rule['dnpipe'] == $queue) {
unset($rule['dnpipe']);
}
if ($rule['pdnpipe'] == $queue) {
unset($rule['pdnpipe']);
}
}
}
class altq_root_queue {
var $interface;
var $tbrconfig ;
var $bandwidth;
var $bandwidthtype; /* b, Kb, Mb, Gb, % */
var $scheduler;
var $qlimit;
var $queues = array();
var $qenabled = false;
var $link;
/* Accessor functions */
function GetDefaultQueuePresent() {
if (!empty($this->queues)) {
foreach ($this->queues as $q) {
if ($q->GetDefault()) {
return true;
}
}
}
return false;
}
function SetLink($link) {
$this->link = $link;
}
function GetLink() {
return $this->link;
}
function GetEnabled() {
return $this->qenabled;
}
function SetEnabled($value) {
$this->qenabled = $value;
}
function CanHaveChildren() {
if ($this->GetScheduler() == "CODELQ") {
return false;
} else {
return true;
}
}
function CanBeDeleted() {
return false;
}
function GetQname() {
return $this->interface;
}
function SetQname($name) {
$this->interface = trim($name);
}
function GetInterface() {
return $this->interface;
}
function SetInterface($name) {
$this->interface = trim($name);
}
function GetTbrConfig() {
return $this->tbrconfig;
}
function SetTbrConfig($tbrconfig) {
$this->tbrconfig = $tbrconfig;
}
function GetBandwidth() {
return $this->bandwidth;
}
function SetBandwidth($bw) {
$this->bandwidth = $bw;
}
function GetBwscale() {
return $this->bandwidthtype;
}
function SetBwscale($bwscale) {
$this->bandwidthtype = $bwscale;
}
function GetScheduler() {
return $this->scheduler;
}
function SetScheduler($scheduler) {
$this->scheduler = trim($scheduler);
}
function GetQlimit() {
return $this->qlimit;
}
function SetQlimit($limit) {
$this->qlimit = $limit;
}
function GetBwscaleText() {
switch ($this->bandwidthtype) {
case "b":
$bwscaletext = "Bit/s";
break;
case "Kb":
$bwscaletext = "Kbit/s";
break;
case "Mb":
$bwscaletext = "Mbit/s";
break;
case "Gb":
$bwscaletext = "Gbit/s";
break;
default:
/* For others that do not need translating like % */
$bwscaletext = $this->bandwidthtype;
break;
}
return $bwscaletext;
}
function CheckBandwidth($bw, $bwtype) {
$sum = $this->GetTotalBw();
if ($sum > $bw * get_bandwidthtype_scale($bwtype))
return 1;
foreach ($this->queues as $q) {
if ($q->CheckBandwidth(0, ''))
return 1;
}
return 0;
}
function GetTotalBw($qignore = NULL) {
$sum = 0;
foreach ($this->queues as $q) {
if ($qignore != NULL && $qignore == $q)
continue;
$sum += get_bandwidth($q->GetBandwidth(), $q->GetBwscale(), $this);
}
return $sum;
}
function validate_input($data, &$input_errors) {
$reqdfields[] = "bandwidth";
$reqdfieldsn[] = gettext("Bandwidth");
$reqdfields[] = "bandwidthtype";
$reqdfieldsn[] = gettext("Bandwidthtype");
shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
if (!isset($data['bandwidth']) || strlen($data['bandwidth']) == 0) {
$input_errors[] = gettext("Bandwidth must be set. This is usually the interface speed.");
}
if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
$input_errors[] = gettext("Bandwidth must be an integer.");
}
if ($data['bandwidth'] < 0) {
$input_errors[] = gettext("Bandwidth cannot be negative.");
}
if ($data['bandwidthtype'] == "%") {
if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100.");
}
}
if ($this->CheckBandwidth($data['bandwidth'], $data['bandwidthtype']))
$input_errors[] = "The sum of child bandwidth is higher than parent.";
if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
$input_errors[] = gettext("Qlimit must be an integer.");
}
if ($data['qlimit'] < 0) {
$input_errors[] = gettext("Qlimit must be positive.");
}
if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) {
$input_errors[] = gettext("Tbrsize must be an integer.");
}
if ($data['tbrconfig'] < 0) {
$input_errors[] = gettext("Tbrsize must be positive.");
}
}
/* Implement this to shorten some code on the frontend page */
function ReadConfig(&$conf) {
if (isset($conf['tbrconfig'])) {
$this->SetTbrConfig($conf['tbrconfig']);
} else {
$this->SetTbrConfig($conf['tbrconfig']);
}
$this->SetBandwidth($conf['bandwidth']);
if ($conf['bandwidthtype'] <> "") {
$this->SetBwscale($conf['bandwidthtype']);
}
if (isset($conf['scheduler'])) {
if ($this->GetScheduler() != $conf['scheduler']) {
foreach ($this->queues as $q) {
clean_child_queues($conf['scheduler'], $this->GetLink());
$q->clean_queue($conf['scheduler']);
}
}
$this->SetScheduler($conf['scheduler']);
}
if (isset($conf['qlimit']) && $conf['qlimit'] <> "") {
$this->SetQlimit($conf['qlimit']);
} else {
$this->SetQlimit("");
}
if (isset($conf['name'])) {
$this->SetQname($conf['name']);
}
if (!empty($conf['enabled'])) {
$this->SetEnabled($conf['enabled']);
} else {
$this->SetEnabled("");
}
}
function copy_queue($interface, &$cflink) {
$cflink['interface'] = $interface;
$cflink['name'] = $interface;
$cflink['scheduler'] = $this->GetScheduler();
$cflink['bandwidth'] = $this->GetBandwidth();
$cflink['bandwidthtype'] = $this->GetBwscale();
$cflink['qlimit'] = $this->GetQlimit();
$cflink['tbrconfig'] = $this->GetTbrConfig();
$cflink['enabled'] = $this->GetEnabled();
if (is_array($this->queues)) {
$cflink['queue'] = array();
foreach ($this->queues as $q) {
$cflink['queue'][$q->GetQname()] = array();
$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
}
}
}
function &get_queue_list(&$q = null) {
$qlist = array();
//$qlist[$this->GetQname()] = & $this;
if (is_array($this->queues)) {
foreach ($this->queues as $queue) {
$queue->get_queue_list($qlist);
}
}
return $qlist;
}
function &add_queue($interface, &$queue, &$path, &$input_errors) {
if (!is_array($this->queues)) {
$this->queues = array();
}
switch ($this->GetScheduler()) {
case "PRIQ":
$q =& new priq_queue();
break;
case "HFSC":
$q =& new hfsc_queue();
break;
case "CBQ":
$q =& new cbq_queue();
break;
case "FAIRQ":
$q =& new fairq_queue();
break;
default:
/* XXX: but should not happen anyway */
return;
break;
}
$q->SetLink($path);
$q->SetInterface($this->GetInterface());
$q->SetEnabled("on");
$q->SetParent($this);
$q->ReadConfig($queue);
$q->validate_input($queue, $input_errors);
$this->queues[$q->GetQname()] = &$q;
ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
if (is_array($queue['queue'])) {
foreach ($queue['queue'] as $key1 => $que) {
array_push($path, $key1);
$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
array_pop($path);
}
}
return $q;
}
/* interface here might be optional */
function &find_queue($interface, $qname) {
if ($qname == $this->GetQname()) {
return $this;
}
foreach ($this->queues as $q) {
$result =& $q->find_queue("", $qname);
if ($result) {
return $result;
}
}
}
function &find_parentqueue($interface, $qname) {
if ($qname == $interface) {
$result = NULL;
} else if ($this->queues[$qname]) {
$result = $this;
} else if ($this->GetScheduler() <> "PRIQ") {
foreach ($this->queues as $q) {
$result = $q->find_parentqueue("", $qname);
if ($result) {
return $result;
}
}
}
}
function build_tree() {
global $shaperIFlist;
$tree = "
";
return $tree;
}
function build_rules() {
global $config, $time_based_rules;
if ($this->GetEnabled() == "") {
return;
}
$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
$found = false;
$bandwidth = $this->GetBandwidth();
if (is_array($bandwidth)) {
foreach ($bandwidth as $bw) {
if ($bw['bwsched'] != "none") {
$time_based_rules = true;
if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
foreach ($config['schedules']['schedule'] as $schedule) {
if ($bw['bwsched'] == $schedule['name']) {
if (filter_get_time_based_rule_status($schedule)) {
$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
$pfq_rule .= " burst ".trim($bw['burst']);
}
$found = true;
break;
}
}
}
} else {
$pfq_rule .= " bw 0";
$found = true;
break;
}
} else {
$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
$pfq_rule .= " burst ".trim($bw['burst']);
}
$found = true;
break;
}
}
if ($found == false) {
$pfq_rule .= " bw 0";
}
} else {
$pfq_rule .= " bw 0";
}
if ($this->GetQlimit()) {
$pfq_rule .= " queue " . $this->GetQlimit();
}
if ($this->GetPlr()) {
$pfq_rule .= " plr " . $this->GetPlr();
}
if ($this->GetBuckets()) {
$pfq_rule .= " buckets " . $this->GetBuckets();
}
if ($this->GetDelay()) {
$pfq_rule .= " delay " . $this->GetDelay();
}
$this->build_mask_rules($pfq_rule);
$pfq_rule .= "\n";
if (!empty($this->subqueues) && count($this->subqueues) > 0) {
foreach ($this->subqueues as $q) {
$pfq_rule .= $q->build_rules();
}
}
$pfq_rule .= " \n";
return $pfq_rule;
}
function update_dn_data(&$data) {
$this->ReadConfig($data);
}
function build_javascript() {
global $g, $config;
$javasr = parent::build_javascript();
//build list of schedules
$schedules = "";
if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
foreach ($config['schedules']['schedule'] as $schedule) {
if ($schedule['name'] <> "") {
$schedules .= "";
}
}
}
$bwopt = "";
foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
$bwopt .= "";
}
$javasr .= <<
//";
cell2.innerHTML = "";
cell3.innerHTML = "";
cell4.innerHTML = 'Delete';
});
})();
function removeBwRow(el) {
var d = el.parentNode.parentNode.rowIndex;
document.getElementById('maintable').deleteRow(d);
}
//]]>
EOD;
return $javasr;
}
// Compose a table of bandwidths that can then be inserted into the form using a Form_StaticText
// The table has been "Bootstrapped" to match the web design while maintaining compatibility with
// with the javascript in this class
function build_bwtable() {
global $config;
$bandwidth = $this->GetBandwidth();
//build list of schedules
$schedules = array();
$schedules[] = "none";//leave none to leave rule enabled all the time
if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
foreach ($config['schedules']['schedule'] as $schedule) {
if ($schedule['name'] != "") {
$schedules[] = $schedule['name'];
}
}
}
$form = '
';
$form .= '
';
$form .= "
";
$form .= "
Bandwidth
";
//$form .= "
Burst
";
$form .= "
Bw type
";
$form .= "
Schedule
";
$form .= "
";
$form .= "
";
$form .= "";
// If there are no bandwidths defined, make a blank one for convenience
if (empty($bandwidth)) {
$bandwidth = array(0 => array('bw' => '', 'bwscale' => 'Kb', 'bwsched' => 'none'));
}
if (is_array($bandwidth)) {
foreach ($bandwidth as $bwidx => $bw) {
$form .= '
";
return $tree;
}
function build_rules() {
if ($this->GetEnabled() == "") {
return;
}
$parent =& $this->GetParent();
$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
if ($this->GetQlimit()) {
$pfq_rule .= " queue " . $this->GetQlimit();
}
if ($this->GetWeight()) {
$pfq_rule .= " weight " . $this->GetWeight();
}
if ($this->GetBuckets()) {
$pfq_rule .= " buckets " . $this->GetBuckets();
}
$this->build_mask_rules($pfq_rule);
$pfq_rule .= "\n";
return $pfq_rule;
}
function build_javascript() {
return parent::build_javascript();
}
function build_form() {
global $g, $config, $pipe, $action, $qname;
//build list of schedules
$schedules = array();
$schedules[] = "none";//leave none to leave rule enabled all the time
if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
foreach ($config['schedules']['schedule'] as $schedule) {
if ($schedule['name'] <> "") {
$schedules[] = $schedule['name'];
}
}
}
$sform = new Form();
$sform->setAction("firewall_shaper.php");
$section = new Form_Section('Limiters');
$section->addInput(new Form_Checkbox(
'enabled',
'Enable',
'Enable this queue',
($this->GetEnabled() == "on"),
'on'
));
$section->addInput(new Form_Input(
'newname',
'Name',
'text',
$this->GetQname()
));
$section->addInput(new Form_Input(
'name',
null,
'hidden',
$this->GetQname()
));
if ($this->GetNumber() > 0) {
$section->addInput(new Form_Input(
'number',
null,
'hidden',
$this->GetNumber()
));
}
$mask = $this->GetMask();
$section->addInput(new Form_Select(
'mask',
'Mask',
$mask['type'],
array('none' => gettext('None'), 'srcaddress' => gettext('Source addresses'), 'dstaddress' => gettext('Destination addresses'))
))->setHelp('If "source" or "destination" slots is chosen a dynamic pipe with the bandwidth, delay, packet loss ' .
'and queue size given above will be created for each source/destination IP address encountered, respectively. ' .
'This makes it possible to easily specify bandwidth limits per host.');
$group = new Form_Group(null);
$group->add(new Form_Select(
'maskbits',
null,
$mask['bits'],
array_combine(range(32, 1, -1), range(32, 1, -1))
))->setHelp('IPv4 mask bits' . ' ' . '255.255.255.255/?');
$group->add(new Form_Select(
'maskbitsv6',
null,
$mask['bitsv6'],
array_combine(range(128, 1, -1), range(128, 1, -1))
))->setHelp('IPv6 mask bits' . ' ' . 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/?');
$section->add($group);
$section->addInput(new Form_Input(
'description',
'Description',
'text',
$this->GetDescription()
))->setHelp('A description may be entered here for administrative reference (not parsed).');
$sform->add($section);
$section = new Form_Section('Advanced Options');
$section->addInput(new Form_Input(
'weight',
'Weight',
'number',
$this->GetWeight(),
['min' => '1', 'max' => '100']
))->setHelp('For queues under the same parent this specifies the share that a queue gets(values range from 1 to 100),' .
' it can be left blank otherwise.');
$section->addInput(new Form_Input(
'plr',
'Packet Loss Rate',
'number',
$this->GetPlr(),
['step' => '0.001', 'min' => '0.000']
))->setHelp('In most cases, zero (0) should be specified here (or leave the field empty). ' .
'A value of 0.001 means one packet in 1000 gets dropped');
$section->addInput(new Form_Input(
'qlimit',
'Queue size (slots)',
'number',
$this->GetQlimit()
))->setHelp('In most cases, the field should be left empty. All packets in this pipe are placed into a fixed-size queue first, ' .
'then they are delayed by value specified in the Delay field, and then they are delivered to their destination.');
$section->addInput(new Form_Input(
'buckets',
'Bucket size (slots)',
'number',
$this->GetBuckets()
))->setHelp('In most cases, this field should be left empty. It increases the hash size set');
$section->addInput(new Form_Input(
'pipe',
null,
'hidden',
$this->GetPipe()
));
$sform->add($section);
return($sform);
}
function update_dn_data(&$data) {
$this->ReadConfig($data);
}
function wconfig() {
$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
if (!is_array($cflink)) {
$cflink = array();
}
$cflink['name'] = $this->GetQname();
$cflink['number'] = $this->GetNumber();
$cflink['qlimit'] = $this->GetQlimit();
$cflink['description'] = $this->GetDescription();
$cflink['weight'] = $this->GetWeight();
$cflink['enabled'] = $this->GetEnabled();
$cflink['buckets'] = $this->GetBuckets();
$mask = $this->GetMask();
$cflink['mask'] = $mask['type'];
$cflink['maskbits'] = $mask['bits'];
$cflink['maskbitsv6'] = $mask['bitsv6'];
}
}
function get_dummynet_name_list() {
$dn_name_list =& get_unique_dnqueue_list();
$dn_name = array();
if (is_array($dn_name_list)) {
foreach ($dn_name_list as $key => $value) {
$dn_name[] = $key;
}
}
return $dn_name;
}
function get_altq_name_list() {
$altq_name_list =& get_unique_queue_list();
$altq_name = array();
if (is_array($altq_name_list)) {
foreach ($altq_name_list as $key => $aqobj) {
$altq_name[] = $key;
}
}
return $altq_name;
}
/*
* XXX: TODO Make a class shaper to hide all these functions
* from the global namespace.
*/
/*
* This is a layer violation but for now there is no way
* I can find to properly do this with PHP.
*/
function altq_get_default_queue($interface) {
global $altq_list_queues;
$altq_tmp = $altq_list_queues[$interface];
if ($altq_tmp) {
return $altq_tmp->GetDefaultQueuePresent();
} else {
return false;
}
}
function altq_check_default_queues() {
global $altq_list_queues;
$count = 0;
if (is_array($altq_list_queues)) {
foreach ($altq_list_queues as $altq) {
if ($altq->GetDefaultQueuePresent()) {
$count++;
}
}
}
else {
$count++;
}
return 0;
}
function &get_unique_queue_list() {
global $altq_list_queues;
$qlist = array();
if (is_array($altq_list_queues)) {
foreach ($altq_list_queues as $altq) {
if ($altq->GetEnabled() == "") {
continue;
}
$tmplist =& $altq->get_queue_list();
foreach ($tmplist as $qname => $link) {
if ($link->GetEnabled() <> "") {
$qlist[$qname] = $link;
}
}
}
}
return $qlist;
}
function &get_unique_dnqueue_list() {
global $dummynet_pipe_list;
$qlist = array();
if (is_array($dummynet_pipe_list)) {
foreach ($dummynet_pipe_list as $dn) {
if ($dn->GetEnabled() == "") {
continue;
}
$tmplist =& $dn->get_queue_list();
foreach ($tmplist as $qname => $link) {
$qlist[$qname] = $link;
}
}
}
return $qlist;
}
function ref_on_altq_queue_list($parent, $qname) {
if (isset($GLOBALS['queue_list'][$qname])) {
$GLOBALS['queue_list'][$qname]++;
} else {
$GLOBALS['queue_list'][$qname] = 1;
}
unref_on_altq_queue_list($parent);
}
function unref_on_altq_queue_list($qname) {
$GLOBALS['queue_list'][$qname]--;
if ($GLOBALS['queue_list'][$qname] <= 1) {
unset($GLOBALS['queue_list'][$qname]);
}
}
function read_altq_config() {
global $altq_list_queues, $config;
$path = array();
if (!is_array($config['shaper'])) {
$config['shaper'] = array();
}
if (!is_array($config['shaper']['queue'])) {
$config['shaper']['queue'] = array();
}
$a_int = &$config['shaper']['queue'];
$altq_list_queues = array();
if (!is_array($config['shaper']['queue'])) {
return;
}
foreach ($a_int as $key => $conf) {
$int = $conf['interface'];
$root =& new altq_root_queue();
$root->SetInterface($int);
$altq_list_queues[$root->GetInterface()] = &$root;
$root->ReadConfig($conf);
array_push($path, $key);
$root->SetLink($path);
if (is_array($conf['queue'])) {
foreach ($conf['queue'] as $key1 => $q) {
array_push($path, $key1);
/*
* XXX: we completely ignore errors here but anyway we must have
* checked them before so no harm should be come from this.
*/
$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
array_pop($path);
}
}
array_pop($path);
}
}
function read_dummynet_config() {
global $dummynet_pipe_list, $config;
$path = array();
if (!is_array($config['dnshaper'])) {
$config['dnshaper'] = array();
}
if (!is_array($config['dnshaper']['queue'])) {
$config['dnshaper']['queue'] = array();
}
$a_int = &$config['dnshaper']['queue'];
$dummynet_pipe_list = array();
if (!is_array($config['dnshaper']['queue']) ||
!count($config['dnshaper']['queue'])) {
return;
}
foreach ($a_int as $key => $conf) {
if (empty($conf['name'])) {
continue; /* XXX: grrrrrr at php */
}
$root =& new dnpipe_class();
$root->ReadConfig($conf);
$dummynet_pipe_list[$root->GetQname()] = &$root;
array_push($path, $key);
$root->SetLink($path);
if (is_array($conf['queue'])) {
foreach ($conf['queue'] as $key1 => $q) {
array_push($path, $key1);
/*
* XXX: we completely ignore errors here but anyway we must have
* checked them before so no harm should be come from this.
*/
$root->add_queue($root->GetQname(), $q, $path, $input_errors);
array_pop($path);
}
}
array_pop($path);
}
}
function get_interface_list_to_show() {
global $altq_list_queues, $config;
global $shaperIFlist;
$tree = "";
foreach ($shaperIFlist as $shif => $shDescr) {
if ($altq_list_queues[$shif]) {
continue;
} else {
if (!is_altq_capable(get_real_interface($shif))) {
continue;
}
$tree .= "