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.3 2008/04/06 18:58:14 dillon 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>
39 #include <net/altq/altq_fairq.h>
42 #include "pfctl_parser.h"
45 class_stats_t cbq_stats
;
46 struct priq_classstats priq_stats
;
47 struct hfsc_classstats hfsc_stats
;
48 struct fairq_classstats fairq_stats
;
52 #define STAT_INTERVAL 5
55 union class_stats data
;
60 u_int64_t prev_packets
;
65 struct pf_altq_node
*next
;
66 struct pf_altq_node
*children
;
67 struct queue_stats qstats
;
70 int pfctl_update_qstats(int, struct pf_altq_node
**);
71 void pfctl_insert_altq_node(struct pf_altq_node
**,
72 const struct pf_altq
, const struct queue_stats
);
73 struct pf_altq_node
*pfctl_find_altq_node(struct pf_altq_node
*,
74 const char *, const char *);
75 void pfctl_print_altq_node(int, const struct pf_altq_node
*,
77 void print_cbqstats(struct queue_stats
);
78 void print_priqstats(struct queue_stats
);
79 void print_hfscstats(struct queue_stats
);
80 void print_fairqstats(struct queue_stats
);
81 void pfctl_free_altq_node(struct pf_altq_node
*);
82 void pfctl_print_altq_nodestat(int,
83 const struct pf_altq_node
*);
85 void update_avg(struct pf_altq_node
*);
88 pfctl_show_altq(int dev
, const char *iface
, int opts
, int verbose2
)
90 struct pf_altq_node
*root
= NULL
, *node
;
91 int nodes
, dotitle
= (opts
& PF_OPT_SHOWALL
);
94 if ((nodes
= pfctl_update_qstats(dev
, &root
)) < 0)
97 for (node
= root
; node
!= NULL
; node
= node
->next
) {
98 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
101 pfctl_print_title("ALTQ:");
104 pfctl_print_altq_node(dev
, node
, 0, opts
);
110 sleep(STAT_INTERVAL
);
111 if (pfctl_update_qstats(dev
, &root
) == -1)
113 for (node
= root
; node
!= NULL
; node
= node
->next
) {
114 if (iface
!= NULL
&& strcmp(node
->altq
.ifname
, iface
))
116 pfctl_print_altq_node(dev
, node
, 0, opts
);
119 pfctl_free_altq_node(root
);
124 pfctl_update_qstats(int dev
, struct pf_altq_node
**root
)
126 struct pf_altq_node
*node
;
127 struct pfioc_altq pa
;
128 struct pfioc_qstats pq
;
130 struct queue_stats qstats
;
131 static u_int32_t last_ticket
;
133 memset(&pa
, 0, sizeof(pa
));
134 memset(&pq
, 0, sizeof(pq
));
135 memset(&qstats
, 0, sizeof(qstats
));
136 if (ioctl(dev
, DIOCGETALTQS
, &pa
)) {
137 warn("DIOCGETALTQS");
141 /* if a new set is found, start over */
142 if (pa
.ticket
!= last_ticket
&& *root
!= NULL
) {
143 pfctl_free_altq_node(*root
);
146 last_ticket
= pa
.ticket
;
149 for (nr
= 0; nr
< mnr
; ++nr
) {
151 if (ioctl(dev
, DIOCGETALTQ
, &pa
)) {
155 if (pa
.altq
.qid
> 0) {
157 pq
.ticket
= pa
.ticket
;
158 pq
.buf
= &qstats
.data
;
159 pq
.nbytes
= sizeof(qstats
.data
);
160 if (ioctl(dev
, DIOCGETQSTATS
, &pq
)) {
161 warn("DIOCGETQSTATS");
164 if ((node
= pfctl_find_altq_node(*root
, pa
.altq
.qname
,
165 pa
.altq
.ifname
)) != NULL
) {
166 memcpy(&node
->qstats
.data
, &qstats
.data
,
167 sizeof(qstats
.data
));
170 pfctl_insert_altq_node(root
, pa
.altq
, qstats
);
178 pfctl_insert_altq_node(struct pf_altq_node
**root
,
179 const struct pf_altq altq
, const struct queue_stats qstats
)
181 struct pf_altq_node
*node
;
183 node
= calloc(1, sizeof(struct pf_altq_node
));
185 err(1, "pfctl_insert_altq_node: calloc");
186 memcpy(&node
->altq
, &altq
, sizeof(struct pf_altq
));
187 memcpy(&node
->qstats
, &qstats
, sizeof(qstats
));
188 node
->next
= node
->children
= NULL
;
192 else if (!altq
.parent
[0]) {
193 struct pf_altq_node
*prev
= *root
;
195 while (prev
->next
!= NULL
)
199 struct pf_altq_node
*parent
;
201 parent
= pfctl_find_altq_node(*root
, altq
.parent
, altq
.ifname
);
203 errx(1, "parent %s not found", altq
.parent
);
204 if (parent
->children
== NULL
)
205 parent
->children
= node
;
207 struct pf_altq_node
*prev
= parent
->children
;
209 while (prev
->next
!= NULL
)
217 struct pf_altq_node
*
218 pfctl_find_altq_node(struct pf_altq_node
*root
, const char *qname
,
221 struct pf_altq_node
*node
, *child
;
223 for (node
= root
; node
!= NULL
; node
= node
->next
) {
224 if (!strcmp(node
->altq
.qname
, qname
)
225 && !(strcmp(node
->altq
.ifname
, ifname
)))
227 if (node
->children
!= NULL
) {
228 child
= pfctl_find_altq_node(node
->children
, qname
,
238 pfctl_print_altq_node(int dev
, const struct pf_altq_node
*node
, unsigned level
,
241 const struct pf_altq_node
*child
;
246 print_altq(&node
->altq
, level
, NULL
, NULL
);
248 if (node
->children
!= NULL
) {
250 for (child
= node
->children
; child
!= NULL
;
251 child
= child
->next
) {
252 printf("%s", child
->altq
.qname
);
253 if (child
->next
!= NULL
)
260 if (opts
& PF_OPT_VERBOSE
)
261 pfctl_print_altq_nodestat(dev
, node
);
263 if (opts
& PF_OPT_DEBUG
)
264 printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
265 node
->altq
.qid
, node
->altq
.ifname
,
266 rate2str((double)(node
->altq
.ifbandwidth
)));
268 for (child
= node
->children
; child
!= NULL
;
270 pfctl_print_altq_node(dev
, child
, level
+ 1, opts
);
274 pfctl_print_altq_nodestat(int dev __unused
, const struct pf_altq_node
*a
)
276 if (a
->altq
.qid
== 0)
279 switch (a
->altq
.scheduler
) {
281 print_cbqstats(a
->qstats
);
284 print_priqstats(a
->qstats
);
287 print_hfscstats(a
->qstats
);
290 print_fairqstats(a
->qstats
);
296 print_cbqstats(struct queue_stats cur
)
298 printf(" [ pkts: %10llu bytes: %10llu "
299 "dropped pkts: %6llu bytes: %6llu ]\n",
300 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.packets
,
301 (unsigned long long)cur
.data
.cbq_stats
.xmit_cnt
.bytes
,
302 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.packets
,
303 (unsigned long long)cur
.data
.cbq_stats
.drop_cnt
.bytes
);
304 printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
305 cur
.data
.cbq_stats
.qcnt
, cur
.data
.cbq_stats
.qmax
,
306 cur
.data
.cbq_stats
.borrows
, cur
.data
.cbq_stats
.delays
);
311 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
312 cur
.avg_packets
/ STAT_INTERVAL
,
313 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
317 print_priqstats(struct queue_stats cur
)
319 printf(" [ pkts: %10llu bytes: %10llu "
320 "dropped pkts: %6llu bytes: %6llu ]\n",
321 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.packets
,
322 (unsigned long long)cur
.data
.priq_stats
.xmitcnt
.bytes
,
323 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.packets
,
324 (unsigned long long)cur
.data
.priq_stats
.dropcnt
.bytes
);
325 printf(" [ qlength: %3d/%3d ]\n",
326 cur
.data
.priq_stats
.qlength
, cur
.data
.priq_stats
.qlimit
);
331 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
332 cur
.avg_packets
/ STAT_INTERVAL
,
333 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
337 print_hfscstats(struct queue_stats cur
)
339 printf(" [ pkts: %10llu bytes: %10llu "
340 "dropped pkts: %6llu bytes: %6llu ]\n",
341 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.packets
,
342 (unsigned long long)cur
.data
.hfsc_stats
.xmit_cnt
.bytes
,
343 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.packets
,
344 (unsigned long long)cur
.data
.hfsc_stats
.drop_cnt
.bytes
);
345 printf(" [ qlength: %3d/%3d ]\n",
346 cur
.data
.hfsc_stats
.qlength
, cur
.data
.hfsc_stats
.qlimit
);
351 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
352 cur
.avg_packets
/ STAT_INTERVAL
,
353 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
357 print_fairqstats(struct queue_stats cur
)
359 printf(" [ pkts: %10llu bytes: %10llu "
360 "dropped pkts: %6llu bytes: %6llu ]\n",
361 (unsigned long long)cur
.data
.fairq_stats
.xmit_cnt
.packets
,
362 (unsigned long long)cur
.data
.fairq_stats
.xmit_cnt
.bytes
,
363 (unsigned long long)cur
.data
.fairq_stats
.drop_cnt
.packets
,
364 (unsigned long long)cur
.data
.fairq_stats
.drop_cnt
.bytes
);
365 printf(" [ qlength: %3d/%3d ]\n",
366 cur
.data
.fairq_stats
.qlength
, cur
.data
.fairq_stats
.qlimit
);
371 printf(" [ measured: %7.1f packets/s, %s/s ]\n",
372 cur
.avg_packets
/ STAT_INTERVAL
,
373 rate2str((8 * cur
.avg_bytes
) / STAT_INTERVAL
));
378 pfctl_free_altq_node(struct pf_altq_node
*node
)
380 while (node
!= NULL
) {
381 struct pf_altq_node
*prev
;
383 if (node
->children
!= NULL
)
384 pfctl_free_altq_node(node
->children
);
392 update_avg(struct pf_altq_node
*a
)
394 struct queue_stats
*qs
;
398 if (a
->altq
.qid
== 0)
404 switch (a
->altq
.scheduler
) {
406 b
= qs
->data
.cbq_stats
.xmit_cnt
.bytes
;
407 p
= qs
->data
.cbq_stats
.xmit_cnt
.packets
;
410 b
= qs
->data
.priq_stats
.xmitcnt
.bytes
;
411 p
= qs
->data
.priq_stats
.xmitcnt
.packets
;
414 b
= qs
->data
.hfsc_stats
.xmit_cnt
.bytes
;
415 p
= qs
->data
.hfsc_stats
.xmit_cnt
.packets
;
418 b
= qs
->data
.fairq_stats
.xmit_cnt
.bytes
;
419 p
= qs
->data
.fairq_stats
.xmit_cnt
.packets
;
429 qs
->prev_packets
= p
;
434 if (b
>= qs
->prev_bytes
)
435 qs
->avg_bytes
= ((qs
->avg_bytes
* (n
- 1)) +
436 (b
- qs
->prev_bytes
)) / n
;
438 if (p
>= qs
->prev_packets
)
439 qs
->avg_packets
= ((qs
->avg_packets
* (n
- 1)) +
440 (p
- qs
->prev_packets
)) / n
;
443 qs
->prev_packets
= p
;