tcp: Make dsack stats available in netstat and also make sure its aware of TLP's.

DSACK accounting has been for quite some time under a NETFLIX_STATS ifdef. Statistics
on DSACKs however are very useful in figuring out how much bad retransmissions you
are doing. This is further complicated, however, by stacks that do TLP. A TLP
when discovering a lost ack in the reverse path will cause the generation
of a DSACK. For this situation we introduce a new dsack-tlp-bytes as well
as the more traditional dsack-bytes and dsack-packets. These will now
all display in netstat -p tcp -s. This also updates all stacks that
are currently built to keep track of these stats.

Reviewed by: tuexen
Sponsored by: Netflix Inc.
Differential Revision: https://reviews.freebsd.org/D32158
This commit is contained in:
Randall Stewart 2021-10-01 10:32:30 -04:00
parent 5b40c0aa73
commit a36230f75e
6 changed files with 63 additions and 10 deletions

View File

@ -604,6 +604,12 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
SEQ_GT(sack.end, tp->snd_una) &&
SEQ_LEQ(sack.end, tp->snd_max)) {
sack_blocks[num_sack_blks++] = sack;
} else if (SEQ_LEQ(sack.start, th_ack) &&
SEQ_LEQ(sack.end, th_ack)) {
/*
* Its a D-SACK block.
*/
tcp_record_dsack(tp, sack.start, sack.end, 0);
}
}
}

View File

@ -7593,14 +7593,12 @@ bbr_log_ack(struct tcpcb *tp, struct tcpopt *to, struct tcphdr *th,
}
sack_blocks[num_sack_blks] = sack;
num_sack_blks++;
#ifdef NETFLIX_STATS
} else if (SEQ_LEQ(sack.start, th_ack) &&
SEQ_LEQ(sack.end, th_ack)) {
/*
* Its a D-SACK block.
*/
tcp_record_dsack(sack.start, sack.end);
#endif
tcp_record_dsack(tp, sack.start, sack.end, 0);
}
}
if (num_sack_blks == 0)

View File

