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[] = "The field '" . $pn . "' contains invalid characters."; } } for ($i = 0; $i < count($reqdfields); $i++) { if ($postdata[$reqdfields[$i]] == "") { $input_errors[] = "The field '" . $reqdfieldsn[$i] . "' is required."; } } } 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 */ var $scheduler; var $qlimit; var $queues = array(); var $qenabled = false; var $link; var $default_present; /* if we have a default queue set */ var $available_bw; /* in b/s */ /* Accesor functions */ function GetAvailableBandwidth() { return $this->available_bw; } function SetAvailableBandwidth($bw) { $this->available_bw = $bw; } function SetDefaultQueuePresent($value) { $this->default_present = $value; } function GetDefaultQueuePresent() { return trim($this->default_present); } function SetLink($link) { $this->link = $link; } function GetLink() { return $this->link; } function GetEnabled() { return $this->qenabled; } function SetEnabled($value) { $this->qenabled = $value; } function CanHaveChildren() { 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 validate_input($data, &$input_errors) { $reqdfields[] = "bandwidth"; $reqdfieldsn[] = "Bandwidth"; $reqdfields[] = "bandwidthtype"; $reqdfieldsn[] = "Bandwidthtype"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) $input_errors[] = "Bandwidth must be an integer."; if ($data['bandwidth'] < 0) $input_errors[] = "Bandwidth cannot be negative."; if ($data['qlimit'] && (!is_numeric($data['qlimit']))) $input_errors[] = "Qlimit must be an integer."; if ($data['qlimit'] < 0) $input_errors[] = "Qlimit must be an positive."; if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) $input_errors[] = "Tbrsize must be an integer."; if ($data['tbrconfig'] < 0) $input_errors[] = "Tbrsize must be an positive."; } /* Implement this to shorten some code on the frontend page */ function ReadConfig(&$conf) { if (isset($conf['tbrconfig'])) $this->SetTbrConfig($conf['tbrconfig']); if ($conf['bandwidth'] <> "") { $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']); 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); if (count($input_errors)) { return $q; } if (isset($queue['bandwidth'])) { switch ($queue['bandwidthtype']) { case "%": $myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100; break; default: $myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwdithtype']); break; } } $q->SetAvailableBandwidth($myBw); $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw); $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 = "
  • GetInterface()."&queue=". $this->GetInterface()."&action=show"; $tree .= "\">" . $shaperIFlist[$this->GetInterface()] . ""; if (is_array($this->queues)) { $tree .= ""; } $tree .= "
  • "; return $tree; } function delete_queue() { foreach ($this->queues as $q) { $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth()); $q->delete_queue(); } unset_object_by_reference($this->GetLink()); } function delete_all() { if (count($this->queues)) { foreach ($this->queues as $q) { $q->delete_all(); unset_object_by_reference($q->GetLink()); unset($q); } unset($this->queues); } } /* * First it spits: * altq on $interface .............. * then it goes like * foreach ($queues as $qkey => $queue) * this->queues[$qkey]->build_rule(); */ function build_rules() { if (count($this->queues) > 0 && $this->GetEnabled() == "on") { $rules = " altq on " . get_real_interface($this->GetInterface()); if ($this->GetScheduler()) $rules .= " ".strtolower($this->GetScheduler()); if ($this->GetBandwidth()) $rules .= " bandwidth ".trim($this->GetBandwidth()); if ($this->GetBwscale()) $rules .= $this->GetBwscale(); if ($this->GetTbrConfig()) $rules .= " tbrsize ".$this->GetTbrConfig(); if (count($this->queues)) { $i = count($this->queues); $rules .= " queue { "; foreach ($this->queues as $qkey => $qnone) { if ($i > 1) { $i--; $rules .= " {$qkey}, "; } else $rules .= " {$qkey} "; } $rules .= " } \n"; foreach ($this->queues as $q) { $rules .= $q->build_rules(); } } } $rules .= " \n"; return $rules; } function build_javascript() { $javascript = ""; return $javascript; } function build_shortform() { global $g; $altq =& $this; if ($altq) $scheduler = ": " . $altq->GetScheduler(); $form = ""; $form .= "GetInterface() . "&queue=". $this->GetInterface()."&action=show\">".$this->GetInterface().": ".$scheduler.""; $form .= ""; $form .= ""; $form .= ""; $form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale(); $form .= ""; $form .= ""; $form .= "GetInterface() . "&queue="; $form .= $this->GetQname() . "&action=delete\">"; $form .= ""; $form .= "Disable shaper on interface"; return $form; } /* * For requesting the parameters of the root queue * to the user like the traffic wizard does. */ function build_form() { $form = "
    "; $form .= "Enable/Disable"; $form .= ""; $form .= " GetEnabled() == "on") $form .= " CHECKED"; $form .= " > Enable/disable discipline and its children"; $form .= ""; $form .= "
    Name"; $form .= ""; $form .= "".$this->GetQname().""; $form .= ""; $form .= "Scheduler Type "; $form .= ""; $form .= ""; $form .= ""; $form .= "
    "; $form .= "NOTE: Changing this changes all child queues!"; $form .= " Beware you can lose information."; $form .= ""; $form .= ""; $form .= "Bandwidth"; $form .= ""; $form .= "GetBandwidth() . "\">"; $form .= ""; $form .= ""; $form .= "Queue Limit"; $form .= ""; $form .= "GetQlimit(); $form .= "\">"; $form .= ""; $form .= "TBR Size"; $form .= ""; $form .= "GetTbrConfig(); $form .= "\">"; $form .= "
    "; $form .= "Adjusts the size, in bytes, of the token bucket regulator. "; $form .= "If not specified, heuristics based on the interface "; $form .= "bandwidth are used to determine the size."; $form .= ""; $form .= "GetInterface() . "\">"; $form .= "GetQname()."\" >"; return $form; } function update_altq_queue_data(&$data) { $this->ReadConfig($data); } /* * Should call on each of it queues and subqueues * the same function much like build_rules(); */ function wconfig() { $cflink = &get_reference_to_me_in_config($this->GetLink()); if (!is_array($cflink)) $cflink = array(); $cflink['interface'] = $this->GetInterface(); $cflink['name'] = $this->GetQname(); $cflink['scheduler'] = $this->GetScheduler(); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['tbrconfig'] = trim($this->GetTbrConfig()); if (empty($cflink['tbrconfig'])) unset($cflink['tbrconfig']); $cflink['enabled'] = $this->GetEnabled(); if (empty($cflink['enabled'])) unset($cflink['enabled']); } } class priq_queue { var $qname; var $qinterface; var $qlimit; var $qpriority; var $description; var $isparent; var $qbandwidth; var $qbandwidthtype; var $qdefault = ""; var $qrio = ""; var $qred = ""; var $qecn = ""; var $qack; var $qenabled = ""; var $qparent; var $link; var $available_bw; /* in b/s */ /* This is here to help with form building and building rules/lists */ var $subqueues = array(); /* Accesor functions */ function GetAvailableBandwidth() { return $this->available_bw; } function SetAvailableBandwidth($bw) { $this->available_bw = $bw; } function SetLink($link) { $this->link = $link; } function GetLink() { return $this->link; } function &GetParent() { return $this->qparent; } function SetParent(&$parent) { $this->qparent = &$parent; } function GetEnabled() { return $this->qenabled; } function SetEnabled($value) { $this->qenabled = $value; } function CanHaveChildren() { return false; } function CanBeDeleted() { return true; } function GetQname() { return $this->qname; } function SetQname($name) { $this->qname = trim($name); } function GetBandwidth() { return $this->qbandwidth; } function SetBandwidth($bandwidth) { $this->qbandwidth = $bandwidth; } function GetInterface() { return $this->qinterface; } function SetInterface($name) { $this->qinterface = trim($name); } function GetQlimit() { return $this->qlimit; } function SetQlimit($limit) { $this->qlimit = $limit; } function GetQpriority() { return $this->qpriority; } function SetQpriority($priority) { $this->qpriority = $priority; } function GetDescription() { return $this->description; } function SetDescription($str) { $this->description = trim($str); } function GetFirstime() { return $this->firsttime; } function SetFirsttime($number) { $this->firsttime = $number; } function GetBwscale() { return $this->qbandwidthtype; } function SetBwscale($scale) { $this->qbandwidthtype = $scale; } function GetDefault() { return $this->qdefault; } function SetDefault($value = false) { $this->qdefault = $value; altq_set_default_queue($this->GetInterface(), "true"); } function GetRed() { return $this->qred; } function SetRed($red = false) { $this->qred = $red; } function GetRio() { return $this->qrio; } function SetRio($rio = false) { $this->qrio = $rio; } function GetEcn() { return $this->qecn; } function SetEcn($ecn = false) { $this->qecn = $ecn; } function GetAck() { return $this->qack; } function SetAck($ack = false) { $this->qack = $ack; } function build_javascript() { $javascript = ""; return $javascript; } function &add_queue($interface, &$qname, &$path, &$input_errors) { return; } /* * Currently this will not be called unless we decide to clone a whole * queue tree on the 'By Queues' view or support drag&drop on the tree/list */ function copy_queue($interface, &$cflink) { $cflink['name'] = $this->GetQname(); $cflink['interface'] = $interface; $cflink['qlimit'] = $this->GetQlimit(); $cflink['priority'] = $this->GetQpriority(); $cflink['description'] = $this->GetDescription(); $cflink['enabled'] = $this->GetEnabled(); $cflink['default'] = $this->GetDefault(); $cflink['red'] = $this->GetRed(); $cflink['rio'] = $this->GetRio(); $cflink['ecn'] = $this->GetEcn(); if (is_array($this->subqueues)) { $cflinkp['queue'] = array(); foreach ($this->subqueues as $q) { $cflink['queue'][$q->GetQname()] = array(); $q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]); } } } function clean_queue($sched) { clean_child_queues($sched, $this->GetLink()); if (is_array($this->subqueues)) { foreach ($this->subqueues as $q) $q->clean_queue($sched); } } function &get_queue_list(&$qlist) { $qlist[$this->GetQname()] = & $this; if (is_array($this->subqueues)) { foreach ($this->subqueues as $queue) $queue->get_queue_list($qlist); } } function delete_queue() { unref_on_altq_queue_list($this->GetQname()); if ($this->GetDefault()) altq_set_default_queue($this->GetInterface(), "false"); cleanup_queue_from_rules($this->GetQname()); unset_object_by_reference($this->GetLink()); } function delete_all() { if (count($this->subqueues)) { foreach ($this->subqueues as $q) { $q->delete_all(); unset_object_by_reference($q->GetLink()); unset($q); } unset($this->subqueues); } } function &find_queue($interface, $qname) { if ($qname == $this->GetQname()) return $this; } function find_parentqueue($interface, $qname) { return; } function validate_input($data, &$input_errors) { $reqdfields[] = "name"; $reqdfieldsn[] = "Name"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if ($data['priority'] && (!is_numeric($data['priority']) || ($data['priority'] < 1) || ($data['priority'] > 15))) { $input_errors[] = "The priority must be an integer between 1 and 15."; } if ($data['qlimit'] && (!is_numeric($data['qlimit']))) $input_errors[] = "Queue limit must be an integer"; if ($data['qlimit'] < 0) $input_errors[] = "Queue limit must be positive"; if (!preg_match("/^[a-zA-Z0-9_-]*$/", $data['name'])) $input_errors[] = "Queue names must be alphanumeric and _ or - only."; } function ReadConfig(&$q) { if (isset($q['name'])) $this->SetQname($q['name']); if (isset($q['interface'])) $this->SetInterface($q['interface']); if ($q['bandwidth'] <> "") { $this->SetBandwidth($q['bandwidth']); if ($q['bandwidthtype'] <> "") $this->SetBwscale($q['bandwidthtype']); } if (!empty($q['qlimit'])) $this->SetQlimit($q['qlimit']); else $this->SetQlimit(""); // Default if (!empty($q['priority'])) $this->SetQPriority($q['priority']); else $this->SetQpriority(""); if (!empty($q['description'])) $this->SetDescription($q['description']); else $this->SetDescription(""); if (!empty($q['red'])) $this->SetRed($q['red']); else $this->SetRed(); if (!empty($q['rio'])) $this->SetRio($q['rio']); else $this->SetRio(); if (!empty($q['ecn'])) $this->SetEcn($q['ecn']); else $this->SetEcn(); if (!empty($q['default'])) $this->SetDefault($q['default']); else $this->SetDefault(); if (!empty($q['enabled'])) $this->SetEnabled($q['enabled']); else $this->SetEnabled(""); } function build_tree() { $tree = "
  • GetInterface()."&queue=". $this->GetQname()."&action=show"; $tree .= "\" "; $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) $tree .= " class=\"navlnk\""; $tree .= " >" . $this->GetQname() . ""; /* * Not needed here! * if (is_array($queues) { * $tree .= ""; * } */ $tree .= "
  • "; return $tree; } /* Should return something like: * queue $qname on $qinterface bandwidth .... */ function build_rules() { $pfq_rule = " queue ". $this->qname; if ($this->GetInterface()) $pfq_rule .= " on ".get_real_interface($this->GetInterface()); $tmpvalue = $this->GetQpriority(); if (!empty($tmpvalue)) $pfq_rule .= " priority ".$this->GetQpriority(); $tmpvalue = $this->GetQlimit(); if (!empty($tmpvalue)) $pfq_rule .= " qlimit " . $this->GetQlimit(); if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault()) { $pfq_rule .= " priq ( "; $tmpvalue = $this->GetRed(); if (!empty($tmpvalue)) { $comma = 1; $pfq_rule .= " red "; } $tmpvalue = $this->GetRio(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " rio "; } $tmpvalue = $this->GetEcn(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " ecn "; } $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $pfq_rule .= " default "; } $pfq_rule .= " ) "; } $pfq_rule .= " \n"; return $pfq_rule; } /* * To return the html form to show to user * for getting the parameters. * Should do even for first time when the * object is created and later when we may * need to update it. */ function build_form() { $form = "
    "; $form .= "Enable/Disable"; $form .= ""; $form .= " GetEnabled() == "on") $form .= " CHECKED"; $form .= " > Enable/Disable queue and its childs"; $form .= ""; $form .= ""; $form .= ""; $form .= "Queue Name"; $form .= "GetQname()); $form .= "\">"; $form .= "
    Enter the name of the queue here. Do not use spaces and limit the size to 15 characters."; $form .= ""; $form .= ""; $form .= "Priority"; $form .= " GetQpriority()); $form .= "\">"; $form .= "
    For hfsc, the range is 0 to 7. The default is 1. Hfsc queues with a higher priority are preferred in the case of overload."; $form .= ""; $form .= ""; $form .= "Queue limit"; $form .= " GetQlimit()); $form .= "\">"; $form .= "
    Queue limit in packets per second."; $form .= ""; $form .= ""; $form .= "Scheduler options"; $form .= ""; $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) { $form .= "GetRed(); if(!empty($tmpvalue)) $form .= " CHECKED"; $form .= "> Random Early Detection
    "; $form .= "GetRio(); if(!empty($tmpvalue)) $form .= " CHECKED"; $form .= "> Random Early Detection In and Out
    "; $form .= "GetEcn(); if(!empty($tmpvalue)) $form .= " CHECKED"; $form .= "> Explicit Congestion Notification
    "; $form .= "
    Select options for this queue"; $form .= ""; $form .= "Description"; $form .= ""; $form .= "GetDescription() . "\" >"; $form .= ""; $form .= "GetInterface()."\">"; return $form; } function build_shortform() { /* XXX: Hacks in site. Mostly layer violations! */ global $g, $altq_list_queues; $altq =& $altq_list_queues[$this->GetInterface()]; if ($altq) $scheduler = ": " . $altq->GetScheduler(); $form = ""; $form .= "GetInterface() . "&queue=" . $this->GetInterface()."&action=show\">".$this->GetInterface().": ".$scheduler.""; $form .= ""; /* * XXX: Hack in sight maybe fix with a class that wraps all * of this layer violations */ $form .= ""; $form .= ""; $form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale(); $form .= ""; $form .= ""; $tmpvalue = $this->GetQpriority(); if (!empty($tmpvalue)) $form .= "Priority: on "; $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) $form .= "Default: on "; $form .= ""; $form .= "GetInterface() . "&queue="; $form .= $this->GetQname() . "&action=delete\">"; $form .= ""; $form .= "Delete queue from interface"; return $form; } function update_altq_queue_data(&$q) { $this->ReadConfig($q); } function wconfig() { $cflink =& get_reference_to_me_in_config($this->GetLink()); if (!is_array($cflink)) $cflink = array(); $cflink['name'] = $this->GetQname(); $cflink['interface'] = $this->GetInterface(); $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = trim($this->GetQpriority()); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['description'] = trim($this->GetDescription()); if (empty($cflink['description'])) unset($cflink['description']); $cflink['enabled'] = trim($this->GetEnabled()); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = trim($this->GetDefault()); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = trim($this->GetRio()); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); } } class hfsc_queue extends priq_queue { /* realtime */ var $realtime; var $r_m1; var $r_d; var $r_m2; /* linkshare */ var $linkshare; var $l_m1; var $l_d; var $l_m2; /* upperlimit */ var $upperlimit; var $u_m1; var $u_d; var $u_m2; /* * HFSC can have nested queues. */ function CanHaveChildren() { return true; } function GetRealtime() { return $this->realtime; } function GetR_m1() { return $this->r_m1; } function GetR_d() { return $this->r_d; } function GetR_m2() { return $this->r_m2; } function SetRealtime() { $this->realtime = "on"; } function DisableRealtime() { $this->realtime = ""; } function SetR_m1($value) { $this->r_m1 = $value; } function SetR_d($value) { $this->r_d = $value; } function SetR_m2($value) { $this->r_m2 = $value; } function GetLinkshare() { return $this->linkshare; } function DisableLinkshare() { $this->linkshare = ""; } function GetL_m1() { return $this->l_m1; } function GetL_d() { return $this->l_d; } function GetL_m2() { return $this->l_m2; } function SetLinkshare() { $this->linkshare = "on"; } function SetL_m1($value) { $this->l_m1 = $value; } function SetL_d($value) { $this->l_d = $value; } function SetL_m2($value) { $this->l_m2 = $value; } function GetUpperlimit() { return $this->upperlimit; } function GetU_m1() { return $this->u_m1; } function GetU_d() { return $this->u_d; } function GetU_m2() { return $this->u_m2; } function SetUpperlimit() { $this->upperlimit = "on"; } function DisableUpperlimit() { $this->upperlimit = ""; } function SetU_m1($value) { $this->u_m1 = $value; } function SetU_d($value) { $this->u_d = $value; } function SetU_m2($value) { $this->u_m2 = $value; } function &add_queue($interface, &$qname, &$path, &$input_errors) { if (!is_array($this->subqueues)) $this->subqueues = array(); $q =& new hfsc_queue(); $q->SetInterface($this->GetInterface()); $q->SetParent(&$this); $q->ReadConfig($qname); $q->validate_input($qname, $input_errors); if (count($input_errors)) { return $q; } $q->SetEnabled("on"); $q->SetLink($path); switch ($q->GetBwscale()) { case "%": $myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100; break; default: $myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale()); break; } $q->SetAvailableBandwidth($myBw); $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw); $this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue() ref_on_altq_queue_list($this->GetQname(), $q->GetQname()); if (is_array($qname['queue'])) { foreach ($qname['queue'] as $key1 => $que) { array_push($path, $key1); $q->add_queue($q->GetInterface(), &$que, &$path, $input_errors); array_pop($path); } } return $q; } function copy_queue($interface, &$cflink) { $cflink['name'] = $this->GetQname(); $cflink['interface'] = $interface; $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = trim($this->GetQpriority()); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['description'] = trim($this->GetDescription()); if (empty($cflink['description'])) unset($cflink['description']); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = trim($this->GetEnabled()); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = trim($this->GetDefault()); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = trim($this->GetRio()); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); if ($this->GetLinkshare() <> "") { if ($this->GetL_m1() <> "") { $cflink['linkshare1'] = $this->GetL_m1(); $cflink['linkshare2'] = $this->GetL_d(); $cflink['linkshare'] = "on"; } else { unset($cflink['linkshare1']); unset($cflink['linkshare2']); unset($cflink['linkshare']); } if ($this->GetL_m2() <> "") { $cflink['linkshare3'] = $this->GetL_m2(); $cflink['linkshare'] = "on"; } else { unset($cflink['linkshare3']); unset($cflink['linkshare']); } } if ($this->GetRealtime() <> "") { if ($this->GetR_m1() <> "") { $cflink['realtime1'] = $this->GetR_m1(); $cflink['realtime2'] = $this->GetR_d(); $cflink['realtime'] = "on"; } else { unset($cflink['realtime1']); unset($cflink['realtime2']); unset($cflink['realtime']); } if ($this->GetR_m2() <> "") { $cflink['realtime3'] = $this->GetR_m2(); $cflink['realtime'] = "on"; } else { unset($cflink['realtime3']); unset($cflink['realtime']); } } if ($this->GetUpperlimit() <> "") { if ($this->GetU_m1() <> "") { $cflink['upperlimit1'] = $this->GetU_m1(); $cflink['upperlimit2'] = $this->GetU_d(); $cflink['upperlimit'] = "on"; } else { unset($cflink['upperlimit']); unset($cflink['upperlimit1']); unset($cflink['upperlimit2']); } if ($this->GetU_m2() <> "") { $cflink['upperlimit3'] = $this->GetU_m2(); $cflink['upperlimit'] = "on"; } else { unset($cflink['upperlimit3']); unset($cflink['upperlimit']); } } if (is_array($this->subqueues)) { $cflinkp['queue'] = array(); foreach ($this->subqueues as $q) { $cflink['queue'][$q->GetQname()] = array(); $q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]); } } } function delete_queue() { unref_on_altq_queue_list($this->GetQname()); $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) altq_set_default_queue($this->GetInterface(), "false"); cleanup_queue_from_rules($this->GetQname()); $parent =& $this->GetParent(); foreach ($this->subqueues as $q) { $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth()); $q->delete_queue(); } unset_object_by_reference($this->GetLink()); } /* * Should search even its children */ function &find_queue($interface, $qname) { if ($qname == $this->GetQname()) return $this; foreach ($this->subqueues as $q) { $result =& $q->find_queue("", $qname); if ($result) return $result; } } function &find_parentqueue($interface, $qname) { if ($this->subqueues[$qname]) return $this; foreach ($this->subqueues as $q) { $result = $q->find_parentqueue("", $qname); if ($result) return $result; } } function validate_input($data, &$input_errors) { parent::validate_input($data, $input_errors); $reqdfields[] = "bandwidth"; $reqdfieldsn[] = "Bandwidth"; $reqdfields[] = "bandwidthtype"; $reqdfieldsn[] = "Bandwidthtype"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if (isset($data['linkshare3']) && $data['linkshare3'] <> "") { if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) $input_errors[] = "Bandwidth must be an integer."; if ($data['bandwidth'] < 0) $input_errors[] = "Bandwidth cannot be negative."; if ($data['bandwidthtype'] == "%") { if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) $input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds."; } /* $parent =& $this->GetParent(); switch ($data['bandwidthtype']) { case "%": $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100; default: $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']); break; } if ($parent->GetAvailableBandwidth() < $myBw) $input_errors[] = "The sum of children bandwidth exceeds that of the parent."; */ } if ($data['upperlimit1'] <> "" && $data['upperlimit2'] == "") $input_errors[] = ("upperlimit service curve defined but missing (d) value"); if ($data['upperlimit2'] <> "" && $data['upperlimit1'] == "") $input_errors[] = ("upperlimit service curve defined but missing initial bandwidth (m1) value"); if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1'])) $input_errors[] = ("upperlimit m1 value needs to be Kb, Mb, Gb, or %"); if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2'])) $input_errors[] = ("upperlimit d value needs to be numeric"); if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3'])) $input_errors[] = ("upperlimit m2 value needs to be Kb, Mb, Gb, or %"); /* if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") { $bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']); $bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']); if (floatval($bw_1) < floatval($bw_2)) $input_errors[] = ("upperlimit m1 cannot be smaller than m2"); if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) $input_errors[] = ("upperlimit specification excedd 80% of allowable allocation."); } */ if ($data['linkshare1'] <> "" && $data['linkshare2'] == "") $input_errors[] = ("linkshare service curve defined but missing (d) value"); if ($data['linkshare2'] <> "" && $data['linkshare1'] == "") $input_errors[] = ("linkshare service curve defined but missing initial bandwidth (m1) value"); if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1'])) $input_errors[] = ("linkshare m1 value needs to be Kb, Mb, Gb, or %"); if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2'])) $input_errors[] = ("linkshare d value needs to be numeric"); if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3'])) $input_errors[] = ("linkshare m2 value needs to be Kb, Mb, Gb, or %"); if ($data['realtime1'] <> "" && $data['realtime2'] == "") $input_errors[] = ("realtime service curve defined but missing (d) value"); if ($data['realtime2'] <> "" && $data['realtime1'] == "") $input_errors[] = ("realtime service curve defined but missing initial bandwidth (m1) value"); /* if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) { $bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']); $bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']); if (floatval($bw_1) < floatval($bw_2)) $input_errors[] = ("linkshare m1 cannot be smaller than m2"); if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) $input_errors[] = ("linkshare specification excedd 80% of allowable allocation."); } */ if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1'])) $input_errors[] = ("realtime m1 value needs to be Kb, Mb, Gb, or %"); if ($data['realtime2'] <> "" && !is_numeric($data['realtime2'])) $input_errors[] = ("realtime d value needs to be numeric"); if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3'])) $input_errors[] = ("realtime m2 value needs to be Kb, Mb, Gb, or %"); /* if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) { $bw_1 = get_hfsc_bandwidth($this, $data['realtime1']); $bw_2 = get_hfsc_bandwidth($this, $data['realtime3']); if (floatval($bw_1) < floatval($bw_2)) $input_errors[] = ("realtime m1 cannot be smaller than m2"); if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) $input_errors[] = ("realtime specification excedd 80% of allowable allocation."); } */ } function ReadConfig(&$cflink) { if (!empty($cflink['linkshare'])) { if (!empty($cflink['linkshare1'])) { $this->SetL_m1($cflink['linkshare1']); $this->SetL_d($cflink['linkshare2']); $this->SetLinkshare(); } if (!empty($cflink['linkshare3'])) { $this->SetL_m2($cflink['linkshare3']); $this->SetLinkshare(); } } else $this->DisableLinkshare(); if (!empty($cflink['realtime'])) { if (!empty($cflink['realtime1'])) { $this->SetR_m1($cflink['realtime1']); $this->SetR_d($cflink['realtime2']); $this->SetRealtime(); } if (!empty($cflink['realtime3'])) { $this->SetR_m2($cflink['realtime3']); $this->SetRealtime(); } } else $this->DisableRealtime(); if (!empty($cflink['upperlimit'])) { if (!empty($cflink['upperlimit1'])) { $this->SetU_m1($cflink['upperlimit1']); $this->SetU_d($cflink['upperlimit2']); $this->SetUpperlimit(); } if (!empty($cflink['upperlimit3'])) { $this->SetU_m2($cflink['upperlimit3']); $this->SetUpperlimit(); } } else $this->DisableUpperlimit(); parent::ReadConfig($cflink); } function build_tree() { $tree = "
  • GetInterface() ."&queue=" . $this->GetQname()."&action=show"; $tree .= "\" "; $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) $tree .= " class=\"navlnk\""; $tree .= " >" . $this->GetQname() . ""; if (is_array($this->subqueues)) { $tree .= ""; } $tree .= "
  • "; return $tree; } /* Even this should take children into consideration */ function build_rules() { $pfq_rule = " queue ". $this->qname; if ($this->GetInterface()) $pfq_rule .= " on ".get_real_interface($this->GetInterface()); if ($this->GetBandwidth() && $this->GetBwscale()) $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale(); $tmpvalue = $this->GetQlimit(); if (!empty($tmpvalue)) $pfq_rule .= " qlimit " . $this->GetQlimit(); if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") { $pfq_rule .= " hfsc ( "; $tmpvalue = $this->GetRed(); if (!empty($tmpvalue)) { $comma = 1; $pfq_rule .= " red "; } $tmpvalue = $this->GetRio(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " rio "; } $tmpvalue = $this->GetEcn(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " ecn "; } $tmpvalue = $this->GetDefault(); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " default "; } if ($this->GetRealtime() <> "") { if ($comma) $pfq_rule .= " , "; if ($this->GetR_m1() <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "") $pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") "; else if ($this->GetR_m2() <> "") $pfq_rule .= " realtime " . $this->GetR_m2(); $comma = 1; } if ($this->GetLinkshare() <> "") { if ($comma) $pfq_rule .= " ,"; if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "") $pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") "; else if ($this->GetL_m2() <> "") $pfq_rule .= " linkshare " . $this->GetL_m2() . " "; $comma = 1; } if ($this->GetUpperlimit() <> "") { if ($comma) $pfq_rule .= " ,"; if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "") $pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") "; else if ($this->GetU_m2() <> "") $pfq_rule .= " upperlimit " . $this->GetU_m2() . " "; } $pfq_rule .= " ) "; } if (count($this->subqueues)) { $i = count($this->subqueues); $pfq_rule .= " { "; foreach ($this->subqueues as $qkey => $qnone) { if ($i > 1) { $i--; $pfq_rule .= " {$qkey}, "; } else $pfq_rule .= " {$qkey} "; } $pfq_rule .= " } \n"; foreach ($this->subqueues as $q) $pfq_rule .= $q->build_rules(); } $pfq_rule .= " \n"; return $pfq_rule; } function build_javascript() { $javascript = parent::build_javascript(); $javascript .= ""; return $javascript; } function build_form() { $form = ""; $form .= "Bandwidth"; $form .= " GetBandwidth()); $form .= "\">"; $form .= "
    "; $form .= "Choose the amount of bandwidth for this queue"; $form .= ""; $form .= parent::build_form(); $form .= ""; $form .= "Service Curve (sc)"; $form .= ""; $form .= ""; $form .= ""; $form .= ""; $form .= ""; $form .= ""; $form .= "
     
    m1
    d
    m2
    GetUpperlimit()<> "") $form .= " CHECKED "; $form .= "onChange=\"enable_upperlimit()\"> Upperlimit:GetU_m1()); $form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" "; if ($this->GetUpperlimit() == "") $form .= " disabled"; $form .= ">GetU_d()); $form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" "; if ($this->GetUpperlimit() == "") $form .= " disabled"; $form .= ">GetU_m2()); $form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" "; if ($this->GetUpperlimit() == "") $form .= " disabled"; $form .= ">The maximum allowed bandwidth for the queue.
    GetRealtime() <> "") $form .= " CHECKED "; $form .= "onChange=\"enable_realtime()\"> Real time:GetR_m1()); $form .= "\" id=\"realtime1\" name=\"realtime1\" "; if ($this->GetRealtime() == "") $form .= " disabled"; $form .= ">GetR_d()); $form .= "\" id=\"realtime2\" name=\"realtime2\" "; if ($this->GetRealtime() == "") $form .= " disabled"; $form .= ">GetR_m2()); $form .= "\" id=\"realtime3\" name=\"realtime3\" "; if ($this->GetRealtime() == "") $form .= " disabled"; $form .= ">The minimum required bandwidth for the queue.
    GetLinkshare() <> "") $form .= " CHECKED "; $form .= "onChange=\"enable_linkshare()\"> Link share:GetL_m1()); $form .= "\" id=\"linkshare1\" name=\"linkshare1\" "; if ($this->GetLinkshare() == "") $form .= " disabled"; $form .= ">GetL_d()); $form .= "\" id=\"linkshare2\" name=\"linkshare2\" "; if ($this->GetLinkshare() == "") $form .= " disabled"; $form .= ">GetL_m2()); $form .= "\" id=\"linkshare3\" name=\"linkshare3\" "; if ($this->GetLinkshare() == "") $form .= " disabled"; $form .= ">The bandwidth share of a backlogged queue - this overrides priority.

    "; $form .= "The format for service curve specifications is (m1, d, m2). m2 controls"; $form .= "the bandwidth assigned to the queue. m1 and d are optional and can be"; $form .= "used to control the initial bandwidth assignment. For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value"; $form .= "given in m2."; $form .= "
    "; $form .= ""; return $form; } function update_altq_queue_data(&$data) { $this->ReadConfig($data); } function wconfig() { $cflink =& get_reference_to_me_in_config($this->GetLink()); if (!is_array($cflink)) $cflink = array(); $cflink['name'] = $this->GetQname(); $cflink['interface'] = $this->GetInterface(); $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = $this->GetQpriority(); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['description'] = $this->GetDescription(); if (empty($cflink['description'])) unset($cflink['description']); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = $this->GetEnabled(); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = $this->GetDefault(); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = $this->GetRio(); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); if ($this->GetLinkshare() <> "") { if ($this->GetL_m1() <> "") { $cflink['linkshare1'] = $this->GetL_m1(); $cflink['linkshare2'] = $this->GetL_d(); $cflink['linkshare'] = "on"; } else { unset($cflink['linkshare']); unset($cflink['linkshare1']); unset($cflink['linkshare2']); } if ($this->GetL_m2() <> "") { $cflink['linkshare3'] = $this->GetL_m2(); $cflink['linkshare'] = "on"; } else { unset($cflink['linkshare']); unset($cflink['linkshare3']); } } else { unset($cflink['linkshare']); unset($cflink['linkshare1']); unset($cflink['linkshare2']); unset($cflink['linkshare3']); } if ($this->GetRealtime() <> "") { if ($this->GetR_m1() <> "") { $cflink['realtime1'] = $this->GetR_m1(); $cflink['realtime2'] = $this->GetR_d(); $cflink['realtime'] = "on"; } else { unset($cflink['realtime']); unset($cflink['realtime1']); unset($cflink['realtime2']); } if ($this->GetR_m2() <> "") { $cflink['realtime3'] = $this->GetR_m2(); $cflink['realtime'] = "on"; } else { unset($cflink['realtime']); unset($cflink['realtime3']); } } else { unset($cflink['realtime']); unset($cflink['realtime1']); unset($cflink['realtime2']); unset($cflink['realtime3']); } if ($this->GetUpperlimit() <> "") { if ($this->GetU_m1() <> "") { $cflink['upperlimit1'] = $this->GetU_m1(); $cflink['upperlimit2'] = $this->GetU_d(); $cflink['upperlimit'] = "on"; } else { unset($cflink['upperlimit']); unset($cflink['upperlimit1']); unset($cflink['upperlimit2']); } if ($this->GetU_m2() <> "") { $cflink['upperlimit3'] = $this->GetU_m2(); $cflink['upperlimit'] = "on"; } else { unset($cflink['upperlimit']); unset($cflink['upperlimit3']); } } else { unset($cflink['upperlimit']); unset($cflink['upperlimit1']); unset($cflink['upperlimit2']); unset($cflink['upperlimit3']); } } } class cbq_queue extends priq_queue { var $qborrow = ""; function GetBorrow() { return $this->qborrow; } function SetBorrow($borrow) { $this->qborrow = $borrow; } function CanHaveChildren() { return true; } function &add_queue($interface, &$qname, &$path, &$input_errors) { if (!is_array($this->subqueues)) $this->subqueues = array(); $q =& new cbq_queue(); $q->SetInterface($this->GetInterface()); $q->SetParent(&$this); $q->ReadConfig($qname); $q->validate_input($qname, $input_errors); if (count($input_errors)) { return $q; } switch ($q->GetBwscale()) { case "%": $myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100; break; default: $myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale()); break; } $q->SetAvailableBandwidth($myBw); $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw); $q->SetEnabled("on"); $q->SetLink($path); $this->subqueues[$q->GetQName()] = &$q; ref_on_altq_queue_list($this->GetQname(), $q->GetQname()); if (is_array($qname['queue'])) { foreach ($qname['queue'] as $key1 => $que) { array_push($path, $key1); $q->add_queue($q->GetInterface(), &$que, &$path, $input_errors); array_pop($path); } } return $q; } function copy_queue($interface, &$cflink) { $cflink['interface'] = $interface; $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($clink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = trim($this->GetQpriority()); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['name'] = $this->GetQname(); $cflink['description'] = trim($this->GetDescription()); if (empty($cflink['description'])) unset($cflink['description']); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = trim($this->GetEnabled()); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = trim($this->GetDefault()); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = trim($this->GetRio()); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); $cflink['borrow'] = trim($this->GetBorrow()); if (empty($cflink['borrow'])) unset($cflink['borrow']); if (is_array($this->queues)) { $cflinkp['queue'] = array(); foreach ($this->subqueues as $q) { $cflink['queue'][$q->GetQname()] = array(); $q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]); } } } /* * Should search even its children */ function &find_queue($interface, $qname) { if ($qname == $this->GetQname()) return $this; foreach ($this->subqueues as $q) { $result =& $q->find_queue("", $qname); if ($result) return $result; } } function &find_parentqueue($interface, $qname) { if ($this->subqueues[$qname]) return $this; foreach ($this->subqueues as $q) { $result = $q->find_parentqueue("", $qname); if ($result) return $result; } } function delete_queue() { unref_on_altq_queue_list($this->GetQname()); if ($this->GetDefault()) altq_set_default_queue($this->GetInterface(), "false"); cleanup_queue_from_rules($this->GetQname()); foreach ($this->subqueues as $q) { $this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth()); $q->delete_queue(); } unset_object_by_reference($this->GetLink()); } function validate_input($data, &$input_errors) { parent::validate_input($data, $input_errors); if ($data['priority'] > 7) $input_errors[] = "Priority must be an integer between 1 and 7."; $reqdfields[] = "bandwidth"; $reqdfieldsn[] = "Bandwidth"; $reqdfields[] = "bandwidthtype"; $reqdfieldsn[] = "Bandwidthtype"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) $input_errors[] = "Bandwidth must be an integer."; if ($data['bandwidth'] < 0) $input_errors[] = "Bandwidth cannot be negative."; if ($data['bandwidthtype'] == "%") { if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) $input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds."; } /* $parent =& $this->GetParent(); switch ($data['bandwidthtype']) { case "%": $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100; default: $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']); break; } if ($parent->GetAvailableBandwidth() < floatval($myBw)) $input_errors[] = "The sum of the children bandwidth exceeds that of the parent."; */ } function ReadConfig(&$q) { parent::ReadConfig($q); if (!empty($q['borrow'])) $this->SetBorrow("on"); } function build_javascript() { return parent::build_javascript(); } function build_tree() { $tree = "
  • GetInterface()."&queue=" . $this->GetQname()."&action=show"; $tree .= "\" "; $tmpvalue = trim($this->GetDefault()); if (!empty($tmpvalue)) $tree .= " class=\"navlnk\""; $tree .= " >" . $this->GetQname() . ""; if (is_array($this->subqueues)) { $tree .= ""; } $tree .= "
  • "; return $tree; } /* Even this should take children into consideration */ function build_rules() { $pfq_rule = "queue ". $this->qname; if ($this->GetInterface()) $pfq_rule .= " on ".get_real_interface($this->GetInterface()); if ($this->GetBandwidth() && $this->GetBwscale()) $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale(); $tmpvalue = $this->GetQpriority(); if (!empty($tmpvalue)) $pfq_rule .= " priority " . $this->GetQpriority(); $tmpvalue = trim($this->GetQlimit()); if (!empty($tmpvalue)) $pfq_rule .= " qlimit " . $this->GetQlimit(); if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow()) { $pfq_rule .= " cbq ( "; $tmpvalue = trim($this->GetRed()); if (!empty($tmpvalue)) { $comma = 1; $pfq_rule .= " red "; } $tmpvalue = trim($this->GetRio()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " rio "; } $tmpvalue = trim($this->GetEcn()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " ecn "; } $tmpvalue = trim($this->GetDefault()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " default "; } $tmpvalue = trim($this->GetBorrow()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= ", "; $pfq_rule .= " borrow "; } $pfq_rule .= " ) "; } if (count($this->subqueues)) { $i = count($this->subqueues); $pfq_rule .= " { "; foreach ($this->subqueues as $qkey => $qnone) { if ($i > 1) { $i--; $pfq_rule .= " {$qkey}, "; } else $pfq_rule .= " {$qkey} "; } $pfq_rule .= " } \n"; foreach ($this->subqueues as $q) $pfq_rule .= $q->build_rules(); } $pfq_rule .= " \n"; return $pfq_rule; } function build_form() { $form = ""; $form .= "Bandwidth"; $form .= " GetBandwidth() > 0) $form .= htmlspecialchars($this->GetBandwidth()); $form .= "\">"; $form .= "
    "; $form .= "Choose the amount of bandwidth for this queue"; $form .= ""; $form .= parent::build_form(); $form .= "Scheduler specific options"; $form .= "GetBorrow() == "on") $form .= " CHECKED "; $form .= "> Borrow from other queues when available
    "; return $form; } function update_altq_queue_data(&$data) { $this->ReadConfig($data); } function wconfig() { $cflink =& get_reference_to_me_in_config($this->GetLink()); if (!is_array($cflink)) $cflink = array(); $cflink['interface'] = $this->GetInterface(); $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = $this->GetQpriority(); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['name'] = $this->GetQname(); $cflink['description'] = $this->GetDescription(); if (empty($cflink['description'])) unset($cflink['description']); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = trim($this->GetEnabled()); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = trim($this->GetDefault()); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = trim($this->GetRio()); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); $cflink['borrow'] = trim($this->GetBorrow()); if (empty($cflink['borrow'])) unset($cflink['borrow']); } } class fairq_queue extends priq_queue { var $hogs; var $buckets; function GetBuckets() { return $this->buckets; } function SetBuckets($buckets) { $this->buckets = $buckets; } function GetHogs() { return $this->hogs; } function SetHogs($hogs) { $this->hogs = $hogs; } function CanHaveChildren() { return false; } function copy_queue($interface, &$cflink) { $cflink['interface'] = $interface; $cflink['qlimit'] = $this->GetQlimit(); $cflink['priority'] = $this->GetQpriority(); $cflink['name'] = $this->GetQname(); $cflink['description'] = $this->GetDescription(); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = $this->GetEnabled(); $cflink['default'] = $this->GetDefault(); $cflink['red'] = $this->GetRed(); $cflink['rio'] = $this->GetRio(); $cflink['ecn'] = $this->GetEcn(); $cflink['buckets'] = $this->GetBuckets(); $cflink['hogs'] = $this->GetHogs(); } /* * Should search even its children */ function &find_queue($interface, $qname) { if ($qname == $this->GetQname()) return $this; } function find_parentqueue($interface, $qname) { return; } function delete_queue() { unref_on_altq_queue_list($this->GetQname()); if ($this->GetDefault()) altq_set_default_queue($this->GetInterface(), "false"); cleanup_queue_from_rules($this->GetQname()); unset_object_by_reference($this->GetLink()); } function validate_input($data, &$input_errors) { parent::validate_input($data, $input_errors); if ($data['priority'] > 255) $input_errors[] = "Priority must be an integer between 1 and 255."; $reqdfields[] = "bandwidth"; $reqdfieldsn[] = "Bandwidth"; $reqdfields[] = "bandwidthtype"; $reqdfieldsn[] = "Bandwidthtype"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) $input_errors[] = "Bandwidth must be an integer."; if ($data['bandwidth'] < 0) $input_errors[] = "Bandwidth cannot be negative."; if ($data['bandwidthtype'] == "%") { if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) $input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds."; } /* $parent =& $this->GetParent(); switch ($data['bandwidthtype']) { case "%": $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100; default: $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']); break; } if ($parent->GetAvailableBandwidth() < floatval($myBw)) $input_errors[] = "The sum of children bandwidth exceeds that of the parent."; */ } function ReadConfig(&$q) { parent::ReadConfig($q); if (!empty($q['buckets'])) $this->SetBuckets($q['buckets']); if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) $this->SetHogs($q['hogs']); } function build_javascript() { return parent::build_javascript(); } function build_tree() { $tree = "
  • GetInterface()."&queue=" . $this->GetQname()."&action=show"; $tree .= "\" "; $tmpvalue = trim($this->GetDefault()); if (!empty($tmpvalue)) $tree .= " class=\"navlnk\""; $tree .= " >" . $this->GetQname() . ""; $tree .= "
  • "; return $tree; } /* Even this should take children into consideration */ function build_rules() { $pfq_rule = "queue ". $this->qname; if ($this->GetInterface()) $pfq_rule .= " on ".get_real_interface($this->GetInterface()); if ($this->GetBandwidth() && $this->GetBwscale()) $pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale(); $tmpvalue = trim($this->GetQpriority()); if (!empty($tmpvalue)) $pfq_rule .= " priority " . $this->GetQpriority(); $tmpvalue = trim($this->GetQlimit()); if (!empty($tmpvalue)) $pfq_rule .= " qlimit " . $this->GetQlimit(); if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBuckets() || $this->GetHogs()) { $pfq_rule .= " fairq ( "; $tmpvalue = trim($this->GetRed()); if (!empty($tmpvalue)) { $comma = 1; $pfq_rule .= " red "; } $tmpvalue = trim($this->GetRio()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " rio "; } $tmpvalue = trim($this->GetEcn()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " ecn "; } $tmpvalue = trim($this->GetDefault()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= " ,"; $comma = 1; $pfq_rule .= " default "; } $tmpvalue = trim($this->GetBuckets()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= ", "; $pfq_rule .= " buckets " . $this->GetBuckets() . " "; } $tmpvalue = trim($this->GetHogs()); if (!empty($tmpvalue)) { if ($comma) $pfq_rule .= ", "; $pfq_rule .= " hogs " . $this->GetHogs() . " "; } $pfq_rule .= " ) "; } $pfq_rule .= " \n"; return $pfq_rule; } function build_form() { $form = ""; $form .= "Bandwidth"; $form .= " GetBandwidth() > 0) $form .= htmlspecialchars($this->GetBandwidth()); $form .= "\">"; $form .= "
    "; $form .= "Choose the amount of bandwidth for this queue"; $form .= ""; $form .= parent::build_form(); $form .= "Scheduler specific options"; $form .= ""; $form .= ""; $form .= "
    "; $form .= "GetBuckets()); if(!empty($tmpvalue)) $form .= $this->GetBuckets(); $form .= "\"> Number of buckets available.
    GetHogs()); if(!empty($tmpvalue)) $form .= $this->GetHogs(); $form .= "\"> Bandwidth limit for hosts to not saturate link.
    "; return $form; } function update_altq_queue_data(&$data) { $this->ReadConfig($data); } function wconfig() { $cflink =& get_reference_to_me_in_config($this->GetLink()); if (!is_array($cflink)) $cflink = array(); $cflink['interface'] = $this->GetInterface(); $cflink['qlimit'] = trim($this->GetQlimit()); if (empty($cflink['qlimit'])) unset($cflink['qlimit']); $cflink['priority'] = trim($this->GetQpriority()); if (empty($cflink['priority'])) unset($cflink['priority']); $cflink['name'] = $this->GetQname(); $cflink['description'] = trim($this->GetDescription()); if (empty($cflink['description'])) unset($cflink['description']); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = $this->GetEnabled(); if (empty($cflink['enabled'])) unset($cflink['enabled']); $cflink['default'] = trim($this->GetDefault()); if (empty($cflink['default'])) unset($cflink['default']); $cflink['red'] = trim($this->GetRed()); if (empty($cflink['red'])) unset($cflink['red']); $cflink['rio'] = trim($this->GetRio()); if (empty($cflink['rio'])) unset($cflink['rio']); $cflink['ecn'] = trim($this->GetEcn()); if (empty($cflink['ecn'])) unset($cflink['ecn']); $cflink['buckets'] = trim($this->GetBuckets()); if (empty($cflink['buckets'])) unset($cflink['buckets']); $cflink['hogs'] = trim($this->GetHogs()); if (empty($cflink['hogs'])) unset($cflink['hogs']); } } /* * dummynet(4) wrappers. */ /* * List of respective objects! */ $dummynet_pipe_list = array(); class dummynet_class { var $qname; var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */ var $qlimit; var $description; var $qenabled; var $link; var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */ var $plr; var $buckets; /* mask parameters */ var $mask; var $noerror; /* Accessor functions */ function SetLink($link) { $this->link = $link; } function GetLink() { return $this->link; } function Getmask() { return $this->mask; } function SetMask($mask) { $this->mask = $mask; } function &GetParent() { return $this->qparent; } function SetParent(&$parent) { $this->qparent = &$parent; } function GetEnabled() { return $this->qenabled; } function SetEnabled($value) { $this->qenabled = $value; } function CanHaveChildren() { return false; } function CanBeDeleted() { return true; } function GetQname() { return $this->qname; } function SetQname($name) { $this->qname = trim($name); } function GetQlimit() { return $this->qlimit; } function SetQlimit($limit) { $this->qlimit = $limit; } function GetDescription() { return $this->description; } function SetDescription($str) { $this->description = trim($str); } function GetFirstime() { return $this->firsttime; } function SetFirsttime($number) { $this->firsttime = $number; } function GetBuckets() { return $this->buckets; } function SetBuckets($buckets) { $this->buckets = $buckets; } function SetNumber($number) { $this->qnumber = $number; } function GetNumber() { return $this->qnumber; } function GetPlr() { return $this->plr; } function SetPlr($plr) { $this->plr = $plr; } function build_javascript() { return; } /* Do not remove */ function validate_input($data, &$input_errors) { $reqdfields[] = "bandwidth"; $reqdfieldsn[] = "Bandwidth"; $reqdfields[] = "bandwidthtype"; $reqdfieldsn[] = "Bandwidthtype"; $reqdfields[] = "name"; $reqdfieldsn[] = "Name"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if ($data['plr'] && ((!is_numeric($data['plr'])) || ($data['plr'] <= 0 && $data['plr'] > 1))) $input_errors[] = "Plr must be an integer between 1 and 100."; if (($data['buckets'] && (!is_numeric($data['buckets']))) || ($data['buckets'] < 1 && $data['buckets'] > 100)) $input_errors[] = "Buckets must be an integer between 16 and 65535."; if ($data['qlimit'] && (!is_numeric($data['qlimit']))) $input_errors[] = "Queue limit must be an integer"; if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['name'])) $input_errors[] = "Queue names must be alphanumeric and _ or - only."; } } class dnpipe_class extends dummynet_class { var $delay; var $qbandwidth; var $qbandwidthtype; /* This is here to help on form building and building rules/lists */ var $subqueues = array(); function CanHaveChildren() { return true; } function SetDelay($delay) { $this->delay = $delay; } function GetDelay() { return $this->delay; } function GetBwscale() { return $this->qbandwidthtype; } function SetBwscale($scale) { $this->qbandwidthtype = $scale; } function delete_queue() { cleanup_dnqueue_from_rules($this->GetQname()); foreach ($this->subqueues as $q) $q->delete_queue(); unset_dn_object_by_reference($this->GetLink()); mwexec("/sbin/ipfw pipe delete " . $this->GetNumber()); } function GetBandwidth() { return $this->qbandwidth; } function SetBandwidth($bandwidth) { $this->qbandwidth = $bandwidth; } function &add_queue($interface, &$queue, &$path, &$input_errors) { if (!is_array($this->subqueues)) $this->subqueues = array(); $q =& new dnqueue_class(); $q->SetLink($path); $q->SetEnabled("on"); $q->SetPipe($this->GetQname()); $q->SetParent(&$this); $q->ReadConfig($queue); $q->validate_input($queue, $input_errors); if (count($input_errors)) return $q; $this->subqueues[$q->GetQname()] = &$q; return $q; } function &get_queue_list($q = null) { $qlist = array(); $qlist[$this->GetQname()] = $this->GetNumber(); if (is_array($this->subqueues)) { foreach ($this->subqueues as $queue) $queue->get_queue_list(&$qlist); } return $qlist; } /* * Should search even its children */ function &find_queue($pipe, $qname) { if ($qname == $this->GetQname()) return $this; foreach ($this->subqueues as $q) { $result =& $q->find_queue("", $qname); if ($result) return $result; } } function &find_parentqueue($pipe, $qname) { return NULL; } function validate_input($data, &$input_errors) { parent::validate_input($data, $input_errors); if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) $input_errors[] = "Bandwidth must be an integer."; if ($data['delay'] && (!is_numeric($data['delay']))) $input_errors[] = "Delay must be an integer."; } function ReadConfig(&$q) { $this->SetQname($q['name']); $this->SetNumber($q['number']); if (isset($q['bandwidth']) && $q['bandwidth'] <> "") { $this->SetBandwidth($q['bandwidth']); if (isset($q['bandwidthtype']) && $q['bandwidthtype']) $this->SetBwscale($q['bandwidthtype']); } if (isset($q['qlimit']) && $q['qlimit'] <> "") $this->SetQlimit($q['qlimit']); if (isset($q['mask']) && $q['mask'] <> "") $this->SetMask($q['mask']); if (isset($q['buckets']) && $q['buckets'] <> "") $this->SetBuckets($q['buckets']); if (isset($q['plr']) && $q['plr'] <> "") $this->SetPlr($q['plr']); if (isset($q['delay']) && $q['delay'] <> "") $this->SetDelay($q['delay']); if (isset($q['description']) && $q['description'] <> "") $this->SetDescription($q['description']); $this->SetEnabled($q['enabled']); } function build_tree() { $tree = "
  • GetQname() ."&queue=".$this->GetQname() ."&action=show\">"; $tree .= $this->GetQname() . ""; if (is_array($this->subqueues)) { $tree .= ""; } $tree .= "
  • "; return $tree; } function build_rules() { if ($this->GetEnabled() == "") return; $pfq_rule = "\npipe ". $this->GetNumber() . " config "; if ($this->GetBandwidth() && $this->GetBwscale()) $pfq_rule .= " bw ".trim($this->GetBandwidth()).$this->GetBwscale(); 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(); $mask = $this->GetMask(); if (!empty($mask)) { /* XXX TODO extend this to support more complicated masks */ switch ($mask) { case 'srcaddress': $pfq_rule .= " mask src-ip 0xffffffff "; break; case 'dstaddress': $pfq_rule .= " mask dst-ip 0xffffffff "; break; default: break; } $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_form() { $form = "
    "; $form .= "Enable/Disable"; $form .= ""; $form .= " GetEnabled() == "on") $form .= " CHECKED"; $form .= " > Enable/Disable limiter and its childs"; $form .= ""; $form .= "
    Name"; $form .= ""; $form .= "GetQname()."\">"; $form .= ""; $form .= "Bandwidth"; $form .= ""; $form .= "GetBandwidth() . "\">"; $form .= ""; $form .= ""; $form .= "Mask"; $form .= ""; $form .= ""; $form .= " 
    "; $form .= "If 'source' or 'destination' is chosen, \n"; $form .= "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"; $form .= "be created for each source/destination IP address encountered, \n"; $form .= "respectively. This makes it possible to easily specify bandwidth \n"; $form .= "limits per host."; $form .= ""; $form .= "Description"; $form .= ""; $form .= "GetDescription(); $form .= "\">"; $form .= "
    "; $form .= "You may enter a description here "; $form .= "for your reference (not parsed)."; $form .= ""; $form .= ""; $form .= ""; $form .= "
    "; $form .= "

    "; $form .= "

    "; $form .= ""; $form .= "Delay"; $form .= ""; $form .= "GetDelay() . "\">"; $form .= " ms
    Hint: in most cases, you "; $form .= "should specify 0 here (or leave the field empty)"; $form .= "
    "; $form .= ""; $form .= "Packet loss rate"; $form .= ""; $form .= "GetPlr() . "\">"; $form .= " 
    Hint: in most cases, you "; $form .= "should specify 0 here (or leave the field empty)."; $form .= "A value of 0.001 means one packet in 1000 gets dropped"; $form .= ""; $form .= ""; $form .= "Queue Size"; $form .= ""; $form .= "GetQlimit() . "\">"; $form .= " slots
    "; $form .= "Hint: in most cases, you "; $form .= "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first,"; $form .= "then they are delayed by value specified in the Delay field, and then they "; $form .= "are delivered to their destination."; $form .= ""; $form .= ""; $form .= "Bucket Size"; $form .= ""; $form .= "GetBuckets() . "\">"; $form .= " slots
    "; $form .= "Hint: in most cases, you "; $form .= "should leave the field empty. It increases the hash size set."; $form .= ""; return $form; } 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['plr'] = $this->GetPlr(); $cflink['description'] = $this->GetDescription(); $cflink['bandwidth'] = $this->GetBandwidth(); $cflink['bandwidthtype'] = $this->GetBwscale(); $cflink['enabled'] = $this->GetEnabled(); $cflink['buckets'] = $this->GetBuckets(); $cflink['mask'] = $this->GetMask(); $cflink['delay'] = $this->GetDelay(); } } class dnqueue_class extends dummynet_class { var $pipeparent; var $weight; function GetWeight() { return $this->weight; } function SetWeight($weight) { $this->weight = $weight; } function GetPipe() { return $this->pipeparent; } function SetPipe($pipe) { $this->pipeparent = $pipe; } /* Just a stub in case we ever try to call this from the frontend. */ function &add_queue($interface, &$queue, &$path, &$input_errors) { return; } function delete_queue() { cleanup_dnqueue_from_rules($this->GetQname()); unset_dn_object_by_reference($this->GetLink()); mwexec("/sbin/ipfw queue delete " . $this->GetNumber()); } function validate_input($data, &$input_errors) { parent::validate_input($data, $input_errors); if ($data['weight'] && ((!is_numeric($data['weight'])) || ($data['weight'] < 1 && $data['weight'] > 100))) $input_errors[] = "Weight must be an integer between 1 and 100."; } /* * Should search even its children */ function &find_queue($pipe, $qname) { if ($qname == $this->GetQname()) return $this; else return NULL; } function &find_parentqueue($pipe, $qname) { return $this->qparent; } function &get_queue_list(&$qlist) { $qlist[$this->GetQname()] = "?" .$this->GetNumber(); } function ReadConfig(&$q) { $this->SetQname($q['name']); $this->SetNumber($q['number']); if (isset($q['qlimit']) && $q['qlimit'] <> "") $this->SetQlimit($q['qlimit']); if (isset($q['mask']) && $q['mask'] <> "") $this->SetMask($q['mask']); if (isset($q['weight']) && $q['weight'] <> "") $this->SetWeight($q['weight']); if (isset($q['description']) && $q['description'] <> "") $this->SetDescription($q['description']); $this->SetEnabled($q['enabled']); } function build_tree() { $parent =& $this->GetParent(); $tree = "
  • GetQname() ."&queue=" . $this->GetQname() ."&action=show\">"; $tree .= $this->GetQname() . ""; $tree .= "
  • "; 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->GetQimit(); if ($this->GetWeight()) $pfq_rule .= " weight " . $this->GetWeight(); if ($this->GetBuckets()) $pfq_rule .= " buckets " . $this->GetBuckets(); $mask = $this->GetMask(); if (!empty($mask)) { /* XXX TODO extend this to support more complicated masks */ switch ($mask) { case 'srcaddress': $pfq_rule .= " mask src-ip 0xffffffff "; break; case 'dstaddress': $pfq_rule .= " mask dst-ip 0xffffffff "; break; default: break; } $pfq_rule .= "\n"; } return $pfq_rule; } function build_form() { $form = "
    "; $form .= "Enable/Disable"; $form .= ""; $form .= " GetEnabled() == "on") $form .= " CHECKED"; $form .= " > Enable/Disable queue and its childs"; $form .= ""; $form .= "
    Name"; $form .= ""; $form .= "GetQname()."\">"; $form .= ""; $form .= "Mask"; $form .= ""; $form .= ""; $form .= " slots
    "; $form .= "If 'source' or 'destination' is chosen, \n"; $form .= "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"; $form .= "be created for each source/destination IP address encountered, \n"; $form .= "respectively. This makes it possible to easily specify bandwidth \n"; $form .= "limits per host."; $form .= ""; $form .= "Description"; $form .= ""; $form .= "GetDescription(); $form .= "\">"; $form .= "
    "; $form .= "You may enter a description here "; $form .= "for your reference (not parsed)."; $form .= ""; $form .= ""; $form .= ""; $form .= "
    "; $form .= "

    "; $form .= "

    "; $form .= ""; $form .= "Weight"; $form .= ""; $form .= "GetWeight() . "\">"; $form .= " ms
    Hint: For queues under the same parent "; $form .= "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)"; $form .= ""; $form .= ""; $form .= "Packet loss rate"; $form .= ""; $form .= "GetPlr() . "\">"; $form .= " 
    Hint: in most cases, you "; $form .= "should specify 0 here (or leave the field empty)."; $form .= "A value of 0.001 means one packet in 1000 gets dropped"; $form .= ""; $form .= ""; $form .= "Queue Size"; $form .= ""; $form .= "GetQlimit() . "\">"; $form .= " slots
    "; $form .= "Hint: in most cases, you "; $form .= "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "; $form .= "then they are delayed by value specified in the Delay field, and then they "; $form .= "are delivered to their destination."; $form .= ""; $form .= ""; $form .= "Bucket Size"; $form .= ""; $form .= "GetBuckets() . "\">"; $form .= " slots
    "; $form .= "Hint: in most cases, you "; $form .= "should leave the field empty. It increases the hash size set."; $form .= ""; $form .= "GetPipe() . "\">"; return $form; } 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(); $cflink['mask'] = $this->GetMask(); } } // List of layer7 objects $layer7_rules_list = array(); class layer7 { var $rname; //alias var $rdescription; //alias description var $rport; //divert port var $renabled; //rule enabled var $rsets = array(); //array of l7 associations // Auxiliary functions function GetRName() { return $this->rname; } function SetRName($rname) { $this->rname = $rname; } function GetRDescription() { return $this->rdescription; } function SetRDescription($rdescription) { $this->rdescription = $rdescription; } function GetRPort() { return $this->rport; } function SetRPort($rport) { $this->rport = $rport; } function GetREnabled() { return $this->renabled; } function SetREnabled($value) { $this->renabled = $value; } function GetRl7() { return $this->rsets; } function SetRl7($rsets) { $this->rsets = $rsets; } //Add a tuple (rule,sctructure,element) to the $rsets function add_rule($l7set) { $this->rsets[] = $l7set; } // Build the layer7 rules function build_l7_rules() { if($this->GetREnabled() == "") { return; } //$l7rules = "#" . $this->rdescription . "\n"; foreach ($this->rsets as $rl7) { $l7rules .= $rl7->build_rules(); } return $l7rules; } // Read the config from array function ReadConfig(&$qname, &$q) { $this->SetRName($qname); $this->SetREnabled($q['enabled']); $this->SetRPort($q['divert_port']); if(isset($q['description']) && $q['description'] <> "") $this->SetRDescription($q['description']); $rsets = $q['l7rules']; //Put individual rules in the array if(is_array($rsets)) { $this->rsets = array(); // XXX: ugly hack foreach($rsets as $l7r) { $l7obj = new l7rule(); $l7obj->SetRProtocol($l7r['protocol']); $l7obj->SetRStructure($l7r['structure']); $l7obj->SetRBehaviour($l7r['behaviour']); $this->add_rule($l7obj); } } } //Generate a random port for the divert socket function gen_divert_port() { $dports = get_divert_ports(); //array of used ports $divert_port = 1; // Initialize while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) { $divert_port = rand(40000, 60000); } return $divert_port; } //Helps building the left tree function build_tree() { $tree = "
  • GetRName() ."&action=show\">"; $tree .= $this->GetRName() . ""; $tree .= "
  • "; return $tree; } function build_form() { $form = "
    "; $form .= "Enable/Disable"; $form .= ""; $form .= " GetREnabled() == "on") { $form .= "checked = \"CHECKED\""; } $form .= " > Enable/Disable layer7 Container"; $form .= ""; $form .= "
    Name"; $form .= ""; $form .= "GetRName()."\">"; $form .= ""; $form .= "Description"; $form .= ""; $form .= "GetRDescription(); $form .= "\">"; $form .= "
    "; $form .= "You may enter a description here "; $form .= "for your reference (not parsed)."; $form .= ""; return $form; } //Write the setting to the $config array function wconfig() { global $config; if(!is_array($config['l7shaper']['container'])) { $config['l7shaper']['container'] = array(); } // $cflink =& get_l7c_reference_to_me_in_config($this->GetRName()); // Test if this rule does exists already if(!$cflink) { $cflink =& $config['l7shaper']['container'][]; } $cflink['name'] = $this->GetRName(); $cflink['enabled'] = $this->GetREnabled(); $cflink['description'] = $this->GetRDescription(); $cflink['divert_port'] = $this->GetRPort(); //Destroy previously existent rules if(is_array($cflink['rules'])) { unset($cflink['l7rules']); } $cflink['l7rules'] = array(); $i = 0; foreach($this->rsets as $rulel7) { $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol(); $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure(); $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour(); $i++; } } //This function is necessary to help producing the overload options for keep state function get_unique_structures() { $unique_structures = array("action" => false, "dummynet" => false, "altq" => false); foreach($this->rsets as $l7rule) { if($l7rule->GetRStructure() == "action") $unique_structures['action'] = true; else if($l7rule->GetRStructure() == "limiter") $unique_structures['dummynet'] = true; else $unique_structures['altq'] = true; } //Delete non used structures so we don't have to check this in filter.inc foreach($unique_structures as $key => $value) if(!$value) unset($unique_structures[$key]); return $unique_structures; } function validate_input($data, &$input_errors) { $reqdfields[] = "container"; $reqdfieldsn[] = "Name"; shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors); if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container'])) $input_errors[] = "Queue names must be alphanumeric and _ or - only."; } function delete_l7c() { mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true); unset_l7_object_by_reference($this->GetRName()); cleanup_l7_from_rules($this->GetRName()); } } class l7rule { var $rprotocol; //protocol var $rstructure; //action, limiter, queue var $rbehaviour; //allow, block, queue_name, pipe_number ... //Auxiliary Functions function GetRProtocol() { return $this->rprotocol; } function SetRProtocol($rprotocol) { $this->rprotocol = $rprotocol; } function GetRStructure() { return $this->rstructure; } function SetRStructure($rstructure) { $this->rstructure = $rstructure; } function GetRBehaviour() { return $this->rbehaviour; } function SetRBehaviour($rbehaviour) { $this->rbehaviour = $rbehaviour; } //XXX Do we need to test any particularity for AltQ queues? function build_rules() { global $dummynet_pipe_list; switch ($this->GetRStructure()) { case "limiter": read_dummynet_config(); $dn_list =& get_unique_dnqueue_list(); $found = false; if(is_array($dn_list)) { foreach($dn_list as $key => $value) { if($key == $this->GetRBehaviour()) { if($value[0] == "?") $l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n"; else $l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n"; $found = true; } if($found) break; } } break; default: //This is for action and for altq $l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n"; break; } return $l7rule; } } /* * This function allows to return an array with all the used divert socket ports */ function get_divert_ports() { global $layer7_rules_list; $dports = array(); foreach($layer7_rules_list as $l7r) $dports[] = $l7r->GetRPort(); return $dports; } function &get_l7c_reference_to_me_in_config(&$name) { global $config; $ptr = NULL; if(is_array($config['l7shaper']['container'])) { foreach($config['l7shaper']['container'] as $key => $value) { if($value['name'] == $name) $ptr =& $config['l7shaper']['container'][$key]; } } return $ptr; // $ptr can be null. has to be checked later } function unset_l7_object_by_reference(&$name) { global $config; if(is_array($config['l7shaper']['container'])) { foreach($config['l7shaper']['container'] as $key => $value) { if($value['name'] == $name) { unset($config['l7shaper']['container'][$key]['l7rules']); unset($config['l7shaper']['container'][$key]); break; } } } } function read_layer7_config() { global $layer7_rules_list, $config; $l7cs = &$config['l7shaper']['container']; $layer7_rules_list = array(); if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) return; foreach ($l7cs as $conf) { if (empty($conf['name'])) continue; /* XXX: grrrrrr at php */ $root =& new layer7(); $root->ReadConfig($conf['name'],$conf); $layer7_rules_list[$root->GetRName()] = &$root; } } function generate_layer7_files() { global $layer7_rules_list, $g; read_layer7_config(); if (!empty($layer7_rules_list)) { if (!is_module_loaded("ipdivert.ko")) mwexec("/sbin/kldload ipdivert.ko"); mwexec("rm -f {$g['tmp_path']}/*.l7"); } foreach($layer7_rules_list as $l7rules) { if($l7rules->GetREnabled()) { $filename = $l7rules->GetRName() . ".l7"; $path = "{$g['tmp_path']}/" . $filename; $rules = $l7rules->build_l7_rules(); $fp = fopen($path,'w'); fwrite($fp,$rules); fclose($fp); } } } function layer7_start_l7daemon() { global $layer7_rules_list, $g; /* * XXX: ermal - Needed ?! * read_layer7_config(); */ foreach($layer7_rules_list as $l7rules) { if($l7rules->GetREnabled()) { $filename = $l7rules->GetRName() . ".l7"; $path = "{$g['tmp_path']}/" . $filename; unset($l7pid); /* Only reread the configuration rather than restart to avoid loosing information. */ exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid); if (count($l7pid) > 0) { log_error("Sending HUP signal to {$l7pid[0]}"); mwexec("/bin/kill -HUP {$l7pid[0]}"); } else { // XXX: Hardcoded number of packets to garbage collect and queue length.. $ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 5 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols"; mwexec_bg($ipfw_classifyd_init); } } } } // This function uses /usr/local/share/protocols as a default directory for searching .pat files function generate_protocols_array() { $protocols = return_dir_as_array("/usr/local/share/protocols"); $protocols_new = array(); if(is_array($protocols)) { foreach($protocols as $key => $proto) { if (strstr($proto, ".pat")) $protocols_new[$key] =& str_replace(".pat", "", $proto); } sort($protocols_new); } return $protocols_new; } function get_l7_unique_list() { global $layer7_rules_list; $l7list = array(); if(is_array($layer7_rules_list)) foreach($layer7_rules_list as $l7c) if($l7c->GetREnabled()) $l7list[] = $l7c->GetRName(); return $l7list; } // Disable a removed l7 container from the filter function cleanup_l7_from_rules(&$name) { global $config; if(is_array($config['filter']['rule'])) foreach ($config['filter']['rule'] as $key => $rule) { if ($rule['l7container'] == $name) unset($config['filter']['rule'][$key]['l7container']); } } 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 function * 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_set_default_queue($interface, $value) { global $altq_list_queues; $altq_tmp =& $altq_list_queues[$interface]; if ($altq_tmp) { if ($value) { $altq_tmp->SetDefaultQueuePresent("true"); } else { $altq_tmp->SetDefaultQueuePresent("false"); } } } function altq_get_default_queue($interface) { global $altq_list_queues; $altq_tmp = $altq_list_queues[$interface]; if ($altq_tmp) return $altq_tmp->GetDefaultQueuePresent(); } 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) { $tmplist =& $altq->get_queue_list(); foreach ($tmplist as $qname => $link) $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) { $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 compeletely 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(); $dnqueuenumber = 1; $dnpipenumber = 1; 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); $root->SetNumber($dnpipenumber); $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 cheat a little here till a better way is found. */ $q['number'] = $dnqueuenumber; /* * XXX: we compeletely 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); $dnqueuenumber++; } } array_pop($path); $dnpipenumber++; } } 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 .= "
  • ".$shDescr."
  • "; } } return $tree; } function filter_generate_altq_queues() { global $altq_list_queues; read_altq_config(); $altq_rules = ""; foreach ($altq_list_queues as $altq) $altq_rules .= $altq->build_rules(); return $altq_rules; } function filter_generate_dummynet_rules() { global $g, $dummynet_pipe_list; read_dummynet_config(); if (!empty($dummynet_pipe_list)) { if (!is_module_loaded("dummynet.ko")) mwexec("/sbin/kldload dummynet"); /* XXX: Needs to be added code elsewhere to clear pipes/queues from kernel when not needed! */ //mwexec("pfctl -F dummynet"); } $dn_rules = ""; foreach ($dummynet_pipe_list as $dn) $dn_rules .= $dn->build_rules(); if (!empty($dn_rules)) { file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules); mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter"); } //return $dn_rules; } function build_iface_without_this_queue($iface, $qname) { global $g, $altq_list_queues; $altq =& $altq_list_queues[$iface]; if ($altq) $scheduler = ": " . $altq->GetScheduler(); $form = ""; $form .= "".$iface.": ".$scheduler.""; $form .= ""; $form .= ""; $form .= ""; $form .= ""; $form .= " Clone shaper/queue on this interface"; return $form; } $default_shaper_msg = ""; $default_shaper_msg .= "

    Welcome to the {$g['product_name']} Traffic Shaper.
    "; $default_shaper_msg .= "The tree on the left helps you navigate through the queues
    "; $default_shaper_msg .= "buttons at the bottom represent queue actions and are activated accordingly."; $default_shaper_msg .= "

    "; $default_shaper_msg .= ""; $dn_default_shaper_msg = ""; $dn_default_shaper_msg .= "

    Welcome to the {$g['product_name']} Traffic Shaper.
    "; $dn_default_shaper_msg .= "The tree on the left helps you navigate through the queues
    "; $dn_default_shaper_msg .= "buttons at the bottom represent queue actions and are activated accordingly."; $dn_default_shaper_msg .= "

    "; $dn_default_shaper_msg .= ""; ?>