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-2020 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
						interfacename_stats[interfacename][parentqueuename]['pkts_ps'] += pkts_ps;
133
						interfacename_stats[interfacename][parentqueuename]['bytes_ps'] += bytes_ps;
134
						interfacename_stats[interfacename][parentqueuename]['borrows'] += borrows;
135
						interfacename_stats[interfacename][parentqueuename]['suspends'] += suspends;
136
						interfacename_stats[interfacename][parentqueuename]['droppedpkts'] += droppedpkts;
137
						find = parentname;
138
					}
139
				}
140
				queuestatprevious[statqname] = queue;
141
			}
142
		}
143
		// Find max pps/bps needed for any scale bar
144
		statmax = 0;
145
		for (interfacename in interfacename_stats) {
146
			interface = interfacename_stats[interfacename];
147
			for (queuename in interface) {
148
				queue = interface[queuename];
149
				if ($stattype == "0") {
150
					if (statmax < queue['pkts_ps']) {
151
						statmax = queue['pkts_ps'];
152
					}
153
				} else {
154
					if (statmax < queue['bytes_ps']) {
155
						statmax = queue['bytes_ps'];
156
					}
157
				}
158
			}
159
		}
160
		// use a slowly sliding max scale value but do make sure its always large enough to accommodate the largest value..
161
		if (graphstatmax < statmax) {
162
			// peek value + 10% keeps a little room for it to increase
163
			graphstatmax = statmax * 1.1;
164
		} else {
165
			// in general make largest bar fill +- 2/3 of the scale
166
			graphstatmax = (graphstatmax * 20 + statmax * 1.5) / 21;
167
		}
168
		// set values on the objects
169
		for (interfacename in interfacename_stats) {
170
			interface = interfacename_stats[interfacename];
171
			for (queuename in interface) {
172
				queue = interface[queuename];
173
				statqname = escapeStr(queuename);
174
				if ($stattype == "0") {
175
					$('#queue'+statqname+'width').css('width', (queue['pkts_ps']*100/graphstatmax).toFixed(0) + '%');
176
				} else {
177
					$('#queue'+statqname+'width').css('width', (queue['bytes_ps']*100/graphstatmax).toFixed(0) + '%');
178
				}
179
				$('#queue'+statqname+'pps').val(queue['pkts_ps'].toFixed(1));
180
				$('#queue'+statqname+'bps').val(formatSpeedBits(queue['bytes_ps']));
181
				$('#queue'+statqname+'borrows').val(queue['borrows']);
182
				$('#queue'+statqname+'suspends').val(queue['suspends']);
183
				$('#queue'+statqname+'drops').val(queue['droppedpkts']);
184
				$('#queue'+statqname+'length').val(queue['qlengthitems']+'/'+queue['qlengthsize']);
185
			}
186
		}
187
		timestampprevious = timestamp;
188
	}
189

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

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

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

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

    
281
include("foot.inc");
282

    
283
function processInterfaceQueues($altqstats, $parent_name) {
284
	global $g;
285
	global $if_queue_list;
286

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