PERFORCE change 185431 for review

Aman Jassal aman at FreeBSD.org
Sat Nov 6 11:51:26 UTC 2010


http://p4web.freebsd.org/@@185431?ac=10

Change 185431 by aman at src on 2010/11/06 11:50:50

	After quite some time, adding some sysctl support for the routing tables in libnetstat.
	The support is still in somewhat experimental state though : it cannot export masks associated
	to a subnet because of kernel page faults and the size of struct rttable_perfib_header should
	be reviewed as well to make sure it is a power of 2.
	
	Submitted by:	aman	
	Reviewed by:	pgj	

Affected files ...

.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_internal.h#69 edit
.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_route.c#9 edit
.. //depot/projects/soc2009/pgj_libstat/src/sys/net/route.h#6 edit
.. //depot/projects/soc2009/pgj_libstat/src/sys/net/rtsock.c#7 edit
.. //depot/projects/soc2009/pgj_libstat/src/usr.bin/netstat/main.c#50 edit

Differences ...

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_internal.h#69 (text+ko) ====

@@ -682,6 +682,8 @@
 struct netisr_work *_netstat_nw_allocate(struct netisr_work_list *);
 
 struct routeaddr_type *extract_address(void *, void *, int);
+struct routeaddr_type *extract_saddress(void *, void *, int);
+
 const char  *resolve_val2str_name(int, const struct val2str *);
 /* XXX: merge these into a common address resolution routine. */
 const char	*routename(in_addr_t in, int numeric);

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_route.c#9 (text+ko) ====

@@ -33,10 +33,12 @@
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_var.h>
+#include <net/route.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
 #include <err.h>
+#include <errno.h>
 #include <kvm.h>
 #include <nlist.h>
 #include <stdio.h>
@@ -64,6 +66,7 @@
 static void process_tree(kvm_t *, struct route_type_list *,
 	    struct radix_node *, int, int);
 static void extract_rtentry_data(struct rtentry *, struct route_type *);
+static void extract_srtentry_data(struct rttable_perfib_data *, struct route_type *, int);
 static void extract_node(struct radix_node *, struct routenode_type *, int);
 
 int
@@ -307,11 +310,76 @@
 
 int
 route_tree_sysctl(struct route_type_list *list, __unused int fib,
-    __unused int domain, __unused int flags)
+    int domain, __unused int flags)
 {
-	/* XXX: unsupported */
-	list->rtl_error = NETSTAT_ERROR_UNSUPPORTED;
-	return (-1);
+	/*
+	 * AJ : Adding sysctl routing tables support, after
+	 *	quite some time...
+	 */
+	char *mibvar_rttables;
+	char *buffer_rtdata, *p;
+	size_t rtdata_len;
+	struct rttable_stream_header *rshp;
+	struct rttable_perfib_header *rphp;
+	struct rttable_perfib_data *rpdp;
+	struct route_type *rtp;
+	uint32_t i, j;
+
+	if (domain == AF_INET)
+		mibvar_rttables = "net.route.inet_dump";
+	else if (domain == AF_INET6)
+		mibvar_rttables = "net.route.inet6_dump";
+	else
+		mibvar_rttables = NULL;
+
+	if (sysctlbyname(mibvar_rttables, 0, &rtdata_len, 0, 0) < 0) {
+		if (errno != ENOENT)
+			warn("sysctl: mibvar estimate");
+		goto end;
+	}
+	if ((buffer_rtdata = malloc(rtdata_len)) == 0) {
+		warnx("malloc %lu bytes", (u_long)rtdata_len);
+		goto end;
+	}
+	if (sysctlbyname(mibvar_rttables, buffer_rtdata, &rtdata_len, 0, 0) < 0) {
+		warn("sysctl: mibvar retrieval");
+		goto out_rtdata;
+	}
+	if (rtdata_len < sizeof(*rshp)) {
+		list->rtl_error = NETSTAT_ERROR_VERSION;
+		goto out_rtdata;
+	}
+
+	p = buffer_rtdata;
+	rshp = (struct rttable_stream_header *)p;
+	p += sizeof(*rshp);
+
+	if (rshp->rsh_version != RTTABLE_STREAM_VERSION) {
+		list->rtl_error = NETSTAT_ERROR_VERSION;
+		goto out_rtdata;
+	}
+
+	for (i = 0; i < rshp->rsh_count; i++) {
+		/*
+		 * Decapsulate per-fib header.
+		 */
+		rphp = (struct rttable_perfib_header *)p;
+		p += sizeof(*rphp);
+
+		for (j = 0; j < rphp->rph_count; j++) {
+			rpdp = (struct rttable_perfib_data *)p;
+			p += sizeof(*rpdp);
+
+			rtp = _netstat_rt_allocate(list);
+			extract_srtentry_data(rpdp, rtp, domain);
+		}
+
+	}
+
+out_rtdata:
+	free(buffer_rtdata);
+end:
+	return (0);
 }
 
 #define CNV_FLAG(X, Y)			\
