Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net MP-safe pppoe(4).



details:   https://anonhg.NetBSD.org/src/rev/6ffcc9524784
branches:  trunk
changeset: 819653:6ffcc9524784
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Tue Dec 13 00:35:11 2016 +0000

description:
MP-safe pppoe(4).

Nearly all parts is implemented by Shoichi YAMAGUCHI<s-yamaguchi@IIJ>, thanks.

diffstat:

 sys/net/if_pppoe.c    |  472 +++++++++++++++++++++++++++++++++----
 sys/net/if_spppsubr.c |  615 ++++++++++++++++++++++++++++++++++++++++++-------
 sys/net/if_spppvar.h  |    6 +-
 3 files changed, 939 insertions(+), 154 deletions(-)

diffs (truncated from 3267 to 300 lines):

diff -r 53b75af29fc3 -r 6ffcc9524784 sys/net/if_pppoe.c
--- a/sys/net/if_pppoe.c        Mon Dec 12 21:56:00 2016 +0000
+++ b/sys/net/if_pppoe.c        Tue Dec 13 00:35:11 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.119 2016/11/18 08:13:02 knakahara Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.120 2016/12/13 00:35:11 knakahara Exp $ */
 
 /*-
  * Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,11 +30,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.119 2016/11/18 08:13:02 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.120 2016/12/13 00:35:11 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "pppoe.h"
 #include "opt_pppoe.h"
+#include "opt_net_mpsafe.h"
 #endif
 
 #include <sys/param.h>
@@ -52,6 +53,8 @@
 #include <sys/device.h>
 #include <sys/module.h>
 #include <sys/sysctl.h>
+#include <sys/rwlock.h>
+#include <sys/mutex.h>
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -64,6 +67,10 @@
 
 #include "ioconf.h"
 
+#ifdef NET_MPSAFE
+#define PPPOE_MPSAFE   1
+#endif
+
 struct pppoehdr {
        uint8_t vertype;
        uint8_t code;
@@ -125,12 +132,39 @@
 #define        IFF_PASSIVE     IFF_LINK0       /* wait passively for connection */
 #endif
 
+#define PPPOE_SESSION_LOCK(_sc, _op)   rw_enter(&(_sc)->sc_session_lock, (_op))
+#define PPPOE_SESSION_UNLOCK(_sc)      rw_exit(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_LOCKED(_sc)      rw_lock_held(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_WLOCKED(_sc)     rw_write_held(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_RLOCKED(_sc)     rw_read_held(&(_sc)->sc_session_lock)
+
+#define PPPOE_PARAM_LOCK(_sc)          if ((_sc)->sc_lock) \
+                                               mutex_enter((_sc)->sc_lock)
+#define PPPOE_PARAM_UNLOCK(_sc)                if ((_sc)->sc_lock) \
+                                               mutex_exit((_sc)->sc_lock)
+#define PPPOE_PARAM_LOCKED(_sc)                (!(_sc)->sc_lock || \
+                                               mutex_owned((_sc)->sc_lock))
+#ifdef PPPOE_MPSAFE
+#define DECLARE_SPLNET_VARIABLE
+#define ACQUIRE_SPLNET()       do { } while (0)
+#define RELEASE_SPLNET()       do { } while (0)
+#else
+#define DECLARE_SPLNET_VARIABLE        int __s
+#define ACQUIRE_SPLNET()       do {                                    \
+                                       __s = splnet();                 \
+                               } while (0)
+#define RELEASE_SPLNET()       do {                                    \
+                                       splx(__s);                      \
+                               } while (0)
+#endif
+
 struct pppoe_softc {
        struct sppp sc_sppp;            /* contains a struct ifnet as first element */
        LIST_ENTRY(pppoe_softc) sc_list;
        struct ifnet *sc_eth_if;        /* ethernet interface we are using */
 
        int sc_state;                   /* discovery phase or session connected */
+       bool sc_state_updating;         /* state update in other components */
        struct ether_addr sc_dest;      /* hardware address of concentrator */
        uint16_t sc_session;            /* PPPoE session id */
 
@@ -147,6 +181,8 @@
        callout_t sc_timeout;   /* timeout while not in session state */
        int sc_padi_retried;            /* number of PADI retries already done */
        int sc_padr_retried;            /* number of PADR retries already done */
+       krwlock_t sc_session_lock;      /* lock of sc_state, sc_session, and sc_eth_if */
+       kmutex_t *sc_lock;              /* lock of other parameters */
 };
 
 /* incoming traffic will be queued here */
