On Sun, Nov 21, 2021 at 03:17:08AM +0300, Vitaliy Makkoveev wrote:
> Can I propose to commit the diff [1] to expose the TDB hardlimit excess
> statistics and then test this diff? I want to see stable systems with
> non null "TDBs with hard limit excess" couter in the statistics like
> below.
Yes please.
If you are wondering how I debug the ref counts, I have ref counter
tracing on top of my diff. I don't want to get that into the tree
now. But it may help you debugging. See #if TDB_TRACE_MAX.
ddb{2}> show tdb /f 0xffff8000080164b0
tdb at 0xffff8000080164b0
...
trace_idx: 5
tdb_trace[0]: 16: refs 1 +1 cpu0 import_lifetime:333
tdb_trace[1]: 17: refs 2 +1 cpu0 import_lifetime:304
tdb_trace[2]: 34: refs 3 -1 cpu0 tdb_soft_timeout:723
tdb_trace[3]: 38: refs 2 +0 cpu0 tdb_timeout:685
tdb_trace[4]: 39: refs 2 -1 cpu0 tdb_delete0:994
bluhm
Index: net/if_bridge.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.358
diff -u -p -r1.358 if_bridge.c
--- net/if_bridge.c 11 Nov 2021 18:08:17 -0000 1.358
+++ net/if_bridge.c 20 Nov 2021 15:14:54 -0000
@@ -1567,20 +1567,28 @@ bridge_ipsec(struct ifnet *ifp, struct e
tdb->tdb_xform != NULL) {
if (tdb->tdb_first_use == 0) {
tdb->tdb_first_use = gettime();
- if (tdb->tdb_flags & TDBF_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_first_tmo,
- tdb->tdb_exp_first_use);
- if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_sfirst_tmo,
- tdb->tdb_soft_first_use);
+ if (tdb->tdb_flags & TDBF_FIRSTUSE) {
+ if (timeout_add_sec(
+ &tdb->tdb_first_tmo,
+ tdb->tdb_exp_first_use))
+ tdb_ref(tdb);
+ }
+ if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) {
+ if (timeout_add_sec(
+ &tdb->tdb_sfirst_tmo,
+ tdb->tdb_soft_first_use))
+ tdb_ref(tdb);
+ }
}
prot = (*(tdb->tdb_xform->xf_input))(&m, tdb, hlen,
off);
+ tdb_unref(tdb);
if (prot != IPPROTO_DONE)
ip_deliver(&m, &hlen, prot, af);
return (1);
} else {
+ tdb_unref(tdb);
skiplookup:
/* XXX do an input policy lookup */
return (0);
Index: net/if_pfsync.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_pfsync.c,v
retrieving revision 1.298
diff -u -p -r1.298 if_pfsync.c
--- net/if_pfsync.c 11 Nov 2021 12:35:01 -0000 1.298
+++ net/if_pfsync.c 19 Nov 2021 13:04:58 -0000
@@ -1325,11 +1325,13 @@ pfsync_update_net_tdb(struct pfsync_tdb
/* Neither replay nor byte counter should ever decrease. */
if (pt->rpl < tdb->tdb_rpl ||
pt->cur_bytes < tdb->tdb_cur_bytes) {
+ tdb_unref(tdb);
goto bad;
}
tdb->tdb_rpl = pt->rpl;
tdb->tdb_cur_bytes = pt->cur_bytes;
+ tdb_unref(tdb);
}
return;
Index: net/pfkeyv2.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2.c,v
retrieving revision 1.221
diff -u -p -r1.221 pfkeyv2.c
--- net/pfkeyv2.c 25 Oct 2021 18:25:01 -0000 1.221
+++ net/pfkeyv2.c 20 Nov 2021 15:14:54 -0000
@@ -1043,8 +1043,11 @@ pfkeyv2_sa_flush(struct tdb *tdb, void *
{
if (!(*((u_int8_t *) satype_vp)) ||
tdb->tdb_satype == *((u_int8_t *) satype_vp)) {
+ /* keep in sync with tdb_delete() */
tdb_unlink_locked(tdb);
- tdb_free(tdb);
+ tdb_unbundle(tdb);
+ tdb_deltimeouts(tdb);
+ tdb_unref(tdb);
}
return (0);
}
@@ -1327,7 +1330,7 @@ pfkeyv2_send(struct socket *so, void *me
if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype,
&newsa->tdb_sproto, &alg))) {
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1363,7 +1366,7 @@ pfkeyv2_send(struct socket *so, void *me
headers[SADB_X_EXT_DST_MASK],
headers[SADB_X_EXT_PROTOCOL],
headers[SADB_X_EXT_FLOW_TYPE]))) {
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1386,7 +1389,7 @@ pfkeyv2_send(struct socket *so, void *me
rval = tdb_init(newsa, alg, &ii);
if (rval) {
rval = EINVAL;
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1397,7 +1400,7 @@ pfkeyv2_send(struct socket *so, void *me
/* Delete old version of the SA, insert new one */
tdb_delete(sa2);
puttdb((struct tdb *) freeme);
- sa2 = freeme = NULL;
+ freeme = NULL;
} else {
/*
* The SA is already initialized, so we're only allowed
to
@@ -1503,7 +1506,7 @@ pfkeyv2_send(struct socket *so, void *me
newsa->tdb_satype = smsg->sadb_msg_satype;
if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype,
&newsa->tdb_sproto, &alg))) {
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1541,7 +1544,7 @@ pfkeyv2_send(struct socket *so, void *me
headers[SADB_X_EXT_DST_MASK],
headers[SADB_X_EXT_PROTOCOL],
headers[SADB_X_EXT_FLOW_TYPE]))) {
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1564,7 +1567,7 @@ pfkeyv2_send(struct socket *so, void *me
rval = tdb_init(newsa, alg, &ii);
if (rval) {
rval = EINVAL;
- tdb_free(freeme);
+ tdb_unref(freeme);
freeme = NULL;
NET_UNLOCK();
goto ret;
@@ -1596,7 +1599,6 @@ pfkeyv2_send(struct socket *so, void *me
tdb_delete(sa2);
NET_UNLOCK();
- sa2 = NULL;
break;
case SADB_X_ASKPOLICY:
@@ -1786,6 +1788,7 @@ pfkeyv2_send(struct socket *so, void *me
ssa->sadb_sa_spi, sunionp,
SADB_X_GETSPROTO(sa_proto->sadb_protocol_proto));
if (tdb2 == NULL) {
+ tdb_unref(tdb1);
rval = ESRCH;
NET_UNLOCK();
goto ret;
@@ -1794,6 +1797,8 @@ pfkeyv2_send(struct socket *so, void *me
/* Detect cycles */
for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext)
if (tdb3 == tdb1) {
+ tdb_unref(tdb1);
+ tdb_unref(tdb2);
rval = ESRCH;
NET_UNLOCK();
goto ret;
@@ -1801,12 +1806,16 @@ pfkeyv2_send(struct socket *so, void *me
/* Maintenance */
if ((tdb1->tdb_onext) &&
- (tdb1->tdb_onext->tdb_inext == tdb1))
+ (tdb1->tdb_onext->tdb_inext == tdb1)) {
+ tdb_unref(tdb1->tdb_onext->tdb_inext);
tdb1->tdb_onext->tdb_inext = NULL;
+ }
if ((tdb2->tdb_inext) &&
- (tdb2->tdb_inext->tdb_onext == tdb2))
+ (tdb2->tdb_inext->tdb_onext == tdb2)) {
+ tdb_unref(tdb2->tdb_inext->tdb_onext);
tdb2->tdb_inext->tdb_onext = NULL;
+ }
/* Link them */
tdb1->tdb_onext = tdb2;
@@ -2008,10 +2017,12 @@ pfkeyv2_send(struct socket *so, void *me
(caddr_t)&ipo->ipo_mask, rnh,
ipo->ipo_nodes, 0)) == NULL) {
/* Remove from linked list of policies on TDB */
- if (ipo->ipo_tdb)
-
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head,
+ if (ipo->ipo_tdb != NULL) {
+ TAILQ_REMOVE(
+ &ipo->ipo_tdb->tdb_policy_head,
ipo, ipo_tdb_next);
-
+ tdb_unref(ipo->ipo_tdb);
+ }
if (ipo->ipo_ids)
ipsp_ids_free(ipo->ipo_ids);
pool_put(&ipsec_policy_pool, ipo);
@@ -2127,6 +2138,10 @@ realret:
free(message, M_PFKEY, len);
free(sa1, M_PFKEY, sizeof(*sa1));
+
+ NET_LOCK();
+ tdb_unref(sa2);
+ NET_UNLOCK();
return (rval);
}
Index: net/pfkeyv2_convert.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2_convert.c,v
retrieving revision 1.75
diff -u -p -r1.75 pfkeyv2_convert.c
--- net/pfkeyv2_convert.c 22 Oct 2021 12:30:53 -0000 1.75
+++ net/pfkeyv2_convert.c 20 Nov 2021 15:14:54 -0000
@@ -299,8 +299,9 @@ import_lifetime(struct tdb *tdb, struct
if ((tdb->tdb_exp_timeout =
sadb_lifetime->sadb_lifetime_addtime) != 0) {
tdb->tdb_flags |= TDBF_TIMER;
- timeout_add_sec(&tdb->tdb_timer_tmo,
- tdb->tdb_exp_timeout);
+ if (timeout_add_sec(&tdb->tdb_timer_tmo,
+ tdb->tdb_exp_timeout))
+ tdb_ref(tdb);
} else
tdb->tdb_flags &= ~TDBF_TIMER;
@@ -327,8 +328,9 @@ import_lifetime(struct tdb *tdb, struct
if ((tdb->tdb_soft_timeout =
sadb_lifetime->sadb_lifetime_addtime) != 0) {
tdb->tdb_flags |= TDBF_SOFT_TIMER;
- timeout_add_sec(&tdb->tdb_stimer_tmo,
- tdb->tdb_soft_timeout);
+ if (timeout_add_sec(&tdb->tdb_stimer_tmo,
+ tdb->tdb_soft_timeout))
+ tdb_ref(tdb);
} else
tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
Index: netinet/ip_ipsp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v
retrieving revision 1.251
diff -u -p -r1.251 ip_ipsp.c
--- netinet/ip_ipsp.c 18 Nov 2021 11:04:10 -0000 1.251
+++ netinet/ip_ipsp.c 20 Nov 2021 15:52:57 -0000
@@ -85,7 +85,6 @@ void tdb_hashstats(void);
#endif
int tdb_rehash(void);
-void tdb_reaper(void *);
void tdb_timeout(void *);
void tdb_firstuse(void *);
void tdb_soft_timeout(void *);
@@ -210,6 +209,9 @@ ipsp_init(void)
M_WAITOK | M_ZERO);
}
+int tdb_trace_level;
+unsigned int tdb_trace_stamp;
+
/*
* Our hashing function needs to stir things with a non-zero random multiplier
* so we cannot be DoS-attacked via choosing of the data to hash.
@@ -297,9 +299,10 @@ reserve_spi(u_int rdomain, u_int32_t ssp
/* Check whether we're using this SPI already. */
exists = gettdb(rdomain, spi, dst, sproto);
- if (exists)
+ if (exists != NULL) {
+ tdb_unref(exists);
continue;
-
+ }
tdbp->tdb_spi = spi;
memcpy(&tdbp->tdb_dst.sa, &dst->sa, dst->sa.sa_len);
@@ -314,8 +317,9 @@ reserve_spi(u_int rdomain, u_int32_t ssp
if (ipsec_keep_invalid > 0) {
tdbp->tdb_flags |= TDBF_TIMER;
tdbp->tdb_exp_timeout = ipsec_keep_invalid;
- timeout_add_sec(&tdbp->tdb_timer_tmo,
- ipsec_keep_invalid);
+ if (timeout_add_sec(&tdbp->tdb_timer_tmo,
+ ipsec_keep_invalid))
+ tdb_ref(tdbp);
}
#endif
@@ -351,6 +355,7 @@ gettdb_dir(u_int rdomain, u_int32_t spi,
!memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len))
break;
+ tdb_ref(tdbp);
mtx_leave(&tdb_sadb_mtx);
return tdbp;
}
@@ -383,6 +388,7 @@ gettdbbysrcdst_dir(u_int rdomain, u_int3
break;
if (tdbp != NULL) {
+ tdb_ref(tdbp);
mtx_leave(&tdb_sadb_mtx);
return tdbp;
}
@@ -402,6 +408,7 @@ gettdbbysrcdst_dir(u_int rdomain, u_int3
tdbp->tdb_src.sa.sa_family == AF_UNSPEC)
break;
+ tdb_ref(tdbp);
mtx_leave(&tdb_sadb_mtx);
return tdbp;
}
@@ -469,6 +476,7 @@ gettdbbydst(u_int rdomain, union sockadd
break;
}
+ tdb_ref(tdbp);
mtx_leave(&tdb_sadb_mtx);
return tdbp;
}
@@ -499,6 +507,7 @@ gettdbbysrc(u_int rdomain, union sockadd
break;
}
+ tdb_ref(tdbp);
mtx_leave(&tdb_sadb_mtx);
return tdbp;
}
@@ -548,6 +557,7 @@ tdb_printit(void *addr, int full, int (*
DUMP(inext, "%p");
DUMP(onext, "%p");
DUMP(xform, "%p");
+ pr("%18s: %d\n", "refcnt", tdb->tdb_refcnt.refs);
DUMP(encalgxform, "%p");
DUMP(authalgxform, "%p");
DUMP(compalgxform, "%p");
@@ -601,12 +611,31 @@ tdb_printit(void *addr, int full, int (*
/* tdb_filtermask */
/* tdb_policy_head */
/* tdb_sync_entry */
+#if TDB_TRACE_MAX > 0
+ {
+ struct tdb_trace *tt;
+ unsigned int idx, i;
+
+ DUMP(trace_idx, "%d");
+ for (i = 0; i < TDB_TRACE_MAX; i++) {
+ idx = (tdb->tdb_trace_idx + i) % TDB_TRACE_MAX;
+ tt = &tdb->tdb_trace[idx];
+ if (tt->tt_stamp == 0)
+ continue;
+ pr(" tdb_trace[%2u]: "
+ "%u: refs %u %+d cpu%d %s:%d\n",
+ idx, tt->tt_stamp, tt->tt_refs, tt->tt_op,
+ tt->tt_cpu, tt->tt_func, tt->tt_line);
+ }
+ }
+#endif
} else {
pr("%p:", tdb);
pr(" %08x", ntohl(tdb->tdb_spi));
pr(" %s", ipsp_address(&tdb->tdb_src, buf, sizeof(buf)));
pr("->%s", ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)));
pr(":%d", tdb->tdb_sproto);
+ pr(" #%d", tdb->tdb_refcnt.refs);
pr(" %08x\n", tdb->tdb_flags);
}
}
@@ -656,6 +685,8 @@ tdb_timeout(void *v)
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
tdb_delete(tdb);
}
+ /* decrement refcount of the timeout argument */
+ tdb_unref(tdb);
NET_UNLOCK();
}
@@ -671,6 +702,8 @@ tdb_firstuse(void *v)
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
tdb_delete(tdb);
}
+ /* decrement refcount of the timeout argument */
+ tdb_unref(tdb);
NET_UNLOCK();
}
@@ -685,6 +718,8 @@ tdb_soft_timeout(void *v)
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
}
+ /* decrement refcount of the timeout argument */
+ tdb_unref(tdb);
NET_UNLOCK();
}
@@ -700,6 +735,8 @@ tdb_soft_firstuse(void *v)
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE;
}
+ /* decrement refcount of the timeout argument */
+ tdb_unref(tdb);
NET_UNLOCK();
}
@@ -890,12 +927,70 @@ tdb_unlink_locked(struct tdb *tdbp)
}
void
-tdb_delete(struct tdb *tdbp)
+tdb_unbundle(struct tdb *tdbp)
+{
+ if (tdbp->tdb_onext != NULL) {
+ if (tdbp->tdb_onext->tdb_inext == tdbp) {
+ tdb_unref(tdbp); /* to us */
+ tdbp->tdb_onext->tdb_inext = NULL;
+ }
+ tdb_unref(tdbp->tdb_onext); /* to other */
+ tdbp->tdb_onext = NULL;
+ }
+ if (tdbp->tdb_inext != NULL) {
+ if (tdbp->tdb_inext->tdb_onext == tdbp) {
+ tdb_unref(tdbp); /* to us */
+ tdbp->tdb_inext->tdb_onext = NULL;
+ }
+ tdb_unref(tdbp->tdb_inext); /* to other */
+ tdbp->tdb_inext = NULL;
+ }
+}
+
+void
+tdb_deltimeouts(struct tdb *tdbp)
+{
+ if (timeout_del(&tdbp->tdb_timer_tmo))
+ tdb_unref(tdbp);
+ if (timeout_del(&tdbp->tdb_first_tmo))
+ tdb_unref(tdbp);
+ if (timeout_del(&tdbp->tdb_stimer_tmo))
+ tdb_unref(tdbp);
+ if (timeout_del(&tdbp->tdb_sfirst_tmo))
+ tdb_unref(tdbp);
+}
+
+struct tdb *
+tdb_ref0(struct tdb *tdb)
+{
+ if (tdb == NULL)
+ return NULL;
+ refcnt_take(&tdb->tdb_refcnt);
+ return tdb;
+}
+
+void
+tdb_unref0(struct tdb *tdb)
+{
+ if (tdb == NULL)
+ return;
+ if (refcnt_rele(&tdb->tdb_refcnt) == 0)
+ return;
+ tdb_free(tdb);
+}
+
+void
+tdb_delete0(struct tdb *tdbp)
{
NET_ASSERT_LOCKED();
tdb_unlink(tdbp);
- tdb_free(tdbp);
+ /* release tdb_onext/tdb_inext references */
+ tdb_unbundle(tdbp);
+ /* delete timeouts and release references */
+ tdb_deltimeouts(tdbp);
+ /* release the reference for tdb_unlink() */
+ tdb_unref(tdbp);
}
/*
@@ -910,6 +1005,7 @@ tdb_alloc(u_int rdomain)
tdbp = pool_get(&tdb_pool, PR_WAITOK | PR_ZERO);
+ refcnt_init(&tdbp->tdb_refcnt);
TAILQ_INIT(&tdbp->tdb_policy_head);
/* Record establishment time. */
@@ -946,9 +1042,9 @@ tdb_free(struct tdb *tdbp)
#endif
/* Cleanup SPD references. */
- for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo;
- ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) {
+ while ((ipo = TAILQ_FIRST(&tdbp->tdb_policy_head)) != NULL) {
TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next);
+ tdb_unref(ipo->ipo_tdb);
ipo->ipo_tdb = NULL;
ipo->ipo_last_searched = 0; /* Force a re-search. */
}
@@ -965,28 +1061,16 @@ tdb_free(struct tdb *tdbp)
}
#endif
- if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp))
- tdbp->tdb_onext->tdb_inext = NULL;
-
- if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp))
- tdbp->tdb_inext->tdb_onext = NULL;
+ KASSERT(tdbp->tdb_onext == NULL);
+ KASSERT(tdbp->tdb_inext == NULL);
/* Remove expiration timeouts. */
tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER |
TDBF_SOFT_TIMER);
- timeout_del(&tdbp->tdb_timer_tmo);
- timeout_del(&tdbp->tdb_first_tmo);
- timeout_del(&tdbp->tdb_stimer_tmo);
- timeout_del(&tdbp->tdb_sfirst_tmo);
-
- timeout_set_proc(&tdbp->tdb_timer_tmo, tdb_reaper, tdbp);
- timeout_add(&tdbp->tdb_timer_tmo, 0);
-}
-
-void
-tdb_reaper(void *xtdbp)
-{
- struct tdb *tdbp = xtdbp;
+ KASSERT(timeout_pending(&tdbp->tdb_timer_tmo) == 0);
+ KASSERT(timeout_pending(&tdbp->tdb_first_tmo) == 0);
+ KASSERT(timeout_pending(&tdbp->tdb_stimer_tmo) == 0);
+ KASSERT(timeout_pending(&tdbp->tdb_sfirst_tmo) == 0);
pool_put(&tdb_pool, tdbp);
}
Index: netinet/ip_ipsp.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v
retrieving revision 1.220
diff -u -p -r1.220 ip_ipsp.h
--- netinet/ip_ipsp.h 16 Nov 2021 13:53:14 -0000 1.220
+++ netinet/ip_ipsp.h 20 Nov 2021 15:53:59 -0000
@@ -307,6 +307,18 @@ struct ipsec_policy {
#define IPSP_IDENTITY_USERFQDN 3
#define IPSP_IDENTITY_ASN1_DN 4
+#define TDB_TRACE_MAX 100
+#if TDB_TRACE_MAX > 0
+struct tdb_trace {
+ const char * tt_func;
+ int tt_line;
+ unsigned int tt_stamp;
+ unsigned int tt_refs;
+ int tt_op;
+ int tt_cpu;
+};
+#endif
+
struct tdb { /* tunnel descriptor block */
/*
* Each TDB is on three hash tables: one keyed on dst/spi/sproto,
@@ -322,6 +334,8 @@ struct tdb { /* tunnel
descriptor blo
struct tdb *tdb_inext;
struct tdb *tdb_onext;
+ struct refcnt tdb_refcnt;
+
const struct xformsw *tdb_xform; /* Transform to use */
const struct enc_xform *tdb_encalgxform; /* Enc algorithm */
const struct auth_hash *tdb_authalgxform; /* Auth algorithm */
@@ -427,6 +441,10 @@ struct tdb { /* tunnel
descriptor blo
TAILQ_HEAD(tdb_policy_head, ipsec_policy) tdb_policy_head;
TAILQ_ENTRY(tdb) tdb_sync_entry;
+#if TDB_TRACE_MAX > 0
+ unsigned int tdb_trace_idx;
+ struct tdb_trace tdb_trace[TDB_TRACE_MAX];
+#endif
};
#define tdb_ipackets tdb_data.tdd_ipackets
#define tdb_opackets tdb_data.tdd_opackets
@@ -496,6 +514,9 @@ extern u_int64_t ipsec_last_added;
extern int encdebug; /* enable message reporting */
extern struct pool tdb_pool;
+extern int tdb_trace_level;
+extern unsigned int tdb_trace_stamp;
+
extern int ipsec_keep_invalid; /* lifetime of embryonic SAs (in sec) */
extern int ipsec_require_pfs; /* use Perfect Forward Secrecy */
extern int ipsec_expire_acquire; /* wait for security assoc. (in sec) */
@@ -547,8 +568,6 @@ int spd_table_walk(unsigned int,
uint32_t reserve_spi(u_int, u_int32_t, u_int32_t, union sockaddr_union *,
union sockaddr_union *, u_int8_t, int *);
struct tdb *gettdb_dir(u_int, u_int32_t, union sockaddr_union *, u_int8_t,
int);
-#define gettdb(a,b,c,d) gettdb_dir((a),(b),(c),(d),0)
-#define gettdb_rev(a,b,c,d) gettdb_dir((a),(b),(c),(d),1)
struct tdb *gettdbbydst(u_int, union sockaddr_union *, u_int8_t,
struct ipsec_ids *,
struct sockaddr_encap *, struct sockaddr_encap *);
@@ -560,12 +579,72 @@ struct tdb *gettdbbysrcdst_dir(u_int, u_
#define gettdbbysrcdst(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),0)
#define gettdbbysrcdst_rev(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),1)
void puttdb(struct tdb *);
-void tdb_delete(struct tdb *);
+void tdb_delete0(struct tdb *);
struct tdb *tdb_alloc(u_int);
+struct tdb *tdb_ref0(struct tdb *);
+void tdb_unref0(struct tdb *);
+
+#if TDB_TRACE_MAX > 0
+#define TDB_TRACE_RECORD(y, f, l, op) do { \
+ struct tdb *x = y; \
+ if (x) { \
+ struct tdb_trace *tt; \
+ unsigned int idx; \
+ \
+ idx = atomic_inc_int_nv(&x->tdb_trace_idx); \
+ tt = &x->tdb_trace[(idx - 1) % TDB_TRACE_MAX]; \
+ tt->tt_stamp = atomic_inc_int_nv(&tdb_trace_stamp); \
+ tt->tt_func = f; \
+ tt->tt_line = l; \
+ tt->tt_op = op; \
+ tt->tt_cpu = cpu_number(); \
+ tt->tt_refs = x->tdb_refcnt.refs; /* RACE */ \
+ if (tdb_trace_level >= 1) \
+ printf("tdb %p: %u: refs %u %+d cpu%d %s:%d\n", \
+ x, tt->tt_stamp, tt->tt_refs, tt->tt_op, \
+ tt->tt_cpu, tt->tt_func, tt->tt_line); \
+ } \
+ } while(0)
+#define tdb_ref(x) ({ \
+ struct tdb *y; \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 1); \
+ y = tdb_ref0(x); \
+ y; \
+ })
+#define tdb_unref(x) do { \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, -1); \
+ tdb_unref0(x); \
+ } while(0)
+#define tdb_delete(x) do { \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 0); \
+ tdb_delete0(x); \
+ } while(0)
+#define gettdb(a,b,c,d) ({ \
+ struct tdb *y; \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 0); \
+ y = gettdb_dir((a),(b),(c),(d),0); \
+ y; \
+ })
+#define gettdb_rev(a,b,c,d) ({ \
+ struct tdb *y; \
+ TDB_TRACE_RECORD(x, __func__, __LINE__, 0); \
+ y = gettdb_dir((a),(b),(c),(d),1); \
+ y; \
+ })
+#else
+#define tdb_ref(x) tdb_ref0(x)
+#define tdb_unref(x) tdb_unref0(x)
+#define tdb_delete(x) tdb_delete0(x)
+#define gettdb(a,b,c,d) gettdb_dir((a),(b),(c),(d),0)
+#define gettdb_rev(a,b,c,d) gettdb_dir((a),(b),(c),(d),1)
+#endif
+
void tdb_free(struct tdb *);
int tdb_init(struct tdb *, u_int16_t, struct ipsecinit *);
void tdb_unlink(struct tdb *);
void tdb_unlink_locked(struct tdb *);
+void tdb_unbundle(struct tdb *);
+void tdb_deltimeouts(struct tdb *);
int tdb_walk(u_int, int (*)(struct tdb *, void *, int), void *);
void tdb_printit(void *, int, int (*)(const char *, ...));
Index: netinet/ip_spd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_spd.c,v
retrieving revision 1.104
diff -u -p -r1.104 ip_spd.c
--- netinet/ip_spd.c 8 Jul 2021 16:39:55 -0000 1.104
+++ netinet/ip_spd.c 19 Nov 2021 13:04:58 -0000
@@ -368,9 +368,11 @@ ipsp_spd_lookup(struct mbuf *m, int af,
}
/* Do we have a cached entry ? If so, check if it's still valid. */
- if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) {
+ if (ipo->ipo_tdb != NULL &&
+ (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) {
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
ipo_tdb_next);
+ tdb_unref(ipo->ipo_tdb);
ipo->ipo_tdb = NULL;
}
@@ -398,7 +400,7 @@ ipsp_spd_lookup(struct mbuf *m, int af,
ids = ipsp_ids_lookup(ipsecflowinfo);
/* Check that the cached TDB (if present), is appropriate. */
- if (ipo->ipo_tdb) {
+ if (ipo->ipo_tdb != NULL) {
if ((ipo->ipo_last_searched <= ipsec_last_added) ||
(ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) ||
memcmp(dignore ? &sdst : &ipo->ipo_dst,
@@ -420,6 +422,7 @@ ipsp_spd_lookup(struct mbuf *m, int af,
/* Cached TDB was not good. */
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
ipo_tdb_next);
+ tdb_unref(ipo->ipo_tdb);
ipo->ipo_tdb = NULL;
ipo->ipo_last_searched = 0;
}
@@ -439,14 +442,14 @@ ipsp_spd_lookup(struct mbuf *m, int af,
ipo->ipo_last_searched = getuptime();
/* Find an appropriate SA from the existing ones. */
- ipo->ipo_tdb =
- gettdbbydst(rdomain,
- dignore ? &sdst : &ipo->ipo_dst,
- ipo->ipo_sproto,
- ids ? ids: ipo->ipo_ids,
- &ipo->ipo_addr, &ipo->ipo_mask);
- if (ipo->ipo_tdb) {
-
TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
+ ipo->ipo_tdb = gettdbbydst(rdomain,
+ dignore ? &sdst : &ipo->ipo_dst,
+ ipo->ipo_sproto, ids ? ids: ipo->ipo_ids,
+ &ipo->ipo_addr, &ipo->ipo_mask);
+ if (ipo->ipo_tdb != NULL) {
+ /* gettdbbydst() has already refcounted tdb */
+ TAILQ_INSERT_TAIL(
+ &ipo->ipo_tdb->tdb_policy_head,
ipo, ipo_tdb_next);
*error = 0;
return ipsp_spd_inp(m, af, hlen, error,
@@ -520,10 +523,12 @@ ipsp_spd_lookup(struct mbuf *m, int af,
goto nomatchin;
/* Add it to the cache. */
- if (ipo->ipo_tdb)
+ if (ipo->ipo_tdb != NULL) {
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head,
ipo, ipo_tdb_next);
- ipo->ipo_tdb = tdbp;
+ tdb_unref(ipo->ipo_tdb);
+ }
+ ipo->ipo_tdb = tdb_ref(tdbp);
TAILQ_INSERT_TAIL(&tdbp->tdb_policy_head, ipo,
ipo_tdb_next);
*error = 0;
@@ -535,7 +540,7 @@ ipsp_spd_lookup(struct mbuf *m, int af,
}
/* Check whether cached entry applies. */
- if (ipo->ipo_tdb) {
+ if (ipo->ipo_tdb != NULL) {
/*
* We only need to check that the correct
* security protocol and security gateway are
@@ -551,8 +556,9 @@ ipsp_spd_lookup(struct mbuf *m, int af,
/* Not applicable, unlink. */
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
ipo_tdb_next);
- ipo->ipo_last_searched = 0;
+ tdb_unref(ipo->ipo_tdb);
ipo->ipo_tdb = NULL;
+ ipo->ipo_last_searched = 0;
}
/* Find whether there exists an appropriate SA. */
@@ -560,14 +566,16 @@ ipsp_spd_lookup(struct mbuf *m, int af,
if (dignore == 0)
ipo->ipo_last_searched = getuptime();
- ipo->ipo_tdb =
- gettdbbysrc(rdomain,
- dignore ? &ssrc : &ipo->ipo_dst,
- ipo->ipo_sproto, ipo->ipo_ids,
- &ipo->ipo_addr, &ipo->ipo_mask);
- if (ipo->ipo_tdb)
-
TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
+ ipo->ipo_tdb = gettdbbysrc(rdomain,
+ dignore ? &ssrc : &ipo->ipo_dst,
+ ipo->ipo_sproto, ipo->ipo_ids,
+ &ipo->ipo_addr, &ipo->ipo_mask);
+ if (ipo->ipo_tdb != NULL) {
+ /* gettdbbysrc() has already refcounted tdb */
+ TAILQ_INSERT_TAIL(
+ &ipo->ipo_tdb->tdb_policy_head,
ipo, ipo_tdb_next);
+ }
}
skipinputsearch:
@@ -637,9 +645,12 @@ ipsec_delete_policy(struct ipsec_policy
rn_delete(&ipo->ipo_addr, &ipo->ipo_mask, rnh, rn) == NULL)
return (ESRCH);
- if (ipo->ipo_tdb != NULL)
+ if (ipo->ipo_tdb != NULL) {
TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
ipo_tdb_next);
+ tdb_unref(ipo->ipo_tdb);
+ ipo->ipo_tdb = NULL;
+ }
while ((ipa = TAILQ_FIRST(&ipo->ipo_acquires)) != NULL)
ipsp_delete_acquire(ipa);
Index: netinet/ipsec_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.191
diff -u -p -r1.191 ipsec_input.c
--- netinet/ipsec_input.c 11 Nov 2021 18:08:18 -0000 1.191
+++ netinet/ipsec_input.c 20 Nov 2021 15:14:54 -0000
@@ -328,12 +328,16 @@ ipsec_common_input(struct mbuf **mp, int
/* Register first use, setup expiration timer. */
if (tdbp->tdb_first_use == 0) {
tdbp->tdb_first_use = gettime();
- if (tdbp->tdb_flags & TDBF_FIRSTUSE)
- timeout_add_sec(&tdbp->tdb_first_tmo,
- tdbp->tdb_exp_first_use);
- if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE)
- timeout_add_sec(&tdbp->tdb_sfirst_tmo,
- tdbp->tdb_soft_first_use);
+ if (tdbp->tdb_flags & TDBF_FIRSTUSE) {
+ if (timeout_add_sec(&tdbp->tdb_first_tmo,
+ tdbp->tdb_exp_first_use))
+ tdb_ref(tdbp);
+ }
+ if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE) {
+ if (timeout_add_sec(&tdbp->tdb_sfirst_tmo,
+ tdbp->tdb_soft_first_use))
+ tdb_ref(tdbp);
+ }
}
tdbp->tdb_ipackets++;
@@ -348,6 +352,7 @@ ipsec_common_input(struct mbuf **mp, int
ipsecstat_inc(ipsec_idrops);
tdbp->tdb_idrops++;
}
+ tdb_unref(tdbp);
return prot;
drop:
@@ -355,6 +360,7 @@ ipsec_common_input(struct mbuf **mp, int
ipsecstat_inc(ipsec_idrops);
if (tdbp != NULL)
tdbp->tdb_idrops++;
+ tdb_unref(tdbp);
return IPPROTO_DONE;
}
@@ -937,6 +943,7 @@ ipsec_common_ctlinput(u_int rdomain, int
tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst,
proto);
ipsec_set_mtu(tdbp, mtu);
+ tdb_unref(tdbp);
}
}
@@ -944,7 +951,7 @@ void
udpencap_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v)
{
struct ip *ip = v;
- struct tdb *tdbp;
+ struct tdb *tdbp, *first;
struct icmp *icp;
u_int32_t mtu;
struct sockaddr_in dst, src;
@@ -973,10 +980,9 @@ udpencap_ctlinput(int cmd, struct sockad
src.sin_addr.s_addr = ip->ip_src.s_addr;
su_src = (union sockaddr_union *)&src;
- tdbp = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst,
- IPPROTO_ESP);
+ first = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst, IPPROTO_ESP);
- for (; tdbp != NULL; tdbp = tdbp->tdb_snext) {
+ for (tdbp = first; tdbp != NULL; tdbp = tdbp->tdb_snext) {
if (tdbp->tdb_sproto == IPPROTO_ESP &&
((tdbp->tdb_flags & (TDBF_INVALID|TDBF_UDPENCAP)) ==
TDBF_UDPENCAP) &&
@@ -985,6 +991,7 @@ udpencap_ctlinput(int cmd, struct sockad
ipsec_set_mtu(tdbp, mtu);
}
}
+ tdb_unref(first);
}
void
@@ -1070,6 +1077,7 @@ ipsec_forward_check(struct mbuf *m, int
} else
tdb = NULL;
ipsp_spd_lookup(m, af, hlen, &error, IPSP_DIRECTION_IN, tdb, NULL, 0);
+ tdb_unref(tdb);
return error;
}
@@ -1142,6 +1150,7 @@ ipsec_local_check(struct mbuf *m, int hl
tdb = NULL;
ipsp_spd_lookup(m, af, hlen, &error, IPSP_DIRECTION_IN,
tdb, NULL, 0);
+ tdb_unref(tdb);
return error;
}
Index: netinet/ipsec_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v
retrieving revision 1.91
diff -u -p -r1.91 ipsec_output.c
--- netinet/ipsec_output.c 23 Oct 2021 15:42:35 -0000 1.91
+++ netinet/ipsec_output.c 20 Nov 2021 15:14:54 -0000
@@ -139,12 +139,16 @@ ipsp_process_packet(struct mbuf *m, stru
*/
if (tdb->tdb_first_use == 0) {
tdb->tdb_first_use = gettime();
- if (tdb->tdb_flags & TDBF_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_first_tmo,
- tdb->tdb_exp_first_use);
- if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
- timeout_add_sec(&tdb->tdb_sfirst_tmo,
- tdb->tdb_soft_first_use);
+ if (tdb->tdb_flags & TDBF_FIRSTUSE) {
+ if (timeout_add_sec(&tdb->tdb_first_tmo,
+ tdb->tdb_exp_first_use))
+ tdb_ref(tdb);
+ }
+ if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) {
+ if (timeout_add_sec(&tdb->tdb_sfirst_tmo,
+ tdb->tdb_soft_first_use))
+ tdb_ref(tdb);
+ }
}
/*
@@ -388,6 +392,7 @@ ipsp_process_done(struct mbuf *m, struct
#ifdef INET6
struct ip6_hdr *ip6;
#endif /* INET6 */
+ struct tdb *tdbo;
struct tdb_ident *tdbi;
struct m_tag *mtag;
int roff, error;
@@ -501,9 +506,13 @@ ipsp_process_done(struct mbuf *m, struct
tdb->tdb_obytes += m->m_pkthdr.len;
/* If there's another (bundled) TDB to apply, do so. */
- if (tdb->tdb_onext)
- return ipsp_process_packet(m, tdb->tdb_onext,
+ tdbo = tdb_ref(tdb->tdb_onext);
+ if (tdbo != NULL) {
+ error = ipsp_process_packet(m, tdbo,
tdb->tdb_dst.sa.sa_family, 0);
+ tdb_unref(tdbo);
+ return error;
+ }
#if NPF > 0
/* Add pf tag if requested. */
@@ -615,13 +624,16 @@ ipsec_adjust_mtu(struct mbuf *m, u_int32
if (tdbp == NULL)
break;
- if ((adjust = ipsec_hdrsz(tdbp)) == -1)
+ if ((adjust = ipsec_hdrsz(tdbp)) == -1) {
+ tdb_unref(tdbp);
break;
+ }
mtu -= adjust;
tdbp->tdb_mtu = mtu;
tdbp->tdb_mtutimeout = gettime() + ip_mtudisc_timeout;
DPRINTF("spi %08x mtu %d adjust %ld mbuf %p",
ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust, m);
+ tdb_unref(tdbp);
}
}
Index: netinet/tcp_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.370
diff -u -p -r1.370 tcp_input.c
--- netinet/tcp_input.c 9 Aug 2021 17:03:08 -0000 1.370
+++ netinet/tcp_input.c 19 Nov 2021 13:04:58 -0000
@@ -380,12 +380,6 @@ tcp_input(struct mbuf **mp, int *offp, i
#ifdef INET6
struct ip6_hdr *ip6 = NULL;
#endif /* INET6 */
-#ifdef IPSEC
- struct m_tag *mtag;
- struct tdb_ident *tdbi;
- struct tdb *tdb;
- int error;
-#endif /* IPSEC */
#ifdef TCP_ECN
u_char iptos;
#endif
@@ -571,16 +565,22 @@ findpcb:
}
#ifdef IPSEC
if (ipsec_in_use) {
+ struct m_tag *mtag;
+ struct tdb *tdb = NULL;
+ int error;
+
/* Find most recent IPsec tag */
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
if (mtag != NULL) {
+ struct tdb_ident *tdbi;
+
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->rdomain, tdbi->spi,
&tdbi->dst, tdbi->proto);
- } else
- tdb = NULL;
+ }
ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
tdb, inp, 0);
+ tdb_unref(tdb);
if (error) {
tcpstat_inc(tcps_rcvnosec);
goto drop;
@@ -2197,7 +2197,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *
continue;
if (sigp && timingsafe_bcmp(sigp, cp + 2, 16))
- return (-1);
+ goto bad;
sigp = cp + 2;
break;
@@ -2248,7 +2248,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *
if ((sigp ? TF_SIGNATURE : 0) ^ (tp->t_flags & TF_SIGNATURE)) {
tcpstat_inc(tcps_rcvbadsig);
- return (-1);
+ goto bad;
}
if (sigp) {
@@ -2256,22 +2256,30 @@ tcp_dooptions(struct tcpcb *tp, u_char *
if (tdb == NULL) {
tcpstat_inc(tcps_rcvbadsig);
- return (-1);
+ goto bad;
}
if (tcp_signature(tdb, tp->pf, m, th, iphlen, 1, sig) < 0)
- return (-1);
+ goto bad;
if (timingsafe_bcmp(sig, sigp, 16)) {
tcpstat_inc(tcps_rcvbadsig);
- return (-1);
+ goto bad;
}
tcpstat_inc(tcps_rcvgoodsig);
}
+
+ tdb_unref(tdb);
#endif /* TCP_SIGNATURE */
return (0);
+
+ bad:
+#ifdef TCP_SIGNATURE
+ tdb_unref(tdb);
+#endif /* TCP_SIGNATURE */
+ return (-1);
}
u_long
@@ -4056,8 +4064,10 @@ syn_cache_respond(struct syn_cache *sc,
if (tcp_signature(tdb, sc->sc_src.sa.sa_family, m, th,
hlen, 0, optp) < 0) {
m_freem(m);
+ tdb_unref(tdb);
return (EINVAL);
}
+ tdb_unref(tdb);
optp += 16;
/* Pad options list to the next 32 bit boundary and
Index: netinet/tcp_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_output.c,v
retrieving revision 1.130
diff -u -p -r1.130 tcp_output.c
--- netinet/tcp_output.c 8 Feb 2021 19:37:15 -0000 1.130
+++ netinet/tcp_output.c 19 Nov 2021 13:04:58 -0000
@@ -879,8 +879,10 @@ send:
if (tcp_signature(tdb, tp->pf, m, th, iphlen, 0,
mtod(m, caddr_t) + hdrlen - optlen + sigoff) < 0) {
m_freem(m);
+ tdb_unref(tdb);
return (EINVAL);
}
+ tdb_unref(tdb);
}
#endif /* TCP_SIGNATURE */
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.264
diff -u -p -r1.264 udp_usrreq.c
--- netinet/udp_usrreq.c 11 Nov 2021 18:08:18 -0000 1.264
+++ netinet/udp_usrreq.c 19 Nov 2021 13:04:58 -0000
@@ -514,11 +514,13 @@ udp_input(struct mbuf **mp, int *offp, i
IPSP_DIRECTION_IN, tdb, inp, 0);
if (error) {
udpstat_inc(udps_nosec);
+ tdb_unref(tdb);
goto bad;
}
/* create ipsec options while we know that tdb cannot be
modified */
if (tdb && tdb->tdb_ids)
ipsecflowinfo = tdb->tdb_ids->id_flow;
+ tdb_unref(tdb);
}
#endif /*IPSEC */