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/56c002c66144
branches: trunk
changeset: 349511:56c002c66144
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 07a4452afa7b -r 56c002c66144 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