Hello,

I noticed that when doing a netstat -s (running on a kernel without SCTP support compiled in), I get the following message output to stderr:

netstat: sysctl: net.inet.sctp.stats: No such file or directory

Wondering why it would attempt to fetch SCTP stats when it was compiled out of the kernel, I noted that netstat could be compiled without SCTP support as well, but that there is no good way to link the two compilation conditions, or to have a generic binary that can run without error regardless of compiled kernel options.

To that end, I added a method to check for environment compatibility in netstat. For SCTP specifically, I used the FEATURE macros and added SCTP as a FEATURE.

Other protocols could also be configured to be checked at runtime if desired, though I haven't implemented any others at this time.

-- Sean



--- main.c@@/main/RELENG_8/RELENG_8_2/plt_ag_os/0	2011-10-21 11:35:33.000000000 -0400
+++ main.c	2011-10-24 14:30:13.000000000 -0400
@@ -198,106 +198,109 @@ struct protox {
 	void	(*pr_stats)(u_long, const char *, int, int);
 					/* statistics printing routine */
 	void	(*pr_istats)(char *);	/* per/if statistics printing routine */
+	int	(*feature_test)(void);	/* test routine to determine if kernel
+					   suppport exists for protocol */
 	const char	*pr_name;		/* well-known name */
 	int	pr_usesysctl;		/* non-zero if we use sysctl, not kvm */
 	int	pr_protocol;
 } protox[] = {
 	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
-	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
+	  tcp_stats,	NULL,		NULL,	"tcp",	1,	IPPROTO_TCP },
 	{ N_UDBINFO,	N_UDPSTAT,	1,	protopr,
-	  udp_stats,	NULL,		"udp",	1,	IPPROTO_UDP },
+	  udp_stats,	NULL,		NULL,	"udp",	1,	IPPROTO_UDP },
 #ifdef SCTP
 	{ -1,		N_SCTPSTAT,	1,	sctp_protopr,
-	  sctp_stats,	NULL,		"sctp",	1,	IPPROTO_SCTP },
+	  sctp_stats,	NULL,		sctp_feature_test,	"sctp",	1,
+	  IPPROTO_SCTP },
 #endif
 	{ N_DIVCBINFO,	-1,		1,	protopr,
-	  NULL,		NULL,		"divert", 1,	IPPROTO_DIVERT },
+	  NULL,		NULL,		NULL,	"divert", 1,	IPPROTO_DIVERT },
 	{ N_RIPCBINFO,	N_IPSTAT,	1,	protopr,
-	  ip_stats,	NULL,		"ip",	1,	IPPROTO_RAW },
+	  ip_stats,	NULL,		NULL,	"ip",	1,	IPPROTO_RAW },
 	{ N_RIPCBINFO,	N_ICMPSTAT,	1,	protopr,
-	  icmp_stats,	NULL,		"icmp",	1,	IPPROTO_ICMP },
+	  icmp_stats,	NULL,		NULL,	"icmp",	1,	IPPROTO_ICMP },
 	{ N_RIPCBINFO,	N_IGMPSTAT,	1,	protopr,
-	  igmp_stats,	NULL,		"igmp",	1,	IPPROTO_IGMP },
+	  igmp_stats,	NULL,		NULL,	"igmp",	1,	IPPROTO_IGMP },
 #ifdef IPSEC
 	{ -1,		N_IPSECSTAT,	1,	NULL,	/* keep as compat */
-	  ipsec_stats,	NULL,		"ipsec", 0,	0},
+	  ipsec_stats,	NULL,		NULL,	"ipsec", 0,	0},
 	{ -1,		N_AHSTAT,	1,	NULL,
-	  ah_stats,	NULL,		"ah",	0,	0},
+	  ah_stats,	NULL,		NULL,	"ah",	0,	0},
 	{ -1,		N_ESPSTAT,	1,	NULL,
-	  esp_stats,	NULL,		"esp",	0,	0},
+	  esp_stats,	NULL,		NULL,	"esp",	0,	0},
 	{ -1,		N_IPCOMPSTAT,	1,	NULL,
-	  ipcomp_stats,	NULL,		"ipcomp", 0,	0},
+	  ipcomp_stats,	NULL,		NULL,	"ipcomp", 0,	0},
 #endif
 	{ N_RIPCBINFO,	N_PIMSTAT,	1,	protopr,
-	  pim_stats,	NULL,		"pim",	1,	IPPROTO_PIM },
+	  pim_stats,	NULL,		NULL,	"pim",	1,	IPPROTO_PIM },
 	{ -1,		N_CARPSTAT,	1,	NULL,
-	  carp_stats,	NULL,		"carp",	1,	0 },
+	  carp_stats,	NULL,		NULL,	"carp",	1,	0 },
 	{ -1,		N_PFSYNCSTAT,	1,	NULL,
-	  pfsync_stats,	NULL,		"pfsync", 1,	0 },
+	  pfsync_stats,	NULL,		NULL,	"pfsync", 1,	0 },
 	{ -1,		N_ARPSTAT,	1,	NULL,
-	  arp_stats,	NULL,		"arp", 1,	0 },
+	  arp_stats,	NULL,		NULL,	"arp", 1,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		NULL,	0,	0 }
+	  NULL,		NULL,		NULL,	NULL,	0,	0 }
 };
 
 #ifdef INET6
 struct protox ip6protox[] = {
 	{ N_TCBINFO,	N_TCPSTAT,	1,	protopr,
-	  tcp_stats,	NULL,		"tcp",	1,	IPPROTO_TCP },
+	  tcp_stats,	NULL,		NULL,	"tcp",	1,	IPPROTO_TCP },
 	{ N_UDBINFO,	N_UDPSTAT,	1,	protopr,
-	  udp_stats,	NULL,		"udp",	1,	IPPROTO_UDP },
+	  udp_stats,	NULL,		NULL,	"udp",	1,	IPPROTO_UDP },
 	{ N_RIPCBINFO,	N_IP6STAT,	1,	protopr,
-	  ip6_stats,	ip6_ifstats,	"ip6",	1,	IPPROTO_RAW },
+	  ip6_stats,	ip6_ifstats,	NULL,	"ip6",	1,	IPPROTO_RAW },
 	{ N_RIPCBINFO,	N_ICMP6STAT,	1,	protopr,
-	  icmp6_stats,	icmp6_ifstats,	"icmp6", 1,	IPPROTO_ICMPV6 },
+	  icmp6_stats,	icmp6_ifstats,	NULL,	"icmp6", 1,	IPPROTO_ICMPV6 },
 #ifdef IPSEC
 	{ -1,		N_IPSEC6STAT,	1,	NULL,
-	  ipsec_stats,	NULL,		"ipsec6", 0,	0 },
+	  ipsec_stats,	NULL,		NULL,	"ipsec6", 0,	0 },
 #endif
 #ifdef notyet
 	{ -1,		N_PIM6STAT,	1,	NULL,
-	  pim6_stats,	NULL,		"pim6",	1,	0 },
+	  pim6_stats,	NULL,		NULL,	"pim6",	1,	0 },
 #endif
 	{ -1,		N_RIP6STAT,	1,	NULL,
-	  rip6_stats,	NULL,		"rip6",	1,	0 },
+	  rip6_stats,	NULL,		NULL,	"rip6",	1,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		NULL,	0,	0 }
+	  NULL,		NULL,		NULL,	NULL,	0,	0 }
 };
 #endif /*INET6*/
 
 #ifdef IPSEC
 struct protox pfkeyprotox[] = {
 	{ -1,		N_PFKEYSTAT,	1,	NULL,
-	  pfkey_stats,	NULL,		"pfkey", 0,	0 },
+	  pfkey_stats,	NULL,		NULL,	"pfkey", 0,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		NULL,	0,	0 }
+	  NULL,		NULL,		NULL,	NULL,	0,	0 }
 };
 #endif
 
 struct protox atalkprotox[] = {
 	{ N_DDPCB,	N_DDPSTAT,	1,	atalkprotopr,
-	  ddp_stats,	NULL,		"ddp",	0,	0 },
+	  ddp_stats,	NULL,		NULL,	"ddp",	0,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		NULL,	0,	0 }
+	  NULL,		NULL,		NULL,	NULL,	0,	0 }
 };
 #ifdef NETGRAPH
 struct protox netgraphprotox[] = {
 	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
-	  NULL,		NULL,		"ctrl",	0,	0 },
+	  NULL,		NULL,		NULL,	"ctrl",	0,	0 },
 	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
