diff options
author | Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> | 2007-11-15 22:44:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:54:06 -0500 |
commit | 9e10c47cb9fe3154416787523f7a0df02133063f (patch) | |
tree | 620f07ee479703562cb9e58c9119a1f8ed6b0804 /net/ipv4/tcp_input.c | |
parent | b7d4815f35ab1d0f1eef2521a94a7d4c789290a2 (diff) |
[TCP]: Create tcp_sacktag_one().
Worker function that implements the main logic of
the inner-most loop of tcp_sacktag_write_queue().
Idea was originally presented by David S. Miller.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 192 |
1 files changed, 96 insertions, 96 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5e01ac2c003c..a62e0f90f566 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1240,6 +1240,99 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, | |||
1240 | return in_sack; | 1240 | return in_sack; |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | static int tcp_sacktag_one(struct sk_buff *skb, struct tcp_sock *tp, | ||
1244 | int *reord, int dup_sack, int fack_count) | ||
1245 | { | ||
1246 | u8 sacked = TCP_SKB_CB(skb)->sacked; | ||
1247 | int flag = 0; | ||
1248 | |||
1249 | /* Account D-SACK for retransmitted packet. */ | ||
1250 | if (dup_sack && (sacked & TCPCB_RETRANS)) { | ||
1251 | if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) | ||
1252 | tp->undo_retrans--; | ||
1253 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una) && | ||
1254 | (sacked & TCPCB_SACKED_ACKED)) | ||
1255 | *reord = min(fack_count, *reord); | ||
1256 | } | ||
1257 | |||
1258 | /* Nothing to do; acked frame is about to be dropped (was ACKed). */ | ||
1259 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) | ||
1260 | return flag; | ||
1261 | |||
1262 | if (!(sacked & TCPCB_SACKED_ACKED)) { | ||
1263 | if (sacked & TCPCB_SACKED_RETRANS) { | ||
1264 | /* If the segment is not tagged as lost, | ||
1265 | * we do not clear RETRANS, believing | ||
1266 | * that retransmission is still in flight. | ||
1267 | */ | ||
1268 | if (sacked & TCPCB_LOST) { | ||
1269 | TCP_SKB_CB(skb)->sacked &= | ||
1270 | ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); | ||
1271 | tp->lost_out -= tcp_skb_pcount(skb); | ||
1272 | tp->retrans_out -= tcp_skb_pcount(skb); | ||
1273 | |||
1274 | /* clear lost hint */ | ||
1275 | tp->retransmit_skb_hint = NULL; | ||
1276 | } | ||
1277 | } else { | ||
1278 | if (!(sacked & TCPCB_RETRANS)) { | ||
1279 | /* New sack for not retransmitted frame, | ||
1280 | * which was in hole. It is reordering. | ||
1281 | */ | ||
1282 | if (before(TCP_SKB_CB(skb)->seq, | ||
1283 | tcp_highest_sack_seq(tp))) | ||
1284 | *reord = min(fack_count, *reord); | ||
1285 | |||
1286 | /* SACK enhanced F-RTO (RFC4138; Appendix B) */ | ||
1287 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) | ||
1288 | flag |= FLAG_ONLY_ORIG_SACKED; | ||
1289 | } | ||
1290 | |||
1291 | if (sacked & TCPCB_LOST) { | ||
1292 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; | ||
1293 | tp->lost_out -= tcp_skb_pcount(skb); | ||
1294 | |||
1295 | /* clear lost hint */ | ||
1296 | tp->retransmit_skb_hint = NULL; | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; | ||
1301 | flag |= FLAG_DATA_SACKED; | ||
1302 | tp->sacked_out += tcp_skb_pcount(skb); | ||
1303 | |||
1304 | fack_count += tcp_skb_pcount(skb); | ||
1305 | |||
1306 | /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ | ||
1307 | if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) && | ||
1308 | before(TCP_SKB_CB(skb)->seq, | ||
1309 | TCP_SKB_CB(tp->lost_skb_hint)->seq)) | ||
1310 | tp->lost_cnt_hint += tcp_skb_pcount(skb); | ||
1311 | |||
1312 | if (fack_count > tp->fackets_out) | ||
1313 | tp->fackets_out = fack_count; | ||
1314 | |||
1315 | if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) | ||
1316 | tp->highest_sack = skb; | ||
1317 | |||
1318 | } else { | ||
1319 | if (dup_sack && (sacked & TCPCB_RETRANS)) | ||
1320 | *reord = min(fack_count, *reord); | ||
1321 | } | ||
1322 | |||
1323 | /* D-SACK. We can detect redundant retransmission in S|R and plain R | ||
1324 | * frames and clear it. undo_retrans is decreased above, L|R frames | ||
1325 | * are accounted above as well. | ||
1326 | */ | ||
1327 | if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) { | ||
1328 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | ||
1329 | tp->retrans_out -= tcp_skb_pcount(skb); | ||
1330 | tp->retransmit_skb_hint = NULL; | ||
1331 | } | ||
1332 | |||
1333 | return flag; | ||
1334 | } | ||
1335 | |||
1243 | static int | 1336 | static int |
1244 | tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) | 1337 | tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) |
1245 | { | 1338 | { |
@@ -1375,7 +1468,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1375 | 1468 | ||
1376 | tcp_for_write_queue_from(skb, sk) { | 1469 | tcp_for_write_queue_from(skb, sk) { |
1377 | int in_sack = 0; | 1470 | int in_sack = 0; |
1378 | u8 sacked; | ||
1379 | 1471 | ||
1380 | if (skb == tcp_send_head(sk)) | 1472 | if (skb == tcp_send_head(sk)) |
1381 | break; | 1473 | break; |
@@ -1413,102 +1505,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1413 | if (unlikely(in_sack < 0)) | 1505 | if (unlikely(in_sack < 0)) |
1414 | break; | 1506 | break; |
1415 | 1507 | ||
1416 | if (!in_sack) { | 1508 | if (in_sack) |
1417 | fack_count += tcp_skb_pcount(skb); | 1509 | flag |= tcp_sacktag_one(skb, tp, &reord, dup_sack, fack_count); |
1418 | continue; | ||
1419 | } | ||
1420 | |||
1421 | sacked = TCP_SKB_CB(skb)->sacked; | ||
1422 | |||
1423 | /* Account D-SACK for retransmitted packet. */ | ||
1424 | if (dup_sack && (sacked & TCPCB_RETRANS)) { | ||
1425 | if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) | ||
1426 | tp->undo_retrans--; | ||
1427 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una) && | ||
1428 | (sacked & TCPCB_SACKED_ACKED)) | ||
1429 | reord = min(fack_count, reord); | ||
1430 | } | ||
1431 | |||
1432 | |||
1433 | /* Nothing to do; acked frame is about to be dropped (was ACKed). */ | ||
1434 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) { | ||
1435 | fack_count += tcp_skb_pcount(skb); | ||
1436 | continue; | ||
1437 | } | ||
1438 | |||
1439 | if (!(sacked&TCPCB_SACKED_ACKED)) { | ||
1440 | if (sacked & TCPCB_SACKED_RETRANS) { | ||
1441 | /* If the segment is not tagged as lost, | ||
1442 | * we do not clear RETRANS, believing | ||
1443 | * that retransmission is still in flight. | ||
1444 | */ | ||
1445 | if (sacked & TCPCB_LOST) { | ||
1446 | TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); | ||
1447 | tp->lost_out -= tcp_skb_pcount(skb); | ||
1448 | tp->retrans_out -= tcp_skb_pcount(skb); | ||
1449 | |||
1450 | /* clear lost hint */ | ||
1451 | tp->retransmit_skb_hint = NULL; | ||
1452 | } | ||
1453 | } else { | ||
1454 | if (!(sacked & TCPCB_RETRANS)) { | ||
1455 | /* New sack for not retransmitted frame, | ||
1456 | * which was in hole. It is reordering. | ||
1457 | */ | ||
1458 | if (before(TCP_SKB_CB(skb)->seq, | ||
1459 | tcp_highest_sack_seq(tp))) | ||
1460 | reord = min(fack_count, reord); | ||
1461 | |||
1462 | /* SACK enhanced F-RTO (RFC4138; Appendix B) */ | ||
1463 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) | ||
1464 | flag |= FLAG_ONLY_ORIG_SACKED; | ||
1465 | } | ||
1466 | |||
1467 | if (sacked & TCPCB_LOST) { | ||
1468 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; | ||
1469 | tp->lost_out -= tcp_skb_pcount(skb); | ||
1470 | |||
1471 | /* clear lost hint */ | ||
1472 | tp->retransmit_skb_hint = NULL; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; | ||
1477 | flag |= FLAG_DATA_SACKED; | ||
1478 | tp->sacked_out += tcp_skb_pcount(skb); | ||
1479 | |||
1480 | fack_count += tcp_skb_pcount(skb); | ||
1481 | |||
1482 | /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ | ||
1483 | if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) && | ||
1484 | before(TCP_SKB_CB(skb)->seq, | ||
1485 | TCP_SKB_CB(tp->lost_skb_hint)->seq)) | ||
1486 | tp->lost_cnt_hint += tcp_skb_pcount(skb); | ||
1487 | |||
1488 | if (fack_count > tp->fackets_out) | ||
1489 | tp->fackets_out = fack_count; | ||
1490 | 1510 | ||
1491 | if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) | 1511 | fack_count += tcp_skb_pcount(skb); |
1492 | tp->highest_sack = skb; | ||
1493 | |||
1494 | } else { | ||
1495 | if (dup_sack && (sacked&TCPCB_RETRANS)) | ||
1496 | reord = min(fack_count, reord); | ||
1497 | |||
1498 | fack_count += tcp_skb_pcount(skb); | ||
1499 | } | ||
1500 | |||
1501 | /* D-SACK. We can detect redundant retransmission | ||
1502 | * in S|R and plain R frames and clear it. | ||
1503 | * undo_retrans is decreased above, L|R frames | ||
1504 | * are accounted above as well. | ||
1505 | */ | ||
1506 | if (dup_sack && | ||
1507 | (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) { | ||
1508 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | ||
1509 | tp->retrans_out -= tcp_skb_pcount(skb); | ||
1510 | tp->retransmit_skb_hint = NULL; | ||
1511 | } | ||
1512 | } | 1512 | } |
1513 | 1513 | ||
1514 | /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct | 1514 | /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct |