Restore netstat -M functionality for most statistics on core dumps. In

general, when support was added to netstat for fetching data using sysctl,
no provision was left for fetching equivalent data from a core dump, and
in fact, netstat would _always_ fetch data from the live kernel using
sysctl even when -M was specified resulting in the user believing they
were getting data from coredumps when they actually weren't.  Some specific
changes:
- Add a global 'live' variable that is true if netstat is running against
  the live kernel and false if -M has been specified.
- Stop abusing the sysctl flag in the protocol tables to hold the protocol
  number.  Instead, the protocol is now its own field in the tables, and
  it is passed as a separate parameter to the PCB and stat routines rather
  than overloading the KVM offset parameter.
- Don't run PCB or stats functions who don't have a namelist offset if we
  are being run against a crash dump (!live).
- For the inet and unix PCB routines, we generate the same buffer from KVM
  that the sysctl usually generates complete with the header and trailer.
- Don't run bpf stats for !live (before it would just silently always run
  live).
- kread() no longer trashes memory when opening the buffer if there is an
  error on open and the passed in buffer is smaller than _POSIX2_LINE_MAX.
- The multicast routing code doesn't fallback to kvm on live kernels if
  the sysctl fails.  Keeping this made the code rather hairy, and netstat
  is already tied to the kernel ABI anyway (even when using sysctl's since
  things like xinpcb contain an inpcb) so any kernels this is run against
  that have the multicast routing stuff should have the sysctls.
- Don't try to dig around in the kernel linker in the netgraph PCB routine
  for core dumps.

Other notes:
- sctp's PCB routine only works on live kernels, it looked rather
  complicated to generate all the same stuff via KVM.  Someone can always
  add it later if desired though.
- Fix the ipsec removal bug where N_xxx for IPSEC stats weren't renumbered.
- Use sysctlbyname() everywhere rather than hardcoded mib values.

MFC after:	1 week
Approved by:	re (rwatson)
This commit is contained in:
John Baldwin 2007-07-16 17:15:55 +00:00
parent 72d7331539
commit feda1a4372
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171465
18 changed files with 750 additions and 366 deletions

View File

