Author: kp
Date: Sun Nov 15 11:46:44 2020
New Revision: 367705
URL: https://svnweb.freebsd.org/changeset/base/367705

Log:
  bridge: epoch-ification
  
  Undo the revert (r363568). This commit still violates epoch rules by sleeping
  within NET_EPOCH. That will be resolved in the following commit.

Modified:
  stable/12/sys/net/if_bridge.c

Modified: stable/12/sys/net/if_bridge.c
==============================================================================
--- stable/12/sys/net/if_bridge.c       Sun Nov 15 11:28:02 2020        
(r367704)
+++ stable/12/sys/net/if_bridge.c       Sun Nov 15 11:46:44 2020        
(r367705)
@@ -189,41 +189,14 @@ extern void       nd6_setmtu(struct ifnet *);
  */
 #define BRIDGE_LOCK_INIT(_sc)          do {                    \
        mtx_init(&(_sc)->sc_mtx, "if_bridge", NULL, MTX_DEF);   \
-       cv_init(&(_sc)->sc_cv, "if_bridge_cv");                 \
 } while (0)
 #define BRIDGE_LOCK_DESTROY(_sc)       do {    \
        mtx_destroy(&(_sc)->sc_mtx);            \
-       cv_destroy(&(_sc)->sc_cv);              \
 } while (0)
 #define BRIDGE_LOCK(_sc)               mtx_lock(&(_sc)->sc_mtx)
 #define BRIDGE_UNLOCK(_sc)             mtx_unlock(&(_sc)->sc_mtx)
 #define BRIDGE_LOCK_ASSERT(_sc)                mtx_assert(&(_sc)->sc_mtx, 
MA_OWNED)
 #define BRIDGE_UNLOCK_ASSERT(_sc)      mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
-#define        BRIDGE_LOCK2REF(_sc, _err)      do {    \
-       mtx_assert(&(_sc)->sc_mtx, MA_OWNED);   \
-       if ((_sc)->sc_iflist_xcnt > 0)          \
-               (_err) = EBUSY;                 \
-       else                                    \
-               (_sc)->sc_iflist_ref++;         \
-       mtx_unlock(&(_sc)->sc_mtx);             \
-} while (0)
-#define        BRIDGE_UNREF(_sc)               do {                            
\
-       mtx_lock(&(_sc)->sc_mtx);                                       \
-       (_sc)->sc_iflist_ref--;                                         \
-       if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) \
-               cv_broadcast(&(_sc)->sc_cv);                            \
-       mtx_unlock(&(_sc)->sc_mtx);                                     \
-} while (0)
-#define        BRIDGE_XLOCK(_sc)               do {            \
-       mtx_assert(&(_sc)->sc_mtx, MA_OWNED);           \
-       (_sc)->sc_iflist_xcnt++;                        \
-       while ((_sc)->sc_iflist_ref > 0)                \
-               cv_wait(&(_sc)->sc_cv, &(_sc)->sc_mtx); \
-} while (0)
-#define        BRIDGE_XDROP(_sc)               do {    \
-       mtx_assert(&(_sc)->sc_mtx, MA_OWNED);   \
-       (_sc)->sc_iflist_xcnt--;                \
-} while (0)
 
 /*
  * Bridge interface list entry.
@@ -237,6 +210,8 @@ struct bridge_iflist {
        uint32_t                bif_addrmax;    /* max # of addresses */
        uint32_t                bif_addrcnt;    /* cur. # of addresses */
        uint32_t                bif_addrexceeded;/* # of address violations */
+
+       struct epoch_context    bif_epoch_ctx;
 };
 
 /*
@@ -250,6 +225,9 @@ struct bridge_rtnode {
        uint8_t                 brt_flags;      /* address flags */
        uint8_t                 brt_addr[ETHER_ADDR_LEN];
        uint16_t                brt_vlan;       /* vlan id */
+
+       struct  vnet            *brt_vnet;
+       struct  epoch_context   brt_epoch_ctx;
 };
 #define        brt_ifp                 brt_dst->bif_ifp
 
