]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sbin/pfctl/pfctl_qstats.c
Fix the build.
[FreeBSD/stable/10.git] / sbin / pfctl / pfctl_qstats.c
1 /*      $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
2
3 /*
4  * Copyright (c) Henning Brauer <henning@openbsd.org>
5  *
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.
9  *
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.
17  */
18
19 #include <sys/cdefs.h>
20 __FBSDID("$FreeBSD$");
21
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25
26 #include <net/if.h>
27 #include <netinet/in.h>
28 #include <net/pfvar.h>
29 #include <arpa/inet.h>
30
31 #include <err.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include <altq/altq.h>
38 #include <altq/altq_cbq.h>
39 #include <altq/altq_priq.h>
40 #include <altq/altq_hfsc.h>
41 #include <altq/altq_fairq.h>
42
43 #include "pfctl.h"
44 #include "pfctl_parser.h"
45
46 union class_stats {
47         class_stats_t           cbq_stats;
48         struct priq_classstats  priq_stats;
49         struct hfsc_classstats  hfsc_stats;
50         struct fairq_classstats fairq_stats;
51 };
52
53 #define AVGN_MAX        8
54 #define STAT_INTERVAL   5
55
56 struct queue_stats {
57         union class_stats        data;
58         int                      avgn;
59         double                   avg_bytes;
60         double                   avg_packets;
61         u_int64_t                prev_bytes;
62         u_int64_t                prev_packets;
63 };
64
65 struct pf_altq_node {
66         struct pf_altq           altq;
67         struct pf_altq_node     *next;
68         struct pf_altq_node     *children;
69         struct queue_stats       qstats;
70 };
71
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 *,
78                             unsigned, int);
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 *);
86
87 void                     update_avg(struct pf_altq_node *);
88
89 int
90 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
91 {
92         struct pf_altq_node     *root = NULL, *node;
93         int                      nodes, dotitle = (opts & PF_OPT_SHOWALL);
94
95 #ifdef __FreeBSD__
96         if (!altqsupport)
97                 return (-1);
98 #endif
99
100         if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
101                 return (-1);
102
103         if (nodes == 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))
107                         continue;
108                 if (dotitle) {
109                         pfctl_print_title("ALTQ:");
110                         dotitle = 0;
111                 }
112                 pfctl_print_altq_node(dev, node, 0, opts);
113         }
114
115         while (verbose2 && nodes > 0) {
116                 printf("\n");
117                 fflush(stdout);
118                 sleep(STAT_INTERVAL);
119                 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
120                         return (-1);
121                 for (node = root; node != NULL; node = node->next) {
122                         if (iface != NULL && strcmp(node->altq.ifname, iface))
123                                 continue;
124 #ifdef __FreeBSD__
125                         if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
126                                 continue;
127 #endif
128                         pfctl_print_altq_node(dev, node, 0, opts);
129                 }
130         }
131         pfctl_free_altq_node(root);
132         return (0);
133 }
134
135 int
136 pfctl_update_qstats(int dev, struct pf_altq_node **root)
137 {
138         struct pf_altq_node     *node;
139         struct pfioc_altq        pa;
140         struct pfioc_qstats      pq;
141         u_int32_t                mnr, nr;
142         struct queue_stats       qstats;
143         static  u_int32_t        last_ticket;
144
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");
150                 return (-1);
151         }
152
153         /* if a new set is found, start over */
154         if (pa.ticket != last_ticket && *root != NULL) {
155                 pfctl_free_altq_node(*root);
156                 *root = NULL;
157         }
158         last_ticket = pa.ticket;
159
160         mnr = pa.nr;
161         for (nr = 0; nr < mnr; ++nr) {
162                 pa.nr = nr;
163                 if (ioctl(dev, DIOCGETALTQ, &pa)) {
164                         warn("DIOCGETALTQ");
165                         return (-1);
166                 }
167 #ifdef __FreeBSD__
168                 if (pa.altq.qid > 0 &&
169                     !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
170 #else
171                 if (pa.altq.qid > 0) {
172 #endif
173                         pq.nr = nr;
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");
179                                 return (-1);
180                         }
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));
185                                 update_avg(node);
186                         } else {
187                                 pfctl_insert_altq_node(root, pa.altq, qstats);
188                         }
189                 }
190 #ifdef __FreeBSD__
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));
197                                 update_avg(node);
198                         } else {
199                                 pfctl_insert_altq_node(root, pa.altq, qstats);
200                         }
201                 }
202 #endif
203         }
204         return (mnr);
205 }
206
207 void
208 pfctl_insert_altq_node(struct pf_altq_node **root,
209     const struct pf_altq altq, const struct queue_stats qstats)
210 {
211         struct pf_altq_node     *node;
212
213         node = calloc(1, sizeof(struct pf_altq_node));
214         if (node == NULL)
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;
219
220         if (*root == NULL)
221                 *root = node;
222         else if (!altq.parent[0]) {
223                 struct pf_altq_node     *prev = *root;
224
225                 while (prev->next != NULL)
226                         prev = prev->next;
227                 prev->next = node;
228         } else {
229                 struct pf_altq_node     *parent;
230
231                 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
232                 if (parent == NULL)
233                         errx(1, "parent %s not found", altq.parent);
234                 if (parent->children == NULL)
235                         parent->children = node;
236                 else {
237                         struct pf_altq_node *prev = parent->children;
238
239                         while (prev->next != NULL)
240                                 prev = prev->next;
241                         prev->next = node;
242                 }
243         }
244         update_avg(node);
245 }
246
247 struct pf_altq_node *
248 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
249     const char *ifname)
250 {
251         struct pf_altq_node     *node, *child;
252
253         for (node = root; node != NULL; node = node->next) {
254                 if (!strcmp(node->altq.qname, qname)
255                     && !(strcmp(node->altq.ifname, ifname)))
256                         return (node);
257                 if (node->children != NULL) {
258                         child = pfctl_find_altq_node(node->children, qname,
259                             ifname);
260                         if (child != NULL)
261                                 return (child);
262                 }
263         }
264         return (NULL);
265 }
266
267 void
268 pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
269     unsigned int level, int opts)
270 {
271         const struct pf_altq_node       *child;
272
273         if (node == NULL)
274                 return;
275
276         print_altq(&node->altq, level, NULL, NULL);
277
278         if (node->children != NULL) {
279                 printf("{");
280                 for (child = node->children; child != NULL;
281                     child = child->next) {
282                         printf("%s", child->altq.qname);
283                         if (child->next != NULL)
284                                 printf(", ");
285                 }
286                 printf("}");
287         }
288         printf("\n");
289
290         if (opts & PF_OPT_VERBOSE)
291                 pfctl_print_altq_nodestat(dev, node);
292
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)));
297
298         for (child = node->children; child != NULL;
299             child = child->next)
300                 pfctl_print_altq_node(dev, child, level + 1, opts);
301 }
302
303 void
304 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
305 {
306         if (a->altq.qid == 0)
307                 return;
308
309 #ifdef __FreeBSD__
310         if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
311                 return;
312 #endif
313         switch (a->altq.scheduler) {
314         case ALTQT_CBQ:
315                 print_cbqstats(a->qstats);
316                 break;
317         case ALTQT_PRIQ:
318                 print_priqstats(a->qstats);
319                 break;
320         case ALTQT_HFSC:
321                 print_hfscstats(a->qstats);
322                 break;
323         case ALTQT_FAIRQ:
324                 print_fairqstats(a->qstats);
325                 break;
326         }
327 }
328
329 void
330 print_cbqstats(struct queue_stats cur)
331 {
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);
341
342         if (cur.avgn < 2)
343                 return;
344
345         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
346             cur.avg_packets / STAT_INTERVAL,
347             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
348 }
349
350 void
351 print_priqstats(struct queue_stats cur)
352 {
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);
361
362         if (cur.avgn < 2)
363                 return;
364
365         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
366             cur.avg_packets / STAT_INTERVAL,
367             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
368 }
369
370 void
371 print_hfscstats(struct queue_stats cur)
372 {
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);
381
382         if (cur.avgn < 2)
383                 return;
384
385         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
386             cur.avg_packets / STAT_INTERVAL,
387             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
388 }
389
390 void
391 print_fairqstats(struct queue_stats cur)
392 {
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);
401
402         if (cur.avgn < 2)
403                 return;
404
405         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
406             cur.avg_packets / STAT_INTERVAL,
407             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
408 }
409
410 void
411 pfctl_free_altq_node(struct pf_altq_node *node)
412 {
413         while (node != NULL) {
414                 struct pf_altq_node     *prev;
415
416                 if (node->children != NULL)
417                         pfctl_free_altq_node(node->children);
418                 prev = node;
419                 node = node->next;
420                 free(prev);
421         }
422 }
423
424 void
425 update_avg(struct pf_altq_node *a)
426 {
427         struct queue_stats      *qs;
428         u_int64_t                b, p;
429         int                      n;
430
431         if (a->altq.qid == 0)
432                 return;
433
434         qs = &a->qstats;
435         n = qs->avgn;
436
437         switch (a->altq.scheduler) {
438         case ALTQT_CBQ:
439                 b = qs->data.cbq_stats.xmit_cnt.bytes;
440                 p = qs->data.cbq_stats.xmit_cnt.packets;
441                 break;
442         case ALTQT_PRIQ:
443                 b = qs->data.priq_stats.xmitcnt.bytes;
444                 p = qs->data.priq_stats.xmitcnt.packets;
445                 break;
446         case ALTQT_HFSC:
447                 b = qs->data.hfsc_stats.xmit_cnt.bytes;
448                 p = qs->data.hfsc_stats.xmit_cnt.packets;
449                 break;
450         case ALTQT_FAIRQ:
451                 b = qs->data.fairq_stats.xmit_cnt.bytes;
452                 p = qs->data.fairq_stats.xmit_cnt.packets;
453                 break;
454         default:
455                 b = 0;
456                 p = 0;
457                 break;
458         }
459
460         if (n == 0) {
461                 qs->prev_bytes = b;
462                 qs->prev_packets = p;
463                 qs->avgn++;
464                 return;
465         }
466
467         if (b >= qs->prev_bytes)
468                 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
469                     (b - qs->prev_bytes)) / n;
470
471         if (p >= qs->prev_packets)
472                 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
473                     (p - qs->prev_packets)) / n;
474
475         qs->prev_bytes = b;
476         qs->prev_packets = p;
477         if (n < AVGN_MAX)
478                 qs->avgn++;
479 }