Changeset View
Standalone View
sys/netinet/tcp_subr.c
Show First 20 Lines • Show All 1,749 Lines • ▼ Show 20 Lines | tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m, | ||||
struct tcphdr *nth; | struct tcphdr *nth; | ||||
struct tcp_log_buffer *lgb; | struct tcp_log_buffer *lgb; | ||||
u_char *optp; | u_char *optp; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
int isipv6; | int isipv6; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
int optlen, tlen, win, ulen; | int optlen, tlen, win, ulen; | ||||
bool incl_opts; | bool incl_opts, lock_upgraded; | ||||
uint16_t port; | uint16_t port; | ||||
int output_ret; | int output_ret; | ||||
KASSERT(tp != NULL || m != NULL, ("tcp_respond: tp and m both NULL")); | KASSERT(tp != NULL || m != NULL, ("tcp_respond: tp and m both NULL")); | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
isipv6 = ((struct ip *)ipgen)->ip_v == (IPV6_VERSION >> 4); | isipv6 = ((struct ip *)ipgen)->ip_v == (IPV6_VERSION >> 4); | ||||
▲ Show 20 Lines • Show All 316 Lines • ▼ Show 20 Lines | |||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (tp == NULL || (inp->inp_socket->so_options & SO_DEBUG)) | if (tp == NULL || (inp->inp_socket->so_options & SO_DEBUG)) | ||||
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); | tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__output, tp, th, m); | TCP_PROBE3(debug__output, tp, th, m); | ||||
if (flags & TH_RST) | if (flags & TH_RST) | ||||
TCP_PROBE5(accept__refused, NULL, NULL, m, tp, nth); | TCP_PROBE5(accept__refused, NULL, NULL, m, tp, nth); | ||||
lock_upgraded = false; | |||||
lgb = NULL; | |||||
if ((tp != NULL) && (tp->t_logstate != TCP_LOG_STATE_OFF)) { | if ((tp != NULL) && (tp->t_logstate != TCP_LOG_STATE_OFF)) { | ||||
union tcp_log_stackspecific log; | union tcp_log_stackspecific log; | ||||
struct timeval tv; | struct timeval tv; | ||||
lock_upgraded = !INP_WLOCKED(inp) && INP_TRY_UPGRADE(inp); | |||||
/* | |||||
*`If we don't already own the write lock and can't upgrade, | |||||
* just don't log the event, but still send the response. | |||||
*/ | |||||
if (INP_WLOCKED(inp)) { | |||||
memset(&log.u_bbr, 0, sizeof(log.u_bbr)); | memset(&log.u_bbr, 0, sizeof(log.u_bbr)); | ||||
log.u_bbr.inhpts = tp->t_inpcb->inp_in_hpts; | log.u_bbr.inhpts = tp->t_inpcb->inp_in_hpts; | ||||
log.u_bbr.ininput = tp->t_inpcb->inp_in_input; | log.u_bbr.ininput = tp->t_inpcb->inp_in_input; | ||||
log.u_bbr.flex8 = 4; | log.u_bbr.flex8 = 4; | ||||
log.u_bbr.pkts_out = tp->t_maxseg; | log.u_bbr.pkts_out = tp->t_maxseg; | ||||
log.u_bbr.timeStamp = tcp_get_usecs(&tv); | log.u_bbr.timeStamp = tcp_get_usecs(&tv); | ||||
log.u_bbr.delivered = 0; | log.u_bbr.delivered = 0; | ||||
lgb = tcp_log_event_(tp, nth, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK, | lgb = tcp_log_event_(tp, nth, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK, | ||||
markj: I'm not familiar with TCP logging. Why is it ok to silently drop an event? Is it generally best… | |||||
Done Inline ActionsThe alternatives would be:
But I'm fine with the alternatives... Just thought that the solution chosen has the least negative impact. tuexen: The alternatives would be:
* Also drop the packet (a RST not affecting the connection in this… | |||||
Done Inline ActionsIt's up to you. Generally logging frameworks try hard to either log an event or log a notification saying that an event was dropped. Silently dropping an event can make for some very frustrating debugging if one is relying on tcp logging to be reliable. I don't see any problems with the change as it is, but I suspect someone more familiar with TCP debugging should weigh in. markj: It's up to you. Generally logging frameworks try hard to either log an event or log a… | |||||
Done Inline ActionsLet's see what rrs@ and jtl@ want to say on this... tuexen: Let's see what rrs@ and jtl@ want to say on this... | |||||
Done Inline ActionsLogging is always best effort. I would have done this a bit different, instead of trying to rrs: Logging is always best effort. I would have done this a bit different, instead of trying to… | |||||
Not Done Inline ActionsWhile I agree that logging any given event is indeed best effort, I strongly agree with @markj's comment that we should always capture when an attempt to log something is unsuccessful. The tcp log buf has the notion of a monotonically increasing record serial number which is the primary mechanism to tell when log events have gone missing for any reason, and so I'd suggest we use that here i.e. figure out a way to increment the serial number without actually writing the log. lstewart: While I agree that logging any given event is indeed best effort, I strongly agree with… | |||||
Done Inline ActionsThe reason we are not incrementing tp->t_logsn is that this requires holding the write lock, we we only have the read lock... tuexen: The reason we are not incrementing `tp->t_logsn` is that this requires holding the write lock… | |||||
Not Done Inline ActionsIf we hold the inp read lock, wouldn't an atomic increment of tp->t_logsn be fine in the "failed to upgrade" case? lstewart: If we hold the inp read lock, wouldn't an atomic increment of `tp->t_logsn` be fine in the… | |||||
0, &log, false, NULL, NULL, 0, &tv); | 0, &log, false, NULL, NULL, 0, &tv); | ||||
} else | } | ||||
lgb = NULL; | } | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (isipv6) { | if (isipv6) { | ||||
TCP_PROBE5(send, NULL, tp, ip6, tp, nth); | TCP_PROBE5(send, NULL, tp, ip6, tp, nth); | ||||
output_ret = ip6_output(m, NULL, NULL, 0, NULL, NULL, inp); | output_ret = ip6_output(m, NULL, NULL, 0, NULL, NULL, inp); | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
#if defined(INET) && defined(INET6) | #if defined(INET) && defined(INET6) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
{ | { | ||||
TCP_PROBE5(send, NULL, tp, ip, tp, nth); | TCP_PROBE5(send, NULL, tp, ip, tp, nth); | ||||
output_ret = ip_output(m, NULL, NULL, 0, NULL, inp); | output_ret = ip_output(m, NULL, NULL, 0, NULL, inp); | ||||
} | } | ||||
#endif | #endif | ||||
if (lgb) { | if (lgb != NULL) | ||||
lgb->tlb_errno = output_ret; | lgb->tlb_errno = output_ret; | ||||
lgb = NULL; | if (lock_upgraded) | ||||
} | INP_DOWNGRADE(inp); | ||||
} | } | ||||
/* | /* | ||||
* Create a new TCP control block, making an | * Create a new TCP control block, making an | ||||
* empty reassembly queue and hooking it to the argument | * empty reassembly queue and hooking it to the argument | ||||
* protocol control block. The `inp' parameter must have | * protocol control block. The `inp' parameter must have | ||||
* come from the zone allocator set up in tcp_init(). | * come from the zone allocator set up in tcp_init(). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 2,107 Lines • Show Last 20 Lines |
I'm not familiar with TCP logging. Why is it ok to silently drop an event? Is it generally best-effort?