@@ -260,13 +238,10 @@ struct bridge_softc {
        struct ifnet            *sc_ifp;        /* make this an interface */
        LIST_ENTRY(bridge_softc) sc_list;
        struct mtx              sc_mtx;
-       struct cv               sc_cv;
        uint32_t                sc_brtmax;      /* max # of addresses */
        uint32_t                sc_brtcnt;      /* cur. # of addresses */
        uint32_t                sc_brttimeout;  /* rt timeout in seconds */
        struct callout          sc_brcallout;   /* bridge callout */
-       uint32_t                sc_iflist_ref;  /* refcount for sc_iflist */
-       uint32_t                sc_iflist_xcnt; /* refcount for sc_iflist */
        CK_LIST_HEAD(, bridge_iflist) sc_iflist;        /* member interface 
list */
        CK_LIST_HEAD(, bridge_rtnode) *sc_rthash;       /* our forwarding table 
*/
        CK_LIST_HEAD(, bridge_rtnode) sc_rtlist;        /* list version of 
above */
@@ -276,6 +251,8 @@ struct bridge_softc {
        uint32_t                sc_brtexceeded; /* # of cache drops */
        struct ifnet            *sc_ifaddr;     /* member mac copied from */
        struct ether_addr       sc_defaddr;     /* Default MAC address */
+
+       struct epoch_context    sc_epoch_ctx;
 };
 
 VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx);
@@ -595,6 +572,11 @@ vnet_bridge_uninit(const void *unused __unused)
        if_clone_detach(V_bridge_cloner);
        V_bridge_cloner = NULL;
        BRIDGE_LIST_LOCK_DESTROY();
+
+       /* Before we can destroy the uma zone, because there are callbacks that
+        * use it. */
+       epoch_drain_callbacks(net_epoch_preempt);
+
        uma_zdestroy(V_bridge_rtnode_zone);
 }
 VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
@@ -757,6 +739,17 @@ bridge_clone_create(struct if_clone *ifc, int unit, ca
        return (0);
 }
 
+static void
+bridge_clone_destroy_cb(struct epoch_context *ctx)
+{
+       struct bridge_softc *sc;
+
+       sc = __containerof(ctx, struct bridge_softc, sc_epoch_ctx);
+
+       BRIDGE_LOCK_DESTROY(sc);
+       free(sc, M_DEVBUF);
+}
+
 /*
  * bridge_clone_destroy:
  *
@@ -767,7 +760,9 @@ bridge_clone_destroy(struct ifnet *ifp)
 {
        struct bridge_softc *sc = ifp->if_softc;
        struct bridge_iflist *bif;
+       struct epoch_tracker et;
 
+       NET_EPOCH_ENTER_ET(et);
        BRIDGE_LOCK(sc);
 
        bridge_stop(ifp, 1);
@@ -792,11 +787,12 @@ bridge_clone_destroy(struct ifnet *ifp)
        BRIDGE_LIST_UNLOCK();
 
        bstp_detach(&sc->sc_stp);
+       NET_EPOCH_EXIT_ET(et);
+
        ether_ifdetach(ifp);
        if_free(ifp);
 
-       BRIDGE_LOCK_DESTROY(sc);
-       free(sc, M_DEVBUF);
+       epoch_call(net_epoch_preempt, &sc->sc_epoch_ctx, 
bridge_clone_destroy_cb);
 }
 
 /*
@@ -822,7 +818,10 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t da
        struct ifdrv *ifd = (struct ifdrv *) data;
        const struct bridge_control *bc;
        int error = 0, oldmtu;
+       struct epoch_tracker et;
 
+       NET_EPOCH_ENTER_ET(et);
+
        switch (cmd) {
 
        case SIOCADDMULTI:
@@ -943,6 +942,8 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t da
                break;
        }
 
+       NET_EPOCH_EXIT_ET(et);
+
        return (error);
 }
 
@@ -957,6 +958,8 @@ bridge_mutecaps(struct bridge_softc *sc)
        struct bridge_iflist *bif;
        int enabled, mask;
 
+       BRIDGE_LOCK_ASSERT(sc);
+
        /* Initial bitmask of capabilities to test */
        mask = BRIDGE_IFCAPS_MASK;
 
