Page MenuHomeFreeBSD

D36381.id109924.diff
No OneTemporary

D36381.id109924.diff

diff --git a/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h
--- a/sys/netinet/ip_divert.h
+++ b/sys/netinet/ip_divert.h
@@ -36,10 +36,9 @@
#ifndef _NETINET_IP_DIVERT_H_
#define _NETINET_IP_DIVERT_H_
+#include <sys/types.h>
/*
- * divert has no custom kernel-userland API.
- *
* All communication occurs through a sockaddr_in socket where
*
* kernel-->userland
@@ -54,4 +53,11 @@
* sin_addr = IN: address of the incoming interface;
* OUT: INADDR_ANY
*/
+
+struct divstat {
+ uint64_t div_diverted; /* successfully diverted to userland */
+ uint64_t div_noport; /* failed due to no bound socket */
+ uint64_t div_outbound; /* re-injected as outbound */
+ uint64_t div_inbound; /* re-injected as inbound */
+};
#endif /* _NETINET_IP_DIVERT_H_ */
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -66,6 +66,7 @@
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_divert.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -110,8 +111,19 @@
* written in the sin_port (ipfw does not allow a rule #0, so sin_port=0
* will apply the entire ruleset to the packet).
*/
+static SYSCTL_NODE(_net_inet, OID_AUTO, divert, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "divert(4)");
+
+VNET_PCPUSTAT_DEFINE_STATIC(struct divstat, divstat);
+VNET_PCPUSTAT_SYSINIT(divstat);
+#ifdef VIMAGE
+VNET_PCPUSTAT_SYSUNINIT(divstat);
+#endif
+SYSCTL_VNET_PCPUSTAT(_net_inet_divert, OID_AUTO, stats, struct divstat,
+ divstat, "divert(4) socket statistics");
+#define DIVSTAT_INC(name) \
+ VNET_PCPUSTAT_ADD(struct divstat, divstat, div_ ## name, 1)
-/* Internal variables. */
VNET_DEFINE_STATIC(struct inpcbinfo, divcbinfo);
#define V_divcbinfo VNET(divcbinfo)
@@ -273,17 +285,18 @@
(struct sockaddr *)&divsrc, m, NULL) == 0) {
soroverflow_locked(sa);
sa = NULL; /* force mbuf reclaim below */
- } else
+ } else {
sorwakeup_locked(sa);
+ DIVSTAT_INC(diverted);
+ }
/* XXX why does only one socket match? */
INP_RUNLOCK(inp);
break;
}
if (sa == NULL) {
m_freem(m);
- KMOD_IPSTAT_INC(ips_noproto);
- KMOD_IPSTAT_DEC(ips_delivered);
- }
+ DIVSTAT_INC(noport);
+ }
}
/*
@@ -310,7 +323,6 @@
/* Packet must have a header (but that's about it) */
if (m->m_len < sizeof (struct ip) &&
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
- KMOD_IPSTAT_INC(ips_toosmall);
m_freem(m);
return (EINVAL);
}
@@ -447,9 +459,6 @@
#endif
}
- /* Send packet to output processing */
- KMOD_IPSTAT_INC(ips_rawout); /* XXX */
-
#ifdef MAC
mac_inpcb_create_mbuf(inp, m);
#endif
@@ -498,6 +507,8 @@
break;
#endif
}
+ if (error == 0)
+ DIVSTAT_INC(outbound);
if (options != NULL)
m_freem(options);
@@ -549,10 +560,12 @@
else if (in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
m->m_flags |= M_BCAST;
netisr_queue_src(NETISR_IP, (uintptr_t)so, m);
+ DIVSTAT_INC(inbound);
break;
#ifdef INET6
case AF_INET6:
netisr_queue_src(NETISR_IPV6, (uintptr_t)so, m);
+ DIVSTAT_INC(inbound);
break;
#endif
default:
@@ -704,16 +717,9 @@
return (error);
}
-
-#ifdef SYSCTL_NODE
-static SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert,
- CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
- "IPDIVERT");
SYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist,
- CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, div_pcblist, "S,xinpcb",
- "List of active divert sockets");
-#endif
+ CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, div_pcblist,
+ "S,xinpcb", "List of active divert sockets");
static struct protosw div_protosw = {
.pr_type = SOCK_RAW,
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -58,6 +58,7 @@
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/igmp_var.h>
+#include <netinet/ip_divert.h>
#include <netinet/ip_var.h>
#include <netinet/pim_var.h>
#include <netinet/tcp.h>
@@ -1432,6 +1433,36 @@
xo_close_container(name);
}
+/*
+ * Dump divert(4) statistics structure.
+ */
+void
+divert_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
+{
+ struct divstat divstat;
+
+ if (fetch_stats("net.inet.divert.stats", off, &divstat,
+ sizeof(divstat), kread_counters) != 0)
+ return;
+
+ xo_open_container(name);
+ xo_emit("{T:/%s}:\n", name);
+
+#define p(f, m) if (divstat.f || sflag <= 1) \
+ xo_emit(m, (uintmax_t)divstat.f, plural(divstat.f))
+
+ p(div_diverted, "\t{:diverted-packets/%ju} "
+ "{N:/packet%s successfully diverted to userland}\n");
+ p(div_noport, "\t{:noport-fails/%ju} "
+ "{N:/packet%s failed to divert due to no socket bound at port}\n");
+ p(div_outbound, "\t{:outbound-packets/%ju} "
+ "{N:/packet%s successfully re-injected as outbound}\n");
+ p(div_inbound, "\t{:inbound-packets/%ju} "
+ "{N:/packet%s successfully re-injected as inbound}\n");
+#undef p
+ xo_close_container(name);
+}
+
#ifdef INET
/*
* Pretty print an Internet address (net address + port).
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -101,7 +101,7 @@
NULL, NULL, "sdp", 1, IPPROTO_TCP },
#endif
{ N_DIVCBINFO, -1, 1, protopr,
- NULL, NULL, "divert", 1, 0 },
+ divert_stats, NULL, "divert", 1, 0 },
{ N_RIPCBINFO, N_IPSTAT, 1, protopr,
ip_stats, NULL, "ip", 1, IPPROTO_RAW },
{ N_RIPCBINFO, N_ICMPSTAT, 1, protopr,
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -92,6 +92,7 @@
void sctp_stats(u_long, const char *, int, int);
#endif
void arp_stats(u_long, const char *, int, int);
+void divert_stats(u_long, const char *, int, 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);

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 27, 11:18 PM (9 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16221214
Default Alt Text
D36381.id109924.diff (5 KB)

Event Timeline