]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfctl/pfctl_qstats.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.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 #define PFIOC_USE_LATEST
23
24 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27
28 #include <net/if.h>
29 #include <netinet/in.h>
30 #include <net/pfvar.h>
31 #include <arpa/inet.h>
32
33 #include <err.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <net/altq/altq.h>
40 #include <net/altq/altq_cbq.h>
41 #include <net/altq/altq_codel.h>
42 #include <net/altq/altq_priq.h>
43 #include <net/altq/altq_hfsc.h>
44 #include <net/altq/altq_fairq.h>
45
46 #include "pfctl.h"
47 #include "pfctl_parser.h"
48
49 union class_stats {
50         class_stats_t           cbq_stats;
51         struct priq_classstats  priq_stats;
52         struct hfsc_classstats  hfsc_stats;
53         struct fairq_classstats fairq_stats;
54         struct codel_ifstats    codel_stats;
55 };
56
57 #define AVGN_MAX        8
58 #define STAT_INTERVAL   5
59
60 struct queue_stats {
61         union class_stats        data;
62         int                      avgn;
63         double                   avg_bytes;
64         double                   avg_packets;
65         u_int64_t                prev_bytes;
66         u_int64_t                prev_packets;
67 };
68
69 struct pf_altq_node {
70         struct pf_altq           altq;
71         struct pf_altq_node     *next;
72         struct pf_altq_node     *children;
73         struct queue_stats       qstats;
74 };
75
76 int                      pfctl_update_qstats(int, struct pf_altq_node **);
77 void                     pfctl_insert_altq_node(struct pf_altq_node **,
78                             const struct pf_altq, const struct queue_stats);
79 struct pf_altq_node     *pfctl_find_altq_node(struct pf_altq_node *,
80                             const char *, const char *);
81 void                     pfctl_print_altq_node(int, const struct pf_altq_node *,
82                             unsigned, int);
83 void                     print_cbqstats(struct queue_stats);
84 void                     print_codelstats(struct queue_stats);
85 void                     print_priqstats(struct queue_stats);
86 void                     print_hfscstats(struct queue_stats);
87 void                     print_fairqstats(struct queue_stats);
88 void                     pfctl_free_altq_node(struct pf_altq_node *);
89 void                     pfctl_print_altq_nodestat(int,
90                             const struct pf_altq_node *);
91
92 void                     update_avg(struct pf_altq_node *);
93
94 int
95 pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
96 {
97         struct pf_altq_node     *root = NULL, *node;
98         int                      nodes, dotitle = (opts & PF_OPT_SHOWALL);
99
100 #ifdef __FreeBSD__
101         if (!altqsupport)
102                 return (-1);
103 #endif
104
105         if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
106                 return (-1);
107
108         if (nodes == 0)
109                 printf("No queue in use\n");
110         for (node = root; node != NULL; node = node->next) {
111                 if (iface != NULL && strcmp(node->altq.ifname, iface))
112                         continue;
113                 if (dotitle) {
114                         pfctl_print_title("ALTQ:");
115                         dotitle = 0;
116                 }
117                 pfctl_print_altq_node(dev, node, 0, opts);
118         }
119
120         while (verbose2 && nodes > 0) {
121                 printf("\n");
122                 fflush(stdout);
123                 sleep(STAT_INTERVAL);
124                 if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
125                         return (-1);
126                 for (node = root; node != NULL; node = node->next) {
127                         if (iface != NULL && strcmp(node->altq.ifname, iface))
128                                 continue;
129 #ifdef __FreeBSD__
130                         if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
131                                 continue;
132 #endif
133                         pfctl_print_altq_node(dev, node, 0, opts);
134                 }
135         }
136         pfctl_free_altq_node(root);
137         return (0);
138 }
139
140 int
141 pfctl_update_qstats(int dev, struct pf_altq_node **root)
142 {
143         struct pf_altq_node     *node;
144         struct pfioc_altq        pa;
145         struct pfioc_qstats      pq;
146         u_int32_t                mnr, nr;
147         struct queue_stats       qstats;
148         static  u_int32_t        last_ticket;
149
150         memset(&pa, 0, sizeof(pa));
151         memset(&pq, 0, sizeof(pq));
152         memset(&qstats, 0, sizeof(qstats));
153         pa.version = PFIOC_ALTQ_VERSION;
154         if (ioctl(dev, DIOCGETALTQS, &pa)) {
155                 warn("DIOCGETALTQS");
156                 return (-1);
157         }
158
159         /* if a new set is found, start over */
160         if (pa.ticket != last_ticket && *root != NULL) {
161                 pfctl_free_altq_node(*root);
162                 *root = NULL;
163         }
164         last_ticket = pa.ticket;
165
166         mnr = pa.nr;
167         for (nr = 0; nr < mnr; ++nr) {
168                 pa.nr = nr;
169                 if (ioctl(dev, DIOCGETALTQ, &pa)) {
170                         warn("DIOCGETALTQ");
171                         return (-1);
172                 }
173 #ifdef __FreeBSD__
174                 if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
175                     !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
176 #else
177                 if (pa.altq.qid > 0) {
178 #endif
179                         pq.nr = nr;
180                         pq.ticket = pa.ticket;
181                         pq.buf = &qstats.data;
182                         pq.nbytes = sizeof(qstats.data);
183                         pq.version = altq_stats_version(pa.altq.scheduler);
184                         if (ioctl(dev, DIOCGETQSTATS, &pq)) {
185                                 warn("DIOCGETQSTATS");
186                                 return (-1);
187                         }
188                         if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
189                             pa.altq.ifname)) != NULL) {
190                                 memcpy(&node->qstats.data, &qstats.data,
191                                     sizeof(qstats.data));
192                                 update_avg(node);
193                         } else {
194                                 pfctl_insert_altq_node(root, pa.altq, qstats);
195                         }
196                 }
197 #ifdef __FreeBSD__
198                 else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
199                         memset(&qstats.data, 0, sizeof(qstats.data));
200                         if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
201                             pa.altq.ifname)) != NULL) {
202                                 memcpy(&node->qstats.data, &qstats.data,
203                                     sizeof(qstats.data));
204                                 update_avg(node);
205                         } else {
206                                 pfctl_insert_altq_node(root, pa.altq, qstats);
207                         }
208                 }
209 #endif
210         }
211         return (mnr);
212 }
213
214 void
215 pfctl_insert_altq_node(struct pf_altq_node **root,
216     const struct pf_altq altq, const struct queue_stats qstats)
217 {
218         struct pf_altq_node     *node;
219
220         node = calloc(1, sizeof(struct pf_altq_node));
221         if (node == NULL)
222                 err(1, "pfctl_insert_altq_node: calloc");
223         memcpy(&node->altq, &altq, sizeof(struct pf_altq));
224         memcpy(&node->qstats, &qstats, sizeof(qstats));
225         node->next = node->children = NULL;
226
227         if (*root == NULL)
228                 *root = node;
229         else if (!altq.parent[0]) {
230                 struct pf_altq_node     *prev = *root;
231
232                 while (prev->next != NULL)
233                         prev = prev->next;
234                 prev->next = node;
235         } else {
236                 struct pf_altq_node     *parent;
237
238                 parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
239                 if (parent == NULL)
240                         errx(1, "parent %s not found", altq.parent);
241                 if (parent->children == NULL)
242                         parent->children = node;
243                 else {
244                         struct pf_altq_node *prev = parent->children;
245
246                         while (prev->next != NULL)
247                                 prev = prev->next;
248                         prev->next = node;
249                 }
250         }
251         update_avg(node);
252 }
253
254 struct pf_altq_node *
255 pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
256     const char *ifname)
257 {
258         struct pf_altq_node     *node, *child;
259
260         for (node = root; node != NULL; node = node->next) {
261                 if (!strcmp(node->altq.qname, qname)
262                     && !(strcmp(node->altq.ifname, ifname)))
263                         return (node);
264                 if (node->children != NULL) {
265                         child = pfctl_find_altq_node(node->children, qname,
266                             ifname);
267                         if (child != NULL)
268                                 return (child);
269                 }
270         }
271         return (NULL);
272 }
273
274 void
275 pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
276     unsigned int level, int opts)
277 {
278         const struct pf_altq_node       *child;
279
280         if (node == NULL)
281                 return;
282
283         print_altq(&node->altq, level, NULL, NULL);
284
285         if (node->children != NULL) {
286                 printf("{");
287                 for (child = node->children; child != NULL;
288                     child = child->next) {
289                         printf("%s", child->altq.qname);
290                         if (child->next != NULL)
291                                 printf(", ");
292                 }
293                 printf("}");
294         }
295         printf("\n");
296
297         if (opts & PF_OPT_VERBOSE)
298                 pfctl_print_altq_nodestat(dev, node);
299
300         if (opts & PF_OPT_DEBUG)
301                 printf("  [ qid=%u ifname=%s ifbandwidth=%s ]\n",
302                     node->altq.qid, node->altq.ifname,
303                     rate2str((double)(node->altq.ifbandwidth)));
304
305         for (child = node->children; child != NULL;
306             child = child->next)
307                 pfctl_print_altq_node(dev, child, level + 1, opts);
308 }
309
310 void
311 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
312 {
313         if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
314                 return;
315
316 #ifdef __FreeBSD__
317         if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
318                 return;
319 #endif
320         switch (a->altq.scheduler) {
321         case ALTQT_CBQ:
322                 print_cbqstats(a->qstats);
323                 break;
324         case ALTQT_PRIQ:
325                 print_priqstats(a->qstats);
326                 break;
327         case ALTQT_HFSC:
328                 print_hfscstats(a->qstats);
329                 break;
330         case ALTQT_FAIRQ:
331                 print_fairqstats(a->qstats);
332                 break;
333         case ALTQT_CODEL:
334                 print_codelstats(a->qstats);
335                 break;
336         }
337 }
338
339 void
340 print_cbqstats(struct queue_stats cur)
341 {
342         printf("  [ pkts: %10llu  bytes: %10llu  "
343             "dropped pkts: %6llu bytes: %6llu ]\n",
344             (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
345             (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
346             (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
347             (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
348         printf("  [ qlength: %3d/%3d  borrows: %6u  suspends: %6u ]\n",
349             cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
350             cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
351
352         if (cur.avgn < 2)
353                 return;
354
355         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
356             cur.avg_packets / STAT_INTERVAL,
357             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
358 }
359
360 void
361 print_codelstats(struct queue_stats cur)
362 {
363         printf("  [ pkts: %10llu  bytes: %10llu  "
364             "dropped pkts: %6llu bytes: %6llu ]\n",
365             (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
366             (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
367             (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
368             cur.data.codel_stats.stats.drop_cnt.packets,
369             (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
370             cur.data.codel_stats.stats.drop_cnt.bytes);
371         printf("  [ qlength: %3d/%3d ]\n",
372             cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
373
374         if (cur.avgn < 2)
375                 return;
376
377         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
378             cur.avg_packets / STAT_INTERVAL,
379             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
380 }
381
382 void
383 print_priqstats(struct queue_stats cur)
384 {
385         printf("  [ pkts: %10llu  bytes: %10llu  "
386             "dropped pkts: %6llu bytes: %6llu ]\n",
387             (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
388             (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
389             (unsigned long long)cur.data.priq_stats.dropcnt.packets,
390             (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
391         printf("  [ qlength: %3d/%3d ]\n",
392             cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
393
394         if (cur.avgn < 2)
395                 return;
396
397         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
398             cur.avg_packets / STAT_INTERVAL,
399             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
400 }
401
402 void
403 print_hfscstats(struct queue_stats cur)
404 {
405         printf("  [ pkts: %10llu  bytes: %10llu  "
406             "dropped pkts: %6llu bytes: %6llu ]\n",
407             (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
408             (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
409             (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
410             (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
411         printf("  [ qlength: %3d/%3d ]\n",
412             cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
413
414         if (cur.avgn < 2)
415                 return;
416
417         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
418             cur.avg_packets / STAT_INTERVAL,
419             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
420 }
421
422 void
423 print_fairqstats(struct queue_stats cur)
424 {
425         printf("  [ pkts: %10llu  bytes: %10llu  "
426             "dropped pkts: %6llu bytes: %6llu ]\n",
427             (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
428             (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
429             (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
430             (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
431         printf("  [ qlength: %3d/%3d ]\n",
432             cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
433
434         if (cur.avgn < 2)
435                 return;
436
437         printf("  [ measured: %7.1f packets/s, %s/s ]\n",
438             cur.avg_packets / STAT_INTERVAL,
439             rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
440 }
441
442 void
443 pfctl_free_altq_node(struct pf_altq_node *node)
444 {
445         while (node != NULL) {
446                 struct pf_altq_node     *prev;
447
448                 if (node->children != NULL)
449                         pfctl_free_altq_node(node->children);
450                 prev = node;
451                 node = node->next;
452                 free(prev);
453         }
454 }
455
456 void
457 update_avg(struct pf_altq_node *a)
458 {
459         struct queue_stats      *qs;
460         u_int64_t                b, p;
461         int                      n;
462
463         if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
464                 return;
465
466         qs = &a->qstats;
467         n = qs->avgn;
468
469         switch (a->altq.scheduler) {
470         case ALTQT_CBQ:
471                 b = qs->data.cbq_stats.xmit_cnt.bytes;
472                 p = qs->data.cbq_stats.xmit_cnt.packets;
473                 break;
474         case ALTQT_PRIQ:
475                 b = qs->data.priq_stats.xmitcnt.bytes;
476                 p = qs->data.priq_stats.xmitcnt.packets;
477                 break;
478         case ALTQT_HFSC:
479                 b = qs->data.hfsc_stats.xmit_cnt.bytes;
480                 p = qs->data.hfsc_stats.xmit_cnt.packets;
481                 break;
482         case ALTQT_FAIRQ:
483                 b = qs->data.fairq_stats.xmit_cnt.bytes;
484                 p = qs->data.fairq_stats.xmit_cnt.packets;
485                 break;
486         case ALTQT_CODEL:
487                 b = qs->data.codel_stats.cl_xmitcnt.bytes;
488                 p = qs->data.codel_stats.cl_xmitcnt.packets;
489                 break;
490         default:
491                 b = 0;
492                 p = 0;
493                 break;
494         }
495
496         if (n == 0) {
497                 qs->prev_bytes = b;
498                 qs->prev_packets = p;
499                 qs->avgn++;
500                 return;
501         }
502
503         if (b >= qs->prev_bytes)
504                 qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
505                     (b - qs->prev_bytes)) / n;
506
507         if (p >= qs->prev_packets)
508                 qs->avg_packets = ((qs->avg_packets * (n - 1)) +
509                     (p - qs->prev_packets)) / n;
510
511         qs->prev_bytes = b;
512         qs->prev_packets = p;
513         if (n < AVGN_MAX)
514                 qs->avgn++;
515 }