tell ether_input() to call pf_test() outside of smr_read sections,
authorsashan <sashan@openbsd.org>
Wed, 7 Jul 2021 20:19:01 +0000 (20:19 +0000)
committersashan <sashan@openbsd.org>
Wed, 7 Jul 2021 20:19:01 +0000 (20:19 +0000)
because smr_read sections don't play well with sleeping locks in pf(4).

OK bluhm@

sys/net/if_bridge.c
sys/net/if_ethersubr.c
sys/net/if_switch.c
sys/net/if_tpmr.c
sys/net/if_veb.c
sys/netinet/if_ether.h

index 703be01..dfd19d1 100644 (file)
@@ -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;
+}
index c9493b7..87e8f01 100644 (file)
@@ -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.
index 22aecdc..43449a7 100644 (file)
@@ -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;
+}
index f6eb99f..5fc186c 100644 (file)
@@ -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;
index 71cc814..79ed8f3 100644 (file)
@@ -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);
 
index 56e6384..3f32a47 100644 (file)
@@ -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;
 };