summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandr Nedvedicky <sashan@cvs.openbsd.org>2021-07-07 20:19:02 +0000
committerAlexandr Nedvedicky <sashan@cvs.openbsd.org>2021-07-07 20:19:02 +0000
commit6d93a660dee1a3acebd56bdd9f4c3ce8e76fbcb1 (patch)
tree085a6b7583d46b2d67356aaf5251b46237fcf892
parent61f3b2ac12eef67cc85790deafc70bb25edfe525 (diff)
tell ether_input() to call pf_test() outside of smr_read sections,
because smr_read sections don't play well with sleeping locks in pf(4). OK bluhm@
-rw-r--r--sys/net/if_bridge.c18
-rw-r--r--sys/net/if_ethersubr.c8
-rw-r--r--sys/net/if_switch.c18
-rw-r--r--sys/net/if_tpmr.c45
-rw-r--r--sys/net/if_veb.c35
-rw-r--r--sys/netinet/if_ether.h4
6 files changed, 112 insertions, 16 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 703be01648f..dfd19d1432c 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.355 2021/06/02 00:40:51 dlg Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.356 2021/07/07 20:19:01 sashan Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -138,6 +138,8 @@ int bridge_ipsec(struct ifnet *, struct ether_header *, int, struct llc *,
#endif
int bridge_clone_create(struct if_clone *, int);
int bridge_clone_destroy(struct ifnet *);
+void bridge_take(void *);
+void bridge_rele(void *);
#define ETHERADDR_IS_IP_MCAST(a) \
/* struct etheraddr *a; */ \
@@ -152,6 +154,8 @@ struct if_clone bridge_cloner =
const struct ether_brport bridge_brport = {
bridge_input,
+ bridge_take,
+ bridge_rele,
NULL,
};
@@ -1986,3 +1990,15 @@ bridge_send_icmp_err(struct ifnet *ifp,
dropit:
m_freem(n);
}
+
+void
+bridge_take(void *unused)
+{
+ return;
+}
+
+void
+bridge_rele(void *unused)
+{
+ return;
+}
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index c9493b7f857..87e8f0146ed 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.274 2021/03/07 06:02:32 dlg Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.275 2021/07/07 20:19:01 sashan Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -426,14 +426,16 @@ ether_input(struct ifnet *ifp, struct mbuf *m)
smr_read_enter();
eb = SMR_PTR_GET(&ac->ac_brport);
+ if (eb != NULL)
+ eb->eb_port_take(eb->eb_port);
+ smr_read_leave();
if (eb != NULL) {
m = (*eb->eb_input)(ifp, m, dst, eb->eb_port);
+ eb->eb_port_rele(eb->eb_port);
if (m == NULL) {
- smr_read_leave();
return;
}
}
- smr_read_leave();
/*
* Fourth phase: drop service delimited packets.
diff --git a/sys/net/if_switch.c b/sys/net/if_switch.c
index 22aecdc6b75..43449a745f2 100644
--- a/sys/net/if_switch.c
+++ b/sys/net/if_switch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_switch.c,v 1.43 2021/03/05 06:44:09 dlg Exp $ */
+/* $OpenBSD: if_switch.c,v 1.44 2021/07/07 20:19:01 sashan Exp $ */
/*
* Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
@@ -110,6 +110,8 @@ struct mbuf
void switch_flow_classifier_dump(struct switch_softc *,
struct switch_flow_classify *);
void switchattach(int);
+void switch_take(void *);
+void switch_rele(void *);
struct if_clone switch_cloner =
IF_CLONE_INITIALIZER("switch", switch_clone_create, switch_clone_destroy);
@@ -122,6 +124,8 @@ struct pool swfcl_pool;
const struct ether_brport switch_brport = {
switch_input,
+ switch_take,
+ switch_rele,
NULL,
};
@@ -1571,3 +1575,15 @@ ofp_split_mbuf(struct mbuf *m, struct mbuf **mtail)
return (0);
}
+
+void
+switch_take(void *unused)
+{
+ return;
+}
+
+void
+switch_rele(void *unused)
+{
+ return;
+}
diff --git a/sys/net/if_tpmr.c b/sys/net/if_tpmr.c
index f6eb99f347c..5fc186c4a3e 100644
--- a/sys/net/if_tpmr.c
+++ b/sys/net/if_tpmr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_tpmr.c,v 1.30 2021/06/02 01:37:10 dlg Exp $ */
+/* $OpenBSD: if_tpmr.c,v 1.31 2021/07/07 20:19:01 sashan Exp $ */
/*
* Copyright (c) 2019 The University of Queensland
@@ -83,6 +83,8 @@ struct tpmr_port {
struct tpmr_softc *p_tpmr;
unsigned int p_slot;
+ int p_refcnt;
+
struct ether_brport p_brport;
};
@@ -125,6 +127,8 @@ static int tpmr_add_port(struct tpmr_softc *,
static int tpmr_del_port(struct tpmr_softc *,
const struct ifbreq *);
static int tpmr_port_list(struct tpmr_softc *, struct ifbifconf *);
+static void tpmr_p_take(void *);
+static void tpmr_p_rele(void *);
static struct if_clone tpmr_cloner =
IF_CLONE_INITIALIZER("tpmr", tpmr_clone_create, tpmr_clone_destroy);
@@ -375,16 +379,21 @@ tpmr_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
}
#endif
- SMR_ASSERT_CRITICAL(); /* ether_input calls us in a crit section */
+ smr_read_enter();
pn = SMR_PTR_GET(&sc->sc_ports[!p->p_slot]);
+ if (pn != NULL)
+ tpmr_p_take(pn);
+ smr_read_leave();
if (pn == NULL)
goto drop;
ifpn = pn->p_ifp0;
#if NPF > 0
if (!ISSET(iff, IFF_LINK1) &&
- (m = tpmr_pf(ifpn, PF_OUT, m)) == NULL)
+ (m = tpmr_pf(ifpn, PF_OUT, m)) == NULL) {
+ tpmr_p_rele(pn);
return (NULL);
+ }
#endif
if (if_enqueue(ifpn, m))
@@ -394,6 +403,8 @@ tpmr_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
ifc_opackets, ifc_obytes, len);
}
+ tpmr_p_rele(pn);
+
return (NULL);
drop:
@@ -532,6 +543,8 @@ tpmr_add_port(struct tpmr_softc *sc, const struct ifbreq *req)
if_detachhook_add(ifp0, &p->p_dtask);
p->p_brport.eb_input = tpmr_input;
+ p->p_brport.eb_port_take = tpmr_p_take;
+ p->p_brport.eb_port_rele = tpmr_p_rele;
p->p_brport.eb_port = p;
/* commit */
@@ -547,6 +560,7 @@ tpmr_add_port(struct tpmr_softc *sc, const struct ifbreq *req)
p->p_slot = i;
+ tpmr_p_take(p);
ether_brport_set(ifp0, &p->p_brport);
ifp0->if_ioctl = tpmr_p_ioctl;
ifp0->if_output = tpmr_p_output;
@@ -701,6 +715,26 @@ tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
}
static void
+tpmr_p_take(void *p)
+{
+ struct tpmr_port *port = p;
+
+ atomic_inc_int(&port->p_refcnt);
+}
+
+static void
+tpmr_p_rele(void *p)
+{
+ struct tpmr_port *port = p;
+ struct ifnet *ifp0 = port->p_ifp0;
+
+ if (atomic_dec_int_nv(&port->p_refcnt) == 0) {
+ if_put(ifp0);
+ free(port, M_DEVBUF, sizeof(*port));
+ }
+}
+
+static void
tpmr_p_dtor(struct tpmr_softc *sc, struct tpmr_port *p, const char *op)
{
struct ifnet *ifp = &sc->sc_if;
@@ -725,10 +759,9 @@ tpmr_p_dtor(struct tpmr_softc *sc, struct tpmr_port *p, const char *op)
if_detachhook_del(ifp0, &p->p_dtask);
if_linkstatehook_del(ifp0, &p->p_ltask);
- smr_barrier();
+ tpmr_p_rele(p);
- if_put(ifp0);
- free(p, M_DEVBUF, sizeof(*p));
+ smr_barrier();
if (ifp->if_link_state != LINK_STATE_DOWN) {
ifp->if_link_state = LINK_STATE_DOWN;
diff --git a/sys/net/if_veb.c b/sys/net/if_veb.c
index 71cc814fa54..79ed8f36bed 100644
--- a/sys/net/if_veb.c
+++ b/sys/net/if_veb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_veb.c,v 1.19 2021/06/02 00:44:18 dlg Exp $ */
+/* $OpenBSD: if_veb.c,v 1.20 2021/07/07 20:19:01 sashan Exp $ */
/*
* Copyright (c) 2021 David Gwynne <dlg@openbsd.org>
@@ -209,6 +209,9 @@ static void veb_eb_port_rele(void *, void *);
static size_t veb_eb_port_ifname(void *, char *, size_t, void *);
static void veb_eb_port_sa(void *, struct sockaddr_storage *, void *);
+static void veb_eb_brport_take(void *);
+static void veb_eb_brport_rele(void *);
+
static const struct etherbridge_ops veb_etherbridge_ops = {
veb_eb_port_cmp,
veb_eb_port_take,
@@ -1060,8 +1063,13 @@ veb_port_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport)
smr_read_enter();
tp = etherbridge_resolve(&sc->sc_eb, dst);
- m = veb_transmit(sc, p, tp, m, src, dst);
+ if (tp != NULL)
+ veb_eb_port_take(NULL, tp);
smr_read_leave();
+ if (tp != NULL) {
+ m = veb_transmit(sc, p, tp, m, src, dst);
+ veb_eb_port_rele(NULL, tp);
+ }
if (m == NULL)
return (NULL);
@@ -1291,6 +1299,9 @@ veb_add_port(struct veb_softc *sc, const struct ifbreq *req, unsigned int span)
p->p_brport.eb_input = veb_port_input;
}
+ p->p_brport.eb_port_take = veb_eb_brport_take;
+ p->p_brport.eb_port_rele = veb_eb_brport_rele;
+
/* this might have changed if we slept for malloc or ifpromisc */
error = ether_brport_isset(ifp0);
if (error != 0)
@@ -1910,8 +1921,8 @@ veb_p_dtor(struct veb_softc *sc, struct veb_port *p, const char *op)
SMR_TAILQ_REMOVE_LOCKED(&port_list->l_list, p, p_entry);
port_list->l_count--;
- smr_barrier();
refcnt_finalize(&p->p_refs, "vebpdtor");
+ smr_barrier();
veb_rule_list_free(TAILQ_FIRST(&p->p_vrl));
@@ -2016,6 +2027,18 @@ veb_eb_port_rele(void *arg, void *port)
refcnt_rele_wake(&p->p_refs);
}
+static void
+veb_eb_brport_take(void *port)
+{
+ veb_eb_port_take(NULL, port);
+}
+
+static void
+veb_eb_brport_rele(void *port)
+{
+ veb_eb_port_rele(NULL, port);
+}
+
static size_t
veb_eb_port_ifname(void *arg, char *dst, size_t len, void *port)
{
@@ -2181,6 +2204,9 @@ vport_enqueue(struct ifnet *ifp, struct mbuf *m)
smr_read_enter();
eb = SMR_PTR_GET(&ac->ac_brport);
+ if (eb != NULL)
+ eb->eb_port_take(eb->eb_port);
+ smr_read_leave();
if (eb != NULL) {
struct ether_header *eh;
uint64_t dst;
@@ -2199,8 +2225,9 @@ vport_enqueue(struct ifnet *ifp, struct mbuf *m)
m = (*eb->eb_input)(ifp, m, dst, eb->eb_port);
error = 0;
+
+ eb->eb_port_rele(eb->eb_port);
}
- smr_read_leave();
m_freem(m);
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index 56e6384f39b..3f32a4729d6 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ether.h,v 1.82 2021/04/23 21:55:36 bluhm Exp $ */
+/* $OpenBSD: if_ether.h,v 1.83 2021/07/07 20:19:01 sashan Exp $ */
/* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */
/*
@@ -220,6 +220,8 @@ do { \
struct ether_brport {
struct mbuf *(*eb_input)(struct ifnet *, struct mbuf *,
uint64_t, void *);
+ void (*eb_port_take)(void *);
+ void (*eb_port_rele)(void *);
void *eb_port;
};