View | Details | Raw Unified | Return to bug 191520 | Differences between
and this patch

Collapse All | Expand All

(-)sys/conf/files (+1 lines)
Lines 3383-3388 netinet/tcp_reass.c optional inet | inet6 Link Here
3383
netinet/tcp_sack.c		optional inet | inet6
3383
netinet/tcp_sack.c		optional inet | inet6
3384
netinet/tcp_subr.c		optional inet | inet6
3384
netinet/tcp_subr.c		optional inet | inet6
3385
netinet/tcp_syncache.c		optional inet | inet6
3385
netinet/tcp_syncache.c		optional inet | inet6
3386
netinet/tcp_newcwv.c		optional inet | inet6
3386
netinet/tcp_timer.c		optional inet | inet6
3387
netinet/tcp_timer.c		optional inet | inet6
3387
netinet/tcp_timewait.c		optional inet | inet6
3388
netinet/tcp_timewait.c		optional inet | inet6
3388
netinet/tcp_usrreq.c		optional inet | inet6
3389
netinet/tcp_usrreq.c		optional inet | inet6
(-)sys/netinet/tcp_input.c (-2 / +35 lines)
Lines 105-110 __FBSDID("$FreeBSD$"); Link Here
105
#include <netinet6/tcp6_var.h>
105
#include <netinet6/tcp6_var.h>
106
#include <netinet/tcpip.h>
106
#include <netinet/tcpip.h>
107
#include <netinet/tcp_syncache.h>
107
#include <netinet/tcp_syncache.h>
108
#include <netinet/tcp_newcwv.h>
108
#ifdef TCPDEBUG
109
#ifdef TCPDEBUG
109
#include <netinet/tcp_debug.h>
110
#include <netinet/tcp_debug.h>
110
#endif /* TCPDEBUG */
111
#endif /* TCPDEBUG */
Lines 174-179 SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, abc_l_var Link Here
174
    &VNET_NAME(tcp_abc_l_var), 2,
175
    &VNET_NAME(tcp_abc_l_var), 2,
175
    "Cap the max cwnd increment during slow-start to this number of segments");
176
    "Cap the max cwnd increment during slow-start to this number of segments");
176
177
178
VNET_DEFINE(int, tcp_do_newcwv) = 0;
179
SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, newcwv, CTLFLAG_RW,
180
    &VNET_NAME(tcp_do_newcwv), 0,
181
    "Enable draft-ietf-tcpm-newcwv-06 (New Congestion Window Validation)");
182
177
static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, ecn, CTLFLAG_RW, 0, "TCP ECN");
183
static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, ecn, CTLFLAG_RW, 0, "TCP ECN");
178
184
179
VNET_DEFINE(int, tcp_do_ecn) = 0;
185
VNET_DEFINE(int, tcp_do_ecn) = 0;
Lines 285-293 cc_ack_received(struct tcpcb *tp, struct tcphdr *t Link Here
285
	INP_WLOCK_ASSERT(tp->t_inpcb);
291
	INP_WLOCK_ASSERT(tp->t_inpcb);
286
292
287
	tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th);
293
	tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th);
288
	if (tp->snd_cwnd <= tp->snd_wnd)
294
	/* draft-ietf-tcpm-newcwv relaxes conditions for growing cwnd */
295
	if (tp->snd_cwnd <= tp->snd_wnd || 
296
		(V_tcp_do_newcwv && tp->newcwv.pipeack >= (tp->snd_cwnd >> 1)) ) {
289
		tp->ccv->flags |= CCF_CWND_LIMITED;
297
		tp->ccv->flags |= CCF_CWND_LIMITED;
290
	else
298
		tp->newcwv.cwnd_valid_ts = ticks;
299
	} else
291
		tp->ccv->flags &= ~CCF_CWND_LIMITED;
300
		tp->ccv->flags &= ~CCF_CWND_LIMITED;
