1 /* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
4 * Copyright (c) Henning Brauer <henning@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/cdefs.h>
20 __FBSDID("$FreeBSD$");
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <net/pfvar.h>
29 #include <arpa/inet.h>
37 #include <altq/altq.h>
38 #include <altq/altq_cbq.h>
39 #include <altq/altq_priq.h>
40 #include <altq/altq_hfsc.h>
43 #include "pfctl_parser.h"
46 class_stats_t cbq_stats;
47 struct priq_classstats priq_stats;
48 struct hfsc_classstats hfsc_stats;
52 #define STAT_INTERVAL 5
55 union class_stats data;
60 u_int64_t prev_packets;
65 struct pf_altq_node *next;
66 struct pf_altq_node *children;
67 struct queue_stats qstats;
70 int pfctl_update_qstats(int, struct pf_altq_node **);
71 void pfctl_insert_altq_node(struct pf_altq_node **,
72 const struct pf_altq, const struct queue_stats);
73 struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
74 const char *, const char *);
75 void pfctl_print_altq_node(int, const struct pf_altq_node *,
77 void print_cbqstats(struct queue_stats);
78 void print_priqstats(struct queue_stats);
79 void print_hfscstats(struct queue_stats);
80 void pfctl_free_altq_node(struct pf_altq_node *);
81 void pfctl_print_altq_nodestat(int,
82 const struct pf_altq_node *);
84 void update_avg(struct pf_altq_node *);
87 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
89 struct pf_altq_node *root = NULL, *node;
90 int nodes, dotitle = (opts & PF_OPT_SHOWALL);
97 if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
101 printf("No queue in use\n");
102 for (node = root; node != NULL; node = node->next) {
103 if (iface != NULL && strcmp(node->altq.ifname, iface))
106 pfctl_print_title("ALTQ:");
109 pfctl_print_altq_node(dev, node, 0, opts);
112 while (verbose2 && nodes > 0) {
115 sleep(STAT_INTERVAL);
116 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
118 for (node = root; node != NULL; node = node->next) {
119 if (iface != NULL && strcmp(node->altq.ifname, iface))
121 pfctl_print_altq_node(dev, node, 0, opts);
124 pfctl_free_altq_node(root);
129 pfctl_update_qstats(int dev, struct pf_altq_node **root)
131 struct pf_altq_node *node;
132 struct pfioc_altq pa;
133 struct pfioc_qstats pq;
135 struct queue_stats qstats;
136 static u_int32_t last_ticket;
138 memset(&pa, 0, sizeof(pa));
139 memset(&pq, 0, sizeof(pq));
140 memset(&qstats, 0, sizeof(qstats));
141 if (ioctl(dev, DIOCGETALTQS, &pa)) {
142 warn("DIOCGETALTQS");
146 /* if a new set is found, start over */
147 if (pa.ticket != last_ticket && *root != NULL) {
148 pfctl_free_altq_node(*root);
151 last_ticket = pa.ticket;
154 for (nr = 0; nr < mnr; ++nr) {
156 if (ioctl(dev, DIOCGETALTQ, &pa)) {
160 if (pa.altq.qid > 0) {
162 pq.ticket = pa.ticket;
163 pq.buf = &qstats.data;
164 pq.nbytes = sizeof(qstats.data);
165 if (ioctl(dev, DIOCGETQSTATS, &pq)) {
166 warn("DIOCGETQSTATS");
169 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
170 pa.altq.ifname)) != NULL) {
171 memcpy(&node->qstats.data, &qstats.data,
172 sizeof(qstats.data));
175 pfctl_insert_altq_node(root, pa.altq, qstats);
183 pfctl_insert_altq_node(struct pf_altq_node **root,
184 const struct pf_altq altq, const struct queue_stats qstats)
186 struct pf_altq_node *node;
188 node = calloc(1, sizeof(struct pf_altq_node));
190 err(1, "pfctl_insert_altq_node: calloc");
191 memcpy(&node->altq, &altq, sizeof(struct pf_altq));
192 memcpy(&node->qstats, &qstats, sizeof(qstats));
193 node->next = node->children = NULL;
197 else if (!altq.parent[0]) {
198 struct pf_altq_node *prev = *root;
200 while (prev->next != NULL)
204 struct pf_altq_node *parent;
206 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
208 errx(1, "parent %s not found", altq.parent);
209 if (parent->children == NULL)
210 parent->children = node;
212 struct pf_altq_node *prev = parent->children;
214 while (prev->next != NULL)
222 struct pf_altq_node *
223 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
226 struct pf_altq_node *node, *child;
228 for (node = root; node != NULL; node = node->next) {
229 if (!strcmp(node->altq.qname, qname)
230 && !(strcmp(node->altq.ifname, ifname)))
232 if (node->children != NULL) {
233 child = pfctl_find_altq_node(node->children, qname,
243 pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level,
246 const struct pf_altq_node *child;
251 print_altq(&node->altq, level, NULL, NULL);
253 if (node->children != NULL) {
255 for (child = node->children; child != NULL;
256 child = child->next) {
257 printf("%s", child->altq.qname);
258 if (child->next != NULL)
265 if (opts & PF_OPT_VERBOSE)
266 pfctl_print_altq_nodestat(dev, node);
268 if (opts & PF_OPT_DEBUG)
269 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
270 node->altq.qid, node->altq.ifname,
271 rate2str((double)(node->altq.ifbandwidth)));
273 for (child = node->children; child != NULL;
275 pfctl_print_altq_node(dev, child, level + 1, opts);
279 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
281 if (a->altq.qid == 0)
284 switch (a->altq.scheduler) {
286 print_cbqstats(a->qstats);
289 print_priqstats(a->qstats);
292 print_hfscstats(a->qstats);
298 print_cbqstats(struct queue_stats cur)
300 printf(" [ pkts: %10llu bytes: %10llu "
301 "dropped pkts: %6llu bytes: %6llu ]\n",
302 (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
303 (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
304 (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
305 (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
306 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
307 cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
308 cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
313 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
314 cur.avg_packets / STAT_INTERVAL,
315 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
319 print_priqstats(struct queue_stats cur)
321 printf(" [ pkts: %10llu bytes: %10llu "
322 "dropped pkts: %6llu bytes: %6llu ]\n",
323 (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
324 (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
325 (unsigned long long)cur.data.priq_stats.dropcnt.packets,
326 (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
327 printf(" [ qlength: %3d/%3d ]\n",
328 cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
333 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
334 cur.avg_packets / STAT_INTERVAL,
335 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
339 print_hfscstats(struct queue_stats cur)
341 printf(" [ pkts: %10llu bytes: %10llu "
342 "dropped pkts: %6llu bytes: %6llu ]\n",
343 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
344 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
345 (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
346 (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
347 printf(" [ qlength: %3d/%3d ]\n",
348 cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
353 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
354 cur.avg_packets / STAT_INTERVAL,
355 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
359 pfctl_free_altq_node(struct pf_altq_node *node)
361 while (node != NULL) {
362 struct pf_altq_node *prev;
364 if (node->children != NULL)
365 pfctl_free_altq_node(node->children);
373 update_avg(struct pf_altq_node *a)
375 struct queue_stats *qs;
379 if (a->altq.qid == 0)
385 switch (a->altq.scheduler) {
387 b = qs->data.cbq_stats.xmit_cnt.bytes;
388 p = qs->data.cbq_stats.xmit_cnt.packets;
391 b = qs->data.priq_stats.xmitcnt.bytes;
392 p = qs->data.priq_stats.xmitcnt.packets;
395 b = qs->data.hfsc_stats.xmit_cnt.bytes;
396 p = qs->data.hfsc_stats.xmit_cnt.packets;
406 qs->prev_packets = p;
411 if (b >= qs->prev_bytes)
412 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
413 (b - qs->prev_bytes)) / n;
415 if (p >= qs->prev_packets)
416 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
417 (p - qs->prev_packets)) / n;
420 qs->prev_packets = p;