@@ -965,7 +968,6 @@ bridge_mutecaps(struct bridge_softc *sc)
                mask &= bif->bif_savedcaps;
        }
 
-       BRIDGE_XLOCK(sc);
        CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                enabled = bif->bif_ifp->if_capenable;
                enabled &= ~BRIDGE_IFCAPS_STRIP;
@@ -976,8 +978,6 @@ bridge_mutecaps(struct bridge_softc *sc)
                bridge_set_ifcap(sc, bif, enabled);
                BRIDGE_LOCK(sc);
        }
-       BRIDGE_XDROP(sc);
-
 }
 
 static void
@@ -1018,7 +1018,7 @@ bridge_lookup_member(struct bridge_softc *sc, const ch
        struct bridge_iflist *bif;
        struct ifnet *ifp;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
 
        CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                ifp = bif->bif_ifp;
@@ -1039,7 +1039,7 @@ bridge_lookup_member_if(struct bridge_softc *sc, struc
 {
        struct bridge_iflist *bif;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
 
        CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                if (bif->bif_ifp == member_ifp)
@@ -1049,6 +1049,16 @@ bridge_lookup_member_if(struct bridge_softc *sc, struc
        return (NULL);
 }
 
+static void
+bridge_delete_member_cb(struct epoch_context *ctx)
+{
+       struct bridge_iflist *bif;
+
+       bif = __containerof(ctx, struct bridge_iflist, bif_epoch_ctx);
+
+       free(bif, M_DEVBUF);
+}
+
 /*
  * bridge_delete_member:
  *
@@ -1068,9 +1078,7 @@ bridge_delete_member(struct bridge_softc *sc, struct b
                bstp_disable(&bif->bif_stp);
 
        ifs->if_bridge = NULL;
-       BRIDGE_XLOCK(sc);
        CK_LIST_REMOVE(bif, bif_next);
-       BRIDGE_XDROP(sc);
 
        /*
         * If removing the interface that gave the bridge its mac address, set
@@ -1129,7 +1137,9 @@ bridge_delete_member(struct bridge_softc *sc, struct b
        }
        bstp_destroy(&bif->bif_stp);    /* prepare to free */
        BRIDGE_LOCK(sc);
-       free(bif, M_DEVBUF);
+
+       epoch_call(net_epoch_preempt, &bif->bif_epoch_ctx,
+           bridge_delete_member_cb);
 }
 
 /*
@@ -1146,7 +1156,9 @@ bridge_delete_span(struct bridge_softc *sc, struct bri
            ("%s: not a span interface", __func__));
 
        CK_LIST_REMOVE(bif, bif_next);
-       free(bif, M_DEVBUF);
+
+       epoch_call(net_epoch_preempt, &bif->bif_epoch_ctx,
+           bridge_delete_member_cb);
 }
 
 static int
@@ -1202,7 +1214,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
                 * If any, remove all inet6 addresses from the member
                 * interfaces.
                 */
-               BRIDGE_XLOCK(sc);
                CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                        if (in6ifa_llaonifp(bif->bif_ifp)) {
                                BRIDGE_UNLOCK(sc);
@@ -1215,7 +1226,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
                                    bif->bif_ifp->if_xname);
                        }
                }
-               BRIDGE_XDROP(sc);
                if (in6ifa_llaonifp(ifs)) {
                        BRIDGE_UNLOCK(sc);
                        in6_ifdetach(ifs);
@@ -1424,9 +1434,9 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
                bifc->ifbic_len = buflen;
                return (0);
        }
-       BRIDGE_UNLOCK(sc);
-       outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
-       BRIDGE_LOCK(sc);
+       outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO);
+       if (outbuf == NULL)
+               return (ENOMEM);
 
        count = 0;
        buf = outbuf;
@@ -1486,9 +1496,9 @@ bridge_ioctl_rts(struct bridge_softc *sc, void *arg)
                count++;
        buflen = sizeof(bareq) * count;
 