292
301
293
	if (type == CC_ACK) {
302
	if (type == CC_ACK) {
Lines 309-314 cc_ack_received(struct tcpcb *tp, struct tcphdr *t Link Here
309
		tp->ccv->curack = th->th_ack;
318
		tp->ccv->curack = th->th_ack;
310
		CC_ALGO(tp)->ack_received(tp->ccv, type);
319
		CC_ALGO(tp)->ack_received(tp->ccv, type);
311
	}
320
	}
321
322
	/*
323
	 * update draft-ietf-newcwv-06 pipeack
324
	 */
325
	if(V_tcp_do_newcwv && !IN_FASTRECOVERY(tp->t_flags))
326
		tcp_newcwv_update_pipeack(tp);
312
}
327
}
313
328
314
static void inline
329
static void inline
Lines 378-383 cc_conn_init(struct tcpcb *tp) Link Here
378
			tp->snd_cwnd = 4 * tp->t_maxseg;
393
			tp->snd_cwnd = 4 * tp->t_maxseg;
379
	}
394
	}
380
395
396
	/* 
397
	 * Initialise NewCWV state
398
	 */
399
	tp->newcwv.init_cwnd = tp->snd_cwnd;
400
	tcp_newcwv_reset(tp);
401
381
	if (CC_ALGO(tp)->conn_init != NULL)
402
	if (CC_ALGO(tp)->conn_init != NULL)
382
		CC_ALGO(tp)->conn_init(tp->ccv);
403
		CC_ALGO(tp)->conn_init(tp->ccv);
383
}
404
}
Lines 426-431 cc_cong_signal(struct tcpcb *tp, struct tcphdr *th Link Here
426
		tp->t_badrxtwin = 0;
447
		tp->t_badrxtwin = 0;
427
		break;
448
		break;
428
	}
449
	}
450
	
451
	if (V_tcp_do_newcwv && 
452
			(type == CC_NDUPACK || type == CC_ECN) &&
453
				tp->newcwv.pipeack <= (tp->snd_cwnd >> 1) )
454
		tcp_newcwv_enter_recovery(tp);
