diff options
Diffstat (limited to 'sys/netinet/tcp_stacks/sack_filter.c')
-rw-r--r-- | sys/netinet/tcp_stacks/sack_filter.c | 166 |
1 files changed, 133 insertions, 33 deletions
diff --git a/sys/netinet/tcp_stacks/sack_filter.c b/sys/netinet/tcp_stacks/sack_filter.c index 2ef0eadfa944..c4b35d5b8ca8 100644 --- a/sys/netinet/tcp_stacks/sack_filter.c +++ b/sys/netinet/tcp_stacks/sack_filter.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017 Netflix, Inc. + * Copyright (c) 2017-9 Netflix, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -140,6 +140,7 @@ static int32_t is_sack_on_board(struct sack_filter *sf, struct sackblk *b) { int32_t i, cnt; + for (i = sf->sf_cur, cnt=0; cnt < SACK_FILTER_BLOCKS; cnt++) { if (sack_blk_used(sf, i)) { if (SEQ_LT(b->start, sf->sf_ack)) { @@ -150,8 +151,9 @@ is_sack_on_board(struct sack_filter *sf, struct sackblk *b) /* End back behind too */ b->end = sf->sf_ack; } - if (b->start == b->end) + if (b->start == b->end) { return(1); + } /* Jonathans Rule 1 */ if (SEQ_LEQ(sf->sf_blks[i].start, b->start) && SEQ_GEQ(sf->sf_blks[i].end, b->end)) { @@ -312,21 +314,22 @@ sack_filter_new(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_seq if (num == 0) return(num); - /* Now what we are left is either + /* Now what we are left with is either * completely merged on to the board - * from the above steps, or are new + * from the above steps, or is new * and need to be added to the board * with the last one updated to current. * - * First copy it out we want to return that + * First copy it out, we want to return that * to our caller for processing. */ memcpy(in, blkboard, (num * sizeof(struct sackblk))); numblks = num; /* Now go through and add to our board as needed */ for(i=(num-1); i>=0; i--) { - if (is_sack_on_board(sf, &blkboard[i])) + if (is_sack_on_board(sf, &blkboard[i])) { continue; + } /* Add this guy its not listed */ sf->sf_cur++; sf->sf_cur %= SACK_FILTER_BLOCKS; @@ -463,25 +466,60 @@ sack_board_collapse(struct sack_filter *sf) } #ifndef _KERNEL +uint64_t saved=0; +uint64_t tot_sack_blks=0; + +static void +sack_filter_dump(FILE *out, struct sack_filter *sf) +{ + int i; + fprintf(out, " sf_ack:%u sf_bits:0x%x c:%d used:%d\n", + sf->sf_ack, sf->sf_bits, + sf->sf_cur, sf->sf_used); + + for(i=0; i<SACK_FILTER_BLOCKS; i++) { + if (sack_blk_used(sf, i)) { + fprintf(out, "Entry:%d start:%u end:%u\n", i, + sf->sf_blks[i].start, + sf->sf_blks[i].end); + } + } +} +#endif + +#ifndef _KERNEL static #endif int -sack_filter_blks(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_seq th_ack) +sack_filter_blks(struct sack_filter *sf, struct sackblk *in, int numblks, + tcp_seq th_ack) { int32_t i, ret; if (numblks > TCP_MAX_SACK) { +#ifdef _KERNEL panic("sf:%p sb:%p Impossible number of sack blocks %d > 4\n", sf, in, numblks); +#endif return(numblks); } +#ifndef _KERNEL + if ((sf->sf_used > 1) && (no_collapse == 0)) + sack_board_collapse(sf); + +#else + if (sf->sf_used > 1) + sack_board_collapse(sf); +#endif if ((sf->sf_used == 0) && numblks) { /* * We are brand new add the blocks in * reverse order. Note we can see more * than one in new, since ack's could be lost. */ + int cnt_added = 0; + sf->sf_ack = th_ack; for(i=(numblks-1), sf->sf_cur=0; i >= 0; i--) { memcpy(&sf->sf_blks[sf->sf_cur], &in[i], sizeof(struct sackblk)); @@ -489,6 +527,7 @@ sack_filter_blks(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_se sf->sf_cur++; sf->sf_cur %= SACK_FILTER_BLOCKS; sf->sf_used++; + cnt_added++; #ifndef _KERNEL if (sf->sf_used > highest_used) highest_used = sf->sf_used; @@ -496,7 +535,8 @@ sack_filter_blks(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_se } if (sf->sf_cur) sf->sf_cur--; - return(numblks); + + return (cnt_added); } if (SEQ_GT(th_ack, sf->sf_ack)) { sack_filter_prune(sf, th_ack); @@ -509,51 +549,82 @@ sack_filter_blks(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_se } } else ret = 0; -#ifndef _KERNEL - if ((sf->sf_used > 1) && (no_collapse == 0)) - sack_board_collapse(sf); - -#else - if (sf->sf_used > 1) - sack_board_collapse(sf); - -#endif return (ret); } -#ifndef _KERNEL -uint64_t saved=0; -uint64_t tot_sack_blks=0; - -static void -sack_filter_dump(FILE *out, struct sack_filter *sf) +void +sack_filter_reject(struct sack_filter *sf, struct sackblk *in) { + /* + * Given a specified block (that had made + * it past the sack filter). Reject that + * block triming it off any sack-filter block + * that has it. Usually because the block was + * too small and did not cover a whole send. + * + * This function will only "undo" sack-blocks + * that are fresh and touch the edges of + * blocks in our filter. + */ int i; - fprintf(out, " sf_ack:%u sf_bits:0x%x c:%d used:%d\n", - sf->sf_ack, sf->sf_bits, - sf->sf_cur, sf->sf_used); for(i=0; i<SACK_FILTER_BLOCKS; i++) { - if (sack_blk_used(sf, i)) { - fprintf(out, "Entry:%d start:%u end:%u\n", i, - sf->sf_blks[i].start, - sf->sf_blks[i].end); + if (sack_blk_used(sf, i) == 0) + continue; + /* + * Now given the sack-filter block does it touch + * with one of the ends + */ + if (sf->sf_blks[i].end == in->end) { + /* The end moves back to start */ + if (SEQ_GT(in->start, sf->sf_blks[i].start)) + /* in-blk |----| */ + /* sf-blk |---------| */ + sf->sf_blks[i].end = in->start; + else { + /* It consumes this block */ + /* in-blk |---------| */ + /* sf-blk |------| */ + /* <or> */ + /* sf-blk |---------| */ + sf->sf_bits = sack_blk_clr(sf, i); + sf->sf_used--; + } + continue; + } + if (sf->sf_blks[i].start == in->start) { + if (SEQ_LT(in->end, sf->sf_blks[i].end)) { + /* in-blk |----| */ + /* sf-blk |---------| */ + sf->sf_blks[i].start = in->end; + } else { + /* It consumes this block */ + /* in-blk |----------| */ + /* sf-blk |-------| */ + /* <or> */ + /* sf-blk |----------| */ + sf->sf_bits = sack_blk_clr(sf, i); + sf->sf_used--; + } + continue; } } } +#ifndef _KERNEL + int main(int argc, char **argv) { char buffer[512]; struct sackblk blks[TCP_MAX_SACK]; FILE *err; - tcp_seq th_ack, snd_una; + tcp_seq th_ack, snd_una, snd_max = 0; struct sack_filter sf; int32_t numblks,i; int snd_una_set=0; double a, b, c; - int invalid_sack_print = 0; + int invalid_sack_print = 0; uint32_t chg_remembered=0; uint32_t sack_chg=0; char line_buf[10][256]; @@ -604,7 +675,11 @@ main(int argc, char **argv) line_buf_at++; if (strncmp(buffer, "QUIT", 4) == 0) { break; - } else if (strncmp(buffer, "DONE", 4) == 0) { + } else if (strncmp(buffer, "DUMP", 4) == 0) { + sack_filter_dump(out, &sf); + } else if (strncmp(buffer, "MAX:", 4) == 0) { + snd_max = strtoul(&buffer[4], NULL, 0); + } else if (strncmp(buffer, "COMMIT", 6) == 0) { int nn, ii; if (numblks) { uint32_t szof, tot_chg; @@ -660,6 +735,7 @@ main(int argc, char **argv) char *end=NULL; uint32_t start; uint32_t endv; + start = strtoul(&buffer[5], &end, 0); if (end) { endv = strtoul(&end[1], NULL, 0); @@ -667,6 +743,8 @@ main(int argc, char **argv) fprintf(out, "--Sack invalid skip 0 start:%u : ??\n", start); continue; } + if (SEQ_GT(endv, snd_max)) + snd_max = endv; if (SEQ_LT(endv, start)) { fprintf(out, "--Sack invalid skip 1 endv:%u < start:%u\n", endv, start); continue; @@ -678,6 +756,28 @@ main(int argc, char **argv) blks[numblks].start = start; blks[numblks].end = endv; numblks++; + } else if (strncmp(buffer, "REJ:n:n", 4) == 0) { + struct sackblk in; + char *end=NULL; + + in.start = strtoul(&buffer[4], &end, 0); + if (end) { + in.end = strtoul(&end[1], NULL, 0); + sack_filter_reject(&sf, &in); + } else + fprintf(out, "Invalid input END:A:B\n"); + } else if (strncmp(buffer, "HELP", 4) == 0) { + fprintf(out, "You can input:\n"); + fprintf(out, "SACK:S:E -- to define a sack block\n"); + fprintf(out, "RXT -- to clear the filter without changing the remembered\n"); + fprintf(out, "EXIT -- To clear the sack filter and start all fresh\n"); + fprintf(out, "ACK:N -- To advance the cum-ack to N\n"); + fprintf(out, "MAX:N -- To set send-max to N\n"); + fprintf(out, "COMMIT -- To apply the sack you built to the filter and dump the filter\n"); + fprintf(out, "DUMP -- To display the current contents of the sack filter\n"); + fprintf(out, "QUIT -- To exit this program\n"); + } else { + fprintf(out, "Command %s unknown\n", buffer); } memset(buffer, 0, sizeof(buffer)); } |