The branch main has been updated by glebius:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2b1c72171e3e44b26793013f04fb98f0b975cbad

commit 2b1c72171e3e44b26793013f04fb98f0b975cbad
Author:     Gleb Smirnoff <gleb...@freebsd.org>
AuthorDate: 2022-08-30 22:09:21 +0000
Commit:     Gleb Smirnoff <gleb...@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);

Reply via email to