aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-11-15 22:44:56 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:54:06 -0500
commit9e10c47cb9fe3154416787523f7a0df02133063f (patch)
tree620f07ee479703562cb9e58c9119a1f8ed6b0804 /net
parentb7d4815f35ab1d0f1eef2521a94a7d4c789290a2 (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')
-rw-r--r--net/ipv4/tcp_input.c192
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
1243static 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
1243static int 1336static int
1244tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) 1337tcp_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