@@ -984,23 +984,41 @@ static int tcp_options_fit_accecn(struct tcp_out_options *opts, int required,
int remaining, int max_combine_saving)
{
int size = TCP_ACCECN_MAXSIZE;
+ int sack_blocks_reduce = 0;
+ int rem = remaining;
opts->num_accecn_fields = TCP_ACCECN_NUMFIELDS;
-
while (opts->num_accecn_fields >= required) {
int leftover_size = size & 0x3;
/* Pad to dword if cannot combine */
if (leftover_size > max_combine_saving)
leftover_size = -((4 - leftover_size) & 0x3);
- if (remaining >= size - leftover_size) {
+ if (rem >= size - leftover_size) {
size -= leftover_size;
break;
+ } else if (opts->num_accecn_fields == required &&
+ opts->num_sack_blocks > 2 &&
+ required > 0) {
+ /* Try to fit the option by removing one SACK block */
+ opts->num_sack_blocks--;
+ sack_blocks_reduce++;
+ rem = rem + TCPOLEN_SACK_PERBLOCK;
+
+ opts->num_accecn_fields = TCP_ACCECN_NUMFIELDS;
+ size = TCP_ACCECN_MAXSIZE;
+ continue;
}
opts->num_accecn_fields--;
size -= TCPOLEN_ACCECN_PERFIELD;
}
+ if (sack_blocks_reduce > 0) {
+ if (opts->num_accecn_fields >= required)
+ size -= sack_blocks_reduce * TCPOLEN_SACK_PERBLOCK;
+ else
+ opts->num_sack_blocks += sack_blocks_reduce;
+ }
if (opts->num_accecn_fields < required)
return 0;