On Mon, Jul 06, 2020 at 10:59:17AM +0200, Martin Pieuchot wrote:
> On 01/07/20(Wed) 22:42, Vitaliy Makkoveev wrote:
> > pipex(4) has 2 mbuf queues: `pipexinq' and `pipexoutq'. When mbuf passed
> > to pipex it goes to one of these queues and pipexintr() will be
> > scheduled to process them. pipexintr() called from `netisr' context.
> > 
> > It's true for pppac(4) but for pppx(4) only incoming mbufs go to
> > `pipexinq. Outgoing mbufs go directly to stack. pppx(4) enabled in
> > npppd.conf(5) by default so I guess it's the common case of pipex(4)
> > usage.
> > 
> > The code looks like there is no requirements to this delayed mbufs
> > processing, we can pass it directly to stack as we do for pppx(4)
> > outgoing traffic.
> > 
> > Also we have some troubles with pipexintr() as it was described in [1].
> > It's protection of `ph_cookie'. We don't this protection this time and
> > we can't because we should brake if_get(9) logic.
> > 
> > Diff below removes pipexintr(). Now all mbufs passed directly without
> > enqueueing within pipex(4). We also can destroy sessions safe in all
> > cases. We also can use if_get(9) instead using unreferenced pointers to
> > `ifnet' within pipex(4). We also avoided context switch while we
> > processing mbufs within pipex(4). We decreased latency.
> > 
> > I'm seeding debian torrents with this diff an all goes well.
> 
> With this diff the content of pipexintr() is no longer executed with the
> KERNEL_LOCK() held.  This can be seen by following the code starting in
> ether_input().
> 
> Grabbing the KERNEL_LOCK() there is not a way forward.  The whole idea
> of if_input_process() is to be free of KERNEL_LOCK() to not introduce
> latency delay.
> 
> So this changes implies that `pipex_session_list' and possibly other
> global data structures as well as the elements linked in those are all
> protected by the NET_LOCK().  I believe this is the easiest way forward.
> 
> That said I would be comfortable with this diff going in if an audit of
> the data structures accessed in the code path starting by pipex_pppoe_input()
> has been done.  That implies annotating/documenting which data structures
> are now protected by the NET_LOCK() and adding the necessary
> NET_ASSERT_LOCK().  Such audit might lead to consider some ioctl code
> path changes to now serialize on the NET_LOCK() instead of the
> KERNEL_LOCK().
> 

pipex(4) is simultaneously locked by NET_LOCK() and KERNEL_LOCK() but
with two exceptions:

1. As you pointed pipex_pppoe_input() called without KERNEL_LOCK() held.
2. pppac_start() called without NET_LOCK() held. Or with NET_LOCK()
   held. It depends on `if_snd' usage.

Diff below enforces pppac_start() to be called with NET_LOCK() held.
Also all externally called pipex(4) input and output routines have
NET_ASSERT_LOCKED() assertion.

Now pipex(4) is fully protected by NET_LOCK() so description of struct
members chenget too.

Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.90
diff -u -p -r1.90 if_pppx.c
--- sys/net/if_pppx.c   24 Jun 2020 08:52:53 -0000      1.90
+++ sys/net/if_pppx.c   6 Jul 2020 11:10:17 -0000
@@ -1117,6 +1117,8 @@ pppacopen(dev_t dev, int flags, int mode
        ifp->if_output = pppac_output;
        ifp->if_start = pppac_start;
        ifp->if_ioctl = pppac_ioctl;
+       /* XXXSMP: be sure pppac_start() called under NET_LOCK() */
+       IFQ_SET_MAXLEN(&ifp->if_snd, 1);
 
        if_counters_alloc(ifp);
        if_attach(ifp);
Index: sys/net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.117
diff -u -p -r1.117 pipex.c
--- sys/net/pipex.c     30 Jun 2020 14:05:13 -0000      1.117
+++ sys/net/pipex.c     6 Jul 2020 11:10:17 -0000
@@ -869,6 +869,7 @@ pipex_output(struct mbuf *m0, int af, in
        struct ip ip;
        struct mbuf *mret;
 
+       NET_ASSERT_LOCKED();
        session = NULL;
        mret = NULL;
        switch (af) {
@@ -962,6 +963,8 @@ pipex_ppp_output(struct mbuf *m0, struct
 {
        u_char *cp, hdr[16];
 
+       NET_ASSERT_LOCKED();
+
 #ifdef PIPEX_MPPE
        if (pipex_session_is_mppe_enabled(session)) {
                if (proto == PPP_IP) {
@@ -1355,6 +1358,7 @@ pipex_pppoe_input(struct mbuf *m0, struc
        int hlen;
        struct pipex_pppoe_header pppoe;
 
+       NET_ASSERT_LOCKED();
        /* already checked at pipex_pppoe_lookup_session */
        KASSERT(m0->m_pkthdr.len >= (sizeof(struct ether_header) +
            sizeof(pppoe)));
@@ -1586,6 +1590,7 @@ pipex_pptp_input(struct mbuf *m0, struct
        struct pipex_pptp_session *pptp_session;
        int rewind = 0;
 
+       NET_ASSERT_LOCKED();
        KASSERT(m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN);
        pptp_session = &session->proto.pptp;
 
@@ -2031,6 +2036,7 @@ pipex_l2tp_input(struct mbuf *m0, int of
        uint16_t flags, ns = 0, nr = 0;
        int rewind = 0;
 
+       NET_ASSERT_LOCKED();
        length = offset = ns = nr = 0;
        l2tp_session = &session->proto.l2tp;
        l2tp_session->ipsecflowinfo = ipsecflowinfo;
Index: sys/net/pipex.h
===================================================================
RCS file: /cvs/src/sys/net/pipex.h,v
retrieving revision 1.23
diff -u -p -r1.23 pipex.h
--- sys/net/pipex.h     5 Jun 2020 19:50:59 -0000       1.23
+++ sys/net/pipex.h     6 Jul 2020 11:10:17 -0000
@@ -187,11 +187,11 @@ struct pipex_session;
  *
  * Locks used to protect struct members:
  *      I       immutable after creation
- *      k       kernel lock
+ *      N       net lock
  */
 struct pipex_iface_context {
        struct  ifnet *ifnet_this;      /* [I] outer interface */
-       u_int   pipexmode;              /* [k] pipex mode */
+       u_int   pipexmode;              /* [N] pipex mode */
        /* [I] virtual pipex_session entry for multicast routing */
        struct pipex_session *multicast_session;
 };
Index: sys/net/pipex_local.h
===================================================================
RCS file: /cvs/src/sys/net/pipex_local.h,v
retrieving revision 1.35
diff -u -p -r1.35 pipex_local.h
--- sys/net/pipex_local.h       18 Jun 2020 14:20:12 -0000      1.35
+++ sys/net/pipex_local.h       6 Jul 2020 11:10:17 -0000
@@ -56,23 +56,23 @@
 /*
  * Locks used to protect struct members:
  *      I       immutable after creation
- *      k       kernel lock
+ *      N       net lock
  */
 
 #ifdef PIPEX_MPPE
 /* mppe rc4 key */
 struct pipex_mppe {
        int16_t stateless:1,                    /* [I] key change mode */
-               resetreq:1,                     /* [k] */
+               resetreq:1,                     /* [N] */
                reserved:14;
        int16_t keylenbits;                     /* [I] key length */
        int16_t keylen;                         /* [I] */
-       uint16_t coher_cnt;                     /* [k] cohency counter */
-       struct  rc4_ctx rc4ctx;                 /* [k] */
-       u_char master_key[PIPEX_MPPE_KEYLEN];   /* [k] master key of MPPE */
-       u_char session_key[PIPEX_MPPE_KEYLEN];  /* [k] session key of MPPE */
+       uint16_t coher_cnt;                     /* [N] cohency counter */
+       struct  rc4_ctx rc4ctx;                 /* [N] */
+       u_char master_key[PIPEX_MPPE_KEYLEN];   /* [N] master key of MPPE */
+       u_char session_key[PIPEX_MPPE_KEYLEN];  /* [N] session key of MPPE */
        u_char (*old_session_keys)[PIPEX_MPPE_KEYLEN];
-                                               /* [k] old session keys */
+                                               /* [N] old session keys */
 };
 #endif /* PIPEX_MPPE */
 
@@ -85,14 +85,14 @@ struct pipex_pppoe_session {
 #ifdef PIPEX_PPTP
 struct pipex_pptp_session {
        /* sequence number gap between pipex and userland */
-       int32_t snd_gap;                /* [k] gap of our sequence */
-       int32_t rcv_gap;                /* [k] gap of peer's sequence */
-       int32_t ul_snd_una;             /* [k] userland send acked seq */
-
-       uint32_t snd_nxt;               /* [k] send next */
-       uint32_t rcv_nxt;               /* [k] receive next */
-       uint32_t snd_una;               /* [k] send acked sequence */
-       uint32_t rcv_acked;             /* [k] recv acked sequence */
+       int32_t snd_gap;                /* [N] gap of our sequence */
+       int32_t rcv_gap;                /* [N] gap of peer's sequence */
+       int32_t ul_snd_una;             /* [N] userland send acked seq */
+
+       uint32_t snd_nxt;               /* [N] send next */
+       uint32_t rcv_nxt;               /* [N] receive next */
+       uint32_t snd_una;               /* [N] send acked sequence */
+       uint32_t rcv_acked;             /* [N] recv acked sequence */
 
        int winsz;                      /* [I] windows size */
        int maxwinsz;                   /* [I] max windows size */
@@ -135,38 +135,38 @@ struct pipex_l2tp_session {
 
        uint32_t option_flags;          /* [I] protocol options */
 
-       int16_t ns_gap;         /* [k] gap between userland and pipex */
-       int16_t nr_gap;         /* [k] gap between userland and pipex */
-       uint16_t ul_ns_una;     /* [k] unacked sequence number (userland) */
-
-       uint16_t ns_nxt;        /* [k] next sequence number to send */
-       uint16_t ns_una;        /* [k] unacked sequence number to send */
-
-       uint16_t nr_nxt;        /* [k] next sequence number to recv */
-       uint16_t nr_acked;      /* [k] acked sequence number to recv */
-       uint32_t ipsecflowinfo; /* [k] IPsec SA flow id for NAT-T */
+       int16_t ns_gap;         /* [N] gap between userland and pipex */
+       int16_t nr_gap;         /* [N] gap between userland and pipex */
+       uint16_t ul_ns_una;     /* [N] unacked sequence number (userland) */
+
+       uint16_t ns_nxt;        /* [N] next sequence number to send */
+       uint16_t ns_una;        /* [N] unacked sequence number to send */
+
+       uint16_t nr_nxt;        /* [N] next sequence number to recv */
+       uint16_t nr_acked;      /* [N] acked sequence number to recv */
+       uint32_t ipsecflowinfo; /* [N] IPsec SA flow id for NAT-T */
 };
 #endif /* PIPEX_L2TP */
 
 /* pppac ip-extension sessoin table */
 struct pipex_session {
        struct radix_node       ps4_rn[2];
-                                       /* [k] tree glue, and other values */
+                                       /* [N] tree glue, and other values */
        struct radix_node       ps6_rn[2];
-                                       /* [k] tree glue, and other values */
-       LIST_ENTRY(pipex_session) session_list; /* [k] all session chain */
-       LIST_ENTRY(pipex_session) state_list;   /* [k] state list chain */
-       LIST_ENTRY(pipex_session) id_chain;     /* [k] id hash chain */
+                                       /* [N] tree glue, and other values */
+       LIST_ENTRY(pipex_session) session_list; /* [N] all session chain */
+       LIST_ENTRY(pipex_session) state_list;   /* [N] state list chain */
+       LIST_ENTRY(pipex_session) id_chain;     /* [N] id hash chain */
        LIST_ENTRY(pipex_session) peer_addr_chain;
-                                       /* [k] peer's address hash chain */
-       uint16_t        state;          /* [k] pipex session state */
+                                       /* [N] peer's address hash chain */
+       uint16_t        state;          /* [N] pipex session state */
 #define PIPEX_STATE_INITIAL            0x0000
 #define PIPEX_STATE_OPENED             0x0001
 #define PIPEX_STATE_CLOSE_WAIT         0x0002
 #define PIPEX_STATE_CLOSE_WAIT2                0x0003
 #define PIPEX_STATE_CLOSED             0x0004
 
-       uint16_t        ip_forward:1,   /* [k] {en|dis}ableIP forwarding */
+       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 */
                        reserved:13;
@@ -182,16 +182,16 @@ struct pipex_session {
        struct sockaddr_in6 ip6_address; /* [I] remote IPv6 address */
        int             ip6_prefixlen;   /* [I] remote IPv6 prefixlen */
 
-       struct pipex_iface_context* pipex_iface; /* [I] context for interface */
+       struct pipex_iface_context* pipex_iface; /* [N] context for interface */
 
        uint32_t        ppp_flags;              /* [I] configure flags */
 #ifdef PIPEX_MPPE
-       int ccp_id;                             /* [k] CCP packet id */
+       int ccp_id;                             /* [N] CCP packet id */
        struct pipex_mppe
            mppe_recv,                          /* MPPE context for incoming */
            mppe_send;                          /* MPPE context for outgoing */ 
 #endif /*PIPEXMPPE */
-       struct pipex_statistics stat;           /* [k] statistics */
+       struct pipex_statistics stat;           /* [N] statistics */
        union {
 #ifdef PIPEX_PPPOE
                struct pipex_pppoe_session pppoe;       /* context for PPPoE */

Reply via email to