1 /* $OpenBSD: pfctl_qstats.c,v 1.31 2007/10/15 02:16:35 deraadt 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/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <net/pf/pfvar.h>
26 #include <arpa/inet.h>
34 #include <net/altq/altq.h>
35 #include <net/altq/altq_cbq.h>
36 #include <net/altq/altq_priq.h>
37 #include <net/altq/altq_hfsc.h>
38 #include <net/altq/altq_fairq.h>
41 #include "pfctl_parser.h"
44 class_stats_t cbq_stats
;
45 struct priq_classstats priq_stats
;
46 struct hfsc_classstats hfsc_stats
;
47 struct fairq_classstats fairq_stats
;
51 #define STAT_INTERVAL 5
54 union class_stats data
;
59 u_int64_t prev_packets
;
64 struct pf_altq_node
*next
;
65 struct pf_altq_node
*children
;
66 struct queue_stats qstats
;
69 int pfctl_update_qstats(int, struct pf_altq_node
**);
70 void pfctl_insert_altq_node(struct pf_altq_node
**,
71 const struct pf_altq
, const struct queue_stats
);
72 struct pf_altq_node
*pfctl_find_altq_node(struct pf_altq_node
*,
73 const char *, const char *);
74 void pfctl_print_altq_node(int, const struct pf_altq_node
*,
76 void print_cbqstats(struct queue_stats
);
77 void print_priqstats(struct queue_stats
);
78 void print_hfscstats(struct queue_stats
);
79 void print_fairqstats(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
);
93 if ((nodes
= pfctl_update_qstats(dev
, &root
)) < 0)
96 for (node
= root
; node
!= NULL
; node
= node
->next
) {
97 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
100 pfctl_print_title("ALTQ:");
103 pfctl_print_altq_node(dev
, node
, 0, opts
);
109 sleep(STAT_INTERVAL
);
110 if (pfctl_update_qstats(dev
, &root
) == -1)
112 for (node
= root
; node
!= NULL
; node
= node
->next
) {
113 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
115 pfctl_print_altq_node(dev
, node
, 0, opts
);
118 pfctl_free_altq_node(root
);
123 pfctl_update_qstats(int dev
, struct pf_altq_node
**root
)
125 struct pf_altq_node
*node
;
126 struct pfioc_altq pa
;
127 struct pfioc_qstats pq
;
129 struct queue_stats qstats
;
130 static u_int32_t last_ticket
;
132 memset(&pa
, 0, sizeof(pa
));
133 memset(&pq
, 0, sizeof(pq
));
134 memset(&qstats
, 0, sizeof(qstats
));
135 if (ioctl(dev
, DIOCGETALTQS
, &pa
)) {
136 warn("DIOCGETALTQS");
140 /* if a new set is found, start over */
141 if (pa
.ticket
!= last_ticket
&& *root
!= NULL
) {
142 pfctl_free_altq_node(*root
);
145 last_ticket
= pa
.ticket
;
148 for (nr
= 0; nr
< mnr
; ++nr
) {
150 if (ioctl(dev
, DIOCGETALTQ
, &pa
)) {
154 if (pa
.altq
.qid
> 0) {
156 pq
.ticket
= pa
.ticket
;
157 pq
.buf
= &qstats
.data
;
158 pq
.nbytes
= sizeof(qstats
.data
);
159 if (ioctl(dev
, DIOCGETQSTATS
, &pq
)) {
160 warn("DIOCGETQSTATS");
163 if ((node
= pfctl_find_altq_node(*root
, pa
.altq
.qname
,
164 pa
.altq
.ifname
)) != NULL
) {
165 memcpy(&node
->qstats
.data
, &qstats
.data
,
166 sizeof(qstats
.data
));
169 pfctl_insert_altq_node(root
, pa
.altq
, qstats
);
177 pfctl_insert_altq_node(struct pf_altq_node
**root
,
178 const struct pf_altq altq
, const struct queue_stats qstats
)
180 struct pf_altq_node
*node
;
182 node
= calloc(1, sizeof(struct pf_altq_node
));
184 err(1, "pfctl_insert_altq_node: calloc");
185 memcpy(&node
->altq
, &altq
, sizeof(struct pf_altq
));
186 memcpy(&node
->qstats
, &qstats
, sizeof(qstats
));
187 node
->next
= node
->children
= NULL
;
191 else if (!altq
.parent
[0]) {
192 struct pf_altq_node
*prev
= *root
;
194 while (prev
->next
!= NULL
)
198 struct pf_altq_node
*parent
;
200 parent
= pfctl_find_altq_node(*root
, altq
.parent
, altq
.ifname
);
202 errx(1, "parent %s not found", altq
.parent
);
203 if (parent
->children
== NULL
)
204 parent
->children
= node
;
206 struct pf_altq_node
*prev
= parent
->children
;
208 while (prev
->next
!= NULL
)
216 struct pf_altq_node
*
217 pfctl_find_altq_node(struct pf_altq_node
*root
, const char *qname
,
220 struct pf_altq_node
*node
, *child
;
222 for (node
= root
; node
!= NULL
; node
= node
->next
) {
223 if (!strcmp(node
->altq
.qname
, qname
)
224 && !(strcmp(node
->altq
.ifname
, ifname
)))
226 if (node
->children
!= NULL
) {
227 child
= pfctl_find_altq_node(node
->children
, qname
,
237 pfctl_print_altq_node(int dev
, const struct pf_altq_node
*node
,
238 unsigned int level
, int opts
)
240 const struct pf_altq_node
*child
;
245 print_altq(&node
->altq
, level
, NULL
, NULL
);
247 if (node
->children
!= NULL
) {
249 for (child
= node
->children
; child
!= NULL
;
250 child
= child
->next
) {
251 printf("%s", child
->altq
.qname
);
252 if (child
->next
!= NULL
)
259 if (opts
& PF_OPT_VERBOSE
)
260 pfctl_print_altq_nodestat(dev
, node
);
262 if (opts
& PF_OPT_DEBUG
)
263 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
264 node
->altq
.qid
, node
->altq
.ifname
,
265 rate2str((double)(node
->altq
.ifbandwidth
)));
267 for (child
= node
->children
; child
!= NULL
;
269 pfctl_print_altq_node(dev
, child
, level
+ 1, opts
);
273 pfctl_print_altq_nodestat(int dev __unused
, const struct pf_altq_node
*a
)
275 if (a
->altq
.qid
== 0)
278 switch (a
->altq
.scheduler
) {
280 print_cbqstats(a
->qstats
);
283 print_priqstats(a
->qstats
);
286 print_hfscstats(a
->qstats
);
289 print_fairqstats(a
->qstats
);
295 print_cbqstats(struct queue_stats cur
)
297 printf(" [ pkts: %10llu bytes: %10llu "
298 "dropped pkts: %6llu bytes: %6llu ]\n",
299 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.packets
,
300 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.bytes
,
301 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.packets
,
302 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.bytes
);
303 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
304 cur
.data
.cbq_stats
.qcnt
, cur
.data
.cbq_stats
.qmax
,
305 cur
.data
.cbq_stats
.borrows
, cur
.data
.cbq_stats
.delays
);
310 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
311 cur
.avg_packets
/ STAT_INTERVAL
,
312 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
316 print_priqstats(struct queue_stats cur
)
318 printf(" [ pkts: %10llu bytes: %10llu "
319 "dropped pkts: %6llu bytes: %6llu ]\n",
320 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.packets
,
321 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.bytes
,
322 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.packets
,
323 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.bytes
);
324 printf(" [ qlength: %3d/%3d ]\n",
325 cur
.data
.priq_stats
.qlength
, cur
.data
.priq_stats
.qlimit
);
330 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
331 cur
.avg_packets
/ STAT_INTERVAL
,
332 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
336 print_hfscstats(struct queue_stats cur
)
338 printf(" [ pkts: %10llu bytes: %10llu "
339 "dropped pkts: %6llu bytes: %6llu ]\n",
340 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.packets
,
341 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.bytes
,
342 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.packets
,
343 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.bytes
);
344 printf(" [ qlength: %3d/%3d ]\n",
345 cur
.data
.hfsc_stats
.qlength
, cur
.data
.hfsc_stats
.qlimit
);
350 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
351 cur
.avg_packets
/ STAT_INTERVAL
,
352 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
356 print_fairqstats(struct queue_stats cur
)
358 printf(" [ pkts: %10llu bytes: %10llu "
359 "dropped pkts: %6llu bytes: %6llu ]\n",
360 (unsigned long long)cur
.data
.fairq_stats
.xmit_cnt
.packets
,
361 (unsigned long long)cur
.data
.fairq_stats
.xmit_cnt
.bytes
,
362 (unsigned long long)cur
.data
.fairq_stats
.drop_cnt
.packets
,
363 (unsigned long long)cur
.data
.fairq_stats
.drop_cnt
.bytes
);
364 printf(" [ qlength: %3d/%3d ]\n",
365 cur
.data
.fairq_stats
.qlength
, cur
.data
.fairq_stats
.qlimit
);
370 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
371 cur
.avg_packets
/ STAT_INTERVAL
,
372 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
377 pfctl_free_altq_node(struct pf_altq_node
*node
)
379 while (node
!= NULL
) {
380 struct pf_altq_node
*prev
;
382 if (node
->children
!= NULL
)
383 pfctl_free_altq_node(node
->children
);
391 update_avg(struct pf_altq_node
*a
)
393 struct queue_stats
*qs
;
397 if (a
->altq
.qid
== 0)
403 switch (a
->altq
.scheduler
) {
405 b
= qs
->data
.cbq_stats
.xmit_cnt
.bytes
;
406 p
= qs
->data
.cbq_stats
.xmit_cnt
.packets
;
409 b
= qs
->data
.priq_stats
.xmitcnt
.bytes
;
410 p
= qs
->data
.priq_stats
.xmitcnt
.packets
;
413 b
= qs
->data
.hfsc_stats
.xmit_cnt
.bytes
;
414 p
= qs
->data
.hfsc_stats
.xmit_cnt
.packets
;
417 b
= qs
->data
.fairq_stats
.xmit_cnt
.bytes
;
418 p
= qs
->data
.fairq_stats
.xmit_cnt
.packets
;
428 qs
->prev_packets
= p
;
433 if (b
>= qs
->prev_bytes
)
434 qs
->avg_bytes
= ((qs
->avg_bytes
* (n
- 1)) +
435 (b
- qs
->prev_bytes
)) / n
;
437 if (p
>= qs
->prev_packets
)
438 qs
->avg_packets
= ((qs
->avg_packets
* (n
- 1)) +
439 (p
- qs
->prev_packets
)) / n
;
442 qs
->prev_packets
= p
;