Hello,

On Tue, Jul 06, 2021 at 10:25:31PM +0200, Alexander Bluhm wrote:
> On Tue, Jul 06, 2021 at 04:02:58PM +0200, Alexandr Nedvedicky wrote:
> >     diff below moves call to pfsync_undefer() to pf_test(). The
> >     pfsync_undefer() will get called _after_ we drop PF_LOCK().
> >     diff below still needs OKs to get committed.
> 
> Could you please replace the void pointer with struct pfsync_deferral ?
> This avoids a cast, see below.
> 
> otherwise OK bluhm@
> 

    earlier diff got updated by change requested by bluhm@:

--------8<---------------8<---------------8<------------------8<--------
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 0672f5f6992..24f51d03d0c 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -99,6 +99,8 @@
 
 #if NPFSYNC > 0
 #include <net/if_pfsync.h>
+#else
+struct pfsync_deferral;
 #endif /* NPFSYNC > 0 */
 
 #ifdef DDB
@@ -195,7 +197,7 @@ void                         pf_rule_to_actions(struct 
pf_rule *,
 int                     pf_test_rule(struct pf_pdesc *, struct pf_rule **,
                            struct pf_state **, struct pf_rule **,
                            struct pf_ruleset **, u_short *,
-                           void **);
+                           struct pfsync_deferral **);
 static __inline int     pf_create_state(struct pf_pdesc *, struct pf_rule *,
                            struct pf_rule *, struct pf_rule *,
                            struct pf_state_key **, struct pf_state_key **,
@@ -3810,7 +3812,7 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset 
*ruleset)
 int
 pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, struct pf_state **sm,
     struct pf_rule **am, struct pf_ruleset **rsm, u_short *reason,
-    void **pdeferral)
+    struct pfsync_deferral **pdeferral)
 {
        struct pf_rule          *r = NULL;
        struct pf_rule          *a = NULL;
@@ -6893,7 +6895,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
        int                      dir = (fwdir == PF_FWD) ? PF_OUT : fwdir;
        u_int32_t                qid, pqid = 0;
        int                      have_pf_lock = 0;
-       void                    *deferral = NULL;
+       struct pfsync_deferral  *deferral = NULL;
 
        if (!pf_status.running)
                return (PF_PASS);
--------8<---------------8<---------------8<------------------8<--------

    chunk above makes sure struct pfsync_deferral is always declared. so code
    also compiles, when building _without_ pfsync.

    updated diff is attached.

thanks and
regards
sashan
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index 744a7ca9dbc..11b4e3f1f2f 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -1931,7 +1931,7 @@ pfsync_insert_state(struct pf_state *st)
 }
 
 int
-pfsync_defer(struct pf_state *st, struct mbuf *m)
+pfsync_defer(struct pf_state *st, struct mbuf *m, struct pfsync_deferral **ppd)
 {
        struct pfsync_softc *sc = pfsyncif;
        struct pfsync_deferral *pd;
@@ -1944,21 +1944,30 @@ pfsync_defer(struct pf_state *st, struct mbuf *m)
            m->m_flags & (M_BCAST|M_MCAST))
                return (0);
 