@@ -173,6 +209,9 @@
 static void pppoe_tls(struct sppp *);
 static void pppoe_tlf(struct sppp *);
 static void pppoe_start(struct ifnet *);
+#ifdef PPPOE_MPSAFE
+static int pppoe_transmit(struct ifnet *, struct mbuf *);
+#endif
 static void pppoe_clear_softc(struct pppoe_softc *, const char *);
 
 /* internal timeout handling */
@@ -191,13 +230,15 @@
 static int pppoe_output(struct pppoe_softc *, struct mbuf *);
 
 /* internal helper functions */
-static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct ifnet *);
-static struct pppoe_softc * pppoe_find_softc_by_hunique(uint8_t *, size_t, struct ifnet *);
+static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct ifnet *, krw_t);
+static struct pppoe_softc * pppoe_find_softc_by_hunique(uint8_t *, size_t,
+    struct ifnet *, krw_t);
 static struct mbuf *pppoe_get_mbuf(size_t len);
 
 static int pppoe_ifattach_hook(void *, struct mbuf **, struct ifnet *, int);
 
 static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;
+static krwlock_t pppoe_softc_list_lock;
 
 static int     pppoe_clone_create(struct if_clone *, int);
 static int     pppoe_clone_destroy(struct ifnet *);
@@ -226,10 +267,11 @@
 {
 
        LIST_INIT(&pppoe_softc_list);
+       rw_init(&pppoe_softc_list_lock);
        if_clone_attach(&pppoe_cloner);
 
-       pppoe_softintr = softint_establish(SOFTINT_NET, pppoe_softintr_handler,
-           NULL);
+       pppoe_softintr = softint_establish(SOFTINT_MPSAFE|SOFTINT_NET,
+           pppoe_softintr_handler, NULL);
        sysctl_net_pppoe_setup(&pppoe_sysctl_clog);
 
        IFQ_LOCK_INIT(&ppoediscinq);
@@ -265,6 +307,9 @@
        sc->sc_sppp.pp_if.if_softc = sc;
        sc->sc_sppp.pp_if.if_mtu = PPPOE_MAXMTU;
        sc->sc_sppp.pp_if.if_flags = IFF_SIMPLEX|IFF_POINTOPOINT|IFF_MULTICAST;
+#ifdef PPPOE_MPSAFE
+       sc->sc_sppp.pp_if.if_extflags = IFEF_OUTPUT_MPSAFE;
+#endif
        sc->sc_sppp.pp_if.if_type = IFT_PPP;
        sc->sc_sppp.pp_if.if_hdrlen = sizeof(struct ether_header) + PPPOE_HEADERLEN;
        sc->sc_sppp.pp_if.if_dlt = DLT_PPP_ETHER;
@@ -280,6 +325,9 @@
        callout_init(&sc->sc_timeout, 0);
 
        sc->sc_sppp.pp_if.if_start = pppoe_start;
+#ifdef PPPOE_MPSAFE
+       sc->sc_sppp.pp_if.if_transmit = pppoe_transmit;
+#endif
        sc->sc_sppp.pp_tls = pppoe_tls;
        sc->sc_sppp.pp_tlf = pppoe_tlf;
        sc->sc_sppp.pp_framebytes = PPPOE_HEADERLEN;    /* framing added to ppp packets */
@@ -293,7 +341,13 @@
        if (LIST_EMPTY(&pppoe_softc_list)) {
                pfil_add_hook(pppoe_ifattach_hook, NULL, PFIL_IFNET, if_pfil);
        }
+
+       sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
+       rw_init(&sc->sc_session_lock);
+
+       rw_enter(&pppoe_softc_list_lock, RW_WRITER);
        LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);
+       rw_exit(&pppoe_softc_list_lock);
        return 0;
 }
 
