Awhile back, DragonlyFlyBSD added a netbw option to systat that I've ported to FreeBSD and found handy at various times:
netbw Display aggregate and per-connection TCP receive and transmit rates. Only active TCP connections are shown. Leading to output such as: tcp accepts connects rcv 1.192G snd 15.77K rexmit 192.168.10.80:22 192.168.10.20:23103 rcv snd 415.7 [ NTSX ] 192.168.10.80:22 192.168.10.20:46560 rcv 19.80M snd 14.47K [ NTSX ] 192.168.10.80:22 192.168.10.20:60699 rcv snd 886.3 [ NTSX ] 192.168.10.81:5201 192.168.10.51:60844 rcv 293.2M snd [R TSX ] 192.168.10.81:5201 192.168.10.51:60845 rcv 293.5M snd [R TSX ] 192.168.10.81:5201 192.168.10.51:60846 rcv 293.2M snd [R TSX ] 192.168.10.81:5201 192.168.10.51:60847 rcv 292.9M snd [R TSX ] It uses the sequences number from the 'struct tcpcb' to derive the rates, which is usually good but certainly not perfect (i.e., don't set the interval too long). I'd like to commit this if anybody else thinks they'd find it useful. http://people.freebsd.org/~bryanv/patches/systat-netbw.patch
From d0a4f282f3e36eb53cb0a50a64aa4597e52b7d42 Mon Sep 17 00:00:00 2001 From: Bryan Venteicher <bry...@daemoninthecloset.org> Date: Tue, 1 Jul 2014 00:51:29 -0500 Subject: [PATCH] Add 'netbw' display to systat --- usr.bin/systat/Makefile | 2 +- usr.bin/systat/cmdtab.c | 3 + usr.bin/systat/extern.h | 7 + usr.bin/systat/netbw.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++ usr.bin/systat/systat.1 | 4 + 5 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 usr.bin/systat/netbw.c diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index 1bb2da0..a17e4dd 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -7,7 +7,7 @@ PROG= systat SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \ netcmds.c netstat.c pigs.c swap.c icmp.c \ mode.c ip.c tcp.c \ - vmstat.c convtbl.c ifcmds.c ifstat.c + vmstat.c convtbl.c ifcmds.c ifstat.c netbw.c .if ${MK_INET6_SUPPORT} != "no" SRCS+= icmp6.c ip6.c diff --git a/usr.bin/systat/cmdtab.c b/usr.bin/systat/cmdtab.c index c9c9e7d..0e225ec 100644 --- a/usr.bin/systat/cmdtab.c +++ b/usr.bin/systat/cmdtab.c @@ -55,6 +55,9 @@ struct cmdtab cmdtab[] = { { "netstat", shownetstat, fetchnetstat, labelnetstat, initnetstat, opennetstat, closenetstat, cmdnetstat, 0, CF_LOADAV }, + { "netbw", shownetbw, fetchnetbw, labelnetbw, + initnetbw, opennetbw, closenetbw, NULL, + 0, 0 }, { "icmp", showicmp, fetchicmp, labelicmp, initicmp, openicmp, closeicmp, cmdmode, reseticmp, CF_LOADAV }, diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h index 17fffc1..38d4084 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -76,6 +76,7 @@ void closeiostat(WINDOW *); void closeip(WINDOW *); void closeip6(WINDOW *); void closekre(WINDOW *); +void closenetbw(WINDOW *); void closenetstat(WINDOW *); void closepigs(WINDOW *); void closeswap(WINDOW *); @@ -83,6 +84,7 @@ void closetcp(WINDOW *); int cmdifstat(const char *, const char *); int cmdiostat(const char *, const char *); int cmdkre(const char *, const char *); +int cmdnetbw(const char *, const char *); int cmdnetstat(const char *, const char *); struct cmdtab *lookup(const char *); void command(const char *); @@ -98,6 +100,7 @@ void fetchip(void); void fetchip6(void); void fetchiostat(void); void fetchkre(void); +void fetchnetbw(void); void fetchnetstat(void); void fetchpigs(void); void fetchswap(void); @@ -111,6 +114,7 @@ int initip(void); int initip6(void); int initiostat(void); int initkre(void); +int initnetbw(void); int initnetstat(void); int initpigs(void); int initswap(void); @@ -124,6 +128,7 @@ void labelip(void); void labelip6(void); void labeliostat(void); void labelkre(void); +void labelnetbw(void); void labelnetstat(void); void labelpigs(void); void labels(void); @@ -139,6 +144,7 @@ WINDOW *openip(void); WINDOW *openip6(void); WINDOW *openiostat(void); WINDOW *openkre(void); +WINDOW *opennetbw(void); WINDOW *opennetstat(void); WINDOW *openpigs(void); WINDOW *openswap(void); @@ -156,6 +162,7 @@ void showip(void); void showip6(void); void showiostat(void); void showkre(void); +void shownetbw(void); void shownetstat(void); void showpigs(void); void showswap(void); diff --git a/usr.bin/systat/netbw.c b/usr.bin/systat/netbw.c new file mode 100644 index 0000000..785af5f --- /dev/null +++ b/usr.bin/systat/netbw.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2013 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon <dil...@backplane.com> + * + * 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 DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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. + */ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/route.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifdef INET6 +#include <netinet/ip6.h> +#endif +#include <netinet/in_pcb.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcp_debug.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <nlist.h> +#include <paths.h> +#include "systat.h" +#include "extern.h" + +/* Reduce diff from DragonflyBSD. */ +union in_dependaddr { + struct in_addr_4in6 id46_addr; + struct in6_addr id6_addr; +}; +typedef int32_t tcp_seq_diff_t; +#define s6_addr16 __u6_addr.__u6_addr16 + +struct mytcpcb { + RB_ENTRY(mytcpcb) rb_node; + int seq; + struct xtcpcb xtcp; + struct xtcpcb last_xtcp; +}; + +static int +mytcpcb_cmp(struct mytcpcb *tcp1, struct mytcpcb *tcp2) +{ + int r; + + /* + * Low local or foreign port comes first (local has priority). + */ + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_lport) >= 1024 && + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_lport) >= 1024) { + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_fport) < + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_fport)) + return(-1); + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_fport) > + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_fport)) + return(1); + } + + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_lport) < + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_lport)) + return(-1); + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_lport) > + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_lport)) + return(1); + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_fport) < + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_fport)) + return(-1); + if (ntohs(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_fport) > + ntohs(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_fport)) + return(1); + + /* + * Sort IPV4 vs IPV6 addresses + */ + if ((tcp1->xtcp.xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) < + (tcp2->xtcp.xt_inp.inp_vflag & (INP_IPV4|INP_IPV6))) + return(-1); + if ((tcp1->xtcp.xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) > + (tcp2->xtcp.xt_inp.inp_vflag & (INP_IPV4|INP_IPV6))) + return(1); + + /* + * Local and foreign addresses + */ + if (tcp1->xtcp.xt_inp.inp_vflag & INP_IPV4) { + if (ntohl(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_laddr.s_addr) < + ntohl(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_laddr.s_addr)) + return(-1); + if (ntohl(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_laddr.s_addr) > + ntohl(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_laddr.s_addr)) + return(1); + if (ntohl(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_faddr.s_addr) < + ntohl(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_faddr.s_addr)) + return(-1); + if (ntohl(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie_faddr.s_addr) > + ntohl(tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie_faddr.s_addr)) + return(1); + } else if (tcp1->xtcp.xt_inp.inp_vflag & INP_IPV6) { + r = bcmp(&tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr, + &tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr, + sizeof(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr)); + if (r) + return(r); + } else { + r = bcmp(&tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr, + &tcp2->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr, + sizeof(tcp1->xtcp.xt_inp.inp_inc.inc_ie.ie6_faddr)); + if (r) + return(r); + } + return(0); +} + +struct mytcpcb_tree; +static RB_HEAD(mytcpcb_tree, mytcpcb); +RB_PROTOTYPE_STATIC(mytcpcb_tree, mytcpcb, rb_node, mytcpcb_cmp); +RB_GENERATE_STATIC(mytcpcb_tree, mytcpcb, rb_node, mytcpcb_cmp); + +static struct mytcpcb_tree mytcp_tree; +static struct timeval tv_curr; +static struct timeval tv_last; +static struct tcpstat tcp_curr; +static struct tcpstat tcp_last; +static int tcp_pcb_seq; + +static const char *numtok(double value); +static void netbwline(int row, struct mytcpcb *elm, double delta_time); +static const char *netaddrstr(u_char vflags, union in_dependaddr *depaddr, + u_int16_t port); +static void updatepcb(struct xtcpcb *xtcp); + +#define DELTARATE(field) \ + ((double)(tcp_curr.field - tcp_last.field) / delta_time) + +#define DELTAELM(field) \ + ((double)(tcp_seq_diff_t)(elm->xtcp.field - \ + elm->last_xtcp.field) / \ + delta_time) + +#define DELTAELMSCALE(field, scale) \ + ((double)((tcp_seq_diff_t)(elm->xtcp.field - \ + elm->last_xtcp.field) << scale) / \ + delta_time) + +WINDOW * +opennetbw(void) +{ + RB_INIT(&mytcp_tree); + return (subwin(stdscr, LINES-0-1, 0, 0, 0)); +} + +void +closenetbw(WINDOW *w) +{ + struct mytcpcb *mytcp; + + while ((mytcp = RB_ROOT(&mytcp_tree)) != NULL) { + RB_REMOVE(mytcpcb_tree, &mytcp_tree, mytcp); + free(mytcp); + } + + if (w != NULL) { + wclear(w); + wrefresh(w); + delwin(w); + } +} + +int +initnetbw(void) +{ + return(1); +} + +void +fetchnetbw(void) +{ + struct xinpgen *inpg; + struct xtcpcb *xtp; + char *cur, *end; + size_t len; + + /* + * Extract PCB list + */ + inpg = (struct xinpgen *)sysctl_dynread("net.inet.tcp.pcblist", &len); + if (inpg == NULL) + return; + /* + * We currently do no require a consistent pcb list. + * Try to be robust in case of struct size changes + */ + cur = ((char *)inpg) + inpg->xig_len; + /* There is also a trailing struct xinpgen */ + end = ((char *)inpg) + len - inpg->xig_len; + if (end <= cur) { + free(inpg); + return; + } + ++tcp_pcb_seq; + xtp = (struct xtcpcb *)cur; + while (cur + xtp->xt_len <= end) { + updatepcb(xtp); + cur += xtp->xt_len; + xtp = (struct xtcpcb *)cur; + } + free(inpg); + + /* + * General stats + */ + tcp_last = tcp_curr; + len = sizeof(tcp_curr); + if (sysctlbyname("net.inet.tcp.stats", &tcp_curr, &len, NULL, 0) < 0) + return; + tv_last = tv_curr; + gettimeofday(&tv_curr, NULL); +} + +void +labelnetbw(void) +{ + wmove(wnd, 0, 0); + wclrtobot(wnd); +#if 0 + mvwaddstr(wnd, 0, LADDR, "Local Address"); + mvwaddstr(wnd, 0, FADDR, "Foreign Address"); + mvwaddstr(wnd, 0, PROTO, "Proto"); + mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); + mvwaddstr(wnd, 0, SNDCC, "Send-Q"); + mvwaddstr(wnd, 0, STATE, "(state)"); +#endif +} + +void +shownetbw(void) +{ + double delta_time; + struct mytcpcb *elm, *telm; + int row; + + delta_time = (double)(tv_curr.tv_sec - tv_last.tv_sec) - 1.0 + + (tv_curr.tv_usec + 1000000 - tv_last.tv_usec) / 1e6; + if (delta_time < 0.1) + return; + + mvwprintw(wnd, 0, 0, + "tcp accepts %s connects %s " + " rcv %s snd %s rexmit %s", + numtok(DELTARATE(tcps_accepts)), + numtok(DELTARATE(tcps_connects) - DELTARATE(tcps_accepts)), + numtok(DELTARATE(tcps_rcvbyte)), + numtok(DELTARATE(tcps_sndbyte)), + numtok(DELTARATE(tcps_sndrexmitbyte))); + + row = 2; + RB_FOREACH_SAFE(elm, mytcpcb_tree, &mytcp_tree, telm) { + if (elm->seq == tcp_pcb_seq && + (elm->xtcp.xt_socket.so_rcv.sb_cc || + elm->xtcp.xt_socket.so_snd.sb_cc || + DELTAELM(xt_tp.snd_max) || + DELTAELM(xt_tp.rcv_nxt) + )) { + if (row < LINES - 3) + netbwline(row, elm, delta_time); + ++row; + } else if (elm->seq != tcp_pcb_seq) { + RB_REMOVE(mytcpcb_tree, &mytcp_tree, elm); + free(elm); + } + } + wmove(wnd, row, 0); + wclrtobot(wnd); + mvwprintw(wnd, LINES-2, 0, + "Rate/sec, " + "R=rxpend T=txpend N=nodelay T=tstmp " + "S=sack X=winscale F=fastrec"); +} + +static void +netbwline(int row, struct mytcpcb *elm, double delta_time) +{ + mvwprintw(wnd, row, 0, + "%s %s " + /*"rxb %s txb %s "*/ + "rcv %s snd %s " + "[%c%c%c%c%c%c%c]", + netaddrstr( + elm->xtcp.xt_inp.inp_vflag, + (union in_dependaddr *)&elm->xtcp.xt_inp.inp_inc.inc_ie. + ie_dependladdr, + ntohs(elm->xtcp.xt_inp.inp_inc.inc_ie.ie_lport)), + netaddrstr( + elm->xtcp.xt_inp.inp_vflag, + (union in_dependaddr*)&elm->xtcp.xt_inp.inp_inc.inc_ie. + ie_dependfaddr, + ntohs(elm->xtcp.xt_inp.inp_inc.inc_ie.ie_fport)), + /* + numtok(elm->xtcp.xt_socket.so_rcv.sb_cc), + numtok(elm->xtcp.xt_socket.so_snd.sb_cc), + */ + numtok(DELTAELM(xt_tp.rcv_nxt)), + numtok(DELTAELM(xt_tp.snd_max)), + (elm->xtcp.xt_socket.so_rcv.sb_cc > 15000 ? + 'R' : ' '), + (elm->xtcp.xt_socket.so_snd.sb_cc > 15000 ? + 'T' : ' '), + ((elm->xtcp.xt_tp.t_flags & TF_NODELAY) ? + 'N' : ' '), + ((elm->xtcp.xt_tp.t_flags & TF_RCVD_TSTMP) ? + 'T' : ' '), + ((elm->xtcp.xt_tp.t_flags & TF_SACK_PERMIT) ? + 'S' : ' '), + ((elm->xtcp.xt_tp.t_flags & TF_RCVD_SCALE) ? + 'X' : ' '), + ((elm->xtcp.xt_tp.t_flags & TF_FASTRECOVERY) ? + 'F' : ' ') + ); + wclrtoeol(wnd); +} + +#if 0 +int +cmdnetbw(const char *cmd __unused, char *args __unused) +{ + fetchnetbw(); + shownetbw(); + refresh(); + + return (0); +} +#endif + +#define MAXINDEXES 8 + +static const char * +numtok(double value) +{ + static char buf[MAXINDEXES][32]; + static int nexti; + static const char *suffixes[] = { " ", "K", "M", "G", "T", NULL }; + int suffix = 0; + const char *fmt; + + while (value >= 1000.0 && suffixes[suffix+1]) { + value /= 1000.0; + ++suffix; + } + nexti = (nexti + 1) % MAXINDEXES; + if (value < 0.001) { + fmt = " "; + } else if (value < 1.0) { + fmt = "%5.3f%s"; + } else if (value < 10.0) { + fmt = "%5.3f%s"; + } else if (value < 100.0) { + fmt = "%5.2f%s"; + } else { + fmt = "%5.1f%s"; + } + snprintf(buf[nexti], sizeof(buf[nexti]), + fmt, value, suffixes[suffix]); + return (buf[nexti]); +} + +static const char * +netaddrstr(u_char vflags, union in_dependaddr *depaddr, u_int16_t port) +{ + static char buf[MAXINDEXES][64]; + static int nexta; + char bufip[64]; + + nexta = (nexta + 1) % MAXINDEXES; + + if (vflags & INP_IPV4) { + snprintf(bufip, sizeof(bufip), + "%d.%d.%d.%d", + (ntohl(depaddr->id46_addr.ia46_addr4.s_addr) >> 24) & + 255, + (ntohl(depaddr->id46_addr.ia46_addr4.s_addr) >> 16) & + 255, + (ntohl(depaddr->id46_addr.ia46_addr4.s_addr) >> 8) & + 255, + (ntohl(depaddr->id46_addr.ia46_addr4.s_addr) >> 0) & + 255); + snprintf(buf[nexta], sizeof(buf[nexta]), + "%15s:%-5d", bufip, port); + } else if (vflags & INP_IPV6) { + snprintf(bufip, sizeof(bufip), + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", + ntohs(depaddr->id6_addr.s6_addr16[0]), + ntohs(depaddr->id6_addr.s6_addr16[1]), + ntohs(depaddr->id6_addr.s6_addr16[2]), + ntohs(depaddr->id6_addr.s6_addr16[3]), + ntohs(depaddr->id6_addr.s6_addr16[4]), + ntohs(depaddr->id6_addr.s6_addr16[5]), + ntohs(depaddr->id6_addr.s6_addr16[6]), + ntohs(depaddr->id6_addr.s6_addr16[7])); + snprintf(buf[nexta], sizeof(buf[nexta]), + "%39s:%-5d", bufip, port); + } else { + snprintf(bufip, sizeof(bufip), "<unknown>"); + snprintf(buf[nexta], sizeof(buf[nexta]), + "%15s:%-5d", bufip, port); + } + return (buf[nexta]); +} + +static void +updatepcb(struct xtcpcb *xtcp) +{ + struct mytcpcb dummy; + struct mytcpcb *elm; + + dummy.xtcp = *xtcp; + if ((elm = RB_FIND(mytcpcb_tree, &mytcp_tree, &dummy)) == NULL) { + elm = malloc(sizeof(*elm)); + bzero(elm, sizeof(*elm)); + elm->xtcp = *xtcp; + elm->last_xtcp = *xtcp; + RB_INSERT(mytcpcb_tree, &mytcp_tree, elm); + } else { + elm->last_xtcp = elm->xtcp; + elm->xtcp = *xtcp; + } + elm->seq = tcp_pcb_seq; +} diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 index 5fc3257..0ab1738 100644 --- a/usr.bin/systat/systat.1 +++ b/usr.bin/systat/systat.1 @@ -94,6 +94,7 @@ to be one of: .Ic iostat , .Ic ip , .Ic ip6 , +.Ic netbw , .Ic netstat , .Ic pigs , .Ic swap , @@ -441,6 +442,9 @@ Display statistics averaged over the refresh interval (the default). .It Cm zero Reset running statistics to zero. .El +.It Ic netbw +Display aggregate and per-connection TCP receive and transmit rates. +Only active TCP connections are shown. .It Ic netstat Display, in the lower window, network connections. By default, -- 1.8.5.4
_______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"