source: rtems-libbsd/freebsd/contrib/pf/pfctl/pfctl_qstats.c @ 084d4db

4.11
Last change on this file since 084d4db was 084d4db, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/05/16 at 14:07:37

pfctl: Import sources from FreeBSD.

  • Property mode set to 100644
File size: 11.0 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*      $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
4
5/*
6 * Copyright (c) Henning Brauer <henning@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__FBSDID("$FreeBSD$");
23
24#include <rtems/bsd/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 <altq/altq.h>
40#include <altq/altq_cbq.h>
41#include <altq/altq_priq.h>
42#include <altq/altq_hfsc.h>
43
44#include "pfctl.h"
45#include "pfctl_parser.h"
46
47union class_stats {
48        class_stats_t           cbq_stats;
49        struct priq_classstats  priq_stats;
50        struct hfsc_classstats  hfsc_stats;
51};
52
53#define AVGN_MAX        8
54#define STAT_INTERVAL   5
55
56struct 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
65struct 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
72int                      pfctl_update_qstats(int, struct pf_altq_node **);
73void                     pfctl_insert_altq_node(struct pf_altq_node **,
74                            const struct pf_altq, const struct queue_stats);
75struct pf_altq_node     *pfctl_find_altq_node(struct pf_altq_node *,
76                            const char *, const char *);
77void                     pfctl_print_altq_node(int, const struct pf_altq_node *,
78                            unsigned, int);
79void                     print_cbqstats(struct queue_stats);
80void                     print_priqstats(struct queue_stats);
81void                     print_hfscstats(struct queue_stats);
82void                     pfctl_free_altq_node(struct pf_altq_node *);
83void                     pfctl_print_altq_nodestat(int,
84                            const struct pf_altq_node *);
85
86void                     update_avg(struct pf_altq_node *);
87
88int
89pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
90{
91        struct pf_altq_node     *root = NULL, *node;
92        int                      nodes, dotitle = (opts & PF_OPT_SHOWALL);
93
94#ifdef __FreeBSD__
95        if (!altqsupport)
96                return (-1);
97#endif
98
99        if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
100                return (-1);
101
102        if (nodes == 0)
103                printf("No queue in use\n");
104        for (node = root; node != NULL; node = node->next) {
105                if (iface != NULL && strcmp(node->altq.ifname, iface))
106                        continue;
107                if (dotitle) {
108                        pfctl_print_title("ALTQ:");
109                        dotitle = 0;
110                }
111                pfctl_print_altq_node(dev, node, 0, opts);
112        }
113
114        while (verbose2 && nodes > 0) {
115                printf("\n");
116                fflush(stdout);
117                sleep(STAT_INTERVAL);
118                if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
119                        return (-1);
120                for (node = root; node != NULL; node = node->next) {
121                        if (iface != NULL && strcmp(node->altq.ifname, iface))
122                                continue;
123#ifdef __FreeBSD__
124                        if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
125                                continue;
126#endif
127                        pfctl_print_altq_node(dev, node, 0, opts);
128                }
129        }
130        pfctl_free_altq_node(root);
131        return (0);
132}
133
134int
135pfctl_update_qstats(int dev, struct pf_altq_node **root)
136{
137        struct pf_altq_node     *node;
138        struct pfioc_altq        pa;
139        struct pfioc_qstats      pq;
140        u_int32_t                mnr, nr;
141        struct queue_stats       qstats;
142        static  u_int32_t        last_ticket;
143
144        memset(&pa, 0, sizeof(pa));
145        memset(&pq, 0, sizeof(pq));
146        memset(&qstats, 0, sizeof(qstats));
147        if (ioctl(dev, DIOCGETALTQS, &pa)) {
148                warn("DIOCGETALTQS");
149                return (-1);
150        }
151
152        /* if a new set is found, start over */
153        if (pa.ticket != last_ticket && *root != NULL) {
154                pfctl_free_altq_node(*root);
155                *root = NULL;
156        }
157        last_ticket = pa.ticket;
158
159        mnr = pa.nr;
160        for (nr = 0; nr < mnr; ++nr) {
161                pa.nr = nr;
162                if (ioctl(dev, DIOCGETALTQ, &pa)) {
163                        warn("DIOCGETALTQ");
164                        return (-1);
165                }
166#ifdef __FreeBSD__
167                if (pa.altq.qid > 0 &&
168                    !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
169#else
170                if (pa.altq.qid > 0) {
171#endif
172                        pq.nr = nr;
173                        pq.ticket = pa.ticket;
174                        pq.buf = &qstats.data;
175                        pq.nbytes = sizeof(qstats.data);
176                        if (ioctl(dev, DIOCGETQSTATS, &pq)) {
177                                warn("DIOCGETQSTATS");
178                                return (-1);
179                        }
180                        if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
181                            pa.altq.ifname)) != NULL) {
182                                memcpy(&node->qstats.data, &qstats.data,
183                                    sizeof(qstats.data));
184                                update_avg(node);
185                        } else {
186                                pfctl_insert_altq_node(root, pa.altq, qstats);
187                        }
188                }
189#ifdef __FreeBSD__
190                else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
191                        memset(&qstats.data, 0, sizeof(qstats.data));
192                        if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
193                            pa.altq.ifname)) != NULL) {
194                                memcpy(&node->qstats.data, &qstats.data,
195                                    sizeof(qstats.data));
196                                update_avg(node);
197                        } else {
198                                pfctl_insert_altq_node(root, pa.altq, qstats);
199                        }
200                }
201#endif
202        }
203        return (mnr);
204}
205
206void
207pfctl_insert_altq_node(struct pf_altq_node **root,
208    const struct pf_altq altq, const struct queue_stats qstats)
209{
210        struct pf_altq_node     *node;
211
212        node = calloc(1, sizeof(struct pf_altq_node));
213        if (node == NULL)
214                err(1, "pfctl_insert_altq_node: calloc");
215        memcpy(&node->altq, &altq, sizeof(struct pf_altq));
216        memcpy(&node->qstats, &qstats, sizeof(qstats));
217        node->next = node->children = NULL;
218
219        if (*root == NULL)
220                *root = node;
221        else if (!altq.parent[0]) {
222                struct pf_altq_node     *prev = *root;
223
224                while (prev->next != NULL)
225                        prev = prev->next;
226                prev->next = node;
227        } else {
228                struct pf_altq_node     *parent;
229
230                parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
231                if (parent == NULL)
232                        errx(1, "parent %s not found", altq.parent);
233                if (parent->children == NULL)
234                        parent->children = node;
235                else {
236                        struct pf_altq_node *prev = parent->children;
237
238                        while (prev->next != NULL)
239                                prev = prev->next;
240                        prev->next = node;
241                }
242        }
243        update_avg(node);
244}
245
246struct pf_altq_node *
247pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
248    const char *ifname)
249{
250        struct pf_altq_node     *node, *child;
251
252        for (node = root; node != NULL; node = node->next) {
253                if (!strcmp(node->altq.qname, qname)
254                    && !(strcmp(node->altq.ifname, ifname)))
255                        return (node);
256                if (node->children != NULL) {
257                        child = pfctl_find_altq_node(node->children, qname,
258                            ifname);
259                        if (child != NULL)
260                                return (child);
261                }
262        }
263        return (NULL);
264}
265
266void
267pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
268    unsigned int level, int opts)
269{
270        const struct pf_altq_node       *child;
271
272        if (node == NULL)
273                return;
274
275        print_altq(&node->altq, level, NULL, NULL);
276
277        if (node->children != NULL) {
278                printf("{");
279                for (child = node->children; child != NULL;
280                    child = child->next) {
281                        printf("%s", child->altq.qname);
282                        if (child->next != NULL)
283                                printf(", ");
284                }
285                printf("}");
286        }
287        printf("\n");
288
289        if (opts & PF_OPT_VERBOSE)
290                pfctl_print_altq_nodestat(dev, node);
291
292        if (opts & PF_OPT_DEBUG)
293                printf("  [ qid=%u ifname=%s ifbandwidth=%s ]\n",
294                    node->altq.qid, node->altq.ifname,
295                    rate2str((double)(node->altq.ifbandwidth)));
296
297        for (child = node->children; child != NULL;
298            child = child->next)
299                pfctl_print_altq_node(dev, child, level + 1, opts);
300}
301
302void
303pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
304{
305        if (a->altq.qid == 0)
306                return;
307
308#ifdef __FreeBSD__
309        if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
310                return;
311#endif
312        switch (a->altq.scheduler) {
313        case ALTQT_CBQ:
314                print_cbqstats(a->qstats);
315                break;
316        case ALTQT_PRIQ:
317                print_priqstats(a->qstats);
318                break;
319        case ALTQT_HFSC:
320                print_hfscstats(a->qstats);
321                break;
322        }
323}
324
325void
326print_cbqstats(struct queue_stats cur)
327{
328        printf("  [ pkts: %10llu  bytes: %10llu  "
329            "dropped pkts: %6llu bytes: %6llu ]\n",
330            (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
331            (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
332            (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
333            (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
334        printf("  [ qlength: %3d/%3d  borrows: %6u  suspends: %6u ]\n",
335            cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
336            cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
337
338        if (cur.avgn < 2)
339                return;
340
341        printf("  [ measured: %7.1f packets/s, %s/s ]\n",
342            cur.avg_packets / STAT_INTERVAL,
343            rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
344}
345
346void
347print_priqstats(struct queue_stats cur)
348{
349        printf("  [ pkts: %10llu  bytes: %10llu  "
350            "dropped pkts: %6llu bytes: %6llu ]\n",
351            (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
352            (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
353            (unsigned long long)cur.data.priq_stats.dropcnt.packets,
354            (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
355        printf("  [ qlength: %3d/%3d ]\n",
356            cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
357
358        if (cur.avgn < 2)
359                return;
360
361        printf("  [ measured: %7.1f packets/s, %s/s ]\n",
362            cur.avg_packets / STAT_INTERVAL,
363            rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
364}
365
366void
367print_hfscstats(struct queue_stats cur)
368{
369        printf("  [ pkts: %10llu  bytes: %10llu  "
370            "dropped pkts: %6llu bytes: %6llu ]\n",
371            (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
372            (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
373            (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
374            (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
375        printf("  [ qlength: %3d/%3d ]\n",
376            cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
377
378        if (cur.avgn < 2)
379                return;
380
381        printf("  [ measured: %7.1f packets/s, %s/s ]\n",
382            cur.avg_packets / STAT_INTERVAL,
383            rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
384}
385
386void
387pfctl_free_altq_node(struct pf_altq_node *node)
388{
389        while (node != NULL) {
390                struct pf_altq_node     *prev;
391
392                if (node->children != NULL)
393                        pfctl_free_altq_node(node->children);
394                prev = node;
395                node = node->next;
396                free(prev);
397        }
398}
399
400void
401update_avg(struct pf_altq_node *a)
402{
403        struct queue_stats      *qs;
404        u_int64_t                b, p;
405        int                      n;
406
407        if (a->altq.qid == 0)
408                return;
409
410        qs = &a->qstats;
411        n = qs->avgn;
412
413        switch (a->altq.scheduler) {
414        case ALTQT_CBQ:
415                b = qs->data.cbq_stats.xmit_cnt.bytes;
416                p = qs->data.cbq_stats.xmit_cnt.packets;
417                break;
418        case ALTQT_PRIQ:
419                b = qs->data.priq_stats.xmitcnt.bytes;
420                p = qs->data.priq_stats.xmitcnt.packets;
421                break;
422        case ALTQT_HFSC:
423                b = qs->data.hfsc_stats.xmit_cnt.bytes;
424                p = qs->data.hfsc_stats.xmit_cnt.packets;
425                break;
426        default:
427                b = 0;
428                p = 0;
429                break;
430        }
431
432        if (n == 0) {
433                qs->prev_bytes = b;
434                qs->prev_packets = p;
435                qs->avgn++;
436                return;
437        }
438
439        if (b >= qs->prev_bytes)
440                qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
441                    (b - qs->prev_bytes)) / n;
442
443        if (p >= qs->prev_packets)
444                qs->avg_packets = ((qs->avg_packets * (n - 1)) +
445                    (p - qs->prev_packets)) / n;
446
447        qs->prev_bytes = b;
448        qs->prev_packets = p;
449        if (n < AVGN_MAX)
450                qs->avgn++;
451}
Note: See TracBrowser for help on using the repository browser.