Added
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-10) 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 |
} |