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 <net/altq/altq.h>
38 #include <net/altq/altq_cbq.h>
39 #include <net/altq/altq_priq.h>
40 #include <net/altq/altq_hfsc.h>
41 #include <net/altq/altq_fairq.h>
44 #include "pfctl_parser.h"
47 class_stats_t cbq_stats;
48 struct priq_classstats priq_stats;
49 struct hfsc_classstats hfsc_stats;
50 struct fairq_classstats fairq_stats;
54 #define STAT_INTERVAL 5
57 union class_stats data;
62 u_int64_t prev_packets;
67 struct pf_altq_node *next;
68 struct pf_altq_node *children;
69 struct queue_stats qstats;
72 int pfctl_update_qstats(int, struct pf_altq_node **);
73 void pfctl_insert_altq_node(struct pf_altq_node **,
74 const struct pf_altq, const struct queue_stats);
75 struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
76 const char *, const char *);
77 void pfctl_print_altq_node(int, const struct pf_altq_node *,
79 void print_cbqstats(struct queue_stats);
80 void print_priqstats(struct queue_stats);
81 void print_hfscstats(struct queue_stats);
82 void print_fairqstats(struct queue_stats);
83 void pfctl_free_altq_node(struct pf_altq_node *);
84 void pfctl_print_altq_nodestat(int,
85 const struct pf_altq_node *);
87 void update_avg(struct pf_altq_node *);
90 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
92 struct pf_altq_node *root = NULL, *node;
93 int nodes, dotitle = (opts & PF_OPT_SHOWALL);
100 if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
104 printf("No queue in use\n");
105 for (node = root; node != NULL; node = node->next) {
106 if (iface != NULL && strcmp(node->altq.ifname, iface))
109 pfctl_print_title("ALTQ:");
112 pfctl_print_altq_node(dev, node, 0, opts);
115 while (verbose2 && nodes > 0) {
118 sleep(STAT_INTERVAL);
119 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
121 for (node = root; node != NULL; node = node->next) {
122 if (iface != NULL && strcmp(node->altq.ifname, iface))
125 if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
128 pfctl_print_altq_node(dev, node, 0, opts);
131 pfctl_free_altq_node(root);
136 pfctl_update_qstats(int dev, struct pf_altq_node **root)
138 struct pf_altq_node *node;
139 struct pfioc_altq pa;
140 struct pfioc_qstats pq;
142 struct queue_stats qstats;
143 static u_int32_t last_ticket;
145 memset(&pa, 0, sizeof(pa));
146 memset(&pq, 0, sizeof(pq));
147 memset(&qstats, 0, sizeof(qstats));
148 if (ioctl(dev, DIOCGETALTQS, &pa)) {
149 warn("DIOCGETALTQS");
153 /* if a new set is found, start over */
154 if (pa.ticket != last_ticket && *root != NULL) {
155 pfctl_free_altq_node(*root);
158 last_ticket = pa.ticket;
161 for (nr = 0; nr < mnr; ++nr) {
163 if (ioctl(dev, DIOCGETALTQ, &pa)) {
168 if (pa.altq.qid > 0 &&
169 !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
171 if (pa.altq.qid > 0) {
174 pq.ticket = pa.ticket;
175 pq.buf = &qstats.data;
176 pq.nbytes = sizeof(qstats.data);
177 if (ioctl(dev, DIOCGETQSTATS, &pq)) {
178 warn("DIOCGETQSTATS");
181 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
182 pa.altq.ifname)) != NULL) {
183 memcpy(&node->qstats.data, &qstats.data,
184 sizeof(qstats.data));
187 pfctl_insert_altq_node(root, pa.altq, qstats);
191 else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
192 memset(&qstats.data, 0, sizeof(qstats.data));
193 if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
194 pa.altq.ifname)) != NULL) {
195 memcpy(&node->qstats.data, &qstats.data,
196 sizeof(qstats.data));
199 pfctl_insert_altq_node(root, pa.altq, qstats);
208 pfctl_insert_altq_node(struct pf_altq_node **root,
209 const struct pf_altq altq, const struct queue_stats qstats)
211 struct pf_altq_node *node;
213 node = calloc(1, sizeof(struct pf_altq_node));
215 err(1, "pfctl_insert_altq_node: calloc");
216 memcpy(&node->altq, &altq, sizeof(struct pf_altq));
217 memcpy(&node->qstats, &qstats, sizeof(qstats));
218 node->next = node->children = NULL;
222 else if (!altq.parent[0]) {
223 struct pf_altq_node *prev = *root;
225 while (prev->next != NULL)
229 struct pf_altq_node *parent;
231 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
233 errx(1, "parent %s not found", altq.parent);
234 if (parent->children == NULL)
235 parent->children = node;
237 struct pf_altq_node *prev = parent->children;
239 while (prev->next != NULL)
247 struct pf_altq_node *
248 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
251 struct pf_altq_node *node, *child;
253 for (node = root; node != NULL; node = node->next) {
254 if (!strcmp(node->altq.qname, qname)
255 && !(strcmp(node->altq.ifname, ifname)))
257 if (node->children != NULL) {
258 child = pfctl_find_altq_node(node->children, qname,
268 pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
269 unsigned int level, int opts)
271 const struct pf_altq_node *child;
276 print_altq(&node->altq, level, NULL, NULL);
278 if (node->children != NULL) {
280 for (child = node->children; child != NULL;
281 child = child->next) {
282 printf("%s", child->altq.qname);
283 if (child->next != NULL)
290 if (opts & PF_OPT_VERBOSE)
291 pfctl_print_altq_nodestat(dev, node);
293 if (opts & PF_OPT_DEBUG)
294 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
295 node->altq.qid, node->altq.ifname,
296 rate2str((double)(node->altq.ifbandwidth)));
298 for (child = node->children; child != NULL;
300 pfctl_print_altq_node(dev, child, level + 1, opts);
304 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
306 if (a->altq.qid == 0)
310 if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
313 switch (a->altq.scheduler) {
315 print_cbqstats(a->qstats);
318 print_priqstats(a->qstats);
321 print_hfscstats(a->qstats);
324 print_fairqstats(a->qstats);
330 print_cbqstats(struct queue_stats cur)
332 printf(" [ pkts: %10llu bytes: %10llu "
333 "dropped pkts: %6llu bytes: %6llu ]\n",
334 (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
335 (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
336 (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
337 (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
338 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
339 cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
340 cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
345 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
346 cur.avg_packets / STAT_INTERVAL,
347 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
351 print_priqstats(struct queue_stats cur)
353 printf(" [ pkts: %10llu bytes: %10llu "
354 "dropped pkts: %6llu bytes: %6llu ]\n",
355 (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
356 (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
357 (unsigned long long)cur.data.priq_stats.dropcnt.packets,
358 (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
359 printf(" [ qlength: %3d/%3d ]\n",
360 cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
365 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
366 cur.avg_packets / STAT_INTERVAL,
367 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
371 print_hfscstats(struct queue_stats cur)
373 printf(" [ pkts: %10llu bytes: %10llu "
374 "dropped pkts: %6llu bytes: %6llu ]\n",
375 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
376 (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
377 (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
378 (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
379 printf(" [ qlength: %3d/%3d ]\n",
380 cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
385 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
386 cur.avg_packets / STAT_INTERVAL,
387 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
391 print_fairqstats(struct queue_stats cur)
393 printf(" [ pkts: %10llu bytes: %10llu "
394 "dropped pkts: %6llu bytes: %6llu ]\n",
395 (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
396 (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
397 (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
398 (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
399 printf(" [ qlength: %3d/%3d ]\n",
400 cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
405 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
406 cur.avg_packets / STAT_INTERVAL,
407 rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
411 pfctl_free_altq_node(struct pf_altq_node *node)
413 while (node != NULL) {
414 struct pf_altq_node *prev;
416 if (node->children != NULL)
417 pfctl_free_altq_node(node->children);
425 update_avg(struct pf_altq_node *a)
427 struct queue_stats *qs;
431 if (a->altq.qid == 0)
437 switch (a->altq.scheduler) {
439 b = qs->data.cbq_stats.xmit_cnt.bytes;
440 p = qs->data.cbq_stats.xmit_cnt.packets;
443 b = qs->data.priq_stats.xmitcnt.bytes;
444 p = qs->data.priq_stats.xmitcnt.packets;
447 b = qs->data.hfsc_stats.xmit_cnt.bytes;
448 p = qs->data.hfsc_stats.xmit_cnt.packets;
451 b = qs->data.fairq_stats.xmit_cnt.bytes;
452 p = qs->data.fairq_stats.xmit_cnt.packets;
462 qs->prev_packets = p;
467 if (b >= qs->prev_bytes)
468 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
469 (b - qs->prev_bytes)) / n;
471 if (p >= qs->prev_packets)
472 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
473 (p - qs->prev_packets)) / n;
476 qs->prev_packets = p;