-       BRIDGE_UNLOCK(sc);
-       outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
-       BRIDGE_LOCK(sc);
+       outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO);
+       if (outbuf == NULL)
+               return (ENOMEM);
 
        count = 0;
        buf = outbuf;
@@ -1529,12 +1539,17 @@ bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif;
        int error;
 
+       MPASS(in_epoch(net_epoch_preempt));
+
        bif = bridge_lookup_member(sc, req->ifba_ifsname);
        if (bif == NULL)
                return (ENOENT);
 
+       /* bridge_rtupdate() may acquire the lock. */
+       BRIDGE_UNLOCK(sc);
        error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1,
            req->ifba_flags);
+       BRIDGE_LOCK(sc);
 
        return (error);
 }
@@ -1809,9 +1824,9 @@ bridge_ioctl_gifsstp(struct bridge_softc *sc, void *ar
                return (0);
        }
 
-       BRIDGE_UNLOCK(sc);
-       outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
-       BRIDGE_LOCK(sc);
+       outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO);
+       if (outbuf == NULL)
+               return (ENOMEM);
 
        count = 0;
        buf = outbuf;
@@ -1873,6 +1888,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
 {
        struct bridge_softc *sc = ifp->if_bridge;
        struct bridge_iflist *bif;
+       struct epoch_tracker et;
 
        if (ifp->if_flags & IFF_RENAMING)
                return;
@@ -1883,6 +1899,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
                 */
                return;
        }
+       NET_EPOCH_ENTER_ET(et);
        /* Check if the interface is a bridge member */
        if (sc != NULL) {
                BRIDGE_LOCK(sc);
@@ -1892,6 +1909,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
                        bridge_delete_member(sc, bif, 1);
 
                BRIDGE_UNLOCK(sc);
+               NET_EPOCH_EXIT_ET(et);
                return;
        }
 
@@ -1908,6 +1926,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp)
                BRIDGE_UNLOCK(sc);
        }
        BRIDGE_LIST_UNLOCK();
