Project

General

Profile

Download (12.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * status_queues.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2024 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

    
24
##|+PRIV
25
##|*IDENT=page-status-trafficshaper-queues
26
##|*NAME=Status: Traffic Shaper: Queues
27
##|*DESCR=Allow access to the 'Status: Traffic Shaper: Queues' page.
28
##|*MATCH=status_queues.php*
29
##|-PRIV
30
/*
31
header("Last-Modified: " . gmdate("D, j M Y H:i:s") . " GMT");
32
header("Expires: " . gmdate("D, j M Y H:i:s", time()) . " GMT");
33
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP/1.1
34
header("Pragma: no-cache"); // HTTP/1.0
35
*/
36

    
37
require_once("guiconfig.inc");
38
include_once("shaper.inc");
39

    
40
$stats = get_queue_stats();
41

    
42
$pgtitle = array(gettext("Status"), gettext("Queues"));
43
$shortcut_section = "trafficshaper";
44
include("head.inc");
45

    
46
if (!isset($config['shaper']['queue']) || !is_array($config['shaper']['queue']) || count($config['shaper']['queue']) < 1) {
47
	print_info_box(gettext("Traffic shaping is not configured."));
48
	include("foot.inc");
49
	exit;
50
}
51

    
52
if (!$error): ?>
53
<form action="status_queues.php" method="post">
54
<script type="text/javascript">
55
//<![CDATA[
56
var refreshrate = 1000;
57
var queuestathistorylength = 0;
58
var queuestathistory = [];
59
var queuestatprevious = [];
60
var timestampprevious;
61
var graphstatmax = 0;
62
events.push(function() {
63
	$('#updatespeed').on('change', function() {
64
		refreshrate = $("#updatespeed").val();
65
	});
66

    
67
	function getqueueactivity() {
68
		var url = "/getqueuestats.php";
69
		var pars = "format=json";
70
		$.ajax(
71
			url,
72
			{
73
				type: 'post',
74
				data: pars,
75
				complete: activitycallback
76
			});
77
	}
78

    
79
	function escapeStr(str)
80
	{
81
		if (str)
82
			return str.replace(/([ #;?%&,.+*~\':"!^$[\]()=>|\/@])/g,'\\$1');
83
		return str;
84
	}
85

    
86
	function activitycallback(transport) {
87
		setTimeout(getqueueactivity, refreshrate);
88
		json = transport.responseJSON;
89
		if (!json) {
90
			return;
91
		}
92
		timestamp = json.timestamp;
93
		timestampdiff = timestamp - timestampprevious;
94
		$stattype = $('#selStatistic').val();
95

    
96
		interfacename_stats = [];
97
		for (interfacename in json.interfacestats) {
98
			var queueparents = [];
99
			interface = json.interfacestats[interfacename];
100
			interfacename_stats[interfacename] = [];
101
			for (queuename in interface) {
102
				queue = interface[queuename];
103
				statqname = queue['name'] + queue['interface'];
104

    
105
				for(childnr in queue['contains']) {
106
					child = queue['contains'][childnr];
107
					if (!queueparents[child]) {
108
						queueparents[child] = [];
109
					}
110
					queueparents[child] = queuename;
111
				}
112

    
113
				if (queuestatprevious[statqname]) {
114
					interfacename_stats[interfacename][statqname] = [];
115
					pkts_ps = (queue['pkts'] - queuestatprevious[statqname]['pkts']) / timestampdiff
116
					bytes_ps = (queue['bytes'] - queuestatprevious[statqname]['bytes']) / timestampdiff
117
					droppedpkts = parseFloat(queue['droppedpkts']);
118
					borrows = parseFloat(queue['borrows']);
119
					suspends = parseFloat(queue['suspends']);
120
					interfacename_stats[interfacename][statqname]['pkts_ps'] = pkts_ps;
121
					interfacename_stats[interfacename][statqname]['bytes_ps'] = bytes_ps;
122
					interfacename_stats[interfacename][statqname]['borrows'] = borrows;
123
					interfacename_stats[interfacename][statqname]['suspends'] = suspends;
124
					interfacename_stats[interfacename][statqname]['droppedpkts'] = droppedpkts;
125
					interfacename_stats[interfacename][statqname]['qlengthitems'] = queue['qlengthitems'];
126
					interfacename_stats[interfacename][statqname]['qlengthsize'] = queue['qlengthsize'];
127
					find = queuename;
128
					while(queueparents[find]) {
129
						// add diff values also to parent queues
130
						parentname = queueparents[find];
131
						parentqueuename = parentname+interfacename;
132
						if (parentname.indexOf('root_') !== 0) {
133
							interfacename_stats[interfacename][parentqueuename]['pkts_ps'] += pkts_ps;
134
							interfacename_stats[interfacename][parentqueuename]['bytes_ps'] += bytes_ps;
135
						}
136
						interfacename_stats[interfacename][parentqueuename]['borrows'] += borrows;
137
						interfacename_stats[interfacename][parentqueuename]['suspends'] += suspends;
138
						interfacename_stats[interfacename][parentqueuename]['droppedpkts'] += droppedpkts;
139
						find = parentname;
140
					}
141
				}
142
				queuestatprevious[statqname] = queue;
143
			}
144
		}
145
		// Find max pps/bps needed for any scale bar
146
		statmax = 0;
147
		for (interfacename in interfacename_stats) {
148
			interface = interfacename_stats[interfacename];
149
			for (queuename in interface) {
150
				queue = interface[queuename];
151
				if ($stattype == "0") {
152
					if (statmax < queue['pkts_ps']) {
153
						statmax = queue['pkts_ps'];
154
					}
155
				} else {
156
					if (statmax < queue['bytes_ps']) {
157
						statmax = queue['bytes_ps'];
158
					}
159
				}
160
			}
161
		}
162
		// use a slowly sliding max scale value but do make sure its always large enough to accommodate the largest value..
163
		if (graphstatmax < statmax) {
164
			// peek value + 10% keeps a little room for it to increase
165
			graphstatmax = statmax * 1.1;
166
		} else {
167
			// in general make largest bar fill +- 2/3 of the scale
168
			graphstatmax = (graphstatmax * 20 + statmax * 1.5) / 21;
169
		}
170
		// set values on the objects
171
		for (interfacename in interfacename_stats) {
172
			interface = interfacename_stats[interfacename];
173
			for (queuename in interface) {
174
				queue = interface[queuename];
175
				statqname = escapeStr(queuename);
176
				if ($stattype == "0") {
177
					$('#queue'+statqname+'width').css('width', (queue['pkts_ps']*100/graphstatmax).toFixed(0) + '%');
178
				} else {
179
					$('#queue'+statqname+'width').css('width', (queue['bytes_ps']*100/graphstatmax).toFixed(0) + '%');
180
				}
181
				$('#queue'+statqname+'pps').val(queue['pkts_ps'].toFixed(1));
182
				$('#queue'+statqname+'bps').val(formatSpeedBits(queue['bytes_ps']));
183
				$('#queue'+statqname+'borrows').val(queue['borrows']);
184
				$('#queue'+statqname+'suspends').val(queue['suspends']);
185
				$('#queue'+statqname+'drops').val(queue['droppedpkts']);
186
				$('#queue'+statqname+'length').val(queue['qlengthitems']+'/'+queue['qlengthsize']);
187
			}
188
		}
189
		timestampprevious = timestamp;
190
	}
191

    
192
	$(document).ready(function() {
193
		setTimeout(getqueueactivity, 150);
194
	});
195
});
196

    
197
function formatSpeedBits(speed) {
198
	// format speed in bits/sec, input: bytes/sec
199
	if (speed < 125000) {
200
		return Math.round(speed / 125) + " <?=gettext("Kbps"); ?>";
201
	}
202
	if (speed < 125000000) {
203
		return Math.round(speed / 1250)/100 + " <?=gettext("Mbps"); ?>";
204
	}
205
	// else
206
	return Math.round(speed / 1250000)/100 + " <?=gettext("Gbps"); ?>";  /* wow! */
207
}
208
//]]>
209
</script>
210
<?php endif;
211

    
212
if ($error):
213
	print_info_box($error);
214
else: ?>
215
	<div class="panel panel-default">
216
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Settings"); ?></h2></div>
217
		<div class="panel-body table-responsive">
218
			<label class="col-sm-2 control-label">
219
				<span>Refresh rate</span>
220
			</label>
221
			<div class="col-sm-10">
222
				<select id="updatespeed" class="form-control">
223
					<option value="500">0.5 <?=gettext("seconds");?></option>
224
					<option value="1000" selected>1 <?=gettext("seconds");?></option>
225
					<option value="2000">2 <?=gettext("seconds");?></option>
226
					<option value="5000">5 <?=gettext("seconds");?></option>
227
				</select>
228
			</div>
229
		</div>
230
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Status Queues"); ?></h2></div>
231
		<div class="panel-body table-responsive">
232
			<table class="table table-striped table-hover">
233
				<thead>
234
					<tr>
235
						<th><?=gettext("Queue"); ?></th>
236
						<th><?=gettext("Statistics"); ?>
237
							<select id="selStatistic" class="form-control">
238
								<option value="0"><?=gettext("PPS");?></option>
239
								<option value="1"><?=gettext("Bandwidth");?></option>
240
							</select>
241
						</th>
242
						<th><?=gettext("PPS"); ?></th>
243
						<th><?=gettext("Bandwidth"); ?></th>
244
						<th><?=gettext("Borrows"); ?></th>
245
						<th><?=gettext("Suspends"); ?></th>
246
						<th><?=gettext("Drops"); ?></th>
247
						<th><?=gettext("Length"); ?></th>
248
					</tr>
249
				</thead>
250
				<tbody>
251
<?php
252
	$if_queue_list = get_configured_interface_list_by_realif(true);
253
	processInterfaceQueues($stats, 0, "");
254
?>
255
<?php endif; ?>
256
				</tbody>
257
			</table>
258
			<br />
259
			<div class="infoblock blockopen">
260
<?php
261
	print_info_box(gettext("Queue graphs sample data on a regular interval."), 'info', false);
262
?>
263
			</div>
264
		</div>
265
	</div>
266
<br/>
267

    
268
<script type="text/javascript">
269
//<![CDATA[
270
	function StatsShowHide(classname) {
271
		var firstrow = $("." + classname).first();
272
		if (firstrow.is(':visible')) {
273
			$("." + classname).hide();
274
		} else {
275
			$("." + classname).show();
276
		}
277
	}
278
//]]>
279
</script>
280
</form>
281
<?php
282

    
283
include("foot.inc");
284

    
285
function processInterfaceQueues($altqstats, $parent_name) {
286
	global $g;
287
	global $if_queue_list;
288

    
289
	$parent_name = $parent_name . " queuerow" . $altqstats['name'] . convert_real_interface_to_friendly_interface_name($altqstats['interface']);
290
	$prev_if = $altqstats['interface'];
291
	if (!is_array($altqstats['interfacestats'])) {
292
		print("<tr><td>");
293
		print("No Queue data available");
294
		print("</td></tr>");
295
		return;
296
	}
297
	foreach ($altqstats['interfacestats'] as $if => $ifq) {
298
		$parents = array();
299
		echo "<tr><td colspan=\"8\"><b>Interface " . htmlspecialchars(convert_real_interface_to_friendly_descr($if)) . "</b></td></tr>\n";
300
		$if_name = "";
301
		foreach ($if_queue_list as $oif => $real_name) {
302
			if ($oif == $if) {
303
				$if_name = $real_name;
304
				break;
305
			}
306
		}
307
		if ($prev_if != $q['interface']) {
308
			$prev_if = $q['interface'];
309
		}
310
		foreach($ifq as $qkey => $q) {
311
			$parent_name = $if . " queuerow" . $altqstats['name'] . convert_real_interface_to_friendly_interface_name($altqstats['interface']);
312
			if (isset($q['contains'])) {
313
				foreach($q['contains'] as $child) {
314
					$parents[$child] = $qkey;
315
				}
316
			}
317
			$find = $qkey;
318
			$level = 0;
319
			while(isset($parents[$find])) {
320
				$find = $parents[$find];
321
				$level++;
322
				$parent_name = $parent_name . " queuerow" . $find . $q['interface'];
323
			}
324
			$qfinterface = convert_real_interface_to_friendly_interface_name($q['interface']);
325
			$qname = str_replace($q['interface'], $qfinterface, $q['name']);
326
?>
327
			<tr class="<?=$parent_name;?>">
328
				<td class="<?=$row_class?>" style="padding-left:<?=$level * 20?>px;">
329
					<?php
330
					if (is_array($q['contains'])) {
331
						echo "<a href=\"#\" onclick=\"StatsShowHide('queuerow{$qname}{$qfinterface}');return false\">+/-</a>";
332
					}
333
					if (strstr($qname, "root_")) {
334
						echo "<a href=\"firewall_shaper.php?interface={$if_name}&amp;queue={$if_name}&amp;action=show\">Root queue</a>";
335
					} else {
336
						echo "<a href=\"firewall_shaper.php?interface={$if_name}&amp;queue={$qname}&amp;action=show\">" . htmlspecialchars($qname) . "</a>";
337
					}
338
					?>
339
				</td>
340
<?php
341
			$cpuUsage = 0;
342
			$stat_prefix = "queue" . $q['name'] . $q['interface'];
343
			print('<td>');
344
			print('<div class="progress" style="height: 7px;width: 170px;">');
345
			print('		<div class="progress-bar" role="progressbar" id="' . $stat_prefix . 'width" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100" style="width: ' . $cpuUsage*100 . '%;"></div>');
346
			print('	  </div>');
347
			print('</td>');
348
			print('<td><input readonly style="border:0;width:70px;text-align:right;" name="' . $stat_prefix . 'pps"      id="' . $stat_prefix . 'pps"      value="(' . gettext("Loading") . ')" /></td>');
349
			print('<td><input readonly style="border:0;width:80px;text-align:right;" name="' . $stat_prefix . 'bps"      id="' . $stat_prefix . 'bps"      value="" /></td>');
350
			print('<td><input readonly style="border:0;width:70px;text-align:right;" name="' . $stat_prefix . 'borrows"  id="' . $stat_prefix . 'borrows"  value="" /></td>');
351
			print('<td><input readonly style="border:0;width:70px;text-align:right;" name="' . $stat_prefix . 'suspends" id="' . $stat_prefix . 'suspends" value="" /></td>');
352
			print('<td><input readonly style="border:0;width:70px;text-align:right;" name="' . $stat_prefix . 'drops"    id="' . $stat_prefix . 'drops"    value="" /></td>');
353
			print('<td><input readonly style="border:0;width:70px;text-align:right;" name="' . $stat_prefix . 'length"   id="' . $stat_prefix . 'length"   value="" /></td>');
354
?>
355
			</tr>
356
<?php
357
			if (is_array($q['queue'])) {
358
				processInterfaceQueues($q, $level + 1, $parent_name);
359
			}
360
		}
361
	};
362
}
363
?>
(179-179/228)