429
455
430
	if (CC_ALGO(tp)->cong_signal != NULL) {
456
	if (CC_ALGO(tp)->cong_signal != NULL) {
431
		if (th != NULL)
457
		if (th != NULL)
Lines 447-452 cc_post_recovery(struct tcpcb *tp, struct tcphdr * Link Here
447
	}
473
	}
448
	/* XXXLAS: EXIT_RECOVERY ? */
474
	/* XXXLAS: EXIT_RECOVERY ? */
449
	tp->t_bytes_acked = 0;
475
	tp->t_bytes_acked = 0;
476
477
	if(V_tcp_do_newcwv) {
478
		if(tp->newcwv.loss_flight_size)
479
			tcp_newcwv_end_recovery(tp);
480
		tcp_newcwv_reset(tp);	
481
	}
482
	tp->newcwv.loss_flight_size = 0;
450
}
483
}
451
484
452
#ifdef TCP_SIGNATURE
485
#ifdef TCP_SIGNATURE
(-)sys/netinet/tcp_newcwv.c (+175 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2014 Tom Jones <jones@sdf.org>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#include <sys/cdefs.h>
29
30
#include <sys/param.h>
31
#include <sys/kernel.h>
32
#include <sys/libkern.h>
33
#include <sys/socket.h>
34
#include <sys/socketvar.h>
35
36
#include <netinet/tcp.h>
37
#include <netinet/tcp_var.h>
38
#include <netinet/tcp_newcwv.h>
39
40
/*
41
 * An implementation of NewCWV (draft-ietf-tcpm-newcwv-06) for FreeBSD.
42
 * Based on the Linux implementation by Raffaello Secchi and the an initial
43
 * implementation of draft-ietf-tcpm-newcwv-00 by Aris Angelogiannopoulos.
44
 */
45
46
#define nextbin(x) (((x)+1) & 0x03)
47
#define prevbin(x) (((x)-1) & 0x03)
48
49
#define NCWV_UNDEF 0xFFFFFFFF
50
#define NCWV_FIVEMINS (300*hz)
51
52
void add_element(struct tcpcb *,u_int32_t);
53
u_int32_t remove_expired_elements(struct tcpcb *);
54
55
void
56
tcp_newcwv_update_pipeack(struct tcpcb *tp)
57
{
58
	u_int32_t tmp_pipeack;
59
	tp->newcwv.psp = MAX(3 * tp->t_srtt,hz); 
60
61
	if (tp->snd_una >= tp->newcwv.prev_snd_nxt) {
62
		/* get the pipeack sample */
63
		tmp_pipeack = tp->snd_una - tp->newcwv.prev_snd_una;
64
65
		tp->newcwv.prev_snd_una = tp->snd_una;
66
		tp->newcwv.prev_snd_nxt = tp->snd_nxt;
67
68
		/* create a new element at the end of current pmp */
69
		if(ticks > tp->newcwv.time_stamp[tp->newcwv.head] + 
70
			(tp->newcwv.psp >> 2)) 
71
			add_element(tp,tmp_pipeack);
72
		else 
73
			tp->newcwv.psample[tp->newcwv.head] = tmp_pipeack;
74
	}
75
76
	tp->newcwv.pipeack = remove_expired_elements(tp);
77
78
	/* check if cwnd is validated */
79
	if (tp->newcwv.pipeack == NCWV_UNDEF || 
80
		((tp->newcwv.pipeack << 1) >= (tp->snd_cwnd * tp->t_maxseg))) {
81
		tp->newcwv.cwnd_valid_ts = ticks;
82
	} 
83
}
84
85
void 
86
add_element(struct tcpcb *tp,u_int32_t value)
87
{
88
	tp->newcwv.head = nextbin(tp->newcwv.head);
89
	tp->newcwv.psample[tp->newcwv.head] = value;
90
	tp->newcwv.time_stamp[tp->newcwv.head] = ticks;
91
}
92
93
u_int32_t
94
remove_expired_elements(struct tcpcb *tp)
95
{
96
	uint8_t head = tp->newcwv.head;
97
	u_int32_t tmp = tp->newcwv.psample[head];
98
99
	while(tp->newcwv.psample[head] != NCWV_UNDEF) {
100
		/* remove the element if expired */
101
		if (tp->newcwv.time_stamp[head] < ticks - tp->newcwv.psp) {
102
			tp->newcwv.psample[head] = NCWV_UNDEF;
103
			return tmp;
104
		}
105
106
		/* search for the max pipeack */
107
		if(tp->newcwv.psample[head] > tmp)
108
			tmp = tp->newcwv.psample[head];
109
110
		head = prevbin(head);
111
		if(head == tp->newcwv.head)
112
			return tmp;
113
	}	
114
115
	return tmp;
116
}
117
118
/* Initialise NewCWV state */
119
void
120
tcp_newcwv_reset(struct tcpcb *tp)
121
{
122
	tp->newcwv.prev_snd_una = tp->snd_una;
123
	tp->newcwv.prev_snd_nxt = tp->snd_nxt;
124
	tp->newcwv.cwnd_valid_ts = ticks;
125
	tp->newcwv.loss_flight_size = 0;
126
127
	tp->newcwv.head = 0;
128
	tp->newcwv.psample[0] = NCWV_UNDEF;
129
	tp->newcwv.pipeack = NCWV_UNDEF;
130
}
131
132
/* NewCWV actions at loss detection */
133
void
134
tcp_newcwv_enter_recovery(struct tcpcb *tp)
135
{
136
	u_int32_t pipe;
137
138
	if(tp->newcwv.pipeack == NCWV_UNDEF)
139
		return;
140
141
	tp->newcwv.prior_retrans = tp->t_sndrexmitpack;
142
143
	/* Calculate the flight size */
144
	u_int32_t awnd = (tp->snd_nxt - tp->snd_fack) + tp->sackhint.sack_bytes_rexmit;
145
	tp->newcwv.loss_flight_size = awnd;
146
147
	pipe = MAX(tp->newcwv.pipeack,tp->newcwv.loss_flight_size);
148
	tp->snd_cwnd = MAX(pipe >> 1,1);
149
}
150
151
/* NewCWV actions at the end of recovery */
152
void
153
tcp_newcwv_end_recovery(struct tcpcb *tp)
154
{
155
	u_int32_t retrans,pipe;
156
157
	retrans = (tp->t_sndrexmitpack - tp->newcwv.prior_retrans) * tp->t_maxseg;
158
	pipe = MAX(tp->newcwv.pipeack,tp->newcwv.loss_flight_size) - retrans;
159
160
	/* Ensure that snd_ssthresh is non 0 */
161
	tp->snd_ssthresh = MAX(pipe >> 1,1); 
162
	tp->snd_cwnd = tp->snd_ssthresh;
163
}
164
165
void
166
tcp_newcwv_datalim_closedown(struct tcpcb *tp)
167
{
168
	while ((ticks - tp->newcwv.cwnd_valid_ts) > NCWV_FIVEMINS && 
169
	  tp->snd_cwnd > tp->newcwv.init_cwnd) {
170
171
		tp->newcwv.cwnd_valid_ts += NCWV_FIVEMINS;
172
		tp->snd_ssthresh = MAX( (3 * tp->snd_cwnd ) >> 2,tp->snd_ssthresh);
173
		tp->snd_cwnd = MAX(tp->snd_cwnd >> 1, tp->newcwv.init_cwnd);
174
	}
175
}
(-)sys/netinet/tcp_newcwv.h (+39 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2014 Tom Jones <jones@sdf.org>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#ifndef _NETINET_TCP_NEWCWV_H_
29
#define _NETINET_TCP_NEWCWV_H_
30
31
#include <netinet/tcp_var.h>
32
33
void tcp_newcwv_update_pipeack(struct tcpcb *);
34
void tcp_newcwv_reset(struct tcpcb *);
35
void tcp_newcwv_enter_recovery(struct tcpcb *);
36
void tcp_newcwv_end_recovery(struct tcpcb *);
37
void tcp_newcwv_datalim_closedown(struct tcpcb *);
38
39
#endif /* _NETINET_TCP_NEWCWV_H_ */
(-)sys/netinet/tcp_output.c (+5 lines)
Lines 74-79 __FBSDID("$FreeBSD$"); Link Here
74
#include <netinet/tcp_timer.h>
74
#include <netinet/tcp_timer.h>
75
#include <netinet/tcp_var.h>
75
#include <netinet/tcp_var.h>
76
#include <netinet/tcpip.h>
76
#include <netinet/tcpip.h>
77
#include <netinet/tcp_newcwv.h>
77
#ifdef TCPDEBUG
78
#ifdef TCPDEBUG
78
#include <netinet/tcp_debug.h>
79
#include <netinet/tcp_debug.h>
79
#endif
80
#endif
Lines 691-696 send: Link Here
691
#endif
692
#endif
692
		hdrlen = sizeof (struct tcpiphdr);
693
		hdrlen = sizeof (struct tcpiphdr);
693
694
695
	/* Trigger the newcwv timer */
696
	if(V_tcp_do_newcwv)
697
		tcp_newcwv_datalim_closedown(tp);
698
694
	/*
699
	/*
695
	 * Compute options for segment.
700
	 * Compute options for segment.
696
	 * We only have to care about SYN and established connection
701
	 * We only have to care about SYN and established connection
(-)sys/netinet/tcp_subr.c (+1 lines)
Lines 800-805 tcp_newtcpcb(struct inpcb *inp) Link Here
800
		tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
800
		tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
801
	if (V_tcp_do_sack)
801
	if (V_tcp_do_sack)
802
		tp->t_flags |= TF_SACK_PERMIT;
802
		tp->t_flags |= TF_SACK_PERMIT;
803
803
	TAILQ_INIT(&tp->snd_holes);
804
	TAILQ_INIT(&tp->snd_holes);
804
	tp->t_inpcb = inp;	/* XXX */
805
	tp->t_inpcb = inp;	/* XXX */
805
	/*
806
	/*
(-)sys/netinet/tcp_var.h (+18 lines)
Lines 172-177 struct tcpcb { Link Here
172
	int	t_sndzerowin;		/* zero-window updates sent */
172
	int	t_sndzerowin;		/* zero-window updates sent */
173
	u_int	t_badrxtwin;		/* window for retransmit recovery */
173
	u_int	t_badrxtwin;		/* window for retransmit recovery */
174
	u_char	snd_limited;		/* segments limited transmitted */
174
	u_char	snd_limited;		/* segments limited transmitted */
175
/* NewCWV releated state */
176
	struct {
177
		u_int32_t pipeack;
178
		u_int32_t psp;			/* pipeack sampling period */
179
180
		u_int32_t head;
181
		u_int32_t psample[4];	/* pipe ack samples */
182
		u_int32_t time_stamp[4];	/* time stamp samples */
183
		u_int32_t prev_snd_una;		/* previous snd_una in this sampe */
184
		u_int32_t prev_snd_nxt;		/* previous snd_nxt in this sampe */
185
186
		u_int32_t loss_flight_size;	/* flightsize at loss detection */
187
		u_int32_t prior_retrans;	/* Retransmission before going into FR */
188
		u_int32_t cwnd_valid_ts;	/*last time cwnd was found valid */
189
		u_int32_t init_cwnd;	/* The inital cwnd */
190
	} newcwv;
175
/* SACK related state */
191
/* SACK related state */
176
	int	snd_numholes;		/* number of holes seen by sender */
192
	int	snd_numholes;		/* number of holes seen by sender */
177
	TAILQ_HEAD(sackhole_head, sackhole) snd_holes;
193
	TAILQ_HEAD(sackhole_head, sackhole) snd_holes;
Lines 605-610 VNET_DECLARE(int, tcp_recvspace); Link Here
605
VNET_DECLARE(int, path_mtu_discovery);
621
VNET_DECLARE(int, path_mtu_discovery);
606
VNET_DECLARE(int, tcp_do_rfc3465);
622
VNET_DECLARE(int, tcp_do_rfc3465);
607
VNET_DECLARE(int, tcp_abc_l_var);
623
VNET_DECLARE(int, tcp_abc_l_var);
624
VNET_DECLARE(int, tcp_do_newcwv);
608
#define	V_tcb			VNET(tcb)
625
#define	V_tcb			VNET(tcb)
609
#define	V_tcbinfo		VNET(tcbinfo)
626
#define	V_tcbinfo		VNET(tcbinfo)
610
#define	V_tcp_mssdflt		VNET(tcp_mssdflt)
627
#define	V_tcp_mssdflt		VNET(tcp_mssdflt)
Lines 617-622 VNET_DECLARE(int, tcp_abc_l_var); Link Here
617
#define	V_path_mtu_discovery	VNET(path_mtu_discovery)
634
#define	V_path_mtu_discovery	VNET(path_mtu_discovery)
618
#define	V_tcp_do_rfc3465	VNET(tcp_do_rfc3465)
635
#define	V_tcp_do_rfc3465	VNET(tcp_do_rfc3465)
619
#define	V_tcp_abc_l_var		VNET(tcp_abc_l_var)
636
#define	V_tcp_abc_l_var		VNET(tcp_abc_l_var)
637
#define	V_tcp_do_newcwv		VNET(tcp_do_newcwv)
620
638
621
VNET_DECLARE(int, tcp_do_sack);			/* SACK enabled/disabled */
639
VNET_DECLARE(int, tcp_do_sack);			/* SACK enabled/disabled */
622
VNET_DECLARE(int, tcp_sc_rst_sock_fail);	/* RST on sock alloc failure */
640
VNET_DECLARE(int, tcp_sc_rst_sock_fail);	/* RST on sock alloc failure */

Return to bug 191520