1145840Smlaier/*	$OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) Henning Brauer <henning@openbsd.org>
5126353Smlaier *
6126353Smlaier * Permission to use, copy, modify, and distribute this software for any
7126353Smlaier * purpose with or without fee is hereby granted, provided that the above
8126353Smlaier * copyright notice and this permission notice appear in all copies.
9126353Smlaier *
10126353Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11126353Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12126353Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13126353Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14126353Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15126353Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16126353Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17126353Smlaier */
18126353Smlaier
19127082Sobrien#include <sys/cdefs.h>
20127082Sobrien__FBSDID("$FreeBSD$");
21127082Sobrien
22126353Smlaier#include <sys/types.h>
23126353Smlaier#include <sys/ioctl.h>
24126353Smlaier#include <sys/socket.h>
25126353Smlaier
26126353Smlaier#include <net/if.h>
27126353Smlaier#include <netinet/in.h>
28126353Smlaier#include <net/pfvar.h>
29126353Smlaier#include <arpa/inet.h>
30126353Smlaier
31126353Smlaier#include <err.h>
32126353Smlaier#include <stdio.h>
33126353Smlaier#include <stdlib.h>
34126353Smlaier#include <string.h>
35126353Smlaier#include <unistd.h>
36126353Smlaier
37126353Smlaier#include <altq/altq.h>
38126353Smlaier#include <altq/altq_cbq.h>
39298133Sloos#include <altq/altq_codel.h>
40126353Smlaier#include <altq/altq_priq.h>
41126353Smlaier#include <altq/altq_hfsc.h>
42298115Sloos#include <altq/altq_fairq.h>
43126353Smlaier
44126353Smlaier#include "pfctl.h"
45126353Smlaier#include "pfctl_parser.h"
46126353Smlaier
47126353Smlaierunion class_stats {
48126353Smlaier	class_stats_t		cbq_stats;
49126353Smlaier	struct priq_classstats	priq_stats;
50126353Smlaier	struct hfsc_classstats	hfsc_stats;
51298091Sloos	struct fairq_classstats fairq_stats;
52298133Sloos	struct codel_ifstats	codel_stats;
53126353Smlaier};
54126353Smlaier
55126353Smlaier#define AVGN_MAX	8
56126353Smlaier#define STAT_INTERVAL	5
57126353Smlaier
58126353Smlaierstruct queue_stats {
59126353Smlaier	union class_stats	 data;
60126353Smlaier	int			 avgn;
61126353Smlaier	double			 avg_bytes;
62126353Smlaier	double			 avg_packets;
63126353Smlaier	u_int64_t		 prev_bytes;
64126353Smlaier	u_int64_t		 prev_packets;
65126353Smlaier};
66126353Smlaier
67126353Smlaierstruct pf_altq_node {
68126353Smlaier	struct pf_altq		 altq;
69126353Smlaier	struct pf_altq_node	*next;
70126353Smlaier	struct pf_altq_node	*children;
71126353Smlaier	struct queue_stats	 qstats;
72126353Smlaier};
73126353Smlaier
74126353Smlaierint			 pfctl_update_qstats(int, struct pf_altq_node **);
75126353Smlaiervoid			 pfctl_insert_altq_node(struct pf_altq_node **,
76126353Smlaier			    const struct pf_altq, const struct queue_stats);
77126353Smlaierstruct pf_altq_node	*pfctl_find_altq_node(struct pf_altq_node *,
78126353Smlaier			    const char *, const char *);
79126353Smlaiervoid			 pfctl_print_altq_node(int, const struct pf_altq_node *,
80223637Sbz			    unsigned, int);
81126353Smlaiervoid			 print_cbqstats(struct queue_stats);
82298133Sloosvoid			 print_codelstats(struct queue_stats);
83126353Smlaiervoid			 print_priqstats(struct queue_stats);
84126353Smlaiervoid			 print_hfscstats(struct queue_stats);
85298091Sloosvoid			 print_fairqstats(struct queue_stats);
86126353Smlaiervoid			 pfctl_free_altq_node(struct pf_altq_node *);
87126353Smlaiervoid			 pfctl_print_altq_nodestat(int,
88126353Smlaier			    const struct pf_altq_node *);
89126353Smlaier
90126353Smlaiervoid			 update_avg(struct pf_altq_node *);
91126353Smlaier
92126353Smlaierint
93130617Smlaierpfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
94126353Smlaier{
95126353Smlaier	struct pf_altq_node	*root = NULL, *node;
96130617Smlaier	int			 nodes, dotitle = (opts & PF_OPT_SHOWALL);
97126353Smlaier
98127024Smlaier#ifdef __FreeBSD__
99126355Smlaier	if (!altqsupport)
100126355Smlaier		return (-1);
101126355Smlaier#endif
102130617Smlaier
103130617Smlaier	if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
104126353Smlaier		return (-1);
105126353Smlaier
106145840Smlaier	if (nodes == 0)
107145840Smlaier		printf("No queue in use\n");
108130617Smlaier	for (node = root; node != NULL; node = node->next) {
109130617Smlaier		if (iface != NULL && strcmp(node->altq.ifname, iface))
110130617Smlaier			continue;
111130617Smlaier		if (dotitle) {
112130617Smlaier			pfctl_print_title("ALTQ:");
113130617Smlaier			dotitle = 0;
114130617Smlaier		}
115126353Smlaier		pfctl_print_altq_node(dev, node, 0, opts);
116130617Smlaier	}
117126353Smlaier
118145840Smlaier	while (verbose2 && nodes > 0) {
119126353Smlaier		printf("\n");
120126353Smlaier		fflush(stdout);
121126353Smlaier		sleep(STAT_INTERVAL);
122145840Smlaier		if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
123126353Smlaier			return (-1);
124130617Smlaier		for (node = root; node != NULL; node = node->next) {
125130617Smlaier			if (iface != NULL && strcmp(node->altq.ifname, iface))
126130617Smlaier				continue;
127177700Smlaier#ifdef __FreeBSD__
128177700Smlaier			if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
129177700Smlaier				continue;
130177700Smlaier#endif
131126353Smlaier			pfctl_print_altq_node(dev, node, 0, opts);
132130617Smlaier		}
133126353Smlaier	}
134126353Smlaier	pfctl_free_altq_node(root);
135126353Smlaier	return (0);
136126353Smlaier}
137126353Smlaier
138126353Smlaierint
139126353Smlaierpfctl_update_qstats(int dev, struct pf_altq_node **root)
140126353Smlaier{
141126353Smlaier	struct pf_altq_node	*node;
142126353Smlaier	struct pfioc_altq	 pa;
143126353Smlaier	struct pfioc_qstats	 pq;
144126353Smlaier	u_int32_t		 mnr, nr;
145126353Smlaier	struct queue_stats	 qstats;
146126353Smlaier	static	u_int32_t	 last_ticket;
147126353Smlaier
148126353Smlaier	memset(&pa, 0, sizeof(pa));
149126353Smlaier	memset(&pq, 0, sizeof(pq));
150126353Smlaier	memset(&qstats, 0, sizeof(qstats));
151126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
152126353Smlaier		warn("DIOCGETALTQS");
153126353Smlaier		return (-1);
154126353Smlaier	}
155126353Smlaier
156126353Smlaier	/* if a new set is found, start over */
157126353Smlaier	if (pa.ticket != last_ticket && *root != NULL) {
158126353Smlaier		pfctl_free_altq_node(*root);
159126353Smlaier		*root = NULL;
160126353Smlaier	}
161126353Smlaier	last_ticket = pa.ticket;
162126353Smlaier
163126353Smlaier	mnr = pa.nr;
164126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
165126353Smlaier		pa.nr = nr;
166126353Smlaier		if (ioctl(dev, DIOCGETALTQ, &pa)) {
167126353Smlaier			warn("DIOCGETALTQ");
168126353Smlaier			return (-1);
169126353Smlaier		}
170177700Smlaier#ifdef __FreeBSD__
171298133Sloos		if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
172177700Smlaier		    !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
173177700Smlaier#else
174126353Smlaier		if (pa.altq.qid > 0) {
175177700Smlaier#endif
176126353Smlaier			pq.nr = nr;
177126353Smlaier			pq.ticket = pa.ticket;
178126353Smlaier			pq.buf = &qstats.data;
179126353Smlaier			pq.nbytes = sizeof(qstats.data);
180126353Smlaier			if (ioctl(dev, DIOCGETQSTATS, &pq)) {
181126353Smlaier				warn("DIOCGETQSTATS");
182126353Smlaier				return (-1);
183126353Smlaier			}
184126353Smlaier			if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
185126353Smlaier			    pa.altq.ifname)) != NULL) {
186126353Smlaier				memcpy(&node->qstats.data, &qstats.data,
187126353Smlaier				    sizeof(qstats.data));
188126353Smlaier				update_avg(node);
189126353Smlaier			} else {
190126353Smlaier				pfctl_insert_altq_node(root, pa.altq, qstats);
191126353Smlaier			}
192126353Smlaier		}
193177700Smlaier#ifdef __FreeBSD__
194223637Sbz		else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
195223637Sbz			memset(&qstats.data, 0, sizeof(qstats.data));
196177700Smlaier			if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
197177700Smlaier			    pa.altq.ifname)) != NULL) {
198177700Smlaier				memcpy(&node->qstats.data, &qstats.data,
199177700Smlaier				    sizeof(qstats.data));
200177700Smlaier				update_avg(node);
201177700Smlaier			} else {
202177700Smlaier				pfctl_insert_altq_node(root, pa.altq, qstats);
203223637Sbz			}
204177700Smlaier		}
205177700Smlaier#endif
206126353Smlaier	}
207130617Smlaier	return (mnr);
208126353Smlaier}
209126353Smlaier
210126353Smlaiervoid
211126353Smlaierpfctl_insert_altq_node(struct pf_altq_node **root,
212126353Smlaier    const struct pf_altq altq, const struct queue_stats qstats)
213126353Smlaier{
214126353Smlaier	struct pf_altq_node	*node;
215126353Smlaier
216126353Smlaier	node = calloc(1, sizeof(struct pf_altq_node));
217126353Smlaier	if (node == NULL)
218126353Smlaier		err(1, "pfctl_insert_altq_node: calloc");
219126353Smlaier	memcpy(&node->altq, &altq, sizeof(struct pf_altq));
220126353Smlaier	memcpy(&node->qstats, &qstats, sizeof(qstats));
221126353Smlaier	node->next = node->children = NULL;
222126353Smlaier
223126353Smlaier	if (*root == NULL)
224126353Smlaier		*root = node;
225126353Smlaier	else if (!altq.parent[0]) {
226126353Smlaier		struct pf_altq_node	*prev = *root;
227126353Smlaier
228126353Smlaier		while (prev->next != NULL)
229126353Smlaier			prev = prev->next;
230126353Smlaier		prev->next = node;
231126353Smlaier	} else {
232126353Smlaier		struct pf_altq_node	*parent;
233126353Smlaier
234126353Smlaier		parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
235126353Smlaier		if (parent == NULL)
236126353Smlaier			errx(1, "parent %s not found", altq.parent);
237126353Smlaier		if (parent->children == NULL)
238126353Smlaier			parent->children = node;
239126353Smlaier		else {
240126353Smlaier			struct pf_altq_node *prev = parent->children;
241126353Smlaier
242126353Smlaier			while (prev->next != NULL)
243126353Smlaier				prev = prev->next;
244126353Smlaier			prev->next = node;
245126353Smlaier		}
246126353Smlaier	}
247126353Smlaier	update_avg(node);
248126353Smlaier}
249126353Smlaier
250126353Smlaierstruct pf_altq_node *
251126353Smlaierpfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
252126353Smlaier    const char *ifname)
253126353Smlaier{
254126353Smlaier	struct pf_altq_node	*node, *child;
255126353Smlaier
256126353Smlaier	for (node = root; node != NULL; node = node->next) {
257126353Smlaier		if (!strcmp(node->altq.qname, qname)
258126353Smlaier		    && !(strcmp(node->altq.ifname, ifname)))
259126353Smlaier			return (node);
260126353Smlaier		if (node->children != NULL) {
261126353Smlaier			child = pfctl_find_altq_node(node->children, qname,
262126353Smlaier			    ifname);
263126353Smlaier			if (child != NULL)
264126353Smlaier				return (child);
265126353Smlaier		}
266126353Smlaier	}
267126353Smlaier	return (NULL);
268126353Smlaier}
269126353Smlaier
270126353Smlaiervoid
271223637Sbzpfctl_print_altq_node(int dev, const struct pf_altq_node *node,
272223637Sbz    unsigned int level, int opts)
273126353Smlaier{
274126353Smlaier	const struct pf_altq_node	*child;
275126353Smlaier
276126353Smlaier	if (node == NULL)
277126353Smlaier		return;
278126353Smlaier
279126353Smlaier	print_altq(&node->altq, level, NULL, NULL);
280126353Smlaier
281126353Smlaier	if (node->children != NULL) {
282126353Smlaier		printf("{");
283126353Smlaier		for (child = node->children; child != NULL;
284126353Smlaier		    child = child->next) {
285126353Smlaier			printf("%s", child->altq.qname);
286126353Smlaier			if (child->next != NULL)
287126353Smlaier				printf(", ");
288126353Smlaier		}
289126353Smlaier		printf("}");
290126353Smlaier	}
291126353Smlaier	printf("\n");
292126353Smlaier
293126353Smlaier	if (opts & PF_OPT_VERBOSE)
294126353Smlaier		pfctl_print_altq_nodestat(dev, node);
295126353Smlaier
296126353Smlaier	if (opts & PF_OPT_DEBUG)
297130617Smlaier		printf("  [ qid=%u ifname=%s ifbandwidth=%s ]\n",
298130617Smlaier		    node->altq.qid, node->altq.ifname,
299130617Smlaier		    rate2str((double)(node->altq.ifbandwidth)));
300126353Smlaier
301126353Smlaier	for (child = node->children; child != NULL;
302126353Smlaier	    child = child->next)
303130617Smlaier		pfctl_print_altq_node(dev, child, level + 1, opts);
304126353Smlaier}
305126353Smlaier
306126353Smlaiervoid
307126353Smlaierpfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
308126353Smlaier{
309298133Sloos	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
310126353Smlaier		return;
311223637Sbz
312177700Smlaier#ifdef __FreeBSD__
313177700Smlaier	if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
314177700Smlaier		return;
315177700Smlaier#endif
316126353Smlaier	switch (a->altq.scheduler) {
317126353Smlaier	case ALTQT_CBQ:
318126353Smlaier		print_cbqstats(a->qstats);
319126353Smlaier		break;
320126353Smlaier	case ALTQT_PRIQ:
321126353Smlaier		print_priqstats(a->qstats);
322126353Smlaier		break;
323126353Smlaier	case ALTQT_HFSC:
324126353Smlaier		print_hfscstats(a->qstats);
325126353Smlaier		break;
326298091Sloos	case ALTQT_FAIRQ:
327298091Sloos		print_fairqstats(a->qstats);
328298091Sloos		break;
329298133Sloos	case ALTQT_CODEL:
330298133Sloos		print_codelstats(a->qstats);
331298133Sloos		break;
332126353Smlaier	}
333126353Smlaier}
334126353Smlaier
335126353Smlaiervoid
336126353Smlaierprint_cbqstats(struct queue_stats cur)
337126353Smlaier{
338127024Smlaier	printf("  [ pkts: %10llu  bytes: %10llu  "
339127024Smlaier	    "dropped pkts: %6llu bytes: %6llu ]\n",
340127024Smlaier	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
341127024Smlaier	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
342127024Smlaier	    (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
343127024Smlaier	    (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
344126353Smlaier	printf("  [ qlength: %3d/%3d  borrows: %6u  suspends: %6u ]\n",
345126353Smlaier	    cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
346126353Smlaier	    cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
347126353Smlaier
348126353Smlaier	if (cur.avgn < 2)
349126353Smlaier		return;
350126353Smlaier
351126353Smlaier	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
352126353Smlaier	    cur.avg_packets / STAT_INTERVAL,
353126353Smlaier	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
354126353Smlaier}
355126353Smlaier
356126353Smlaiervoid
357298133Sloosprint_codelstats(struct queue_stats cur)
358298133Sloos{
359298133Sloos	printf("  [ pkts: %10llu  bytes: %10llu  "
360298133Sloos	    "dropped pkts: %6llu bytes: %6llu ]\n",
361298133Sloos	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
362298133Sloos	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
363298133Sloos	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
364298133Sloos	    cur.data.codel_stats.stats.drop_cnt.packets,
365298133Sloos	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
366298133Sloos	    cur.data.codel_stats.stats.drop_cnt.bytes);
367298133Sloos	printf("  [ qlength: %3d/%3d ]\n",
368298133Sloos	    cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
369298133Sloos
370298133Sloos	if (cur.avgn < 2)
371298133Sloos		return;
372298133Sloos
373298133Sloos	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
374298133Sloos	    cur.avg_packets / STAT_INTERVAL,
375298133Sloos	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
376298133Sloos}
377298133Sloos
378298133Sloosvoid
379126353Smlaierprint_priqstats(struct queue_stats cur)
380126353Smlaier{
381127024Smlaier	printf("  [ pkts: %10llu  bytes: %10llu  "
382127024Smlaier	    "dropped pkts: %6llu bytes: %6llu ]\n",
383127024Smlaier	    (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
384127024Smlaier	    (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
385127024Smlaier	    (unsigned long long)cur.data.priq_stats.dropcnt.packets,
386127024Smlaier	    (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
387126353Smlaier	printf("  [ qlength: %3d/%3d ]\n",
388126353Smlaier	    cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
389126353Smlaier
390126353Smlaier	if (cur.avgn < 2)
391126353Smlaier		return;
392126353Smlaier
393126353Smlaier	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
394126353Smlaier	    cur.avg_packets / STAT_INTERVAL,
395126353Smlaier	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
396126353Smlaier}
397126353Smlaier
398126353Smlaiervoid
399126353Smlaierprint_hfscstats(struct queue_stats cur)
400126353Smlaier{
401127024Smlaier	printf("  [ pkts: %10llu  bytes: %10llu  "
402127024Smlaier	    "dropped pkts: %6llu bytes: %6llu ]\n",
403127024Smlaier	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
404127024Smlaier	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
405127024Smlaier	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
406127024Smlaier	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
407126353Smlaier	printf("  [ qlength: %3d/%3d ]\n",
408126353Smlaier	    cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
409126353Smlaier
410126353Smlaier	if (cur.avgn < 2)
411126353Smlaier		return;
412126353Smlaier
413126353Smlaier	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
414126353Smlaier	    cur.avg_packets / STAT_INTERVAL,
415126353Smlaier	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
416126353Smlaier}
417126353Smlaier
418126353Smlaiervoid
419298091Sloosprint_fairqstats(struct queue_stats cur)
420298091Sloos{
421298091Sloos	printf("  [ pkts: %10llu  bytes: %10llu  "
422298091Sloos	    "dropped pkts: %6llu bytes: %6llu ]\n",
423298091Sloos	    (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
424298091Sloos	    (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
425298091Sloos	    (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
426298091Sloos	    (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
427298091Sloos	printf("  [ qlength: %3d/%3d ]\n",
428298091Sloos	    cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
429298091Sloos
430298091Sloos	if (cur.avgn < 2)
431298091Sloos		return;
432298091Sloos
433298091Sloos	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
434298091Sloos	    cur.avg_packets / STAT_INTERVAL,
435298091Sloos	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
436298091Sloos}
437298091Sloos
438298091Sloosvoid
439126353Smlaierpfctl_free_altq_node(struct pf_altq_node *node)
440126353Smlaier{
441126353Smlaier	while (node != NULL) {
442126353Smlaier		struct pf_altq_node	*prev;
443126353Smlaier
444126353Smlaier		if (node->children != NULL)
445126353Smlaier			pfctl_free_altq_node(node->children);
446126353Smlaier		prev = node;
447126353Smlaier		node = node->next;
448126353Smlaier		free(prev);
449126353Smlaier	}
450126353Smlaier}
451126353Smlaier
452126353Smlaiervoid
453126353Smlaierupdate_avg(struct pf_altq_node *a)
454126353Smlaier{
455126353Smlaier	struct queue_stats	*qs;
456126353Smlaier	u_int64_t		 b, p;
457126353Smlaier	int			 n;
458126353Smlaier
459298133Sloos	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
460126353Smlaier		return;
461126353Smlaier
462126353Smlaier	qs = &a->qstats;
463126353Smlaier	n = qs->avgn;
464126353Smlaier
465126353Smlaier	switch (a->altq.scheduler) {
466126353Smlaier	case ALTQT_CBQ:
467126353Smlaier		b = qs->data.cbq_stats.xmit_cnt.bytes;
468126353Smlaier		p = qs->data.cbq_stats.xmit_cnt.packets;
469126353Smlaier		break;
470126353Smlaier	case ALTQT_PRIQ:
471126353Smlaier		b = qs->data.priq_stats.xmitcnt.bytes;
472126353Smlaier		p = qs->data.priq_stats.xmitcnt.packets;
473126353Smlaier		break;
474126353Smlaier	case ALTQT_HFSC:
475126353Smlaier		b = qs->data.hfsc_stats.xmit_cnt.bytes;
476126353Smlaier		p = qs->data.hfsc_stats.xmit_cnt.packets;
477126353Smlaier		break;
478298091Sloos	case ALTQT_FAIRQ:
479298091Sloos		b = qs->data.fairq_stats.xmit_cnt.bytes;
480298091Sloos		p = qs->data.fairq_stats.xmit_cnt.packets;
481298091Sloos		break;
482298133Sloos	case ALTQT_CODEL:
483298133Sloos		b = qs->data.codel_stats.cl_xmitcnt.bytes;
484298133Sloos		p = qs->data.codel_stats.cl_xmitcnt.packets;
485298133Sloos		break;
486126353Smlaier	default:
487126353Smlaier		b = 0;
488126353Smlaier		p = 0;
489126353Smlaier		break;
490126353Smlaier	}
491126353Smlaier
492126353Smlaier	if (n == 0) {
493126353Smlaier		qs->prev_bytes = b;
494126353Smlaier		qs->prev_packets = p;
495126353Smlaier		qs->avgn++;
496126353Smlaier		return;
497126353Smlaier	}
498126353Smlaier
499126353Smlaier	if (b >= qs->prev_bytes)
500126353Smlaier		qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
501126353Smlaier		    (b - qs->prev_bytes)) / n;
502126353Smlaier
503126353Smlaier	if (p >= qs->prev_packets)
504126353Smlaier		qs->avg_packets = ((qs->avg_packets * (n - 1)) +
505126353Smlaier		    (p - qs->prev_packets)) / n;
506126353Smlaier
507126353Smlaier	qs->prev_bytes = b;
508126353Smlaier	qs->prev_packets = p;
509126353Smlaier	if (n < AVGN_MAX)
510126353Smlaier		qs->avgn++;
511126353Smlaier}
512