tcp_sack.c (8291294024cbe743b2d0dd60c6307c96ca053df9) | tcp_sack.c (e891d82b5674ff785a8ab1018610c598f36b7b8a) |
---|---|
1/*- 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 3 * The Regents of the University of California. 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 --- 156 unchanged lines hidden (view full) --- 165extern struct uma_zone *sack_hole_zone; 166 167SYSCTL_NODE(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW, 0, "TCP SACK"); 168int tcp_do_sack = 1; 169SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, enable, CTLFLAG_RW, 170 &tcp_do_sack, 0, "Enable/Disable TCP SACK support"); 171TUNABLE_INT("net.inet.tcp.sack.enable", &tcp_do_sack); 172 | 1/*- 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 3 * The Regents of the University of California. 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 --- 156 unchanged lines hidden (view full) --- 165extern struct uma_zone *sack_hole_zone; 166 167SYSCTL_NODE(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW, 0, "TCP SACK"); 168int tcp_do_sack = 1; 169SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, enable, CTLFLAG_RW, 170 &tcp_do_sack, 0, "Enable/Disable TCP SACK support"); 171TUNABLE_INT("net.inet.tcp.sack.enable", &tcp_do_sack); 172 |
173static int tcp_sack_maxholes = 128; 174SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, maxholes, CTLFLAG_RW, 175 &tcp_sack_maxholes, 0, 176 "Maximum number of TCP SACK holes allowed per connection"); 177 178static int tcp_sack_globalmaxholes = 65536; 179SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, globalmaxholes, CTLFLAG_RW, 180 &tcp_sack_globalmaxholes, 0, 181 "Global maximum number of TCP SACK holes"); 182 183static int tcp_sack_globalholes = 0; 184SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, globalholes, CTLFLAG_RD, 185 &tcp_sack_globalholes, 0, 186 "Global number of TCP SACK holes currently allocated"); |
|
173/* 174 * This function is called upon receipt of new valid data (while not in header 175 * prediction mode), and it updates the ordered list of sacks. 176 */ 177void 178tcp_update_sack_list(tp, rcv_laststart, rcv_lastend) 179 struct tcpcb *tp; 180 tcp_seq rcv_laststart, rcv_lastend; --- 111 unchanged lines hidden (view full) --- 292{ 293 int tmp_olen; 294 u_char *tmp_cp; 295 struct sackhole *cur, *p, *temp; 296 297 INP_LOCK_ASSERT(tp->t_inpcb); 298 if (!tp->sack_enable) 299 return (1); | 187/* 188 * This function is called upon receipt of new valid data (while not in header 189 * prediction mode), and it updates the ordered list of sacks. 190 */ 191void 192tcp_update_sack_list(tp, rcv_laststart, rcv_lastend) 193 struct tcpcb *tp; 194 tcp_seq rcv_laststart, rcv_lastend; --- 111 unchanged lines hidden (view full) --- 306{ 307 int tmp_olen; 308 u_char *tmp_cp; 309 struct sackhole *cur, *p, *temp; 310 311 INP_LOCK_ASSERT(tp->t_inpcb); 312 if (!tp->sack_enable) 313 return (1); |
300 | 314 if ((th->th_flags & TH_ACK) == 0) 315 return (1); |
301 /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */ 302 if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0) 303 return (1); | 316 /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */ 317 if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0) 318 return (1); |
304 /* If ack is outside window, ignore the SACK options */ | 319 /* If ack is outside [snd_una, snd_max], ignore the SACK options */ |
305 if (SEQ_LT(th->th_ack, tp->snd_una) || SEQ_GT(th->th_ack, tp->snd_max)) 306 return (1); 307 tmp_cp = cp + 2; 308 tmp_olen = optlen - 2; 309 tcpstat.tcps_sack_rcv_blocks++; | 320 if (SEQ_LT(th->th_ack, tp->snd_una) || SEQ_GT(th->th_ack, tp->snd_max)) 321 return (1); 322 tmp_cp = cp + 2; 323 tmp_olen = optlen - 2; 324 tcpstat.tcps_sack_rcv_blocks++; |
310 if (tp->snd_numholes < 0) | 325 if (tp->snd_numholes < 0) /* XXX panic? */ |
311 tp->snd_numholes = 0; 312 if (tp->t_maxseg == 0) 313 panic("tcp_sack_option"); /* Should never happen */ 314 while (tmp_olen > 0) { 315 struct sackblk sack; 316 317 bcopy(tmp_cp, (char *) &(sack.start), sizeof(tcp_seq)); 318 sack.start = ntohl(sack.start); --- 8 unchanged lines hidden (view full) --- 327 continue; /* old block */ 328 if (SEQ_GT(th->th_ack, tp->snd_una)) { 329 if (SEQ_LT(sack.start, th->th_ack)) 330 continue; 331 } 332 if (SEQ_GT(sack.end, tp->snd_max)) 333 continue; 334 if (tp->snd_holes == NULL) { /* first hole */ | 326 tp->snd_numholes = 0; 327 if (tp->t_maxseg == 0) 328 panic("tcp_sack_option"); /* Should never happen */ 329 while (tmp_olen > 0) { 330 struct sackblk sack; 331 332 bcopy(tmp_cp, (char *) &(sack.start), sizeof(tcp_seq)); 333 sack.start = ntohl(sack.start); --- 8 unchanged lines hidden (view full) --- 342 continue; /* old block */ 343 if (SEQ_GT(th->th_ack, tp->snd_una)) { 344 if (SEQ_LT(sack.start, th->th_ack)) 345 continue; 346 } 347 if (SEQ_GT(sack.end, tp->snd_max)) 348 continue; 349 if (tp->snd_holes == NULL) { /* first hole */ |
350 if (tcp_sack_globalholes >= tcp_sack_globalmaxholes || 351 tcp_sack_maxholes == 0) { 352 tcpstat.tcps_sack_sboverflow++; 353 continue; 354 } |
|
335 tp->snd_holes = (struct sackhole *) 336 uma_zalloc(sack_hole_zone,M_NOWAIT); 337 if (tp->snd_holes == NULL) { 338 /* ENOBUFS, so ignore SACKed block for now*/ 339 continue; 340 } 341 cur = tp->snd_holes; 342 cur->start = th->th_ack; 343 cur->end = sack.start; 344 cur->rxmit = cur->start; 345 cur->next = NULL; 346 tp->snd_numholes = 1; | 355 tp->snd_holes = (struct sackhole *) 356 uma_zalloc(sack_hole_zone,M_NOWAIT); 357 if (tp->snd_holes == NULL) { 358 /* ENOBUFS, so ignore SACKed block for now*/ 359 continue; 360 } 361 cur = tp->snd_holes; 362 cur->start = th->th_ack; 363 cur->end = sack.start; 364 cur->rxmit = cur->start; 365 cur->next = NULL; 366 tp->snd_numholes = 1; |
367 tcp_sack_globalholes++; |
|
347 tp->rcv_lastsack = sack.end; 348 continue; /* with next sack block */ 349 } 350 /* Go thru list of holes: p = previous, cur = current */ 351 p = cur = tp->snd_holes; 352 while (cur) { 353 if (SEQ_LEQ(sack.end, cur->start)) 354 /* SACKs data before the current hole */ --- 14 unchanged lines hidden (view full) --- 369 cur = p->next; 370 } else { 371 cur = cur->next; 372 uma_zfree(sack_hole_zone, p); 373 p = cur; 374 tp->snd_holes = p; 375 } 376 tp->snd_numholes--; | 368 tp->rcv_lastsack = sack.end; 369 continue; /* with next sack block */ 370 } 371 /* Go thru list of holes: p = previous, cur = current */ 372 p = cur = tp->snd_holes; 373 while (cur) { 374 if (SEQ_LEQ(sack.end, cur->start)) 375 /* SACKs data before the current hole */ --- 14 unchanged lines hidden (view full) --- 390 cur = p->next; 391 } else { 392 cur = cur->next; 393 uma_zfree(sack_hole_zone, p); 394 p = cur; 395 tp->snd_holes = p; 396 } 397 tp->snd_numholes--; |
398 tcp_sack_globalholes--; |
|
377 continue; 378 } 379 /* otherwise, move start of hole forward */ 380 cur->start = sack.end; 381 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start); 382 p = cur; 383 cur = cur->next; 384 continue; --- 7 unchanged lines hidden (view full) --- 392 continue; 393 } 394 if (SEQ_LT(cur->start, sack.start) && 395 SEQ_GT(cur->end, sack.end)) { 396 /* 397 * ACKs some data in middle of a hole; need to 398 * split current hole 399 */ | 399 continue; 400 } 401 /* otherwise, move start of hole forward */ 402 cur->start = sack.end; 403 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start); 404 p = cur; 405 cur = cur->next; 406 continue; --- 7 unchanged lines hidden (view full) --- 414 continue; 415 } 416 if (SEQ_LT(cur->start, sack.start) && 417 SEQ_GT(cur->end, sack.end)) { 418 /* 419 * ACKs some data in middle of a hole; need to 420 * split current hole 421 */ |
422 if (tp->snd_numholes >= tcp_sack_maxholes || 423 tcp_sack_globalholes >= 424 tcp_sack_globalmaxholes) { 425 tcpstat.tcps_sack_sboverflow++; 426 continue; 427 } |
|
400 temp = (struct sackhole *) 401 uma_zalloc(sack_hole_zone,M_NOWAIT); 402 if (temp == NULL) 403 continue; /* ENOBUFS */ 404 temp->next = cur->next; 405 temp->start = sack.end; 406 temp->end = cur->end; 407 temp->rxmit = SEQ_MAX(cur->rxmit, temp->start); 408 cur->end = sack.start; 409 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); 410 cur->next = temp; 411 p = temp; 412 cur = p->next; 413 tp->snd_numholes++; | 428 temp = (struct sackhole *) 429 uma_zalloc(sack_hole_zone,M_NOWAIT); 430 if (temp == NULL) 431 continue; /* ENOBUFS */ 432 temp->next = cur->next; 433 temp->start = sack.end; 434 temp->end = cur->end; 435 temp->rxmit = SEQ_MAX(cur->rxmit, temp->start); 436 cur->end = sack.start; 437 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); 438 cur->next = temp; 439 p = temp; 440 cur = p->next; 441 tp->snd_numholes++; |
442 tcp_sack_globalholes++; |
|
414 } 415 } 416 /* At this point, p points to the last hole on the list */ 417 if (SEQ_LT(tp->rcv_lastsack, sack.start)) { 418 /* 419 * Need to append new hole at end. 420 * Last hole is p (and it's not NULL). 421 */ | 443 } 444 } 445 /* At this point, p points to the last hole on the list */ 446 if (SEQ_LT(tp->rcv_lastsack, sack.start)) { 447 /* 448 * Need to append new hole at end. 449 * Last hole is p (and it's not NULL). 450 */ |
451 if (tp->snd_numholes >= tcp_sack_maxholes || 452 tcp_sack_globalholes >= tcp_sack_globalmaxholes) { 453 tcpstat.tcps_sack_sboverflow++; 454 continue; 455 } |
|
422 temp = (struct sackhole *) 423 uma_zalloc(sack_hole_zone,M_NOWAIT); 424 if (temp == NULL) 425 continue; /* ENOBUFS */ 426 temp->start = tp->rcv_lastsack; 427 temp->end = sack.start; 428 temp->rxmit = temp->start; 429 temp->next = 0; 430 p->next = temp; 431 tp->rcv_lastsack = sack.end; 432 tp->snd_numholes++; | 456 temp = (struct sackhole *) 457 uma_zalloc(sack_hole_zone,M_NOWAIT); 458 if (temp == NULL) 459 continue; /* ENOBUFS */ 460 temp->start = tp->rcv_lastsack; 461 temp->end = sack.start; 462 temp->rxmit = temp->start; 463 temp->next = 0; 464 p->next = temp; 465 tp->rcv_lastsack = sack.end; 466 tp->snd_numholes++; |
467 tcp_sack_globalholes++; |
|
433 } 434 } 435 return (0); 436} 437 438/* 439 * Delete stale (i.e, cumulatively ack'd) holes. Hole is deleted only if 440 * it is completely acked; otherwise, tcp_sack_option(), called from --- 12 unchanged lines hidden (view full) --- 453 struct sackhole *cur = tp->snd_holes; 454 struct sackhole *prev; 455 while (cur) 456 if (SEQ_LEQ(cur->end, lastack)) { 457 prev = cur; 458 cur = cur->next; 459 uma_zfree(sack_hole_zone, prev); 460 tp->snd_numholes--; | 468 } 469 } 470 return (0); 471} 472 473/* 474 * Delete stale (i.e, cumulatively ack'd) holes. Hole is deleted only if 475 * it is completely acked; otherwise, tcp_sack_option(), called from --- 12 unchanged lines hidden (view full) --- 488 struct sackhole *cur = tp->snd_holes; 489 struct sackhole *prev; 490 while (cur) 491 if (SEQ_LEQ(cur->end, lastack)) { 492 prev = cur; 493 cur = cur->next; 494 uma_zfree(sack_hole_zone, prev); 495 tp->snd_numholes--; |
496 tcp_sack_globalholes--; |
|
461 } else if (SEQ_LT(cur->start, lastack)) { 462 cur->start = lastack; 463 if (SEQ_LT(cur->rxmit, cur->start)) 464 cur->rxmit = cur->start; 465 break; 466 } else 467 break; 468 tp->snd_holes = cur; --- 6 unchanged lines hidden (view full) --- 475 struct sackhole *p, *q; 476 477 INP_LOCK_ASSERT(tp->t_inpcb); 478 q = tp->snd_holes; 479 while (q != NULL) { 480 p = q; 481 q = q->next; 482 uma_zfree(sack_hole_zone, p); | 497 } else if (SEQ_LT(cur->start, lastack)) { 498 cur->start = lastack; 499 if (SEQ_LT(cur->rxmit, cur->start)) 500 cur->rxmit = cur->start; 501 break; 502 } else 503 break; 504 tp->snd_holes = cur; --- 6 unchanged lines hidden (view full) --- 511 struct sackhole *p, *q; 512 513 INP_LOCK_ASSERT(tp->t_inpcb); 514 q = tp->snd_holes; 515 while (q != NULL) { 516 p = q; 517 q = q->next; 518 uma_zfree(sack_hole_zone, p); |
519 tcp_sack_globalholes--; |
|
483 } 484 tp->snd_holes = 0; | 520 } 521 tp->snd_holes = 0; |
522 tp->snd_numholes = 0; |
|
485} 486 487/* 488 * Partial ack handling within a sack recovery episode. 489 * Keeping this very simple for now. When a partial ack 490 * is received, force snd_cwnd to a value that will allow 491 * the sender to transmit no more than 2 segments. 492 * If necessary, a better scheme can be adopted at a --- 105 unchanged lines hidden --- | 523} 524 525/* 526 * Partial ack handling within a sack recovery episode. 527 * Keeping this very simple for now. When a partial ack 528 * is received, force snd_cwnd to a value that will allow 529 * the sender to transmit no more than 2 segments. 530 * If necessary, a better scheme can be adopted at a --- 105 unchanged lines hidden --- |