Hi, the following adds new queue support for systat(1). Both old and new queues are shown in the same display (newqs are shown first). Majority of the code taken from pfctl.
For new queues the BW field only shows the target bandwidth (no burst info for example). Index: pftop.c =================================================================== RCS file: /cvs/src/usr.bin/systat/pftop.c,v retrieving revision 1.21 diff -u -p -r1.21 pftop.c --- pftop.c 12 Oct 2013 12:17:32 -0000 1.21 +++ pftop.c 21 Nov 2013 10:23:10 -0000 @@ -46,6 +46,8 @@ #include <altq/altq_priq.h> #include <altq/altq_hfsc.h> +#include <net/hfsc.h> + #include <ctype.h> #include <curses.h> #include <err.h> @@ -115,6 +117,7 @@ u_int32_t num_states = 0; u_int32_t num_states_all = 0; u_int32_t num_rules = 0; u_int32_t num_queues = 0; +u_int32_t num_altqs = 0; int cachestates = 0; char *filter_string = NULL; @@ -303,7 +306,7 @@ union class_stats { struct hfsc_classstats hfsc_stats; }; -struct queue_stats { +struct altq_stats { union class_stats data; struct timeval timestamp; u_int8_t valid; @@ -314,12 +317,28 @@ struct pf_altq_node { struct pf_altq_node *next; struct pf_altq_node *children; struct pf_altq_node *next_flat; - struct queue_stats qstats; - struct queue_stats qstats_last; + struct altq_stats qstats; + struct altq_stats qstats_last; u_int8_t depth; u_int8_t visited; }; +/* queue structures from pfctl */ + +struct queue_stats { + struct hfsc_class_stats data; + int valid; + struct timeval timestamp; +}; + +struct pfctl_queue_node { + TAILQ_ENTRY(pfctl_queue_node) entries; + struct pf_queuespec qs; + struct queue_stats qstats; + struct queue_stats qstats_last; + int depth; +}; +TAILQ_HEAD(qnodes, pfctl_queue_node) qnodes = TAILQ_HEAD_INITIALIZER(qnodes); /* ordering functions */ @@ -1515,7 +1534,7 @@ pfctl_find_altq_node(struct pf_altq_node void pfctl_insert_altq_node(struct pf_altq_node **root, - const struct pf_altq altq, const struct queue_stats qstats) + const struct pf_altq altq, const struct altq_stats qstats) { struct pf_altq_node *node; @@ -1569,14 +1588,106 @@ pfctl_set_next_flat(struct pf_altq_node } } +struct pfctl_queue_node * +pfctl_find_queue_node(const char *qname, const char *ifname) +{ + struct pfctl_queue_node *node; + + TAILQ_FOREACH(node, &qnodes, entries) + if (!strcmp(node->qs.qname, qname) + && !(strcmp(node->qs.ifname, ifname))) + return (node); + return (NULL); +} + +void +pfctl_insert_queue_node(const struct pf_queuespec qs, + const struct queue_stats qstats) +{ + struct pfctl_queue_node *node, *parent; + + node = calloc(1, sizeof(struct pfctl_queue_node)); + if (node == NULL) + err(1, "pfctl_insert_queue_node: calloc"); + memcpy(&node->qs, &qs, sizeof(qs)); + memcpy(&node->qstats, &qstats, sizeof(qstats)); + + if (node->qs.parent[0]) { + parent = pfctl_find_queue_node(node->qs.parent, + node->qs.ifname); + if (parent) + node->depth = parent->depth + 1; + } + + TAILQ_INSERT_TAIL(&qnodes, node, entries); +} + +int +pfctl_update_qstats(void) +{ + struct pfctl_queue_node *node; + struct pfioc_queue pq; + struct pfioc_qstats pqs; + u_int32_t mnr, nr; + struct queue_stats qstats; + static u_int32_t last_ticket; + + memset(&pq, 0, sizeof(pq)); + memset(&pqs, 0, sizeof(pqs)); + memset(&qstats, 0, sizeof(qstats)); + + if (pf_dev < 0) + return (-1); + + if (ioctl(pf_dev, DIOCGETQUEUES, &pq)) { + error("DIOCGETQUEUES: %s", strerror(errno)); + return (-1); + } + + /* if a new set is found, start over */ + if (pq.ticket != last_ticket) + while ((node = TAILQ_FIRST(&qnodes)) != NULL) + TAILQ_REMOVE(&qnodes, node, entries); + last_ticket = pq.ticket; + + num_queues = mnr = pq.nr; + for (nr = 0; nr < mnr; ++nr) { + pqs.nr = nr; + pqs.ticket = pq.ticket; + pqs.buf = &qstats.data; + pqs.nbytes = sizeof(qstats.data); + if (ioctl(pf_dev, DIOCGETQSTATS, &pqs)) { + error("DIOCGETQSTATS: %s", strerror(errno)); + return (-1); + } + if (pqs.queue.qname[0] != '_') { + if (pqs.queue.parent[0] && pqs.queue.parent[0] == '_') + pqs.queue.parent[0] = '\0'; + qstats.valid = 1; + gettimeofday(&qstats.timestamp, NULL); + if ((node = pfctl_find_queue_node(pqs.queue.qname, + pqs.queue.ifname)) != NULL) { + memcpy(&node->qstats_last, &node->qstats, + sizeof(struct queue_stats)); + memcpy(&node->qstats, &qstats, + sizeof(struct queue_stats)); + } else { + pfctl_insert_queue_node(pqs.queue, qstats); + } + } else + num_queues--; + } + return (0); +} + int -pfctl_update_qstats(struct pf_altq_node **root, int *inserts) +pfctl_update_altqstats(struct pf_altq_node **root, int *inserts) { struct pf_altq_node *node; struct pfioc_altq pa; struct pfioc_altqstats pq; u_int32_t nr; - struct queue_stats qstats; + struct altq_stats qstats; u_int32_t nr_queues; int ret = 0; @@ -1593,7 +1704,7 @@ pfctl_update_qstats(struct pf_altq_node return (-1); } - num_queues = nr_queues = pa.nr; + num_altqs = nr_queues = pa.nr; for (nr = 0; nr < nr_queues; ++nr) { pa.nr = nr; if (ioctl(pf_dev, DIOCGETALTQ, &pa)) { @@ -1606,8 +1717,8 @@ pfctl_update_qstats(struct pf_altq_node pq.ticket = pa.ticket; pq.buf = &qstats; pq.nbytes = sizeof(qstats); - if (ioctl(pf_dev, DIOCGETQSTATS, &pq)) { - error("DIOCGETQSTATS: %s", strerror(errno)); + if (ioctl(pf_dev, DIOCGETALTQSTATS, &pq)) { + error("DIOCGETALTQSTATS: %s", strerror(errno)); ret = -1; break; } @@ -1618,7 +1729,7 @@ pfctl_update_qstats(struct pf_altq_node /* update altq data too as bandwidth may have changed */ memcpy(&node->altq, &pa.altq, sizeof(struct pf_altq)); memcpy(&node->qstats_last, &node->qstats, - sizeof(struct queue_stats)); + sizeof(struct altq_stats)); memcpy(&node->qstats, &qstats, sizeof(qstats)); node->visited = 1; @@ -1628,7 +1739,7 @@ pfctl_update_qstats(struct pf_altq_node } } else - --num_queues; + --num_altqs; } pfctl_set_next_flat(*root, NULL); @@ -1683,7 +1794,7 @@ struct pf_altq_node *altq_root = NULL; int select_queues(void) { - num_disp = num_queues; + num_disp = num_queues + num_altqs; return (0); } @@ -1691,11 +1802,17 @@ int read_queues(void) { static int first_read = 1; + struct pfctl_queue_node *node; int inserts; - num_disp = num_queues = 0; - + num_disp = num_altqs = num_queues = 0; + pfctl_mark_all_unvisited(altq_root); - if (pfctl_update_qstats(&altq_root, &inserts)) + if (pfctl_update_altqstats(&altq_root, &inserts)) + return (-1); + + while ((node = TAILQ_FIRST(&qnodes)) != NULL) + TAILQ_REMOVE(&qnodes, node, entries); + if (pfctl_update_qstats() < 0) return (-1); /* Allow inserts only on first read; @@ -1706,12 +1823,12 @@ read_queues(void) pfctl_free_altq_node(altq_root); altq_root = NULL; first_read = 1; - if (pfctl_update_qstats(&altq_root, &inserts)) + if (pfctl_update_altqstats(&altq_root, &inserts)) return (-1); } first_read = 0; - num_disp = num_queues; + num_disp = num_queues + num_altqs; return(0); } @@ -1748,7 +1865,7 @@ calc_pps(u_int64_t new_pkts, u_int64_t l #define DEFAULT_PRIORITY 1 void -print_queue(struct pf_altq_node *node) +print_altqueue(struct pf_altq_node *node) { u_int8_t d; double interval, pps, bps; @@ -1848,19 +1965,87 @@ print_queue(struct pf_altq_node *node) } void +print_queue_node(struct pfctl_queue_node *node) +{ + u_int rate; + int i; + double interval, pps, bps; + static const char unit[] = " KMG"; + + tb_start(); + for (i = 0; i < node->depth; i++) + tbprintf(" "); + tbprintf("%s", node->qs.qname); + print_fld_tb(FLD_QUEUE); + + // XXX: missing min, max, burst + tb_start(); + rate = node->qs.linkshare.m2.absolute; + for (i = 0; rate >= 1000 && i <= 3; i++) + rate /= 1000; + tbprintf("%u%c", rate, unit[i]); + print_fld_tb(FLD_BANDW); + + if (node->qstats.valid && node->qstats_last.valid) + interval = calc_interval(&node->qstats.timestamp, + &node->qstats_last.timestamp); + else + interval = 0; + + print_fld_size(FLD_PKTS, node->qstats.data.xmit_cnt.packets); + print_fld_size(FLD_BYTES, node->qstats.data.xmit_cnt.bytes); + print_fld_size(FLD_DROPP, node->qstats.data.drop_cnt.packets); + print_fld_size(FLD_DROPB, node->qstats.data.drop_cnt.bytes); + print_fld_size(FLD_QLEN, node->qstats.data.qlength); + + if (interval > 0) { + pps = calc_pps(node->qstats.data.xmit_cnt.packets, + node->qstats_last.data.xmit_cnt.packets, interval); + bps = calc_rate(node->qstats.data.xmit_cnt.bytes, + node->qstats_last.data.xmit_cnt.bytes, interval); + + tb_start(); + if (pps > 0 && pps < 1) + tbprintf("%-3.1lf", pps); + else + tbprintf("%u", (unsigned int)pps); + + print_fld_tb(FLD_PKTSPS); + print_fld_bw(FLD_BYTESPS, bps); + } +} + +void print_queues(void) { - u_int32_t n, count = 0; - struct pf_altq_node *node = altq_root; + uint32_t n, count, start; + struct pf_altq_node *altqnode = altq_root; + struct pfctl_queue_node *node; + + n = count = 0; + start = dispstart; + + TAILQ_FOREACH(node, &qnodes, entries) { + if (n < start) { + n++; + continue; + } + print_queue_node(node); + end_line(); + count++; + if (maxprint > 0 && count >= maxprint) + return; + } - for (n = 0; n < dispstart; n++) - node = node->next_flat; + start -= n; + for (n = 0; n < start; n++) + altqnode = altqnode->next_flat; - for (; n < num_disp; n++) { - print_queue(node); - node = node->next_flat; + for (; n < num_altqs; n++) { + print_altqueue(altqnode); + altqnode = altqnode->next_flat; end_line(); - count ++; + count++; if (maxprint > 0 && count >= maxprint) break; }