summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcanacar <canacar@openbsd.org>2008-12-17 08:21:43 +0000
committercanacar <canacar@openbsd.org>2008-12-17 08:21:43 +0000
commit06c5ffd0e0bf16541fa3503b12f7e3be2e3ab4a5 (patch)
treed4aac26c36511492b0ddf60c183cf37cc5abdaeb
parentfix spell errors, from Thomas Pfaff <tpfaff(at)tp76.info>, thanks! (diff)
downloadwireguard-openbsd-06c5ffd0e0bf16541fa3503b12f7e3be2e3ab4a5.tar.xz
wireguard-openbsd-06c5ffd0e0bf16541fa3503b12f7e3be2e3ab4a5.zip
Rewrite the 'mbuf' page to display mbuf usage information from system pools
and mbuf cluster statistics collected for each interface. More useful than earlier bar graphs about mbuf types. Requested by and ok deraadt@
-rw-r--r--usr.bin/systat/mbufs.c414
-rw-r--r--usr.bin/systat/systat.19
2 files changed, 303 insertions, 120 deletions
diff --git a/usr.bin/systat/mbufs.c b/usr.bin/systat/mbufs.c
index b947c97489d..d90966037e5 100644
--- a/usr.bin/systat/mbufs.c
+++ b/usr.bin/systat/mbufs.c
@@ -1,191 +1,375 @@
-/* $OpenBSD: mbufs.c,v 1.18 2008/06/12 22:26:01 canacar Exp $ */
-/* $NetBSD: mbufs.c,v 1.2 1995/01/20 08:52:02 jtc Exp $ */
-
-/*-
- * Copyright (c) 1980, 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/* $OpenBSD: mbufs.c,v 1.19 2008/12/17 08:21:43 canacar Exp $ */
+/*
+ * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-
#include <sys/param.h>
#include <sys/types.h>
-#include <sys/mbuf.h>
+#include <sys/socket.h>
#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <net/if.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
-#include <err.h>
-#include <paths.h>
+
#include "systat.h"
+/* pool info for mcl* pools */
+struct mclpool_info {
+ char title[16];
+ int pool_offset;
+ int size;
+} mclpools[MCLPOOLS];
+
+int mclpool_count = 0;
+int mbpool_index = -1;
+struct pool mbpool;
+
+/* interfaces */
+static int num_ifs;
+struct if_info {
+ char name[16];
+ struct if_data data;
+} *interfaces = NULL;
+
void print_mb(void);
int read_mb(void);
int select_mb(void);
-static void showmbuf(int);
-
-static struct mbstat mb;
-
-char *mtnames[] = {
- "free",
- "data",
- "headers",
- "sockets",
- "pcbs",
- "routes",
- "hosts",
- "arps",
- "socknames",
- "zombies",
- "sockopts",
- "frags",
- "rights",
- "ifaddrs",
+static void
+showmbuf(struct if_info *, int);
+
+
+/* Define fields */
+field_def fields_mbuf[] = {
+ {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
+ {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
+ {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
};
-#define NUM_TYPES (sizeof(mb.m_mtypes) / sizeof(mb.m_mtypes[0]))
-#define NNAMES (sizeof (mtnames) / sizeof (mtnames[0]))
-
-int mb_index[NUM_TYPES];
-int mbuf_cnt = 0;
+#define FIELD_ADDR(x) (&fields_mbuf[x])
-field_def fields_mb[] = {
- {"TYPE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
- {"VALUE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
- {"", 40, 80, 1, FLD_ALIGN_BAR, -1, 0, 0, 60},
-};
+#define FLD_MB_IFACE FIELD_ADDR(0)
+#define FLD_MB_RXDELAY FIELD_ADDR(1)
+#define FLD_MB_TXDELAY FIELD_ADDR(2)
+#define FLD_MB_LLOCKS FIELD_ADDR(3)
+#define FLD_MB_MSIZE FIELD_ADDR(4)
+#define FLD_MB_MALIVE FIELD_ADDR(5)
+#define FLD_MB_MLWM FIELD_ADDR(6)
+#define FLD_MB_MHWM FIELD_ADDR(7)
-#define FIELD_ADDR(x) (&fields_mb[x])
-
-#define FLD_MB_NAME FIELD_ADDR(0)
-#define FLD_MB_VALUE FIELD_ADDR(1)
-#define FLD_MB_BAR FIELD_ADDR(2)
/* Define views */
-field_def *view_mb_0[] = {
- FLD_MB_NAME, FLD_MB_VALUE, FLD_MB_BAR, NULL
+field_def *view_mbuf[] = {
+ FLD_MB_IFACE,
+#if NOTYET
+ FLD_MB_RXDELAY, FLD_MB_TXDELAY,
+#endif
+ FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
+ NULL
};
-
/* Define view managers */
+
struct view_manager mbuf_mgr = {
"Mbufs", select_mb, read_mb, NULL, print_header,
print_mb, keyboard_callback, NULL, NULL
};
field_view views_mb[] = {
- {view_mb_0, "mbufs", '4', &mbuf_mgr},
+ {view_mbuf, "mbufs", '4', &mbuf_mgr},
{NULL, NULL, 0, NULL}
};
int
-select_mb(void)
+initmembufs(void)
{
- int i, w = 50;
+ field_view *v;
+ int i, mib[4], npools;
+ struct pool pool;
+ char pname[32];
+ size_t size;
+ /* go through all pools to identify mbuf and cluster pools */
+ bzero(mclpools, sizeof(mclpools));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_POOL;
+ mib[2] = KERN_POOL_NPOOLS;
+ size = sizeof(npools);
+
+ if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
+ err(1, "sysctl(KERN_POOL_NPOOLS)");
+ /* NOTREACHED */
+ }
+
+ for (i = 1; i <= npools; i++) {
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_POOL;
+ mib[2] = KERN_POOL_NAME;
+ mib[3] = i;
+ size = sizeof(pname);
+ if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) {
+ err(1, "sysctl(KERN_POOL_POOLNAME, %d)", i);
+ /* NOTREACHED */
+ }
+
+ if (strcmp(pname, "mbpl") == 0) {
+ mbpool_index = i;
+ continue;
+ }
+
+ if (strncmp(pname, "mcl", 3) != 0)
+ continue;
+
+ if (mclpool_count == MCLPOOLS) {
+ warnx("mbufs: Too many mcl* pools", i);
+ break;
+ }
+
+ mib[2] = KERN_POOL_POOL;
+ size = sizeof(struct pool);
+
+ if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
+ err(1, "sysctl(KERN_POOL_POOL, %d)", i);
+ /* NOTREACHED */
+ }
+
+ mclpools[mclpool_count].size = pool.pr_size;
+ mclpools[mclpool_count].pool_offset = i;
+ snprintf(mclpools[mclpool_count].title,
+ sizeof(mclpools[0].title), "%dk",
+ pool.pr_size / 1024);
+
+ mclpool_count++;
+ }
+
+ if (mclpool_count != MCLPOOLS)
+ warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS);
+
+ /* add view to the engine */
+ for (v = views_mb; v->name != NULL; v++)
+ add_view(v);
+
+
+ /* finally read it once */
read_mb();
- for (i = 0; i < NUM_TYPES; i++)
- if (w < (5 * mb.m_mtypes[i] / 4))
- w = 5 * mb.m_mtypes[i] / 4;
- w -= w % 10;
- FLD_MB_BAR->arg = w;
+ return(1);
+}
+int
+select_mb(void)
+{
+ num_disp = 0;
return (0);
}
int
read_mb(void)
{
- int mib[2], i;
- size_t size = sizeof (mb);
+ struct pool pool;
+ struct ifaddrs *ifap, *ifa;
+ struct if_info *ifi;
+ int mib[4];
+ int i, p, nif, ret = 1;
+ size_t size;
+
+ num_disp = 0;
+ if (getifaddrs(&ifap)) {
+ error("getifaddrs: %s", strerror(errno));
+ return (1);
+ }
- mib[0] = CTL_KERN;
- mib[1] = KERN_MBSTAT;
+ nif = 1;
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
+ nif++;
+
+ if (interfaces == NULL || num_ifs < nif) {
+ size_t len = sizeof(*ifi) * nif;
+ if (nif > SIZE_MAX / sizeof(*ifi)) {
+ error("overflow allocting %u interfaces", nif);
+ goto exit;
+ }
+
+ ifi = realloc(interfaces, len);
+ if (ifi == NULL) {
+ error("realloc: out of memory allocating %lld bytes",
+ (long long) len);
+ goto exit;
+ }
+
+ interfaces = ifi;
+ num_ifs = nif;
+ }
- if (sysctl(mib, 2, &mb, &size, NULL, 0) < 0) {
- error("sysctl(KERN_MBSTAT) failed");
- return 1;
+ /* Fill in the "real" interfaces */
+ ifi = interfaces + 1;
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name));
+
+ if (ifa->ifa_data)
+ memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data));
+ else
+ bzero(&ifi->data, sizeof(ifi->data));
+ ifi++;
}
- mbuf_cnt = 0;
- memset(mb_index, 0, sizeof(mb_index));
+ /* Fill in the "System" entry from pools */
+ bzero(interfaces, sizeof(interfaces[0]));
+ strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name));
- for (i = 0; i < NUM_TYPES; i++) {
- if (mb.m_mtypes[i])
- mb_index[mbuf_cnt++] = i;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_POOL;
+ mib[2] = KERN_POOL_POOL;
+ mib[3] = mbpool_index;
+ size = sizeof(struct pool);
+
+ if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) {
+ error("sysctl(KERN_POOL_POOL, %d)", i);
+ goto exit;
}
- num_disp = mbuf_cnt;
+ for (i = 0; i < mclpool_count; i++) {
+ struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i];
- return 0;
-}
+ mib[3] = mclpools[i].pool_offset;
+ size = sizeof(struct pool);
+ if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
+ error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
+ continue;
+ }
-void
-print_mb(void)
-{
- int n, count = 0;
+ mp->mcl_size = pool.pr_size;
+ mp->mcl_alive = pool.pr_nget - pool.pr_nput;
+ mp->mcl_hwm = pool.pr_hiwat;
+ }
- for (n = dispstart; n < num_disp; n++) {
- showmbuf(n);
- count++;
- if (maxprint > 0 && count >= maxprint)
- break;
+ num_disp = 1;
+ ret = 0;
+
+ for (i = 0; i < num_ifs; i++) {
+ struct if_info *ifi = &interfaces[i];
+ int pnd = num_disp;
+ for (p = 0; p < mclpool_count; p++) {
+ struct mclpool *mp = &ifi->data.ifi_mclpool[p];
+ if (mp->mcl_size != (ushort)mclpools[p].size)
+ break;
+ if (mp->mcl_alive == 0)
+ continue;
+ num_disp++;
+ }
+ if (i && pnd == num_disp)
+ num_disp++;
}
+
+ exit:
+ freeifaddrs(ifap);
+ return (ret);
}
-int
-initmembufs(void)
+void
+print_mb(void)
{
- field_view *v;
+ int i, p, n, count = 0;
- for (v = views_mb; v->name != NULL; v++)
- add_view(v);
+ showmbuf(interfaces, -1);
- return(1);
+ for (n = i = 0; i < num_ifs; i++) {
+ struct if_info *ifi = &interfaces[i];
+ int pcnt = count;
+ if (maxprint > 0 && count >= maxprint)
+ return;
+
+ for (p = 0; p < mclpool_count; p++) {
+ struct mclpool *mp = &ifi->data.ifi_mclpool[p];
+ if (mp->mcl_size != (ushort)mclpools[p].size)
+ break;
+ if (mp->mcl_alive == 0)
+ continue;
+ if (n++ >= dispstart) {
+ showmbuf(ifi, p);
+ count++;
+ }
+ }
+
+ if (i && pcnt == count) {
+ /* only print the first line */
+ if (n++ >= dispstart) {
+ showmbuf(ifi, -1);
+ count++;
+ }
+ }
+
+
+ }
}
static void
-showmbuf(int m)
+showmbuf(struct if_info *ifi, int p)
{
int i;
- i = mb_index[m];
- if (i < NNAMES)
- print_fld_str(FLD_MB_NAME, mtnames[i]);
- else
- print_fld_uint(FLD_MB_NAME, i);
- print_fld_uint(FLD_MB_VALUE, mb.m_mtypes[i]);
- print_fld_bar(FLD_MB_BAR, mb.m_mtypes[i]);
+ if (p == -1 || (p == 0 && ifi != interfaces)) {
+ print_fld_str(FLD_MB_IFACE, ifi->name);
+ }
+
+ if (p == -1 && ifi == interfaces) {
+ print_fld_size(FLD_MB_MSIZE, mbpool.pr_size);
+ print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput);
+ print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat);
+ }
+
+
+
+#if NOTYET
+ print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay);
+ print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay);
+ print_fld_size(FLD_MB_LLOCKS, ifi->data.ifi_txdelay);
+#endif
+
+ if (p >= 0 && p < mclpool_count) {
+ struct mclpool *mp = &ifi->data.ifi_mclpool[p];
+
+ print_fld_str(FLD_MB_MSIZE, mclpools[p].title);
+ print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive);
+ if (mp->mcl_lwm)
+ print_fld_size(FLD_MB_MLWM, mp->mcl_lwm);
+ if (mp->mcl_hwm)
+ print_fld_size(FLD_MB_MHWM, mp->mcl_hwm);
+ }
end_line();
}
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
index 9d481b34dc9..174a74a4d9a 100644
--- a/usr.bin/systat/systat.1
+++ b/usr.bin/systat/systat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: systat.1,v 1.77 2008/12/11 13:33:41 jmc Exp $
+.\" $OpenBSD: systat.1,v 1.78 2008/12/17 08:21:43 canacar Exp $
.\" $NetBSD: systat.1,v 1.6 1996/05/10 23:16:39 thorpej Exp $
.\"
.\" Copyright (c) 1985, 1990, 1993
@@ -30,7 +30,7 @@
.\"
.\" @(#)systat.1 8.2 (Berkeley) 12/30/93
.\"
-.Dd $Mdocdate: December 11 2008 $
+.Dd $Mdocdate: December 17 2008 $
.Dt SYSTAT 1
.Os
.Sh NAME
@@ -270,9 +270,8 @@ Available orderings are:
and
.Ic requests .
.It Ic mbufs
-Display the number of mbufs allocated
-for particular uses,
-such as data and socket structures.
+Display mbuf usage information from kernel pools
+and mbuf cluster pool statistics of each network interface.
.It Ic netstat
Display network connections.
By default, network servers awaiting requests are not displayed.