tcp: move features to separate files
Type: refactor Signed-off-by: Florin Coras <fcoras@cisco.com> Change-Id: Ia477b8dba9266f47907967e363c11048e5cd95ab
This commit is contained in:
committed by
Dave Barach
parent
a26f54421a
commit
999840cf80
@@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <vnet/tcp/tcp.h>
|
||||
#include <vnet/tcp/tcp_inlines.h>
|
||||
|
||||
#define TCP_TEST_I(_cond, _comment, _args...) \
|
||||
({ \
|
||||
|
||||
@@ -659,9 +659,11 @@ list(APPEND VNET_SOURCES
|
||||
tcp/tcp_output.c
|
||||
tcp/tcp_input.c
|
||||
tcp/tcp_newreno.c
|
||||
tcp/tcp_cubic.c
|
||||
tcp/tcp_bt.c
|
||||
tcp/tcp_cli.c
|
||||
tcp/tcp_cubic.c
|
||||
tcp/tcp_debug.c
|
||||
tcp/tcp_sack.c
|
||||
tcp/tcp.c
|
||||
)
|
||||
|
||||
@@ -674,7 +676,12 @@ list(APPEND VNET_MULTIARCH_SOURCES
|
||||
list(APPEND VNET_HEADERS
|
||||
tcp/tcp_packet.h
|
||||
tcp/tcp_timer.h
|
||||
tcp/tcp_bt.h
|
||||
tcp/tcp_cc.h
|
||||
tcp/tcp_debug.h
|
||||
tcp/tcp_inlines.h
|
||||
tcp/tcp_sack.h
|
||||
tcp/tcp_types.h
|
||||
tcp/tcp.h
|
||||
tcp/tcp_error.def
|
||||
)
|
||||
|
||||
+1
-1052
File diff suppressed because it is too large
Load Diff
+24
-939
File diff suppressed because it is too large
Load Diff
@@ -115,11 +115,6 @@ tcp_api_hookup (vlib_main_t * vm)
|
||||
|
||||
VLIB_API_INIT_FUNCTION (tcp_api_hookup);
|
||||
|
||||
void
|
||||
tcp_api_reference (void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
* draft-cheng-iccrg-delivery-rate-estimation-00
|
||||
*/
|
||||
|
||||
#include <vnet/tcp/tcp_bt.h>
|
||||
#include <vnet/tcp/tcp.h>
|
||||
#include <vnet/tcp/tcp_inlines.h>
|
||||
|
||||
static tcp_bt_sample_t *
|
||||
bt_get_sample (tcp_byte_tracker_t * bt, u32 bts_index)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Cisco and/or its affiliates.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Rate estimation
|
||||
*/
|
||||
|
||||
#ifndef SRC_VNET_TCP_TCP_BT_H_
|
||||
#define SRC_VNET_TCP_TCP_BT_H_
|
||||
|
||||
#include <vnet/tcp/tcp_types.h>
|
||||
|
||||
/**
|
||||
* Byte tracker initialize
|
||||
*
|
||||
* @param tc connection for which the byte tracker should be allocated and
|
||||
* initialized
|
||||
*/
|
||||
void tcp_bt_init (tcp_connection_t * tc);
|
||||
/**
|
||||
* Byte tracker cleanup
|
||||
*
|
||||
* @param tc connection for which the byte tracker should be cleaned up
|
||||
*/
|
||||
void tcp_bt_cleanup (tcp_connection_t * tc);
|
||||
/**
|
||||
* Flush byte tracker samples
|
||||
*
|
||||
* @param tc tcp connection for which samples should be flushed
|
||||
*/
|
||||
void tcp_bt_flush_samples (tcp_connection_t * tc);
|
||||
/**
|
||||
* Track a tcp tx burst
|
||||
*
|
||||
* @param tc tcp connection
|
||||
*/
|
||||
void tcp_bt_track_tx (tcp_connection_t * tc, u32 len);
|
||||
/**
|
||||
* Track a tcp retransmission
|
||||
*
|
||||
* @param tc tcp connection
|
||||
* @param start start sequence number
|
||||
* @param end end sequence number
|
||||
*/
|
||||
void tcp_bt_track_rxt (tcp_connection_t * tc, u32 start, u32 end);
|
||||
/**
|
||||
* Generate a delivery rate sample from recently acked bytes
|
||||
*
|
||||
* @param tc tcp connection
|
||||
* @param rs resulting rate sample
|
||||
*/
|
||||
void tcp_bt_sample_delivery_rate (tcp_connection_t * tc,
|
||||
tcp_rate_sample_t * rs);
|
||||
/**
|
||||
* Check if sample to be generated is app limited
|
||||
*
|
||||
* @param tc tcp connection
|
||||
*/
|
||||
void tcp_bt_check_app_limited (tcp_connection_t * tc);
|
||||
/**
|
||||
* Check if the byte tracker is in sane state
|
||||
*
|
||||
* Should be used only for testing
|
||||
*
|
||||
* @param bt byte tracker
|
||||
*/
|
||||
int tcp_bt_is_sane (tcp_byte_tracker_t * bt);
|
||||
|
||||
format_function_t format_tcp_bt;
|
||||
|
||||
#endif /* SRC_VNET_TCP_TCP_BT_H_ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Cisco and/or its affiliates.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SRC_VNET_TCP_TCP_CC_H_
|
||||
#define SRC_VNET_TCP_TCP_CC_H_
|
||||
|
||||
#include <vnet/tcp/tcp_types.h>
|
||||
|
||||
always_inline void
|
||||
tcp_cc_rcv_ack (tcp_connection_t * tc, tcp_rate_sample_t * rs)
|
||||
{
|
||||
tc->cc_algo->rcv_ack (tc, rs);
|
||||
tc->tsecr_last_ack = tc->rcv_opts.tsecr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_rcv_cong_ack (tcp_connection_t * tc, tcp_cc_ack_t ack_type,
|
||||
tcp_rate_sample_t * rs)
|
||||
{
|
||||
tc->cc_algo->rcv_cong_ack (tc, ack_type, rs);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_congestion (tcp_connection_t * tc)
|
||||
{
|
||||
tc->cc_algo->congestion (tc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_loss (tcp_connection_t * tc)
|
||||
{
|
||||
tc->cc_algo->loss (tc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_recovered (tcp_connection_t * tc)
|
||||
{
|
||||
tc->cc_algo->recovered (tc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_undo_recovery (tcp_connection_t * tc)
|
||||
{
|
||||
if (tc->cc_algo->undo_recovery)
|
||||
tc->cc_algo->undo_recovery (tc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_cc_event (tcp_connection_t * tc, tcp_cc_event_t evt)
|
||||
{
|
||||
if (tc->cc_algo->event)
|
||||
tc->cc_algo->event (tc, evt);
|
||||
}
|
||||
|
||||
static inline u64
|
||||
tcp_cc_get_pacing_rate (tcp_connection_t * tc)
|
||||
{
|
||||
if (tc->cc_algo->get_pacing_rate)
|
||||
return tc->cc_algo->get_pacing_rate (tc);
|
||||
|
||||
f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
|
||||
|
||||
/* TODO should constrain to interface's max throughput but
|
||||
* we don't have link speeds for sw ifs ..*/
|
||||
return ((f64) tc->cwnd / srtt);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
tcp_cc_data (tcp_connection_t * tc)
|
||||
{
|
||||
return (void *) tc->cc_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register exiting cc algo type
|
||||
*/
|
||||
void tcp_cc_algo_register (tcp_cc_algorithm_type_e type,
|
||||
const tcp_cc_algorithm_t * vft);
|
||||
|
||||
/**
|
||||
* Register new cc algo type
|
||||
*/
|
||||
tcp_cc_algorithm_type_e tcp_cc_algo_new_type (const tcp_cc_algorithm_t * vft);
|
||||
tcp_cc_algorithm_t *tcp_cc_algo_get (tcp_cc_algorithm_type_e type);
|
||||
|
||||
|
||||
void newreno_rcv_cong_ack (tcp_connection_t * tc, tcp_cc_ack_t ack_type,
|
||||
tcp_rate_sample_t * rs);
|
||||
|
||||
|
||||
#endif /* SRC_VNET_TCP_TCP_CC_H_ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include <vnet/tcp/tcp.h>
|
||||
#include <vnet/tcp/tcp_inlines.h>
|
||||
#include <math.h>
|
||||
|
||||
#define beta_cubic 0.7
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1
-863
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include <vnet/tcp/tcp.h>
|
||||
#include <vnet/tcp/tcp_inlines.h>
|
||||
|
||||
typedef struct nwreno_cfg_
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include <vnet/tcp/tcp.h>
|
||||
#include <vnet/tcp/tcp_inlines.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef enum _tcp_output_next
|
||||
@@ -166,90 +167,6 @@ tcp_window_to_advertise (tcp_connection_t * tc, tcp_state_t state)
|
||||
return tc->rcv_wnd >> tc->rcv_wscale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write TCP options to segment.
|
||||
*/
|
||||
static u32
|
||||
tcp_options_write (u8 * data, tcp_options_t * opts)
|
||||
{
|
||||
u32 opts_len = 0;
|
||||
u32 buf, seq_len = 4;
|
||||
|
||||
if (tcp_opts_mss (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_MSS;
|
||||
*data++ = TCP_OPTION_LEN_MSS;
|
||||
buf = clib_host_to_net_u16 (opts->mss);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->mss));
|
||||
data += sizeof (opts->mss);
|
||||
opts_len += TCP_OPTION_LEN_MSS;
|
||||
}
|
||||
|
||||
if (tcp_opts_wscale (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_WINDOW_SCALE;
|
||||
*data++ = TCP_OPTION_LEN_WINDOW_SCALE;
|
||||
*data++ = opts->wscale;
|
||||
opts_len += TCP_OPTION_LEN_WINDOW_SCALE;
|
||||
}
|
||||
|
||||
if (tcp_opts_sack_permitted (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_SACK_PERMITTED;
|
||||
*data++ = TCP_OPTION_LEN_SACK_PERMITTED;
|
||||
opts_len += TCP_OPTION_LEN_SACK_PERMITTED;
|
||||
}
|
||||
|
||||
if (tcp_opts_tstamp (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_TIMESTAMP;
|
||||
*data++ = TCP_OPTION_LEN_TIMESTAMP;
|
||||
buf = clib_host_to_net_u32 (opts->tsval);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->tsval));
|
||||
data += sizeof (opts->tsval);
|
||||
buf = clib_host_to_net_u32 (opts->tsecr);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->tsecr));
|
||||
data += sizeof (opts->tsecr);
|
||||
opts_len += TCP_OPTION_LEN_TIMESTAMP;
|
||||
}
|
||||
|
||||
if (tcp_opts_sack (opts))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (opts->n_sack_blocks != 0)
|
||||
{
|
||||
*data++ = TCP_OPTION_SACK_BLOCK;
|
||||
*data++ = 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
|
||||
for (i = 0; i < opts->n_sack_blocks; i++)
|
||||
{
|
||||
buf = clib_host_to_net_u32 (opts->sacks[i].start);
|
||||
clib_memcpy_fast (data, &buf, seq_len);
|
||||
data += seq_len;
|
||||
buf = clib_host_to_net_u32 (opts->sacks[i].end);
|
||||
clib_memcpy_fast (data, &buf, seq_len);
|
||||
data += seq_len;
|
||||
}
|
||||
opts_len += 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate TCP options */
|
||||
if (opts_len % 4)
|
||||
{
|
||||
*data++ = TCP_OPTION_EOL;
|
||||
opts_len += TCP_OPTION_LEN_EOL;
|
||||
}
|
||||
|
||||
/* Pad with zeroes to a u32 boundary */
|
||||
while (opts_len % 4)
|
||||
{
|
||||
*data++ = TCP_OPTION_NOOP;
|
||||
opts_len += TCP_OPTION_LEN_NOOP;
|
||||
}
|
||||
return opts_len;
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_make_syn_options (tcp_connection_t * tc, tcp_options_t * opts)
|
||||
{
|
||||
@@ -563,7 +480,7 @@ tcp_make_ack (tcp_connection_t * tc, vlib_buffer_t * b)
|
||||
/**
|
||||
* Convert buffer to FIN-ACK
|
||||
*/
|
||||
void
|
||||
static void
|
||||
tcp_make_fin (tcp_connection_t * tc, vlib_buffer_t * b)
|
||||
{
|
||||
tcp_make_ack_i (tc, b, TCP_STATE_ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_ACK);
|
||||
@@ -598,7 +515,7 @@ tcp_make_syn (tcp_connection_t * tc, vlib_buffer_t * b)
|
||||
/**
|
||||
* Convert buffer to SYN-ACK
|
||||
*/
|
||||
void
|
||||
static void
|
||||
tcp_make_synack (tcp_connection_t * tc, vlib_buffer_t * b)
|
||||
{
|
||||
tcp_options_t _snd_opts, *snd_opts = &_snd_opts;
|
||||
|
||||
@@ -172,6 +172,219 @@ typedef struct
|
||||
#define TCP_MAX_WND_SCALE 14 /* See RFC 1323 */
|
||||
#define TCP_OPTS_ALIGN 4
|
||||
#define TCP_OPTS_MAX_SACK_BLOCKS 3
|
||||
|
||||
/* Modulo arithmetic for TCP sequence numbers */
|
||||
#define seq_lt(_s1, _s2) ((i32)((_s1)-(_s2)) < 0)
|
||||
#define seq_leq(_s1, _s2) ((i32)((_s1)-(_s2)) <= 0)
|
||||
#define seq_gt(_s1, _s2) ((i32)((_s1)-(_s2)) > 0)
|
||||
#define seq_geq(_s1, _s2) ((i32)((_s1)-(_s2)) >= 0)
|
||||
#define seq_max(_s1, _s2) (seq_gt((_s1), (_s2)) ? (_s1) : (_s2))
|
||||
|
||||
/* Modulo arithmetic for timestamps */
|
||||
#define timestamp_lt(_t1, _t2) ((i32)((_t1)-(_t2)) < 0)
|
||||
#define timestamp_leq(_t1, _t2) ((i32)((_t1)-(_t2)) <= 0)
|
||||
|
||||
/**
|
||||
* Parse TCP header options.
|
||||
*
|
||||
* @param th TCP header
|
||||
* @param to TCP options data structure to be populated
|
||||
* @param is_syn set if packet is syn
|
||||
* @return -1 if parsing failed
|
||||
*/
|
||||
always_inline int
|
||||
tcp_options_parse (tcp_header_t * th, tcp_options_t * to, u8 is_syn)
|
||||
{
|
||||
const u8 *data;
|
||||
u8 opt_len, opts_len, kind;
|
||||
int j;
|
||||
sack_block_t b;
|
||||
|
||||
opts_len = (tcp_doff (th) << 2) - sizeof (tcp_header_t);
|
||||
data = (const u8 *) (th + 1);
|
||||
|
||||
/* Zero out all flags but those set in SYN */
|
||||
to->flags &= (TCP_OPTS_FLAG_SACK_PERMITTED | TCP_OPTS_FLAG_WSCALE
|
||||
| TCP_OPTS_FLAG_TSTAMP | TCP_OPTS_FLAG_MSS);
|
||||
|
||||
for (; opts_len > 0; opts_len -= opt_len, data += opt_len)
|
||||
{
|
||||
kind = data[0];
|
||||
|
||||
/* Get options length */
|
||||
if (kind == TCP_OPTION_EOL)
|
||||
break;
|
||||
else if (kind == TCP_OPTION_NOOP)
|
||||
{
|
||||
opt_len = 1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* broken options */
|
||||
if (opts_len < 2)
|
||||
return -1;
|
||||
opt_len = data[1];
|
||||
|
||||
/* weird option length */
|
||||
if (opt_len < 2 || opt_len > opts_len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse options */
|
||||
switch (kind)
|
||||
{
|
||||
case TCP_OPTION_MSS:
|
||||
if (!is_syn)
|
||||
break;
|
||||
if ((opt_len == TCP_OPTION_LEN_MSS) && tcp_syn (th))
|
||||
{
|
||||
to->flags |= TCP_OPTS_FLAG_MSS;
|
||||
to->mss = clib_net_to_host_u16 (*(u16 *) (data + 2));
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_WINDOW_SCALE:
|
||||
if (!is_syn)
|
||||
break;
|
||||
if ((opt_len == TCP_OPTION_LEN_WINDOW_SCALE) && tcp_syn (th))
|
||||
{
|
||||
to->flags |= TCP_OPTS_FLAG_WSCALE;
|
||||
to->wscale = data[2];
|
||||
if (to->wscale > TCP_MAX_WND_SCALE)
|
||||
to->wscale = TCP_MAX_WND_SCALE;
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_TIMESTAMP:
|
||||
if (is_syn)
|
||||
to->flags |= TCP_OPTS_FLAG_TSTAMP;
|
||||
if ((to->flags & TCP_OPTS_FLAG_TSTAMP)
|
||||
&& opt_len == TCP_OPTION_LEN_TIMESTAMP)
|
||||
{
|
||||
to->tsval = clib_net_to_host_u32 (*(u32 *) (data + 2));
|
||||
to->tsecr = clib_net_to_host_u32 (*(u32 *) (data + 6));
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_SACK_PERMITTED:
|
||||
if (!is_syn)
|
||||
break;
|
||||
if (opt_len == TCP_OPTION_LEN_SACK_PERMITTED && tcp_syn (th))
|
||||
to->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
|
||||
break;
|
||||
case TCP_OPTION_SACK_BLOCK:
|
||||
/* If SACK permitted was not advertised or a SYN, break */
|
||||
if ((to->flags & TCP_OPTS_FLAG_SACK_PERMITTED) == 0 || tcp_syn (th))
|
||||
break;
|
||||
|
||||
/* If too short or not correctly formatted, break */
|
||||
if (opt_len < 10 || ((opt_len - 2) % TCP_OPTION_LEN_SACK_BLOCK))
|
||||
break;
|
||||
|
||||
to->flags |= TCP_OPTS_FLAG_SACK;
|
||||
to->n_sack_blocks = (opt_len - 2) / TCP_OPTION_LEN_SACK_BLOCK;
|
||||
vec_reset_length (to->sacks);
|
||||
for (j = 0; j < to->n_sack_blocks; j++)
|
||||
{
|
||||
b.start = clib_net_to_host_u32 (*(u32 *) (data + 2 + 8 * j));
|
||||
b.end = clib_net_to_host_u32 (*(u32 *) (data + 6 + 8 * j));
|
||||
vec_add1 (to->sacks, b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Nothing to see here */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write TCP options to segment.
|
||||
*
|
||||
* @param data buffer where to write the options
|
||||
* @param opts options to write
|
||||
* @return length of options written
|
||||
*/
|
||||
always_inline u32
|
||||
tcp_options_write (u8 * data, tcp_options_t * opts)
|
||||
{
|
||||
u32 opts_len = 0;
|
||||
u32 buf, seq_len = 4;
|
||||
|
||||
if (tcp_opts_mss (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_MSS;
|
||||
*data++ = TCP_OPTION_LEN_MSS;
|
||||
buf = clib_host_to_net_u16 (opts->mss);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->mss));
|
||||
data += sizeof (opts->mss);
|
||||
opts_len += TCP_OPTION_LEN_MSS;
|
||||
}
|
||||
|
||||
if (tcp_opts_wscale (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_WINDOW_SCALE;
|
||||
*data++ = TCP_OPTION_LEN_WINDOW_SCALE;
|
||||
*data++ = opts->wscale;
|
||||
opts_len += TCP_OPTION_LEN_WINDOW_SCALE;
|
||||
}
|
||||
|
||||
if (tcp_opts_sack_permitted (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_SACK_PERMITTED;
|
||||
*data++ = TCP_OPTION_LEN_SACK_PERMITTED;
|
||||
opts_len += TCP_OPTION_LEN_SACK_PERMITTED;
|
||||
}
|
||||
|
||||
if (tcp_opts_tstamp (opts))
|
||||
{
|
||||
*data++ = TCP_OPTION_TIMESTAMP;
|
||||
*data++ = TCP_OPTION_LEN_TIMESTAMP;
|
||||
buf = clib_host_to_net_u32 (opts->tsval);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->tsval));
|
||||
data += sizeof (opts->tsval);
|
||||
buf = clib_host_to_net_u32 (opts->tsecr);
|
||||
clib_memcpy_fast (data, &buf, sizeof (opts->tsecr));
|
||||
data += sizeof (opts->tsecr);
|
||||
opts_len += TCP_OPTION_LEN_TIMESTAMP;
|
||||
}
|
||||
|
||||
if (tcp_opts_sack (opts))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (opts->n_sack_blocks != 0)
|
||||
{
|
||||
*data++ = TCP_OPTION_SACK_BLOCK;
|
||||
*data++ = 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
|
||||
for (i = 0; i < opts->n_sack_blocks; i++)
|
||||
{
|
||||
buf = clib_host_to_net_u32 (opts->sacks[i].start);
|
||||
clib_memcpy_fast (data, &buf, seq_len);
|
||||
data += seq_len;
|
||||
buf = clib_host_to_net_u32 (opts->sacks[i].end);
|
||||
clib_memcpy_fast (data, &buf, seq_len);
|
||||
data += seq_len;
|
||||
}
|
||||
opts_len += 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate TCP options */
|
||||
if (opts_len % 4)
|
||||
{
|
||||
*data++ = TCP_OPTION_EOL;
|
||||
opts_len += TCP_OPTION_LEN_EOL;
|
||||
}
|
||||
|
||||
/* Pad with zeroes to a u32 boundary */
|
||||
while (opts_len % 4)
|
||||
{
|
||||
*data++ = TCP_OPTION_NOOP;
|
||||
opts_len += TCP_OPTION_LEN_NOOP;
|
||||
}
|
||||
return opts_len;
|
||||
}
|
||||
|
||||
#endif /* included_tcp_packet_h */
|
||||
|
||||
/*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Cisco and/or its affiliates.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SRC_VNET_TCP_TCP_SACK_H_
|
||||
#define SRC_VNET_TCP_TCP_SACK_H_
|
||||
|
||||
#include <vnet/tcp/tcp_types.h>
|
||||
|
||||
always_inline u32
|
||||
scoreboard_hole_index (sack_scoreboard_t * sb, sack_scoreboard_hole_t * hole)
|
||||
{
|
||||
ASSERT (!pool_is_free_index (sb->holes, hole - sb->holes));
|
||||
return hole - sb->holes;
|
||||
}
|
||||
|
||||
always_inline u32
|
||||
scoreboard_hole_bytes (sack_scoreboard_hole_t * hole)
|
||||
{
|
||||
return hole->end - hole->start;
|
||||
}
|
||||
|
||||
always_inline sack_scoreboard_hole_t *
|
||||
scoreboard_get_hole (sack_scoreboard_t * sb, u32 index)
|
||||
{
|
||||
if (index != TCP_INVALID_SACK_HOLE_INDEX)
|
||||
return pool_elt_at_index (sb->holes, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline sack_scoreboard_hole_t *
|
||||
scoreboard_next_hole (sack_scoreboard_t * sb, sack_scoreboard_hole_t * hole)
|
||||
{
|
||||
if (hole->next != TCP_INVALID_SACK_HOLE_INDEX)
|
||||
return pool_elt_at_index (sb->holes, hole->next);
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline sack_scoreboard_hole_t *
|
||||
scoreboard_prev_hole (sack_scoreboard_t * sb, sack_scoreboard_hole_t * hole)
|
||||
{
|
||||
if (hole->prev != TCP_INVALID_SACK_HOLE_INDEX)
|
||||
return pool_elt_at_index (sb->holes, hole->prev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline sack_scoreboard_hole_t *
|
||||
scoreboard_first_hole (sack_scoreboard_t * sb)
|
||||
{
|
||||
if (sb->head != TCP_INVALID_SACK_HOLE_INDEX)
|
||||
return pool_elt_at_index (sb->holes, sb->head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline sack_scoreboard_hole_t *
|
||||
scoreboard_last_hole (sack_scoreboard_t * sb)
|
||||
{
|
||||
if (sb->tail != TCP_INVALID_SACK_HOLE_INDEX)
|
||||
return pool_elt_at_index (sb->holes, sb->tail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if TCP_SCOREBOARD_TRACE
|
||||
#define tcp_scoreboard_trace_add(_tc, _ack) \
|
||||
{ \
|
||||
static u64 _group = 0; \
|
||||
sack_scoreboard_t *_sb = &_tc->sack_sb; \
|
||||
sack_block_t *_sack, *_sacks; \
|
||||
scoreboard_trace_elt_t *_elt; \
|
||||
int i; \
|
||||
_group++; \
|
||||
_sacks = _tc->rcv_opts.sacks; \
|
||||
for (i = 0; i < vec_len (_sacks); i++) \
|
||||
{ \
|
||||
_sack = &_sacks[i]; \
|
||||
vec_add2 (_sb->trace, _elt, 1); \
|
||||
_elt->start = _sack->start; \
|
||||
_elt->end = _sack->end; \
|
||||
_elt->ack = _elt->end == _ack ? _ack : 0; \
|
||||
_elt->snd_una_max = _elt->end == _ack ? _tc->snd_una_max : 0; \
|
||||
_elt->group = _group; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define tcp_scoreboard_trace_add(_tc, _ack)
|
||||
#endif
|
||||
|
||||
sack_scoreboard_hole_t *scoreboard_next_rxt_hole (sack_scoreboard_t * sb,
|
||||
sack_scoreboard_hole_t *
|
||||
start, u8 have_sent_1_smss,
|
||||
u8 * can_rescue,
|
||||
u8 * snd_limited);
|
||||
void scoreboard_clear (sack_scoreboard_t * sb);
|
||||
void scoreboard_clear_reneging (sack_scoreboard_t * sb, u32 start, u32 end);
|
||||
void scoreboard_init (sack_scoreboard_t * sb);
|
||||
void scoreboard_init_rxt (sack_scoreboard_t * sb, u32 snd_una);
|
||||
|
||||
format_function_t format_tcp_scoreboard;
|
||||
|
||||
/* Made public for unit testing only */
|
||||
void tcp_update_sack_list (tcp_connection_t * tc, u32 start, u32 end);
|
||||
u32 tcp_sack_list_bytes (tcp_connection_t * tc);
|
||||
void tcp_rcv_sacks (tcp_connection_t * tc, u32 ack);
|
||||
u8 *tcp_scoreboard_replay (u8 * s, tcp_connection_t * tc, u8 verbose);
|
||||
u8 tcp_scoreboard_is_sane_post_recovery (tcp_connection_t * tc);
|
||||
|
||||
#endif /* SRC_VNET_TCP_TCP_SACK_H_ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user