@@ -302,11 +356,20 @@
 {
        struct pppoe_softc * sc = ifp->if_softc;
 
-       callout_stop(&sc->sc_timeout);
+       rw_enter(&pppoe_softc_list_lock, RW_WRITER);
+
+       PPPOE_PARAM_LOCK(sc);
+       callout_halt(&sc->sc_timeout, NULL);
+
        LIST_REMOVE(sc, sc_list);
+
        if (LIST_EMPTY(&pppoe_softc_list)) {
                pfil_remove_hook(pppoe_ifattach_hook, NULL, PFIL_IFNET, if_pfil);
        }
+       rw_exit(&pppoe_softc_list_lock);
+
+       PPPOE_SESSION_LOCK(sc, RW_WRITER);
+
        bpf_detach(ifp);
        sppp_detach(&sc->sc_sppp.pp_if);
        if_detach(ifp);
@@ -319,6 +382,13 @@
        if (sc->sc_relay_sid)
                free(sc->sc_relay_sid, M_DEVBUF);
        callout_destroy(&sc->sc_timeout);
+
+       PPPOE_PARAM_UNLOCK(sc);
+       if (sc->sc_lock)
+               mutex_obj_free(sc->sc_lock);
+       PPPOE_SESSION_UNLOCK(sc);
+       rw_destroy(&sc->sc_session_lock);
+
        free(sc, M_DEVBUF);
 
        return (0);
@@ -331,26 +401,32 @@
  * be 1.
  */
 static struct pppoe_softc *
-pppoe_find_softc_by_session(u_int session, struct ifnet *rcvif)
+pppoe_find_softc_by_session(u_int session, struct ifnet *rcvif, krw_t lock)
 {
-       struct pppoe_softc *sc;
+       struct pppoe_softc *sc = NULL;
 
        if (session == 0)
                return NULL;
-
+       rw_enter(&pppoe_softc_list_lock, RW_READER);
        LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
-               if (sc->sc_state == PPPOE_STATE_SESSION
+               PPPOE_SESSION_LOCK(sc, lock);
+               if (!sc->sc_state_updating
+                   && sc->sc_state == PPPOE_STATE_SESSION
                    && sc->sc_session == session
                    && sc->sc_eth_if == rcvif)
-                       return sc;
+                       break;
+
+               PPPOE_SESSION_UNLOCK(sc);
        }
-       return NULL;
+       rw_exit(&pppoe_softc_list_lock);
+       return sc;
 }
 
 /* Check host unique token passed and return appropriate softc pointer,
  * or NULL if token is bogus. */
 static struct pppoe_softc *
-pppoe_find_softc_by_hunique(uint8_t *token, size_t len, struct ifnet *rcvif)
+pppoe_find_softc_by_hunique(uint8_t *token, size_t len,
+    struct ifnet *rcvif, krw_t lock)
 {
        struct pppoe_softc *sc, *t;
 
@@ -361,8 +437,14 @@
                return NULL;
        memcpy(&t, token, len);
 
-       LIST_FOREACH(sc, &pppoe_softc_list, sc_list)
-               if (sc == t) break;
+       rw_enter(&pppoe_softc_list_lock, RW_READER);
+       LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
+               if (sc == t) {
+                       PPPOE_SESSION_LOCK(sc, lock);
+                       break;
+               }
+       }
+       rw_exit(&pppoe_softc_list_lock);
 
        if (sc == NULL) {
 #ifdef PPPOE_DEBUG
@@ -371,15 +453,26 @@
                return NULL;
        }
 
+       if (sc->sc_state_updating) {
+#ifdef PPPOE_DEBUG
+               printf("%s: host unique tag found, but its state is updating\n",
+                   sc->sc_sppp.pp_if.if_xname);
+#endif
+               PPPOE_SESSION_UNLOCK(sc);
+               return NULL;
+       }
+
        /* should be safe to access *sc now */
        if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
                printf("%s: host unique tag found, but it belongs to a connection in state %d\n",
                        sc->sc_sppp.pp_if.if_xname, sc->sc_state);
+               PPPOE_SESSION_UNLOCK(sc);
                return NULL;
        }
        if (sc->sc_eth_if != rcvif) {
                printf("%s: wrong interface, not accepting host unique\n",
                        sc->sc_sppp.pp_if.if_xname);
+               PPPOE_SESSION_UNLOCK(sc);
                return NULL;
        }
        return sc;
@@ -389,9 +482,7 @@
 pppoe_softintr_handler(void *dummy)
 {
        /* called at splsoftnet() */
-       mutex_enter(softnet_lock);
        pppoeintr();
-       mutex_exit(softnet_lock);
 }
 
 /* called at appropriate protection level */
@@ -401,6 +492,10 @@
        struct mbuf *m;



Home | Main Index | Thread Index | Old Index