+       NET_EPOCH_EXIT_ET(et);
 }
 
 /*
@@ -2062,23 +2081,26 @@ static int
 bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
     struct rtentry *rt)
 {
+       struct epoch_tracker et;
        struct ether_header *eh;
        struct ifnet *dst_if;
        struct bridge_softc *sc;
        uint16_t vlan;
 
+       NET_EPOCH_ENTER_ET(et);
+
        if (m->m_len < ETHER_HDR_LEN) {
                m = m_pullup(m, ETHER_HDR_LEN);
-               if (m == NULL)
+               if (m == NULL) {
+                       NET_EPOCH_EXIT_ET(et);
                        return (0);
+               }
        }
 
        eh = mtod(m, struct ether_header *);
        sc = ifp->if_bridge;
        vlan = VLANTAGOF(m);
 
-       BRIDGE_LOCK(sc);
-
        /*
         * If bridge is down, but the original output interface is up,
         * go ahead and send out that interface.  Otherwise, the packet
@@ -2100,16 +2122,10 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struc
        if (dst_if == NULL) {
                struct bridge_iflist *bif;
                struct mbuf *mc;
-               int error = 0, used = 0;
+               int used = 0;
 
                bridge_span(sc, m);
 
-               BRIDGE_LOCK2REF(sc, error);
-               if (error) {
-                       m_freem(m);
-                       return (0);
-               }
-
                CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
                        dst_if = bif->bif_ifp;
 
@@ -2143,7 +2159,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struc
                }
                if (used == 0)
                        m_freem(m);
-               BRIDGE_UNREF(sc);
+               NET_EPOCH_EXIT_ET(et);
                return (0);
        }
 
@@ -2155,12 +2171,12 @@ sendunicast:
        bridge_span(sc, m);
        if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                m_freem(m);
-               BRIDGE_UNLOCK(sc);
+               NET_EPOCH_EXIT_ET(et);
                return (0);
        }
 
-       BRIDGE_UNLOCK(sc);
        bridge_enqueue(sc, dst_if, m);
+       NET_EPOCH_EXIT_ET(et);
        return (0);
 }
 
@@ -2173,25 +2189,28 @@ sendunicast:
 static int
 bridge_transmit(struct ifnet *ifp, struct mbuf *m)
 {
+       struct epoch_tracker et;
        struct bridge_softc *sc;
        struct ether_header *eh;
        struct ifnet *dst_if;
        int error = 0;
 
+       NET_EPOCH_ENTER_ET(et);
+
        sc = ifp->if_softc;
 
        ETHER_BPF_MTAP(ifp, m);
 
        eh = mtod(m, struct ether_header *);
 
-       BRIDGE_LOCK(sc);
        if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) &&
            (dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1)) != NULL) {
-               BRIDGE_UNLOCK(sc);
                error = bridge_enqueue(sc, dst_if, m);
        } else
                bridge_broadcast(sc, ifp, m, 0);
 
+       NET_EPOCH_EXIT_ET(et);
+
        return (error);
 }
 
@@ -2221,6 +2240,8 @@ bridge_forward(struct bridge_softc *sc, struct bridge_
        uint8_t *dst;
        int error;
 
+       MPASS(in_epoch(net_epoch_preempt));
+
        src_if = m->m_pkthdr.rcvif;
        ifp = sc->sc_ifp;
 
@@ -2299,12 +2320,10 @@ bridge_forward(struct bridge_softc *sc, struct bridge_
            || PFIL_HOOKED(&V_inet6_pfil_hook)
 #endif
            ) {
-               BRIDGE_UNLOCK(sc);
                if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
                        return;
                if (m == NULL)
                        return;
-               BRIDGE_LOCK(sc);
        }
 
        if (dst_if == NULL) {
@@ -2332,8 +2351,6 @@ bridge_forward(struct bridge_softc *sc, struct bridge_
            dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
                goto drop;
 
-       BRIDGE_UNLOCK(sc);
-
        if (PFIL_HOOKED(&V_inet_pfil_hook)
 #ifdef INET6
            || PFIL_HOOKED(&V_inet6_pfil_hook)
@@ -2349,7 +2366,6 @@ bridge_forward(struct bridge_softc *sc, struct bridge_
        return;
 
 drop:
-       BRIDGE_UNLOCK(sc);
        m_freem(m);
 }
 
@@ -2362,6 +2378,7 @@ drop:
 static struct mbuf *
 bridge_input(struct ifnet *ifp, struct mbuf *m)
 {
+       struct epoch_tracker et;
        struct bridge_softc *sc = ifp->if_bridge;
        struct bridge_iflist *bif, *bif2;
        struct ifnet *bifp;
@@ -2370,8 +2387,12 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
        uint16_t vlan;
        int error;
 
-       if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+       NET_EPOCH_ENTER_ET(et);
+
+       if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+               NET_EPOCH_EXIT_ET(et);
                return (m);
+       }
 
        bifp = sc->sc_ifp;
        vlan = VLANTAGOF(m);
@@ -2388,12 +2409,12 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1);
                if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
                m_freem(m);
+               NET_EPOCH_EXIT_ET(et);
                return (NULL);
        }
-       BRIDGE_LOCK(sc);
        bif = bridge_lookup_member_if(sc, ifp);
        if (bif == NULL) {
-               BRIDGE_UNLOCK(sc);
+               NET_EPOCH_EXIT_ET(et);
                return (m);
        }
 
@@ -2406,13 +2427,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                if (memcmp(eh->ether_dhost, bstp_etheraddr,
                    ETHER_ADDR_LEN) == 0) {
                        bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */
-                       BRIDGE_UNLOCK(sc);
+                       NET_EPOCH_EXIT_ET(et);
                        return (NULL);
                }
 
                if ((bif->bif_flags & IFBIF_STP) &&
                    bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
-                       BRIDGE_UNLOCK(sc);
+                       NET_EPOCH_EXIT_ET(et);
                        return (m);
                }
 
@@ -2423,7 +2444,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                 */
                mc = m_dup(m, M_NOWAIT);
                if (mc == NULL) {
-                       BRIDGE_UNLOCK(sc);
+                       NET_EPOCH_EXIT_ET(et);
                        return (m);
                }
 
