systat - Add -altq display, bug fixes
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 4 Sep 2014 17:53:28 +0000 (10:53 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 4 Sep 2014 17:53:28 +0000 (10:53 -0700)
* Add systat -altq.  This displays altq packet statistics in a nice
  [ifname x altqname] matrix.  Packets, bytes, and drops are displayed.

  Previously the only way to do this was to use 'pfctl -s queue -vvv'
  which is formatted so horribly that picking information out of it
  at a glance is impossible.

  Example usage:  systat -altq 1

* Correct a bug in -ifstat that caused the statistics to not display
  when switching out and then back into the ifstat display.

usr.bin/systat/Makefile
usr.bin/systat/altqs.c [copied from usr.bin/systat/ifstat.c with 50% similarity]
usr.bin/systat/cmdtab.c
usr.bin/systat/extern.h
usr.bin/systat/ifstat.c

index 3e086e4..ad615a6 100644 (file)
@@ -8,7 +8,7 @@ CFLAGS+=-DINET6 -I${.CURDIR}/../../sys
 SRCS=  cmds.c cmdtab.c convtbl.c devs.c fetch.c ifcmds.c ifstat.c iostat.c \
        keyboard.c main.c mbufs.c netcmds.c netstat.c pigs.c sensors.c swap.c \
        icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c symbols.c \
-       utmpentry.c netbw.c pftop.c
+       utmpentry.c netbw.c pftop.c altqs.c
 DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM} ${LIBDEVSTAT} ${LIBKINFO}
 LDADD= -lcurses -ltermcap -lm -lkvm -ldevstat -lkinfo
 BINGRP=        kmem
similarity index 50%
copy from usr.bin/systat/ifstat.c
copy to usr.bin/systat/altqs.c
index 98fceca..bfb7c23 100644 (file)
@@ -24,8 +24,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD: src/usr.bin/systat/ifstat.c,v 1.7 2008/01/12 00:11:26 delphij Exp $
  */
 
 #include <sys/types.h>
 
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <err.h>
 #include <errno.h>
 
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include <net/pf/pfvar.h>
+
 #include "systat.h"
 #include "extern.h"
 #include "convtbl.h"
 
-                                /* Column numbers */
+static SLIST_HEAD(, qcol) qcols;
+static SLIST_HEAD(, if_stat) curlist;
+static int pf_fd = -1;
+static int qccols;
+static int TopSection1;
+static int TopSection2;
+static int TopSection3;
+
+struct qcol {
+       SLIST_ENTRY(qcol) link;
+       char *qname;
+       int col;
+};
 
-#define C1     0               /*  0-19 */
-#define C2     20              /* 20-39 */
-#define C3     40              /* 40-59 */
-#define C4     60              /* 60-80 */
-#define C5     80              /* Used for label positioning. */
+typedef struct qcol qcol_t;
 
-static const int col0 = 0;
-static const int col1 = C1;
-static const int col2 = C2;
-static const int col3 = C3;
-static const int col4 = C4;
-static const int col5 = C5;
+union class_stats {
+       class_stats_t           cbq;
+       struct priq_classstats  priq;
+       struct hfsc_classstats  hfsc;
+       struct fairq_classstats fairq;
+};
 
+struct queue_stats {
+       SLIST_ENTRY(queue_stats) link;
+       struct pfioc_altq       pa;
+       struct pfioc_qstats     pq;
+       qcol_t                  *qc;
+       union class_stats       ostats;
+       union class_stats       nstats;
+       uint64_t  old_bytes;
+       uint64_t  old_packets;
+};
 
-SLIST_HEAD(, if_stat)          curlist;
-SLIST_HEAD(, if_stat_disp)     displist;
+typedef struct queue_stats queue_stats_t;
 
 struct if_stat {
-       SLIST_ENTRY(if_stat)     link;
+       SLIST_ENTRY(if_stat) link;
+       SLIST_HEAD(, queue_stats) queues;
        char    if_name[IF_NAMESIZE];
        struct  ifmibdata if_mib;
        struct  timeval tv;
@@ -73,93 +98,89 @@ struct if_stat {
        u_long  if_in_traffic_peak;
        u_long  if_out_traffic_peak;
        u_int   if_row;                 /* Index into ifmib sysctl */
-       u_int   if_ypos;                /* 0 if not being displayed */
+       u_int   row;                    /* display row (relative) */
        u_int   display;
 };
 
+typedef struct if_stat if_stat_t;
+
 extern  u_int curscale;
 
-static  void  right_align_string(struct if_stat *);
+static  void  load_altqs(void);
+static  void  print_altq(if_stat_t *p, queue_stats_t *q);
+static  void  right_align_string(if_stat_t *);
 static  void  getifmibdata(const int, struct ifmibdata *);
 static  void  sort_interface_list(void);
 static  u_int getifnum(void);
 
 #define IFSTAT_ERR(n, s)       do {                                    \
        putchar('\f');                                                   \
-       closeifstat(wnd);                                               \
+       closealtqs(wnd);                                                \
        err((n), (s));                                                  \
 } while (0)
 
