With bluhm@'s "forwarding in parallel" diff pipex(4) session could be
accessed in parallel through (*ifp->if_input) -> ether_input().

Except statistics and MPPE data PPPOE sessions are mostly immutable. We
have only place where we should reset 'idle_time' in input path with
shared netlock. But since pipex(4) garbage collector uses exclusive
netlock we could reset it with shared netlock.

At the first step I propose to turn session statistics to per-CPU
counters. This make sense because we could have sessions with MPPE
disabled and PPPOE input will be lockless for this case.

Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.110
diff -u -p -r1.110 if_pppx.c
--- sys/net/if_pppx.c   25 Feb 2021 02:48:21 -0000      1.110
+++ sys/net/if_pppx.c   19 Jul 2021 21:56:12 -0000
@@ -746,8 +746,7 @@ pppx_del_session(struct pppx_dev *pxd, s
        if (pxi == NULL)
                return (EINVAL);
 
-       req->pcr_stat = pxi->pxi_session->stat;
-
+       pipex_export_session_stats(pxi->pxi_session, &req->pcr_stat);
        pppx_if_destroy(pxd, pxi);
        return (0);
 }
Index: sys/net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.133
diff -u -p -r1.133 pipex.c
--- sys/net/pipex.c     15 May 2021 08:07:20 -0000      1.133
+++ sys/net/pipex.c     19 Jul 2021 21:56:12 -0000
@@ -39,6 +39,7 @@
 #include <sys/timeout.h>
 #include <sys/kernel.h>
 #include <sys/pool.h>