@ -217,7 +217,8 @@ atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what)
}
void
atalkprotopr(u_long off __unused, const char *name, int af1 __unused)
atalkprotopr(u_long off __unused, const char *name, int af1 __unused,
int proto __unused)
{
struct ddpcb *this, *next;
@ -266,7 +267,8 @@ atalkprotopr(u_long off __unused, const char *name, int af1 __unused)
* Dump DDP statistics structure.
*/
void
ddp_stats(u_long off __unused, const char *name, int af1 __unused)
ddp_stats(u_long off __unused, const char *name, int af1 __unused,
int proto __unused)
{
struct ddpstat ddpstat;

View File

@ -28,6 +28,7 @@
#include <sys/types.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#include <sys/user.h>

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/time.h>
@ -85,19 +86,22 @@ static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
* Dump pfsync statistics structure.
*/
void
pfsync_stats(u_long off __unused, const char *name, int af1 __unused)
pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct pfsyncstats pfsyncstat, zerostat;
size_t len = sizeof(struct pfsyncstats);
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.pfsync.stats", &pfsyncstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.pfsync.stats");
return;
}
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.pfsync.stats", &pfsyncstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.pfsync.stats");
return;
}
} else
kread(off, &pfsyncstat, len);
printf("%s:\n", name);

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/domain.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
@ -90,6 +91,208 @@ void inetprint (struct in_addr *, int, const char *, int);
static int udp_done, tcp_done;
#endif /* INET6 */
static int
pcblist_sysctl(int proto, char **bufp, int istcp)
{
const char *mibvar;
char *buf;
size_t len;
switch (proto) {
case IPPROTO_TCP:
mibvar = "net.inet.tcp.pcblist";
break;
case IPPROTO_UDP:
mibvar = "net.inet.udp.pcblist";
break;
case IPPROTO_DIVERT:
mibvar = "net.inet.divert.pcblist";
break;
default:
mibvar = "net.inet.raw.pcblist";
break;
}
len = 0;
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: %s", mibvar);
return (0);
}
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
return (0);
}
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
warn("sysctl: %s", mibvar);
free(buf);
return (0);
}
*bufp = buf;
return (1);
}
/*
* Copied directly from uipc_socket2.c. We leave out some fields that are in
* nested structures that aren't used to avoid extra work.
*/
static void
sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
{
xsb->sb_cc = sb->sb_cc;
xsb->sb_hiwat = sb->sb_hiwat;
xsb->sb_mbcnt = sb->sb_mbcnt;
xsb->sb_mbmax = sb->sb_mbmax;
xsb->sb_lowat = sb->sb_lowat;
xsb->sb_flags = sb->sb_flags;
xsb->sb_timeo = sb->sb_timeo;
}
int
sotoxsocket(struct socket *so, struct xsocket *xso)
{
struct protosw proto;
struct domain domain;
bzero(xso, sizeof *xso);
xso->xso_len = sizeof *xso;
xso->xso_so = so;
xso->so_type = so->so_type;
xso->so_options = so->so_options;
xso->so_linger = so->so_linger;
xso->so_state = so->so_state;
xso->so_pcb = so->so_pcb;
if (kread((uintptr_t)so->so_proto, &proto, sizeof(proto)) != 0)
return (-1);
xso->xso_protocol = proto.pr_protocol;
if (kread((uintptr_t)proto.pr_domain, &domain, sizeof(domain)) != 0)
return (-1);
xso->xso_family = domain.dom_family;
xso->so_qlen = so->so_qlen;
xso->so_incqlen = so->so_incqlen;
xso->so_qlimit = so->so_qlimit;
xso->so_timeo = so->so_timeo;
xso->so_error = so->so_error;
xso->so_oobmark = so->so_oobmark;
sbtoxsockbuf(&so->so_snd, &xso->so_snd);
sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
return (0);
}
static int
pcblist_kvm(u_long off, char **bufp, int istcp)
{
struct inpcbinfo pcbinfo;
struct inpcbhead listhead;
struct inpcb *inp;
struct xinpcb xi;
struct xinpgen xig;
struct xtcpcb xt;
struct socket so;
struct xsocket *xso;
char *buf, *p;
size_t len;
if (off == 0)
return (0);
kread(off, &pcbinfo, sizeof(pcbinfo));
if (istcp)
len = 2 * sizeof(xig) +
(pcbinfo.ipi_count + pcbinfo.ipi_count / 8) *
sizeof(struct xtcpcb);
else
len = 2 * sizeof(xig) +
(pcbinfo.ipi_count + pcbinfo.ipi_count / 8) *
sizeof(struct xinpcb);
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
return (0);
}
p = buf;
#define COPYOUT(obj, size) do { \
if (len < (size)) { \
warnx("buffer size exceeded"); \
goto fail; \
} \
bcopy((obj), p, (size)); \
len -= (size); \
p += (size); \
} while (0)
#define KREAD(off, buf, len) do { \
if (kread((uintptr_t)(off), (buf), (len)) != 0) \
goto fail; \
} while (0)
/* Write out header. */
xig.xig_len = sizeof xig;
xig.xig_count = pcbinfo.ipi_count;
xig.xig_gen = pcbinfo.ipi_gencnt;
xig.xig_sogen = 0;
COPYOUT(&xig, sizeof xig);
/* Walk the PCB list. */
xt.xt_len = sizeof xt;
xi.xi_len = sizeof xi;
if (istcp)
xso = &xt.xt_socket;
else
xso = &xi.xi_socket;
KREAD(pcbinfo.ipi_listhead, &listhead, sizeof(listhead));
LIST_FOREACH(inp, &listhead, inp_list) {
if (istcp) {
KREAD(inp, &xt.xt_inp, sizeof(*inp));
inp = &xt.xt_inp;
} else {
KREAD(inp, &xi.xi_inp, sizeof(*inp));
inp = &xi.xi_inp;
}
if (inp->inp_gencnt > pcbinfo.ipi_gencnt)
continue;
if (istcp) {
if (inp->inp_ppcb == NULL)
bzero(&xt.xt_tp, sizeof xt.xt_tp);
else if (inp->inp_vflag & INP_TIMEWAIT) {
bzero(&xt.xt_tp, sizeof xt.xt_tp);
xt.xt_tp.t_state = TCPS_TIME_WAIT;
} else
KREAD(inp->inp_ppcb, &xt.xt_tp,
sizeof xt.xt_tp);
}
if (inp->inp_socket) {
KREAD(inp->inp_socket, &so, sizeof(so));
if (sotoxsocket(&so, xso) != 0)
goto fail;
} else {
bzero(xso, sizeof(*xso));
if (istcp)
xso->xso_protocol = IPPROTO_TCP;
}
if (istcp)
COPYOUT(&xt, sizeof xt);
else
COPYOUT(&xi, sizeof xi);
}
/* Reread the pcbinfo and write out the footer. */
kread(off, &pcbinfo, sizeof(pcbinfo));
xig.xig_count = pcbinfo.ipi_count;
xig.xig_gen = pcbinfo.ipi_gencnt;
COPYOUT(&xig, sizeof xig);
*bufp = buf;
return (1);
fail:
free(buf);
return (0);
#undef COPYOUT
#undef KREAD
}
/*
* Print a summary of connections related to an Internet
* protocol. For TCP, also give state of connection.
@ -97,18 +300,16 @@ static int udp_done, tcp_done;
* -a (all) flag is specified.
*/
void
protopr(u_long proto, /* for sysctl version we pass proto # */
const char *name, int af1)
protopr(u_long off, const char *name, int af1, int proto)
{
int istcp;
static int first = 1;
char *buf;
const char *mibvar, *vchar;
const char *vchar;
struct tcpcb *tp = NULL;
struct inpcb *inp;
struct xinpgen *xig, *oxig;
struct xsocket *so;
size_t len;
istcp = 0;
switch (proto) {
@ -120,7 +321,6 @@ protopr(u_long proto, /* for sysctl version we pass proto # */
tcp_done = 1;
#endif
istcp = 1;
mibvar = "net.inet.tcp.pcblist";
break;
case IPPROTO_UDP:
#ifdef INET6
@ -129,29 +329,14 @@ protopr(u_long proto, /* for sysctl version we pass proto # */
else
udp_done = 1;
#endif
mibvar = "net.inet.udp.pcblist";
break;
case IPPROTO_DIVERT:
mibvar = "net.inet.divert.pcblist";
break;
default:
mibvar = "net.inet.raw.pcblist";
break;
}
len = 0;
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: %s", mibvar);
return;
}
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
return;
}
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
warn("sysctl: %s", mibvar);
free(buf);
return;
if (live) {
if (!pcblist_sysctl(proto, &buf, istcp))
return;
} else {
if (!pcblist_kvm(off, &buf, istcp))
return;
}
oxig = xig = (struct xinpgen *)buf;
@ -168,7 +353,7 @@ protopr(u_long proto, /* for sysctl version we pass proto # */
}
/* Ignore sockets for protocols other than the desired one. */
if (so->xso_protocol != (int)proto)
if (so->xso_protocol != proto)
continue;
/* Ignore PCBs which were freed during copyout. */
@ -347,18 +532,10 @@ protopr(u_long proto, /* for sysctl version we pass proto # */
* Dump TCP statistics structure.
*/
void
tcp_stats(u_long off __unused, const char *name, int af1 __unused)
tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct tcpstat tcpstat, zerostat;
size_t len = sizeof tcpstat;
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.tcp.stats");
return;
}
#ifdef INET6
if (tcp_done != 0)
@ -367,6 +544,17 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused)
tcp_done = 1;
#endif
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.tcp.stats");
return;
}
} else
kread(off, &tcpstat, len);
printf ("%s:\n", name);
#define p(f, m) if (tcpstat.f || sflag <= 1) \
@ -480,20 +668,12 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused)
* Dump UDP statistics structure.
*/
void
udp_stats(u_long off __unused, const char *name, int af1 __unused)
udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct udpstat udpstat, zerostat;
size_t len = sizeof udpstat;
u_long delivered;
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.udp.stats");
return;
}
#ifdef INET6
if (udp_done != 0)
return;
@ -501,6 +681,17 @@ udp_stats(u_long off __unused, const char *name, int af1 __unused)
udp_done = 1;
#endif
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.udp.stats");
return;
}
} else
kread(off, &udpstat, len);
printf("%s:\n", name);
#define p(f, m) if (udpstat.f || sflag <= 1) \
printf(m, udpstat.f, plural(udpstat.f))
@ -537,18 +728,24 @@ udp_stats(u_long off __unused, const char *name, int af1 __unused)
* Dump CARP statistics structure.
*/
void
carp_stats(u_long off __unused, const char *name, int af1 __unused)
carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct carpstats carpstat, zerostat;
size_t len = sizeof(struct carpstats);
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.carp.stats");
return;
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.carp.stats");
return;
}
} else {
if (off == 0)
return;
kread(off, &carpstat, len);
}
printf("%s:\n", name);
@ -582,18 +779,21 @@ carp_stats(u_long off __unused, const char *name, int af1 __unused)
* Dump IP statistics structure.
*/
void
ip_stats(u_long off __unused, const char *name, int af1 __unused)
ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct ipstat ipstat, zerostat;
size_t len = sizeof ipstat;
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.ip.stats", &ipstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.ip.stats");
return;
}
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.ip.stats", &ipstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.ip.stats");
return;
}
} else
kread(off, &ipstat, len);
printf("%s:\n", name);
@ -687,26 +887,23 @@ static const char *icmpnames[ICMP_MAXTYPE + 1] = {
* Dump ICMP statistics.
*/
void
icmp_stats(u_long off __unused, const char *name, int af1 __unused)
icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct icmpstat icmpstat, zerostat;
int i, first;
int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
size_t len;
mib[0] = CTL_NET;
mib[1] = PF_INET;
mib[2] = IPPROTO_ICMP;
mib[3] = ICMPCTL_STATS;
len = sizeof icmpstat;
if (zflag)
memset(&zerostat, 0, len);
if (sysctl(mib, 4, &icmpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.icmp.stats");
return;
}
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.icmp.stats");
return;
}
} else
kread(off, &icmpstat, len);
printf("%s:\n", name);
@ -758,30 +955,35 @@ icmp_stats(u_long off __unused, const char *name, int af1 __unused)
#undef p
#undef p1a
#undef p2
mib[3] = ICMPCTL_MASKREPL;
len = sizeof i;
if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
return;
printf("\tICMP address mask responses are %sabled\n",
i ? "en" : "dis");
if (live) {
len = sizeof i;
if (sysctlbyname("net.inet.icmp.maskrepl", &i, &len, NULL, 0) <
0)
return;
printf("\tICMP address mask responses are %sabled\n",
i ? "en" : "dis");
}
}
/*
* Dump IGMP statistics structure.
*/
void
igmp_stats(u_long off __unused, const char *name, int af1 __unused)
igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct igmpstat igmpstat, zerostat;
size_t len = sizeof igmpstat;
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.igmp.stats");
return;
}
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.igmp.stats");
return;
}
} else
kread(off, &igmpstat, len);
printf("%s:\n", name);
@ -806,18 +1008,25 @@ igmp_stats(u_long off __unused, const char *name, int af1 __unused)
* Dump PIM statistics structure.
*/
void
pim_stats(u_long off __unused, const char *name, int af1 __unused)
pim_stats(u_long off __unused, const char *name, int af1 __unused,
int proto __unused)
{
struct pimstat pimstat, zerostat;
size_t len = sizeof pimstat;
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.pim.stats");
return;
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet.pim.stats");
return;
}
} else {
if (off == 0)
return;
kread(off, &pimstat, len);
}
printf("%s:\n", name);