@@ -363,10 +431,64 @@
 		}
 	}
 	rtp->rt_mtu = rte->rt_rmx.rmx_mtu;
-	rtp->rt_fib = rte->rt_fibnum;
+}
+#undef CNV_FLAG
+
+#define CNV_FLAG(X, Y)			\
+	if (rpdp->rpd_flags & (X))	\
+		rpdp->rpd_flags |= (Y)
+
+void
+extract_srtentry_data(struct rttable_perfib_data *rpdp, struct route_type *rtp, int domain)
+{
+	time_t expire_time;
+	struct timespec	uptime;
+	struct sockaddr_storage *sa, *mk;
+
+	CNV_FLAG(RTF_UP, NETSTAT_RT_UP);
+	CNV_FLAG(RTF_GATEWAY, NETSTAT_RT_GATEWAY);
+	CNV_FLAG(RTF_HOST, NETSTAT_RT_HOST);
+	CNV_FLAG(RTF_REJECT, NETSTAT_RT_REJECT);
+	CNV_FLAG(RTF_DYNAMIC, NETSTAT_RT_DYNAMIC);
+	CNV_FLAG(RTF_MODIFIED, NETSTAT_RT_MODIFIED);
+	CNV_FLAG(RTF_DONE, NETSTAT_RT_DONE);
+	CNV_FLAG(RTF_XRESOLVE, NETSTAT_RT_XRESOLVE);
+	CNV_FLAG(RTF_LLINFO, NETSTAT_RT_LLINFO);
+	CNV_FLAG(RTF_STATIC, NETSTAT_RT_STATIC);
+	CNV_FLAG(RTF_PROTO1, NETSTAT_RT_PROTO1);
+	CNV_FLAG(RTF_PROTO2, NETSTAT_RT_PROTO2);
+	CNV_FLAG(RTF_PROTO3, NETSTAT_RT_PROTO3);
+	CNV_FLAG(RTF_BLACKHOLE, NETSTAT_RT_BLACKHOLE);
+	CNV_FLAG(RTF_BROADCAST, NETSTAT_RT_BROADCAST);
+
+	rtp->rt_fib = rpdp->rpd_fib;
+	rtp->rt_family = (rpdp->rpd_dst).ss_family;
+	sa = &rpdp->rpd_dst;
+	mk = &rpdp->rpd_mask;
+	rtp->rt_destination = extract_saddress(sa, mk, rpdp->rpd_flags);
+	sa = &rpdp->rpd_gw;
+	rtp->rt_gateway = extract_saddress(sa, NULL, RTF_HOST);
+	rtp->rt_refs = rpdp->rpd_refs;
+	rtp->rt_used = rpdp->rpd_used;
+	if (rpdp->rpd_interface_name != NULL)
+		rtp->rt_interface = strdup(rpdp->rpd_interface_name);
+	else
+		rtp->rt_interface = strdup("---");
+	if (rpdp->rpd_expire > 0) {
+		if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) {
+			warn("netstat_route: clock_gettime() failed");
+		}
+		expire_time = rpdp->rpd_expire - uptime.tv_sec;
+		if (expire_time > 0) {
+			rtp->rt_flags |= NETSTAT_RT_EXPIRES;
+			rtp->rt_expire = expire_time;
+		}
+	}
+	rtp->rt_mtu = rpdp->rpd_mtu;
 }
 #undef CNV_FLAG
 
+
 struct routeaddr_type *
 extract_address(void *saddr, void *maddr, int flags)
 {
@@ -523,6 +645,163 @@
 	return (rap);
 }
 