-#define STARTING_ROW   (8)
-#define ROW_SPACING    (3)
+#define TOPLINE                1
+#define TOPQSTART      20
+#define TOPQWIDTH      10
 
-#define TOPLINE 5
-#define TOPLABEL \
-"      Interface           Traffic               Peak                Total"
-
-#define CLEAR_LINE(y, x)       do {                                    \
-       wmove(wnd, y, x);                                               \
-       wclrtoeol(wnd);                                                 \
-} while (0)
-
-#define IN_col2                (ifp->if_in_curtraffic)
-#define OUT_col2       (ifp->if_out_curtraffic)
-#define IN_col3                (ifp->if_in_traffic_peak)
-#define OUT_col3       (ifp->if_out_traffic_peak)
-#define IN_col4                (ifp->if_mib.ifmd_data.ifi_ibytes)
-#define OUT_col4       (ifp->if_mib.ifmd_data.ifi_obytes)
-
-#define EMPTY_COLUMN   "                    "
-#define CLEAR_COLUMN(y, x)     mvprintw((y), (x), "%20s", EMPTY_COLUMN);
-
-#define DOPUTRATE(c, r, d)     do {                                    \
-       CLEAR_COLUMN(r, c);                                             \
-       mvprintw(r, (c), "%10.3f %s%s  ",                               \
-                convert(d##_##c, curscale),                            \
-                get_string(d##_##c, curscale),                         \
-                "/s");                                                 \
-} while (0)
+WINDOW *
+openaltqs(void)
+{
+       if_stat_t *p = NULL;
+       u_int    n = 0, i = 0;
 
-#define DOPUTTOTAL(c, r, d)    do {                                    \
-       CLEAR_COLUMN((r), (c));                                         \
-       mvprintw((r), (c), "%12.3f %s  ",                               \
-                convert(d##_##c, SC_AUTOBYTE),                         \
-                get_string(d##_##c, SC_AUTOBYTE));                     \
-} while (0)
+       pf_fd = open("/dev/pf", O_RDONLY);
 
-#define PUTRATE(c, r)  do {                                            \
-       DOPUTRATE(c, (r), IN);                                          \
-       DOPUTRATE(c, (r)+1, OUT);                                       \
-} while (0)
+       n = getifnum();         /* NOTE: can return < 0 */
 
-#define PUTTOTAL(c, r) do {                                            \
-       DOPUTTOTAL(c, (r), IN);                                         \
-       DOPUTTOTAL(c, (r)+1, OUT);                                      \
-} while (0)
+       SLIST_INIT(&curlist);
+       SLIST_INIT(&qcols);
+       for (i = 0; i < n; i++) {
+               p = (if_stat_t *)calloc(1, sizeof(if_stat_t));
+               if (p == NULL)
+                       IFSTAT_ERR(1, "out of memory");
+               SLIST_INSERT_HEAD(&curlist, p, link);
+               SLIST_INIT(&p->queues);
+               p->if_row = i+1;
+               getifmibdata(p->if_row, &p->if_mib);
+               right_align_string(p);
 
-#define PUTNAME(p) do {                                                        \
-       mvprintw(p->if_ypos, 0, "%s", p->if_name);                      \
-       mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in");         \
-       mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out");      \
-} while (0)
+               /*
+                * Initially, we only display interfaces that have
+                * received some traffic.
+                */
+               if (p->if_mib.ifmd_data.ifi_ibytes != 0)
+                       p->display = 1;
+       }
+       load_altqs();
 
+       sort_interface_list();
 
-WINDOW *
-openifstat(void)
-{
        return (subwin(stdscr, LINES-1-5, 0, 5, 0));
 }
 
 void