View File

@ -362,22 +362,24 @@ static char *srcrule_str[] = {
* Dump IP6 statistics structure.
*/
void
ip6_stats(u_long off __unused, const char *name, int af1 __unused)
ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct ip6stat ip6stat;
int first, i;
int mib[4];
size_t len;
mib[0] = CTL_NET;
mib[1] = PF_INET6;
mib[2] = IPPROTO_IPV6;
mib[3] = IPV6CTL_STATS;
len = sizeof ip6stat;
memset(&ip6stat, 0, len);
if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0)
return;
if (live) {
memset(&ip6stat, 0, len);
if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, NULL,
0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet6.ip6.stats");
return;
}
} else
kread(off, &ip6stat, len);
printf("%s:\n", name);
#define p(f, m) if (ip6stat.f || sflag <= 1) \
@ -842,22 +844,24 @@ static const char *icmp6names[] = {
* Dump ICMP6 statistics.
*/
void
icmp6_stats(u_long off __unused, const char *name, int af1 __unused)
icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct icmp6stat icmp6stat;
int i, first;
int mib[4];
size_t len;
mib[0] = CTL_NET;
mib[1] = PF_INET6;
mib[2] = IPPROTO_ICMPV6;
mib[3] = ICMPV6CTL_STATS;
len = sizeof icmp6stat;
memset(&icmp6stat, 0, len);
if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0)
return;
if (live) {
memset(&icmp6stat, 0, len);
if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
NULL, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet6.icmp6.stats");
return;
}
} else
kread(off, &icmp6stat, len);
printf("%s:\n", name);
#define p(f, m) if (icmp6stat.f || sflag <= 1) \
@ -994,20 +998,26 @@ icmp6_ifstats(char *ifname)
* Dump PIM statistics structure.
*/
void
pim6_stats(u_long off __unused, const char *name, int af1 __unused)
pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct pim6stat pim6stat, zerostat;
size_t len = sizeof pim6stat;
/* TODO put back the KVM functionality for -M switch ie coredumps. */
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet6.pim.stats");
return;
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet6.pim.stats");
return;
}
} else {
if (off == 0)
return;
kread(off, &pim6stat, len);
}
printf("%s:\n", name);
#define p(f, m) if (pim6stat.f || sflag <= 1) \
@ -1026,24 +1036,22 @@ pim6_stats(u_long off __unused, const char *name, int af1 __unused)
* Dump raw ip6 statistics structure.
*/
void
rip6_stats(u_long off __unused, const char *name, int af1 __unused)
rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct rip6stat rip6stat;
u_quad_t delivered;
int mib[4];
size_t l;
size_t len;
mib[0] = CTL_NET;
mib[1] = PF_INET6;
mib[2] = IPPROTO_IPV6;
mib[3] = IPV6CTL_RIP6STATS;
l = sizeof(rip6stat);
if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) {
/* Just shut up if the kernel doesn't have ipv6. */
if (errno != ENOENT)
perror("Warning: sysctl(net.inet6.ip6.rip6stats)");
return;
}
len = sizeof(rip6stat);
if (live) {
if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
NULL, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: net.inet6.ip6.rip6stats");
return;
}
} else
kread(off, &rip6stat, len);
printf("%s:\n", name);

