xref: /freebsd-src/sbin/pfctl/pfctl_qstats.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
13b3a8eb9SGleb Smirnoff /*	$OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
23b3a8eb9SGleb Smirnoff 
33b3a8eb9SGleb Smirnoff /*
43b3a8eb9SGleb Smirnoff  * Copyright (c) Henning Brauer <henning@openbsd.org>
53b3a8eb9SGleb Smirnoff  *
63b3a8eb9SGleb Smirnoff  * Permission to use, copy, modify, and distribute this software for any
73b3a8eb9SGleb Smirnoff  * purpose with or without fee is hereby granted, provided that the above
83b3a8eb9SGleb Smirnoff  * copyright notice and this permission notice appear in all copies.
93b3a8eb9SGleb Smirnoff  *
103b3a8eb9SGleb Smirnoff  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113b3a8eb9SGleb Smirnoff  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123b3a8eb9SGleb Smirnoff  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133b3a8eb9SGleb Smirnoff  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143b3a8eb9SGleb Smirnoff  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153b3a8eb9SGleb Smirnoff  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163b3a8eb9SGleb Smirnoff  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173b3a8eb9SGleb Smirnoff  */
183b3a8eb9SGleb Smirnoff 
193b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
20*249cc75fSPatrick Kelsey #define PFIOC_USE_LATEST
21*249cc75fSPatrick Kelsey 
223b3a8eb9SGleb Smirnoff #include <sys/types.h>
233b3a8eb9SGleb Smirnoff #include <sys/ioctl.h>
243b3a8eb9SGleb Smirnoff #include <sys/socket.h>
253b3a8eb9SGleb Smirnoff 
263b3a8eb9SGleb Smirnoff #include <net/if.h>
273b3a8eb9SGleb Smirnoff #include <netinet/in.h>
283b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
293b3a8eb9SGleb Smirnoff #include <arpa/inet.h>
303b3a8eb9SGleb Smirnoff 
313b3a8eb9SGleb Smirnoff #include <err.h>
323b3a8eb9SGleb Smirnoff #include <stdio.h>
333b3a8eb9SGleb Smirnoff #include <stdlib.h>
343b3a8eb9SGleb Smirnoff #include <string.h>
353b3a8eb9SGleb Smirnoff #include <unistd.h>
363b3a8eb9SGleb Smirnoff 
37772e66a6SGleb Smirnoff #include <net/altq/altq.h>
38772e66a6SGleb Smirnoff #include <net/altq/altq_cbq.h>
390a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h>
40772e66a6SGleb Smirnoff #include <net/altq/altq_priq.h>
41772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h>
42a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h>
433b3a8eb9SGleb Smirnoff 
443b3a8eb9SGleb Smirnoff #include "pfctl.h"
453b3a8eb9SGleb Smirnoff #include "pfctl_parser.h"
463b3a8eb9SGleb Smirnoff 
473b3a8eb9SGleb Smirnoff union class_stats {
483b3a8eb9SGleb Smirnoff 	class_stats_t		cbq_stats;
493b3a8eb9SGleb Smirnoff 	struct priq_classstats	priq_stats;
503b3a8eb9SGleb Smirnoff 	struct hfsc_classstats	hfsc_stats;
51a5b789f6SErmal Luçi 	struct fairq_classstats fairq_stats;
520a70aaf8SLuiz Otavio O Souza 	struct codel_ifstats	codel_stats;
533b3a8eb9SGleb Smirnoff };
543b3a8eb9SGleb Smirnoff 
553b3a8eb9SGleb Smirnoff #define AVGN_MAX	8
563b3a8eb9SGleb Smirnoff #define STAT_INTERVAL	5
573b3a8eb9SGleb Smirnoff 
583b3a8eb9SGleb Smirnoff struct queue_stats {
593b3a8eb9SGleb Smirnoff 	union class_stats	 data;
603b3a8eb9SGleb Smirnoff 	int			 avgn;
613b3a8eb9SGleb Smirnoff 	double			 avg_bytes;
623b3a8eb9SGleb Smirnoff 	double			 avg_packets;
633b3a8eb9SGleb Smirnoff 	u_int64_t		 prev_bytes;
643b3a8eb9SGleb Smirnoff 	u_int64_t		 prev_packets;
653b3a8eb9SGleb Smirnoff };
663b3a8eb9SGleb Smirnoff 
673b3a8eb9SGleb Smirnoff struct pf_altq_node {
683b3a8eb9SGleb Smirnoff 	struct pf_altq		 altq;
693b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*next;
703b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*children;
713b3a8eb9SGleb Smirnoff 	struct queue_stats	 qstats;
723b3a8eb9SGleb Smirnoff };
733b3a8eb9SGleb Smirnoff 
743b3a8eb9SGleb Smirnoff int			 pfctl_update_qstats(int, struct pf_altq_node **);
753b3a8eb9SGleb Smirnoff void			 pfctl_insert_altq_node(struct pf_altq_node **,
763b3a8eb9SGleb Smirnoff 			    const struct pf_altq, const struct queue_stats);
773b3a8eb9SGleb Smirnoff struct pf_altq_node	*pfctl_find_altq_node(struct pf_altq_node *,
783b3a8eb9SGleb Smirnoff 			    const char *, const char *);
793b3a8eb9SGleb Smirnoff void			 pfctl_print_altq_node(int, const struct pf_altq_node *,
803b3a8eb9SGleb Smirnoff 			    unsigned, int);
813b3a8eb9SGleb Smirnoff void			 print_cbqstats(struct queue_stats);
820a70aaf8SLuiz Otavio O Souza void			 print_codelstats(struct queue_stats);
833b3a8eb9SGleb Smirnoff void			 print_priqstats(struct queue_stats);
843b3a8eb9SGleb Smirnoff void			 print_hfscstats(struct queue_stats);
85a5b789f6SErmal Luçi void			 print_fairqstats(struct queue_stats);
863b3a8eb9SGleb Smirnoff void			 pfctl_free_altq_node(struct pf_altq_node *);
873b3a8eb9SGleb Smirnoff void			 pfctl_print_altq_nodestat(int,
883b3a8eb9SGleb Smirnoff 			    const struct pf_altq_node *);
893b3a8eb9SGleb Smirnoff 
903b3a8eb9SGleb Smirnoff void			 update_avg(struct pf_altq_node *);
913b3a8eb9SGleb Smirnoff 
923b3a8eb9SGleb Smirnoff int
pfctl_show_altq(int dev,const char * iface,int opts,int verbose2)933b3a8eb9SGleb Smirnoff pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
943b3a8eb9SGleb Smirnoff {
953b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*root = NULL, *node;
963b3a8eb9SGleb Smirnoff 	int			 nodes, dotitle = (opts & PF_OPT_SHOWALL);
973b3a8eb9SGleb Smirnoff 
983b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
993b3a8eb9SGleb Smirnoff 	if (!altqsupport)
1003b3a8eb9SGleb Smirnoff 		return (-1);
1013b3a8eb9SGleb Smirnoff #endif
1023b3a8eb9SGleb Smirnoff 
1033b3a8eb9SGleb Smirnoff 	if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
1043b3a8eb9SGleb Smirnoff 		return (-1);
1053b3a8eb9SGleb Smirnoff 
1063b3a8eb9SGleb Smirnoff 	if (nodes == 0)
1073b3a8eb9SGleb Smirnoff 		printf("No queue in use\n");
1083b3a8eb9SGleb Smirnoff 	for (node = root; node != NULL; node = node->next) {
1093b3a8eb9SGleb Smirnoff 		if (iface != NULL && strcmp(node->altq.ifname, iface))
1103b3a8eb9SGleb Smirnoff 			continue;
1113b3a8eb9SGleb Smirnoff 		if (dotitle) {
1123b3a8eb9SGleb Smirnoff 			pfctl_print_title("ALTQ:");
1133b3a8eb9SGleb Smirnoff 			dotitle = 0;
1143b3a8eb9SGleb Smirnoff 		}
1153b3a8eb9SGleb Smirnoff 		pfctl_print_altq_node(dev, node, 0, opts);
1163b3a8eb9SGleb Smirnoff 	}
1173b3a8eb9SGleb Smirnoff 
1183b3a8eb9SGleb Smirnoff 	while (verbose2 && nodes > 0) {
1193b3a8eb9SGleb Smirnoff 		printf("\n");
1203b3a8eb9SGleb Smirnoff 		fflush(stdout);
1213b3a8eb9SGleb Smirnoff 		sleep(STAT_INTERVAL);
1223b3a8eb9SGleb Smirnoff 		if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
1233b3a8eb9SGleb Smirnoff 			return (-1);
1243b3a8eb9SGleb Smirnoff 		for (node = root; node != NULL; node = node->next) {
1253b3a8eb9SGleb Smirnoff 			if (iface != NULL && strcmp(node->altq.ifname, iface))
1263b3a8eb9SGleb Smirnoff 				continue;
1273b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
1283b3a8eb9SGleb Smirnoff 			if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
1293b3a8eb9SGleb Smirnoff 				continue;
1303b3a8eb9SGleb Smirnoff #endif
1313b3a8eb9SGleb Smirnoff 			pfctl_print_altq_node(dev, node, 0, opts);
1323b3a8eb9SGleb Smirnoff 		}
1333b3a8eb9SGleb Smirnoff 	}
1343b3a8eb9SGleb Smirnoff 	pfctl_free_altq_node(root);
1353b3a8eb9SGleb Smirnoff 	return (0);
1363b3a8eb9SGleb Smirnoff }
1373b3a8eb9SGleb Smirnoff 
1383b3a8eb9SGleb Smirnoff int
pfctl_update_qstats(int dev,struct pf_altq_node ** root)1393b3a8eb9SGleb Smirnoff pfctl_update_qstats(int dev, struct pf_altq_node **root)
1403b3a8eb9SGleb Smirnoff {
1413b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*node;
1423b3a8eb9SGleb Smirnoff 	struct pfioc_altq	 pa;
1433b3a8eb9SGleb Smirnoff 	struct pfioc_qstats	 pq;
1443b3a8eb9SGleb Smirnoff 	u_int32_t		 mnr, nr;
1453b3a8eb9SGleb Smirnoff 	struct queue_stats	 qstats;
1463b3a8eb9SGleb Smirnoff 	static	u_int32_t	 last_ticket;
1473b3a8eb9SGleb Smirnoff 
1483b3a8eb9SGleb Smirnoff 	memset(&pa, 0, sizeof(pa));
1493b3a8eb9SGleb Smirnoff 	memset(&pq, 0, sizeof(pq));
1503b3a8eb9SGleb Smirnoff 	memset(&qstats, 0, sizeof(qstats));
151*249cc75fSPatrick Kelsey 	pa.version = PFIOC_ALTQ_VERSION;
1523b3a8eb9SGleb Smirnoff 	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1533b3a8eb9SGleb Smirnoff 		warn("DIOCGETALTQS");
1543b3a8eb9SGleb Smirnoff 		return (-1);
1553b3a8eb9SGleb Smirnoff 	}
1563b3a8eb9SGleb Smirnoff 
1573b3a8eb9SGleb Smirnoff 	/* if a new set is found, start over */
1583b3a8eb9SGleb Smirnoff 	if (pa.ticket != last_ticket && *root != NULL) {
1593b3a8eb9SGleb Smirnoff 		pfctl_free_altq_node(*root);
1603b3a8eb9SGleb Smirnoff 		*root = NULL;
1613b3a8eb9SGleb Smirnoff 	}
1623b3a8eb9SGleb Smirnoff 	last_ticket = pa.ticket;
1633b3a8eb9SGleb Smirnoff 
1643b3a8eb9SGleb Smirnoff 	mnr = pa.nr;
1653b3a8eb9SGleb Smirnoff 	for (nr = 0; nr < mnr; ++nr) {
1663b3a8eb9SGleb Smirnoff 		pa.nr = nr;
1673b3a8eb9SGleb Smirnoff 		if (ioctl(dev, DIOCGETALTQ, &pa)) {
1683b3a8eb9SGleb Smirnoff 			warn("DIOCGETALTQ");
1693b3a8eb9SGleb Smirnoff 			return (-1);
1703b3a8eb9SGleb Smirnoff 		}
1713b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
1720a70aaf8SLuiz Otavio O Souza 		if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
1733b3a8eb9SGleb Smirnoff 		    !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
1743b3a8eb9SGleb Smirnoff #else
1753b3a8eb9SGleb Smirnoff 		if (pa.altq.qid > 0) {
1763b3a8eb9SGleb Smirnoff #endif
1773b3a8eb9SGleb Smirnoff 			pq.nr = nr;
1783b3a8eb9SGleb Smirnoff 			pq.ticket = pa.ticket;
1793b3a8eb9SGleb Smirnoff 			pq.buf = &qstats.data;
1803b3a8eb9SGleb Smirnoff 			pq.nbytes = sizeof(qstats.data);
181*249cc75fSPatrick Kelsey 			pq.version = altq_stats_version(pa.altq.scheduler);
1823b3a8eb9SGleb Smirnoff 			if (ioctl(dev, DIOCGETQSTATS, &pq)) {
1833b3a8eb9SGleb Smirnoff 				warn("DIOCGETQSTATS");
1843b3a8eb9SGleb Smirnoff 				return (-1);
1853b3a8eb9SGleb Smirnoff 			}
1863b3a8eb9SGleb Smirnoff 			if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
1873b3a8eb9SGleb Smirnoff 			    pa.altq.ifname)) != NULL) {
1883b3a8eb9SGleb Smirnoff 				memcpy(&node->qstats.data, &qstats.data,
1893b3a8eb9SGleb Smirnoff 				    sizeof(qstats.data));
1903b3a8eb9SGleb Smirnoff 				update_avg(node);
1913b3a8eb9SGleb Smirnoff 			} else {
1923b3a8eb9SGleb Smirnoff 				pfctl_insert_altq_node(root, pa.altq, qstats);
1933b3a8eb9SGleb Smirnoff 			}
1943b3a8eb9SGleb Smirnoff 		}
1953b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
1963b3a8eb9SGleb Smirnoff 		else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
1973b3a8eb9SGleb Smirnoff 			memset(&qstats.data, 0, sizeof(qstats.data));
1983b3a8eb9SGleb Smirnoff 			if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
1993b3a8eb9SGleb Smirnoff 			    pa.altq.ifname)) != NULL) {
2003b3a8eb9SGleb Smirnoff 				memcpy(&node->qstats.data, &qstats.data,
2013b3a8eb9SGleb Smirnoff 				    sizeof(qstats.data));
2023b3a8eb9SGleb Smirnoff 				update_avg(node);
2033b3a8eb9SGleb Smirnoff 			} else {
2043b3a8eb9SGleb Smirnoff 				pfctl_insert_altq_node(root, pa.altq, qstats);
2053b3a8eb9SGleb Smirnoff 			}
2063b3a8eb9SGleb Smirnoff 		}
2073b3a8eb9SGleb Smirnoff #endif
2083b3a8eb9SGleb Smirnoff 	}
2093b3a8eb9SGleb Smirnoff 	return (mnr);
2103b3a8eb9SGleb Smirnoff }
2113b3a8eb9SGleb Smirnoff 
2123b3a8eb9SGleb Smirnoff void
2133b3a8eb9SGleb Smirnoff pfctl_insert_altq_node(struct pf_altq_node **root,
2143b3a8eb9SGleb Smirnoff     const struct pf_altq altq, const struct queue_stats qstats)
2153b3a8eb9SGleb Smirnoff {
2163b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*node;
2173b3a8eb9SGleb Smirnoff 
2183b3a8eb9SGleb Smirnoff 	node = calloc(1, sizeof(struct pf_altq_node));
2193b3a8eb9SGleb Smirnoff 	if (node == NULL)
2203b3a8eb9SGleb Smirnoff 		err(1, "pfctl_insert_altq_node: calloc");
2213b3a8eb9SGleb Smirnoff 	memcpy(&node->altq, &altq, sizeof(struct pf_altq));
2223b3a8eb9SGleb Smirnoff 	memcpy(&node->qstats, &qstats, sizeof(qstats));
2233b3a8eb9SGleb Smirnoff 	node->next = node->children = NULL;
2243b3a8eb9SGleb Smirnoff 
2253b3a8eb9SGleb Smirnoff 	if (*root == NULL)
2263b3a8eb9SGleb Smirnoff 		*root = node;
2273b3a8eb9SGleb Smirnoff 	else if (!altq.parent[0]) {
2283b3a8eb9SGleb Smirnoff 		struct pf_altq_node	*prev = *root;
2293b3a8eb9SGleb Smirnoff 
2303b3a8eb9SGleb Smirnoff 		while (prev->next != NULL)
2313b3a8eb9SGleb Smirnoff 			prev = prev->next;
2323b3a8eb9SGleb Smirnoff 		prev->next = node;
2333b3a8eb9SGleb Smirnoff 	} else {
2343b3a8eb9SGleb Smirnoff 		struct pf_altq_node	*parent;
2353b3a8eb9SGleb Smirnoff 
2363b3a8eb9SGleb Smirnoff 		parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
2373b3a8eb9SGleb Smirnoff 		if (parent == NULL)
2383b3a8eb9SGleb Smirnoff 			errx(1, "parent %s not found", altq.parent);
2393b3a8eb9SGleb Smirnoff 		if (parent->children == NULL)
2403b3a8eb9SGleb Smirnoff 			parent->children = node;
2413b3a8eb9SGleb Smirnoff 		else {
2423b3a8eb9SGleb Smirnoff 			struct pf_altq_node *prev = parent->children;
2433b3a8eb9SGleb Smirnoff 
2443b3a8eb9SGleb Smirnoff 			while (prev->next != NULL)
2453b3a8eb9SGleb Smirnoff 				prev = prev->next;
2463b3a8eb9SGleb Smirnoff 			prev->next = node;
2473b3a8eb9SGleb Smirnoff 		}
2483b3a8eb9SGleb Smirnoff 	}
2493b3a8eb9SGleb Smirnoff 	update_avg(node);
2503b3a8eb9SGleb Smirnoff }
2513b3a8eb9SGleb Smirnoff 
2523b3a8eb9SGleb Smirnoff struct pf_altq_node *
2533b3a8eb9SGleb Smirnoff pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
2543b3a8eb9SGleb Smirnoff     const char *ifname)
2553b3a8eb9SGleb Smirnoff {
2563b3a8eb9SGleb Smirnoff 	struct pf_altq_node	*node, *child;
2573b3a8eb9SGleb Smirnoff 
2583b3a8eb9SGleb Smirnoff 	for (node = root; node != NULL; node = node->next) {
2593b3a8eb9SGleb Smirnoff 		if (!strcmp(node->altq.qname, qname)
2603b3a8eb9SGleb Smirnoff 		    && !(strcmp(node->altq.ifname, ifname)))
2613b3a8eb9SGleb Smirnoff 			return (node);
2623b3a8eb9SGleb Smirnoff 		if (node->children != NULL) {
2633b3a8eb9SGleb Smirnoff 			child = pfctl_find_altq_node(node->children, qname,
2643b3a8eb9SGleb Smirnoff 			    ifname);
2653b3a8eb9SGleb Smirnoff 			if (child != NULL)
2663b3a8eb9SGleb Smirnoff 				return (child);
2673b3a8eb9SGleb Smirnoff 		}
2683b3a8eb9SGleb Smirnoff 	}
2693b3a8eb9SGleb Smirnoff 	return (NULL);
2703b3a8eb9SGleb Smirnoff }
2713b3a8eb9SGleb Smirnoff 
2723b3a8eb9SGleb Smirnoff void
2733b3a8eb9SGleb Smirnoff pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
2743b3a8eb9SGleb Smirnoff     unsigned int level, int opts)
2753b3a8eb9SGleb Smirnoff {
2763b3a8eb9SGleb Smirnoff 	const struct pf_altq_node	*child;
2773b3a8eb9SGleb Smirnoff 
2783b3a8eb9SGleb Smirnoff 	if (node == NULL)
2793b3a8eb9SGleb Smirnoff 		return;
2803b3a8eb9SGleb Smirnoff 
2813b3a8eb9SGleb Smirnoff 	print_altq(&node->altq, level, NULL, NULL);
2823b3a8eb9SGleb Smirnoff 
2833b3a8eb9SGleb Smirnoff 	if (node->children != NULL) {
2843b3a8eb9SGleb Smirnoff 		printf("{");
2853b3a8eb9SGleb Smirnoff 		for (child = node->children; child != NULL;
2863b3a8eb9SGleb Smirnoff 		    child = child->next) {
2873b3a8eb9SGleb Smirnoff 			printf("%s", child->altq.qname);
2883b3a8eb9SGleb Smirnoff 			if (child->next != NULL)
2893b3a8eb9SGleb Smirnoff 				printf(", ");
2903b3a8eb9SGleb Smirnoff 		}
2913b3a8eb9SGleb Smirnoff 		printf("}");
2923b3a8eb9SGleb Smirnoff 	}
2933b3a8eb9SGleb Smirnoff 	printf("\n");
2943b3a8eb9SGleb Smirnoff 
2953b3a8eb9SGleb Smirnoff 	if (opts & PF_OPT_VERBOSE)
2963b3a8eb9SGleb Smirnoff 		pfctl_print_altq_nodestat(dev, node);
2973b3a8eb9SGleb Smirnoff 
2983b3a8eb9SGleb Smirnoff 	if (opts & PF_OPT_DEBUG)
2993b3a8eb9SGleb Smirnoff 		printf("  [ qid=%u ifname=%s ifbandwidth=%s ]\n",
3003b3a8eb9SGleb Smirnoff 		    node->altq.qid, node->altq.ifname,
3013b3a8eb9SGleb Smirnoff 		    rate2str((double)(node->altq.ifbandwidth)));
3023b3a8eb9SGleb Smirnoff 
3033b3a8eb9SGleb Smirnoff 	for (child = node->children; child != NULL;
3043b3a8eb9SGleb Smirnoff 	    child = child->next)
3053b3a8eb9SGleb Smirnoff 		pfctl_print_altq_node(dev, child, level + 1, opts);
3063b3a8eb9SGleb Smirnoff }
3073b3a8eb9SGleb Smirnoff 
3083b3a8eb9SGleb Smirnoff void
3093b3a8eb9SGleb Smirnoff pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
3103b3a8eb9SGleb Smirnoff {
3110a70aaf8SLuiz Otavio O Souza 	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
3123b3a8eb9SGleb Smirnoff 		return;
3133b3a8eb9SGleb Smirnoff 
3143b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
3153b3a8eb9SGleb Smirnoff 	if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
3163b3a8eb9SGleb Smirnoff 		return;
3173b3a8eb9SGleb Smirnoff #endif
3183b3a8eb9SGleb Smirnoff 	switch (a->altq.scheduler) {
3193b3a8eb9SGleb Smirnoff 	case ALTQT_CBQ:
3203b3a8eb9SGleb Smirnoff 		print_cbqstats(a->qstats);
3213b3a8eb9SGleb Smirnoff 		break;
3223b3a8eb9SGleb Smirnoff 	case ALTQT_PRIQ:
3233b3a8eb9SGleb Smirnoff 		print_priqstats(a->qstats);
3243b3a8eb9SGleb Smirnoff 		break;
3253b3a8eb9SGleb Smirnoff 	case ALTQT_HFSC:
3263b3a8eb9SGleb Smirnoff 		print_hfscstats(a->qstats);
3273b3a8eb9SGleb Smirnoff 		break;
328a5b789f6SErmal Luçi 	case ALTQT_FAIRQ:
329a5b789f6SErmal Luçi 		print_fairqstats(a->qstats);
330a5b789f6SErmal Luçi 		break;
3310a70aaf8SLuiz Otavio O Souza 	case ALTQT_CODEL:
3320a70aaf8SLuiz Otavio O Souza 		print_codelstats(a->qstats);
3330a70aaf8SLuiz Otavio O Souza 		break;
3343b3a8eb9SGleb Smirnoff 	}
3353b3a8eb9SGleb Smirnoff }
3363b3a8eb9SGleb Smirnoff 
3373b3a8eb9SGleb Smirnoff void
3383b3a8eb9SGleb Smirnoff print_cbqstats(struct queue_stats cur)
3393b3a8eb9SGleb Smirnoff {
3403b3a8eb9SGleb Smirnoff 	printf("  [ pkts: %10llu  bytes: %10llu  "
3413b3a8eb9SGleb Smirnoff 	    "dropped pkts: %6llu bytes: %6llu ]\n",
3423b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
3433b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
3443b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
3453b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
3463b3a8eb9SGleb Smirnoff 	printf("  [ qlength: %3d/%3d  borrows: %6u  suspends: %6u ]\n",
3473b3a8eb9SGleb Smirnoff 	    cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
3483b3a8eb9SGleb Smirnoff 	    cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
3493b3a8eb9SGleb Smirnoff 
3503b3a8eb9SGleb Smirnoff 	if (cur.avgn < 2)
3513b3a8eb9SGleb Smirnoff 		return;
3523b3a8eb9SGleb Smirnoff 
3533b3a8eb9SGleb Smirnoff 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
3543b3a8eb9SGleb Smirnoff 	    cur.avg_packets / STAT_INTERVAL,
3553b3a8eb9SGleb Smirnoff 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
3563b3a8eb9SGleb Smirnoff }
3573b3a8eb9SGleb Smirnoff 
3583b3a8eb9SGleb Smirnoff void
3590a70aaf8SLuiz Otavio O Souza print_codelstats(struct queue_stats cur)
3600a70aaf8SLuiz Otavio O Souza {
3610a70aaf8SLuiz Otavio O Souza 	printf("  [ pkts: %10llu  bytes: %10llu  "
3620a70aaf8SLuiz Otavio O Souza 	    "dropped pkts: %6llu bytes: %6llu ]\n",
3630a70aaf8SLuiz Otavio O Souza 	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
3640a70aaf8SLuiz Otavio O Souza 	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
3650a70aaf8SLuiz Otavio O Souza 	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
3660a70aaf8SLuiz Otavio O Souza 	    cur.data.codel_stats.stats.drop_cnt.packets,
3670a70aaf8SLuiz Otavio O Souza 	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
3680a70aaf8SLuiz Otavio O Souza 	    cur.data.codel_stats.stats.drop_cnt.bytes);
3690a70aaf8SLuiz Otavio O Souza 	printf("  [ qlength: %3d/%3d ]\n",
3700a70aaf8SLuiz Otavio O Souza 	    cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
3710a70aaf8SLuiz Otavio O Souza 
3720a70aaf8SLuiz Otavio O Souza 	if (cur.avgn < 2)
3730a70aaf8SLuiz Otavio O Souza 		return;
3740a70aaf8SLuiz Otavio O Souza 
3750a70aaf8SLuiz Otavio O Souza 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
3760a70aaf8SLuiz Otavio O Souza 	    cur.avg_packets / STAT_INTERVAL,
3770a70aaf8SLuiz Otavio O Souza 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
3780a70aaf8SLuiz Otavio O Souza }
3790a70aaf8SLuiz Otavio O Souza 
3800a70aaf8SLuiz Otavio O Souza void
3813b3a8eb9SGleb Smirnoff print_priqstats(struct queue_stats cur)
3823b3a8eb9SGleb Smirnoff {
3833b3a8eb9SGleb Smirnoff 	printf("  [ pkts: %10llu  bytes: %10llu  "
3843b3a8eb9SGleb Smirnoff 	    "dropped pkts: %6llu bytes: %6llu ]\n",
3853b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
3863b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
3873b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.priq_stats.dropcnt.packets,
3883b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
3893b3a8eb9SGleb Smirnoff 	printf("  [ qlength: %3d/%3d ]\n",
3903b3a8eb9SGleb Smirnoff 	    cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
3913b3a8eb9SGleb Smirnoff 
3923b3a8eb9SGleb Smirnoff 	if (cur.avgn < 2)
3933b3a8eb9SGleb Smirnoff 		return;
3943b3a8eb9SGleb Smirnoff 
3953b3a8eb9SGleb Smirnoff 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
3963b3a8eb9SGleb Smirnoff 	    cur.avg_packets / STAT_INTERVAL,
3973b3a8eb9SGleb Smirnoff 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
3983b3a8eb9SGleb Smirnoff }
3993b3a8eb9SGleb Smirnoff 
4003b3a8eb9SGleb Smirnoff void
4013b3a8eb9SGleb Smirnoff print_hfscstats(struct queue_stats cur)
4023b3a8eb9SGleb Smirnoff {
4033b3a8eb9SGleb Smirnoff 	printf("  [ pkts: %10llu  bytes: %10llu  "
4043b3a8eb9SGleb Smirnoff 	    "dropped pkts: %6llu bytes: %6llu ]\n",
4053b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
4063b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
4073b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
4083b3a8eb9SGleb Smirnoff 	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
4093b3a8eb9SGleb Smirnoff 	printf("  [ qlength: %3d/%3d ]\n",
4103b3a8eb9SGleb Smirnoff 	    cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
4113b3a8eb9SGleb Smirnoff 
4123b3a8eb9SGleb Smirnoff 	if (cur.avgn < 2)
4133b3a8eb9SGleb Smirnoff 		return;
4143b3a8eb9SGleb Smirnoff 
4153b3a8eb9SGleb Smirnoff 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
4163b3a8eb9SGleb Smirnoff 	    cur.avg_packets / STAT_INTERVAL,
4173b3a8eb9SGleb Smirnoff 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
4183b3a8eb9SGleb Smirnoff }
4193b3a8eb9SGleb Smirnoff 
4203b3a8eb9SGleb Smirnoff void
421a5b789f6SErmal Luçi print_fairqstats(struct queue_stats cur)
422a5b789f6SErmal Luçi {
423a5b789f6SErmal Luçi 	printf("  [ pkts: %10llu  bytes: %10llu  "
424a5b789f6SErmal Luçi 	    "dropped pkts: %6llu bytes: %6llu ]\n",
425a5b789f6SErmal Luçi 	    (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
426a5b789f6SErmal Luçi 	    (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
427a5b789f6SErmal Luçi 	    (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
428a5b789f6SErmal Luçi 	    (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
429a5b789f6SErmal Luçi 	printf("  [ qlength: %3d/%3d ]\n",
430a5b789f6SErmal Luçi 	    cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
431a5b789f6SErmal Luçi 
432a5b789f6SErmal Luçi 	if (cur.avgn < 2)
433a5b789f6SErmal Luçi 		return;
434a5b789f6SErmal Luçi 
435a5b789f6SErmal Luçi 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
436a5b789f6SErmal Luçi 	    cur.avg_packets / STAT_INTERVAL,
437a5b789f6SErmal Luçi 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
438a5b789f6SErmal Luçi }
439a5b789f6SErmal Luçi 
440a5b789f6SErmal Luçi void
4413b3a8eb9SGleb Smirnoff pfctl_free_altq_node(struct pf_altq_node *node)
4423b3a8eb9SGleb Smirnoff {
4433b3a8eb9SGleb Smirnoff 	while (node != NULL) {
4443b3a8eb9SGleb Smirnoff 		struct pf_altq_node	*prev;
4453b3a8eb9SGleb Smirnoff 
4463b3a8eb9SGleb Smirnoff 		if (node->children != NULL)
4473b3a8eb9SGleb Smirnoff 			pfctl_free_altq_node(node->children);
4483b3a8eb9SGleb Smirnoff 		prev = node;
4493b3a8eb9SGleb Smirnoff 		node = node->next;
4503b3a8eb9SGleb Smirnoff 		free(prev);
4513b3a8eb9SGleb Smirnoff 	}
4523b3a8eb9SGleb Smirnoff }
4533b3a8eb9SGleb Smirnoff 
4543b3a8eb9SGleb Smirnoff void
4553b3a8eb9SGleb Smirnoff update_avg(struct pf_altq_node *a)
4563b3a8eb9SGleb Smirnoff {
4573b3a8eb9SGleb Smirnoff 	struct queue_stats	*qs;
4583b3a8eb9SGleb Smirnoff 	u_int64_t		 b, p;
4593b3a8eb9SGleb Smirnoff 	int			 n;
4603b3a8eb9SGleb Smirnoff 
4610a70aaf8SLuiz Otavio O Souza 	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
4623b3a8eb9SGleb Smirnoff 		return;
4633b3a8eb9SGleb Smirnoff 
4643b3a8eb9SGleb Smirnoff 	qs = &a->qstats;
4653b3a8eb9SGleb Smirnoff 	n = qs->avgn;
4663b3a8eb9SGleb Smirnoff 
4673b3a8eb9SGleb Smirnoff 	switch (a->altq.scheduler) {
4683b3a8eb9SGleb Smirnoff 	case ALTQT_CBQ:
4693b3a8eb9SGleb Smirnoff 		b = qs->data.cbq_stats.xmit_cnt.bytes;
4703b3a8eb9SGleb Smirnoff 		p = qs->data.cbq_stats.xmit_cnt.packets;
4713b3a8eb9SGleb Smirnoff 		break;
4723b3a8eb9SGleb Smirnoff 	case ALTQT_PRIQ:
4733b3a8eb9SGleb Smirnoff 		b = qs->data.priq_stats.xmitcnt.bytes;
4743b3a8eb9SGleb Smirnoff 		p = qs->data.priq_stats.xmitcnt.packets;
4753b3a8eb9SGleb Smirnoff 		break;
4763b3a8eb9SGleb Smirnoff 	case ALTQT_HFSC:
4773b3a8eb9SGleb Smirnoff 		b = qs->data.hfsc_stats.xmit_cnt.bytes;
4783b3a8eb9SGleb Smirnoff 		p = qs->data.hfsc_stats.xmit_cnt.packets;
4793b3a8eb9SGleb Smirnoff 		break;
480a5b789f6SErmal Luçi 	case ALTQT_FAIRQ:
481a5b789f6SErmal Luçi 		b = qs->data.fairq_stats.xmit_cnt.bytes;
482a5b789f6SErmal Luçi 		p = qs->data.fairq_stats.xmit_cnt.packets;
483a5b789f6SErmal Luçi 		break;
4840a70aaf8SLuiz Otavio O Souza 	case ALTQT_CODEL:
4850a70aaf8SLuiz Otavio O Souza 		b = qs->data.codel_stats.cl_xmitcnt.bytes;
4860a70aaf8SLuiz Otavio O Souza 		p = qs->data.codel_stats.cl_xmitcnt.packets;
4870a70aaf8SLuiz Otavio O Souza 		break;
4883b3a8eb9SGleb Smirnoff 	default:
4893b3a8eb9SGleb Smirnoff 		b = 0;
4903b3a8eb9SGleb Smirnoff 		p = 0;
4913b3a8eb9SGleb Smirnoff 		break;
4923b3a8eb9SGleb Smirnoff 	}
4933b3a8eb9SGleb Smirnoff 
4943b3a8eb9SGleb Smirnoff 	if (n == 0) {
4953b3a8eb9SGleb Smirnoff 		qs->prev_bytes = b;
4963b3a8eb9SGleb Smirnoff 		qs->prev_packets = p;
4973b3a8eb9SGleb Smirnoff 		qs->avgn++;
4983b3a8eb9SGleb Smirnoff 		return;
4993b3a8eb9SGleb Smirnoff 	}
5003b3a8eb9SGleb Smirnoff 
5013b3a8eb9SGleb Smirnoff 	if (b >= qs->prev_bytes)
5023b3a8eb9SGleb Smirnoff 		qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
5033b3a8eb9SGleb Smirnoff 		    (b - qs->prev_bytes)) / n;
5043b3a8eb9SGleb Smirnoff 
5053b3a8eb9SGleb Smirnoff 	if (p >= qs->prev_packets)
5063b3a8eb9SGleb Smirnoff 		qs->avg_packets = ((qs->avg_packets * (n - 1)) +
5073b3a8eb9SGleb Smirnoff 		    (p - qs->prev_packets)) / n;
5083b3a8eb9SGleb Smirnoff 
5093b3a8eb9SGleb Smirnoff 	qs->prev_bytes = b;
5103b3a8eb9SGleb Smirnoff 	qs->prev_packets = p;
5113b3a8eb9SGleb Smirnoff 	if (n < AVGN_MAX)
5123b3a8eb9SGleb Smirnoff 		qs->avgn++;
5133b3a8eb9SGleb Smirnoff }
514