Use kvm_counter_u64_fetch() to fix obtaining ipstat and tcpstat from

kernel core files.

Sponsored by:	Nginx, Inc.
This commit is contained in:
Gleb Smirnoff 2013-04-10 20:29:23 +00:00
parent 2a2134043c
commit 29dde48df4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=249345
3 changed files with 69 additions and 29 deletions

View File

@ -603,8 +603,13 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
warn("sysctl: net.inet.tcp.stats");
return;
}
} else
kread(off, &tcpstat, len);
} else {
u_long tcpstat_p[sizeof(struct tcpstat)/sizeof(uint64_t)];
kread(off, &tcpstat_p, sizeof(tcpstat_p));
kread_counters(tcpstat_p, (uint64_t *)&tcpstat,
sizeof(struct tcpstat)/sizeof(uint64_t));
}
printf ("%s:\n", name);
@ -858,8 +863,13 @@ ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
warn("sysctl: net.inet.ip.stats");
return;
}
} else
kread(off, &ipstat, len);
} else {
u_long ipstat_p[sizeof(struct ipstat)/sizeof(uint64_t)];
kread(off, &ipstat_p, sizeof(ipstat_p));
kread_counters(ipstat_p, (uint64_t *)&ipstat,
sizeof(struct ipstat)/sizeof(uint64_t));
}
printf("%s:\n", name);

View File

@ -147,11 +147,11 @@ static struct nlist nl[] = {
#define N_IPCOMPSTAT 37
{ .n_name = "_ipcompstat" },
#define N_TCPSTAT 38
{ .n_name = "_tcpstat" },
{ .n_name = "_tcpstatp" },
#define N_UDPSTAT 39
{ .n_name = "_udpstat" },
#define N_IPSTAT 40
{ .n_name = "_ipstat" },
{ .n_name = "_ipstatp" },
#define N_ICMPSTAT 41
{ .n_name = "_icmpstat" },
#define N_IGMPSTAT 42
@ -696,37 +696,50 @@ printproto(struct protox *tp, const char *name)
(*pr)(off, name, af, tp->pr_protocol);
}
static int
kvmd_init(void)
{
char errbuf[_POSIX2_LINE_MAX];
if (kvmd != NULL)
return (0);
kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
setgid(getgid());
if (kvmd == NULL) {
warnx("kvm not available: %s", errbuf);
return (-1);
}
if (kvm_nlist(kvmd, nl) < 0) {
if (nlistf)
errx(1, "%s: kvm_nlist: %s", nlistf,
kvm_geterr(kvmd));
else
errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
}
if (nl[0].n_type == 0) {
if (nlistf)
errx(1, "%s: no namelist", nlistf);
else
errx(1, "no namelist");
}
return (0);
}
/*
* Read kernel memory, return 0 on success.
*/
int
kread(u_long addr, void *buf, size_t size)
{
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)
errx(1, "%s: kvm_nlist: %s", nlistf,
kvm_geterr(kvmd));
else
errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
}
if (kvmd_init() < 0)
return (-1);
if (nl[0].n_type == 0) {
if (nlistf)
errx(1, "%s: no namelist", nlistf);
else
errx(1, "no namelist");
}
} else {
warnx("kvm not available: %s", errbuf);
return(-1);
}
}
if (!buf)
return (0);
if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
@ -736,6 +749,22 @@ kread(u_long addr, void *buf, size_t size)
return (0);
}
/*
* Read an array of N counters in kernel memory into array of N uint64_t's.
*/
int
kread_counters(u_long *addr, uint64_t *rval, size_t count)
{
if (kvmd_init() < 0)
return (-1);
for (u_int i = 0; i < count; i++, addr++, rval++)
*rval = kvm_counter_u64_fetch(kvmd, *addr);
return (0);
}
const char *
plural(uintmax_t n)
{

View File

@ -60,6 +60,7 @@ extern int af; /* address family */
extern int live; /* true if we are examining a live system */
int kread(u_long addr, void *buf, size_t size);
int kread_counters(u_long *addr, uint64_t *rval, size_t count);
const char *plural(uintmax_t);
const char *plurales(uintmax_t);
const char *pluralies(uintmax_t);