1145840Smlaier/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */ 2126353Smlaier 3126353Smlaier/* 4126353Smlaier * Copyright (c) Henning Brauer <henning@openbsd.org> 5126353Smlaier * 6126353Smlaier * Permission to use, copy, modify, and distribute this software for any 7126353Smlaier * purpose with or without fee is hereby granted, provided that the above 8126353Smlaier * copyright notice and this permission notice appear in all copies. 9126353Smlaier * 10126353Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11126353Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12126353Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13126353Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14126353Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15126353Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16126353Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17126353Smlaier */ 18126353Smlaier 19127082Sobrien#include <sys/cdefs.h> 20127082Sobrien__FBSDID("$FreeBSD$"); 21127082Sobrien 22126353Smlaier#include <sys/types.h> 23126353Smlaier#include <sys/ioctl.h> 24126353Smlaier#include <sys/socket.h> 25126353Smlaier 26126353Smlaier#include <net/if.h> 27126353Smlaier#include <netinet/in.h> 28126353Smlaier#include <net/pfvar.h> 29126353Smlaier#include <arpa/inet.h> 30126353Smlaier 31126353Smlaier#include <err.h> 32126353Smlaier#include <stdio.h> 33126353Smlaier#include <stdlib.h> 34126353Smlaier#include <string.h> 35126353Smlaier#include <unistd.h> 36126353Smlaier 37126353Smlaier#include <altq/altq.h> 38126353Smlaier#include <altq/altq_cbq.h> 39126353Smlaier#include <altq/altq_priq.h> 40126353Smlaier#include <altq/altq_hfsc.h> 41126353Smlaier 42126353Smlaier#include "pfctl.h" 43126353Smlaier#include "pfctl_parser.h" 44126353Smlaier 45126353Smlaierunion class_stats { 46126353Smlaier class_stats_t cbq_stats; 47126353Smlaier struct priq_classstats priq_stats; 48126353Smlaier struct hfsc_classstats hfsc_stats; 49126353Smlaier}; 50126353Smlaier 51126353Smlaier#define AVGN_MAX 8 52126353Smlaier#define STAT_INTERVAL 5 53126353Smlaier 54126353Smlaierstruct queue_stats { 55126353Smlaier union class_stats data; 56126353Smlaier int avgn; 57126353Smlaier double avg_bytes; 58126353Smlaier double avg_packets; 59126353Smlaier u_int64_t prev_bytes; 60126353Smlaier u_int64_t prev_packets; 61126353Smlaier}; 62126353Smlaier 63126353Smlaierstruct pf_altq_node { 64126353Smlaier struct pf_altq altq; 65126353Smlaier struct pf_altq_node *next; 66126353Smlaier struct pf_altq_node *children; 67126353Smlaier struct queue_stats qstats; 68126353Smlaier}; 69126353Smlaier 70126353Smlaierint pfctl_update_qstats(int, struct pf_altq_node **); 71126353Smlaiervoid pfctl_insert_altq_node(struct pf_altq_node **, 72126353Smlaier const struct pf_altq, const struct queue_stats); 73126353Smlaierstruct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *, 74126353Smlaier const char *, const char *); 75126353Smlaiervoid pfctl_print_altq_node(int, const struct pf_altq_node *, 76223637Sbz unsigned, int); 77126353Smlaiervoid print_cbqstats(struct queue_stats); 78126353Smlaiervoid print_priqstats(struct queue_stats); 79126353Smlaiervoid print_hfscstats(struct queue_stats); 80126353Smlaiervoid pfctl_free_altq_node(struct pf_altq_node *); 81126353Smlaiervoid pfctl_print_altq_nodestat(int, 82126353Smlaier const struct pf_altq_node *); 83126353Smlaier 84126353Smlaiervoid update_avg(struct pf_altq_node *); 85126353Smlaier 86126353Smlaierint 87130617Smlaierpfctl_show_altq(int dev, const char *iface, int opts, int verbose2) 88126353Smlaier{ 89126353Smlaier struct pf_altq_node *root = NULL, *node; 90130617Smlaier int nodes, dotitle = (opts & PF_OPT_SHOWALL); 91126353Smlaier 92127024Smlaier#ifdef __FreeBSD__ 93126355Smlaier if (!altqsupport) 94126355Smlaier return (-1); 95126355Smlaier#endif 96130617Smlaier 97130617Smlaier if ((nodes = pfctl_update_qstats(dev, &root)) < 0) 98126353Smlaier return (-1); 99126353Smlaier 100145840Smlaier if (nodes == 0) 101145840Smlaier printf("No queue in use\n"); 102130617Smlaier for (node = root; node != NULL; node = node->next) { 103130617Smlaier if (iface != NULL && strcmp(node->altq.ifname, iface)) 104130617Smlaier continue; 105130617Smlaier if (dotitle) { 106130617Smlaier pfctl_print_title("ALTQ:"); 107130617Smlaier dotitle = 0; 108130617Smlaier } 109126353Smlaier pfctl_print_altq_node(dev, node, 0, opts); 110130617Smlaier } 111126353Smlaier 112145840Smlaier while (verbose2 && nodes > 0) { 113126353Smlaier printf("\n"); 114126353Smlaier fflush(stdout); 115126353Smlaier sleep(STAT_INTERVAL); 116145840Smlaier if ((nodes = pfctl_update_qstats(dev, &root)) == -1) 117126353Smlaier return (-1); 118130617Smlaier for (node = root; node != NULL; node = node->next) { 119130617Smlaier if (iface != NULL && strcmp(node->altq.ifname, iface)) 120130617Smlaier continue; 121177700Smlaier#ifdef __FreeBSD__ 122177700Smlaier if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) 123177700Smlaier continue; 124177700Smlaier#endif 125126353Smlaier pfctl_print_altq_node(dev, node, 0, opts); 126130617Smlaier } 127126353Smlaier } 128126353Smlaier pfctl_free_altq_node(root); 129126353Smlaier return (0); 130126353Smlaier} 131126353Smlaier 132126353Smlaierint 133126353Smlaierpfctl_update_qstats(int dev, struct pf_altq_node **root) 134126353Smlaier{ 135126353Smlaier struct pf_altq_node *node; 136126353Smlaier struct pfioc_altq pa; 137126353Smlaier struct pfioc_qstats pq; 138126353Smlaier u_int32_t mnr, nr; 139126353Smlaier struct queue_stats qstats; 140126353Smlaier static u_int32_t last_ticket; 141126353Smlaier 142126353Smlaier memset(&pa, 0, sizeof(pa)); 143126353Smlaier memset(&pq, 0, sizeof(pq)); 144126353Smlaier memset(&qstats, 0, sizeof(qstats)); 145126353Smlaier if (ioctl(dev, DIOCGETALTQS, &pa)) { 146126353Smlaier warn("DIOCGETALTQS"); 147126353Smlaier return (-1); 148126353Smlaier } 149126353Smlaier 150126353Smlaier /* if a new set is found, start over */ 151126353Smlaier if (pa.ticket != last_ticket && *root != NULL) { 152126353Smlaier pfctl_free_altq_node(*root); 153126353Smlaier *root = NULL; 154126353Smlaier } 155126353Smlaier last_ticket = pa.ticket; 156126353Smlaier 157126353Smlaier mnr = pa.nr; 158126353Smlaier for (nr = 0; nr < mnr; ++nr) { 159126353Smlaier pa.nr = nr; 160126353Smlaier if (ioctl(dev, DIOCGETALTQ, &pa)) { 161126353Smlaier warn("DIOCGETALTQ"); 162126353Smlaier return (-1); 163126353Smlaier } 164177700Smlaier#ifdef __FreeBSD__ 165177700Smlaier if (pa.altq.qid > 0 && 166177700Smlaier !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { 167177700Smlaier#else 168126353Smlaier if (pa.altq.qid > 0) { 169177700Smlaier#endif 170126353Smlaier pq.nr = nr; 171126353Smlaier pq.ticket = pa.ticket; 172126353Smlaier pq.buf = &qstats.data; 173126353Smlaier pq.nbytes = sizeof(qstats.data); 174126353Smlaier if (ioctl(dev, DIOCGETQSTATS, &pq)) { 175126353Smlaier warn("DIOCGETQSTATS"); 176126353Smlaier return (-1); 177126353Smlaier } 178126353Smlaier if ((node = pfctl_find_altq_node(*root, pa.altq.qname, 179126353Smlaier pa.altq.ifname)) != NULL) { 180126353Smlaier memcpy(&node->qstats.data, &qstats.data, 181126353Smlaier sizeof(qstats.data)); 182126353Smlaier update_avg(node); 183126353Smlaier } else { 184126353Smlaier pfctl_insert_altq_node(root, pa.altq, qstats); 185126353Smlaier } 186126353Smlaier } 187177700Smlaier#ifdef __FreeBSD__ 188223637Sbz else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { 189223637Sbz memset(&qstats.data, 0, sizeof(qstats.data)); 190177700Smlaier if ((node = pfctl_find_altq_node(*root, pa.altq.qname, 191177700Smlaier pa.altq.ifname)) != NULL) { 192177700Smlaier memcpy(&node->qstats.data, &qstats.data, 193177700Smlaier sizeof(qstats.data)); 194177700Smlaier update_avg(node); 195177700Smlaier } else { 196177700Smlaier pfctl_insert_altq_node(root, pa.altq, qstats); 197223637Sbz } 198177700Smlaier } 199177700Smlaier#endif 200126353Smlaier } 201130617Smlaier return (mnr); 202126353Smlaier} 203126353Smlaier 204126353Smlaiervoid 205126353Smlaierpfctl_insert_altq_node(struct pf_altq_node **root, 206126353Smlaier const struct pf_altq altq, const struct queue_stats qstats) 207126353Smlaier{ 208126353Smlaier struct pf_altq_node *node; 209126353Smlaier 210126353Smlaier node = calloc(1, sizeof(struct pf_altq_node)); 211126353Smlaier if (node == NULL) 212126353Smlaier err(1, "pfctl_insert_altq_node: calloc"); 213126353Smlaier memcpy(&node->altq, &altq, sizeof(struct pf_altq)); 214126353Smlaier memcpy(&node->qstats, &qstats, sizeof(qstats)); 215126353Smlaier node->next = node->children = NULL; 216126353Smlaier 217126353Smlaier if (*root == NULL) 218126353Smlaier *root = node; 219126353Smlaier else if (!altq.parent[0]) { 220126353Smlaier struct pf_altq_node *prev = *root; 221126353Smlaier 222126353Smlaier while (prev->next != NULL) 223126353Smlaier prev = prev->next; 224126353Smlaier prev->next = node; 225126353Smlaier } else { 226126353Smlaier struct pf_altq_node *parent; 227126353Smlaier 228126353Smlaier parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname); 229126353Smlaier if (parent == NULL) 230126353Smlaier errx(1, "parent %s not found", altq.parent); 231126353Smlaier if (parent->children == NULL) 232126353Smlaier parent->children = node; 233126353Smlaier else { 234126353Smlaier struct pf_altq_node *prev = parent->children; 235126353Smlaier 236126353Smlaier while (prev->next != NULL) 237126353Smlaier prev = prev->next; 238126353Smlaier prev->next = node; 239126353Smlaier } 240126353Smlaier } 241126353Smlaier update_avg(node); 242126353Smlaier} 243126353Smlaier 244126353Smlaierstruct pf_altq_node * 245126353Smlaierpfctl_find_altq_node(struct pf_altq_node *root, const char *qname, 246126353Smlaier const char *ifname) 247126353Smlaier{ 248126353Smlaier struct pf_altq_node *node, *child; 249126353Smlaier 250126353Smlaier for (node = root; node != NULL; node = node->next) { 251126353Smlaier if (!strcmp(node->altq.qname, qname) 252126353Smlaier && !(strcmp(node->altq.ifname, ifname))) 253126353Smlaier return (node); 254126353Smlaier if (node->children != NULL) { 255126353Smlaier child = pfctl_find_altq_node(node->children, qname, 256126353Smlaier ifname); 257126353Smlaier if (child != NULL) 258126353Smlaier return (child); 259126353Smlaier } 260126353Smlaier } 261126353Smlaier return (NULL); 262126353Smlaier} 263126353Smlaier 264126353Smlaiervoid 265223637Sbzpfctl_print_altq_node(int dev, const struct pf_altq_node *node, 266223637Sbz unsigned int level, int opts) 267126353Smlaier{ 268126353Smlaier const struct pf_altq_node *child; 269126353Smlaier 270126353Smlaier if (node == NULL) 271126353Smlaier return; 272126353Smlaier 273126353Smlaier print_altq(&node->altq, level, NULL, NULL); 274126353Smlaier 275126353Smlaier if (node->children != NULL) { 276126353Smlaier printf("{"); 277126353Smlaier for (child = node->children; child != NULL; 278126353Smlaier child = child->next) { 279126353Smlaier printf("%s", child->altq.qname); 280126353Smlaier if (child->next != NULL) 281126353Smlaier printf(", "); 282126353Smlaier } 283126353Smlaier printf("}"); 284126353Smlaier } 285126353Smlaier printf("\n"); 286126353Smlaier 287126353Smlaier if (opts & PF_OPT_VERBOSE) 288126353Smlaier pfctl_print_altq_nodestat(dev, node); 289126353Smlaier 290126353Smlaier if (opts & PF_OPT_DEBUG) 291130617Smlaier printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", 292130617Smlaier node->altq.qid, node->altq.ifname, 293130617Smlaier rate2str((double)(node->altq.ifbandwidth))); 294126353Smlaier 295126353Smlaier for (child = node->children; child != NULL; 296126353Smlaier child = child->next) 297130617Smlaier pfctl_print_altq_node(dev, child, level + 1, opts); 298126353Smlaier} 299126353Smlaier 300126353Smlaiervoid 301126353Smlaierpfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) 302126353Smlaier{ 303126353Smlaier if (a->altq.qid == 0) 304126353Smlaier return; 305223637Sbz 306177700Smlaier#ifdef __FreeBSD__ 307177700Smlaier if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) 308177700Smlaier return; 309177700Smlaier#endif 310126353Smlaier switch (a->altq.scheduler) { 311126353Smlaier case ALTQT_CBQ: 312126353Smlaier print_cbqstats(a->qstats); 313126353Smlaier break; 314126353Smlaier case ALTQT_PRIQ: 315126353Smlaier print_priqstats(a->qstats); 316126353Smlaier break; 317126353Smlaier case ALTQT_HFSC: 318126353Smlaier print_hfscstats(a->qstats); 319126353Smlaier break; 320126353Smlaier } 321126353Smlaier} 322126353Smlaier 323126353Smlaiervoid 324126353Smlaierprint_cbqstats(struct queue_stats cur) 325126353Smlaier{ 326127024Smlaier printf(" [ pkts: %10llu bytes: %10llu " 327127024Smlaier "dropped pkts: %6llu bytes: %6llu ]\n", 328127024Smlaier (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets, 329127024Smlaier (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes, 330127024Smlaier (unsigned long long)cur.data.cbq_stats.drop_cnt.packets, 331127024Smlaier (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes); 332126353Smlaier printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n", 333126353Smlaier cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax, 334126353Smlaier cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays); 335126353Smlaier 336126353Smlaier if (cur.avgn < 2) 337126353Smlaier return; 338126353Smlaier 339126353Smlaier printf(" [ measured: %7.1f packets/s, %s/s ]\n", 340126353Smlaier cur.avg_packets / STAT_INTERVAL, 341126353Smlaier rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); 342126353Smlaier} 343126353Smlaier 344126353Smlaiervoid 345126353Smlaierprint_priqstats(struct queue_stats cur) 346126353Smlaier{ 347127024Smlaier printf(" [ pkts: %10llu bytes: %10llu " 348127024Smlaier "dropped pkts: %6llu bytes: %6llu ]\n", 349127024Smlaier (unsigned long long)cur.data.priq_stats.xmitcnt.packets, 350127024Smlaier (unsigned long long)cur.data.priq_stats.xmitcnt.bytes, 351127024Smlaier (unsigned long long)cur.data.priq_stats.dropcnt.packets, 352127024Smlaier (unsigned long long)cur.data.priq_stats.dropcnt.bytes); 353126353Smlaier printf(" [ qlength: %3d/%3d ]\n", 354126353Smlaier cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit); 355126353Smlaier 356126353Smlaier if (cur.avgn < 2) 357126353Smlaier return; 358126353Smlaier 359126353Smlaier printf(" [ measured: %7.1f packets/s, %s/s ]\n", 360126353Smlaier cur.avg_packets / STAT_INTERVAL, 361126353Smlaier rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); 362126353Smlaier} 363126353Smlaier 364126353Smlaiervoid 365126353Smlaierprint_hfscstats(struct queue_stats cur) 366126353Smlaier{ 367127024Smlaier printf(" [ pkts: %10llu bytes: %10llu " 368127024Smlaier "dropped pkts: %6llu bytes: %6llu ]\n", 369127024Smlaier (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets, 370127024Smlaier (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes, 371127024Smlaier (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets, 372127024Smlaier (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes); 373126353Smlaier printf(" [ qlength: %3d/%3d ]\n", 374126353Smlaier cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit); 375126353Smlaier 376126353Smlaier if (cur.avgn < 2) 377126353Smlaier return; 378126353Smlaier 379126353Smlaier printf(" [ measured: %7.1f packets/s, %s/s ]\n", 380126353Smlaier cur.avg_packets / STAT_INTERVAL, 381126353Smlaier rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); 382126353Smlaier} 383126353Smlaier 384126353Smlaiervoid 385126353Smlaierpfctl_free_altq_node(struct pf_altq_node *node) 386126353Smlaier{ 387126353Smlaier while (node != NULL) { 388126353Smlaier struct pf_altq_node *prev; 389126353Smlaier 390126353Smlaier if (node->children != NULL) 391126353Smlaier pfctl_free_altq_node(node->children); 392126353Smlaier prev = node; 393126353Smlaier node = node->next; 394126353Smlaier free(prev); 395126353Smlaier } 396126353Smlaier} 397126353Smlaier 398126353Smlaiervoid 399126353Smlaierupdate_avg(struct pf_altq_node *a) 400126353Smlaier{ 401126353Smlaier struct queue_stats *qs; 402126353Smlaier u_int64_t b, p; 403126353Smlaier int n; 404126353Smlaier 405126353Smlaier if (a->altq.qid == 0) 406126353Smlaier return; 407126353Smlaier 408126353Smlaier qs = &a->qstats; 409126353Smlaier n = qs->avgn; 410126353Smlaier 411126353Smlaier switch (a->altq.scheduler) { 412126353Smlaier case ALTQT_CBQ: 413126353Smlaier b = qs->data.cbq_stats.xmit_cnt.bytes; 414126353Smlaier p = qs->data.cbq_stats.xmit_cnt.packets; 415126353Smlaier break; 416126353Smlaier case ALTQT_PRIQ: 417126353Smlaier b = qs->data.priq_stats.xmitcnt.bytes; 418126353Smlaier p = qs->data.priq_stats.xmitcnt.packets; 419126353Smlaier break; 420126353Smlaier case ALTQT_HFSC: 421126353Smlaier b = qs->data.hfsc_stats.xmit_cnt.bytes; 422126353Smlaier p = qs->data.hfsc_stats.xmit_cnt.packets; 423126353Smlaier break; 424126353Smlaier default: 425126353Smlaier b = 0; 426126353Smlaier p = 0; 427126353Smlaier break; 428126353Smlaier } 429126353Smlaier 430126353Smlaier if (n == 0) { 431126353Smlaier qs->prev_bytes = b; 432126353Smlaier qs->prev_packets = p; 433126353Smlaier qs->avgn++; 434126353Smlaier return; 435126353Smlaier } 436126353Smlaier 437126353Smlaier if (b >= qs->prev_bytes) 438126353Smlaier qs->avg_bytes = ((qs->avg_bytes * (n - 1)) + 439126353Smlaier (b - qs->prev_bytes)) / n; 440126353Smlaier 441126353Smlaier if (p >= qs->prev_packets) 442126353Smlaier qs->avg_packets = ((qs->avg_packets * (n - 1)) + 443126353Smlaier (p - qs->prev_packets)) / n; 444126353Smlaier 445126353Smlaier qs->prev_bytes = b; 446126353Smlaier qs->prev_packets = p; 447126353Smlaier if (n < AVGN_MAX) 448126353Smlaier qs->avgn++; 449126353Smlaier} 450