View File

@ -101,6 +101,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
@ -267,7 +268,7 @@ print_ipsecstats(const struct ipsecstat *ipsecstat)
}
void
ipsec_stats(u_long off, const char *name, int af1 __unused)
ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct ipsecstat ipsecstat;
@ -355,7 +356,7 @@ print_ahstats(const struct ahstat *ahstat)
}
void
ah_stats(u_long off, const char *name, int family __unused)
ah_stats(u_long off, const char *name, int family __unused, int proto __unused)
{
struct ahstat ahstat;
@ -405,7 +406,7 @@ print_espstats(const struct espstat *espstat)
}
void
esp_stats(u_long off, const char *name, int family __unused)
esp_stats(u_long off, const char *name, int family __unused, int proto __unused)
{
struct espstat espstat;
@ -450,7 +451,8 @@ print_ipcompstats(const struct ipcompstat *ipcompstat)
}
void
ipcomp_stats(u_long off, const char *name, int family __unused)
ipcomp_stats(u_long off, const char *name, int family __unused,
int proto __unused)
{
struct ipcompstat ipcompstat;

View File

@ -82,7 +82,7 @@ extern char *tcpstates[];
*/
void
ipxprotopr(u_long off, const char *name, int af1 __unused)
ipxprotopr(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct ipxpcbhead cb;
struct ipxpcb *ipxp;
@ -155,7 +155,7 @@ ipxprotopr(u_long off, const char *name, int af1 __unused)
* Dump SPX statistics structure.
*/
void
spx_stats(u_long off, const char *name, int af1 __unused)
spx_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct spx_istat spx_istat;
#define spxstat spx_istat.newstats
@ -231,7 +231,7 @@ spx_stats(u_long off, const char *name, int af1 __unused)
* Dump IPX statistics structure.
*/
void
ipx_stats(u_long off, const char *name, int af1 __unused)
ipx_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct ipxstat ipxstat;
@ -274,7 +274,7 @@ static struct {
*/
/*ARGSUSED*/
void
ipxerr_stats(u_long off, const char *name, int af __unused)
ipxerr_stats(u_long off, const char *name, int af __unused, int proto __unused)
{
struct ipx_errstat ipx_errstat;
int j;

View File

@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/file.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
@ -141,121 +142,154 @@ static struct nlist nl[] = {
{ .n_name = "_carpstats" },
#define N_PFSYNCSTAT 34
{ .n_name = "_pfsyncstats" },
#define N_AHSTAT 36
#define N_AHSTAT 35
{ .n_name = "_ahstat" },
#define N_ESPSTAT 37
#define N_ESPSTAT 36
{ .n_name = "_espstat" },
#define N_IPCOMPSTAT 38
#define N_IPCOMPSTAT 37
{ .n_name = "_ipcompstat" },
#define N_TCPSTAT 38
{ .n_name = "_tcpstat" },
#define N_UDPSTAT 39
{ .n_name = "_udpstat" },
#define N_IPSTAT 40
{ .n_name = "_ipstat" },
#define N_ICMPSTAT 41
{ .n_name = "_icmpstat" },
#define N_IGMPSTAT 42
{ .n_name = "_igmpstat" },
#define N_PIMSTAT 43
{ .n_name = "_pimstat" },
#define N_TCBINFO 44
{ .n_name = "_tcbinfo" },
#define N_UDBINFO 45
{ .n_name = "_udbinfo" },
#define N_DIVCBINFO 46
{ .n_name = "_divcbinfo" },
#define N_RIPCBINFO 47
{ .n_name = "_ripcbinfo" },
#define N_UNP_COUNT 48
{ .n_name = "_unp_count" },
#define N_UNP_GENCNT 49
{ .n_name = "_unp_gencnt" },
#define N_UNP_DHEAD 50
{ .n_name = "_unp_dhead" },
#define N_UNP_SHEAD 51
{ .n_name = "_unp_shead" },
#define N_RIP6STAT 52
{ .n_name = "_rip6stat" },
#define N_SCTPSTAT 53
{ .n_name = "_sctpstat" },
{ .n_name = NULL },
};
struct protox {
u_char pr_index; /* index into nlist of cb head */
u_char pr_sindex; /* index into nlist of stat block */
int pr_index; /* index into nlist of cb head */
int pr_sindex; /* index into nlist of stat block */
u_char pr_wanted; /* 1 if wanted, 0 otherwise */
void (*pr_cblocks)(u_long, const char *, int);
void (*pr_cblocks)(u_long, const char *, int, int);
/* control blocks printing routine */
void (*pr_stats)(u_long, const char *, int);
void (*pr_stats)(u_long, const char *, int, int);
/* statistics printing routine */
void (*pr_istats)(char *); /* per/if statistics printing routine */
const char *pr_name; /* well-known name */
u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */
int pr_protocol;
} protox[] = {
{ -1, -1, 1, protopr,
tcp_stats, NULL, "tcp", IPPROTO_TCP },
{ -1, -1, 1, protopr,
udp_stats, NULL, "udp", IPPROTO_UDP },
{ N_TCBINFO, N_TCPSTAT, 1, protopr,
tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
{ N_UDBINFO, N_UDPSTAT, 1, protopr,
udp_stats, NULL, "udp", 1, IPPROTO_UDP },
#ifdef SCTP
{ -1, -1, 1, sctp_protopr,
sctp_stats, NULL, "sctp", IPPROTO_SCTP },
{ -1, N_SCTPSTAT, 1, sctp_protopr,
sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP },
#endif
{ -1, -1, 1, protopr,
NULL, NULL, "divert",IPPROTO_DIVERT },
{ -1, -1, 1, protopr,
ip_stats, NULL, "ip", IPPROTO_RAW },
{ -1, -1, 1, protopr,
icmp_stats, NULL, "icmp", IPPROTO_ICMP },
{ -1, -1, 1, protopr,
igmp_stats, NULL, "igmp", IPPROTO_IGMP },
{ N_DIVCBINFO, -1, 1, protopr,
NULL, NULL, "divert", 1, IPPROTO_DIVERT },
{ N_RIPCBINFO, N_IPSTAT, 1, protopr,
ip_stats, NULL, "ip", 1, IPPROTO_RAW },
{ N_RIPCBINFO, N_ICMPSTAT, 1, protopr,
icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP },
{ N_RIPCBINFO, N_IGMPSTAT, 1, protopr,
igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP },
#ifdef IPSEC
{ -1, N_IPSECSTAT, 1, NULL, /* keep as compat */
ipsec_stats, NULL, "ipsec", 0},
ipsec_stats, NULL, "ipsec", 0, 0},
{ -1, N_AHSTAT, 1, NULL,
ah_stats, NULL, "ah", 0},
ah_stats, NULL, "ah", 0, 0},
{ -1, N_ESPSTAT, 1, NULL,
esp_stats, NULL, "esp", 0},
esp_stats, NULL, "esp", 0, 0},
{ -1, N_IPCOMPSTAT, 1, NULL,
ipcomp_stats, NULL, "ipcomp", 0},
ipcomp_stats, NULL, "ipcomp", 0, 0},
#endif
{ -1, -1, 1, protopr,
pim_stats, NULL, "pim", IPPROTO_PIM },
{ -1, N_CARPSTAT, 1, 0,
carp_stats, NULL, "carp", 0},
{ -1, -1, 1, NULL,
pfsync_stats, NULL, "pfsync", 1},
{ N_RIPCBINFO, N_PIMSTAT, 1, protopr,
pim_stats, NULL, "pim", 1, IPPROTO_PIM },
{ -1, N_CARPSTAT, 1, NULL,
carp_stats, NULL, "carp", 1, 0 },
{ -1, N_PFSYNCSTAT, 1, NULL,
pfsync_stats, NULL, "pfsync", 1, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
NULL, NULL, NULL, 0, 0 }
};
#ifdef INET6
struct protox ip6protox[] = {
{ -1, -1, 1, protopr,
tcp_stats, NULL, "tcp", IPPROTO_TCP },
{ -1, -1, 1, protopr,
udp_stats, NULL, "udp", IPPROTO_UDP },
{ -1, N_IP6STAT, 1, protopr,
ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
{ -1, N_ICMP6STAT, 1, protopr,
icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
{ N_TCBINFO, N_TCPSTAT, 1, protopr,
tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
{ N_UDBINFO, N_UDPSTAT, 1, protopr,
udp_stats, NULL, "udp", 1, IPPROTO_UDP },
{ N_RIPCBINFO, N_IP6STAT, 1, protopr,
ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW },
{ N_RIPCBINFO, N_ICMP6STAT, 1, protopr,
icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 },
#ifdef IPSEC
{ -1, N_IPSEC6STAT, 1, NULL,
ipsec_stats, NULL, "ipsec6",0 },
ipsec_stats, NULL, "ipsec6", 0, 0 },
#endif
#ifdef notyet
{ -1, N_PIM6STAT, 1, NULL,
pim6_stats, NULL, "pim6", 0 },
pim6_stats, NULL, "pim6", 1, 0 },
#endif
{ -1, -1, 1, NULL,
rip6_stats, NULL, "rip6", 0 },
{ -1, N_RIP6STAT, 1, NULL,
rip6_stats, NULL, "rip6", 1, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
NULL, NULL, NULL, 0, 0 }
};
#endif /*INET6*/
#ifdef IPSEC
struct protox pfkeyprotox[] = {
{ -1, N_PFKEYSTAT, 1, NULL,
pfkey_stats, NULL, "pfkey", 0 },
pfkey_stats, NULL, "pfkey", 0, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
NULL, NULL, NULL, 0, 0 }
};
#endif
struct protox atalkprotox[] = {
{ N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
ddp_stats, NULL, "ddp", 0 },
ddp_stats, NULL, "ddp", 0, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
NULL, NULL, NULL, 0, 0 }
};
struct protox netgraphprotox[] = {
{ N_NGSOCKS, -1, 1, netgraphprotopr,
NULL, NULL, "ctrl", 0 },
NULL, NULL, "ctrl", 0, 0 },
{ N_NGSOCKS, -1, 1, netgraphprotopr,
NULL, NULL, "data", 0 },
NULL, NULL, "data", 0, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
NULL, NULL, NULL, 0, 0 }
};
#ifdef IPX
struct protox ipxprotox[] = {
{ N_IPX, N_IPXSTAT, 1, ipxprotopr,
ipx_stats, NULL, "ipx", 0 },
ipx_stats, NULL, "ipx", 0, 0 },
{ N_IPX, N_SPXSTAT, 1, ipxprotopr,
spx_stats, NULL, "spx", 0 },
spx_stats, NULL, "spx", 0, 0 },
{ -1, -1, 0, NULL,
NULL, NULL, 0, 0 }
NULL, NULL, 0, 0, 0 }
};
#endif
@ -305,6 +339,7 @@ char *interface; /* desired i/f for stats, or NULL for all i/fs */
int unit; /* unit number for above */
int af; /* address family */
int live; /* true if we are examining a live system */
int
main(int argc, char *argv[])
@ -453,16 +488,19 @@ main(int argc, char *argv[])
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
*/
if (nlistf != NULL || memf != NULL)
live = (nlistf == NULL && memf == NULL);
if (!live)
setgid(getgid());
if (Bflag) {
if (!live)
usage();
bpf_stats(interface);
exit(0);
}
if (mflag) {
if (memf != NULL) {
if (kread(0, 0, 0) == 0)
if (kread(0, NULL, 0) == 0)
mbpr(kvmd, nl[N_MBSTAT].n_value);
} else
mbpr(NULL, 0);
@ -482,13 +520,12 @@ main(int argc, char *argv[])
* used for the queries, which is slower.
*/
#endif
kread(0, NULL, 0);
if (iflag && !sflag) {
kread(0, 0, 0);
intpr(interval, nl[N_IFNET].n_value, NULL);
exit(0);
}
if (rflag) {
kread(0, 0, 0);
if (sflag)
rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value);
else
@ -496,7 +533,6 @@ main(int argc, char *argv[])
exit(0);
}
if (gflag) {
kread(0, 0, 0);
if (sflag) {
if (af == AF_INET || af == AF_UNSPEC)
mrt_stats(nl[N_MRTSTAT].n_value);
@ -518,7 +554,6 @@ main(int argc, char *argv[])
exit(0);
}
kread(0, 0, 0);
if (tp) {
printproto(tp, tp->pr_name);
exit(0);
@ -538,7 +573,6 @@ main(int argc, char *argv[])
#endif /*IPSEC*/
#ifdef IPX
if (af == AF_IPX || af == AF_UNSPEC) {
kread(0, 0, 0);
for (tp = ipxprotox; tp->pr_name; tp++)
printproto(tp, tp->pr_name);
}
@ -550,7 +584,8 @@ main(int argc, char *argv[])
for (tp = netgraphprotox; tp->pr_name; tp++)
printproto(tp, tp->pr_name);
if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
unixpr();
unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value);
exit(0);
}
@ -564,7 +599,7 @@ printproto(tp, name)
struct protox *tp;
const char *name;
{
void (*pr)(u_long, const char *, int);
void (*pr)(u_long, const char *, int, int);
u_long off;
if (sflag) {
@ -576,17 +611,24 @@ printproto(tp, name)
printf("%s: no per-interface stats routine\n",
tp->pr_name);
return;
}
else {
} else {
pr = tp->pr_stats;
if (!pr) {
if (pflag)
printf("%s: no stats routine\n",
tp->pr_name);
return;
}
off = tp->pr_usesysctl ? tp->pr_usesysctl
: nl[tp->pr_sindex].n_value;
}
if (tp->pr_usesysctl && live)
off = 0;
else if (tp->pr_sindex < 0) {
if (pflag)
printf(
"%s: stats routine doesn't work on cores\n",
tp->pr_name);
return;
} else
off = nl[tp->pr_sindex].n_value;
}
} else {
pr = tp->pr_cblocks;
@ -595,28 +637,36 @@ printproto(tp, name)
printf("%s: no PCB routine\n", tp->pr_name);
return;
}
off = tp->pr_usesysctl ? tp->pr_usesysctl
: nl[tp->pr_index].n_value;
if (tp->pr_usesysctl && live)
off = 0;
else if (tp->pr_index < 0) {
if (pflag)
printf(
"%s: PCB routine doesn't work on cores\n",
tp->pr_name);
return;
} else
off = nl[tp->pr_index].n_value;
}
if (pr != NULL && (off || af != AF_UNSPEC))
(*pr)(off, name, af);
if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
af != AF_UNSPEC))
(*pr)(off, name, af, tp->pr_protocol);
}
/*
* Read kernel memory, return 0 on success.
*/
int
kread(u_long addr, char *buf, int size)
kread(u_long addr, void *buf, size_t size)
{
if (kvmd == 0) {
/*
* XXX.
*/
kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
char errbuf[_POSIX2_LINE_MAX];
if (kvmd == NULL) {
kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
setgid(getgid());
if (kvmd != NULL) {
if (kvm_nlist(kvmd, nl) < 0) {
if(nlistf)
if (nlistf)
errx(1, "%s: kvm_nlist: %s", nlistf,
kvm_geterr(kvmd));
else
@ -624,20 +674,21 @@ kread(u_long addr, char *buf, int size)
}
if (nl[0].n_type == 0) {
if(nlistf)
if (nlistf)
errx(1, "%s: no namelist", nlistf);
else
errx(1, "no namelist");
}
} else {
warnx("kvm not available");
warnx("kvm not available: %s", errbuf);
return(-1);
}
}
if (!buf)
return (0);
if (kvm_read(kvmd, addr, buf, size) != size) {
if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
warnx("%s", kvm_geterr(kvmd));
abort();
return (-1);
}
return (0);

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <err.h>
@ -80,9 +81,8 @@ mbpr(void *kvmd, u_long mbaddr)
int nsfbufs, nsfbufspeak, nsfbufsused;
struct mbstat mbstat;
size_t mlen;
int error, live;
int error;
live = (kvmd == NULL);
mtlp = memstat_mtl_alloc();
if (mtlp == NULL) {
warn("memstat_mtl_alloc");

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <net/if_var.h>

View File

@ -84,32 +84,24 @@ mroutepr(u_long mfcaddr, u_long vifaddr)
size_t len;
len = sizeof(mfctable);
if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) {
warn("sysctl: net.inet.ip.mfctable");
if (mfcaddr == 0) {
printf("No IPv4 multicast forwarding configured in "
"the running system.\n");
if (live) {
if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.mfctable");
return;
}
/*
* XXX: Try KVM if the module is neither compiled nor loaded.
* The correct behaviour would be to always use KVM if
* the -M option is specified to netstat(1).
*/
} else
kread(mfcaddr, (char *)mfctable, sizeof(mfctable));
}
len = sizeof(viftable);
if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) {
warn("sysctl: net.inet.ip.viftable");
if (vifaddr == 0) {
printf("No IPv4 multicast forwarding configured in "
"the running system.\n");
if (live) {
if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.viftable");
return;
}
/* XXX KVM */
} else
kread(vifaddr, (char *)viftable, sizeof(viftable));
}
saved_numeric_addr = numeric_addr;
numeric_addr = 1;
@ -276,18 +268,15 @@ mrt_stats(u_long mstaddr)
struct mrtstat mrtstat;
size_t len = sizeof mrtstat;
if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet.ip.mrtstat");
/* Compatability with older kernels - candidate for removal */
if (mstaddr == 0) {
printf("No IPv4 multicast forwarding configured in "
"the running system.\n");
if (live) {
if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL,
0) < 0) {
warn("sysctl: net.inet.ip.mrtstat");
return;
}
/* XXX KVM */
} else
kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
}
printf("IPv4 multicast forwarding:\n");
#define p(f, m) if (mrtstat.f || sflag <= 1) \

