diff --git a/src/etc/inc/shaper.inc b/src/etc/inc/shaper.inc
index 250386bf64..459d53c77c 100644
--- a/src/etc/inc/shaper.inc
+++ b/src/etc/inc/shaper.inc
@@ -31,6 +31,200 @@ require_once("util.inc");
require_once("notices.inc");
include_once("interfaces.inc");//required for convert_real_interface_to_friendly_interface_name() in get_queue_stats() to get altq interface name.
+/* Limiter patch */
+// I need this crazy looking model/struct to specify various algos, ecn caps, and params.
+// update as needed when dummynet changes
+
+// List of schedulers ('type' command on scheduler/pipe) that dummynet/ipfw is supposed to support
+function getSchedulers() {
+ return array(
+ "fifo" => array(
+ "name" => "FIFO",
+ "parameter_format" => "type fifo",
+ "description" => "First-in-First-out is a fundamental queueing discipline which ensures packet sequence.",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "qfq" => array(
+ "name" => "Quick Fair Queueing",
+ "parameter_format" => "type qfq",
+ "description" => "QFQ is a fast, low-complexity Approximated Fair Queueing scheduler.",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "rr" => array(
+ "name" => "Round Robin",
+ "parameter_format" => "type rr",
+ "description" => "Round Robin (RR) schedules packets in a round-robin fashion.",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "wf2q+" => array(
+ "name" => "Worst-case Weighted fair Queueing",
+ "parameter_format" => "type wf2q+",
+ "description" => "Worst-case Weighted fair Queueing (WF2Q+) schedules flows with an associated weight.",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "prio" => array(
+ "name" => "PRIO",
+ "parameter_format" => "type prio",
+ "description" => "PRIO schedules packets by their corresponding priority.",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "fq_codel" => array(
+ "name" => "FQ_CODEL",
+ "parameter_format" => "type fq_codel target %sms interval %sms quantum %s limit %s flows %s",
+ "description" => "CoDel is a novel \"no knobs\", \"just works\", \"handles variable bandwidth and RTT\", and simple AQM algorithm."
+ . " As a scheduler, FQ_CODEL implements several flows (defined below), each having their own CoDel AQM.",
+ "parameters" => array(
+ "target" => array("name" => "Target Delay (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqcodel.target") / 1000),
+ "interval" => array("name" => "Interval (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqcodel.interval") / 1000),
+ "quantum" => array("name" => "quantum", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqcodel.quantum")),
+ "limit" => array("name" => "limit", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqcodel.limit")),
+ "flows" => array("name" => "flows", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqcodel.flows"))
+ ),
+ "ecn" => true
+ ),
+ "fq_pie" => array(
+ "name" => "FQ_PIE",
+ "parameter_format" => "type fq_pie target %sms tupdate %sms alpha %s beta %s max_burst %s max_ecnth %s",
+ "description" => "Fair Queue Proportional Integral controller Enhanced AQM (FQ_PIE) is similar to FQ_CODEL but uses a slightly different algorithm.",
+ "parameters" => array(
+ "target" => array("name" => "Target Delay (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.target") / 1000),
+ "tupdate" => array("name" => "Interval (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.tupdate") / 1000),
+ "alpha" => array("name" => "alpha", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.alpha")),
+ "beta" => array("name" => "beta", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.beta")),
+ "max_burst" => array("name" => "max_burst", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.max_burst")),
+ "max_ecnth" => array("name" => "max_ecnth", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.max_ecnth"))
+ ),
+ "ecn" => true
+ )
+ );
+}
+// list of AQMs that dummynet supports
+function getAQMs() {
+ return array(
+ "droptail" => array(
+ "name" => "Tail Drop",
+ "description" => "Tail Drop is a fundamental queue management algorithm which drops inbound packets once the queue is full.",
+ "parameter_format" => "droptail",
+ "parameters" => array(),
+ "ecn" => false
+ ),
+ "codel" => array(
+ "name" => "CoDel",
+ "description" => "CoDel is a novel \"no knobs\", \"just works\", \"handles variable bandwidth and RTT\", and simple AQM algorithm.",
+ "parameter_format" => "codel target %sms interval %sms",
+ "parameters" => array(
+ "target" => array("name" => "Target Delay (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.codel.target") / 1000),
+ "interval" => array("name" => "Interval (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.codel.interval") / 1000),
+ ),
+ "ecn" => true
+ ),
+ "pie" => array(
+ "name" => "PIE",
+ "description" => "Proportional Integral controller Enhanced AQM (PIE) is similar to CoDel but uses a slightly different algorithm.",
+ "parameter_format" => "pie target %sms tupdate %sms alpha %s beta %s max_burst %s max_ecnth %s",
+ "parameters" => array(
+ "target" => array("name" => "Target Delay (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.target") / 1000),
+ "tupdate" => array("name" => "Interval (ms)", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.tupdate") / 1000),
+ "alpha" => array("name" => "alpha", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.alpha")),
+ "beta" => array("name" => "beta", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.beta")),
+ "max_burst" => array("name" => "max_burst", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.max_burst")),
+ "max_ecnth" => array("name" => "max_ecnth", "type" => "number", "default" => get_single_sysctl("net.inet.ip.dummynet.fqpie.max_ecnth"))
+ ),
+ "ecn" => true
+ ),
+ "red" => array(
+ "name" => "Random Early Detection (RED)",
+ "description" => "Random Early Detection (RED) drops packets based on probability, which increases as the queue increases in size.",
+ "parameter_format" => "red %s/%s/%s/%s",
+ "parameters" => array(
+ "w_q" => array("name" => "w_q", "type" => "number", "default" => 1),
+ "min_th" => array("name" => "min_th", "type" => "number", "default" => 0),
+ "max_th" => array("name" => "max_th", "type" => "number", "default" => 1),
+ "max_p" => array("name" => "max_p", "type" => "number", "default" => 1)
+ ),
+ "ecn" => true
+ ),
+ "gred" => array(
+ "name" => "Gentle Random Early Detection (GRED)",
+ "description" => "Gentle Random Early Detection (GRED) drops packets based on probability, which increases as the queue increases in size.",
+ "parameter_format" => "gred %s/%s/%s/%s",
+ "parameters" => array(
+ "w_q" => array("name" => "w_q", "type" => "number", "default" => 1),
+ "min_th" => array("name" => "min_th", "type" => "number", "default" => 0),
+ "max_th" => array("name" => "max_th", "type" => "number", "default" => 1),
+ "max_p" => array("name" => "max_p", "type" => "number", "default" => 1)
+ ),
+ "ecn" => true
+ )
+ );
+}
+// used to map above
+function array_map_assoc(callable $f, array $a) {
+ return array_column(array_map($f, array_keys($a), $a), 1, 0);
+}
+function build_queue_params($array, $selected, $params, $id) {
+ $form .= '
';
+
+ $selectedAlgorithm = $array[$selected];
+
+ if ($selectedAlgorithm) {
+ $form .= '
' . gettext($selectedAlgorithm['description']) . '';
+ }
+
+ $parameters = $selectedAlgorithm["parameters"];
+
+ if (!$parameters || sizeof($parameters) <= 0) {
+ if (!$selectedAlgorithm) {
+ $form .= 'No parameters for selected algorithm.';
+ } else {
+ $form .= 'No parameters for ' . $selectedAlgorithm["name"] . '.';
+ }
+ } else {
+ $form .= '
";
+ }
+
+ $form .= '
';
+ $form .= '';
+
+ return($form);
+}
+function FormatParameters($format_string, $params) {
+ return vsprintf($format_string, $params);
+}
+/* End limiter patch */
+
function get_queue_stats() {
// due to sysutils\qstats not providing accurate stats with 'currently' valid numbers
// in its current implementation this php function does the job for now..
@@ -3459,6 +3653,56 @@ class dnpipe_class extends dummynet_class {
var $delay;
var $qbandwidth = array();
var $qbandwidthtype;
+
+ /* Limiter queue patch */
+ var $ecn; // ecn 'on' or 'off'
+ var $aqm; // key to aqm_map
+ var $aqm_params = array(); // AQM params
+ var $scheduler; // key to scheduler_map
+ var $scheduler_params = array(); // AQM params
+ function GetAQM() {
+ return $this->aqm;
+ }
+ function SetAQM($aqm) {
+ $this->aqm = $aqm;
+ }
+ function GetAQMParameters() {
+ return $this->aqm_params;
+ }
+ function GetAQMParameter($parameter) {
+ return $this->aqm_params[$parameter];
+ }
+ function SetAQMParameter($key, $value) {
+ return $this->aqm_params[$key] = $value;
+ }
+ function SetAQMParameters($params) {
+ $this->aqm_params = $params;
+ }
+ function GetECN() {
+ return $this->ecn;
+ }
+ function SetECN($ecn) {
+ $this->ecn = $ecn;
+ }
+ function GetScheduler() {
+ return $this->scheduler;
+ }
+ function SetScheduler($scheduler) {
+ $this->scheduler = $scheduler;
+ }
+ function GetSchedulerParameters() {
+ return $this->scheduler_params;
+ }
+ function SetSchedulerParameters($params) {
+ $this->scheduler_params = $params;
+ }
+ function SetSchedulerParameter($key, $value) {
+ $this->scheduler_params[$key] = $value;
+ }
+ function GetSchedulerParameter($key) {
+ return $this->scheduler_params[$key];
+ }
+ /* End limiter queue patch */
/* This is here to help on form building and building rules/lists */
var $subqueues = array();
@@ -3479,6 +3723,7 @@ class dnpipe_class extends dummynet_class {
}
unset_dn_object_by_reference($this->GetLink());
@pfSense_ipfw_pipe("pipe delete " . $this->GetNumber());
+ @pfSense_ipfw_pipe("sched delete " . $this->GetNumber());
}
function GetBandwidth() {
return $this->qbandwidth;
@@ -3590,6 +3835,20 @@ class dnpipe_class extends dummynet_class {
if ($data['delay'] && (!is_numeric($data['delay']))) {
$input_errors[] = gettext("Delay must be an integer.");
}
+
+ /* Limiter patch */
+ $selectedScheduler = getSchedulers()[$data['sched']];
+ if (!$selectedScheduler) {
+ $input_errors[] = gettext("Selected scheduler not recognized.");
+ }
+ $selectedAqm = getAQMs()[$data['aqm']];
+ if (!$selectedAqm) {
+ $input_errors[] = gettext("Selected AQM not recognized.");
+ }
+ if ($data['ecn'] && $data['ecn'] == 'on' && !$selectedScheduler["ecn"] && !$selectedAqm["ecn"]) {
+ $input_errors[] = gettext("Explicit Congestion Notification is selected, but neither " . $selectedAqm["name"] . " nor " . $selectedScheduler["name"] . " support it.");
+ }
+ /* End limiter patch */
}
function ReadConfig(&$q) {
@@ -3669,7 +3928,48 @@ class dnpipe_class extends dummynet_class {
$this->SetDescription("");
}
$this->SetEnabled($q['enabled']);
-
+
+ /* Limiter patch */
+ if (isset($q['aqm']) && $q['aqm'] <> "") {
+ $this->SetAQM($q['aqm']);
+ } else {
+ $this->SetAQM('droptail');
+ }
+ // parse AQM arguments
+ $aqm_map = getAQMs();
+ $selectedParameters = $aqm_map[$this->getAQM()]["parameters"];
+ if (is_array($selectedParameters)) {
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetAQM() . '_' . $key;
+ if (isset($q[$config_key]) && $q[$config_key] <> "") {
+ $this->SetAQMParameter($key, $q[$config_key]);
+ } else {
+ $this->SetAQMParameter($key, $value["default"]);
+ }
+ }
+ }
+
+ if (isset($q['sched']) && $q['sched'] <> "") {
+ $this->SetScheduler($q['sched']);
+ } else {
+ $this->SetScheduler('fifo');
+ }
+ $scheduler_map = getSchedulers();
+ $selectedParameters = $scheduler_map[$this->getScheduler()]["parameters"];
+ if (is_array($selectedParameters)) {
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetScheduler() . '_' . $key;
+ if (isset($q[$config_key]) && $q[$config_key] <> "") {
+ $this->SetSchedulerParameter($key, $q[$config_key]);
+ } else {
+ $this->SetSchedulerParameter($key, $value["default"]);
+ }
+ }
+ }
+
+ // ecn flag
+ $this->SetECN($q['ecn']);
+ /* End limiter patch */
}
function build_tree() {
@@ -3751,13 +4051,38 @@ class dnpipe_class extends dummynet_class {
}
$this->build_mask_rules($pfq_rule);
+ /* Limiter patch */
+ $selectedAQM = getAQMs()[$this->getAQM()];
+ if ($selectedAQM) {
+ $pfq_rule .= " " . FormatParameters($selectedAQM["parameter_format"], $this->GetAQMParameters());
+ if ($selectedAQM["ecn"]) {
+ if ($this->getECN() == 'on') {
+ $pfq_rule .= ' ecn';
+ } else {
+ $pfq_rule .= ' noecn';
+ }
+ }
+ }
+ $selectedScheduler = getSchedulers()[$this->getScheduler()];
+ if ($selectedScheduler) {
+ $pfq_rule .= "\nsched ". $this->GetNumber() . " config pipe " . $this->GetNumber() . " " . FormatParameters($selectedScheduler["parameter_format"], $this->GetSchedulerParameters());
+ if ($selectedScheduler["ecn"]) {
+ if ($this->getECN() == 'on') {
+ $pfq_rule .= ' ecn';
+ } else {
+ $pfq_rule .= ' noecn';
+ }
+ }
+ }
$pfq_rule .= "\n";
-
+ /* End patch */
+
if (!empty($this->subqueues) && count($this->subqueues) > 0) {
foreach ($this->subqueues as $q) {
$pfq_rule .= $q->build_rules();
}
}
+
$pfq_rule .= " \n";
return $pfq_rule;
@@ -4010,6 +4335,60 @@ EOD;
$sform->add($section);
+ /* Begin limiter patch */
+ $aqm_map = getAQMs();
+ $scheduler_map = getSchedulers();
+
+ $section = new Form_Section('Queue');
+ $section->addInput(new Form_Select(
+ 'aqm',
+ 'Queue Management Algorithm',
+ $this->GetAQM(),
+ array_map_assoc(function ($k, $v) {
+ return [$k, $v["name"]];
+ }, $aqm_map)
+ ))->setHelp('Active queue management (AQM) is the intelligent drop of network packets inside the limiter, ' .
+ 'when it becomes full or gets close to becoming full, with the goal of reducing ' .
+ 'network congestion.');
+
+ $section->addInput(new Form_StaticText(
+ '',
+ build_queue_params($aqm_map, $this->GetAQM(), $this->GetAQMParameters(), "aqm")
+ ))->setHelp('Specifies the queue management algorithm parameters.');
+
+ $section->addInput(new Form_Select(
+ 'sched',
+ 'Scheduler',
+ $this->GetScheduler(),
+ array_map_assoc(function ($k, $v) {
+ return [$k, $v["name"]];
+ }, $scheduler_map)
+ ))->setHelp('The scheduler manages the sequence of network packets in the limiter\'s queue.');
+
+ $section->addInput(new Form_StaticText(
+ '',
+ build_queue_params($scheduler_map, $this->GetScheduler(), $this->GetSchedulerParameters(), "sched")
+ ))->setHelp('Specifies the scheduler parameters.');
+
+ $section->addInput(new Form_Input(
+ 'qlimit',
+ 'Queue length',
+ 'number',
+ $this->GetQlimit()
+ ))->setHelp('Specifies the length of the limiter\'s queue, which the scheduler and AQM are responsible for. ' .
+ 'This field may be left empty.');
+
+ $section->addInput(new Form_Checkbox(
+ 'ecn',
+ 'ECN',
+ 'Enable Explicit Congestion Notification (ECN)',
+ ($this->GetECN() == "on"),
+ 'on'
+ ))->setHelp('ECN sets a reserved TCP flag when the queue is nearing or exceeding capacity. Not all AQMs or schedulers support this.');
+
+ $sform->add($section);
+ /* End limiter patch */
+
$section = new Form_Section('Advanced Options');
$section->addInput(new Form_Input(
@@ -4028,14 +4407,6 @@ EOD;
))->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)',
@@ -4075,6 +4446,24 @@ EOD;
$cflink['maskbits'] = $mask['bits'];
$cflink['maskbitsv6'] = $mask['bitsv6'];
$cflink['delay'] = $this->GetDelay();
+
+ /* Limiter queue patch */
+ $cflink['sched'] = $this->GetScheduler();
+ $scheduler_map = getSchedulers();
+ $selectedParameters = $scheduler_map[$this->getScheduler()]["parameters"];
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetScheduler() . '_' . $key;
+ $cflink[$config_key] = $this->GetSchedulerParameter($key);
+ }
+ $cflink['aqm'] = $this->GetAQM();
+ $aqm_map = GetAQMs();
+ $selectedParameters = $aqm_map[$this->getAQM()]["parameters"];
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetAQM() . '_' . $key;
+ $cflink[$config_key] = $this->GetAQMParameter($key);
+ }
+ $cflink['ecn'] = $this->GetECN();
+ /* End limiter queue patch */
}
}
@@ -4082,6 +4471,35 @@ EOD;
class dnqueue_class extends dummynet_class {
var $pipeparent;
var $weight;
+ /* Limiter queue patch */
+ var $ecn; // ecn 'on' or 'off'
+ var $aqm; // key to aqm_map
+ var $aqm_params = array(); // AQM params
+ function GetAQM() {
+ return $this->aqm;
+ }
+ function SetAQM($aqm) {
+ $this->aqm = $aqm;
+ }
+ function GetAQMParameters() {
+ return $this->aqm_params;
+ }
+ function GetAQMParameter($parameter) {
+ return $this->aqm_params[$parameter];
+ }
+ function SetAQMParameter($key, $value) {
+ return $this->aqm_params[$key] = $value;
+ }
+ function SetAQMParameters($params) {
+ $this->aqm_params = $params;
+ }
+ function GetECN() {
+ return $this->ecn;
+ }
+ function SetECN($ecn) {
+ $this->ecn = $ecn;
+ }
+ /* End limiter queue patch */
function GetWeight() {
return $this->weight;
@@ -4109,6 +4527,17 @@ class dnqueue_class extends dummynet_class {
function validate_input($data, &$input_errors) {
parent::validate_input($data, $input_errors);
+
+
+ /* Limiter patch */
+ $selectedAqm = getAQMs()[$data['aqm']];
+ if (!$selectedAqm) {
+ $input_errors[] = gettext("Selected AQM not recognized.");
+ }
+ if ($data['ecn'] && $data['ecn'] == 'on' && !$selectedAqm["ecn"]) {
+ $input_errors[] = gettext("Explicit Congestion Notification is selected, but " . $selectedAqm["name"] . " does not support it.");
+ }
+ /* End limiter patch */
if ($data['weight'] && ((!is_numeric($data['weight'])) ||
($data['weight'] < 1 && $data['weight'] > 100))) {
@@ -4189,6 +4618,28 @@ class dnqueue_class extends dummynet_class {
$this->SetDescription("");
}
$this->SetEnabled($q['enabled']);
+
+ /* Limiter patch */
+ if (isset($q['aqm']) && $q['aqm'] <> "") {
+ $this->SetAQM($q['aqm']);
+ } else {
+ $this->SetAQM('droptail');
+ }
+ // parse AQM arguments
+ $aqm_map = getAQMs();
+ $selectedParameters = $aqm_map[$this->getAQM()]["parameters"];
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetAQM() . '_' . $key;
+ if (isset($q[$config_key]) && $q[$config_key] <> "") {
+ $this->SetAQMParameter($key, $q[$config_key]);
+ } else {
+ $this->SetAQMParameter($key, $value["default"]);
+ }
+ }
+
+ // ecn flag
+ $this->SetECN($q['ecn']);
+ /* End limiter patch */
}
function build_tree() {
@@ -4217,6 +4668,21 @@ class dnqueue_class extends dummynet_class {
$pfq_rule .= " buckets " . $this->GetBuckets();
}
$this->build_mask_rules($pfq_rule);
+
+ /* Limiter patch */
+ $selectedAQM = getAQMs()[$this->getAQM()];
+ if ($selectedAQM) {
+ $pfq_rule .= " " . FormatParameters($selectedAQM["parameter_format"], $this->GetAQMParameters());
+ if ($selectedAQM["ecn"]) {
+ if ($this->getECN() == 'on') {
+ $pfq_rule .= ' ecn';
+ } else {
+ $pfq_rule .= ' noecn';
+ }
+ }
+ }
+ /* End patch */
+
$pfq_rule .= "\n";
return $pfq_rule;
@@ -4313,6 +4779,44 @@ class dnqueue_class extends dummynet_class {
))->setHelp('A description may be entered here for administrative reference (not parsed).');
$sform->add($section);
+
+ /* Begin limiter patch */
+ $aqm_map = getAQMs();
+
+ $section = new Form_Section('Queue');
+ $section->addInput(new Form_Select(
+ 'aqm',
+ 'Queue Management Algorithm',
+ $this->GetAQM(),
+ array_map_assoc(function ($k, $v) {
+ return [$k, $v["name"]];
+ }, $aqm_map)
+ ))->setHelp('Active queue management (AQM) is the intelligent drop of network packets inside this limiter\'s queue, ' .
+ 'when it becomes full or gets close to becoming full, with the goal of reducing ' .
+ 'network congestion.');
+
+ $section->addInput(new Form_StaticText(
+ '',
+ build_queue_params($aqm_map, $this->GetAQM(), $this->GetAQMParameters(), "aqm")
+ ))->setHelp('Specifies the queue management algorithm parameters.');
+
+ $section->addInput(new Form_Input(
+ 'qlimit',
+ 'Queue length',
+ 'number',
+ $this->GetQlimit()
+ ))->setHelp('Specifies the length of this queue, which the AQM is responsible for. This field may be left empty.');
+
+ $section->addInput(new Form_Checkbox(
+ 'ecn',
+ 'ECN',
+ 'Enable Explicit Congestion Notification (ECN)',
+ ($this->GetECN() == "on"),
+ 'on'
+ ))->setHelp('ECN sets a reserved TCP flag when the queue is nearing or exceeding capacity. Not all AQMs or schedulers support this.');
+
+ $sform->add($section);
+ /* End limiter patch */
$section = new Form_Section('Advanced Options');
@@ -4333,15 +4837,7 @@ class dnqueue_class extends dummynet_class {
['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)',
@@ -4381,6 +4877,17 @@ class dnqueue_class extends dummynet_class {
$cflink['mask'] = $mask['type'];
$cflink['maskbits'] = $mask['bits'];
$cflink['maskbitsv6'] = $mask['bitsv6'];
+
+ /* Limiter queue patch */
+ $cflink['aqm'] = $this->GetAQM();
+ $aqm_map = GetAQMs();
+ $selectedParameters = $aqm_map[$this->getAQM()]["parameters"];
+ foreach ($selectedParameters as $key => $value) {
+ $config_key = 'param_' . $this->GetAQM() . '_' . $key;
+ $cflink[$config_key] = $this->GetAQMParameter($key);
+ }
+ $cflink['ecn'] = $this->GetECN();
+ /* End limiter queue patch */
}
}
@@ -4776,4 +5283,4 @@ function interface_has_queue($if) {
return false;
}
-?>
+?>
\ No newline at end of file