34#include <sys/kernel.h>
36#include <sys/malloc.h>
40#include <sys/refcount.h>
41#include <sys/rwlock.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/sysctl.h>
47#include <sys/counter.h>
49#include <dev/tcp_log/tcp_log_dev.h>
52#include <net/if_var.h>
62#define TCP_LOG_EXPIRE_TIME ((sbintime_t)60 * SBT_1S)
65#define TCP_LOG_EXPIRE_INTVL ((sbintime_t)5 * SBT_1S)
74 STAILQ_HEAD_INITIALIZER(tcp_log_expireq_head);
75static struct mtx tcp_log_expireq_mtx;
76static struct callout tcp_log_expireq_callout;
77static u_long tcp_log_auto_ratio = 0;
78static volatile u_long tcp_log_auto_ratio_cur = 0;
80static bool tcp_log_auto_all =
false;
81static uint32_t tcp_disable_all_bb_logs = 0;
85SYSCTL_NODE(_net_inet_tcp, OID_AUTO, bb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
86 "TCP Black Box controls");
89 0,
"Force verbose logging for TCP traces");
91SYSCTL_INT(_net_inet_tcp_bb, OID_AUTO, log_session_limit,
93 "Maximum number of events maintained for each TCP session");
95SYSCTL_UMA_MAX(_net_inet_tcp_bb, OID_AUTO, log_global_limit, CTLFLAG_RW,
96 &
tcp_log_zone,
"Maximum number of events maintained for all TCP sessions");
98SYSCTL_UMA_CUR(_net_inet_tcp_bb, OID_AUTO, log_global_entries, CTLFLAG_RD,
99 &
tcp_log_zone,
"Current number of events maintained for all TCP sessions");
101SYSCTL_UMA_MAX(_net_inet_tcp_bb, OID_AUTO, log_id_limit, CTLFLAG_RW,
104SYSCTL_UMA_CUR(_net_inet_tcp_bb, OID_AUTO, log_id_entries, CTLFLAG_RD,
107SYSCTL_UMA_MAX(_net_inet_tcp_bb, OID_AUTO, log_id_tcpcb_limit, CTLFLAG_RW,
110SYSCTL_UMA_CUR(_net_inet_tcp_bb, OID_AUTO, log_id_tcpcb_entries, CTLFLAG_RD,
113SYSCTL_U32(_net_inet_tcp_bb, OID_AUTO, log_version, CTLFLAG_RD, &
tcp_log_version,
114 0,
"Version of log formats exported");
116SYSCTL_U32(_net_inet_tcp_bb, OID_AUTO, disable_all, CTLFLAG_RW,
118 "Disable all BB logging for all connections");
120SYSCTL_ULONG(_net_inet_tcp_bb, OID_AUTO, log_auto_ratio, CTLFLAG_RW,
121 &tcp_log_auto_ratio, 0,
"Do auto capturing for 1 out of N sessions");
123SYSCTL_U32(_net_inet_tcp_bb, OID_AUTO, log_auto_mode, CTLFLAG_RW,
125 "Logging mode for auto-selected sessions (default is TCP_LOG_STATE_HEAD_AUTO)");
127SYSCTL_BOOL(_net_inet_tcp_bb, OID_AUTO, log_auto_all, CTLFLAG_RW,
128 &tcp_log_auto_all,
false,
129 "Auto-select from all sessions (rather than just those with IDs)");
131#ifdef TCPLOG_DEBUG_COUNTERS
132counter_u64_t tcp_log_queued;
133counter_u64_t tcp_log_que_fail1;
134counter_u64_t tcp_log_que_fail2;
135counter_u64_t tcp_log_que_fail3;
136counter_u64_t tcp_log_que_fail4;
137counter_u64_t tcp_log_que_fail5;
138counter_u64_t tcp_log_que_copyout;
139counter_u64_t tcp_log_que_read;
140counter_u64_t tcp_log_que_freed;
143 &tcp_log_queued,
"Number of entries queued");
145 &tcp_log_que_fail1,
"Number of entries queued but fail 1");
147 &tcp_log_que_fail2,
"Number of entries queued but fail 2");
149 &tcp_log_que_fail3,
"Number of entries queued but fail 3");
151 &tcp_log_que_fail4,
"Number of entries queued but fail 4");
153 &tcp_log_que_fail5,
"Number of entries queued but fail 4");
155 &tcp_log_que_copyout,
"Number of entries copied out");
157 &tcp_log_que_read,
"Number of entries read from the queue");
159 &tcp_log_que_freed,
"Number of entries freed after reading");
163#define TCPLOG_DEBUG_RINGBUF
166#define ACTIVE_REQUEST_COUNT 10
169static counter_u64_t tcp_log_pcb_ids_cur;
170static counter_u64_t tcp_log_pcb_ids_tot;
173 &tcp_log_pcb_ids_cur,
"Number of pcb IDs allocated in the system");
175 &tcp_log_pcb_ids_tot,
"Total number of pcb IDs that have been allocated");
179 STAILQ_ENTRY(tcp_log_mem) tlm_queue;
182#ifdef TCPLOG_DEBUG_RINGBUF
183 volatile int tlm_refcnt;
229#define TCPID_TREE_WLOCK() rw_wlock(&tcp_id_tree_lock)
230#define TCPID_TREE_RLOCK() rw_rlock(&tcp_id_tree_lock)
231#define TCPID_TREE_UPGRADE() rw_try_upgrade(&tcp_id_tree_lock)
232#define TCPID_TREE_WUNLOCK() rw_wunlock(&tcp_id_tree_lock)
233#define TCPID_TREE_RUNLOCK() rw_runlock(&tcp_id_tree_lock)
234#define TCPID_TREE_WLOCK_ASSERT() rw_assert(&tcp_id_tree_lock, RA_WLOCKED)
235#define TCPID_TREE_RLOCK_ASSERT() rw_assert(&tcp_id_tree_lock, RA_RLOCKED)
236#define TCPID_TREE_UNLOCK_ASSERT() rw_assert(&tcp_id_tree_lock, RA_UNLOCKED)
238#define TCPID_BUCKET_LOCK_INIT(tlb) mtx_init(&((tlb)->tlb_mtx), "tcp log id bucket", NULL, MTX_DEF)
239#define TCPID_BUCKET_LOCK_DESTROY(tlb) mtx_destroy(&((tlb)->tlb_mtx))
240#define TCPID_BUCKET_LOCK(tlb) mtx_lock(&((tlb)->tlb_mtx))
241#define TCPID_BUCKET_UNLOCK(tlb) mtx_unlock(&((tlb)->tlb_mtx))
242#define TCPID_BUCKET_LOCK_ASSERT(tlb) mtx_assert(&((tlb)->tlb_mtx), MA_OWNED)
243#define TCPID_BUCKET_UNLOCK_ASSERT(tlb) mtx_assert(&((tlb)->tlb_mtx), MA_NOTOWNED)
245#define TCPID_BUCKET_REF(tlb) refcount_acquire(&((tlb)->tlb_refcnt))
246#define TCPID_BUCKET_UNREF(tlb) refcount_release(&((tlb)->tlb_refcnt))
248#define TCPLOG_EXPIREQ_LOCK() mtx_lock(&tcp_log_expireq_mtx)
249#define TCPLOG_EXPIREQ_UNLOCK() mtx_unlock(&tcp_log_expireq_mtx)
264 volatile u_int tlb_refcnt;
265 volatile u_int tlb_reqcnt;
274 sbintime_t tln_expiretime;
283 struct inpcb *tln_inp;
284 struct tcpcb *tln_tp;
287 struct tcp_log_stailq tln_entries;
289 volatile int tln_closed;
308 if (tcp_log_auto_ratio &&
309 (tcp_disable_all_bb_logs == 0) &&
310 (atomic_fetchadd_long(&tcp_log_auto_ratio_cur, 1) %
311 tcp_log_auto_ratio) == 0)
319 KASSERT(a != NULL, (
"tcp_log_id_cmp: argument a is unexpectedly NULL"));
320 KASSERT(b != NULL, (
"tcp_log_id_cmp: argument b is unexpectedly NULL"));
331 switch (tree_locked) {
342 kassert_panic(
"%s:%d: unknown tree lock state", __func__,
353 KASSERT(SLIST_EMPTY(&tlb->tlb_head),
354 (
"%s: Attempt to remove non-empty bucket", __func__));
357 kassert_panic(
"%s:%d: error removing element from tree",
362 counter_u64_add(tcp_log_pcb_ids_cur, (int64_t)-1);
381 KASSERT(tlb != NULL, (
"%s: called with NULL tlb", __func__));
382 KASSERT(tree_locked != NULL, (
"%s: called with NULL tree_locked",
453 int orig_tree_locked;
455 KASSERT(tp != NULL || (tlb != NULL && tln != NULL),
456 (
"%s: called with tp=%p, tlb=%p, tln=%p", __func__,
458 KASSERT(tree_locked != NULL, (
"%s: called with NULL tree_locked",
464 KASSERT(tlb != NULL, (
"%s: unexpectedly NULL tlb", __func__));
465 KASSERT(tln != NULL, (
"%s: unexpectedly NULL tln", __func__));
481 orig_tree_locked = *tree_locked;
484 return (*tree_locked != orig_tree_locked);
487#define RECHECK_INP_CLEAN(cleanup) do { \
488 if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \
493 tp = intotcpcb(inp); \
496#define RECHECK_INP() RECHECK_INP_CLEAN()
505 if (V_tcp_perconn_stats_enable == 2 && tp->
t_stats == NULL)
514 atomic_fetchadd_int(&tlb->tlb_reqcnt, 1);
573 bucket_locked =
false;
580 (tp->
t_lib == NULL && *
id == 0)) {
581 if (tp->
t_lib != NULL) {
583 if ((tp->
t_lib->tlb_logstate) &&
589 if ((tp->
t_lib->tlb_loglimit) &&
609 if (tp->
t_lib != NULL) {
619 bucket_locked =
true;
627 bucket_locked =
false;
648 if (tlb == NULL || tp->
t_lib != tlb) {
649 KASSERT(bucket_locked || tlb == NULL,
650 (
"%s: bucket_locked (%d) and tlb (%p) are "
651 "inconsistent", __func__, bucket_locked, tlb));
655 bucket_locked =
false;
675 bucket_locked =
false;
696 KASSERT(tp->
t_lib == NULL, (
"%s: tp->t_lib is not NULL", __func__));
732 KASSERT(tlb == NULL, (
"%s:%d tlb unexpectedly non-NULL",
733 __func__, __LINE__));
757 if (tmp_tlb == NULL) {
764 counter_u64_add(tcp_log_pcb_ids_cur, 1);
765 counter_u64_add(tcp_log_pcb_ids_tot, 1);
767 if ((tcp_log_auto_all ==
false) &&
771 tlb->tlb_logstate = tcp_log_auto_mode;
774 tlb->tlb_loglimit = 0;
786 strncpy(tlb->
tlb_id,
id, TCP_LOG_ID_LEN - 1);
787 tlb->
tlb_id[TCP_LOG_ID_LEN - 1] =
'\0';
796 SLIST_INIT(&tlb->tlb_head);
797 refcount_init(&tlb->tlb_refcnt, 1);
799 memset(&tlb->tlb_mtx, 0,
sizeof(
struct mtx));
802 bucket_locked =
true;
804#define FREE_NEW_TLB() do { \
805 TCPID_BUCKET_LOCK_DESTROY(tlb); \
806 uma_zfree(tcp_log_bucket_zone, tlb); \
807 counter_u64_add(tcp_log_pcb_ids_cur, (int64_t)-1); \
808 counter_u64_add(tcp_log_pcb_ids_tot, (int64_t)-1); \
809 bucket_locked = false; \
818 if (tp->
t_lib != NULL) {
826 KASSERT(tmp_tlb == NULL,
827 (
"%s: Unexpected conflicting bucket (%p) while "
828 "adding new bucket (%p)", __func__, tmp_tlb, tlb));
835 if (tmp_tlb != NULL) {
843 if (tmp_tlb != NULL) {
846 bucket_locked =
true;
855 if (tp->
t_lib != NULL) {
857 bucket_locked =
false;
872 SLIST_INSERT_HEAD(&tlb->tlb_head, tln, tln_list);
875 if (tp->
t_lib->tlb_logstate) {
880 if (tp->
t_lib->tlb_loglimit) {
898 }
else if (tlb != NULL)
925 if (tp->
t_lib != NULL) {
926 len = strlcpy(buf, tp->
t_lib->
tlb_id, TCP_LOG_ID_LEN);
927 KASSERT(len < TCP_LOG_ID_LEN,
928 (
"%s:%d: tp->t_lib->tlb_id too long (%zu)",
929 __func__, __LINE__, len));
961 (
"%s:%d: tp->t_lib->tlb_tag too long (%zu)",
962 __func__, __LINE__, len));
993 return ((tp->
t_lib == NULL) ? 0 : tp->
t_lib->tlb_refcnt);
996#ifdef TCPLOG_DEBUG_RINGBUF
1003_tcp_log_entry_refcnt_add(
struct tcp_log_mem *log_entry,
const char *func,
1008 refcnt = atomic_fetchadd_int(&log_entry->tlm_refcnt, 1);
1010 panic(
"%s:%d: log_entry(%p)->tlm_refcnt is %d (expected 0)",
1011 func, line, log_entry, refcnt);
1013#define tcp_log_entry_refcnt_add(l) \
1014 _tcp_log_entry_refcnt_add((l), __func__, __LINE__)
1017_tcp_log_entry_refcnt_rem(
struct tcp_log_mem *log_entry,
const char *func,
1022 refcnt = atomic_fetchadd_int(&log_entry->tlm_refcnt, -1);
1024 panic(
"%s:%d: log_entry(%p)->tlm_refcnt is %d (expected 1)",
1025 func, line, log_entry, refcnt);
1027#define tcp_log_entry_refcnt_rem(l) \
1028 _tcp_log_entry_refcnt_rem((l), __func__, __LINE__)
1032#define tcp_log_entry_refcnt_add(l)
1033#define tcp_log_entry_refcnt_rem(l)
1048 KASSERT(*
count >= 0,
1049 (
"%s: count unexpectedly negative", __func__));
1056 struct tcp_log_mem *log_entry;
1059 while ((log_entry = STAILQ_FIRST(head)) != NULL) {
1060 STAILQ_REMOVE_HEAD(head, tlm_queue);
1073 (
"%s: tp->t_lognum unexpectedly negative", __func__));
1081 KASSERT(log_entry == STAILQ_FIRST(&tp->
t_logs),
1082 (
"%s: attempt to remove non-HEAD log entry", __func__));
1083 STAILQ_REMOVE_HEAD(&tp->
t_logs, tlm_queue);
1088#ifdef TCPLOG_DEBUG_RINGBUF
1094tcp_log_zone_init(
void *mem,
int size,
int flags __unused)
1096 struct tcp_log_mem *tlm;
1098 KASSERT(size >=
sizeof(
struct tcp_log_mem),
1099 (
"%s: unexpectedly short (%d) allocation", __func__, size));
1100 tlm = (
struct tcp_log_mem *)mem;
1101 tlm->tlm_refcnt = 0;
1109tcp_log_zone_ctor(
void *mem,
int size,
void *args __unused,
int flags __unused)
1111 struct tcp_log_mem *tlm;
1113 KASSERT(size >=
sizeof(
struct tcp_log_mem),
1114 (
"%s: unexpectedly short (%d) allocation", __func__, size));
1115 tlm = (
struct tcp_log_mem *)mem;
1116 if (tlm->tlm_refcnt != 0)
1117 panic(
"%s:%d: tlm(%p)->tlm_refcnt is %d (expected 0)",
1118 __func__, __LINE__, tlm, tlm->tlm_refcnt);
1123tcp_log_zone_dtor(
void *mem,
int size,
void *args __unused)
1125 struct tcp_log_mem *tlm;
1127 KASSERT(size >=
sizeof(
struct tcp_log_mem),
1128 (
"%s: unexpectedly short (%d) allocation", __func__, size));
1129 tlm = (
struct tcp_log_mem *)mem;
1130 if (tlm->tlm_refcnt != 0)
1131 panic(
"%s:%d: tlm(%p)->tlm_refcnt is %d (expected 0)",
1132 __func__, __LINE__, tlm, tlm->tlm_refcnt);
1141 tcp_log_zone = uma_zcreate(
"tcp_log",
sizeof(
struct tcp_log_mem),
1142#ifdef TCPLOG_DEBUG_RINGBUF
1143 tcp_log_zone_ctor, tcp_log_zone_dtor, tcp_log_zone_init,
1147 NULL, UMA_ALIGN_PTR, 0);
1155#ifdef TCPLOG_DEBUG_COUNTERS
1156 tcp_log_queued = counter_u64_alloc(M_WAITOK);
1157 tcp_log_que_fail1 = counter_u64_alloc(M_WAITOK);
1158 tcp_log_que_fail2 = counter_u64_alloc(M_WAITOK);
1159 tcp_log_que_fail3 = counter_u64_alloc(M_WAITOK);
1160 tcp_log_que_fail4 = counter_u64_alloc(M_WAITOK);
1161 tcp_log_que_fail5 = counter_u64_alloc(M_WAITOK);
1162 tcp_log_que_copyout = counter_u64_alloc(M_WAITOK);
1163 tcp_log_que_read = counter_u64_alloc(M_WAITOK);
1164 tcp_log_que_freed = counter_u64_alloc(M_WAITOK);
1166 tcp_log_pcb_ids_cur = counter_u64_alloc(M_WAITOK);
1167 tcp_log_pcb_ids_tot = counter_u64_alloc(M_WAITOK);
1170 mtx_init(&tcp_log_expireq_mtx,
"TCP log expireq", NULL, MTX_DEF);
1171 callout_init(&tcp_log_expireq_callout, 1);
1180 STAILQ_INIT(&tp->
t_logs);
1187 if ((tcp_log_auto_all ==
true) &&
1188 tcp_log_auto_mode &&
1201 sbintime_t expiry_limit;
1205 if (callout_pending(&tcp_log_expireq_callout)) {
1215 expiry_limit = getsbinuptime() + SBT_1S;
1218 while ((tln = STAILQ_FIRST(&tcp_log_expireq_head)) != NULL &&
1219 tln->tln_expiretime <= expiry_limit) {
1220 if (!callout_active(&tcp_log_expireq_callout)) {
1234 STAILQ_REMOVE_HEAD(&tcp_log_expireq_head, tln_expireq);
1235 tln->tln_expiretime = SBT_MAX;
1241 tlb = tln->tln_bucket;
1271 callout_deactivate(&tcp_log_expireq_callout);
1279 if (expiry_limit < tln->tln_expiretime)
1280 expiry_limit = tln->tln_expiretime;
1281 callout_reset_sbt(&tcp_log_expireq_callout, expiry_limit,
1305 tln->tln_af = AF_INET6;
1307 tln->tln_af = AF_INET;
1308 tln->tln_entries = tp->
t_logs;
1310 tln->tln_bucket = tp->
t_lib;
1313 STAILQ_INIT(&tp->
t_logs);
1322 struct tcp_log_mem *log_entry;
1323 sbintime_t callouttime;
1384 if (tp->
t_lin != NULL) {
1387 KASSERT(tln->tln_inp == tp->
t_inpcb,
1388 (
"%s: Mismatched inp (tln->tln_inp=%p, tp->t_inpcb=%p)",
1389 __func__, tln->tln_inp, tp->
t_inpcb));
1413 tln->tln_expiretime = getsbinuptime();
1415 if (tln->tln_count) {
1417 if (STAILQ_EMPTY(&tcp_log_expireq_head) &&
1418 !callout_active(&tcp_log_expireq_callout)) {
1424 callout_reset_sbt(&tcp_log_expireq_callout,
1428 STAILQ_INSERT_TAIL(&tcp_log_expireq_head, tln,
1431 callouttime = tln->tln_expiretime +
1433 tln_first = STAILQ_FIRST(&tcp_log_expireq_head);
1435 if ((tln_first == NULL ||
1436 callouttime < tln_first->tln_expiretime) &&
1437 (callout_pending(&tcp_log_expireq_callout) ||
1438 !callout_active(&tcp_log_expireq_callout))) {
1446 callout_reset_sbt(&tcp_log_expireq_callout,
1459 if (tln_first == NULL ||
1460 tln->tln_expiretime < tln_first->tln_expiretime)
1461 STAILQ_INSERT_HEAD(&tcp_log_expireq_head, tln,
1464 STAILQ_INSERT_AFTER(&tcp_log_expireq_head,
1465 tln_first, tln, tln_expireq);
1477 atomic_store_rel_int(&tln->tln_closed, 1);
1480 while ((log_entry = STAILQ_FIRST(&tp->
t_logs)) != NULL)
1483 (
"%s: After freeing entries, tp->t_lognum=%d (expected 0)",
1497 struct tcp_log_mem *log_entry;
1505 while ((log_entry = STAILQ_FIRST(&tp->
t_logs)) != NULL)
1508 (
"%s: After freeing entries, tp->t_lognum=%d (expected 0)",
1523 const char *output_caller,
const char *func,
int line,
const struct timeval *itv)
1525 struct tcp_log_mem *log_entry;
1527 int attempt_count = 0;
1531 KASSERT((func == NULL && line == 0) || (func != NULL && line > 0),
1532 (
"%s called with inconsistent func (%p) and line (%d) arguments",
1533 __func__, func, line));
1536 if (tcp_disable_all_bb_logs) {
1552 (
"%s called with unexpected tp->t_logstate (%d)", __func__,
1568 if ((log_entry = uma_zalloc(
tcp_log_zone, M_NOWAIT)) != NULL)
1574 if (log_entry == NULL) {
1582 !tcp_log_auto_all) {
1585 panic(
"%s:%d: tcp_log_state_change() failed "
1586 "to set tp %p to TCP_LOG_STATE_CLEAR",
1587 __func__, __LINE__, tp);
1606 if (attempt_count == 0) {
1610#ifdef TCPLOG_DEBUG_COUNTERS
1611 counter_u64_add(tcp_log_que_fail4, 1);
1632 if ((log_entry = STAILQ_FIRST(&tp->
t_logs)) == NULL)
1634 STAILQ_REMOVE_HEAD(&tp->
t_logs, tlm_queue);
1638 KASSERT(log_entry != NULL,
1639 (
"%s: log_entry unexpectedly NULL", __func__));
1642 log_buf = &log_entry->tlm_buf;
1643 log_verbose = &log_entry->tlm_v;
1647 getmicrouptime(&log_buf->
tlb_tv);
1649 memcpy(&log_buf->
tlb_tv, itv,
sizeof(
struct timeval));
1658 if (rxbuf != NULL) {
1664 if (txbuf != NULL) {
1671#define COPY_STAT(f) log_buf->tlb_ ## f = tp->f
1672#define COPY_STAT_T(f) log_buf->tlb_ ## f = tp->t_ ## f
1703 if (stackinfo != NULL) {
1718 optlen = (th->th_off << 2) -
sizeof (
struct tcphdr);
1720 memcpy(log_buf->
tlb_opts, th + 1, optlen);
1726 if (output_caller != NULL)
1736 STAILQ_INSERT_TAIL(&tp->
t_logs, log_entry, tlm_queue);
1748 struct tcp_log_mem *log_entry;
1753 while ((log_entry = STAILQ_FIRST(&tp->
t_logs)) != NULL)
1772 if (tcp_disable_all_bb_logs) {
1785 struct tcp_log_mem *log_entry, *
next;
1789 if ((target = tp->
t_lognum / 2) == 0)
1800 STAILQ_FOREACH(log_entry, &tp->
t_logs, tlm_queue)
1803 KASSERT(log_entry != NULL,
1804 (
"%s: skipped through all entries!", __func__));
1805 if (log_entry == NULL)
1807 while ((
next = STAILQ_NEXT(log_entry, tlm_queue)) != NULL) {
1808 STAILQ_REMOVE_AFTER(&tp->
t_logs, log_entry, tlm_queue);
1815 KASSERT(target == 0,
1816 (
"%s: After removing from tail, target was %d", __func__,
1822 while ((log_entry = STAILQ_FIRST(&tp->
t_logs)) != NULL &&
1825 KASSERT(target <= 0,
1826 (
"%s: After removing from head, target was %d", __func__,
1829 (
"%s: After removing from head, tp->t_lognum was %d",
1831 KASSERT(log_entry != NULL,
1832 (
"%s: After removing from head, the tailq was empty",
1841 if (sopt->sopt_td != NULL)
1842 return (copyout(src, dst, len));
1843 bcopy(src, dst, len);
1852 struct tcp_log_mem *log_entry;
1856 int orig_count =
count;
1862 STAILQ_FOREACH(log_entry, log_tailqp, tlm_queue) {
1865 (
"%s:%d: Exceeded expected count (%d) processing list %p",
1866 __func__, __LINE__, orig_count, log_tailqp));
1868#ifdef TCPLOG_DEBUG_COUNTERS
1869 counter_u64_add(tcp_log_que_copyout, 1);
1886 if (!(log_entry->tlm_buf.tlb_eventflags &
TLB_FLAG_HDR)) {
1888 ((
uint8_t *)out_entry) + entrysize,
1903 (((
uint8_t *) (out_entry + 1)) +
1909 KASSERT(error ||
count == 0,
1910 (
"%s:%d: Less than expected count (%d) processing list %p"
1911 " (%d remain)", __func__, __LINE__, orig_count,
1912 log_tailqp,
count));
1929 struct tcp_log_stailq log_tailq;
1930 struct tcp_log_mem *log_entry, *log_next;
1933 size_t outsize, entrysize;
1948 log_entry = STAILQ_LAST(&tp->
t_logs, tcp_log_mem, tlm_queue);
1954 outsize = outnum = 0;
1956 STAILQ_FOREACH(log_next, &tp->
t_logs, tlm_queue) {
1958 if (log_next->tlm_buf.tlb_eventflags &
1961 if ((sopt->sopt_valsize - outsize) < entrysize)
1963 outsize += entrysize;
1965 log_entry = log_next;
1967 KASSERT(outsize <= sopt->sopt_valsize,
1968 (
"%s: calculated output size (%zu) greater than available"
1969 "space (%zu)", __func__, outsize, sopt->sopt_valsize));
1981 if (sopt->sopt_val == NULL) {
1987 if (sopt->sopt_valsize > outsize)
1988 sopt->sopt_valsize = outsize;
2005 if (log_entry != NULL && log_next == NULL) {
2008 (
"%s:%d: outnum (%d) should match tp->t_lognum (%d)",
2009 __func__, __LINE__, outnum, tp->
t_lognum));
2012 STAILQ_INIT(&tp->
t_logs);
2013 }
else if (log_entry != NULL) {
2015 KASSERT(outnum < tp->t_lognum,
2016 (
"%s:%d: outnum (%d) not less than tp->t_lognum (%d)",
2017 __func__, __LINE__, outnum, tp->
t_lognum));
2018 STAILQ_FIRST(&log_tailq) = STAILQ_FIRST(&tp->
t_logs);
2019 STAILQ_FIRST(&tp->
t_logs) = STAILQ_NEXT(log_entry, tlm_queue);
2020 KASSERT(STAILQ_NEXT(log_entry, tlm_queue) != NULL,
2021 (
"%s:%d: tp->t_logs is unexpectedly shorter than expected"
2022 "(tp: %p, log_tailq: %p, outnum: %d, tp->t_lognum: %d)",
2023 __func__, __LINE__, tp, &log_tailq, outnum, tp->
t_lognum));
2024 STAILQ_NEXT(log_entry, tlm_queue) = NULL;
2025 log_tailq.stqh_last = &STAILQ_NEXT(log_entry, tlm_queue);
2028 STAILQ_INIT(&log_tailq);
2043 STAILQ_CONCAT(&log_tailq, &tp->
t_logs);
2050 KASSERT(((caddr_t)out_entry - (caddr_t)sopt->sopt_val) ==
2051 outsize, (
"%s: Actual output size (%zu) != "
2052 "calculated output size (%zu)", __func__,
2053 (
size_t)((caddr_t)out_entry - (caddr_t)sopt->sopt_val),
2057 STAILQ_FOREACH_SAFE(log_entry, &log_tailq, tlm_queue, log_next) {
2063 sopt->sopt_valsize = (size_t)((caddr_t)out_entry -
2064 (caddr_t)sopt->sopt_val);
2071 struct tcp_log_dev_log_queue *entry;
2073 KASSERT(param != NULL, (
"%s: called with NULL param", __func__));
2077 entry = (
struct tcp_log_dev_log_queue *)param;
2083 if (entry->tldl_common.tldq_buf != NULL)
2084 free(entry->tldl_common.tldq_buf, M_TCPLOGDEV);
2087 free(entry, M_TCPLOGDEV);
2090static struct tcp_log_common_header *
2093 struct tcp_log_dev_log_queue *entry;
2094 struct tcp_log_header *hdr;
2096 struct sockopt sopt;
2099 entry = (
struct tcp_log_dev_log_queue *)param;
2102 sopt.sopt_valsize =
sizeof(
struct tcp_log_header) +
2105 hdr = malloc(sopt.sopt_valsize, M_TCPLOGDEV, M_NOWAIT);
2107#ifdef TCPLOG_DEBUG_COUNTERS
2108 counter_u64_add(tcp_log_que_fail5, entry->tldl_count);
2112 sopt.sopt_val = hdr + 1;
2113 sopt.sopt_valsize -=
sizeof(
struct tcp_log_header);
2114 sopt.sopt_td = NULL;
2119 free(hdr, M_TCPLOGDEV);
2125 entry->tldl_count = 0;
2127 memset(hdr, 0,
sizeof(
struct tcp_log_header));
2129 hdr->tlh_type = TCP_LOG_DEV_TYPE_BBR;
2130 hdr->tlh_length = end - (
uint8_t *)hdr;
2131 hdr->tlh_ie = entry->tldl_ie;
2132 hdr->tlh_af = entry->tldl_af;
2133 getboottime(&hdr->tlh_offset);
2134 strlcpy(hdr->tlh_id, entry->tldl_id, TCP_LOG_ID_LEN);
2137 return ((
struct tcp_log_common_header *)hdr);
2154 struct tcp_log_dev_log_queue *entry;
2156#ifdef TCPLOG_DEBUG_COUNTERS
2169 !tcp_log_auto_all && !force) {
2170 struct tcp_log_mem *log_entry;
2178 while ((log_entry = STAILQ_FIRST(&tp->
t_logs)) != NULL)
2181 (
"%s: After freeing entries, tp->t_lognum=%d (expected 0)",
2192 entry = malloc(
sizeof(
struct tcp_log_dev_log_queue), M_TCPLOGDEV,
2194 if (entry == NULL && (how & M_NOWAIT)) {
2195#ifdef TCPLOG_DEBUG_COUNTERS
2196 counter_u64_add(tcp_log_que_fail3, 1);
2200 if (entry == NULL) {
2202 entry = malloc(
sizeof(
struct tcp_log_dev_log_queue),
2203 M_TCPLOGDEV, M_WAITOK);
2214 free(entry, M_TCPLOGDEV);
2215#ifdef TCPLOG_DEBUG_COUNTERS
2216 counter_u64_add(tcp_log_que_fail2, 1);
2218 return (ECONNRESET);
2222 free(entry, M_TCPLOGDEV);
2228 if (tp->
t_lib != NULL) {
2229 strlcpy(entry->tldl_id, tp->
t_lib->
tlb_id, TCP_LOG_ID_LEN);
2232 strlcpy(entry->tldl_id,
"UNKNOWN", TCP_LOG_ID_LEN);
2238 strlcpy(entry->tldl_reason,
"UNKNOWN", TCP_LOG_ID_LEN);
2241 entry->tldl_af = AF_INET6;
2243 entry->tldl_af = AF_INET;
2244 entry->tldl_entries = tp->
t_logs;
2248 entry->tldl_common.tldq_buf = NULL;
2253#ifdef TCPLOG_DEBUG_COUNTERS
2257 STAILQ_INIT(&tp->
t_logs);
2260 if (tcp_log_dev_add_log((
struct tcp_log_dev_queue *)entry)) {
2262#ifdef TCPLOG_DEBUG_COUNTERS
2263 counter_u64_add(tcp_log_que_fail1, num_entries);
2265 counter_u64_add(tcp_log_queued, num_entries);
2285 struct tcp_log_dev_log_queue *entry;
2288 tlb = tln->tln_bucket;
2290 KASSERT(tlb->tlb_refcnt > 0,
2291 (
"%s:%d: Called with unreferenced bucket (tln=%p, tlb=%p)",
2292 __func__, __LINE__, tln, tlb));
2293 KASSERT(tln->tln_closed,
2294 (
"%s:%d: Called for node with tln_closed==false (tln=%p)",
2295 __func__, __LINE__, tln));
2298 if (tln->tln_count == 0)
2306 entry = malloc(
sizeof(
struct tcp_log_dev_log_queue), M_TCPLOGDEV,
2308 if (entry == NULL && (how & M_NOWAIT))
2310 if (entry == NULL) {
2312 entry = malloc(
sizeof(
struct tcp_log_dev_log_queue),
2313 M_TCPLOGDEV, M_WAITOK);
2318 entry->tldl_common.tldq_buf = NULL;
2323 strlcpy(entry->tldl_id, tlb->
tlb_id, TCP_LOG_ID_LEN);
2328 strlcpy(entry->tldl_reason,
"UNKNOWN", TCP_LOG_ID_LEN);
2329 entry->tldl_ie = tln->tln_ie;
2330 entry->tldl_entries = tln->tln_entries;
2331 entry->tldl_count = tln->tln_count;
2332 entry->tldl_af = tln->tln_af;
2335 if (tcp_log_dev_add_log((
struct tcp_log_dev_queue *)entry))
2348#define LOCAL_SAVE 10
2356 int i, num_local_entries, tree_locked;
2357 bool expireq_locked;
2375 expireq_locked =
false;
2376 num_local_entries = 0;
2379 SLIST_FOREACH_SAFE(cur_tln, &tlb->tlb_head, tln_list, tmp_tln) {
2386 if (cur_tln->tln_closed) {
2393 if (!expireq_locked) {
2395 expireq_locked =
true;
2402 KASSERT(cur_tln->tln_expiretime > (sbintime_t) 0,
2403 (
"%s:%d: node on the expire queue without positive "
2404 "expire time", __func__, __LINE__));
2405 if (cur_tln->tln_expiretime == SBT_MAX) {
2411 STAILQ_REMOVE(&tcp_log_expireq_head, cur_tln,
2415 if (prev_tln != NULL)
2416 SLIST_REMOVE_AFTER(prev_tln, tln_list);
2418 SLIST_REMOVE_HEAD(&tlb->tlb_head, tln_list);
2426 expireq_locked =
false;
2435 panic(
"%s: Bucket refcount unexpectedly 0.",
2443 &cur_tln->tln_count);
2455 local_entries[num_local_entries] =
2457 num_local_entries++;
2460 &cur_tln->tln_entries,
2461 &cur_tln->tln_count);
2484 if (expireq_locked) {
2486 expireq_locked =
false;
2490 inp = cur_tln->tln_inp;
2498 if (cur_tln->tln_closed) {
2512 tp = cur_tln->tln_tp;
2516 &local_entries[num_local_entries]);
2517 local_entries[num_local_entries].tln_closed = 1;
2518 KASSERT(local_entries[num_local_entries].tln_bucket ==
2519 tlb, (
"%s: %d: bucket mismatch for node %p",
2520 __func__, __LINE__, cur_tln));
2521 num_local_entries++;
2535 (
"%s: %d: tree unexpectedly locked", __func__, __LINE__));
2536 switch (tree_locked) {
2546 if (expireq_locked) {
2548 expireq_locked =
false;
2556 for (i = 0; i < num_local_entries; i++)
2565 switch (tree_locked) {
2610 switch (tree_locked) {
SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW, &parse_http_version, 1, "Parse http version so that non 1.x requests work")
static SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "HTTP accept filter")
SYSCTL_BOOL(_net_inet_ip, OID_AUTO, broadcast_lowest, CTLFLAG_VNET|CTLFLAG_RW, &VNET_NAME(broadcast_lowest), 0, "Treat lowest address on a subnet (host 0) as broadcast")
SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxgrpsrc, CTLFLAG_RWTUN, &in_mcast_maxgrpsrc, 0, "Max source filters per group")
void in_pcbref(struct inpcb *inp)
bool in_pcbrele_wlocked(struct inpcb *inp)
#define INP_LOCK_ASSERT(inp)
#define INP_WLOCK_ASSERT(inp)
#define INP_UNLOCK_ASSERT(inp)
SYSCTL_UMA_CUR(_net_inet_ip, OID_AUTO, fragpackets, CTLFLAG_VNET, &VNET_NAME(ipq_zone), "Current number of IPv4 fragment reassembly queue entries")
struct in_endpoints inc_ie
struct socket * inp_socket
struct in_conninfo inp_inc
uint8_t tlb_opts[TCP_MAXOLEN]
struct tcp_log_sockbuf tlb_rxbuf
struct tcp_log_sockbuf tlb_txbuf
union tcp_log_stackspecific tlb_stackinfo
struct tcp_log_verbose tlb_verbose[0]
char tlb_id[TCP_LOG_ID_LEN]
char tlb_tag[TCP_LOG_TAG_LEN]
char tlv_trace_func[TCP_FUNC_LEN]
char tlv_snd_frm[TCP_FUNC_LEN]
struct tcp_log_stailq t_logs
struct tcp_log_id_bucket * t_lib
struct statsblob * t_stats
struct tcp_log_id_node * t_lin
struct tcp_function_block * t_fb
SYSCTL_COUNTER_U64(_net_inet_tcp_hpts_stats, OID_AUTO, hopeless, CTLFLAG_RD, &hpts_hopelessly_behind, "Number of times hpts could not catch up and was behind hopelessly")
int tcp_log_getlogbuf(struct sockopt *sopt, struct tcpcb *tp)
#define TCPID_BUCKET_REF(tlb)
static void tcp_log_remove_log_cleanup(struct tcpcb *tp, struct tcp_log_mem *log_entry)
static int tcp_log_copyout(struct sockopt *sopt, void *src, void *dst, size_t len)
#define tcp_log_entry_refcnt_rem(l)
static void tcp_log_grow_tlb(char *tlb_id, struct tcpcb *tp)
static int tcp_log_dump_node_logbuf(struct tcp_log_id_node *tln, char *reason, int how)
RB_HEAD(tcp_log_id_tree, tcp_log_id_bucket)
#define TCP_LOG_EXPIRE_TIME
void tcp_log_drain(struct tcpcb *tp)
#define RECHECK_INP_CLEAN(cleanup)
static void tcp_log_remove_log_head(struct tcpcb *tp, struct tcp_log_mem *log_entry)
#define TCPID_BUCKET_LOCK(tlb)
#define TCPID_TREE_RLOCK_ASSERT()
static uma_zone_t tcp_log_node_zone
#define TCPID_TREE_WLOCK()
void tcp_log_tcpcbinit(struct tcpcb *tp)
u_int tcp_log_get_id_cnt(struct tcpcb *tp)
void tcp_log_flowend(struct tcpcb *tp)
#define TCPID_BUCKET_LOCK_DESTROY(tlb)
#define TCPID_BUCKET_UNLOCK(tlb)
#define TCPID_TREE_RLOCK()
static int tcp_log_session_limit
static __inline bool tcp_log_selectauto(void)
#define TCPID_TREE_WUNLOCK()
struct tcp_log_buffer * tcp_log_event_(struct tcpcb *tp, struct tcphdr *th, struct sockbuf *rxbuf, struct sockbuf *txbuf, uint8_t eventid, int errornum, uint32_t len, union tcp_log_stackspecific *stackinfo, int th_hostorder, const char *output_caller, const char *func, int line, const struct timeval *itv)
#define TCPID_TREE_UNLOCK_ASSERT()
static uma_zone_t tcp_log_bucket_zone
int tcp_log_set_tag(struct tcpcb *tp, char *tag)
void tcp_log_tcpcbfini(struct tcpcb *tp)
static struct rwlock tcp_id_tree_lock
#define TCPID_BUCKET_LOCK_ASSERT(tlb)
static uint32_t tcp_log_version
size_t tcp_log_get_tag(struct tcpcb *tp, char *buf)
#define TCPID_TREE_WLOCK_ASSERT()
static uint8_t zerobuf[76]
#define TCPID_BUCKET_LOCK_INIT(tlb)
static STAILQ_HEAD(tcp_log_id_node)
static void tcp_log_purge_tp_logbuf(struct tcpcb *tp)
static void tcp_log_increment_reqcnt(struct tcp_log_id_bucket *tlb)
int tcp_log_set_id(struct tcpcb *tp, char *id)
#define TCPID_BUCKET_UNREF(tlb)
#define TCPID_TREE_RUNLOCK()
#define TCPID_TREE_UPGRADE()
int tcp_log_state_change(struct tcpcb *tp, int state)
#define tcp_log_entry_refcnt_add(l)
#define TCP_LOG_EXPIRE_INTVL
static int tcp_log_logs_to_buf(struct sockopt *sopt, struct tcp_log_stailq *log_tailqp, struct tcp_log_buffer **end, int count)
static void tcp_log_free_queue(struct tcp_log_dev_queue *param)
static bool tcp_log_unref_bucket(struct tcp_log_id_bucket *tlb, int *tree_locked, struct inpcb *inp)
int tcp_log_dump_tp_logbuf(struct tcpcb *tp, char *reason, int how, bool force)
static void tcp_log_dumpbucketlogs(struct tcp_log_id_bucket *tlb, char *reason)
static void tcp_log_expire(void *unused __unused)
#define TCPLOG_EXPIREQ_LOCK()
#define TCPLOG_EXPIREQ_UNLOCK()
static void tcp_log_free_log_common(struct tcp_log_mem *log_entry, int *count __unused)
static struct tcp_log_common_header * tcp_log_expandlogbuf(struct tcp_log_dev_queue *param)
static __inline int tcp_log_id_cmp(struct tcp_log_id_bucket *a, struct tcp_log_id_bucket *b)
void tcp_log_dump_tp_bucket_logbufs(struct tcpcb *tp, char *reason)
#define TCPID_BUCKET_UNLOCK_ASSERT(tlb)
SLIST_HEAD(tcp_log_id_head, tcp_log_id_node)
static __inline void tcp_log_id_validate_tree_lock(int tree_locked)
size_t tcp_log_get_id(struct tcpcb *tp, char *buf)
static void tcp_log_free_entries(struct tcp_log_stailq *head, int *count)
static struct tcp_log_id_tree tcp_log_id_head
static uma_zone_t tcp_log_zone
static __inline void tcp_log_remove_bucket(struct tcp_log_id_bucket *tlb)
static void tcp_log_move_tp_to_node(struct tcpcb *tp, struct tcp_log_id_node *tln)
static bool tcp_log_remove_id_node(struct inpcb *inp, struct tcpcb *tp, struct tcp_log_id_bucket *tlb, struct tcp_log_id_node *tln, int *tree_locked)
@ TCP_LOG_STATE_CONTINUAL
@ TCP_LOG_STATE_TAIL_AUTO
@ TCP_LOG_STATE_HEAD_AUTO
#define TCP_LOG_BUF_DEFAULT_SESSION_LIMIT
#define TCP_LOG_BUF_DEFAULT_GLOBAL_LIMIT
#define TCP_LOG_REASON_LEN
#define TCP_LOG_EVENT(tp, th, rxbuf, txbuf, eventid, errornum, len, stackinfo, th_hostorder)
#define TLB_FLAG_STACKINFO
int tcp_stats_sample_rollthedice(struct tcpcb *tp, void *seed_bytes, size_t seed_len)
static void tcp_fields_to_net(struct tcphdr *th)