View File

@ -116,16 +116,14 @@ mroute6pr(u_long mfcaddr, u_long mifaddr)
size_t len;
len = sizeof(mif6table);
if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mif6table");
if (mifaddr == 0) {
printf("No IPv6 multicast forwarding configured in "
"the running system.\n");
if (live) {
if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mif6table");
return;
}
} else
kread(mifaddr, (char *)mif6table, sizeof(mif6table));
}
saved_numeric_addr = numeric_addr;
numeric_addr = 1;
@ -161,21 +159,14 @@ mroute6pr(u_long mfcaddr, u_long mifaddr)
printf("\nIPv6 Multicast Interface Table is empty\n");
len = sizeof(mf6ctable);
if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mf6ctable");
if (mfcaddr == 0) {
printf("No IPv6 multicast forwarding configured in "
"the running system.\n");
if (live) {
if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mf6ctable");
return;
}
/*
* XXX: Try KVM if the module is neither compiled nor loaded.
* The correct behaviour would be to always use KVM if
* the -M option is specified to netstat(1).
*/
} else
kread(mfcaddr, (char *)mf6ctable, sizeof(mf6ctable));
}
banner_printed = 0;
@ -232,16 +223,15 @@ mrt6_stats(u_long mstaddr)
struct mrt6stat mrtstat;
size_t len = sizeof mrtstat;
if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mrt6stat");
if (mstaddr == 0) {
printf("No IPv6 multicast forwarding configured in the "
"running system.\n");
if (live) {
if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len,
NULL, 0) < 0) {
warn("sysctl: net.inet6.ip6.mrt6stat");
return;
}
} else
kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
}
printf("IPv6 multicast forwarding:\n");
#define p(f, m) if (mrtstat.f || sflag <= 1) \

