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_codel.h>
40 #include <altq/altq_priq.h>
41 #include <altq/altq_hfsc.h>
42 #include <altq/altq_fairq.h>
45 #include "pfctl_parser.h"
48 class_stats_t cbq_stats;
49 struct priq_classstats priq_stats;
50 struct hfsc_classstats hfsc_stats;
51 struct fairq_classstats fairq_stats;
52 struct codel_ifstats codel_stats;
56 #define STAT_INTERVAL 5
59 union class_stats data;
64 u_int64_t prev_packets;
69 struct pf_altq_node *next;
70 struct pf_altq_node *children;
71 struct queue_stats qstats;
74 int pfctl_update_qstats(int, struct pf_altq_node **);
75 void pfctl_insert_altq_node(struct pf_altq_node **,
76 const struct pf_altq, const struct queue_stats);
77 struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
78 const char *, const char *);
79 void pfctl_print_altq_node(int, const struct pf_altq_node *,
81 void print_cbqstats(struct queue_stats);
82 void print_codelstats(struct queue_stats);
83 void print_priqstats(struct queue_stats);
84 void print_hfscstats(struct queue_stats);
85 void print_fairqstats(struct queue_stats);
86 void pfctl_free_altq_node(struct pf_altq_node *);
87 void pfctl_print_altq_nodestat(int,
88 const struct pf_altq_node *);
90 void update_avg(struct pf_altq_node *);
93 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
95 struct pf_altq_node *root = NULL, *node;
96 int nodes, dotitle = (opts & PF_OPT_SHOWALL);
103 if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
107 printf("No queue in use\n");
108 for (node = root; node != NULL; node = node->next) {
109 if (iface != NULL && strcmp(node->altq.ifname, iface))
112 pfctl_print_title("ALTQ:");
115 pfctl_print_altq_node(dev, node, 0, opts);
118 while (verbose2 && nodes > 0) {
121 sleep(STAT_INTERVAL);
122 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
124 for (node = root; node != NULL; node = node->next) {
125 if (iface != NULL && strcmp(node->altq.ifname, iface))
128 if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
131 pfctl_print_altq_node(dev, node, 0, opts);
134 pfctl_free_altq_node(root);
139 pfctl_update_qstats(int dev, struct pf_altq_node **root)
141 struct pf_altq_node *node;
142 struct pfioc_altq pa;
143 struct pfioc_qstats pq;
145 struct queue_stats qstats;
146 static u_int32_t last_ticket;
148 memset(&pa, 0, sizeof(pa));
149 memset(&pq, 0, sizeof(pq));
150 memset(&qstats, 0, sizeof(qstats));
151 if (ioctl(dev, DIOCGETALTQS, &pa)) {
152 warn("DIOCGETALTQS");
156 /* if a new set is found, start over */
157 if (pa.ticket != last_ticket && *root != NULL) {
158 pfctl_free_altq_node(*root);
161 last_ticket = pa.ticket;
164 for (nr = 0; nr < mnr; ++nr) {
166 if (ioctl(dev, DIOCGETALTQ, &pa)) {
171 if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
172 !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
174 if (pa.altq.qid > 0) {
177 pq.ticket = pa.ticket;
178 pq.buf = &qstats.data;
179 pq.nbytes = sizeof(qstats.data);
180 if (ioctl(dev, DIOCGETQSTATS, &pq)) {
181 warn("DIOCGETQSTATS");
184 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
185 pa.altq.ifname)) != NULL) {
186 memcpy(&node->qstats.data, &qstats.data,
187 sizeof(qstats.data));
190 pfctl_insert_altq_node(root, pa.altq, qstats);
194 else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
195 memset(&qstats.data, 0, sizeof(qstats.data));
196 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
197 pa.altq.ifname)) != NULL) {
198 memcpy(&node->qstats.data, &qstats.data,
199 sizeof(qstats.data));
202 pfctl_insert_altq_node(root, pa.altq, qstats);
211 pfctl_insert_altq_node(struct pf_altq_node **root,
212 const struct pf_altq altq, const struct queue_stats qstats)
214 struct pf_altq_node *node;
216 node = calloc(1, sizeof(struct pf_altq_node));
218 err(1, "pfctl_insert_altq_node: calloc");
219 memcpy(&node->altq, &altq, sizeof(struct pf_altq));
220 memcpy(&node->qstats, &qstats, sizeof(qstats));
221 node->next = node->children = NULL;
225 else if (!altq.parent[0]) {
226 struct pf_altq_node *prev = *root;
228 while (prev->next != NULL)
232 struct pf_altq_node *parent;
234 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
236 errx(1, "parent %s not found", altq.parent);
237 if (parent->children == NULL)
238 parent->children = node;
240 struct pf_altq_node *prev = parent->children;
242 while (prev->next != NULL)
250 struct pf_altq_node *
251 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
254 struct pf_altq_node *node, *child;
256 for (node = root; node != NULL; node = node->next) {
257 if (!strcmp(node->altq.qname, qname)
258 && !(strcmp(node->altq.ifname, ifname)))
260 if (node->children != NULL) {
261 child = pfctl_find_altq_node(node->children, qname,
271 pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
272 unsigned int level, int opts)
274 const struct pf_altq_node *child;
279 print_altq(&node->altq, level, NULL, NULL);
281 if (node->children != NULL) {
283 for (child = node->children; child != NULL;
284 child = child->next) {
285 printf("%s", child->altq.qname);
286 if (child->next != NULL)
293 if (opts & PF_OPT_VERBOSE)
294 pfctl_print_altq_nodestat(dev, node);
296 if (opts & PF_OPT_DEBUG)
297 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
298 node->altq.qid, node->altq.ifname,
299 rate2str((double)(node->altq.ifbandwidth)));
301 for (child = node->children; child != NULL;
303 pfctl_print_altq_node(dev, child, level + 1, opts);
307 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
309 if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
313 if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
316 switch (a->altq.scheduler) {
318 print_cbqstats(a->qstats);
321 print_priqstats(a->qstats);
324 print_hfscstats(a->qstats);
327 print_fairqstats(a->qstats);
330 print_codelstats(a->qstats);
336 print_cbqstats(struct queue_stats cur)
338 printf(" [ pkts: %10llu bytes: %10llu "
339 "dropped pkts: %6llu bytes: %6llu ]\n",
340 (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
341 (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
342 (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
343 (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
344 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
345 cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
346 cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
351 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
352 cur.avg_packets / STAT_INTERVAL,
353 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
357 print_codelstats(struct queue_stats cur)
359 printf(" [ pkts: %10llu bytes: %10llu "
360 "dropped pkts: %6llu bytes: %6llu ]\n",
361 (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
362 (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
363 (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
364 cur.data.codel_stats.stats.drop_cnt.packets,
365 (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
366 cur.data.codel_stats.stats.drop_cnt.bytes);
367 printf(" [ qlength: %3d/%3d ]\n",
368 cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
373 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
374 cur.avg_packets / STAT_INTERVAL,
375 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
379 print_priqstats(struct queue_stats cur)
381 printf(" [ pkts: %10llu bytes: %10llu "
382 "dropped pkts: %6llu bytes: %6llu ]\n",
383 (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
384 (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
385 (unsigned long long)cur.data.priq_stats.dropcnt.packets,
386 (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
387 printf(" [ qlength: %3d/%3d ]\n",
388 cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
393 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
394 cur.avg_packets / STAT_INTERVAL,
395 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
399 print_hfscstats(struct queue_stats cur)
401 printf(" [ pkts: %10llu bytes: %10llu "
402 "dropped pkts: %6llu bytes: %6llu ]\n",
403 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
404 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
405 (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
406 (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
407 printf(" [ qlength: %3d/%3d ]\n",
408 cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
413 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
414 cur.avg_packets / STAT_INTERVAL,
415 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
419 print_fairqstats(struct queue_stats cur)
421 printf(" [ pkts: %10llu bytes: %10llu "
422 "dropped pkts: %6llu bytes: %6llu ]\n",
423 (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
424 (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
425 (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
426 (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
427 printf(" [ qlength: %3d/%3d ]\n",
428 cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
433 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
434 cur.avg_packets / STAT_INTERVAL,
435 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
439 pfctl_free_altq_node(struct pf_altq_node *node)
441 while (node != NULL) {
442 struct pf_altq_node *prev;
444 if (node->children != NULL)
445 pfctl_free_altq_node(node->children);
453 update_avg(struct pf_altq_node *a)
455 struct queue_stats *qs;
459 if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
465 switch (a->altq.scheduler) {
467 b = qs->data.cbq_stats.xmit_cnt.bytes;
468 p = qs->data.cbq_stats.xmit_cnt.packets;
471 b = qs->data.priq_stats.xmitcnt.bytes;
472 p = qs->data.priq_stats.xmitcnt.packets;
475 b = qs->data.hfsc_stats.xmit_cnt.bytes;
476 p = qs->data.hfsc_stats.xmit_cnt.packets;
479 b = qs->data.fairq_stats.xmit_cnt.bytes;
480 p = qs->data.fairq_stats.xmit_cnt.packets;
483 b = qs->data.codel_stats.cl_xmitcnt.bytes;
484 p = qs->data.codel_stats.cl_xmitcnt.packets;
494 qs->prev_packets = p;
499 if (b >= qs->prev_bytes)
500 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
501 (b - qs->prev_bytes)) / n;
503 if (p >= qs->prev_packets)
504 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
505 (p - qs->prev_packets)) / n;
508 qs->prev_packets = p;