* ticks to timer units */
#define TCP_DELACK_TIME 1 /* 0.1s */
#define TCP_ESTABLISH_TIME 750 /* 75s */
+#define TCP_SYN_RCVD_TIME 600 /* 60s */
#define TCP_2MSL_TIME 300 /* 30s */
-#define TCP_CLOSEWAIT_TIME 20 /* 0.1s */
-#define TCP_CLEANUP_TIME 5 /* 0.5s Time to wait before cleanup */
+#define TCP_CLOSEWAIT_TIME 20 /* 2s */
+#define TCP_TIMEWAIT_TIME 100 /* 10s */
+#define TCP_CLEANUP_TIME 10 /* 1s Time to wait before cleanup */
#define TCP_TIMER_PERSIST_MIN 2 /* 0.2s */
#define TCP_RTO_MAX 60 * THZ /* Min max RTO (60s) as per RFC6298 */
#define foreach_tcp_connection_flag \
_(SNDACK, "Send ACK") \
_(FINSNT, "FIN sent") \
- _(SENT_RCV_WND0, "Sent 0 receive window") \
- _(RECOVERY, "Recovery on") \
- _(FAST_RECOVERY, "Fast Recovery on") \
+ _(SENT_RCV_WND0, "Sent 0 rcv_wnd") \
+ _(RECOVERY, "Recovery") \
+ _(FAST_RECOVERY, "Fast Recovery") \
_(FR_1_SMSS, "Sent 1 SMSS") \
- _(HALF_OPEN_DONE, "Half-open completed")
+ _(HALF_OPEN_DONE, "Half-open completed") \
+ _(FINPNDG, "FIN pending")
typedef enum _tcp_connection_flag_bits
{
u8 log2_tstamp_clocks_per_tick;
f64 tstamp_ticks_per_clock;
+ u32 *time_now;
/** per-worker tx buffer free lists */
u32 **tx_buffers;
+ /** per-worker tx frames to tcp 4/6 output nodes */
+ vlib_frame_t **tx_frames[2];
+ /** per-worker tx frames to ip 4/6 lookup nodes */
+ vlib_frame_t **ip_lookup_tx_frames[2];
/* Per worker-thread timer wheel for connections timers */
tw_timer_wheel_16t_2w_512sl_t *timer_wheels;
tcp_connection_t *half_open_connections;
clib_spinlock_t half_open_lock;
- /* Pool of local TCP endpoints */
- transport_endpoint_t *local_endpoints;
-
- /* Local endpoints lookup table */
- transport_endpoint_table_t local_endpoints_table;
- clib_spinlock_t local_endpoints_lock;
-
/* Congestion control algorithms registered */
tcp_cc_algorithm_t *cc_algos;
u32 preallocated_connections;
u32 preallocated_half_open_connections;
+ /** Transport table (preallocation) size parameters */
+ u32 local_endpoints_table_memory;
+ u32 local_endpoints_table_buckets;
+
/** Vectors of src addresses. Optional unless one needs > 63K active-opens */
ip4_address_t *ip4_src_addresses;
u32 last_v4_address_rotor;
u32 last_v6_address_rotor;
ip6_address_t *ip6_src_addresses;
- /* convenience */
- vlib_main_t *vlib_main;
- vnet_main_t *vnet_main;
- ip4_main_t *ip4_main;
- ip6_main_t *ip6_main;
+ /** vlib buffer size */
+ u32 bytes_per_buffer;
+
+ u8 punt_unknown4;
+ u8 punt_unknown6;
} tcp_main_t;
extern tcp_main_t tcp_main;
clib_error_t *vnet_tcp_enable_disable (vlib_main_t * vm, u8 is_en);
+void tcp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
+
always_inline tcp_connection_t *
tcp_connection_get (u32 conn_index, u32 thread_index)
{
int tcp_half_open_connection_cleanup (tcp_connection_t * tc);
tcp_connection_t *tcp_connection_new (u8 thread_index);
void tcp_connection_reset (tcp_connection_t * tc);
-
+int tcp_configure_v4_source_address_range (vlib_main_t * vm,
+ ip4_address_t * start,
+ ip4_address_t * end, u32 table_id);
+int tcp_configure_v6_source_address_range (vlib_main_t * vm,
+ ip6_address_t * start,
+ ip6_address_t * end, u32 table_id);
+void tcp_api_reference (void);
u8 *format_tcp_connection_id (u8 * s, va_list * args);
u8 *format_tcp_connection (u8 * s, va_list * args);
u8 *format_tcp_scoreboard (u8 * s, va_list * args);
void tcp_make_ack (tcp_connection_t * ts, vlib_buffer_t * b);
void tcp_make_fin (tcp_connection_t * tc, vlib_buffer_t * b);
void tcp_make_synack (tcp_connection_t * ts, vlib_buffer_t * b);
-void tcp_send_reset (tcp_connection_t * tc, vlib_buffer_t * pkt, u8 is_ip4);
+void tcp_send_reset_w_pkt (tcp_connection_t * tc, vlib_buffer_t * pkt,
+ u8 is_ip4);
+void tcp_send_reset (tcp_connection_t * tc);
void tcp_send_syn (tcp_connection_t * tc);
void tcp_send_fin (tcp_connection_t * tc);
void tcp_init_mss (tcp_connection_t * tc);
void tcp_update_snd_mss (tcp_connection_t * tc);
void tcp_update_rto (tcp_connection_t * tc);
+void tcp_flush_frame_to_output (vlib_main_t * vm, u8 thread_index, u8 is_ip4);
+void tcp_flush_frames_to_output (u8 thread_index);
always_inline u32
tcp_end_seq (tcp_header_t * th, u32 len)
}
always_inline u32
-tcp_available_wnd (const tcp_connection_t * tc)
+tcp_available_snd_wnd (const tcp_connection_t * tc)
{
return clib_min (tc->cwnd, tc->snd_wnd);
}
+always_inline u32
+tcp_available_output_snd_space (const tcp_connection_t * tc)
+{
+ u32 available_wnd = tcp_available_snd_wnd (tc);
+ int flight_size = (int) (tc->snd_nxt - tc->snd_una);
+
+ if (available_wnd <= flight_size)
+ return 0;
+
+ return available_wnd - flight_size;
+}
+
+/**
+ * Estimate of how many bytes we can still push into the network
+ */
always_inline u32
tcp_available_snd_space (const tcp_connection_t * tc)
{
- u32 available_wnd = tcp_available_wnd (tc);
+ u32 available_wnd = tcp_available_snd_wnd (tc);
u32 flight_size = tcp_flight_size (tc);
if (available_wnd <= flight_size)
return available_wnd - flight_size;
}
+always_inline u8
+tcp_is_lost_fin (tcp_connection_t * tc)
+{
+ if ((tc->flags & TCP_CONN_FINSNT) && tc->snd_una_max - tc->snd_una == 1)
+ return 1;
+ return 0;
+}
+
i32 tcp_rcv_wnd_available (tcp_connection_t * tc);
u32 tcp_snd_space (tcp_connection_t * tc);
void tcp_update_rcv_wnd (tcp_connection_t * tc);
always_inline u32
tcp_time_now (void)
{
- return clib_cpu_time_now () * tcp_main.tstamp_ticks_per_clock;
+ return tcp_main.time_now[vlib_get_thread_index ()];
+}
+
+always_inline u32
+tcp_set_time_now (u32 thread_index)
+{
+ tcp_main.time_now[thread_index] = clib_cpu_time_now ()
+ * tcp_main.tstamp_ticks_per_clock;
+ return tcp_main.time_now[thread_index];
}
always_inline void
tcp_update_time (f64 now, u32 thread_index)
{
+ tcp_set_time_now (thread_index);
tw_timer_expire_timers_16t_2w_512sl (&tcp_main.timer_wheels[thread_index],
now);
+ tcp_flush_frames_to_output (thread_index);
}
u32 tcp_push_header (transport_connection_t * tconn, vlib_buffer_t * b);
u32
-tcp_prepare_retransmit_segment (tcp_connection_t * tc, vlib_buffer_t * b,
- u32 offset, u32 max_bytes);
+tcp_prepare_retransmit_segment (tcp_connection_t * tc, u32 offset,
+ u32 max_bytes, vlib_buffer_t ** b);
void tcp_connection_timers_init (tcp_connection_t * tc);
void tcp_connection_timers_reset (tcp_connection_t * tc);
+void tcp_init_snd_vars (tcp_connection_t * tc);
void tcp_connection_init_vars (tcp_connection_t * tc);
always_inline void
tcp_timer_set (tcp_connection_t * tc, u8 timer_id, u32 interval)
{
ASSERT (tc->c_thread_index == vlib_get_thread_index ());
+ ASSERT (tc->timers[timer_id] == TCP_TIMER_HANDLE_INVALID);
tc->timers[timer_id]
= tw_timer_start_16t_2w_512sl (&tcp_main.timer_wheels[tc->c_thread_index],
tc->c_c_index, timer_id, interval);
always_inline void
tcp_retransmit_timer_set (tcp_connection_t * tc)
{
+ ASSERT (tc->snd_una != tc->snd_una_max);
tcp_timer_set (tc, TCP_TIMER_RETRANSMIT,
clib_max (tc->rto * TCP_TO_TIMER_TICK, 1));
}
{
tcp_retransmit_timer_reset (tc);
if (tc->snd_wnd < tc->snd_mss)
- tcp_persist_timer_set (tc);
+ tcp_persist_timer_update (tc);
}
else
tcp_timer_update (tc, TCP_TIMER_RETRANSMIT,