-	  NULL,		NULL,		"data",	0,	0 },
+	  NULL,		NULL,		NULL,	"data",	0,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		NULL,	0,	0 }
+	  NULL,		NULL,		NULL,	NULL,	0,	0 }
 };
 #endif
 #ifdef IPX
 struct protox ipxprotox[] = {
 	{ N_IPX,	N_IPXSTAT,	1,	ipxprotopr,
-	  ipx_stats,	NULL,		"ipx",	0,	0 },
+	  ipx_stats,	NULL,		NULL,	"ipx",	0,	0 },
 	{ N_IPX,	N_SPXSTAT,	1,	ipxprotopr,
-	  spx_stats,	NULL,		"spx",	0,	0 },
+	  spx_stats,	NULL,		NULL,	"spx",	0,	0 },
 	{ -1,		-1,		0,	NULL,
-	  NULL,		NULL,		0,	0,	0 }
+	  NULL,		NULL,		NULL,	0,	0,	0 }
 };
 #endif
 
@@ -624,6 +627,12 @@ printproto(tp, name)
 	void (*pr)(u_long, const char *, int, int);
 	u_long off;
 
+	if (tp->feature_test != NULL && !(*tp->feature_test)()) {
+		if (pflag)
+			fprintf(stderr, "%s: not supported in kernel\n", tp->pr_name);
+		return;
+	}
+
 	if (sflag) {
 		if (iflag) {
 			if (tp->pr_istats)
--- netstat.h@@/main/RELENG_8/RELENG_8_2/plt_ag_os/0	2011-10-21 12:16:04.000000000 -0400
+++ netstat.h	2011-10-24 14:30:13.000000000 -0400
@@ -73,6 +73,7 @@ void	protopr(u_long, const char *, int, 
 void	tcp_stats(u_long, const char *, int, int);
 void	udp_stats(u_long, const char *, int, int);
 #ifdef SCTP
+int	sctp_feature_test(void);
 void	sctp_protopr(u_long, const char *, int, int);
 void	sctp_stats(u_long, const char *, int, int);
 #endif
--- sctp.c@@/main/RELENG_8/RELENG_8_2/plt_ag_os/0	2011-10-20 18:00:53.000000000 -0400
+++ sctp.c	2011-10-24 14:30:14.000000000 -0400
@@ -102,6 +102,13 @@ struct xraddr_entry {
         LIST_ENTRY(xraddr_entry) xraddr_entries;
 };
 
+int
+sctp_feature_test(void)
+{
+
+	return (feature_present("sctp"));
+}
+
 static int
 sctp_skip_xinpcb_ifneed(char *buf, const size_t buflen, size_t *offset)
 {
--- sctp_sysctl.c@@/main/RELENG_8/RELENG_8_2/plt_ag_os/0	2011-10-20 17:36:01.000000000 -0400
+++ sctp_sysctl.c	2011-10-24 14:30:11.000000000 -0400
@@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$");
 #include <netinet/sctp_output.h>
 #include <sys/smp.h>
 
+FEATURE(sctp, "Stream Control Transmission Protocol");
+
 /*
  * sysctl tunable variables
  */
_______________________________________________
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"

Reply via email to