summaryrefslogtreecommitdiffstats
path: root/usr.bin/netstat
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2013-12-20 00:17:26 +0000
committermelifaro <melifaro@FreeBSD.org>2013-12-20 00:17:26 +0000
commit8bd5f6c17c9114783f5e62ffeb7b2dac564d3a30 (patch)
tree15128778b84a316461bc6ac0321ccfd38190f556 /usr.bin/netstat
parent5dab6f9ed3816204ff73fd075abfaba1ed5c7673 (diff)
downloadFreeBSD-src-8bd5f6c17c9114783f5e62ffeb7b2dac564d3a30.zip
FreeBSD-src-8bd5f6c17c9114783f5e62ffeb7b2dac564d3a30.tar.gz
Use more fine-grained kvm(3) symbol lookup: routing code retrieves only
necessary symbols needed per subsystem. Main kvm(3) init is now delayed as much as possbile. This finally fixes performance issues reported in kern/167204. Some non-working code (ng_socket.ko symbol addresses calculation) removed. Some global variables eliminated. PR: kern/167204 MFC after: 4 weeks
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r--usr.bin/netstat/if.c2
-rw-r--r--usr.bin/netstat/main.c51
-rw-r--r--usr.bin/netstat/mroute.c43
-rw-r--r--usr.bin/netstat/mroute6.c38
-rw-r--r--usr.bin/netstat/netgraph.c51
-rw-r--r--usr.bin/netstat/netstat.h18
-rw-r--r--usr.bin/netstat/route.c44
7 files changed, 150 insertions, 97 deletions
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 573a75d..4e98bad 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -223,7 +223,7 @@ next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family)
* Print a description of the network interfaces.
*/
void
-intpr(int interval, void (*pfunc)(char *))
+intpr(int interval, void (*pfunc)(char *), int af)
{
struct ifaddrs *ifap, *ifa;
struct ifmaddrs *ifmap, *ifma;
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 7426bbd..1c7bc00 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -319,7 +319,6 @@ int gflag; /* show group (multicast) routing or stats */
int hflag; /* show counters in human readable format */
int iflag; /* show interfaces */
int Lflag; /* show size of listen queues */
-int Mflag; /* read statistics from core */
int mflag; /* show memory stats */
int noutputs = 0; /* how much outputs before we exit */
int numeric_addr; /* show addresses numerically */
@@ -425,7 +424,6 @@ main(int argc, char *argv[])
Lflag = 1;
break;
case 'M':
- Mflag = 1;
memf = optarg;
break;
case 'm':
@@ -554,40 +552,40 @@ main(int argc, char *argv[])
* used for the queries, which is slower.
*/
#endif
- kread(0, NULL, 0);
if (iflag && !sflag) {
- intpr(interval, NULL);
+ intpr(interval, NULL, af);
exit(0);
}
if (rflag) {
if (sflag)
- rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value);
+ rt_stats();
else
- routepr(nl[N_RTREE].n_value, fib);
+ routepr(fib, af);
exit(0);
}
+
if (gflag) {
if (sflag) {
if (af == AF_INET || af == AF_UNSPEC)
- mrt_stats(nl[N_MRTSTAT].n_value);
+ mrt_stats();
#ifdef INET6
if (af == AF_INET6 || af == AF_UNSPEC)
- mrt6_stats(nl[N_MRT6STAT].n_value);
+ mrt6_stats();
#endif
} else {
if (af == AF_INET || af == AF_UNSPEC)
- mroutepr(nl[N_MFCHASHTBL].n_value,
- nl[N_MFCTABLESIZE].n_value,
- nl[N_VIFTABLE].n_value);
+ mroutepr();
#ifdef INET6
if (af == AF_INET6 || af == AF_UNSPEC)
- mroute6pr(nl[N_MF6CTABLE].n_value,
- nl[N_MIF6TABLE].n_value);
+ mroute6pr();
#endif
}
exit(0);
}
+ /* Load all necessary kvm symbols */
+ kresolve_list(nl);
+
if (tp) {
printproto(tp, tp->pr_name);
exit(0);
@@ -640,7 +638,7 @@ printproto(struct protox *tp, const char *name)
if (sflag) {
if (iflag) {
if (tp->pr_istats)
- intpr(interval, tp->pr_istats);
+ intpr(interval, tp->pr_istats, af);
else if (pflag)
printf("%s: no per-interface stats routine\n",
tp->pr_name);
@@ -703,7 +701,23 @@ kvmd_init(void)
return (-1);
}
- if (kvm_nlist(kvmd, nl) < 0) {
+ return (0);
+}
+
+/*
+ * Resolve symbol list, return 0 on success.
+ */
+int
+kresolve_list(struct nlist *_nl)
+{
+
+ if ((kvmd == NULL) && (kvmd_init() != 0))
+ return (-1);
+
+ if (_nl[0].n_type != 0)
+ return (0);
+
+ if (kvm_nlist(kvmd, _nl) < 0) {
if (nlistf)
errx(1, "%s: kvm_nlist: %s", nlistf,
kvm_geterr(kvmd));
@@ -711,13 +725,6 @@ kvmd_init(void)
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);
}
diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c
index 7cade4e..3766415 100644
--- a/usr.bin/netstat/mroute.c
+++ b/usr.bin/netstat/mroute.c
@@ -65,11 +65,26 @@ __FBSDID("$FreeBSD$");
#undef _KERNEL
#include <err.h>
+#include <nlist.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "netstat.h"
+/*
+ * kvm(3) bindings for every needed symbol
+ */
+static struct nlist mrl[] = {
+#define N_MRTSTAT 0
+ { .n_name = "_mrtstat" },
+#define N_MFCHASHTBL 1
+ { .n_name = "_mfchashtbl" },
+#define N_VIFTABLE 2
+ { .n_name = "_viftable" },
+#define N_MFCTABLESIZE 3
+ { .n_name = "_mfctablesize" },
+ { .n_name = NULL },
+};
static void print_bw_meter(struct bw_meter *, int *);
static void print_mfc(struct mfc *, int, int *);
@@ -193,11 +208,12 @@ print_mfc(struct mfc *m, int maxvif, int *banner_printed)
}
void
-mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl)
+mroutepr()
{
struct vif viftable[MAXVIFS];
struct vif *v;
struct mfc *m;
+ u_long pmfchashtbl, pmfctablesize, pviftbl;
int banner_printed;
int saved_numeric_addr;
size_t len;
@@ -221,6 +237,16 @@ mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl)
*/
maxvif = 0;
+ kresolve_list(mrl);
+ pmfchashtbl = mrl[N_MFCHASHTBL].n_value;
+ pmfctablesize = mrl[N_MFCTABLESIZE].n_value;
+ pviftbl = mrl[N_VIFTABLE].n_value;
+
+ if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) {
+ fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
+ return;
+ }
+
len = sizeof(viftable);
if (live) {
if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
@@ -338,15 +364,24 @@ mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl)
}
void
-mrt_stats(u_long mstaddr)
+mrt_stats()
{
struct mrtstat mrtstat;
- size_t len = sizeof mrtstat;
+ u_long mstaddr;
+ size_t len = sizeof(mrtstat);
+
+ kresolve_list(mrl);
+ mstaddr = mrl[N_MRTSTAT].n_value;
+
+ if (mstaddr == 0) {
+ fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
+ return;
+ }
if (live) {
if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL,
0) < 0) {
- warn("sysctl: net.inet.ip.mrtstat");
+ warn("sysctl: net.inet.ip.mrtstat failed.");
return;
}
} else
diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c
index c526d7c..ac31f5e 100644
--- a/usr.bin/netstat/mroute6.c
+++ b/usr.bin/netstat/mroute6.c
@@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <err.h>
+#include <nlist.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -95,17 +96,32 @@ __FBSDID("$FreeBSD$");
#include "netstat.h"
+/*
+ * kvm(3) bindings for every needed symbol
+ */
+static struct nlist mrl[] = {
+#define N_MF6CTABLE 0
+ { .n_name = "_mf6ctable" },
+#define N_MIF6TABLE 1
+ { .n_name = "_mif6table" },
+#define N_MRT6STAT 2
+ { .n_name = "_mrt6stat" },
+ { .n_name = NULL },
+};
+
+
#define WID_ORG (Wflag ? 39 : (numeric_addr ? 29 : 18)) /* width of origin column */
#define WID_GRP (Wflag ? 18 : (numeric_addr ? 16 : 18)) /* width of group column */
void
-mroute6pr(u_long mfcaddr, u_long mifaddr)
+mroute6pr()
{
struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
struct mif6 mif6table[MAXMIFS];
struct mf6c mfc;
struct rtdetq rte, *rtep;
struct mif6 *mifp;
+ u_long mfcaddr, mifaddr;
mifi_t mifi;
int i;
int banner_printed;
@@ -114,6 +130,15 @@ mroute6pr(u_long mfcaddr, u_long mifaddr)
long int waitings;
size_t len;
+ kresolve_list(mrl);
+ mfcaddr = mrl[N_MF6CTABLE].n_value;
+ mifaddr = mrl[N_MIF6TABLE].n_value;
+
+ if (mfcaddr == 0 || mifaddr == 0) {
+ fprintf(stderr, "No IPv6 MROUTING kernel support.\n");
+ return;
+ }
+
len = sizeof(mif6table);
if (live) {
if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len,
@@ -217,11 +242,20 @@ mroute6pr(u_long mfcaddr, u_long mifaddr)
}
void
-mrt6_stats(u_long mstaddr)
+mrt6_stats()
{
struct mrt6stat mrtstat;
+ u_long mstaddr;
size_t len = sizeof mrtstat;
+ kresolve_list(mrl);
+ mstaddr = mrl[N_MRT6STAT].n_value;
+
+ if (mstaddr == 0) {
+ fprintf(stderr, "No IPv6 MROUTING kernel support.\n");
+ return;
+ }
+
if (live) {
if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len,
NULL, 0) < 0) {
diff --git a/usr.bin/netstat/netgraph.c b/usr.bin/netstat/netgraph.c
index 3427dd3..95578af 100644
--- a/usr.bin/netstat/netgraph.c
+++ b/usr.bin/netstat/netgraph.c
@@ -72,53 +72,10 @@ netgraphprotopr(u_long off, const char *name, int af1 __unused,
/* If symbol not found, try looking in the KLD module */
if (off == 0) {
- const char *const modname = "ng_socket.ko";
-/* XXX We should get "mpath" from "sysctl kern.module_path" */
- const char *mpath[] = { "/", "/boot/", "/modules/", NULL };
- struct nlist sym[] = { { .n_name = "_ngsocklist" },
- { .n_name = NULL } };
- const char **pre;
- 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)
- warn("kldfind(%s)", modname);
- return;
- }
-
- /* Get module info */
- memset(&ks, 0, sizeof(ks));
- ks.version = sizeof(struct kld_file_stat);
- if (kldstat(fileid, &ks) < 0) {
- if (debug)
- warn("kldstat(%d)", fileid);
- return;
- }
-
- /* Get symbol table from module file */
- for (pre = mpath; *pre; pre++) {
- char path[MAXPATHLEN];
-
- snprintf(path, sizeof(path), "%s%s", *pre, modname);
- if (nlist(path, sym) == 0)
- break;
- }
-
- /* Did we find it? */
- if (sym[0].n_value == 0) {
- if (debug)
- warnx("%s not found", modname);
- return;
- }
-
- /* Symbol found at load address plus symbol offset */
- off = (u_long) ks.address + sym[0].n_value;
+ if (debug)
+ fprintf(stderr,
+ "Error reading symbols from ng_socket.ko");
+ return;
}
/* Get pointer to first socket */
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 804a29e..cf89933 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -40,7 +40,6 @@ extern int gflag; /* show group (multicast) routing or stats */
extern int hflag; /* show counters in human readable format */
extern int iflag; /* show interfaces */
extern int Lflag; /* show size of listen queues */
-extern int Mflag; /* read statistics from core */
extern int mflag; /* show memory stats */
extern int noutputs; /* how much outputs before we exit */
extern int numeric_addr; /* show addresses numerically */
@@ -57,11 +56,12 @@ extern int interval; /* repeat interval for i/f stats */
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 */
+struct nlist;
int kread(u_long addr, void *buf, size_t size);
int kread_counters(u_long addr, void *buf, size_t size);
+int kresolve_list(struct nlist *);
const char *plural(uintmax_t);
const char *plurales(uintmax_t);
const char *pluralies(uintmax_t);
@@ -98,8 +98,8 @@ void icmp6_stats(u_long, const char *, int, int);
void icmp6_ifstats(char *);
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);
+void mroute6pr(void);
+void mrt6_stats(void);
struct sockaddr_in6;
struct in6_addr;
@@ -120,11 +120,11 @@ void netisr_stats(void *);
void hostpr(u_long, u_long);
void impstats(u_long, u_long);
-void intpr(int, void (*)(char *));
+void intpr(int, void (*)(char *), int);
void pr_rthdr(int);
void pr_family(int);
-void rt_stats(u_long, u_long);
+void rt_stats(void);
char *ipx_pnet(struct sockaddr *);
char *ipx_phost(struct sockaddr *);
char *ns_phost(struct sockaddr *);
@@ -136,7 +136,7 @@ char *atalk_print(struct sockaddr *, int);
char *atalk_print2(struct sockaddr *, struct sockaddr *, int);
char *ipx_print(struct sockaddr *);
char *ns_print(struct sockaddr *);
-void routepr(u_long, int);
+void routepr(int, int);
void ipxprotopr(u_long, const char *, int, int);
void spx_stats(u_long, const char *, int, int);
@@ -166,6 +166,6 @@ void tp_protopr(u_long, const char *, int, int);
void tp_inproto(u_long);
void tp_stats(caddr_t, caddr_t);
-void mroutepr(u_long, u_long, u_long);
-void mrt_stats(u_long);
+void mroutepr(void);
+void mrt_stats(void);
void bpf_stats(char *);
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 31ef3c0..a5d2635 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <ifaddrs.h>
#include <libutil.h>
#include <netdb.h>
+#include <nlist.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -106,6 +107,19 @@ struct bits {
{ 0 , 0 }
};
+/*
+ * kvm(3) bindings for every needed symbol
+ */
+static struct nlist rl[] = {
+#define N_RTSTAT 0
+ { .n_name = "_rtstat" },
+#define N_RTREE 1
+ { .n_name = "_rt_tables"},
+#define N_RTTRASH 2
+ { .n_name = "_rttrash" },
+ { .n_name = NULL },
+};
+
typedef union {
long dummy; /* Helps align structure. */
struct sockaddr u_sa;
@@ -151,9 +165,10 @@ static void domask(char *, in_addr_t, u_long);
* Print routing tables.
*/
void
-routepr(u_long rtree, int fibnum)
+routepr(int fibnum, int af)
{
struct radix_node_head **rnhp, *rnh, head;
+ u_long rtree;
size_t intsize;
int fam, numfibs;
@@ -165,10 +180,6 @@ routepr(u_long rtree, int fibnum)
numfibs = 1;
if (fibnum < 0 || fibnum > numfibs - 1)
errx(EX_USAGE, "%d: invalid fib", fibnum);
- rt_tables = calloc(numfibs * (AF_MAX+1),
- sizeof(struct radix_node_head *));
- if (rt_tables == NULL)
- err(EX_OSERR, "memory allocation failed");
/*
* Since kernel & userland use different timebase
* (time_uptime vs time_second) and we are reading kernel memory
@@ -182,14 +193,20 @@ routepr(u_long rtree, int fibnum)
printf(" (fib: %d)", fibnum);
printf("\n");
- if (Aflag == 0 && Mflag == 0 && NewTree)
+ if (Aflag == 0 && live != 0 && NewTree)
ntreestuff(fibnum, af);
else {
- if (rtree == 0) {
+ kresolve_list(rl);
+ if ((rtree = rl[N_RTREE].n_value) == 0) {
printf("rt_tables: symbol not in namelist\n");
return;
}
+ rt_tables = calloc(numfibs * (AF_MAX + 1),
+ sizeof(struct radix_node_head *));
+ if (rt_tables == NULL)
+ err(EX_OSERR, "memory allocation failed");
+
if (kread((u_long)(rtree), (char *)(rt_tables), (numfibs *
(AF_MAX+1) * sizeof(struct radix_node_head *))) != 0)
return;
@@ -572,14 +589,14 @@ ntreestuff(int fibnum, int af)
mib[5] = 0;
mib[6] = fibnum;
if (sysctl(mib, 7, NULL, &needed, NULL, 0) < 0) {
- err(1, "sysctl: net.route.0.0.dump estimate");
+ err(1, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum);
}
if ((buf = malloc(needed)) == 0) {
errx(2, "malloc(%lu)", (unsigned long)needed);
}
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- err(1, "sysctl: net.route.0.0.dump");
+ err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum);
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
@@ -1071,16 +1088,19 @@ routename6(struct sockaddr_in6 *sa6)
* Print routing statistics
*/
void
-rt_stats(u_long rtsaddr, u_long rttaddr)
+rt_stats(void)
{
struct rtstat rtstat;
+ u_long rtsaddr, rttaddr;
int rttrash;
- if (rtsaddr == 0) {
+ kresolve_list(rl);
+
+ if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) {
printf("rtstat: symbol not in namelist\n");
return;
}
- if (rttaddr == 0) {
+ if ((rttaddr = rl[N_RTTRASH].n_value) == 0) {
printf("rttrash: symbol not in namelist\n");
return;
}
OpenPOWER on IntegriCloud