1 /* $OpenBSD: pfctl_qstats.c,v 1.29 2004/03/15 15:25:44 dhartmei Exp $ */
2 /* $DragonFly: src/usr.sbin/pfctl/pfctl_qstats.c,v 1.2 2005/02/11 22:31:45 joerg Exp $ */
5 * Copyright (c) Henning Brauer <henning@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <net/pf/pfvar.h>
27 #include <arpa/inet.h>
35 #include <net/altq/altq.h>
36 #include <net/altq/altq_cbq.h>
37 #include <net/altq/altq_priq.h>
38 #include <net/altq/altq_hfsc.h>
41 #include "pfctl_parser.h"
44 class_stats_t cbq_stats
;
45 struct priq_classstats priq_stats
;
46 struct hfsc_classstats hfsc_stats
;
50 #define STAT_INTERVAL 5
53 union class_stats data
;
58 u_int64_t prev_packets
;
63 struct pf_altq_node
*next
;
64 struct pf_altq_node
*children
;
65 struct queue_stats qstats
;
68 int pfctl_update_qstats(int, struct pf_altq_node
**);
69 void pfctl_insert_altq_node(struct pf_altq_node
**,
70 const struct pf_altq
, const struct queue_stats
);
71 struct pf_altq_node
*pfctl_find_altq_node(struct pf_altq_node
*,
72 const char *, const char *);
73 void pfctl_print_altq_node(int, const struct pf_altq_node
*,
75 void print_cbqstats(struct queue_stats
);
76 void print_priqstats(struct queue_stats
);
77 void print_hfscstats(struct queue_stats
);
78 void pfctl_free_altq_node(struct pf_altq_node
*);
79 void pfctl_print_altq_nodestat(int,
80 const struct pf_altq_node
*);
82 void update_avg(struct pf_altq_node
*);
85 pfctl_show_altq(int dev
, const char *iface
, int opts
, int verbose2
)
87 struct pf_altq_node
*root
= NULL
, *node
;
88 int nodes
, dotitle
= (opts
& PF_OPT_SHOWALL
);
91 if ((nodes
= pfctl_update_qstats(dev
, &root
)) < 0)
94 for (node
= root
; node
!= NULL
; node
= node
->next
) {
95 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
98 pfctl_print_title("ALTQ:");
101 pfctl_print_altq_node(dev
, node
, 0, opts
);
107 sleep(STAT_INTERVAL
);
108 if (pfctl_update_qstats(dev
, &root
) == -1)
110 for (node
= root
; node
!= NULL
; node
= node
->next
) {
111 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
113 pfctl_print_altq_node(dev
, node
, 0, opts
);
116 pfctl_free_altq_node(root
);
121 pfctl_update_qstats(int dev
, struct pf_altq_node
**root
)
123 struct pf_altq_node
*node
;
124 struct pfioc_altq pa
;
125 struct pfioc_qstats pq
;
127 struct queue_stats qstats
;
128 static u_int32_t last_ticket
;
130 memset(&pa
, 0, sizeof(pa
));
131 memset(&pq
, 0, sizeof(pq
));
132 memset(&qstats
, 0, sizeof(qstats
));
133 if (ioctl(dev
, DIOCGETALTQS
, &pa
)) {
134 warn("DIOCGETALTQS");
138 /* if a new set is found, start over */
139 if (pa
.ticket
!= last_ticket
&& *root
!= NULL
) {
140 pfctl_free_altq_node(*root
);
143 last_ticket
= pa
.ticket
;
146 for (nr
= 0; nr
< mnr
; ++nr
) {
148 if (ioctl(dev
, DIOCGETALTQ
, &pa
)) {
152 if (pa
.altq
.qid
> 0) {
154 pq
.ticket
= pa
.ticket
;
155 pq
.buf
= &qstats
.data
;
156 pq
.nbytes
= sizeof(qstats
.data
);
157 if (ioctl(dev
, DIOCGETQSTATS
, &pq
)) {
158 warn("DIOCGETQSTATS");
161 if ((node
= pfctl_find_altq_node(*root
, pa
.altq
.qname
,
162 pa
.altq
.ifname
)) != NULL
) {
163 memcpy(&node
->qstats
.data
, &qstats
.data
,
164 sizeof(qstats
.data
));
167 pfctl_insert_altq_node(root
, pa
.altq
, qstats
);
175 pfctl_insert_altq_node(struct pf_altq_node
**root
,
176 const struct pf_altq altq
, const struct queue_stats qstats
)
178 struct pf_altq_node
*node
;
180 node
= calloc(1, sizeof(struct pf_altq_node
));
182 err(1, "pfctl_insert_altq_node: calloc");
183 memcpy(&node
->altq
, &altq
, sizeof(struct pf_altq
));
184 memcpy(&node
->qstats
, &qstats
, sizeof(qstats
));
185 node
->next
= node
->children
= NULL
;
189 else if (!altq
.parent
[0]) {
190 struct pf_altq_node
*prev
= *root
;
192 while (prev
->next
!= NULL
)
196 struct pf_altq_node
*parent
;
198 parent
= pfctl_find_altq_node(*root
, altq
.parent
, altq
.ifname
);
200 errx(1, "parent %s not found", altq
.parent
);
201 if (parent
->children
== NULL
)
202 parent
->children
= node
;
204 struct pf_altq_node
*prev
= parent
->children
;
206 while (prev
->next
!= NULL
)
214 struct pf_altq_node
*
215 pfctl_find_altq_node(struct pf_altq_node
*root
, const char *qname
,
218 struct pf_altq_node
*node
, *child
;
220 for (node
= root
; node
!= NULL
; node
= node
->next
) {
221 if (!strcmp(node
->altq
.qname
, qname
)
222 && !(strcmp(node
->altq
.ifname
, ifname
)))
224 if (node
->children
!= NULL
) {
225 child
= pfctl_find_altq_node(node
->children
, qname
,
235 pfctl_print_altq_node(int dev
, const struct pf_altq_node
*node
, unsigned level
,
238 const struct pf_altq_node
*child
;
243 print_altq(&node
->altq
, level
, NULL
, NULL
);
245 if (node
->children
!= NULL
) {
247 for (child
= node
->children
; child
!= NULL
;
248 child
= child
->next
) {
249 printf("%s", child
->altq
.qname
);
250 if (child
->next
!= NULL
)
257 if (opts
& PF_OPT_VERBOSE
)
258 pfctl_print_altq_nodestat(dev
, node
);
260 if (opts
& PF_OPT_DEBUG
)
261 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
262 node
->altq
.qid
, node
->altq
.ifname
,
263 rate2str((double)(node
->altq
.ifbandwidth
)));
265 for (child
= node
->children
; child
!= NULL
;
267 pfctl_print_altq_node(dev
, child
, level
+ 1, opts
);
271 pfctl_print_altq_nodestat(int dev __unused
, const struct pf_altq_node
*a
)
273 if (a
->altq
.qid
== 0)
276 switch (a
->altq
.scheduler
) {
278 print_cbqstats(a
->qstats
);
281 print_priqstats(a
->qstats
);
284 print_hfscstats(a
->qstats
);
290 print_cbqstats(struct queue_stats cur
)
292 printf(" [ pkts: %10llu bytes: %10llu "
293 "dropped pkts: %6llu bytes: %6llu ]\n",
294 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.packets
,
295 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.bytes
,
296 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.packets
,
297 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.bytes
);
298 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
299 cur
.data
.cbq_stats
.qcnt
, cur
.data
.cbq_stats
.qmax
,
300 cur
.data
.cbq_stats
.borrows
, cur
.data
.cbq_stats
.delays
);
305 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
306 cur
.avg_packets
/ STAT_INTERVAL
,
307 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
311 print_priqstats(struct queue_stats cur
)
313 printf(" [ pkts: %10llu bytes: %10llu "
314 "dropped pkts: %6llu bytes: %6llu ]\n",
315 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.packets
,
316 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.bytes
,
317 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.packets
,
318 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.bytes
);
319 printf(" [ qlength: %3d/%3d ]\n",
320 cur
.data
.priq_stats
.qlength
, cur
.data
.priq_stats
.qlimit
);
325 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
326 cur
.avg_packets
/ STAT_INTERVAL
,
327 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
331 print_hfscstats(struct queue_stats cur
)
333 printf(" [ pkts: %10llu bytes: %10llu "
334 "dropped pkts: %6llu bytes: %6llu ]\n",
335 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.packets
,
336 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.bytes
,
337 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.packets
,
338 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.bytes
);
339 printf(" [ qlength: %3d/%3d ]\n",
340 cur
.data
.hfsc_stats
.qlength
, cur
.data
.hfsc_stats
.qlimit
);
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 pfctl_free_altq_node(struct pf_altq_node
*node
)
353 while (node
!= NULL
) {
354 struct pf_altq_node
*prev
;
356 if (node
->children
!= NULL
)
357 pfctl_free_altq_node(node
->children
);
365 update_avg(struct pf_altq_node
*a
)
367 struct queue_stats
*qs
;
371 if (a
->altq
.qid
== 0)
377 switch (a
->altq
.scheduler
) {
379 b
= qs
->data
.cbq_stats
.xmit_cnt
.bytes
;
380 p
= qs
->data
.cbq_stats
.xmit_cnt
.packets
;
383 b
= qs
->data
.priq_stats
.xmitcnt
.bytes
;
384 p
= qs
->data
.priq_stats
.xmitcnt
.packets
;
387 b
= qs
->data
.hfsc_stats
.xmit_cnt
.bytes
;
388 p
= qs
->data
.hfsc_stats
.xmit_cnt
.packets
;
398 qs
->prev_packets
= p
;
403 if (b
>= qs
->prev_bytes
)
404 qs
->avg_bytes
= ((qs
->avg_bytes
* (n
- 1)) +
405 (b
- qs
->prev_bytes
)) / n
;
407 if (p
>= qs
->prev_packets
)
408 qs
->avg_packets
= ((qs
->avg_packets
* (n
- 1)) +
409 (p
- qs
->prev_packets
)) / n
;
412 qs
->prev_packets
= p
;