-closeifstat(WINDOW *w)
+closealtqs(WINDOW *w)
 {
-       struct if_stat  *node = NULL;
+       if_stat_t       *node = NULL;
+       queue_stats_t   *q;
 
        while (!SLIST_EMPTY(&curlist)) {
                node = SLIST_FIRST(&curlist);
                SLIST_REMOVE_HEAD(&curlist, link);
+               while ((q = SLIST_FIRST(&node->queues)) != NULL) {
+                       SLIST_REMOVE_HEAD(&node->queues, link);
+                       free(q);
+               }
                free(node);
        }
+       while (!SLIST_EMPTY(&qcols)) {
+               qcol_t *qc = SLIST_FIRST(&qcols);
+               SLIST_REMOVE_HEAD(&qcols, link);
+               free(qc->qname);
+               free(qc);
+       }
+       qccols = 0;
 
        if (w != NULL) {
                wclear(w);
@@ -167,73 +188,62 @@ closeifstat(WINDOW *w)
                delwin(w);
        }
 
+       if (pf_fd >= 0) {
+               close(pf_fd);
+               pf_fd = -1;
+       }
+
        return;
 }
 
-
 void
-labelifstat(void)
+labelaltqs(void)
 {
-
        wmove(wnd, TOPLINE, 0);
        wclrtoeol(wnd);
-       mvprintw(TOPLINE, 0, "%s", TOPLABEL);
-
-       return;
 }
 
 void
