1 /* $NetBSD: pfctl_qstats.c,v 1.4 2004/11/14 11:26:48 yamt Exp $ */
2 /* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc 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/pfvar.h>
27 #include <arpa/inet.h>
35 #include <altq/altq.h>
36 #include <altq/altq_cbq.h>
37 #include <altq/altq_priq.h>
38 #include <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)
95 printf("No queue in use\n");
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
);
106 while (verbose2
&& nodes
> 0) {
109 sleep(STAT_INTERVAL
);
110 if ((nodes
= 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
, unsigned level
,
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
, 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
);
292 print_cbqstats(struct queue_stats cur
)
294 printf(" [ pkts: %10llu bytes: %10llu "
295 "dropped pkts: %6llu bytes: %6llu ]\n",
296 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.packets
,
297 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.bytes
,
298 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.packets
,
299 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.bytes
);
300 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
301 cur
.data
.cbq_stats
.qcnt
, cur
.data
.cbq_stats
.qmax
,
302 cur
.data
.cbq_stats
.borrows
, cur
.data
.cbq_stats
.delays
);
307 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
308 cur
.avg_packets
/ STAT_INTERVAL
,
309 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
313 print_priqstats(struct queue_stats cur
)
315 printf(" [ pkts: %10llu bytes: %10llu "
316 "dropped pkts: %6llu bytes: %6llu ]\n",
317 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.packets
,
318 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.bytes
,
319 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.packets
,
320 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.bytes
);
321 printf(" [ qlength: %3d/%3d ]\n",
322 cur
.data
.priq_stats
.qlength
, cur
.data
.priq_stats
.qlimit
);
327 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
328 cur
.avg_packets
/ STAT_INTERVAL
,
329 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
333 print_hfscstats(struct queue_stats cur
)
335 printf(" [ pkts: %10llu bytes: %10llu "
336 "dropped pkts: %6llu bytes: %6llu ]\n",
337 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.packets
,
338 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.bytes
,
339 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.packets
,
340 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.bytes
);
341 printf(" [ qlength: %3d/%3d ]\n",
342 cur
.data
.hfsc_stats
.qlength
, cur
.data
.hfsc_stats
.qlimit
);
347 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
348 cur
.avg_packets
/ STAT_INTERVAL
,
349 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
353 pfctl_free_altq_node(struct pf_altq_node
*node
)
355 while (node
!= NULL
) {
356 struct pf_altq_node
*prev
;
358 if (node
->children
!= NULL
)
359 pfctl_free_altq_node(node
->children
);
367 update_avg(struct pf_altq_node
*a
)
369 struct queue_stats
*qs
;
373 if (a
->altq
.qid
== 0)
379 switch (a
->altq
.scheduler
) {
381 b
= qs
->data
.cbq_stats
.xmit_cnt
.bytes
;
382 p
= qs
->data
.cbq_stats
.xmit_cnt
.packets
;
385 b
= qs
->data
.priq_stats
.xmitcnt
.bytes
;
386 p
= qs
->data
.priq_stats
.xmitcnt
.packets
;
389 b
= qs
->data
.hfsc_stats
.xmit_cnt
.bytes
;
390 p
= qs
->data
.hfsc_stats
.xmit_cnt
.packets
;
400 qs
->prev_packets
= p
;
405 if (b
>= qs
->prev_bytes
)
406 qs
->avg_bytes
= ((qs
->avg_bytes
* (n
- 1)) +
407 (b
- qs
->prev_bytes
)) / n
;
409 if (p
>= qs
->prev_packets
)
410 qs
->avg_packets
= ((qs
->avg_packets
* (n
- 1)) +
411 (p
- qs
->prev_packets
)) / n
;
414 qs
->prev_packets
= p
;