View File

@ -62,7 +62,8 @@ static int first = 1;
static int csock = -1;
void
netgraphprotopr(u_long off, const char *name, int af1 __unused)
netgraphprotopr(u_long off, const char *name, int af1 __unused,
int proto __unused)
{
struct ngpcb *this, *next;
struct ngpcb ngpcb;
@ -81,6 +82,10 @@ netgraphprotopr(u_long off, const char *name, int af1 __unused)
struct kld_file_stat ks;
int fileid;
/* Can't do this for core dumps. */
if (!live)
return;
/* See if module is loaded */
if ((fileid = kldfind(modname)) < 0) {
if (debug)

View File

@ -59,39 +59,41 @@ extern char *interface; /* desired i/f for stats, or NULL for all i/fs */
extern int unit; /* unit number for above */
extern int af; /* address family */
extern int live; /* true if we are examining a live system */
int kread(u_long addr, char *buf, int size);
int kread(u_long addr, void *buf, size_t size);
const char *plural(uintmax_t);
const char *plurales(uintmax_t);
const char *pluralies(uintmax_t);
void protopr(u_long, const char *, int);
void tcp_stats(u_long, const char *, int);
void udp_stats(u_long, const char *, int);
int sotoxsocket(struct socket *, struct xsocket *);
void protopr(u_long, const char *, int, int);
void tcp_stats(u_long, const char *, int, int);
void udp_stats(u_long, const char *, int, int);
#ifdef SCTP
void sctp_protopr(u_long, const char *, int);
void sctp_stats(u_long, const char *, int);
void sctp_protopr(u_long, const char *, int, int);
void sctp_stats(u_long, const char *, int, int);
#endif
void ip_stats(u_long, const char *, int);
void icmp_stats(u_long, const char *, int);
void igmp_stats(u_long, const char *, int);
void pim_stats(u_long, const char *, int);
void carp_stats (u_long, const char *, int);
void pfsync_stats (u_long, const char *, int);
void ip_stats(u_long, const char *, int, int);
void icmp_stats(u_long, const char *, int, int);
void igmp_stats(u_long, const char *, int, int);
void pim_stats(u_long, const char *, int, int);
void carp_stats (u_long, const char *, int, int);
void pfsync_stats (u_long, const char *, int, int);
#ifdef IPSEC
void ipsec_stats(u_long, const char *, int);
void esp_stats (u_long, const char *, int);
void ah_stats (u_long, const char *, int);
void ipcomp_stats (u_long, const char *, int);
void ipsec_stats(u_long, const char *, int, int);
void esp_stats (u_long, const char *, int, int);
void ah_stats (u_long, const char *, int, int);
void ipcomp_stats (u_long, const char *, int, int);
#endif
#ifdef INET6
void ip6_stats(u_long, const char *, int);
void ip6_stats(u_long, const char *, int, int);
void ip6_ifstats(char *);
void icmp6_stats(u_long, const char *, int);
void icmp6_stats(u_long, const char *, int, int);
void icmp6_ifstats(char *);
void pim6_stats(u_long, const char *, int);
void rip6_stats(u_long, const char *, int);
void pim6_stats(u_long, const char *, int, int);
void rip6_stats(u_long, const char *, int, int);
void mroute6pr(u_long, u_long);
void mrt6_stats(u_long);
@ -103,7 +105,7 @@ void inet6print(struct in6_addr *, int, const char *, int);
#endif /*INET6*/
#ifdef IPSEC
void pfkey_stats(u_long, const char *, int);
void pfkey_stats(u_long, const char *, int, int);
#endif
void mbpr(void *, u_long);
@ -129,29 +131,29 @@ char *ipx_print(struct sockaddr *);
char *ns_print(struct sockaddr *);
void routepr(u_long);
void ipxprotopr(u_long, const char *, int);
void spx_stats(u_long, const char *, int);
void ipx_stats(u_long, const char *, int);
void ipxerr_stats(u_long, const char *, int);
void ipxprotopr(u_long, const char *, int, int);
void spx_stats(u_long, const char *, int, int);
void ipx_stats(u_long, const char *, int, int);
void ipxerr_stats(u_long, const char *, int, int);
void nsprotopr(u_long, const char *, int);
void spp_stats(u_long, const char *, int);
void idp_stats(u_long, const char *, int);
void nserr_stats(u_long, const char *, int);
void nsprotopr(u_long, const char *, int, int);
void spp_stats(u_long, const char *, int, int);
void idp_stats(u_long, const char *, int, int);
void nserr_stats(u_long, const char *, int, int);
void atalkprotopr(u_long, const char *, int);
void ddp_stats(u_long, const char *, int);
void atalkprotopr(u_long, const char *, int, int);
void ddp_stats(u_long, const char *, int, int);
void netgraphprotopr(u_long, const char *, int);
void netgraphprotopr(u_long, const char *, int, int);
void unixpr(void);
void unixpr(u_long, u_long, u_long, u_long);
void esis_stats(u_long, const char *, int);
void clnp_stats(u_long, const char *, int);
void cltp_stats(u_long, const char *, int);
void iso_protopr(u_long, const char *, int);
void esis_stats(u_long, const char *, int, int);
void clnp_stats(u_long, const char *, int, int);
void cltp_stats(u_long, const char *, int, int);
void iso_protopr(u_long, const char *, int, int);
void iso_protopr1(u_long, int);
void tp_protopr(u_long, const char *, int);
void tp_protopr(u_long, const char *, int, int);
void tp_inproto(u_long);
void tp_stats(caddr_t, caddr_t);

View File

@ -76,6 +76,7 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
@ -116,7 +117,8 @@ pfkey_msgtype_names(int x)
}
void
pfkey_stats(u_long off, const char *name, int family __unused)
pfkey_stats(u_long off, const char *name, int family __unused,
int proto __unused)
{
struct pfkeystat pfkeystat;
unsigned first, type;

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
#include <net/ethernet.h>

View File

@ -432,8 +432,8 @@ sctp_process_inpcb(struct xsctp_inpcb *xinpcb, const char *name,
* protocol.
*/
void
sctp_protopr(u_long proto,
const char *name, int af1)
sctp_protopr(u_long off __unused,
const char *name, int af1, int proto)
{
char *buf;
const char *mibvar = "net.inet.sctp.assoclist";
@ -511,18 +511,21 @@ sctp_statesprint(uint32_t state)
* Dump SCTP statistics structure.
*/
void
sctp_stats(u_long off __unused, const char *name, int af1 __unused)
sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
{
struct sctpstat sctpstat, zerostat;
size_t len = sizeof(sctpstat);
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.sctp.stats");
return;
}
if (live) {
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.sctp.stats");
return;
}
} else
kread(off, &sctpstat, len);
printf ("%s:\n", name);

View File

@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <kvm.h>
#include "netstat.h"
@ -69,35 +70,148 @@ static void unixdomainpr (struct xunpcb *, struct xsocket *);
static const char *const socktype[] =
{ "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
void
unixpr(void)
static int
pcblist_sysctl(int type, char **bufp)
{
char *buf;
int type;
size_t len;
char mibvar[sizeof "net.local.seqpacket.pcblist"];
sprintf(mibvar, "net.local.%s.pcblist", socktype[type]);
len = 0;
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: %s", mibvar);
return (-1);
}
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
return (-2);
}
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
warn("sysctl: %s", mibvar);
free(buf);
return (-2);
}
*bufp = buf;
return (0);
}
static int
pcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp)
{
struct unp_head head;
struct unpcb *unp, unp_conn;
u_char sun_len;
struct socket so;
struct xunpgen xug;
struct xunpcb xu;
unp_gen_t unp_gencnt;
u_int unp_count;
char *buf, *p;
size_t len;
if (count_off == 0 || gencnt_off == 0)
return (-2);
if (head_off == 0)
return (-1);
kread(count_off, &unp_count, sizeof(unp_count));
len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu);
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
return (-2);
}
p = buf;
#define COPYOUT(obj, size) do { \
if (len < (size)) { \
warnx("buffer size exceeded"); \
goto fail; \
} \
bcopy((obj), p, (size)); \
len -= (size); \
p += (size); \
} while (0)
#define KREAD(off, buf, len) do { \
if (kread((uintptr_t)(off), (buf), (len)) != 0) \
goto fail; \
} while (0)
/* Write out header. */
kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
xug.xug_len = sizeof xug;
xug.xug_count = unp_count;
xug.xug_gen = unp_gencnt;
xug.xug_sogen = 0;
COPYOUT(&xug, sizeof xug);
/* Walk the PCB list. */
xu.xu_len = sizeof xu;
KREAD(head_off, &head, sizeof(head));
LIST_FOREACH(unp, &head, unp_link) {
xu.xu_unpp = unp;
KREAD(unp, &xu.xu_unp, sizeof (*unp));
unp = &xu.xu_unp;
if (unp->unp_gencnt > unp_gencnt)
continue;
if (unp->unp_addr != NULL) {
KREAD(unp->unp_addr, &sun_len, sizeof(sun_len));
KREAD(unp->unp_addr, &xu.xu_addr, sun_len);
}
if (unp->unp_conn != NULL) {
KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn));
if (unp_conn.unp_addr != NULL) {
KREAD(unp_conn.unp_addr, &sun_len,
sizeof(sun_len));
KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len);
}
}
KREAD(unp->unp_socket, &so, sizeof(so));
if (sotoxsocket(&so, &xu.xu_socket) != 0)
goto fail;
COPYOUT(&xu, sizeof(xu));
}
/* Reread the counts and write the footer. */
kread(count_off, &unp_count, sizeof(unp_count));
kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
xug.xug_count = unp_count;
xug.xug_gen = unp_gencnt;
COPYOUT(&xug, sizeof xug);
*bufp = buf;
return (0);
fail:
free(buf);
return (-1);
#undef COPYOUT
#undef KREAD
}
void
unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off)
{
char *buf;
int ret, type;
struct xsocket *so;
struct xunpgen *xug, *oxug;
struct xunpcb *xunp;
char mibvar[sizeof "net.local.seqpacket.pcblist"];
for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
sprintf(mibvar, "net.local.%s.pcblist", socktype[type]);
len = 0;
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
if (errno != ENOENT)
warn("sysctl: %s", mibvar);
if (live)
ret = pcblist_sysctl(type, &buf);
else
ret = pcblist_kvm(count_off, gencnt_off,
type == SOCK_STREAM ? shead_off :
(type == SOCK_DGRAM ? dhead_off : 0), &buf);
if (ret == -1)
continue;
}
if ((buf = malloc(len)) == 0) {
warnx("malloc %lu bytes", (u_long)len);
if (ret < 0)
return;
}
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
warn("sysctl: %s", mibvar);
free(buf);
return;
}
oxug = xug = (struct xunpgen *)buf;
for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);