+       pd = pool_get(&sc->sc_pool, M_NOWAIT);
+       if (pd == NULL)
+               return (0);
+
+       /*
+        * deferral queue grows faster, than timeout can consume,
+        * we have to ask packet (caller) to help timer and dispatch
+        * one deferral for us.
+        *
+        * We wish to call pfsync_undefer() here. Unfortunately we can't,
+        * because pfsync_undefer() will be calling to ip_output(),
+        * which in turn will call to pf_test(), which would then attempt
+        * to grab PF_LOCK() we currently hold.
+        */
        if (sc->sc_deferred >= 128) {
                mtx_enter(&sc->sc_deferrals_mtx);
-               pd = TAILQ_FIRST(&sc->sc_deferrals);
-               if (pd != NULL) {
-                       TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry);
+               *ppd = TAILQ_FIRST(&sc->sc_deferrals);
+               if (*ppd != NULL) {
+                       TAILQ_REMOVE(&sc->sc_deferrals, *ppd, pd_entry);
                        sc->sc_deferred--;
                }
                mtx_leave(&sc->sc_deferrals_mtx);
-               if (pd != NULL)
-                       pfsync_undefer(pd, 0);
-       }
-
-       pd = pool_get(&sc->sc_pool, M_NOWAIT);
-       if (pd == NULL)
-               return (0);
+       } else
+               *ppd = NULL;
 
        m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
        SET(st->state_flags, PFSTATE_ACK);
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index 2520c87a36c..037219537e8 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -297,6 +297,8 @@ enum pfsync_counters {
 
 extern struct cpumem *pfsynccounters;
 
+struct pfsync_deferral;
+
 static inline void
 pfsyncstat_inc(enum pfsync_counters c)
 {
@@ -335,7 +337,9 @@ void                        pfsync_clear_states(u_int32_t, 
const char *);
 void                   pfsync_update_tdb(struct tdb *, int);
 void                   pfsync_delete_tdb(struct tdb *);
 
-int                    pfsync_defer(struct pf_state *, struct mbuf *);
+int                    pfsync_defer(struct pf_state *, struct mbuf *,
+                           struct pfsync_deferral **);
+void                   pfsync_undefer(struct pfsync_deferral *, int);
 
 int                    pfsync_up(void);
 int                    pfsync_state_in_use(struct pf_state *);
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 672f4159719..24f51d03d0c 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -99,6 +99,8 @@
 
 #if NPFSYNC > 0
 #include <net/if_pfsync.h>
+#else
+struct pfsync_deferral;
 #endif /* NPFSYNC > 0 */
 
 #ifdef DDB
@@ -194,7 +196,8 @@ void                         pf_rule_to_actions(struct 
pf_rule *,
                            struct pf_rule_actions *);
 int                     pf_test_rule(struct pf_pdesc *, struct pf_rule **,
                            struct pf_state **, struct pf_rule **,
-                           struct pf_ruleset **, u_short *);
+                           struct pf_ruleset **, u_short *,
+                           struct pfsync_deferral **);
 static __inline int     pf_create_state(struct pf_pdesc *, struct pf_rule *,
                            struct pf_rule *, struct pf_rule *,
                            struct pf_state_key **, struct pf_state_key **,
@@ -3808,7 +3811,8 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset 
*ruleset)
 
 int
 pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, struct pf_state **sm,
-    struct pf_rule **am, struct pf_ruleset **rsm, u_short *reason)
+    struct pf_rule **am, struct pf_ruleset **rsm, u_short *reason,
+    struct pfsync_deferral **pdeferral)
 {
        struct pf_rule          *r = NULL;
        struct pf_rule          *a = NULL;
@@ -4041,7 +4045,8 @@ pf_test_rule(struct pf_pdesc *pd, struct pf_rule **rm, 
struct pf_state **sm,
                 * firewall has to know about it to allow
                 * replies through it.
                 */
-               if (pfsync_defer(*sm, pd->m))
+               if (pfsync_defer(*sm, pd->m,
+                   (struct pfsync_deferral **)pdeferral))
                        return (PF_DEFER);
        }
 #endif /* NPFSYNC > 0 */
@@ -6890,6 +6895,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
        int                      dir = (fwdir == PF_FWD) ? PF_OUT : fwdir;
        u_int32_t                qid, pqid = 0;
        int                      have_pf_lock = 0;
+       struct pfsync_deferral  *deferral = NULL;
 
        if (!pf_status.running)
                return (PF_PASS);
@@ -6992,7 +6998,8 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
                 */
                PF_LOCK();
                have_pf_lock = 1;
-               action = pf_test_rule(&pd, &r, &s, &a, &ruleset, &reason);
+               action = pf_test_rule(&pd, &r, &s, &a, &ruleset, &reason,
+                   &deferral);
                s = pf_state_ref(s);
                if (action != PF_PASS)
                        REASON_SET(&reason, PFRES_FRAG);
@@ -7024,7 +7031,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
                        PF_LOCK();
                        have_pf_lock = 1;
                        action = pf_test_rule(&pd, &r, &s, &a, &ruleset,
-                           &reason);
+                           &reason, &deferral);
                        s = pf_state_ref(s);
                }
                break;
@@ -7056,7 +7063,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
                        PF_LOCK();
                        have_pf_lock = 1;
                        action = pf_test_rule(&pd, &r, &s, &a, &ruleset,
-                           &reason);
+                           &reason, &deferral);
                        s = pf_state_ref(s);
                }
                break;
@@ -7132,7 +7139,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, 
struct mbuf **m0)
                        PF_LOCK();
                        have_pf_lock = 1;
                        action = pf_test_rule(&pd, &r, &s, &a, &ruleset,
-                           &reason);
+                           &reason, &deferral);
                        s = pf_state_ref(s);
                }
 
@@ -7268,6 +7275,14 @@ done:
                m_freem(pd.m);
                /* FALLTHROUGH */
        case PF_DEFER:
+#if NPFSYNC > 0
+               /*
+                * We no longer hold PF_LOCK() here, so we can dispatch
+                * deferral if we are asked to do so.
+                */
+               if (deferral != NULL)
+                       pfsync_undefer(deferral, 0);
+#endif /* NPFSYNC > 0 */
                pd.m = NULL;
                action = PF_PASS;
                break;

Reply via email to