+
+struct routeaddr_type *
+extract_saddress(void *saddr, void *maddr, int flags)
+{
+	struct routeaddr_type *rap;
+	struct sockaddr	*sa, *mask;
+	struct sockaddr_in  *sa_in, *mk_in;
+#ifdef INET6
+	struct sockaddr_in6 *sa_in6, *mk_in6;
+	struct in6_addr *in6;
+#endif
+	struct sockaddr_dl  *sa_dl;
+	char *cp, *cq, *cqlim, *p;
+	int n;
+	char workbuf[128];
+	u_char *s, *slim;
+
+	if (saddr == NULL)
+		return (NULL);
+
+	sa = (struct sockaddr *)saddr;
+	mask = (struct sockaddr *)maddr;
+	sa_in = (struct sockaddr_in *)sa;
+	mk_in = (struct sockaddr_in *)mask;
+#ifdef INET6
+	sa_in6 = (struct sockaddr_in6 *)sa;
+	in6 = &sa_in6->sin6_addr;
+	mk_in6 = (struct sockaddr_in6 *)mask;
+#endif
+	sa_dl = (struct sockaddr_dl *)sa;
+
+	rap = _netstat_rat_allocate(sa->sa_family, sa, sizeof(struct sockaddr));
+	if (rap == NULL)
+		return (NULL);
+
+	switch (sa->sa_family) {
+	case PF_INET:
+		if ((sa_in->sin_addr.s_addr == INADDR_ANY) &&
+		    (mask != NULL) &&
+		    (ntohl(mk_in->sin_addr.s_addr) == 0L)) {
+			rap->rat_address = strdup("default");
+			strlcpy(rap->rat_ni_address, "default",
+			    sizeof(rap->rat_ni_address));
+		} else if (flags & RTF_HOST) {
+			inet_ntop(PF_INET, &sa_in->sin_addr,
+			    rap->rat_ni_address, sizeof(rap->rat_ni_address));
+			rap->rat_address =
+			    strdup(routename(sa_in->sin_addr.s_addr, 0));
+		} else if (mask != NULL) {
+			strlcpy(rap->rat_ni_address,
+			    netname(sa_in->sin_addr.s_addr,
+				ntohl(mk_in->sin_addr.s_addr), 1),
+			    sizeof(rap->rat_ni_address));
+			rap->rat_address =
+			    strdup(netname(sa_in->sin_addr.s_addr,
+				ntohl(mk_in->sin_addr.s_addr), 0));
+		} else {
+			rap->rat_address =
+			    strdup(netname(sa_in->sin_addr.s_addr,
+				0L, 0));
+			strlcpy(rap->rat_ni_address, rap->rat_address,
+			    sizeof(rap->rat_ni_address));
+		}
+		rap->rat_data = malloc(sizeof(struct sockaddr_in));
+		if (rap->rat_data != NULL) {
+			rap->rat_data_len = sizeof(struct sockaddr_in);
+			memcpy(rap->rat_data, sa_in, rap->rat_data_len);
+		}
+		break;
+#ifdef INET6
+	case PF_INET6:
+		/*
+		 * XXX: This is a special workaround for KAME kernels.
+		 * sin6_scope_id field of SA should be set in the future.
+		 */
+		if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+		    IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+			sa_in6->sin6_scope_id =
+			    (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+			*(u_short *)&in6->s6_addr[2] = 0;
+		}
+		if (flags & RTF_HOST) {
+			rap->rat_address = strdup(routename6(sa_in6, 0));
+			strlcpy(rap->rat_ni_address, routename6(sa_in6, 1),
+			    sizeof(rap->rat_ni_address));
+		}
+		else if (mask != NULL) {
+			rap->rat_address = strdup(netname6(sa_in6,
+			    &mk_in6->sin6_addr, 0));
+			strlcpy(rap->rat_ni_address,
+			    netname6(sa_in6, &mk_in6->sin6_addr, 1),
+			    sizeof(rap->rat_ni_address));
+		} else {
+			rap->rat_address = strdup(netname6(sa_in6, 0L, 0));
+			strlcpy(rap->rat_ni_address, rap->rat_address,
+			    sizeof(rap->rat_ni_address));
+		}
+		rap->rat_data = malloc(sizeof(struct sockaddr_in6));
+		if (rap->rat_data != NULL) {
+			rap->rat_data_len = sizeof(struct sockaddr_in6);
+			memcpy(rap->rat_data, sa_in6, rap->rat_data_len);
+		}
+		break;
+#endif
+	case PF_IPX:
+		break;
+	case PF_APPLETALK:
+		break;
+	case PF_NETGRAPH:
+		break;
+	case PF_LINK:
+		if (sa_dl->sdl_nlen == 0 && sa_dl->sdl_alen == 0 &&
+		    sa_dl->sdl_slen == 0) {
+			sprintf(rap->rat_ni_address, "<Link#%d>",
+			    sa_dl->sdl_index);
+		} else {
+			cp = (char *)LLADDR(sa_dl);
+			n = sa_dl->sdl_alen;
+			p = rap->rat_address;
+			while (--n >= 0) {
+				sprintf(p, "%02x%s", *cp++ & 0xff,
+				    n > 0 ? ":" : "");
+				p += 3;
+			}
+		}
+		rap->rat_address = strdup(rap->rat_ni_address);
+		rap->rat_data = malloc(sizeof(struct sockaddr_dl));
+		if (rap->rat_data != NULL) {
+			rap->rat_data_len = sizeof(struct sockaddr_dl);
+			memcpy(rap->rat_data, sa_dl, rap->rat_data_len);
+		}
+		break;
+	default:
+		s = (u_char *)sa->sa_data;
+		cq = workbuf;
+		slim = sa->sa_len + (u_char *)sa;
+		cqlim = cq + sizeof(workbuf) - 6;
+		cq += sprintf(cq, "(%d)", sa->sa_family);
+		while (s < slim && cq < cqlim) {
+			cq += sprintf(cq, " %02x", *s++);
+			if (s < slim)
+				cq += sprintf(cq, "%02x", *s++);
+		}
+		rap->rat_address = strdup(workbuf);
+		strlcpy(rap->rat_ni_address, workbuf,
+		    sizeof(rap->rat_ni_address));
+		rap->rat_data = malloc(sizeof(struct sockaddr));
+		if (rap->rat_data != NULL) {
+			rap->rat_data_len = sizeof(struct sockaddr);
+			memcpy(rap->rat_data, sa, rap->rat_data_len);
+		}
+		break;
+	}
+
+	return (rap);
+}
+
 void
 extract_node(struct radix_node *rn, struct routenode_type *rnp, int mkcnt)
 {

==== //depot/projects/soc2009/pgj_libstat/src/sys/net/route.h#6 (text+ko) ====

@@ -309,6 +309,46 @@
 };
 
 /*
+ * Statistics structures to be used by user space monitoring tools.
+ */
+#define RID_MAX_NAME		16
+#define RTTABLE_STREAM_VERSION	0x00000001
+
+struct rttable_stream_header {
+	uint32_t	rsh_version;	/* Stream format version */
+	uint32_t	rsh_count;	/* Number of fibs */
+	uint32_t	rsh_family;	/* Address family */
+	uint32_t	_rsh_pad;	/* Padding/Reserved field for future use. */
+};
+
+struct rttable_perfib_header {
+	uint32_t	rph_fib;	/* Fib instance */
+	uint32_t	rph_count;	/* Number of nodes for the given fib */
+	uint32_t	_rph_pad[2];	/* Padding/Reserved field for future use. */
+};
+
+struct rttable_perfib_data {
+	/*
+	 * Struct sockaddr_storage to store the sockets' information.
+	 */
+	struct sockaddr_storage	rpd_dst; // Destination subnet
+	struct sockaddr_storage rpd_mask; // Destination subnet's netmask
+	struct sockaddr_storage rpd_gw; // Gateway
+	
+	/*
+	 * Remaining struct rtentry fields
+	 */
+	uint32_t	rpd_fib;
+	uint32_t	rpd_flags;
+	uint64_t	rpd_refs;
+	uint64_t	rpd_used;
+	char		rpd_interface_name[RID_MAX_NAME];
+	uint64_t	rpd_expire;
+	uint32_t	rpd_mtu;
+	uint8_t		_rpid_pad[16];
+};
+
+/*
  * This macro returns the size of a struct sockaddr when passed
  * through a routing socket. Basically we round up sa_len to
  * a multiple of sizeof(long), with a minimum of sizeof(long).

==== //depot/projects/soc2009/pgj_libstat/src/sys/net/rtsock.c#7 (text+ko) ====

@@ -46,6 +46,7 @@
 #include <sys/proc.h>
 #include <sys/protosw.h>
 #include <sys/rwlock.h>
+#include <sys/sbuf.h>
 #include <sys/signalvar.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
@@ -1666,6 +1667,211 @@
 
 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
 
+static int
+sysctl_export_rttable(SYSCTL_HANDLER_ARGS)
+{
+	int af, buflen, error, fib_instance, rt_entry_counter_total, i;
+	int rt_entry_counter[RT_NUMFIBS];
+	char *buffer;
+	struct sbuf sbuf;
+	struct rttable_stream_header rsh;
+	struct rttable_perfib_header rph;
+	struct rttable_perfib_data rpd;
+	struct radix_node_head *rt_table = NULL;
+	struct radix_node *base, *next;
+	register struct radix_node *rn;
+	struct rtentry *rtp;
+
+	for (i = 0; i < RT_NUMFIBS; i++)
+		rt_entry_counter[i] = 0;
+	rt_entry_counter_total = 0;
+	error = 0;
+	buflen = 0;
+
+	switch ((intptr_t)arg1) {
+	case AF_INET:
+		af = AF_INET;
+		break;
+	case AF_INET6:
+		af = AF_INET6;
+		break;
+	default:
+		error = EAFNOSUPPORT;
+		return(0);
+	}
+
+	for (fib_instance = 0; fib_instance < RT_NUMFIBS; fib_instance++) {
+
+		rt_table = rt_tables_get_rnh(fib_instance, af);
+
+		RADIX_NODE_HEAD_RLOCK(rt_table);
+		rn = rt_table->rnh_treetop;
+
+		while (rn->rn_bit >= 0)
+			rn = rn->rn_left;
+		for (;;) {
+			base = rn;
+			/* If at right child go back up, otherwise, go right */
+			while (rn->rn_parent->rn_right == rn
+				&& (rn->rn_flags & RNF_ROOT) == 0)
+				rn = rn->rn_parent;
+
+			/* Find the next *leaf* since next node might vanish, too */
+			for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+				rn = rn->rn_left;
+			next = rn;
+			
+			/* Process leaves */
+			while ((rn = base)) {
+				base = rn->rn_dupedkey;
+				if (!(rn->rn_flags & RNF_ROOT)) {
+					rt_entry_counter[fib_instance]++;
+					rt_entry_counter_total++;
+				}
+			}
+
+			rn = next;
+			if (rn->rn_flags & RNF_ROOT)
+				break;
+		}
+
+		RADIX_NODE_HEAD_RUNLOCK(rt_table);
+	}
+
+	buflen = sizeof(rsh) + RT_NUMFIBS * sizeof(rph) + rt_entry_counter_total * sizeof(rpd) + 1;
+	buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
+
+	sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN);
+
+	/*
+	 * Insert stream header.
+	 */
+	bzero(&rsh, sizeof(rsh));
+	rsh.rsh_version = RTTABLE_STREAM_VERSION;
+	rsh.rsh_count = RT_NUMFIBS;
+	rsh.rsh_family = af;
+
+	if (sbuf_bcat(&sbuf, &rsh, sizeof(rsh)) < 0) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	for (fib_instance = 0; fib_instance < RT_NUMFIBS; fib_instance++) {
+
+		i = 0;
+		rt_table = rt_tables_get_rnh(fib_instance, af);
+
+		/*
+		 * Insert headers per-fib.
+		 * The second header indicates the number of routing
+		 * entries in the routing table, the counting was performed
+		 * earlier in rt_entry_counter.
+		 */
+		bzero(&rph, sizeof(rph));
+		rph.rph_fib = fib_instance;
+		rph.rph_count = rt_entry_counter[fib_instance];
+
+		if (sbuf_bcat(&sbuf, &rph, sizeof(rph)) < 0) {
+			error = ENOMEM;
+			goto out;
+		}
+
+		/*
+		 * AJ : The radix tree is protected by a rwlock.
+		 *	Since we only need to go through the
+		 *	radix tree and read all the nodes, holding
+		 *	the rwlock in read mode should be enough.
+		 *
+		 *	Here, we fill all the rttable_perfib_data
+		 *	structures and build up the data stream.
+		 *	If we reach the maximum number of entries
+		 *	initially allocated, we stop processing the
+		 *	radix tree and go on to the next one.
+		 *	The aim here is to make a quick snapshot of
+		 *	the routing table.
+		 */
+		RADIX_NODE_HEAD_RLOCK(rt_table);
+		rn = rt_table->rnh_treetop;
+
+		while (rn->rn_bit >= 0)
+			rn = rn->rn_left;
+		
+		for (;;) {
+			base = rn;
+			/* If at right child go back up, otherwise, go right */
+			while (rn->rn_parent->rn_right == rn
+				&& (rn->rn_flags & RNF_ROOT) == 0)
+				rn = rn->rn_parent;
+
+			/* Find the next *leaf* since next node might vanish, too */
+			for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+				rn = rn->rn_left;
+			next = rn;
+			
+			/* Process leaves */
+			while ((rn = base)) {
+				base = rn->rn_dupedkey;
+				if (!(rn->rn_flags & RNF_ROOT)) {
+					rtp = (struct rtentry *)rn;
+
+					rpd.rpd_fib = rtp->rt_fibnum;
+					rpd.rpd_flags = rtp->rt_flags;
+					rpd.rpd_refs = rtp->rt_refcnt;
+					rpd.rpd_used = rtp->rt_rmx.rmx_pksent;
+					bcopy(rtp->rt_ifp->if_xname, rpd.rpd_interface_name, RID_MAX_NAME);
+					rpd.rpd_expire = rtp->rt_rmx.rmx_expire;
+					rpd.rpd_mtu = rtp->rt_rmx.rmx_mtu;
+
+					rpd.rpd_dst = *((struct sockaddr_storage *)rt_key(rtp));
+					rpd.rpd_gw = *((struct sockaddr_storage *)rtp->rt_gateway);
+					
+					/*
+					 * AJ : For some reason, calling rt_mask() ALWAYS ends up
+					 *	in a kernel page fault, this is seriously irritating
+					 *	because without the netmask, handling the subnet
+					 *	is meaningless.
+					 */
+					//rpd.rpd_mask = *((struct sockaddr_storage *)rt_mask(rtp));
+
+					if (sbuf_bcat(&sbuf, &rpd, sizeof(rpd)) < 0) {
+						RADIX_NODE_HEAD_RUNLOCK(rt_table);
+						error = ENOMEM;
+						goto out;
+					}
+
+					if (af == AF_INET && i < rph.rph_count)
+						i++;
+					else if (af == AF_INET6 && i < rph.rph_count)
+						i++;
+					else
+						goto rt_out;
+				}
+			}
+
+			rn = next;
+			if (rn->rn_flags & RNF_ROOT)
+				break;
+		}
+rt_out:
+		RADIX_NODE_HEAD_RUNLOCK(rt_table);
+	}
+
+	sbuf_finish(&sbuf);
+	error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
+out:
+	sbuf_delete(&sbuf);
+	free(buffer, M_TEMP);
+	return(error);
+}
+
+SYSCTL_PROC(_net_route, OID_AUTO, inet_dump, CTLFLAG_RD|CTLTYPE_STRUCT,
+	(caddr_t)(long)AF_INET, 0, sysctl_export_rttable, "s, struct rttable_perfib_header",
+	"Inet Routing Tables (stream)");
+
+SYSCTL_PROC(_net_route, OID_AUTO, inet6_dump, CTLFLAG_RD|CTLTYPE_STRUCT,
+	(caddr_t)(long)AF_INET6, 0, sysctl_export_rttable, "s, struct rttable_perfib_header",
+	"Inet6 Routing Tables (stream)");
+
 /*
  * Definitions of protocols supported in the ROUTE domain.
  */

==== //depot/projects/soc2009/pgj_libstat/src/usr.bin/netstat/main.c#50 (text+ko) ====

@@ -477,7 +477,8 @@
 			netstat_session_free(session);
 		}
 		else {
-			kread(0, NULL, 0);
+			if (!live)
+				kread(0, NULL, 0);
 			session = netstat_session_new(kvmd);
 			routepr(session, af);
 			netstat_session_free(session);


More information about the p4-projects mailing list