From baf715768bffa92c878b78653d9c82e7e7dc7978 Mon Sep 17 00:00:00 2001 From: sashan Date: Wed, 7 Jul 2021 20:19:01 +0000 Subject: [PATCH] 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@ --- sys/net/if_bridge.c | 18 ++++++++++++++++- sys/net/if_ethersubr.c | 8 +++++--- sys/net/if_switch.c | 18 ++++++++++++++++- sys/net/if_tpmr.c | 45 ++++++++++++++++++++++++++++++++++++------ sys/net/if_veb.c | 35 ++++++++++++++++++++++++++++---- sys/netinet/if_ether.h | 4 +++- 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 @@ -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; @@ -700,6 +714,26 @@ tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst, return ((*p_output)(ifp0, m, dst, rt)); } +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) { @@ -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 @@ -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; }; -- 2.20.1