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 #define PFIOC_USE_LATEST
24 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <net/pfvar.h>
31 #include <arpa/inet.h>
39 #include <net/altq/altq.h>
40 #include <net/altq/altq_cbq.h>
41 #include <net/altq/altq_codel.h>
42 #include <net/altq/altq_priq.h>
43 #include <net/altq/altq_hfsc.h>
44 #include <net/altq/altq_fairq.h>
47 #include "pfctl_parser.h"
50 class_stats_t cbq_stats;
51 struct priq_classstats priq_stats;
52 struct hfsc_classstats hfsc_stats;
53 struct fairq_classstats fairq_stats;
54 struct codel_ifstats codel_stats;
58 #define STAT_INTERVAL 5
61 union class_stats data;
66 u_int64_t prev_packets;
71 struct pf_altq_node *next;
72 struct pf_altq_node *children;
73 struct queue_stats qstats;
76 int pfctl_update_qstats(int, struct pf_altq_node **);
77 void pfctl_insert_altq_node(struct pf_altq_node **,
78 const struct pf_altq, const struct queue_stats);
79 struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
80 const char *, const char *);
81 void pfctl_print_altq_node(int, const struct pf_altq_node *,
83 void print_cbqstats(struct queue_stats);
84 void print_codelstats(struct queue_stats);
85 void print_priqstats(struct queue_stats);
86 void print_hfscstats(struct queue_stats);
87 void print_fairqstats(struct queue_stats);
88 void pfctl_free_altq_node(struct pf_altq_node *);
89 void pfctl_print_altq_nodestat(int,
90 const struct pf_altq_node *);
92 void update_avg(struct pf_altq_node *);
95 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
97 struct pf_altq_node *root = NULL, *node;
98 int nodes, dotitle = (opts & PF_OPT_SHOWALL);
105 if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
109 printf("No queue in use\n");
110 for (node = root; node != NULL; node = node->next) {
111 if (iface != NULL && strcmp(node->altq.ifname, iface))
114 pfctl_print_title("ALTQ:");
117 pfctl_print_altq_node(dev, node, 0, opts);
120 while (verbose2 && nodes > 0) {
123 sleep(STAT_INTERVAL);
124 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
126 for (node = root; node != NULL; node = node->next) {
127 if (iface != NULL && strcmp(node->altq.ifname, iface))
130 if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
133 pfctl_print_altq_node(dev, node, 0, opts);
136 pfctl_free_altq_node(root);
141 pfctl_update_qstats(int dev, struct pf_altq_node **root)
143 struct pf_altq_node *node;
144 struct pfioc_altq pa;
145 struct pfioc_qstats pq;
147 struct queue_stats qstats;
148 static u_int32_t last_ticket;
150 memset(&pa, 0, sizeof(pa));
151 memset(&pq, 0, sizeof(pq));
152 memset(&qstats, 0, sizeof(qstats));
153 pa.version = PFIOC_ALTQ_VERSION;
154 if (ioctl(dev, DIOCGETALTQS, &pa)) {
155 warn("DIOCGETALTQS");
159 /* if a new set is found, start over */
160 if (pa.ticket != last_ticket && *root != NULL) {
161 pfctl_free_altq_node(*root);
164 last_ticket = pa.ticket;
167 for (nr = 0; nr < mnr; ++nr) {
169 if (ioctl(dev, DIOCGETALTQ, &pa)) {
174 if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
175 !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
177 if (pa.altq.qid > 0) {
180 pq.ticket = pa.ticket;
181 pq.buf = &qstats.data;
182 pq.nbytes = sizeof(qstats.data);
183 pq.version = altq_stats_version(pa.altq.scheduler);
184 if (ioctl(dev, DIOCGETQSTATS, &pq)) {
185 warn("DIOCGETQSTATS");
188 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
189 pa.altq.ifname)) != NULL) {
190 memcpy(&node->qstats.data, &qstats.data,
191 sizeof(qstats.data));
194 pfctl_insert_altq_node(root, pa.altq, qstats);
198 else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
199 memset(&qstats.data, 0, sizeof(qstats.data));
200 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
201 pa.altq.ifname)) != NULL) {
202 memcpy(&node->qstats.data, &qstats.data,
203 sizeof(qstats.data));
206 pfctl_insert_altq_node(root, pa.altq, qstats);
215 pfctl_insert_altq_node(struct pf_altq_node **root,
216 const struct pf_altq altq, const struct queue_stats qstats)
218 struct pf_altq_node *node;
220 node = calloc(1, sizeof(struct pf_altq_node));
222 err(1, "pfctl_insert_altq_node: calloc");
223 memcpy(&node->altq, &altq, sizeof(struct pf_altq));
224 memcpy(&node->qstats, &qstats, sizeof(qstats));
225 node->next = node->children = NULL;
229 else if (!altq.parent[0]) {
230 struct pf_altq_node *prev = *root;
232 while (prev->next != NULL)
236 struct pf_altq_node *parent;
238 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
240 errx(1, "parent %s not found", altq.parent);
241 if (parent->children == NULL)
242 parent->children = node;
244 struct pf_altq_node *prev = parent->children;
246 while (prev->next != NULL)
254 struct pf_altq_node *
255 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
258 struct pf_altq_node *node, *child;
260 for (node = root; node != NULL; node = node->next) {
261 if (!strcmp(node->altq.qname, qname)
262 && !(strcmp(node->altq.ifname, ifname)))
264 if (node->children != NULL) {
265 child = pfctl_find_altq_node(node->children, qname,
275 pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
276 unsigned int level, int opts)
278 const struct pf_altq_node *child;
283 print_altq(&node->altq, level, NULL, NULL);
285 if (node->children != NULL) {
287 for (child = node->children; child != NULL;
288 child = child->next) {
289 printf("%s", child->altq.qname);
290 if (child->next != NULL)
297 if (opts & PF_OPT_VERBOSE)
298 pfctl_print_altq_nodestat(dev, node);
300 if (opts & PF_OPT_DEBUG)
301 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
302 node->altq.qid, node->altq.ifname,
303 rate2str((double)(node->altq.ifbandwidth)));
305 for (child = node->children; child != NULL;
307 pfctl_print_altq_node(dev, child, level + 1, opts);
311 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
313 if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
317 if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
320 switch (a->altq.scheduler) {
322 print_cbqstats(a->qstats);
325 print_priqstats(a->qstats);
328 print_hfscstats(a->qstats);
331 print_fairqstats(a->qstats);
334 print_codelstats(a->qstats);
340 print_cbqstats(struct queue_stats cur)
342 printf(" [ pkts: %10llu bytes: %10llu "
343 "dropped pkts: %6llu bytes: %6llu ]\n",
344 (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
345 (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
346 (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
347 (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
348 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
349 cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
350 cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
355 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
356 cur.avg_packets / STAT_INTERVAL,
357 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
361 print_codelstats(struct queue_stats cur)
363 printf(" [ pkts: %10llu bytes: %10llu "
364 "dropped pkts: %6llu bytes: %6llu ]\n",
365 (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
366 (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
367 (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
368 cur.data.codel_stats.stats.drop_cnt.packets,
369 (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
370 cur.data.codel_stats.stats.drop_cnt.bytes);
371 printf(" [ qlength: %3d/%3d ]\n",
372 cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
377 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
378 cur.avg_packets / STAT_INTERVAL,
379 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
383 print_priqstats(struct queue_stats cur)
385 printf(" [ pkts: %10llu bytes: %10llu "
386 "dropped pkts: %6llu bytes: %6llu ]\n",
387 (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
388 (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
389 (unsigned long long)cur.data.priq_stats.dropcnt.packets,
390 (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
391 printf(" [ qlength: %3d/%3d ]\n",
392 cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
397 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
398 cur.avg_packets / STAT_INTERVAL,
399 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
403 print_hfscstats(struct queue_stats cur)
405 printf(" [ pkts: %10llu bytes: %10llu "
406 "dropped pkts: %6llu bytes: %6llu ]\n",
407 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
408 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
409 (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
410 (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
411 printf(" [ qlength: %3d/%3d ]\n",
412 cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
417 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
418 cur.avg_packets / STAT_INTERVAL,
419 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
423 print_fairqstats(struct queue_stats cur)
425 printf(" [ pkts: %10llu bytes: %10llu "
426 "dropped pkts: %6llu bytes: %6llu ]\n",
427 (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
428 (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
429 (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
430 (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
431 printf(" [ qlength: %3d/%3d ]\n",
432 cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
437 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
438 cur.avg_packets / STAT_INTERVAL,
439 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
443 pfctl_free_altq_node(struct pf_altq_node *node)
445 while (node != NULL) {
446 struct pf_altq_node *prev;
448 if (node->children != NULL)
449 pfctl_free_altq_node(node->children);
457 update_avg(struct pf_altq_node *a)
459 struct queue_stats *qs;
463 if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
469 switch (a->altq.scheduler) {
471 b = qs->data.cbq_stats.xmit_cnt.bytes;
472 p = qs->data.cbq_stats.xmit_cnt.packets;
475 b = qs->data.priq_stats.xmitcnt.bytes;
476 p = qs->data.priq_stats.xmitcnt.packets;
479 b = qs->data.hfsc_stats.xmit_cnt.bytes;
480 p = qs->data.hfsc_stats.xmit_cnt.packets;
483 b = qs->data.fairq_stats.xmit_cnt.bytes;
484 p = qs->data.fairq_stats.xmit_cnt.packets;
487 b = qs->data.codel_stats.cl_xmitcnt.bytes;
488 p = qs->data.codel_stats.cl_xmitcnt.packets;
498 qs->prev_packets = p;
503 if (b >= qs->prev_bytes)
504 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
505 (b - qs->prev_bytes)) / n;
507 if (p >= qs->prev_packets)
508 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
509 (p - qs->prev_packets)) / n;
512 qs->prev_packets = p;