git: 2b1c72171e3e - main - divert(4): provide statistics
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 30 Aug 2022 22:49:26 UTC
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=2b1c72171e3e44b26793013f04fb98f0b975cbad commit 2b1c72171e3e44b26793013f04fb98f0b975cbad Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2022-08-30 22:09:21 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2022-08-30 22:09:21 +0000 divert(4): provide statistics Instead of incrementing pretty random counters in the IP statistics, create divert socket statistics structure. Export via netstat(1). Differential revision: https://reviews.freebsd.org/D36381 --- sys/netinet/ip_divert.c | 42 ++++++++++++++++++++++++------------------ sys/netinet/ip_divert.h | 10 ++++++++-- usr.bin/netstat/inet.c | 31 +++++++++++++++++++++++++++++++ usr.bin/netstat/main.c | 2 +- usr.bin/netstat/netstat.h | 1 + 5 files changed, 65 insertions(+), 21 deletions(-) diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index b09d7e1dda7a..0cecbbd0d15d 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #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 @@ __FBSDID("$FreeBSD$"); * 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 @@ divert_packet(struct mbuf *m, bool incoming) (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 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, /* 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 @@ div_output_outbound(int family, struct socket *so, struct mbuf *m) #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 @@ div_output_outbound(int family, struct socket *so, struct mbuf *m) break; #endif } + if (error == 0) + DIVSTAT_INC(outbound); if (options != NULL) m_freem(options); @@ -549,10 +560,12 @@ div_output_inbound(int family, struct socket *so, struct mbuf *m, 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 @@ div_pcblist(SYSCTL_HANDLER_ARGS) 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/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h index a426afeca217..dd0568bbfb07 100644 --- 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/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index e848874d1695..468bd9aba3e5 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #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 @@ pim_stats(u_long off __unused, const char *name, int af1 __unused, 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 index d1b069f38f0c..078d8cca3c61 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -101,7 +101,7 @@ static struct protox { 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 index eb5b77eade0e..32dbbc9d5576 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -92,6 +92,7 @@ void sctp_protopr(u_long, const char *, int, int); 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);