Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_subr.c
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#endif | #endif | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet/tcp_log_buf.h> | |||||
#include <netinet/tcp_syncache.h> | #include <netinet/tcp_syncache.h> | ||||
#include <netinet/cc/cc.h> | #include <netinet/cc/cc.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet6/tcp6_var.h> | #include <netinet6/tcp6_var.h> | ||||
#endif | #endif | ||||
#include <netinet/tcpip.h> | #include <netinet/tcpip.h> | ||||
#include <netinet/tcp_fastopen.h> | #include <netinet/tcp_fastopen.h> | ||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
▲ Show 20 Lines • Show All 312 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, functions_available, | SYSCTL_PROC(_net_inet_tcp, OID_AUTO, functions_available, | ||||
CTLTYPE_STRING|CTLFLAG_RD, | CTLTYPE_STRING|CTLFLAG_RD, | ||||
NULL, 0, sysctl_net_inet_list_available, "A", | NULL, 0, sysctl_net_inet_list_available, "A", | ||||
"list available TCP Function sets"); | "list available TCP Function sets"); | ||||
/* | /* | ||||
* Exports one (struct tcp_function_id) for each non-alias. | |||||
*/ | |||||
static int | |||||
sysctl_net_inet_list_func_ids(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
int error, cnt; | |||||
struct tcp_function *f; | |||||
struct tcp_function_id tfi; | |||||
/* | |||||
* We don't allow writes. | |||||
*/ | |||||
if (req->newptr != NULL) | |||||
return (EINVAL); | |||||
/* | |||||
* Wire the old buffer so we can directly copy the functions to | |||||
* user space without dropping the lock. | |||||
*/ | |||||
if (req->oldptr != NULL) { | |||||
error = sysctl_wire_old_buffer(req, 0); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
/* | |||||
* Walk the list, comparing the name of the function entry and | |||||
* function block to determine which is an alias. | |||||
* If exporting the list, copy out matching entries. Otherwise, | |||||
* just record the total length. | |||||
*/ | |||||
cnt = 0; | |||||
rw_rlock(&tcp_function_lock); | |||||
TAILQ_FOREACH(f, &t_functions, tf_next) { | |||||
if (strncmp(f->tf_name, f->tf_fb->tfb_tcp_block_name, | |||||
TCP_FUNCTION_NAME_LEN_MAX)) | |||||
continue; | |||||
if (req->oldptr != NULL) { | |||||
tfi.tfi_id = f->tf_fb->tfb_id; | |||||
(void)strncpy(tfi.tfi_name, f->tf_name, | |||||
TCP_FUNCTION_NAME_LEN_MAX); | |||||
tfi.tfi_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; | |||||
error = SYSCTL_OUT(req, &tfi, sizeof(tfi)); | |||||
/* | |||||
* Don't stop on error, as that is the | |||||
* mechanism we use to accumulate length | |||||
* information if the buffer was too short. | |||||
*/ | |||||
} else | |||||
cnt++; | |||||
} | |||||
rw_runlock(&tcp_function_lock); | |||||
if (req->oldptr == NULL) | |||||
error = SYSCTL_OUT(req, NULL, | |||||
(cnt + 1) * sizeof(struct tcp_function_id)); | |||||
return (error); | |||||
} | |||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, function_ids, | |||||
CTLTYPE_OPAQUE | CTLFLAG_SKIP | CTLFLAG_RD | CTLFLAG_MPSAFE, | |||||
NULL, 0, sysctl_net_inet_list_func_ids, "S,tcp_function_id", | |||||
"List TCP function block name-to-ID mappings"); | |||||
/* | |||||
* Target size of TCP PCB hash tables. Must be a power of two. | * Target size of TCP PCB hash tables. Must be a power of two. | ||||
* | * | ||||
* Note that this can be overridden by the kernel environment | * Note that this can be overridden by the kernel environment | ||||
* variable net.inet.tcp.tcbhashsize | * variable net.inet.tcp.tcbhashsize | ||||
*/ | */ | ||||
#ifndef TCBHASHSIZE | #ifndef TCBHASHSIZE | ||||
#define TCBHASHSIZE 0 | #define TCBHASHSIZE 0 | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | maketcp_hashsize(int size) | ||||
hashsize = 1 << fls(size); | hashsize = 1 << fls(size); | ||||
/* catch overflow, and just go one power of 2 smaller */ | /* catch overflow, and just go one power of 2 smaller */ | ||||
if (hashsize < size) { | if (hashsize < size) { | ||||
hashsize = 1 << (fls(size) - 1); | hashsize = 1 << (fls(size) - 1); | ||||
} | } | ||||
return (hashsize); | return (hashsize); | ||||
} | } | ||||
static volatile int next_tcp_stack_id = 1; | |||||
/* | /* | ||||
* Register a TCP function block with the name provided in the names | * Register a TCP function block with the name provided in the names | ||||
* array. (Note that this function does NOT automatically register | * array. (Note that this function does NOT automatically register | ||||
* blk->tfb_tcp_block_name as a stack name. Therefore, you should | * blk->tfb_tcp_block_name as a stack name. Therefore, you should | ||||
* explicitly include blk->tfb_tcp_block_name in the list of names if | * explicitly include blk->tfb_tcp_block_name in the list of names if | ||||
* you wish to register the stack with that name.) | * you wish to register the stack with that name.) | ||||
* | * | ||||
* Either all name registrations will succeed or all will fail. If | * Either all name registrations will succeed or all will fail. If | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if ((blk->tfb_tcp_timer_stop_all == NULL) || | ||||
(blk->tfb_tcp_timer_stop == NULL)) { | (blk->tfb_tcp_timer_stop == NULL)) { | ||||
*num_names = 0; | *num_names = 0; | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
refcount_init(&blk->tfb_refcnt, 0); | refcount_init(&blk->tfb_refcnt, 0); | ||||
blk->tfb_flags = 0; | blk->tfb_flags = 0; | ||||
blk->tfb_id = atomic_fetchadd_int(&next_tcp_stack_id, 1); | |||||
for (i = 0; i < *num_names; i++) { | for (i = 0; i < *num_names; i++) { | ||||
n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); | n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); | ||||
if (n == NULL) { | if (n == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
n->tf_fb = blk; | n->tf_fb = blk; | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | #endif | ||||
tcp_persmin = TCPTV_PERSMIN; | tcp_persmin = TCPTV_PERSMIN; | ||||
tcp_persmax = TCPTV_PERSMAX; | tcp_persmax = TCPTV_PERSMAX; | ||||
tcp_rexmit_slop = TCPTV_CPU_VAR; | tcp_rexmit_slop = TCPTV_CPU_VAR; | ||||
tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT; | tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT; | ||||
tcp_tcbhashsize = hashsize; | tcp_tcbhashsize = hashsize; | ||||
/* Setup the tcp function block list */ | /* Setup the tcp function block list */ | ||||
init_tcp_functions(); | init_tcp_functions(); | ||||
register_tcp_functions(&tcp_def_funcblk, M_WAITOK); | register_tcp_functions(&tcp_def_funcblk, M_WAITOK); | ||||
/* Initialize the TCP logging data. */ | |||||
tcp_log_init(); | |||||
if (tcp_soreceive_stream) { | if (tcp_soreceive_stream) { | ||||
#ifdef INET | #ifdef INET | ||||
tcp_usrreqs.pru_soreceive = soreceive_stream; | tcp_usrreqs.pru_soreceive = soreceive_stream; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
tcp6_usrreqs.pru_soreceive = soreceive_stream; | tcp6_usrreqs.pru_soreceive = soreceive_stream; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | #endif /* INET6 */ | ||||
inp->inp_ip_ttl = V_ip_defttl; | inp->inp_ip_ttl = V_ip_defttl; | ||||
inp->inp_ppcb = tp; | inp->inp_ppcb = tp; | ||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
/* | /* | ||||
* Init the TCP PCAP queues. | * Init the TCP PCAP queues. | ||||
*/ | */ | ||||
tcp_pcap_tcpcb_init(tp); | tcp_pcap_tcpcb_init(tp); | ||||
#endif | #endif | ||||
/* Initialize the per-TCPCB log data. */ | |||||
tcp_log_tcpcbinit(tp); | |||||
if (tp->t_fb->tfb_tcp_fb_init) { | if (tp->t_fb->tfb_tcp_fb_init) { | ||||
(*tp->t_fb->tfb_tcp_fb_init)(tp); | (*tp->t_fb->tfb_tcp_fb_init)(tp); | ||||
} | } | ||||
return (tp); /* XXX */ | return (tp); /* XXX */ | ||||
} | } | ||||
/* | /* | ||||
* Switch the congestion control algorithm back to NewReno for any active | * Switch the congestion control algorithm back to NewReno for any active | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | |||||
#ifdef TCP_HHOOK | #ifdef TCP_HHOOK | ||||
khelp_destroy_osd(tp->osd); | khelp_destroy_osd(tp->osd); | ||||
#endif | #endif | ||||
CC_ALGO(tp) = NULL; | CC_ALGO(tp) = NULL; | ||||
inp->inp_ppcb = NULL; | inp->inp_ppcb = NULL; | ||||
if (tp->t_timers->tt_draincnt == 0) { | if (tp->t_timers->tt_draincnt == 0) { | ||||
/* We own the last reference on tcpcb, let's free it. */ | /* We own the last reference on tcpcb, let's free it. */ | ||||
tcp_log_tcpcbfini(tp); | |||||
TCPSTATES_DEC(tp->t_state); | TCPSTATES_DEC(tp->t_state); | ||||
if (tp->t_fb->tfb_tcp_fb_fini) | if (tp->t_fb->tfb_tcp_fb_fini) | ||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | ||||
refcount_release(&tp->t_fb->tfb_refcnt); | refcount_release(&tp->t_fb->tfb_refcnt); | ||||
tp->t_inpcb = NULL; | tp->t_inpcb = NULL; | ||||
uma_zfree(V_tcpcb_zone, tp); | uma_zfree(V_tcpcb_zone, tp); | ||||
released = in_pcbrele_wlocked(inp); | released = in_pcbrele_wlocked(inp); | ||||
KASSERT(!released, ("%s: inp %p should not have been released " | KASSERT(!released, ("%s: inp %p should not have been released " | ||||
Show All 14 Lines | tcp_timer_discard(void *ptp) | ||||
KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", | KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", | ||||
__func__, tp)); | __func__, tp)); | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, | KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, | ||||
("%s: tcpcb has to be stopped here", __func__)); | ("%s: tcpcb has to be stopped here", __func__)); | ||||
tp->t_timers->tt_draincnt--; | tp->t_timers->tt_draincnt--; | ||||
if (tp->t_timers->tt_draincnt == 0) { | if (tp->t_timers->tt_draincnt == 0) { | ||||
/* We own the last reference on this tcpcb, let's free it. */ | /* We own the last reference on this tcpcb, let's free it. */ | ||||
tcp_log_tcpcbfini(tp); | |||||
TCPSTATES_DEC(tp->t_state); | TCPSTATES_DEC(tp->t_state); | ||||
if (tp->t_fb->tfb_tcp_fb_fini) | if (tp->t_fb->tfb_tcp_fb_fini) | ||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); | ||||
refcount_release(&tp->t_fb->tfb_refcnt); | refcount_release(&tp->t_fb->tfb_refcnt); | ||||
tp->t_inpcb = NULL; | tp->t_inpcb = NULL; | ||||
uma_zfree(V_tcpcb_zone, tp); | uma_zfree(V_tcpcb_zone, tp); | ||||
if (in_pcbrele_wlocked(inp)) { | if (in_pcbrele_wlocked(inp)) { | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | */ | ||||
INP_INFO_WLOCK(&V_tcbinfo); | INP_INFO_WLOCK(&V_tcbinfo); | ||||
LIST_FOREACH(inpb, V_tcbinfo.ipi_listhead, inp_list) { | LIST_FOREACH(inpb, V_tcbinfo.ipi_listhead, inp_list) { | ||||
if (inpb->inp_flags & INP_TIMEWAIT) | if (inpb->inp_flags & INP_TIMEWAIT) | ||||
continue; | continue; | ||||
INP_WLOCK(inpb); | INP_WLOCK(inpb); | ||||
if ((tcpb = intotcpcb(inpb)) != NULL) { | if ((tcpb = intotcpcb(inpb)) != NULL) { | ||||
tcp_reass_flush(tcpb); | tcp_reass_flush(tcpb); | ||||
tcp_clean_sackreport(tcpb); | tcp_clean_sackreport(tcpb); | ||||
tcp_log_drain(tcpb); | |||||
#ifdef TCPPCAP | #ifdef TCPPCAP | ||||
if (tcp_pcap_aggressive_free) { | if (tcp_pcap_aggressive_free) { | ||||
/* Free the TCP PCAP queues. */ | /* Free the TCP PCAP queues. */ | ||||
tcp_pcap_drain(&(tcpb->t_inpkts)); | tcp_pcap_drain(&(tcpb->t_inpkts)); | ||||
tcp_pcap_drain(&(tcpb->t_outpkts)); | tcp_pcap_drain(&(tcpb->t_outpkts)); | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,140 Lines • ▼ Show 20 Lines | tcp_inptoxtp(const struct inpcb *inp, struct xtcpcb *xt) | ||||
struct tcpcb *tp = intotcpcb(inp); | struct tcpcb *tp = intotcpcb(inp); | ||||
sbintime_t now; | sbintime_t now; | ||||
if (inp->inp_flags & INP_TIMEWAIT) { | if (inp->inp_flags & INP_TIMEWAIT) { | ||||
bzero(xt, sizeof(struct xtcpcb)); | bzero(xt, sizeof(struct xtcpcb)); | ||||
xt->t_state = TCPS_TIME_WAIT; | xt->t_state = TCPS_TIME_WAIT; | ||||
} else { | } else { | ||||
xt->t_state = tp->t_state; | xt->t_state = tp->t_state; | ||||
xt->t_logstate = tp->t_logstate; | |||||
xt->t_flags = tp->t_flags; | xt->t_flags = tp->t_flags; | ||||
xt->t_sndzerowin = tp->t_sndzerowin; | xt->t_sndzerowin = tp->t_sndzerowin; | ||||
xt->t_sndrexmitpack = tp->t_sndrexmitpack; | xt->t_sndrexmitpack = tp->t_sndrexmitpack; | ||||
xt->t_rcvoopack = tp->t_rcvoopack; | xt->t_rcvoopack = tp->t_rcvoopack; | ||||
now = getsbinuptime(); | now = getsbinuptime(); | ||||
#define COPYTIMER(ttt) do { \ | #define COPYTIMER(ttt) do { \ | ||||
if (callout_active(&tp->t_timers->ttt)) \ | if (callout_active(&tp->t_timers->ttt)) \ | ||||
xt->ttt = (tp->t_timers->ttt.c_time - now) / \ | xt->ttt = (tp->t_timers->ttt.c_time - now) / \ | ||||
SBT_1MS; \ | SBT_1MS; \ | ||||
else \ | else \ | ||||
xt->ttt = 0; \ | xt->ttt = 0; \ | ||||
} while (0) | } while (0) | ||||
COPYTIMER(tt_delack); | COPYTIMER(tt_delack); | ||||
COPYTIMER(tt_rexmt); | COPYTIMER(tt_rexmt); | ||||
COPYTIMER(tt_persist); | COPYTIMER(tt_persist); | ||||
COPYTIMER(tt_keep); | COPYTIMER(tt_keep); | ||||
COPYTIMER(tt_2msl); | COPYTIMER(tt_2msl); | ||||
#undef COPYTIMER | #undef COPYTIMER | ||||
xt->t_rcvtime = 1000 * (ticks - tp->t_rcvtime) / hz; | xt->t_rcvtime = 1000 * (ticks - tp->t_rcvtime) / hz; | ||||
bcopy(tp->t_fb->tfb_tcp_block_name, xt->xt_stack, | bcopy(tp->t_fb->tfb_tcp_block_name, xt->xt_stack, | ||||
TCP_FUNCTION_NAME_LEN_MAX); | TCP_FUNCTION_NAME_LEN_MAX); | ||||
bzero(xt->xt_logid, TCP_LOG_ID_LEN); | |||||
(void)tcp_log_get_id(tp, xt->xt_logid); | |||||
} | } | ||||
xt->xt_len = sizeof(struct xtcpcb); | xt->xt_len = sizeof(struct xtcpcb); | ||||
in_pcbtoxinpcb(inp, &xt->xt_inp); | in_pcbtoxinpcb(inp, &xt->xt_inp); | ||||
if (inp->inp_socket == NULL) | if (inp->inp_socket == NULL) | ||||
xt->xt_inp.xi_socket.xso_protocol = IPPROTO_TCP; | xt->xt_inp.xi_socket.xso_protocol = IPPROTO_TCP; | ||||
} | } |