@@ -2450,12 +2471,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                }
 
                /* Return the original packet for local processing. */
+               NET_EPOCH_EXIT_ET(et);
                return (m);
        }
 
        if ((bif->bif_flags & IFBIF_STP) &&
            bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
-               BRIDGE_UNLOCK(sc);
+               NET_EPOCH_EXIT_ET(et);
                return (m);
        }
 
@@ -2495,7 +2517,6 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                             OR_PFIL_HOOKED_INET6)) {                   \
                                if (bridge_pfil(&m, NULL, ifp,          \
                                    PFIL_IN) != 0 || m == NULL) {       \
-                                       BRIDGE_UNLOCK(sc);              \
                                        return (NULL);                  \
                                }                                       \
                                eh = mtod(m, struct ether_header *);    \
@@ -2505,13 +2526,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
                        error = bridge_rtupdate(sc, eh->ether_shost,    \
                            vlan, bif, 0, IFBAF_DYNAMIC);               \
                        if (error && bif->bif_addrmax) {                \
-                               BRIDGE_UNLOCK(sc);                      \
                                m_freem(m);                             \
+                               NET_EPOCH_EXIT_ET(et);                  \
                                return (NULL);                          \
                        }                                               \
                }                                                       \
                m->m_pkthdr.rcvif = iface;                              \
-               BRIDGE_UNLOCK(sc);                                      \
+               NET_EPOCH_EXIT_ET(et);                                  \
                return (m);                                             \
        }                                                               \
                                                                        \
@@ -2519,8 +2540,8 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
        if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \
            OR_CARP_CHECK_WE_ARE_SRC((iface))                   \
            ) {                                                         \
-               BRIDGE_UNLOCK(sc);                                      \
                m_freem(m);                                             \
+               NET_EPOCH_EXIT_ET(et);                                  \
                return (NULL);                                          \
        }
 
@@ -2551,6 +2572,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
        /* Perform the bridge forwarding function. */
        bridge_forward(sc, bif, m);
 
+       NET_EPOCH_EXIT_ET(et);
        return (NULL);
 }
 
@@ -2570,16 +2592,12 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet
        struct bridge_iflist *dbif, *sbif;
        struct mbuf *mc;
        struct ifnet *dst_if;
-       int error = 0, used = 0, i;
+       int used = 0, i;
 
+       MPASS(in_epoch(net_epoch_preempt));
+
        sbif = bridge_lookup_member_if(sc, src_if);
 
-       BRIDGE_LOCK2REF(sc, error);
-       if (error) {
-               m_freem(m);
-               return;
-       }
-
        /* Filter on the bridge interface before broadcasting */
        if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
 #ifdef INET6
@@ -2587,9 +2605,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet
 #endif
            )) {
                if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0)
-                       goto out;
+                       return;
                if (m == NULL)
-                       goto out;
+                       return;
        }
 
        CK_LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) {
@@ -2652,9 +2670,6 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet
        }
        if (used == 0)
                m_freem(m);
-
-out:
-       BRIDGE_UNREF(sc);
 }
 
 /*
@@ -2670,6 +2685,8 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
        struct ifnet *dst_if;
        struct mbuf *mc;
 
+       MPASS(in_epoch(net_epoch_preempt));
+
        if (CK_LIST_EMPTY(&sc->sc_spanlist))
                return;
 
@@ -2701,7 +2718,8 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
        struct bridge_rtnode *brt;
        int error;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
+       BRIDGE_UNLOCK_ASSERT(sc);
 
        /* Check the source address is valid and not multicast. */
        if (ETHER_IS_MULTICAST(dst) ||
@@ -2718,13 +2736,24 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
         * update it, otherwise create a new one.
         */
        if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) {
+               BRIDGE_LOCK(sc);
+
+               /* Check again, now that we have the lock. There could have
+                * been a race and we only want to insert this once. */
+               if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) != NULL) {
+                       BRIDGE_UNLOCK(sc);
+                       return (0);
+               }
+
                if (sc->sc_brtcnt >= sc->sc_brtmax) {
                        sc->sc_brtexceeded++;
+                       BRIDGE_UNLOCK(sc);
                        return (ENOSPC);
                }
                /* Check per interface address limits (if enabled) */
                if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) {
                        bif->bif_addrexceeded++;
+                       BRIDGE_UNLOCK(sc);
                        return (ENOSPC);
                }
 