-showifstat(void)
+showaltqs(void)
 {
-       struct  if_stat *ifp = NULL;
-       SLIST_FOREACH(ifp, &curlist, link) {
-               if (ifp->display == 0)
-                       continue;
-               PUTNAME(ifp);
-               PUTRATE(col2, ifp->if_ypos);
-               PUTRATE(col3, ifp->if_ypos);
-               PUTTOTAL(col4, ifp->if_ypos);
+       if_stat_t *p = NULL;
+       queue_stats_t   *q;
+       qcol_t          *qc;
+
+       mvprintw(TopSection1, 0, "        PACKETS");
+       mvprintw(TopSection2, 0, "        BYTES");
+       mvprintw(TopSection3, 0, "        DROPS");
+       SLIST_FOREACH(qc, &qcols, link) {
+               mvprintw(TopSection1, TOPQSTART + TOPQWIDTH * qc->col,
+                        "%9s", qc->qname);
+               mvprintw(TopSection2, TOPQSTART + TOPQWIDTH * qc->col,
+                        "%9s", qc->qname);
+               mvprintw(TopSection3, TOPQSTART + TOPQWIDTH * qc->col,
+                        "%9s", qc->qname);
        }
 
-       return;
+       SLIST_FOREACH(p, &curlist, link) {
+               if (p->display == 0)
+                       continue;
+               mvprintw(TopSection1 + p->row, 0, "%s", p->if_name);
+               mvprintw(TopSection2 + p->row, 0, "%s", p->if_name);
+               mvprintw(TopSection3 + p->row, 0, "%s", p->if_name);
+               SLIST_FOREACH(q, &p->queues, link) {
+                       print_altq(p, q);
+               }
+       }
 }
 
 int
-initifstat(void)
+initaltqs(void)
 {
-       struct   if_stat *p = NULL;
-       u_int    n = 0, i = 0;
-
-       n = getifnum();
-       if (n <= 0)
-               return -1;
-
-       SLIST_INIT(&curlist);
-
-       for (i = 0; i < n; i++) {
-               p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
-               if (p == NULL)
-                       IFSTAT_ERR(1, "out of memory");
-               SLIST_INSERT_HEAD(&curlist, p, link);
-               p->if_row = i+1;
-               getifmibdata(p->if_row, &p->if_mib);
-               right_align_string(p);
-
-               /*
-                * Initially, we only display interfaces that have
-                * received some traffic.
-                */
-               if (p->if_mib.ifmd_data.ifi_ibytes != 0)
-                       p->display = 1;
-       }
-
-       sort_interface_list();
+       TopSection1 = TOPLINE;
 
        return 1;
 }
 
 void
-fetchifstat(void)
+fetchaltqs(void)
 {
        struct  if_stat *ifp = NULL;
        struct  timeval tv, new_tv, old_tv;
@@ -295,6 +305,8 @@ fetchifstat(void)
 
        }
 
+       load_altqs();
+
        if (we_need_to_sort_interface_list)
                sort_interface_list();
 
@@ -306,7 +318,7 @@ fetchifstat(void)
  * (first sixteen or so characters), so we need to do some alignment.
  */
 static void
-right_align_string(struct if_stat *ifp)
+right_align_string(if_stat_t *ifp)
 {
        int      str_len = 0, pad_len = 0;
        char    *newstr = NULL, *ptr = NULL;
@@ -332,7 +344,7 @@ right_align_string(struct if_stat *ifp)
  * This function iterates through our list of interfaces, identifying
  * those that are to be displayed (ifp->display = 1).  For each interf-
  * rface that we're displaying, we generate an appropriate position for
- * it on the screen (ifp->if_ypos).
+ * it on the screen (ifp->row).
  *
  * This function is called any time a change is made to an interface's
  * ``display'' state.
@@ -340,16 +352,16 @@ right_align_string(struct if_stat *ifp)
 void
 sort_interface_list(void)
 {
-       struct  if_stat *ifp = NULL;
-       u_int   y = 0;
+       if_stat_t *ifp;
+       u_int y;
 
-       y = STARTING_ROW;
+       y = 1;
        SLIST_FOREACH(ifp, &curlist, link) {
-               if (ifp->display) {
-                       ifp->if_ypos = y;
-                       y += ROW_SPACING;
-               }
+               if (ifp->display)
+                       ifp->row = ++y;
        }
+       TopSection2 = TopSection1 + y + 4;
+       TopSection3 = TopSection2 + y + 4;
 }
 
 static
@@ -389,15 +401,163 @@ getifmibdata(int row, struct ifmibdata *data)
                IFSTAT_ERR(2, "sysctl error getting interface data");
 }
 
+static void
+load_altqs(void)
+{
+       struct pfioc_altq pa;
+       struct pfioc_qstats pq;
+       if_stat_t *p;
+       queue_stats_t *q;
+       qcol_t *qc;
+       int i;
+       int n;
+
+       bzero(&pa, sizeof(pa));
+       bzero(&pq, sizeof(pq));
+
+       if (ioctl(pf_fd, DIOCGETALTQS, &pa))
+               return;
+       n = pa.nr;
+       for (i = 0; i < n; ++i) {
+               pa.nr = i;
+               if (ioctl(pf_fd, DIOCGETALTQ, &pa))
+                       return;
+               if (pa.altq.qid <= 0)
+                       continue;
+
+               SLIST_FOREACH(p, &curlist, link) {
+                       if (strcmp(pa.altq.ifname, p->if_mib.ifmd_name) == 0)
+                               break;
+               }
+               if (p == NULL)
+                       continue;
+               SLIST_FOREACH(q, &p->queues, link) {
+                       if (strcmp(pa.altq.qname, q->pa.altq.qname) == 0)
+                               break;
+               }
+               if (q == NULL) {
+                       q = calloc(1, sizeof(*q));
+                       q->pa = pa;
+                       SLIST_INSERT_HEAD(&p->queues, q, link);
+               } else {
+                       q->pa.ticket = pa.ticket;
+               }
+               q->ostats = q->nstats;
+               q->pq.nr = i;
+               q->pq.ticket = q->pa.ticket;
+               q->pq.buf = &q->nstats;
+               q->pq.nbytes = sizeof(q->nstats);
+               if (ioctl(pf_fd, DIOCGETQSTATS, &q->pq) < 0) {
+                       SLIST_REMOVE(&p->queues, q, queue_stats, link);
+                       free(q);
+               }
+               SLIST_FOREACH(qc, &qcols, link) {
+                       if (strcmp(q->pa.altq.qname, qc->qname) == 0)
+                               break;
+               }
+               if (qc == NULL) {
+                       qc = calloc(1, sizeof(*qc));
+                       qc->qname = strdup(q->pa.altq.qname);
+                       qc->col = qccols++;
+                       SLIST_INSERT_HEAD(&qcols, qc, link);
+               }
+               q->qc = qc;
+       }
+}
+
+static
+void
+print_altq(if_stat_t *p, queue_stats_t *q)
+{
+       uint64_t xmit_pkts;
+       uint64_t xmit_bytes;
+       uint64_t drop_pkts;
+       uint64_t drop_bytes __unused;
+
+       switch(q->pa.altq.scheduler) {
+       case ALTQT_CBQ:
+               xmit_pkts = q->nstats.cbq.xmit_cnt.packets;
+               xmit_bytes = q->nstats.cbq.xmit_cnt.bytes;
+               drop_pkts = q->nstats.cbq.drop_cnt.packets;
+               drop_bytes = q->nstats.cbq.drop_cnt.bytes;
+               xmit_pkts -= q->ostats.cbq.xmit_cnt.packets;
+               xmit_bytes -= q->ostats.cbq.xmit_cnt.bytes;
+               drop_pkts -= q->ostats.cbq.drop_cnt.packets;
+               drop_bytes -= q->ostats.cbq.drop_cnt.bytes;
+               break;
+       case ALTQT_PRIQ:
+               xmit_pkts = q->nstats.priq.xmitcnt.packets;
+               xmit_bytes = q->nstats.priq.xmitcnt.bytes;
+               drop_pkts = q->nstats.priq.dropcnt.packets;
+               drop_bytes = q->nstats.priq.dropcnt.bytes;
+               xmit_pkts -= q->ostats.priq.xmitcnt.packets;
+               xmit_bytes -= q->ostats.priq.xmitcnt.bytes;
+               drop_pkts -= q->ostats.priq.dropcnt.packets;
+               drop_bytes -= q->ostats.priq.dropcnt.bytes;
+               break;
+       case ALTQT_HFSC:
+               xmit_pkts = q->nstats.hfsc.xmit_cnt.packets;
+               xmit_bytes = q->nstats.hfsc.xmit_cnt.bytes;
+               drop_pkts = q->nstats.hfsc.drop_cnt.packets;
+               drop_bytes = q->nstats.hfsc.drop_cnt.bytes;
+               xmit_pkts -= q->ostats.hfsc.xmit_cnt.packets;
+               xmit_bytes -= q->ostats.hfsc.xmit_cnt.bytes;
+               drop_pkts -= q->ostats.hfsc.drop_cnt.packets;
+               drop_bytes -= q->ostats.hfsc.drop_cnt.bytes;
+               break;
+       case ALTQT_FAIRQ:
+               xmit_pkts = q->nstats.fairq.xmit_cnt.packets;
+               xmit_bytes = q->nstats.fairq.xmit_cnt.bytes;
+               drop_pkts = q->nstats.fairq.drop_cnt.packets;
+               drop_bytes = q->nstats.fairq.drop_cnt.bytes;
+               xmit_pkts -= q->ostats.fairq.xmit_cnt.packets;
+               xmit_bytes -= q->ostats.fairq.xmit_cnt.bytes;
+               drop_pkts -= q->ostats.fairq.drop_cnt.packets;
+               drop_bytes -= q->ostats.fairq.drop_cnt.bytes;
+               break;
+       default:
+               xmit_pkts = 0;
+               xmit_bytes = 0;
+               drop_pkts = 0;
+               drop_bytes = 0;
+               break;
+       }
+       if (xmit_pkts == 0)
+               mvprintw(TopSection1 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9s", "");
+       else
+               mvprintw(TopSection1 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9jd",  (intmax_t)xmit_pkts);
+
+       if (xmit_bytes == 0)
+               mvprintw(TopSection2 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9s", "");
+       else
+               mvprintw(TopSection2 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9jd",  (intmax_t)xmit_bytes);
+       if (drop_pkts == 0)
+               mvprintw(TopSection3 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9s", "");
+       else
+               mvprintw(TopSection3 + p->row,
+                        TOPQSTART + q->qc->col * TOPQWIDTH,
+                        "%9jd",  (intmax_t)drop_pkts);
+}
+
 int
-cmdifstat(const char *cmd, char *args)
+cmdaltqs(const char *cmd, char *args)
 {
        int     retval = 0;
 
        retval = ifcmd(cmd, args);
        /* ifcmd() returns 1 on success */
        if (retval == 1) {
-               showifstat();
+               showaltqs();
                refresh();
        }
 
index 91e1c88..d37deb6 100644 (file)
@@ -75,6 +75,9 @@ struct        cmdtab cmdtab[] = {
        { "ifstat",     showifstat,     fetchifstat,    labelifstat,
           initifstat,   openifstat,     closeifstat,    cmdifstat,
           NULL,                CF_LOADAV },
+       { "altqs",      showaltqs,      fetchaltqs,     labelaltqs,
+          initaltqs,    openaltqs,      closealtqs,     cmdaltqs,
+          NULL,                0 },
        { "ip6",        showip6,        fetchip6,       labelip6,
          initip6,      openip6,        closeip6,       cmdmode,
          resetip6,     CF_LOADAV },
index 4c246a5..74e3967 100644 (file)
@@ -67,6 +67,7 @@ int    checkhost(struct inpcb *);
 int     checkport(struct inpcb *);
 void    closeiostat(WINDOW *);
 void     closeifstat(WINDOW *);
+void     closealtqs(WINDOW *);
 void    closeicmp(WINDOW *);
 void     closeicmp6(WINDOW *);
 void    closeip(WINDOW *);
@@ -83,6 +84,7 @@ void   closetcp(WINDOW *);
 void    closevmm(WINDOW *);
 int     cmdiostat(const char *, char *);
 int     cmdifstat(const char *, char *);
+int     cmdaltqs(const char *, char *);
 int     cmdkre(const char *, char *);
 int     cmdnetstat(const char *, char *);
 int     cmdnetbw(const char *, char *);
@@ -97,6 +99,7 @@ void   error(const char *fmt, ...) __printflike(1, 2);
 void    fetchicmp(void);
 void    fetchicmp6(void);
 void     fetchifstat(void);
+void     fetchaltqs(void);
 void    fetchip(void);
 void    fetchip6(void);
 void    fetchiostat(void);
@@ -114,6 +117,7 @@ int  ifcmd(const char *, const char *);
 int     initicmp(void);
 int     initicmp6(void);
 int      initifstat(void);
+int      initaltqs(void);
 int     initip(void);
 int     initip6(void);
 int     initiostat(void);
@@ -132,6 +136,7 @@ int  kvm_ckread(void *, void *, int);
 void    labelicmp(void);
 void    labelicmp6(void);
 void     labelifstat(void);
+void     labelaltqs(void);
 void    labelip(void);
 void    labelip6(void);
 void    labeliostat(void);
@@ -152,6 +157,7 @@ void         nlisterr(struct nlist []);
 WINDOW *openicmp(void);
 WINDOW *openicmp6(void);
 WINDOW  *openifstat(void);
+WINDOW  *openaltqs(void);
 WINDOW *openip(void);
 WINDOW *openip6(void);
 WINDOW *openiostat(void);
@@ -174,6 +180,7 @@ void         resettcp(void);
 void    showicmp(void);
 void    showicmp6(void);
 void     showifstat(void);
+void     showaltqs(void);
 void    showip(void);
 void    showip6(void);
 void    showiostat(void);
index 98fceca..8b003cc 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <err.h>
 #include <errno.h>
 
@@ -59,8 +60,7 @@ static const int col4 = C4;
 static const int col5 = C5;
 
 
-SLIST_HEAD(, if_stat)          curlist;
-SLIST_HEAD(, if_stat_disp)     displist;
+static SLIST_HEAD(, if_stat) curlist;
 
 struct if_stat {
        SLIST_ENTRY(if_stat)     link;
@@ -147,6 +147,31 @@ static      u_int getifnum(void);
 WINDOW *
 openifstat(void)
 {
+       struct   if_stat *p = NULL;
+       u_int    n = 0, i = 0;
+
+       n = getifnum();         /* NOTE: can return < 0 */
+
+       SLIST_INIT(&curlist);
+       for (i = 0; i < n; i++) {
+               p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
+               if (p == NULL)
+                       IFSTAT_ERR(1, "out of memory");
+               SLIST_INSERT_HEAD(&curlist, p, link);
+               p->if_row = i+1;
+               getifmibdata(p->if_row, &p->if_mib);
+               right_align_string(p);
+
+               /*
+                * Initially, we only display interfaces that have
+                * received some traffic.
+                */
+               if (p->if_mib.ifmd_data.ifi_ibytes != 0)
+                       p->display = 1;
+       }
+
+       sort_interface_list();
+
        return (subwin(stdscr, LINES-1-5, 0, 5, 0));
 }
 
@@ -201,34 +226,6 @@ showifstat(void)
 int
 initifstat(void)
 {
-       struct   if_stat *p = NULL;
-       u_int    n = 0, i = 0;
-
-       n = getifnum();
-       if (n <= 0)
-               return -1;
-
-       SLIST_INIT(&curlist);
-
-       for (i = 0; i < n; i++) {
-               p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
-               if (p == NULL)
-                       IFSTAT_ERR(1, "out of memory");
-               SLIST_INSERT_HEAD(&curlist, p, link);
-               p->if_row = i+1;
-               getifmibdata(p->if_row, &p->if_mib);
-               right_align_string(p);
-
-               /*
-                * Initially, we only display interfaces that have
-                * received some traffic.
-                */
-               if (p->if_mib.ifmd_data.ifi_ibytes != 0)
-                       p->display = 1;
-       }
-
-       sort_interface_list();
-
        return 1;
 }