summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_pfsync.c97
-rw-r--r--sys/net/pfvar.h4
-rw-r--r--sys/netinet/ip_ipsp.h4
3 files changed, 77 insertions, 28 deletions
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index fb28da1295d..c78ca62766e 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.c,v 1.304 2022/04/20 20:51:09 bluhm Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.305 2022/04/21 15:22:49 sashan Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -181,6 +181,7 @@ void pfsync_q_del(struct pf_state *);
struct pfsync_upd_req_item {
TAILQ_ENTRY(pfsync_upd_req_item) ur_entry;
+ TAILQ_ENTRY(pfsync_upd_req_item) ur_snap;
struct pfsync_upd_req ur_msg;
};
TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item);
@@ -295,7 +296,7 @@ void pfsync_bulk_update(void *);
void pfsync_bulk_fail(void *);
void pfsync_grab_snapshot(struct pfsync_snapshot *, struct pfsync_softc *);
-void pfsync_drop_snapshot(struct pfsync_snapshot *, struct pfsync_softc *);
+void pfsync_drop_snapshot(struct pfsync_snapshot *);
void pfsync_send_dispatch(void *);
void pfsync_send_pkt(struct mbuf *);
@@ -422,8 +423,7 @@ pfsync_clone_destroy(struct ifnet *ifp)
sc->sc_deferred = 0;
mtx_leave(&sc->sc_deferrals_mtx);
- while (!TAILQ_EMPTY(&deferrals)) {
- pd = TAILQ_FIRST(&deferrals);
+ while ((pd = TAILQ_FIRST(&deferrals)) != NULL) {
TAILQ_REMOVE(&deferrals, pd, pd_entry);
pfsync_undefer(pd, 0);
}
@@ -1574,6 +1574,9 @@ void
pfsync_grab_snapshot(struct pfsync_snapshot *sn, struct pfsync_softc *sc)
{
int q;
+ struct pf_state *st;
+ struct pfsync_upd_req_item *ur;
+ struct tdb *tdb;
sn->sn_sc = sc;
@@ -1583,14 +1586,31 @@ pfsync_grab_snapshot(struct pfsync_snapshot *sn, struct pfsync_softc *sc)
for (q = 0; q < PFSYNC_S_COUNT; q++) {
TAILQ_INIT(&sn->sn_qs[q]);
- TAILQ_CONCAT(&sn->sn_qs[q], &sc->sc_qs[q], sync_list);
+
+ while ((st = TAILQ_FIRST(&sc->sc_qs[q])) != NULL) {
+ KASSERT(st->snapped == 0);
+ TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
+ TAILQ_INSERT_TAIL(&sn->sn_qs[q], st, sync_snap);
+ st->snapped = 1;
+ }
}
TAILQ_INIT(&sn->sn_upd_req_list);
- TAILQ_CONCAT(&sn->sn_upd_req_list, &sc->sc_upd_req_list, ur_entry);
+ while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
+ TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
+ TAILQ_INSERT_TAIL(&sn->sn_upd_req_list, ur, ur_snap);
+ }
TAILQ_INIT(&sn->sn_tdb_q);
- TAILQ_CONCAT(&sn->sn_tdb_q, &sc->sc_tdb_q, tdb_sync_entry);
+ while ((tdb = TAILQ_FIRST(&sc->sc_tdb_q)) != NULL) {
+ TAILQ_REMOVE(&sc->sc_tdb_q, tdb, tdb_sync_entry);
+ TAILQ_INSERT_TAIL(&sn->sn_tdb_q, tdb, tdb_sync_snap);
+
+ mtx_enter(&tdb->tdb_mtx);
+ KASSERT(!ISSET(tdb->tdb_flags, TDBF_PFSYNC_SNAPPED));
+ SET(tdb->tdb_flags, TDBF_PFSYNC_SNAPPED);
+ mtx_leave(&tdb->tdb_mtx);
+ }
sn->sn_len = sc->sc_len;
sc->sc_len = PFSYNC_MINPKT;
@@ -1606,39 +1626,40 @@ pfsync_grab_snapshot(struct pfsync_snapshot *sn, struct pfsync_softc *sc)
}
void
-pfsync_drop_snapshot(struct pfsync_snapshot *sn, struct pfsync_softc * sc)
+pfsync_drop_snapshot(struct pfsync_snapshot *sn)
{
struct pf_state *st;
struct pfsync_upd_req_item *ur;
struct tdb *t;
int q;
-
for (q = 0; q < PFSYNC_S_COUNT; q++) {
if (TAILQ_EMPTY(&sn->sn_qs[q]))
continue;
while ((st = TAILQ_FIRST(&sn->sn_qs[q])) != NULL) {
- TAILQ_REMOVE(&sn->sn_qs[q], st, sync_list);
KASSERT(st->sync_state == q);
+ KASSERT(st->snapped == 1);
+ TAILQ_REMOVE(&sn->sn_qs[q], st, sync_snap);
st->sync_state = PFSYNC_S_NONE;
+ st->snapped = 0;
pf_state_unref(st);
}
}
while ((ur = TAILQ_FIRST(&sn->sn_upd_req_list)) != NULL) {
- TAILQ_REMOVE(&sn->sn_upd_req_list, ur, ur_entry);
+ TAILQ_REMOVE(&sn->sn_upd_req_list, ur, ur_snap);
pool_put(&sn->sn_sc->sc_pool, ur);
}
- mtx_enter(&sc->sc_tdb_mtx);
while ((t = TAILQ_FIRST(&sn->sn_tdb_q)) != NULL) {
- TAILQ_REMOVE(&sn->sn_tdb_q, t, tdb_sync_entry);
+ TAILQ_REMOVE(&sn->sn_tdb_q, t, tdb_sync_snap);
mtx_enter(&t->tdb_mtx);
+ KASSERT(ISSET(t->tdb_flags, TDBF_PFSYNC_SNAPPED));
+ CLR(t->tdb_flags, TDBF_PFSYNC_SNAPPED);
CLR(t->tdb_flags, TDBF_PFSYNC);
mtx_leave(&t->tdb_mtx);
}
- mtx_leave(&sc->sc_tdb_mtx);
}
int
@@ -1665,7 +1686,7 @@ pfsync_drop(struct pfsync_softc *sc)
struct pfsync_snapshot sn;
pfsync_grab_snapshot(&sn, sc);
- pfsync_drop_snapshot(&sn, sc);
+ pfsync_drop_snapshot(&sn);
}
void
@@ -1757,7 +1778,7 @@ pfsync_sendout(void)
if (m == NULL) {
sc->sc_if.if_oerrors++;
pfsyncstat_inc(pfsyncs_onomem);
- pfsync_drop_snapshot(&sn, sc);
+ pfsync_drop_snapshot(&sn);
return;
}
@@ -1767,7 +1788,7 @@ pfsync_sendout(void)
m_free(m);
sc->sc_if.if_oerrors++;
pfsyncstat_inc(pfsyncs_onomem);
- pfsync_drop_snapshot(&sn, sc);
+ pfsync_drop_snapshot(&sn);
return;
}
}
@@ -1797,7 +1818,7 @@ pfsync_sendout(void)
count = 0;
while ((ur = TAILQ_FIRST(&sn.sn_upd_req_list)) != NULL) {
- TAILQ_REMOVE(&sn.sn_upd_req_list, ur, ur_entry);
+ TAILQ_REMOVE(&sn.sn_upd_req_list, ur, ur_snap);
bcopy(&ur->ur_msg, m->m_data + offset,
sizeof(ur->ur_msg));
@@ -1825,18 +1846,19 @@ pfsync_sendout(void)
subh = (struct pfsync_subheader *)(m->m_data + offset);
offset += sizeof(*subh);
- mtx_enter(&sc->sc_tdb_mtx);
count = 0;
while ((t = TAILQ_FIRST(&sn.sn_tdb_q)) != NULL) {
- TAILQ_REMOVE(&sn.sn_tdb_q, t, tdb_sync_entry);
+ TAILQ_REMOVE(&sn.sn_tdb_q, t, tdb_sync_snap);
pfsync_out_tdb(t, m->m_data + offset);
offset += sizeof(struct pfsync_tdb);
mtx_enter(&t->tdb_mtx);
+ KASSERT(ISSET(t->tdb_flags, TDBF_PFSYNC_SNAPPED));
+ CLR(t->tdb_flags, TDBF_PFSYNC_SNAPPED);
CLR(t->tdb_flags, TDBF_PFSYNC);
mtx_leave(&t->tdb_mtx);
+ tdb_unref(t);
count++;
}
- mtx_leave(&sc->sc_tdb_mtx);
bzero(subh, sizeof(*subh));
subh->action = PFSYNC_ACT_TDB;
@@ -1854,9 +1876,11 @@ pfsync_sendout(void)
count = 0;
while ((st = TAILQ_FIRST(&sn.sn_qs[q])) != NULL) {
- TAILQ_REMOVE(&sn.sn_qs[q], st, sync_list);
+ TAILQ_REMOVE(&sn.sn_qs[q], st, sync_snap);
KASSERT(st->sync_state == q);
+ KASSERT(st->snapped == 1);
st->sync_state = PFSYNC_S_NONE;
+ st->snapped = 0;
pfsync_qs[q].write(st, m->m_data + offset);
offset += pfsync_qs[q].len;
@@ -2397,16 +2421,15 @@ pfsync_q_ins(struct pf_state *st, int q)
struct pfsync_softc *sc = pfsyncif;
size_t nlen, sclen;
-#ifdef DIAGNOSTIC
if (sc->sc_len < PFSYNC_MINPKT)
panic("pfsync pkt len is too low %zd", sc->sc_len);
-#endif
do {
mtx_enter(&sc->sc_st_mtx);
/*
- * If two threads are competing to insert the same state, then
- * there must be just single winner.
+ * There are either two threads trying to update the
+ * the same state, or the state is just being processed
+ * (is on snapshot queue).
*/
if (st->sync_state != PFSYNC_S_NONE) {
mtx_leave(&sc->sc_st_mtx);
@@ -2444,6 +2467,15 @@ pfsync_q_del(struct pf_state *st)
mtx_enter(&sc->sc_st_mtx);
q = st->sync_state;
+ /*
+ * re-check under mutex
+ * if state is snapped already, then just bail out, because we came
+ * too late, the state is being just processed/dispatched to peer.
+ */
+ if ((q == PFSYNC_S_NONE) || (st->snapped)) {
+ mtx_leave(&sc->sc_st_mtx);
+ return;
+ }
atomic_sub_long(&sc->sc_len, pfsync_qs[q].len);
TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
if (TAILQ_EMPTY(&sc->sc_qs[q]))
@@ -2489,6 +2521,7 @@ pfsync_update_tdb(struct tdb *t, int output)
}
TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry);
+ tdb_ref(t);
SET(t->tdb_flags, TDBF_PFSYNC);
mtx_leave(&t->tdb_mtx);
@@ -2519,7 +2552,17 @@ pfsync_delete_tdb(struct tdb *t)
mtx_enter(&sc->sc_tdb_mtx);
+ /*
+ * if tdb entry is just being processed (found in snapshot),
+ * then it can not be deleted. we just came too late
+ */
+ if (ISSET(t->tdb_flags, TDBF_PFSYNC_SNAPPED)) {
+ mtx_leave(&sc->sc_tdb_mtx);
+ return;
+ }
+
TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry);
+
mtx_enter(&t->tdb_mtx);
CLR(t->tdb_flags, TDBF_PFSYNC);
mtx_leave(&t->tdb_mtx);
@@ -2530,6 +2573,8 @@ pfsync_delete_tdb(struct tdb *t)
atomic_sub_long(&sc->sc_len, nlen);
mtx_leave(&sc->sc_tdb_mtx);
+
+ tdb_unref(t);
}
void
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index bd7ec1d88e7..4abcbaf0b90 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.505 2021/12/26 01:00:32 sashan Exp $ */
+/* $OpenBSD: pfvar.h,v 1.506 2022/04/21 15:22:49 sashan Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -749,6 +749,7 @@ struct pf_state {
u_int8_t pad[3];
TAILQ_ENTRY(pf_state) sync_list;
+ TAILQ_ENTRY(pf_state) sync_snap;
TAILQ_ENTRY(pf_state) entry_list;
SLIST_ENTRY(pf_state) gc_list;
RB_ENTRY(pf_state) entry_id;
@@ -797,6 +798,7 @@ struct pf_state {
pf_refcnt_t refcnt;
u_int16_t delay;
u_int8_t rt;
+ u_int8_t snapped;
};
/*
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index c697994047b..7004a40a579 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.237 2022/03/13 21:38:32 bluhm Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.238 2022/04/21 15:22:50 sashan Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr),
@@ -355,6 +355,7 @@ struct tdb { /* tunnel descriptor block */
#define TDBF_PFSYNC 0x40000 /* TDB will be synced */
#define TDBF_PFSYNC_RPL 0x80000 /* Replay counter should be bumped */
#define TDBF_ESN 0x100000 /* 64-bit sequence numbers (ESN) */
+#define TDBF_PFSYNC_SNAPPED 0x200000 /* entry is being dispatched to peer */
#define TDBF_BITS ("\20" \
"\1UNIQUE\2TIMER\3BYTES\4ALLOCATIONS" \
@@ -439,6 +440,7 @@ struct tdb { /* tunnel descriptor block */
TAILQ_HEAD(tdb_policy_head, ipsec_policy) tdb_policy_head; /* [p] */
TAILQ_ENTRY(tdb) tdb_sync_entry;
+ TAILQ_ENTRY(tdb) tdb_sync_snap;
};
enum tdb_counters {