+#include <sys/percpu.h>
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -273,6 +274,8 @@ pipex_init_session(struct pipex_session 
 
        session->ip_forward = 1;
 
+       session->stat_counters = counters_alloc(pxc_ncounters);
+
        session->ip_address.sin_family = AF_INET;
        session->ip_address.sin_len = sizeof(struct sockaddr_in);
        session->ip_address.sin_addr = req->pr_ip_address;
@@ -361,6 +364,7 @@ pipex_rele_session(struct pipex_session 
 {
        if (session->mppe_recv.old_session_keys)
                pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys);
+       counters_free(session->stat_counters, pxc_ncounters);
        pool_put(&pipex_session_pool, session);
 }
 
@@ -466,12 +470,29 @@ pipex_notify_close_session(struct pipex_
 {
        NET_ASSERT_LOCKED();
        session->state = PIPEX_STATE_CLOSE_WAIT;
-       session->stat.idle_time = 0;
+       session->idle_time = 0;
        LIST_INSERT_HEAD(&pipex_close_wait_list, session, state_list);
 
        return (0);
 }
 
+void
+pipex_export_session_stats(struct pipex_session *session,
+    struct pipex_statistics *stats)
+{
+       uint64_t counters[pxc_ncounters];
+
+       counters_read(session->stat_counters, counters, pxc_ncounters);
+
+       stats->ipackets = counters[pxc_ipackets];
+       stats->ierrors = counters[pxc_ierrors];
+       stats->ibytes = counters[pxc_ibytes];
+       stats->opackets = counters[pxc_opackets];
+       stats->oerrors = counters[pxc_oerrors];
+       stats->obytes = counters[pxc_obytes];
+       stats->idle_time = session->idle_time;
+}
+
 Static int
 pipex_config_session(struct pipex_session_config_req *req, void *ownersc)
 {
@@ -501,7 +522,7 @@ pipex_get_stat(struct pipex_session_stat
                return (EINVAL);
        if (session->ownersc != ownersc)
                return (EINVAL);
-       req->psr_stat = session->stat;
+       pipex_export_session_stats(session, &req->psr_stat);
 
        return (0);
 }
@@ -619,8 +640,8 @@ pipex_timer(void *ignored_arg)
                        if (session->timeout_sec == 0)
                                continue;
 
-                       session->stat.idle_time++;
-                       if (session->stat.idle_time < session->timeout_sec)
+                       session->idle_time++;
+                       if (session->idle_time < session->timeout_sec)
                                continue;
 
                        pipex_notify_close_session(session);
@@ -629,8 +650,8 @@ pipex_timer(void *ignored_arg)
                case PIPEX_STATE_CLOSE_WAIT:
                case PIPEX_STATE_CLOSE_WAIT2:
                        /* Waiting PIPEXDSESSION from userland */
-                       session->stat.idle_time++;
-                       if (session->stat.idle_time < PIPEX_CLOSE_TIMEOUT)
+                       session->idle_time++;
+                       if (session->idle_time < PIPEX_CLOSE_TIMEOUT)
                                continue;
                        /* Release the sessions when timeout */
                        pipex_unlink_session(session);
@@ -669,7 +690,7 @@ pipex_ip_output(struct mbuf *m0, struct 
                                goto dropped;
                        if (is_idle == 0)
                                /* update expire time */
-                               session->stat.idle_time = 0;
+                               session->idle_time = 0;
                }
 
                /* adjust tcpmss */
@@ -694,7 +715,8 @@ pipex_ip_output(struct mbuf *m0, struct 
                                continue;
                        m = m_copym(m0, 0, M_COPYALL, M_NOWAIT);
                        if (m == NULL) {
-                               session_tmp->stat.oerrors++;
+                               counters_inc(session->stat_counters,
+                                   pxc_oerrors);
                                continue;
                        }
                        pipex_ppp_output(m, session_tmp, PPP_IP);
@@ -706,7 +728,7 @@ pipex_ip_output(struct mbuf *m0, struct 
 drop:
        m_freem(m0);
 dropped:
-       session->stat.oerrors++;
+       counters_inc(session->stat_counters, pxc_oerrors);
 }
 
 Static void
@@ -760,7 +782,7 @@ pipex_ppp_output(struct mbuf *m0, struct
        return;
 drop:
        m_freem(m0);
-       session->stat.oerrors++;
+       counters_inc(session->stat_counters, pxc_oerrors);
 }
 
 Static void
@@ -848,7 +870,7 @@ pipex_ppp_input(struct mbuf *m0, struct 
        return;
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 }
 
 Static void
@@ -887,7 +909,7 @@ pipex_ip_input(struct mbuf *m0, struct p
                        goto drop;
                if (is_idle == 0)
                        /* update expire time */
-                       session->stat.idle_time = 0;
+                       session->idle_time = 0;
        }
 
        /* adjust tcpmss */
@@ -912,8 +934,7 @@ pipex_ip_input(struct mbuf *m0, struct p
 #endif
 
        counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len);
-       session->stat.ipackets++;
-       session->stat.ibytes += len;
+       counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len);
        ipv4_input(ifp, m0);
 
        if_put(ifp);
@@ -921,7 +942,7 @@ pipex_ip_input(struct mbuf *m0, struct p
        return;
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 }
 
 #ifdef INET6
@@ -961,8 +982,7 @@ pipex_ip6_input(struct mbuf *m0, struct 
 #endif
 
        counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len);
-       session->stat.ipackets++;
-       session->stat.ibytes += len;
+       counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len);
        ipv6_input(ifp, m0);
 
        if_put(ifp);
@@ -970,7 +990,7 @@ pipex_ip6_input(struct mbuf *m0, struct 
        return;
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 }
 #endif
 
@@ -1030,7 +1050,7 @@ pipex_common_input(struct pipex_session 
 
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
        return (NULL);
 
 not_ours:
@@ -1130,7 +1150,7 @@ pipex_pppoe_input(struct mbuf *m0, struc
            == NULL)
                return (NULL);
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
        return (NULL);
 }
 
@@ -1152,7 +1172,7 @@ pipex_pppoe_output(struct mbuf *m0, stru
        if (m0 == NULL) {
                PIPEX_DBG((NULL, LOG_ERR,
                    "<%s> cannot prepend header.", __func__));
-               session->stat.oerrors++;
+               counters_inc(session->stat_counters, pxc_oerrors);
                return;
        }
        padlen = ETHERMIN - m0->m_pkthdr.len;
@@ -1173,11 +1193,11 @@ pipex_pppoe_output(struct mbuf *m0, stru
        ifp = if_get(session->proto.pppoe.over_ifidx);
        if (ifp != NULL) {
                ifp->if_output(ifp, m0, &session->peer.sa, NULL);
-               session->stat.opackets++;
-               session->stat.obytes += len;
+               counters_pkt(session->stat_counters, pxc_opackets,
+                   pxc_obytes, len);
        } else {
                m_freem(m0);
-               session->stat.oerrors++;
+               counters_inc(session->stat_counters, pxc_oerrors);
        }
        if_put(ifp);
 }
@@ -1261,13 +1281,13 @@ pipex_pptp_output(struct mbuf *m0, struc
        ip_send(m0);
        if (len > 0) {  /* network layer only */
                /* countup statistics */
-               session->stat.opackets++;
-               session->stat.obytes += len;
+               counters_pkt(session->stat_counters, pxc_opackets,
+                   pxc_obytes, len);
        }
 
        return;
 drop:
-       session->stat.oerrors++;
+       counters_inc(session->stat_counters, pxc_oerrors);
 }
 
 struct pipex_session *
@@ -1472,7 +1492,7 @@ out_seq:
        /* FALLTHROUGH */
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 
        return (NULL);
 }
@@ -1737,14 +1757,14 @@ pipex_l2tp_output(struct mbuf *m0, struc
 
        if (datalen > 0) {      /* network layer only */
                /* countup statistics */
-               session->stat.opackets++;
-               session->stat.obytes += datalen;
+               counters_pkt(session->stat_counters, pxc_opackets,
+                   pxc_obytes, datalen);
        }
 
        return;
 drop:
        m_freem(m0);
-       session->stat.oerrors++;
+       counters_inc(session->stat_counters, pxc_oerrors);
 }
 
 struct pipex_session *
@@ -1912,7 +1932,7 @@ out_seq:
        /* FALLTHROUGH */
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 
        return (NULL);
 }
@@ -2323,7 +2343,7 @@ pipex_mppe_input(struct mbuf *m0, struct
        return;
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 }
 
 Static void
@@ -2412,7 +2432,7 @@ pipex_mppe_output(struct mbuf *m0, struc
 
        return;
 drop:
-       session->stat.oerrors++;
+       counters_inc(session->stat_counters, pxc_oerrors);
 }
 
 Static void
@@ -2453,7 +2473,7 @@ pipex_ccp_input(struct mbuf *m0, struct 
        return;
 drop:
        m_freem(m0);
-       session->stat.ierrors++;
+       counters_inc(session->stat_counters, pxc_ierrors);
 }
 
 Static int
@@ -2464,7 +2484,7 @@ pipex_ccp_output(struct pipex_session *s
 
        MGETHDR(m, M_DONTWAIT, MT_DATA);
        if (m == NULL) {
-               session->stat.oerrors++;
+               counters_inc(session->stat_counters, pxc_oerrors);
                return (1);
        }
        m->m_pkthdr.len = m->m_len = 4;
Index: sys/net/pipex_local.h
===================================================================
RCS file: /cvs/src/sys/net/pipex_local.h,v
retrieving revision 1.41
diff -u -p -r1.41 pipex_local.h
--- sys/net/pipex_local.h       4 Jan 2021 12:21:38 -0000       1.41
+++ sys/net/pipex_local.h       19 Jul 2021 21:56:12 -0000
@@ -148,6 +148,8 @@ struct pipex_l2tp_session {
 };
 #endif /* PIPEX_L2TP */
 
+struct cpumem;
+
 /* pppac ip-extension sessoin table */
 struct pipex_session {
        struct radix_node       ps4_rn[2];
@@ -166,6 +168,7 @@ struct pipex_session {
 #define PIPEX_STATE_CLOSE_WAIT2                0x0003
 #define PIPEX_STATE_CLOSED             0x0004
 
+       uint32_t        idle_time;      /* [N] idle time in seconds */
        uint16_t        ip_forward:1,   /* [N] {en|dis}ableIP forwarding */
                        ip6_forward:1,  /* [I] {en|dis}able IPv6 forwarding */
                        is_multicast:1, /* [I] virtual entry for multicast */
@@ -193,7 +196,9 @@ struct pipex_session {
            mppe_recv,                          /* MPPE context for incoming */
            mppe_send;                          /* MPPE context for outgoing */ 
 #endif /*PIPEXMPPE */
-       struct pipex_statistics stat;           /* [N] statistics */
+
+       struct cpumem   *stat_counters;
+
        union {
 #ifdef PIPEX_PPPOE
                struct pipex_pppoe_session pppoe;       /* context for PPPoE */
@@ -214,6 +219,16 @@ struct pipex_session {
        } peer, local;                                  /* [I] */
 };
 
+enum pipex_counters {
+       pxc_ipackets,   /* packets received from tunnel */
+       pxc_ierrors,    /* error packets received from tunnel */
+       pxc_ibytes,     /* number of received bytes from tunnel */
+       pxc_opackets,   /* packets sent to tunnel */
+       pxc_oerrors,    /* error packets on sending to tunnel */
+       pxc_obytes,     /* number of sent bytes to tunnel */
+       pxc_ncounters
+};
+
 /* gre header */
 struct pipex_gre_header {
        uint16_t flags;                         /* flags and version*/
@@ -384,6 +399,8 @@ void                  pipex_rele_session
 int                   pipex_link_session(struct pipex_session *,
                           struct ifnet *, void *);
 void                  pipex_unlink_session(struct pipex_session *);
+void                  pipex_export_session_stats(struct pipex_session *,
+                          struct pipex_statistics *);
 int                   pipex_config_session (struct pipex_session_config_req *,
                           void *);
 int                   pipex_get_stat (struct pipex_session_stat_req *,

Reply via email to