@ -9402,11 +9402,12 @@ rack_do_detection(struct tcpcb *tp, struct tcp_rack *rack, uint32_t bytes_this_
}
#endif
static void
static int
rack_note_dsack(struct tcp_rack *rack, tcp_seq start, tcp_seq end)
{
uint32_t am, l_end;
int was_tlp = 0;
if (SEQ_GT(end, start))
am = end - start;
@ -9422,6 +9423,7 @@ rack_note_dsack(struct tcp_rack *rack, tcp_seq start, tcp_seq end)
* our previous retransmit TLP.
*/
rack_log_dsack_event(rack, 7, __LINE__, start, end);
was_tlp = 1;
goto skip_dsack_round;
}
if (rack->rc_last_sent_tlp_seq_valid) {
@ -9433,6 +9435,7 @@ rack_note_dsack(struct tcp_rack *rack, tcp_seq start, tcp_seq end)
* for reordering purposes.
*/
rack_log_dsack_event(rack, 7, __LINE__, start, end);
was_tlp = 1;
goto skip_dsack_round;
}
}
@ -9462,6 +9465,7 @@ rack_note_dsack(struct tcp_rack *rack, tcp_seq start, tcp_seq end)
rack->r_ctl.retran_during_recovery = 0;
rack->r_ctl.dsack_byte_cnt = 0;
}
return (was_tlp);
}
static void
@ -9614,13 +9618,13 @@ rack_log_ack(struct tcpcb *tp, struct tcpopt *to, struct tcphdr *th, int entered
num_sack_blks++;
} else if (SEQ_LEQ(sack.start, th_ack) &&
SEQ_LEQ(sack.end, th_ack)) {
#ifdef NETFLIX_STATS
int was_tlp;
was_tlp = rack_note_dsack(rack, sack.start, sack.end);
/*
* Its a D-SACK block.
*/
tcp_record_dsack(sack.start, sack.end);
#endif
rack_note_dsack(rack, sack.start, sack.end);
tcp_record_dsack(tp, sack.start, sack.end, was_tlp);
}
}
if (rack->rc_dsack_round_seen) {

View File

@ -390,6 +390,30 @@ static int tcp_fb_cnt = 0;
struct tcp_funchead t_functions;
static struct tcp_function_block *tcp_func_set_ptr = &tcp_def_funcblk;
void
tcp_record_dsack(struct tcpcb *tp, tcp_seq start, tcp_seq end, int tlp)
{
TCPSTAT_INC(tcps_dsack_count);
tp->t_dsack_pack++;
if (tlp == 0) {
if (SEQ_GT(end, start)) {
tp->t_dsack_bytes += (end - start);
TCPSTAT_ADD(tcps_dsack_bytes, (end - start));
} else {
tp->t_dsack_tlp_bytes += (start - end);
TCPSTAT_ADD(tcps_dsack_bytes, (start - end));
}
} else {
if (SEQ_GT(end, start)) {
tp->t_dsack_bytes += (end - start);
TCPSTAT_ADD(tcps_dsack_tlp_bytes, (end - start));
} else {
tp->t_dsack_tlp_bytes += (start - end);
TCPSTAT_ADD(tcps_dsack_tlp_bytes, (start - end));
}
}
}
static struct tcp_function_block *
find_tcp_functions_locked(struct tcp_function_set *fs)
{
@ -4003,6 +4027,9 @@ tcp_inptoxtp(const struct inpcb *inp, struct xtcpcb *xt)
xt->t_snd_wnd = tp->snd_wnd;
xt->t_snd_cwnd = tp->snd_cwnd;
xt->t_snd_ssthresh = tp->snd_ssthresh;
xt->t_dsack_bytes = tp->t_dsack_bytes;
xt->t_dsack_tlp_bytes = tp->t_dsack_tlp_bytes;
xt->t_dsack_pack = tp->t_dsack_pack;
xt->t_maxseg = tp->t_maxseg;
xt->xt_ecn = (tp->t_flags2 & TF2_ECN_PERMIT) ? 1 : 0 +
(tp->t_flags2 & TF2_ACE_PERMIT) ? 2 : 0;

View File

@ -265,6 +265,9 @@ struct tcpcb {
uint64_t t_sndtlpbyte; /* total tail loss probe bytes sent */
uint64_t t_sndbytes; /* total bytes sent */
uint64_t t_snd_rxt_bytes; /* total bytes retransmitted */
uint32_t t_dsack_bytes; /* Total number of dsack bytes we have received */
uint32_t t_dsack_tlp_bytes; /* Total number of dsack bytes we have received for TLPs sent */
uint32_t t_dsack_pack; /* Total dsack packets we have recieved */
uint8_t t_tfo_client_cookie_len; /* TCP Fast Open client cookie length */
uint32_t t_end_info_status; /* Status flag of end info */
@ -703,7 +706,12 @@ struct tcpstat {
uint64_t tcps_tunneled_pkts; /* Packets encap's in UDP received */
uint64_t tcps_tunneled_errs; /* Packets that had errors that were UDP encaped */
uint64_t _pad[9]; /* 6 UTO, 3 TBD */
/* Dsack related stats */
uint64_t tcps_dsack_count; /* Number of ACKs arriving with DSACKs */
uint64_t tcps_dsack_bytes; /* Number of bytes DSACK'ed no TLP */
uint64_t tcps_dsack_tlp_bytes; /* Number of bytes DSACK'ed due to TLPs */
uint64_t _pad[6]; /* 3 UTO, 3 TBD */
};
#define tcps_rcvmemdrop tcps_rcvreassfull /* compat */
@ -801,9 +809,12 @@ struct xtcpcb {
uint32_t t_rcv_wnd; /* (s) */
uint32_t t_snd_wnd; /* (s) */
uint32_t xt_ecn; /* (s) */
uint32_t t_dsack_bytes; /* (n) */
uint32_t t_dsack_tlp_bytes; /* (n) */
uint32_t t_dsack_pack; /* (n) */
uint16_t xt_encaps_port; /* (s) */
int16_t spare16;
int32_t spare32[25];
int32_t spare32[22];
} __aligned(8);
#ifdef _KERNEL
@ -1064,6 +1075,7 @@ int tcp_twcheck(struct inpcb *, struct tcpopt *, struct tcphdr *,
struct mbuf *, int);
void tcp_setpersist(struct tcpcb *);
void tcp_slowtimo(void);
void tcp_record_dsack(struct tcpcb *tp, tcp_seq start, tcp_seq end, int tlp);
struct tcptemp *
tcpip_maketemplate(struct inpcb *);
void tcpip_fillheaders(struct inpcb *, uint16_t, void *, void *);

View File

@ -695,6 +695,12 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
"{N:/window probe%s}\n");
p(tcps_rcvwinupd, "\t\t{:receive-window-update-packets/%ju} "
"{N:/window update packet%s}\n");
p(tcps_dsack_count, "\t\t{:received-with-dsack-packets/%ju} "
"{N:/packet%s received with dsack}\n");
p(tcps_dsack_bytes, "\t\t{:received-with-dsack-bytes/%ju} "
"{N:/dsack byte%s received (no TLP involved)}\n");
p(tcps_dsack_tlp_bytes, "\t\t{:received-with-dsack-bytes-tlp/%ju} "
"{N:/dsack byte%s received (TLP responsible)}\n");
p(tcps_rcvafterclose, "\t\t{:received-after-close-packets/%ju} "
"{N:/packet%s received after close}\n");
p(tcps_rcvbadsum, "\t\t{:discard-bad-checksum/%ju} "