git: c1241c6e30c7 - main - pf: modify pfik_flags atomically

From: R. Christian McDonald <rcm_at_FreeBSD.org>
Date: Wed, 30 Sep 2026 23:19:03 UTC
The branch main has been updated by rcm:

URL: https://cgit.FreeBSD.org/src/commit/?id=c1241c6e30c792fb514f4689d2ed92ee21d3cf39

commit c1241c6e30c792fb514f4689d2ed92ee21d3cf39
Author:     R. Christian McDonald <rcm@FreeBSD.org>
AuthorDate: 2026-09-30 22:56:22 +0000
Commit:     R. Christian McDonald <rcm@FreeBSD.org>
CommitDate: 2026-09-30 22:56:22 +0000

    pf: modify pfik_flags atomically
    
    The purge thread sets PFI_IFLAG_REFS on the interfaces that states
    refer to without the rules lock, under which the other flags are
    changed. The updates can interleave, so that a "set skip on" is lost,
    or outlives its removal, until the next ruleset load.
    
    Use atomic operations to modify the flags. In the purge thread, only
    write if the flag is not already set.
    
    Reviewed by:            kp
    Approved by:            kp (mentor)
    MFC after:              1 week
    Sponsored by:           Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D60107
---
 sys/netpfil/pf/pf.c    | 12 ++++++++++--
 sys/netpfil/pf/pf_if.c | 10 +++++-----
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 9c9509900ea9..73e6900ec6eb 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -3223,6 +3223,14 @@ pf_free_state(struct pf_kstate *cur)
 	pf_counter_u64_add(&V_pf_status.fcounters[FCNT_STATE_REMOVALS], 1);
 }
 
+static inline void
+pf_kkif_mark(struct pfi_kkif *kif)
+{
+
+	if ((atomic_load_int(&kif->pfik_flags) & PFI_IFLAG_REFS) == 0)
+		atomic_set_int(&kif->pfik_flags, PFI_IFLAG_REFS);
+}
+
 /*
  * Called only from pf_purge_thread(), thus serialized.
  */
@@ -3258,11 +3266,11 @@ relock:
 					s->nat_rule->rule_ref |= PFRULE_REFS;
 				if (s->anchor != NULL)
 					s->anchor->rule_ref |= PFRULE_REFS;
-				s->kif->pfik_flags |= PFI_IFLAG_REFS;
+				pf_kkif_mark(s->kif);
 				SLIST_FOREACH(mrm, &s->match_rules, entry)
 					mrm->r->rule_ref |= PFRULE_REFS;
 				if (s->act.rt_kif)
-					s->act.rt_kif->pfik_flags |= PFI_IFLAG_REFS;
+					pf_kkif_mark(s->act.rt_kif);
 				count++;
 			}
 			PF_HASHROW_UNLOCK(ih);
diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c
index aed1af15fb30..7528e920e433 100644
--- a/sys/netpfil/pf/pf_if.c
+++ b/sys/netpfil/pf/pf_if.c
@@ -426,7 +426,7 @@ pfi_kkif_remove_if_unref(struct pfi_kkif *kif)
 	}
 	RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif);
 
-	kif->pfik_flags |= PFI_IFLAG_REFS;
+	atomic_set_int(&kif->pfik_flags, PFI_IFLAG_REFS);
 
 	mtx_lock(&pfi_unlnkdkifs_mtx);
 	LIST_INSERT_HEAD(&V_pfi_unlinked_kifs, kif, pfik_list);
@@ -460,7 +460,7 @@ pfi_kkif_purge(void)
 			LIST_REMOVE(kif, pfik_list);
 			pf_kkif_free(kif);
 		} else
-			kif->pfik_flags &= ~PFI_IFLAG_REFS;
+			atomic_clear_int(&kif->pfik_flags, PFI_IFLAG_REFS);
 	}
 	mtx_unlock(&pfi_unlnkdkifs_mtx);
 }
@@ -660,7 +660,7 @@ pfi_kkif_update(struct pfi_kkif *kif)
 			if (tmpkif == NULL)
 				continue;
 
-			tmpkif->pfik_flags |= kif->pfik_flags;
+			atomic_set_int(&tmpkif->pfik_flags, kif->pfik_flags);
 		}
 	}
 
@@ -1018,7 +1018,7 @@ pfi_set_flags(const char *name, int flags)
 	RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) {
 		if (pfi_skip_if(name, p))
 			continue;
-		p->pfik_flags |= flags;
+		atomic_set_int(&p->pfik_flags, flags);
 	}
 	NET_EPOCH_EXIT(et);
 	return (0);
@@ -1034,7 +1034,7 @@ pfi_clear_flags(const char *name, int flags)
 	RB_FOREACH_SAFE(p, pfi_ifhead, &V_pfi_ifs, tmp) {
 		if (pfi_skip_if(name, p))
 			continue;
-		p->pfik_flags &= ~flags;
+		atomic_clear_int(&p->pfik_flags, flags);
 
 		if (p->pfik_ifp == NULL && p->pfik_group == NULL &&
 		    p->pfik_flags == 0 && p->pfik_rulerefs == 0) {