@@ -2734,8 +2763,11 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
                 * address.
                 */
                brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
-               if (brt == NULL)
+               if (brt == NULL) {
+                       BRIDGE_UNLOCK(sc);
                        return (ENOMEM);
+               }
+               brt->brt_vnet = curvnet;
 
                if (bif->bif_flags & IFBIF_STICKY)
                        brt->brt_flags = IFBAF_STICKY;
@@ -2747,17 +2779,22 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t
 
                if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
                        uma_zfree(V_bridge_rtnode_zone, brt);
+                       BRIDGE_UNLOCK(sc);
                        return (error);
                }
                brt->brt_dst = bif;
                bif->bif_addrcnt++;
+
+               BRIDGE_UNLOCK(sc);
        }
 
        if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC &&
            brt->brt_dst != bif) {
+               BRIDGE_LOCK(sc);
                brt->brt_dst->bif_addrcnt--;
                brt->brt_dst = bif;
                brt->brt_dst->bif_addrcnt++;
+               BRIDGE_UNLOCK(sc);
        }
 
        if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
@@ -2778,7 +2815,7 @@ bridge_rtlookup(struct bridge_softc *sc, const uint8_t
 {
        struct bridge_rtnode *brt;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
 
        if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL)
                return (NULL);
@@ -3017,7 +3054,7 @@ bridge_rtnode_lookup(struct bridge_softc *sc, const ui
        uint32_t hash;
        int dir;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
 
        hash = bridge_rthash(sc, addr);
        CK_LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
@@ -3080,6 +3117,18 @@ out:
        return (0);
 }
 
+static void
+bridge_rtnode_destroy_cb(struct epoch_context *ctx)
+{
+       struct bridge_rtnode *brt;
+
+       brt = __containerof(ctx, struct bridge_rtnode, brt_epoch_ctx);
+
+       CURVNET_SET(brt->brt_vnet);
+       uma_zfree(V_bridge_rtnode_zone, brt);
+       CURVNET_RESTORE();
+}
+
 /*
  * bridge_rtnode_destroy:
  *
@@ -3095,7 +3144,9 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct 
        CK_LIST_REMOVE(brt, brt_list);
        sc->sc_brtcnt--;
        brt->brt_dst->bif_addrcnt--;
-       uma_zfree(V_bridge_rtnode_zone, brt);
+
+       epoch_call(net_epoch_preempt, &brt->brt_epoch_ctx,
+           bridge_rtnode_destroy_cb);
 }
 
 /*
@@ -3640,17 +3691,20 @@ bridge_linkstate(struct ifnet *ifp)
 {
        struct bridge_softc *sc = ifp->if_bridge;
        struct bridge_iflist *bif;
+       struct epoch_tracker et;
 
-       BRIDGE_LOCK(sc);
+       NET_EPOCH_ENTER_ET(et);
+
        bif = bridge_lookup_member_if(sc, ifp);
        if (bif == NULL) {
-               BRIDGE_UNLOCK(sc);
+               NET_EPOCH_EXIT_ET(et);
                return;
        }
        bridge_linkcheck(sc);
-       BRIDGE_UNLOCK(sc);
 
        bstp_linkstate(&bif->bif_stp);
+
+       NET_EPOCH_EXIT_ET(et);
 }
 
 static void
@@ -3659,7 +3713,8 @@ bridge_linkcheck(struct bridge_softc *sc)
        struct bridge_iflist *bif;
        int new_link, hasls;
 
-       BRIDGE_LOCK_ASSERT(sc);
+       MPASS(in_epoch(net_epoch_preempt));
+
        new_link = LINK_STATE_DOWN;
        hasls = 0;
        /* Our link is considered up if at least one of our ports is active */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to