Blame view
net/sctp/transport.c
19.9 KB
60c778b25
|
1 |
/* SCTP kernel implementation |
1da177e4c
|
2 3 4 5 6 7 |
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 International Business Machines Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 La Monte H.P. Yarroll * |
60c778b25
|
8 |
* This file is part of the SCTP kernel implementation |
1da177e4c
|
9 10 11 12 13 |
* * This module provides the abstraction for an SCTP tranport representing * a remote transport address. For local transport addresses, we just use * union sctp_addr. * |
60c778b25
|
14 |
* This SCTP implementation is free software; |
1da177e4c
|
15 16 17 18 19 |
* you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * |
60c778b25
|
20 |
* This SCTP implementation is distributed in the hope that it |
1da177e4c
|
21 22 23 24 25 26 |
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License |
4b2f13a25
|
27 28 |
* along with GNU CC; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. |
1da177e4c
|
29 30 31 |
* * Please send any bug reports or fixes you make to the * email address(es): |
91705c61b
|
32 |
* lksctp developers <linux-sctp@vger.kernel.org> |
1da177e4c
|
33 |
* |
1da177e4c
|
34 35 36 37 38 39 40 41 |
* Written or modified by: * La Monte H.P. Yarroll <piggy@acm.org> * Karl Knutson <karl@athena.chicago.il.us> * Jon Grimm <jgrimm@us.ibm.com> * Xingang Guo <xingang.guo@intel.com> * Hui Huang <hui.huang@nokia.com> * Sridhar Samudrala <sri@us.ibm.com> * Ardelle Fan <ardelle.fan@intel.com> |
1da177e4c
|
42 |
*/ |
145ce502e
|
43 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
5a0e3ad6a
|
44 |
#include <linux/slab.h> |
1da177e4c
|
45 |
#include <linux/types.h> |
ad8fec172
|
46 |
#include <linux/random.h> |
1da177e4c
|
47 48 49 50 51 52 |
#include <net/sctp/sctp.h> #include <net/sctp/sm.h> /* 1st Level Abstractions. */ /* Initialize a new transport from provided memory. */ |
89bf3450c
|
53 54 |
static struct sctp_transport *sctp_transport_init(struct net *net, struct sctp_transport *peer, |
1da177e4c
|
55 |
const union sctp_addr *addr, |
dd0fc66fb
|
56 |
gfp_t gfp) |
1da177e4c
|
57 58 59 60 |
{ /* Copy in the address. */ peer->ipaddr = *addr; peer->af_specific = sctp_get_af_specific(addr->sa.sa_family); |
1da177e4c
|
61 |
memset(&peer->saddr, 0, sizeof(union sctp_addr)); |
4244854d2
|
62 |
peer->sack_generation = 0; |
1da177e4c
|
63 64 65 66 67 68 |
/* From 6.3.1 RTO Calculation: * * C1) Until an RTT measurement has been made for a packet sent to the * given destination transport address, set RTO to the protocol * parameter 'RTO.Initial'. */ |
e1fc3b14f
|
69 |
peer->rto = msecs_to_jiffies(net->sctp.rto_initial); |
1da177e4c
|
70 |
|
39d2adebf
|
71 |
peer->last_time_heard = ktime_set(0, 0); |
1da177e4c
|
72 |
peer->last_time_ecne_reduced = jiffies; |
52ccb8e90
|
73 74 75 |
peer->param_flags = SPP_HB_DISABLE | SPP_PMTUD_ENABLE | SPP_SACKDELAY_ENABLE; |
1da177e4c
|
76 77 |
/* Initialize the default path max_retrans. */ |
e1fc3b14f
|
78 79 |
peer->pathmaxrxt = net->sctp.max_retrans_path; peer->pf_retrans = net->sctp.pf_retrans; |
1da177e4c
|
80 81 82 83 |
INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); |
b24b8a247
|
84 85 86 87 |
setup_timer(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event, (unsigned long)peer); setup_timer(&peer->hb_timer, sctp_generate_heartbeat_event, (unsigned long)peer); |
50b5d6ad6
|
88 89 |
setup_timer(&peer->proto_unreach_timer, sctp_generate_proto_unreach_event, (unsigned long)peer); |
1da177e4c
|
90 |
|
ad8fec172
|
91 92 |
/* Initialize the 64-bit random nonce sent with heartbeat. */ get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce)); |
1da177e4c
|
93 |
atomic_set(&peer->refcnt, 1); |
1da177e4c
|
94 95 96 97 98 |
return peer; } /* Allocate and initialize a new transport. */ |
89bf3450c
|
99 100 |
struct sctp_transport *sctp_transport_new(struct net *net, const union sctp_addr *addr, |
dd0fc66fb
|
101 |
gfp_t gfp) |
1da177e4c
|
102 |
{ |
d808ad9ab
|
103 |
struct sctp_transport *transport; |
1da177e4c
|
104 |
|
939cfa75a
|
105 |
transport = kzalloc(sizeof(*transport), gfp); |
1da177e4c
|
106 107 |
if (!transport) goto fail; |
89bf3450c
|
108 |
if (!sctp_transport_init(net, transport, addr, gfp)) |
1da177e4c
|
109 |
goto fail_init; |
1da177e4c
|
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
SCTP_DBG_OBJCNT_INC(transport); return transport; fail_init: kfree(transport); fail: return NULL; } /* This transport is no longer needed. Free up if possible, or * delay until it last reference count. */ void sctp_transport_free(struct sctp_transport *transport) { |
1da177e4c
|
126 127 128 129 130 131 132 133 134 |
/* Try to delete the heartbeat timer. */ if (del_timer(&transport->hb_timer)) sctp_transport_put(transport); /* Delete the T3_rtx timer if it's active. * There is no point in not doing this now and letting * structure hang around in memory since we know * the tranport is going away. */ |
25cc4ae91
|
135 |
if (del_timer(&transport->T3_rtx_timer)) |
1da177e4c
|
136 |
sctp_transport_put(transport); |
55fa0cfd7
|
137 |
/* Delete the ICMP proto unreachable timer if it's active. */ |
25cc4ae91
|
138 |
if (del_timer(&transport->proto_unreach_timer)) |
55fa0cfd7
|
139 |
sctp_association_put(transport->asoc); |
1da177e4c
|
140 141 142 |
sctp_transport_put(transport); } |
45122ca26
|
143 |
static void sctp_transport_destroy_rcu(struct rcu_head *head) |
1da177e4c
|
144 |
{ |
45122ca26
|
145 |
struct sctp_transport *transport; |
1da177e4c
|
146 |
|
45122ca26
|
147 |
transport = container_of(head, struct sctp_transport, rcu); |
1da177e4c
|
148 149 150 151 152 |
dst_release(transport->dst); kfree(transport); SCTP_DBG_OBJCNT_DEC(transport); } |
45122ca26
|
153 154 155 156 157 |
/* Destroy the transport data structure. * Assumes there are no more users of this structure. */ static void sctp_transport_destroy(struct sctp_transport *transport) { |
47faa1e4c
|
158 |
if (unlikely(atomic_read(&transport->refcnt))) { |
bb33381d0
|
159 160 161 162 |
WARN(1, "Attempt to destroy undead transport %p! ", transport); return; } |
45122ca26
|
163 |
|
8c98653f0
|
164 165 166 167 |
sctp_packet_free(&transport->packet); if (transport->asoc) sctp_association_put(transport->asoc); |
771085d6b
|
168 169 |
call_rcu(&transport->rcu, sctp_transport_destroy_rcu); |
45122ca26
|
170 |
} |
1da177e4c
|
171 172 173 |
/* Start T3_rtx timer if it is not already running and update the heartbeat * timer. This routine is called every time a DATA chunk is sent. */ |
ba6f5e33b
|
174 |
void sctp_transport_reset_t3_rtx(struct sctp_transport *transport) |
1da177e4c
|
175 176 177 178 179 180 181 182 |
{ /* RFC 2960 6.3.2 Retransmission Timer Rules * * R1) Every time a DATA chunk is sent to any address(including a * retransmission), if the T3-rtx timer of that address is not running * start it running so that it will expire after the RTO of that * address. */ |
d9efc2231
|
183 |
if (!timer_pending(&transport->T3_rtx_timer)) |
1da177e4c
|
184 185 186 |
if (!mod_timer(&transport->T3_rtx_timer, jiffies + transport->rto)) sctp_transport_hold(transport); |
ba6f5e33b
|
187 188 189 190 191 |
} void sctp_transport_reset_hb_timer(struct sctp_transport *transport) { unsigned long expires; |
1da177e4c
|
192 193 |
/* When a data chunk is sent, reset the heartbeat interval. */ |
ba6f5e33b
|
194 195 196 197 198 |
expires = jiffies + sctp_transport_timeout(transport); if (time_before(transport->hb_timer.expires, expires) && !mod_timer(&transport->hb_timer, expires + prandom_u32_max(transport->rto))) sctp_transport_hold(transport); |
1da177e4c
|
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
} /* This transport has been assigned to an association. * Initialize fields from the association or from the sock itself. * Register the reference count in the association. */ void sctp_transport_set_owner(struct sctp_transport *transport, struct sctp_association *asoc) { transport->asoc = asoc; sctp_association_hold(asoc); } /* Initialize the pmtu of a transport. */ |
9914ae3ca
|
213 |
void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) |
1da177e4c
|
214 |
{ |
da0420bee
|
215 |
/* If we don't have a fresh route, look one up */ |
f5b0a8743
|
216 |
if (!transport->dst || transport->dst->obsolete) { |
da0420bee
|
217 218 |
dst_release(transport->dst); transport->af_specific->get_dst(transport, &transport->saddr, |
8663c938c
|
219 |
&transport->fl, sk); |
da0420bee
|
220 |
} |
1da177e4c
|
221 |
|
da0420bee
|
222 |
if (transport->dst) { |
3822a5ff4
|
223 |
transport->pathmtu = WORD_TRUNC(dst_mtu(transport->dst)); |
1da177e4c
|
224 |
} else |
52ccb8e90
|
225 |
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
1da177e4c
|
226 |
} |
02f3d4ce9
|
227 |
void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu) |
c910b47e1
|
228 229 230 231 |
{ struct dst_entry *dst; if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { |
145ce502e
|
232 233 234 235 |
pr_warn("%s: Reported pmtu %d too low, using default minimum of %d ", __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); |
c910b47e1
|
236 237 238 239 |
/* Use default minimum segment size and disable * pmtu discovery on this transport. */ t->pathmtu = SCTP_DEFAULT_MINSEGMENT; |
c910b47e1
|
240 241 242 243 244 |
} else { t->pathmtu = pmtu; } dst = sctp_transport_dst_check(t); |
02f3d4ce9
|
245 246 247 248 |
if (!dst) t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); if (dst) { |
6700c2709
|
249 |
dst->ops->update_pmtu(dst, sk, NULL, pmtu); |
02f3d4ce9
|
250 251 252 253 254 |
dst = sctp_transport_dst_check(t); if (!dst) t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); } |
c910b47e1
|
255 |
} |
1da177e4c
|
256 257 258 259 260 261 262 263 |
/* Caches the dst entry and source address for a transport's destination * address. */ void sctp_transport_route(struct sctp_transport *transport, union sctp_addr *saddr, struct sctp_sock *opt) { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; |
1da177e4c
|
264 |
|
8663c938c
|
265 |
af->get_dst(transport, saddr, &transport->fl, sctp_opt2sk(opt)); |
1da177e4c
|
266 267 268 269 |
if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else |
8663c938c
|
270 |
af->get_saddr(opt, transport, &transport->fl); |
1da177e4c
|
271 |
|
52ccb8e90
|
272 273 274 |
if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } |
da0420bee
|
275 |
if (transport->dst) { |
3822a5ff4
|
276 |
transport->pathmtu = WORD_TRUNC(dst_mtu(transport->dst)); |
1da177e4c
|
277 278 279 |
/* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). |
d808ad9ab
|
280 |
*/ |
a78102e74
|
281 282 |
if (asoc && (!asoc->peer.primary_path || (transport == asoc->peer.active_path))) |
299ee123e
|
283 284 |
opt->pf->to_sk_saddr(&transport->saddr, asoc->base.sk); |
1da177e4c
|
285 |
} else |
52ccb8e90
|
286 |
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
1da177e4c
|
287 288 289 |
} /* Hold a reference to a transport. */ |
1eed67793
|
290 |
int sctp_transport_hold(struct sctp_transport *transport) |
1da177e4c
|
291 |
{ |
1eed67793
|
292 |
return atomic_add_unless(&transport->refcnt, 1, 0); |
1da177e4c
|
293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
} /* Release a reference to a transport and clean up * if there are no more references. */ void sctp_transport_put(struct sctp_transport *transport) { if (atomic_dec_and_test(&transport->refcnt)) sctp_transport_destroy(transport); } /* Update transport's RTO based on the newly calculated RTT. */ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) { |
bb33381d0
|
307 308 309 310 |
if (unlikely(!tp->rto_pending)) /* We should not be doing any RTO updates unless rto_pending is set. */ pr_debug("%s: rto_pending not set on transport %p! ", __func__, tp); |
1da177e4c
|
311 312 |
if (tp->rttvar || tp->srtt) { |
e1fc3b14f
|
313 |
struct net *net = sock_net(tp->asoc->base.sk); |
1da177e4c
|
314 315 316 317 318 319 320 321 322 323 324 |
/* 6.3.1 C3) When a new RTT measurement R' is made, set * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' */ /* Note: The above algorithm has been rewritten to * express rto_beta and rto_alpha as inverse powers * of two. * For example, assuming the default value of RTO.Alpha of * 1/8, rto_alpha would be expressed as 3. */ |
e1fc3b14f
|
325 |
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) |
79211c8ed
|
326 |
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta); |
e1fc3b14f
|
327 328 |
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) + (rtt >> net->sctp.rto_alpha); |
1da177e4c
|
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
} else { /* 6.3.1 C2) When the first RTT measurement R is made, set * SRTT <- R, RTTVAR <- R/2. */ tp->srtt = rtt; tp->rttvar = rtt >> 1; } /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then * adjust RTTVAR <- G, where G is the CLOCK GRANULARITY. */ if (tp->rttvar == 0) tp->rttvar = SCTP_CLOCK_GRANULARITY; /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ tp->rto = tp->srtt + (tp->rttvar << 2); /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min * seconds then it is rounded up to RTO.Min seconds. */ if (tp->rto < tp->asoc->rto_min) tp->rto = tp->asoc->rto_min; /* 6.3.1 C7) A maximum value may be placed on RTO provided it is * at least RTO.max seconds. */ if (tp->rto > tp->asoc->rto_max) tp->rto = tp->asoc->rto_max; |
196d67593
|
357 |
sctp_max_rto(tp->asoc, tp); |
1da177e4c
|
358 359 360 361 362 363 |
tp->rtt = rtt; /* Reset rto_pending so that a new RTT measurement is started when a * new data chunk is sent. */ tp->rto_pending = 0; |
bb33381d0
|
364 365 366 |
pr_debug("%s: transport:%p, rtt:%d, srtt:%d rttvar:%d, rto:%ld ", __func__, tp, rtt, tp->srtt, tp->rttvar, tp->rto); |
1da177e4c
|
367 368 369 370 371 372 373 374 |
} /* This routine updates the transport's cwnd and partial_bytes_acked * parameters based on the bytes acked in the received SACK. */ void sctp_transport_raise_cwnd(struct sctp_transport *transport, __u32 sack_ctsn, __u32 bytes_acked) { |
cf9b4812e
|
375 |
struct sctp_association *asoc = transport->asoc; |
1da177e4c
|
376 377 378 379 |
__u32 cwnd, ssthresh, flight_size, pba, pmtu; cwnd = transport->cwnd; flight_size = transport->flight_size; |
a64652348
|
380 |
/* See if we need to exit Fast Recovery first */ |
cf9b4812e
|
381 382 383 |
if (asoc->fast_recovery && TSN_lte(asoc->fast_recovery_exit, sack_ctsn)) asoc->fast_recovery = 0; |
a64652348
|
384 |
|
1da177e4c
|
385 |
/* The appropriate cwnd increase algorithm is performed if, and only |
a64652348
|
386 |
* if the cumulative TSN whould advanced and the congestion window is |
1da177e4c
|
387 388 |
* being fully utilized. */ |
a64652348
|
389 |
if (TSN_lte(sack_ctsn, transport->asoc->ctsn_ack_point) || |
1da177e4c
|
390 391 392 393 394 |
(flight_size < cwnd)) return; ssthresh = transport->ssthresh; pba = transport->partial_bytes_acked; |
52ccb8e90
|
395 |
pmtu = transport->asoc->pathmtu; |
1da177e4c
|
396 397 |
if (cwnd <= ssthresh) { |
a64652348
|
398 399 400 401 402 403 404 405 406 407 408 409 410 |
/* RFC 4960 7.2.1 * o When cwnd is less than or equal to ssthresh, an SCTP * endpoint MUST use the slow-start algorithm to increase * cwnd only if the current congestion window is being fully * utilized, an incoming SACK advances the Cumulative TSN * Ack Point, and the data sender is not in Fast Recovery. * Only when these three conditions are met can the cwnd be * increased; otherwise, the cwnd MUST not be increased. * If these conditions are met, then cwnd MUST be increased * by, at most, the lesser of 1) the total size of the * previously outstanding DATA chunk(s) acknowledged, and * 2) the destination's path MTU. This upper bound protects * against the ACK-Splitting attack outlined in [SAVAGE99]. |
1da177e4c
|
411 |
*/ |
cf9b4812e
|
412 |
if (asoc->fast_recovery) |
a64652348
|
413 |
return; |
1da177e4c
|
414 415 416 417 |
if (bytes_acked > pmtu) cwnd += pmtu; else cwnd += bytes_acked; |
bb33381d0
|
418 419 420 421 422 423 |
pr_debug("%s: slow start: transport:%p, bytes_acked:%d, " "cwnd:%d, ssthresh:%d, flight_size:%d, pba:%d ", __func__, transport, bytes_acked, cwnd, ssthresh, flight_size, pba); |
1da177e4c
|
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
} else { /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, * upon each SACK arrival that advances the Cumulative TSN Ack * Point, increase partial_bytes_acked by the total number of * bytes of all new chunks acknowledged in that SACK including * chunks acknowledged by the new Cumulative TSN Ack and by * Gap Ack Blocks. * * When partial_bytes_acked is equal to or greater than cwnd * and before the arrival of the SACK the sender had cwnd or * more bytes of data outstanding (i.e., before arrival of the * SACK, flightsize was greater than or equal to cwnd), * increase cwnd by MTU, and reset partial_bytes_acked to * (partial_bytes_acked - cwnd). */ pba += bytes_acked; if (pba >= cwnd) { cwnd += pmtu; pba = ((cwnd < pba) ? (pba - cwnd) : 0); } |
bb33381d0
|
444 445 446 447 448 449 450 |
pr_debug("%s: congestion avoidance: transport:%p, " "bytes_acked:%d, cwnd:%d, ssthresh:%d, " "flight_size:%d, pba:%d ", __func__, transport, bytes_acked, cwnd, ssthresh, flight_size, pba); |
1da177e4c
|
451 452 453 454 455 456 457 458 459 460 461 462 |
} transport->cwnd = cwnd; transport->partial_bytes_acked = pba; } /* This routine is used to lower the transport's cwnd when congestion is * detected. */ void sctp_transport_lower_cwnd(struct sctp_transport *transport, sctp_lower_cwnd_t reason) { |
cf9b4812e
|
463 |
struct sctp_association *asoc = transport->asoc; |
1da177e4c
|
464 465 466 467 468 469 470 471 472 473 |
switch (reason) { case SCTP_LOWER_CWND_T3_RTX: /* RFC 2960 Section 7.2.3, sctpimpguide * When the T3-rtx timer expires on an address, SCTP should * perform slow start by: * ssthresh = max(cwnd/2, 4*MTU) * cwnd = 1*MTU * partial_bytes_acked = 0 */ transport->ssthresh = max(transport->cwnd/2, |
cf9b4812e
|
474 475 |
4*asoc->pathmtu); transport->cwnd = asoc->pathmtu; |
33ce82813
|
476 |
|
cf9b4812e
|
477 478 |
/* T3-rtx also clears fast recovery */ asoc->fast_recovery = 0; |
1da177e4c
|
479 480 481 482 483 484 485 |
break; case SCTP_LOWER_CWND_FAST_RTX: /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the * destination address(es) to which the missing DATA chunks * were last sent, according to the formula described in * Section 7.2.3. |
d808ad9ab
|
486 487 |
* * RFC 2960 7.2.3, sctpimpguide Upon detection of packet |
1da177e4c
|
488 489 490 491 492 493 |
* losses from SACK (see Section 7.2.4), An endpoint * should do the following: * ssthresh = max(cwnd/2, 4*MTU) * cwnd = ssthresh * partial_bytes_acked = 0 */ |
cf9b4812e
|
494 |
if (asoc->fast_recovery) |
a64652348
|
495 496 497 |
return; /* Mark Fast recovery */ |
cf9b4812e
|
498 499 |
asoc->fast_recovery = 1; asoc->fast_recovery_exit = asoc->next_tsn - 1; |
a64652348
|
500 |
|
1da177e4c
|
501 |
transport->ssthresh = max(transport->cwnd/2, |
cf9b4812e
|
502 |
4*asoc->pathmtu); |
1da177e4c
|
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
transport->cwnd = transport->ssthresh; break; case SCTP_LOWER_CWND_ECNE: /* RFC 2481 Section 6.1.2. * If the sender receives an ECN-Echo ACK packet * then the sender knows that congestion was encountered in the * network on the path from the sender to the receiver. The * indication of congestion should be treated just as a * congestion loss in non-ECN Capable TCP. That is, the TCP * source halves the congestion window "cwnd" and reduces the * slow start threshold "ssthresh". * A critical condition is that TCP does not react to * congestion indications more than once every window of * data (or more loosely more than once every round-trip time). */ |
f61f6f82c
|
519 520 |
if (time_after(jiffies, transport->last_time_ecne_reduced + transport->rtt)) { |
1da177e4c
|
521 |
transport->ssthresh = max(transport->cwnd/2, |
cf9b4812e
|
522 |
4*asoc->pathmtu); |
1da177e4c
|
523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
transport->cwnd = transport->ssthresh; transport->last_time_ecne_reduced = jiffies; } break; case SCTP_LOWER_CWND_INACTIVE: /* RFC 2960 Section 7.2.1, sctpimpguide * When the endpoint does not transmit data on a given * transport address, the cwnd of the transport address * should be adjusted to max(cwnd/2, 4*MTU) per RTO. * NOTE: Although the draft recommends that this check needs * to be done every RTO interval, we do it every hearbeat * interval. */ |
245cba7e5
|
537 |
transport->cwnd = max(transport->cwnd/2, |
cf9b4812e
|
538 |
4*asoc->pathmtu); |
1da177e4c
|
539 |
break; |
3ff50b799
|
540 |
} |
1da177e4c
|
541 542 |
transport->partial_bytes_acked = 0; |
bb33381d0
|
543 544 545 546 547 |
pr_debug("%s: transport:%p, reason:%d, cwnd:%d, ssthresh:%d ", __func__, transport, reason, transport->cwnd, transport->ssthresh); |
1da177e4c
|
548 |
} |
46d5a8085
|
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
/* Apply Max.Burst limit to the congestion window: * sctpimpguide-05 2.14.2 * D) When the time comes for the sender to * transmit new DATA chunks, the protocol parameter Max.Burst MUST * first be applied to limit how many new DATA chunks may be sent. * The limit is applied by adjusting cwnd as follows: * if ((flightsize+ Max.Burst * MTU) < cwnd) * cwnd = flightsize + Max.Burst * MTU */ void sctp_transport_burst_limited(struct sctp_transport *t) { struct sctp_association *asoc = t->asoc; u32 old_cwnd = t->cwnd; u32 max_burst_bytes; |
78ac814f1
|
564 |
if (t->burst_limited || asoc->max_burst == 0) |
46d5a8085
|
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
return; max_burst_bytes = t->flight_size + (asoc->max_burst * asoc->pathmtu); if (max_burst_bytes < old_cwnd) { t->cwnd = max_burst_bytes; t->burst_limited = old_cwnd; } } /* Restore the old cwnd congestion window, after the burst had it's * desired effect. */ void sctp_transport_burst_reset(struct sctp_transport *t) { if (t->burst_limited) { t->cwnd = t->burst_limited; t->burst_limited = 0; } } |
1da177e4c
|
584 |
/* What is the next timeout value for this transport? */ |
8f61059a9
|
585 |
unsigned long sctp_transport_timeout(struct sctp_transport *trans) |
1da177e4c
|
586 |
{ |
8f61059a9
|
587 |
/* RTO + timer slack +/- 50% of RTO */ |
ba6f5e33b
|
588 |
unsigned long timeout = trans->rto >> 1; |
8f61059a9
|
589 590 591 592 |
if (trans->state != SCTP_UNCONFIRMED && trans->state != SCTP_PF) timeout += trans->hbinterval; |
ba6f5e33b
|
593 |
return timeout; |
1da177e4c
|
594 |
} |
749bf9215
|
595 596 597 598 599 600 601 602 603 604 605 606 |
/* Reset transport variables to their initial values */ void sctp_transport_reset(struct sctp_transport *t) { struct sctp_association *asoc = t->asoc; /* RFC 2960 (bis), Section 5.2.4 * All the congestion control parameters (e.g., cwnd, ssthresh) * related to this peer MUST be reset to their initial values * (see Section 6.2.1) */ t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); |
46d5a8085
|
607 |
t->burst_limited = 0; |
289f42492
|
608 |
t->ssthresh = asoc->peer.i.a_rwnd; |
5fdd4baef
|
609 |
t->rto = asoc->rto_initial; |
196d67593
|
610 |
sctp_max_rto(asoc, t); |
749bf9215
|
611 612 613 614 615 616 617 618 619 620 621 |
t->rtt = 0; t->srtt = 0; t->rttvar = 0; /* Reset these additional varibles so that we have a clean * slate. */ t->partial_bytes_acked = 0; t->flight_size = 0; t->error_count = 0; t->rto_pending = 0; |
faee47cdb
|
622 |
t->hb_sent = 0; |
749bf9215
|
623 624 625 626 627 628 629 |
/* Initialize the state information for SFR-CACC */ t->cacc.changeover_active = 0; t->cacc.cycling_changeover = 0; t->cacc.next_tsn_at_change = 0; t->cacc.cacc_saw_newack = 0; } |
ddc4bbee6
|
630 631 632 633 634 |
/* Schedule retransmission on the given transport */ void sctp_transport_immediate_rtx(struct sctp_transport *t) { /* Stop pending T3_rtx_timer */ |
25cc4ae91
|
635 |
if (del_timer(&t->T3_rtx_timer)) |
ddc4bbee6
|
636 |
sctp_transport_put(t); |
25cc4ae91
|
637 |
|
ddc4bbee6
|
638 639 640 641 642 |
sctp_retransmit(&t->asoc->outqueue, t, SCTP_RTXR_T3_RTX); if (!timer_pending(&t->T3_rtx_timer)) { if (!mod_timer(&t->T3_rtx_timer, jiffies + t->rto)) sctp_transport_hold(t); } |
ddc4bbee6
|
643 |
} |