diff options
author | Matt Smith <mgsmith@netgate.com> | 2015-11-18 10:28:52 -0600 |
---|---|---|
committer | Matt Smith <mgsmith@netgate.com> | 2015-11-18 10:28:52 -0600 |
commit | a5762bff1263841e6caf002bab333ea7d9279c51 (patch) | |
tree | 1b3b240c4f5fe9a92fbb2e47962cf7caa3cfd162 | |
parent | c35d9192929a399908c9ba97f3f08b9b72c87fc5 (diff) | |
download | FreeBSD-src-a5762bff1263841e6caf002bab333ea7d9279c51.zip FreeBSD-src-a5762bff1263841e6caf002bab333ea7d9279c51.tar.gz |
Importing pfSense patch altq_codel.diff
-rw-r--r-- | sbin/pfctl/parse.y | 128 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_altq.c | 43 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 1 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_qstats.c | 36 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/conf/options | 1 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq.h | 3 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_cbq.c | 4 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_cbq.h | 3 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_classq.h | 6 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_codel.c | 434 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_codel.h | 87 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_fairq.c | 43 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_fairq.h | 10 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_hfsc.c | 35 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_hfsc.h | 10 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_priq.c | 40 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_priq.h | 11 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_rmclass.c | 29 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_rmclass.h | 9 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_subr.c | 20 | ||||
-rw-r--r-- | sys/contrib/altq/altq/altq_var.h | 5 | ||||
-rw-r--r-- | sys/netpfil/pf/pf_altq.h | 7 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 1 |
24 files changed, 922 insertions, 45 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 99189b7..ad4153a 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <altq/altq_priq.h> #include <altq/altq_hfsc.h> #include <altq/altq_fairq.h> +#include <altq/altq_codel.h> #include <stdio.h> #include <unistd.h> @@ -315,6 +316,7 @@ struct pool_opts { struct node_hfsc_opts hfsc_opts; struct node_fairq_opts fairq_opts; +struct codel_opts codel_opts; struct node_state_opt *keep_state_defaults = NULL; int disallow_table(struct node_host *, const char *); @@ -439,6 +441,7 @@ typedef struct { struct pool_opts pool_opts; struct node_hfsc_opts hfsc_opts; struct node_fairq_opts fairq_opts; + struct codel_opts codel_opts; } v; int lineno; } YYSTYPE; @@ -463,8 +466,8 @@ int parseport(char *, struct range *r, int); %token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID %token ANTISPOOF FOR INCLUDE %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY -%token ALTQ CBQ PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT -%token QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE +%token ALTQ CBQ PRIQ HFSC FAIRQ CODEL BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT +%token QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE INTERVAL %token DNPIPE DNQUEUE %token LOAD RULESET_OPTIMIZATION %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE @@ -515,6 +518,7 @@ int parseport(char *, struct range *r, int); %type <v.number> priqflags_list priqflags_item %type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts %type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts +%type <v.codel_opts> codelopts_list codelopts_item codel_opts %type <v.queue_bwspec> bandwidth %type <v.filter_opts> filter_opts filter_opt filter_opts_l %type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l @@ -1491,7 +1495,7 @@ altqif : ALTQ interface queue_opts QUEUE qassign { a.scheduler = $3.scheduler.qtype; a.qlimit = $3.qlimit; a.tbrsize = $3.tbrsize; - if ($5 == NULL) { + if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) { yyerror("no child queues specified"); YYERROR; } @@ -1701,6 +1705,15 @@ scheduler : CBQ { $$.qtype = ALTQT_FAIRQ; $$.data.fairq_opts = $3; } + | CODEL { + $$.qtype = ALTQT_CODEL; + bzero(&$$.data.codel_opts, + sizeof(struct codel_opts)); + } + | CODEL '(' codel_opts ')' { + $$.qtype = ALTQT_CODEL; + $$.data.codel_opts = $3; + } ; cbqflags_list : cbqflags_item { $$ |= $1; } @@ -1718,6 +1731,8 @@ cbqflags_item : STRING { $$ = CBQCLF_RED|CBQCLF_ECN; else if (!strcmp($1, "rio")) $$ = CBQCLF_RIO; + else if (!strcmp($1, "codel")) + $$ = CBQCLF_CODEL; else { yyerror("unknown cbq flag \"%s\"", $1); free($1); @@ -1740,6 +1755,8 @@ priqflags_item : STRING { $$ = PRCF_RED|PRCF_ECN; else if (!strcmp($1, "rio")) $$ = PRCF_RIO; + else if (!strcmp($1, "codel")) + $$ = PRCF_CODEL; else { yyerror("unknown priq flag \"%s\"", $1); free($1); @@ -1840,6 +1857,8 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.flags |= HFCF_RED|HFCF_ECN; else if (!strcmp($1, "rio")) hfsc_opts.flags |= HFCF_RIO; + else if (!strcmp($1, "codel")) + hfsc_opts.flags |= HFCF_CODEL; else { yyerror("unknown hfsc flag \"%s\"", $1); free($1); @@ -1895,6 +1914,8 @@ fairqopts_item : LINKSHARE bandwidth { fairq_opts.flags |= FARF_RED|FARF_ECN; else if (!strcmp($1, "rio")) fairq_opts.flags |= FARF_RIO; + else if (!strcmp($1, "codel")) + fairq_opts.flags |= FARF_CODEL; else { yyerror("unknown fairq flag \"%s\"", $1); free($1); @@ -1904,6 +1925,45 @@ fairqopts_item : LINKSHARE bandwidth { } ; +codel_opts : { + bzero(&codel_opts, + sizeof(struct codel_opts)); + } + codelopts_list { + $$ = codel_opts; + } + ; + +codelopts_list : codelopts_item + | codelopts_list comma codelopts_item + ; + +codelopts_item : QLIMIT number { + if (codel_opts.target) { + yyerror("target already specified"); + YYERROR; + } + codel_opts.target = $2; + } + | INTERVAL number { + if (codel_opts.interval) { + yyerror("interval already specified"); + YYERROR; + } + codel_opts.interval = $2; + } + | STRING { + if (!strcmp($1, "ecn")) + codel_opts.ecn = 1; + else { + yyerror("unknown codel option \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + qassign : /* empty */ { $$ = NULL; } | qassign_item { $$ = $1; } | '{' optnl qassign_list '}' { $$ = $3; } @@ -5051,7 +5111,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces, if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); return (0); } @@ -5113,37 +5174,40 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces, errs++; } - LOOP_THROUGH(struct node_queue, queue, nqueues, - n = calloc(1, sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_altq: calloc"); - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC /* || - pa.scheduler == ALTQT_FAIRQ */) - if (strlcpy(n->parent, qname, - sizeof(n->parent)) >= - sizeof(n->parent)) + if (nqueues) { + LOOP_THROUGH(struct node_queue, queue, nqueues, + n = calloc(1, sizeof(struct node_queue)); + if (n == NULL) + err(1, "expand_altq: calloc"); + if (pa.scheduler == ALTQT_CBQ || + pa.scheduler == ALTQT_HFSC /* || + pa.scheduler == ALTQT_FAIRQ */) + if (strlcpy(n->parent, qname, + sizeof(n->parent)) >= + sizeof(n->parent)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(n->queue, queue->queue, + sizeof(n->queue)) >= sizeof(n->queue)) errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->queue, queue->queue, - sizeof(n->queue)) >= sizeof(n->queue)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->ifname, interface->ifname, - sizeof(n->ifname)) >= sizeof(n->ifname)) - errx(1, "expand_altq: strlcpy"); - n->scheduler = pa.scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - ); + if (strlcpy(n->ifname, interface->ifname, + sizeof(n->ifname)) >= sizeof(n->ifname)) + errx(1, "expand_altq: strlcpy"); + n->scheduler = pa.scheduler; + n->next = NULL; + n->tail = n; + if (queues == NULL) + queues = n; + else { + queues->tail->next = n; + queues->tail = n; + } + ); + } } ); FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); return (errs); } @@ -5557,6 +5621,7 @@ lookup(char *s) { "buckets", BUCKETS}, { "cbq", CBQ}, { "code", CODE}, + { "codelq", CODEL}, { "crop", FRAGCROP}, { "debug", DEBUG}, { "divert-reply", DIVERTREPLY}, @@ -5591,6 +5656,7 @@ lookup(char *s) { "include", INCLUDE}, { "inet", INET}, { "inet6", INET6}, + { "interval", INTERVAL}, { "keep", KEEP}, { "label", LABEL}, { "limit", LIMIT}, diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c index 5810db2..8656113 100644 --- a/sbin/pfctl/pfctl_altq.c +++ b/sbin/pfctl/pfctl_altq.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <altq/altq_priq.h> #include <altq/altq_hfsc.h> #include <altq/altq_fairq.h> +#include <altq/altq_codel.h> #include "pfctl_parser.h" #include "pfctl.h" @@ -75,6 +76,9 @@ static int print_fairq_opts(const struct pf_altq *, const struct node_queue_opt *); static int check_commit_fairq(int, int, struct pf_altq *); +static int print_codel_opts(const struct pf_altq *, + const struct node_queue_opt *); + static void gsc_add_sc(struct gen_sc *, struct service_curve *); static int is_gsc_under_sc(struct gen_sc *, struct service_curve *); @@ -186,6 +190,10 @@ print_altq(const struct pf_altq *a, unsigned int level, if (!print_fairq_opts(a, qopts)) printf("fairq "); break; + case ALTQT_CODEL: + if (!print_codel_opts(a, qopts)) + printf("codel "); + break; } if (bw != NULL && bw->bw_percent > 0) { @@ -588,6 +596,8 @@ print_cbq_opts(const struct pf_altq *a) printf(" ecn"); if (opts->flags & CBQCLF_RIO) printf(" rio"); + if (opts->flags & CBQCLF_CODEL) + printf(" codel"); if (opts->flags & CBQCLF_CLEARDSCP) printf(" cleardscp"); if (opts->flags & CBQCLF_FLOWVALVE) @@ -675,6 +685,8 @@ print_priq_opts(const struct pf_altq *a) printf(" ecn"); if (opts->flags & PRCF_RIO) printf(" rio"); + if (opts->flags & PRCF_CODEL) + printf(" codel"); if (opts->flags & PRCF_CLEARDSCP) printf(" cleardscp"); if (opts->flags & PRCF_DEFAULTCLASS) @@ -1000,6 +1012,8 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) printf(" ecn"); if (opts->flags & HFCF_RIO) printf(" rio"); + if (opts->flags & HFCF_CODEL) + printf(" codel"); if (opts->flags & HFCF_CLEARDSCP) printf(" cleardscp"); if (opts->flags & HFCF_DEFAULTCLASS) @@ -1022,6 +1036,28 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) } static int +print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) +{ + const struct codel_opts *opts; + + opts = &a->pq_u.codel_opts; + if (opts->target || opts->interval || opts->ecn) { + printf("codel("); + if (opts->target) + printf(" target %d", opts->target); + if (opts->interval) + printf(" interval %d", opts->interval); + if (opts->ecn) + printf("ecn"); + printf(") "); + + return (1); + } + + return (0); +} + +static int print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) { const struct fairq_opts *opts; @@ -1043,6 +1079,8 @@ print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) printf(" ecn"); if (opts->flags & FARF_RIO) printf(" rio"); + if (opts->flags & FARF_CODEL) + printf(" codel"); if (opts->flags & FARF_CLEARDSCP) printf(" cleardscp"); if (opts->flags & FARF_DEFAULTCLASS) @@ -1394,6 +1432,11 @@ eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, opts->data.fairq_opts.linkshare.d; } break; + case ALTQT_CODEL: + pa->pq_u.codel_opts.target = opts->data.codel_opts.target; + pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval; + pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn; + break; default: warnx("eval_queue_opts: unknown scheduler type %u", opts->qtype); diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index 8a4e84e..74a6a25 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -169,6 +169,7 @@ struct node_queue_opt { union { struct cbq_opts cbq_opts; struct priq_opts priq_opts; + struct codel_opts codel_opts; struct node_hfsc_opts hfsc_opts; struct node_fairq_opts fairq_opts; } data; diff --git a/sbin/pfctl/pfctl_qstats.c b/sbin/pfctl/pfctl_qstats.c index 4087d71..5530572 100644 --- a/sbin/pfctl/pfctl_qstats.c +++ b/sbin/pfctl/pfctl_qstats.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <altq/altq_priq.h> #include <altq/altq_hfsc.h> #include <altq/altq_fairq.h> +#include <altq/altq_codel.h> #include "pfctl.h" #include "pfctl_parser.h" @@ -48,6 +49,7 @@ union class_stats { struct priq_classstats priq_stats; struct hfsc_classstats hfsc_stats; struct fairq_classstats fairq_stats; + struct codel_ifstats codel_stats; }; #define AVGN_MAX 8 @@ -78,6 +80,7 @@ void pfctl_print_altq_node(int, const struct pf_altq_node *, unsigned, int); void print_cbqstats(struct queue_stats); void print_priqstats(struct queue_stats); +void print_codelstats(struct queue_stats); void print_hfscstats(struct queue_stats); void print_fairqstats(struct queue_stats); void pfctl_free_altq_node(struct pf_altq_node *); @@ -165,7 +168,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) return (-1); } #ifdef __FreeBSD__ - if (pa.altq.qid > 0 && + if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) && !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { #else if (pa.altq.qid > 0) { @@ -303,7 +306,7 @@ pfctl_print_altq_node(int dev, const struct pf_altq_node *node, void pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) { - if (a->altq.qid == 0) + if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL) return; #ifdef __FreeBSD__ @@ -323,6 +326,9 @@ pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) case ALTQT_FAIRQ: print_fairqstats(a->qstats); break; + case ALTQT_CODEL: + print_codelstats(a->qstats); + break; } } @@ -368,6 +374,26 @@ print_priqstats(struct queue_stats cur) } void +print_codelstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets, + (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes, + (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets + cur.data.codel_stats.stats.drop_cnt.packets, + (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes + cur.data.codel_stats.stats.drop_cnt.bytes); + printf(" [ qlength: %3d/%3d ]\n", + cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void print_hfscstats(struct queue_stats cur) { printf(" [ pkts: %10llu bytes: %10llu " @@ -428,7 +454,7 @@ update_avg(struct pf_altq_node *a) u_int64_t b, p; int n; - if (a->altq.qid == 0) + if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL) return; qs = &a->qstats; @@ -451,6 +477,10 @@ update_avg(struct pf_altq_node *a) b = qs->data.fairq_stats.xmit_cnt.bytes; p = qs->data.fairq_stats.xmit_cnt.packets; break; + case ALTQT_CODEL: + b = qs->data.codel_stats.cl_xmitcnt.bytes; + p = qs->data.codel_stats.cl_xmitcnt.packets; + break; default: b = 0; p = 0; diff --git a/sys/conf/files b/sys/conf/files index c3bb44f..aed9fff 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -249,6 +249,7 @@ compat/freebsd32/freebsd32_sysent.c optional compat_freebsd32 contrib/altq/altq/altq_cbq.c optional altq contrib/altq/altq/altq_cdnr.c optional altq contrib/altq/altq/altq_hfsc.c optional altq +contrib/altq/altq/altq_codel.c optional altq contrib/altq/altq/altq_fairq.c optional altq contrib/altq/altq/altq_priq.c optional altq contrib/altq/altq/altq_red.c optional altq diff --git a/sys/conf/options b/sys/conf/options index 4e818f1..bb43d6a 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -389,6 +389,7 @@ ALTQ_NOPCC opt_altq.h ALTQ_PRIQ opt_altq.h ALTQ_RED opt_altq.h ALTQ_RIO opt_altq.h +ALTQ_CODEL opt_altq.h BOOTP opt_bootp.h BOOTP_BLOCKSIZE opt_bootp.h BOOTP_COMPAT opt_bootp.h diff --git a/sys/contrib/altq/altq/altq.h b/sys/contrib/altq/altq/altq.h index 6200ac5..26d6cb7 100644 --- a/sys/contrib/altq/altq/altq.h +++ b/sys/contrib/altq/altq/altq.h @@ -64,7 +64,8 @@ #define ALTQT_PRIQ 11 /* priority queue */ #define ALTQT_JOBS 12 /* JoBS */ #define ALTQT_FAIRQ 13 /* fairq */ -#define ALTQT_MAX 14 /* should be max discipline type + 1 */ +#define ALTQT_CODEL 14 /* fairq */ +#define ALTQT_MAX 15 /* should be max discipline type + 1 */ #ifdef ALTQ3_COMPAT struct altqreq { diff --git a/sys/contrib/altq/altq/altq_cbq.c b/sys/contrib/altq/altq/altq_cbq.c index 3991d1d..13f9721 100644 --- a/sys/contrib/altq/altq/altq_cbq.c +++ b/sys/contrib/altq/altq/altq_cbq.c @@ -241,6 +241,10 @@ get_class_stats(class_stats_t *statsp, struct rm_class *cl) if (q_is_rio(cl->q_)) rio_getstats((rio_t *)cl->red_, &statsp->red[0]); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->q_)) + codel_getstats(cl->codel_, &statsp->codel); +#endif } int diff --git a/sys/contrib/altq/altq/altq_cbq.h b/sys/contrib/altq/altq/altq_cbq.h index 76096af..45509f0 100644 --- a/sys/contrib/altq/altq/altq_cbq.h +++ b/sys/contrib/altq/altq/altq_cbq.h @@ -37,6 +37,7 @@ #include <altq/altq_rmclass.h> #include <altq/altq_red.h> #include <altq/altq_rio.h> +#include <altq/altq_codel.h> #ifdef __cplusplus extern "C" { @@ -51,6 +52,7 @@ extern "C" { #define CBQCLF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */ #define CBQCLF_CLEARDSCP 0x0010 /* clear diffserv codepoint */ #define CBQCLF_BORROW 0x0020 /* borrow from parent */ +#define CBQCLF_CODEL 0x0040 /* use CODEL */ /* class flags only for root class */ #define CBQCLF_WRR 0x0100 /* weighted-round robin */ @@ -93,6 +95,7 @@ typedef struct _cbq_class_stats_ { /* red and rio related info */ int qtype; struct redstats red[3]; + struct codel_stats codel; } class_stats_t; #ifdef ALTQ3_COMPAT diff --git a/sys/contrib/altq/altq/altq_classq.h b/sys/contrib/altq/altq/altq_classq.h index dc5c646..8e4d1db 100644 --- a/sys/contrib/altq/altq/altq_classq.h +++ b/sys/contrib/altq/altq/altq_classq.h @@ -49,6 +49,7 @@ extern "C" { #define Q_RED 0x01 #define Q_RIO 0x02 #define Q_DROPTAIL 0x03 +#define Q_CODEL 0x04 #ifdef _KERNEL @@ -58,6 +59,7 @@ extern "C" { struct _class_queue_ { struct mbuf *tail_; /* Tail of packet queue */ int qlen_; /* Queue length (in number of packets) */ + int qsize_; /* Queue size (in number of bytes*) */ int qlim_; /* Queue limit (in number of packets*) */ int qtype_; /* Queue type */ }; @@ -67,11 +69,13 @@ typedef struct _class_queue_ class_queue_t; #define qtype(q) (q)->qtype_ /* Get queue type */ #define qlimit(q) (q)->qlim_ /* Max packets to be queued */ #define qlen(q) (q)->qlen_ /* Current queue length. */ +#define qsize(q) (q)->qsize_ /* Current queue size. */ #define qtail(q) (q)->tail_ /* Tail of the queue */ #define qhead(q) ((q)->tail_ ? (q)->tail_->m_nextpkt : NULL) #define qempty(q) ((q)->qlen_ == 0) /* Is the queue empty?? */ #define q_is_red(q) ((q)->qtype_ == Q_RED) /* Is the queue a red queue */ +#define q_is_codel(q) ((q)->qtype_ == Q_CODEL) /* Is the queue a codel queue */ #define q_is_rio(q) ((q)->qtype_ == Q_RIO) /* Is the queue a rio queue */ #define q_is_red_or_rio(q) ((q)->qtype_ == Q_RED || (q)->qtype_ == Q_RIO) @@ -100,6 +104,7 @@ _addq(class_queue_t *q, struct mbuf *m) m0->m_nextpkt = m; qtail(q) = m; qlen(q)++; + qsize(q) += m_pktlen(m); } static __inline struct mbuf * @@ -114,6 +119,7 @@ _getq(class_queue_t *q) else qtail(q) = NULL; qlen(q)--; + qsize(q) -= m_pktlen(m0); m0->m_nextpkt = NULL; return (m0); } diff --git a/sys/contrib/altq/altq/altq_codel.c b/sys/contrib/altq/altq/altq_codel.c new file mode 100644 index 0000000..cf68207 --- /dev/null +++ b/sys/contrib/altq/altq/altq_codel.c @@ -0,0 +1,434 @@ +/* + * Codel - The Controlled-Delay Active Queue Management algorithm + * + * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com> + * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net> + * Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net> + * Copyright (C) 2012 Eric Dumazet <edumazet@google.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <netinet/in.h> + +#include <net/pfvar.h> + +#include <altq/altq.h> +#include <altq/altq_codel.h> + +static int codel_should_drop(struct codel *, class_queue_t *, + struct mbuf *, u_int64_t); +static void codel_Newton_step(struct codel_vars *); +static u_int64_t codel_control_law(u_int64_t t, u_int64_t, u_int32_t); + +#define codel_time_after(a, b) ((int64_t)(a) - (int64_t)(b) > 0) +#define codel_time_after_eq(a, b) ((int64_t)(a) - (int64_t)(b) >= 0) +#define codel_time_before(a, b) ((int64_t)(a) - (int64_t)(b) < 0) +#define codel_time_before_eq(a, b) ((int64_t)(a) - (int64_t)(b) <= 0) + +static int codel_request(struct ifaltq *, int, void *); + +static int codel_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *); +static struct mbuf *codel_dequeue(struct ifaltq *, int); + +int +codel_pfattach(struct pf_altq *a) +{ + struct ifnet *ifp; + int s, error; + + if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) + return (EINVAL); +#ifdef __NetBSD__ + s = splnet(); +#else + s = splimp(); +#endif + error = altq_attach(&ifp->if_snd, ALTQT_CODEL, a->altq_disc, + codel_enqueue, codel_dequeue, codel_request, NULL, NULL); + splx(s); + return (error); +} + +int +codel_add_altq(struct pf_altq *a) +{ + struct codel_if *cif; + struct ifnet *ifp; + struct codel_opts *opts; + + if ((ifp = ifunit(a->ifname)) == NULL) + return (EINVAL); + if (!ALTQ_IS_READY(&ifp->if_snd)) + return (ENODEV); + + opts = &a->pq_u.codel_opts; + + cif = malloc(sizeof(struct codel_if), M_DEVBUF, M_NOWAIT | M_ZERO); + if (cif == NULL) + return (ENOMEM); + cif->cif_bandwidth = a->ifbandwidth; + cif->cif_ifq = &ifp->if_snd; + + cif->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO); + if (cif->cl_q == NULL) { + free(cif, M_DEVBUF); + return (ENOMEM); + } + + if (a->qlimit == 0) + a->qlimit = 5; + qlimit(cif->cl_q) = a->qlimit; + qtype(cif->cl_q) = Q_CODEL; + qlen(cif->cl_q) = 0; + qsize(cif->cl_q) = 0; + + if (!opts->target) + opts->target = a->qlimit; + if (!opts->interval) + opts->interval = 100; + cif->codel.params.target = machclk_freq * opts->target / 1000; + cif->codel.params.interval = machclk_freq * opts->interval / 1000; + cif->codel.params.ecn = opts->ecn; + cif->codel.stats.maxpacket = 256; + + cif->cl_stats.qlength = qlen(cif->cl_q); + cif->cl_stats.qlimit = qlimit(cif->cl_q); + + /* keep the state in pf_altq */ + a->altq_disc = cif; + + return (0); +} + +int +codel_remove_altq(struct pf_altq *a) +{ + struct codel_if *cif; + + if ((cif = a->altq_disc) == NULL) + return (EINVAL); + a->altq_disc = NULL; + + if (cif->cl_q) + free(cif->cl_q, M_DEVBUF); + free(cif, M_DEVBUF); + return (0); +} + +int +codel_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) +{ + struct codel_if *cif; + struct codel_ifstats stats; + int error = 0; + + if ((cif = altq_lookup(a->ifname, ALTQT_CODEL)) == NULL) + return (EBADF); + + if (*nbytes < sizeof(stats)) + return (EINVAL); + + stats = cif->cl_stats; + stats.stats = cif->codel.stats; + + if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0) + return (error); + *nbytes = sizeof(stats); + return (0); +} + +static int +codel_request(struct ifaltq *ifq, int req, void *arg) +{ + struct codel_if *cif = (struct codel_if *)ifq->altq_disc; + struct mbuf *m; + + IFQ_LOCK_ASSERT(ifq); + + switch (req) { + case ALTRQ_PURGE: + if (!ALTQ_IS_ENABLED(cif->cif_ifq)) + break; + + if (qempty(cif->cl_q)) + break; + + while ((m = _getq(cif->cl_q)) != NULL) { + PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m)); + m_freem(m); + IFQ_DEC_LEN(cif->cif_ifq); + } + cif->cif_ifq->ifq_len = 0; + break; + } + return (0); +} + +static int +codel_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr) +{ + + struct codel_if *cif = (struct codel_if *) ifq->altq_disc; + + IFQ_LOCK_ASSERT(ifq); + + /* grab class set by classifier */ + if ((m->m_flags & M_PKTHDR) == 0) { + /* should not happen */ + printf("altq: packet for %s does not have pkthdr\n", + ifq->altq_ifp->if_xname); + m_freem(m); + PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m)); + return (ENOBUFS); + } + + if (codel_addq(&cif->codel, cif->cl_q, m)) { + PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m)); + return (ENOBUFS); + } + IFQ_INC_LEN(ifq); + + return (0); +} + +static struct mbuf * +codel_dequeue(struct ifaltq *ifq, int op) +{ + struct codel_if *cif = (struct codel_if *)ifq->altq_disc; + struct mbuf *m; + + IFQ_LOCK_ASSERT(ifq); + + if (IFQ_IS_EMPTY(ifq)) + return (NULL); + + if (op == ALTDQ_POLL) + return (qhead(cif->cl_q)); + + + m = codel_getq(&cif->codel, cif->cl_q); + if (m != NULL) { + IFQ_DEC_LEN(ifq); + PKTCNTR_ADD(&cif->cl_stats.cl_xmitcnt, m_pktlen(m)); + return (m); + } + + return (NULL); +} + +struct codel * +codel_alloc(int target, int interval, int ecn) +{ + struct codel *c; + + c = malloc(sizeof(*c), M_DEVBUF, M_NOWAIT|M_ZERO); + + c->params.target = machclk_freq * target / 1000; + c->params.interval = machclk_freq * interval / 1000; + c->params.ecn = ecn; + c->stats.maxpacket = 256; + + return (c); +} + +void +codel_destroy(struct codel *c) +{ + free(c, M_DEVBUF); +} + +int +codel_addq(struct codel *c, class_queue_t *q, struct mbuf *m) +{ + if (qlen(q) < qlimit(q)) { + m->m_pkthdr.enqueue_time = read_machclk(); + _addq(q, m); + return (0); + } + c->drop_overlimit++; + m_freem(m); + return (-1); +} + +static int +codel_should_drop(struct codel *c, class_queue_t *q, struct mbuf *m, + u_int64_t now) +{ + if (m == NULL) { + c->vars.first_above_time = 0; + return (0); + } + + c->vars.ldelay = now - m->m_pkthdr.enqueue_time; + c->stats.maxpacket = MAX(c->stats.maxpacket, m_pktlen(m)); + + if (codel_time_before(c->vars.ldelay, c->params.target) || + qsize(q) <= c->stats.maxpacket) { + /* went below - stay below for at least interval */ + c->vars.first_above_time = 0; + return (0); + } + if (c->vars.first_above_time == 0) { + /* just went above from below. If we stay above + * for at least interval we'll say it's ok to drop + */ + c->vars.first_above_time = now + c->params.interval; + return (0); + } + if (codel_time_after(now, c->vars.first_above_time)) + return (1); + return (0); +} + +/* + * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots + * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2) + * + * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32 + */ +static void codel_Newton_step(struct codel_vars *vars) +{ +#define REC_INV_SQRT_BITS (8 * sizeof(u_int16_t)) /* or sizeof_in_bits(rec_inv_sqrt) */ +/* needed shift to get a Q0.32 number from rec_inv_sqrt */ +#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS) + + u_int32_t invsqrt = ((u_int32_t)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT; + u_int32_t invsqrt2 = ((u_int64_t)invsqrt * invsqrt) >> 32; + u_int64_t val = (3LL << 32) - ((u_int64_t)vars->count * invsqrt2); + + val >>= 2; /* avoid overflow in following multiply */ + val = (val * invsqrt) >> (32 - 2 + 1); + + vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT; +} + +static u_int64_t +codel_control_law(u_int64_t t, u_int64_t interval, u_int32_t rec_inv_sqrt) +{ + return (t + (u_int32_t)(((u_int64_t)interval * + (rec_inv_sqrt << REC_INV_SQRT_SHIFT)) >> 32)); +} + +struct mbuf * +codel_getq(struct codel *c, class_queue_t *q) +{ + struct mbuf *m; + u_int64_t now; + int drop; + + if ((m = _getq(q)) == NULL) { + c->vars.dropping = 0; + return (m); + } + + now = read_machclk(); + drop = codel_should_drop(c, q, m, now); + if (c->vars.dropping) { + if (!drop) { + /* sojourn time below target - leave dropping state */ + c->vars.dropping = 0; + } else if (codel_time_after_eq(now, c->vars.drop_next)) { + /* It's time for the next drop. Drop the current + * packet and dequeue the next. The dequeue might + * take us out of dropping state. + * If not, schedule the next drop. + * A large backlog might result in drop rates so high + * that the next drop should happen now, + * hence the while loop. + */ + while (c->vars.dropping && + codel_time_after_eq(now, c->vars.drop_next)) { + c->vars.count++; /* don't care of possible wrap + * since there is no more + * divide */ + codel_Newton_step(&c->vars); + /* TODO ECN */ + PKTCNTR_ADD(&c->stats.drop_cnt, m_pktlen(m)); + m_freem(m); + m = _getq(q); + if (!codel_should_drop(c, q, m, now)) + /* leave dropping state */ + c->vars.dropping = 0; + else + /* and schedule the next drop */ + c->vars.drop_next = + codel_control_law(c->vars.drop_next, + c->params.interval, + c->vars.rec_inv_sqrt); + } + } + } else if (drop) { + /* TODO ECN */ + PKTCNTR_ADD(&c->stats.drop_cnt, m_pktlen(m)); + m_freem(m); + + m = _getq(q); + drop = codel_should_drop(c, q, m, now); + + c->vars.dropping = 1; + /* if min went above target close to when we last went below it + * assume that the drop rate that controlled the queue on the + * last cycle is a good starting point to control it now. + */ + if (codel_time_before(now - c->vars.drop_next, + 16 * c->params.interval)) { + c->vars.count = (c->vars.count - c->vars.lastcount) | 1; + /* we dont care if rec_inv_sqrt approximation + * is not very precise : + * Next Newton steps will correct it quadratically. + */ + codel_Newton_step(&c->vars); + } else { + c->vars.count = 1; + c->vars.rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT; + } + c->vars.lastcount = c->vars.count; + c->vars.drop_next = codel_control_law(now, c->params.interval, + c->vars.rec_inv_sqrt); + } + + return m; +} + +void +codel_getstats(struct codel *c, struct codel_stats *s) +{ + *s = c->stats; +} diff --git a/sys/contrib/altq/altq/altq_codel.h b/sys/contrib/altq/altq/altq_codel.h new file mode 100644 index 0000000..9413ae1 --- /dev/null +++ b/sys/contrib/altq/altq/altq_codel.h @@ -0,0 +1,87 @@ +#ifndef _ALTQ_ALTQ_CODEL_H_ +#define _ALTQ_ALTQ_CODEL_H_ + +struct codel_stats { + u_int32_t maxpacket; + struct pktcntr drop_cnt; + u_int marked_packets; +}; + +struct codel_ifstats { + u_int qlength; + u_int qlimit; + struct codel_stats stats; + struct pktcntr cl_xmitcnt; /* transmitted packet counter */ + struct pktcntr cl_dropcnt; /* dropped packet counter */ +}; + +#ifdef _KERNEL +#include <altq/altq_classq.h> + +/** + * struct codel_params - contains codel parameters + * <at> target: target queue size (in time units) + * <at> interval: width of moving time window + * <at> ecn: is Explicit Congestion Notification enabled + */ +struct codel_params { + u_int64_t target; + u_int64_t interval; + int ecn; +}; + +/** + * struct codel_vars - contains codel variables + * <at> count: how many drops we've done since the last time we + * entered dropping state + * <at> lastcount: count at entry to dropping state + * <at> dropping: set to true if in dropping state + * <at> rec_inv_sqrt: reciprocal value of sqrt(count) >> 1 + * <at> first_above_time: when we went (or will go) continuously above target + * for interval + * <at> drop_next: time to drop next packet, or when we dropped last + * <at> ldelay: sojourn time of last dequeued packet + */ +struct codel_vars { + u_int32_t count; + u_int32_t lastcount; + int dropping; + u_int16_t rec_inv_sqrt; + u_int64_t first_above_time; + u_int64_t drop_next; + u_int64_t ldelay; +}; + +struct codel { + struct codel_params params; + struct codel_vars vars; + struct codel_stats stats; + u_int32_t drop_overlimit; +}; + +/* + * codel interface state + */ +struct codel_if { + struct codel_if *cif_next; /* interface state list */ + struct ifaltq *cif_ifq; /* backpointer to ifaltq */ + u_int cif_bandwidth; /* link bandwidth in bps */ + + class_queue_t *cl_q; /* class queue structure */ + struct codel codel; + + /* statistics */ + struct codel_ifstats cl_stats; +}; + +struct codel; + +struct codel *codel_alloc(int, int, int); +void codel_destroy(struct codel *); +int codel_addq(struct codel *, class_queue_t *, struct mbuf *); +struct mbuf *codel_getq(struct codel *, class_queue_t *); +void codel_getstats(struct codel *, struct codel_stats *); + +#endif + +#endif /* _ALTQ_ALTQ_CODEL_H_ */ diff --git a/sys/contrib/altq/altq/altq_fairq.c b/sys/contrib/altq/altq/altq_fairq.c index 2267bfd..a32f1c8 100644 --- a/sys/contrib/altq/altq/altq_fairq.c +++ b/sys/contrib/altq/altq/altq_fairq.c @@ -156,10 +156,7 @@ fairq_add_altq(struct pf_altq *a) MALLOC(pif, struct fairq_if *, sizeof(struct fairq_if), - M_DEVBUF, M_WAITOK); - if (pif == NULL) - return (ENOMEM); - bzero(pif, sizeof(struct fairq_if)); + M_DEVBUF, M_WAITOK|M_ZERO); pif->pif_bandwidth = a->ifbandwidth; pif->pif_maxpri = -1; pif->pif_ifq = &ifp->if_snd; @@ -318,6 +315,14 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit, return (NULL); } #endif +#ifndef ALTQ_CODEL + if (flags & FARF_CODEL) { +#ifdef ALTQ_DEBUG + printf("fairq_class_create: CODEL not configured for FAIRQ!\n"); +#endif + return (NULL); + } +#endif if (nbuckets == 0) nbuckets = 256; if (nbuckets > FAIRQ_MAX_BUCKETS) @@ -342,6 +347,10 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit, if (cl->cl_qtype == Q_RED) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (cl->cl_qtype == Q_CODEL) + codel_destroy(cl->cl_codel); +#endif } else { MALLOC(cl, struct fairq_class *, sizeof(struct fairq_class), M_DEVBUF, M_WAITOK); @@ -415,6 +424,12 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit, } } #endif /* ALTQ_RED */ +#ifdef ALTQ_CODEL + if (flags & FARF_CODEL) { + cl->cl_codel = codel_alloc(5, 100, 0); + cl->cl_qtype = Q_CODEL; + } +#endif return (cl); @@ -431,6 +446,10 @@ err_ret: if (cl->cl_qtype == Q_RED) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (cl->cl_qtype == Q_CODEL) + codel_destroy(cl->cl_codel); +#endif } if (cl != NULL) FREE(cl, M_DEVBUF); @@ -474,6 +493,10 @@ fairq_class_destroy(struct fairq_class *cl) if (cl->cl_qtype == Q_RED) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (cl->cl_qtype == Q_CODEL) + codel_destroy(cl->cl_codel); +#endif } FREE(cl->cl_buckets, M_DEVBUF); cl->cl_head = NULL; /* sanity */ @@ -671,6 +694,10 @@ fairq_addq(struct fairq_class *cl, struct mbuf *m, u_int32_t bucketid) if (cl->cl_qtype == Q_RED) return red_addq(cl->cl_red, &b->queue, m, cl->cl_pktattr); #endif +#ifdef ALTQ_CODEL + if (cl->cl_qtype == Q_CODEL) + return codel_addq(cl->cl_codel, &b->queue, m); +#endif if (qlen(&b->queue) >= qlimit(&b->queue)) { m_freem(m); return (-1); @@ -701,6 +728,10 @@ fairq_getq(struct fairq_class *cl, uint64_t cur_time) else if (cl->cl_qtype == Q_RED) m = red_getq(cl->cl_red, &b->queue); #endif +#ifdef ALTQ_CODEL + else if (cl->cl_qtype == Q_CODEL) + m = codel_getq(cl->cl_codel, &b->queue); +#endif else m = _getq(&b->queue); @@ -882,6 +913,10 @@ get_class_stats(struct fairq_classstats *sp, struct fairq_class *cl) if (cl->cl_qtype == Q_RIO) rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); #endif +#ifdef ALTQ_CODEL + if (cl->cl_qtype == Q_CODEL) + codel_getstats(cl->cl_codel, &sp->codel); +#endif } /* convert a class handle to the corresponding class pointer */ diff --git a/sys/contrib/altq/altq/altq_fairq.h b/sys/contrib/altq/altq/altq_fairq.h index e4675e0..f13513b 100644 --- a/sys/contrib/altq/altq/altq_fairq.h +++ b/sys/contrib/altq/altq/altq_fairq.h @@ -42,6 +42,7 @@ #include <altq/altq_red.h> #include <altq/altq_rio.h> #include <altq/altq_rmclass.h> +#include <altq/altq_codel.h> #define FAIRQ_MAX_BUCKETS 2048 /* maximum number of sorting buckets */ #define FAIRQ_MAXPRI RM_MAXPRIO @@ -52,6 +53,7 @@ #define FARF_RED 0x0001 /* use RED */ #define FARF_ECN 0x0002 /* use RED/ECN */ #define FARF_RIO 0x0004 /* use RIO */ +#define FARF_CODEL 0x0008 /* use CODEL */ #define FARF_CLEARDSCP 0x0010 /* clear diffserv codepoint */ #define FARF_DEFAULTCLASS 0x1000 /* default class */ @@ -76,6 +78,7 @@ struct fairq_classstats { /* red and rio related info */ int qtype; struct redstats red[3]; /* rio has 3 red stats */ + struct codel_stats codel; }; #ifdef _KERNEL @@ -97,7 +100,10 @@ struct fairq_class { fairq_bucket_t *cl_buckets; fairq_bucket_t *cl_head; /* head of circular bucket list */ fairq_bucket_t *cl_polled; - struct red *cl_red; /* RED state */ + union { + struct red *cl_red; /* RED state */ + struct codel *cl_codel; + } cl_aqm; u_int cl_hogs_m1; u_int cl_lssc_m1; u_int cl_bandwidth; @@ -117,6 +123,8 @@ struct fairq_class { struct pktcntr cl_xmitcnt; /* transmitted packet counter */ struct pktcntr cl_dropcnt; /* dropped packet counter */ }; +#define cl_red cl_aqm.cl_red +#define cl_codel cl_aqm.cl_codel /* * fairq interface state diff --git a/sys/contrib/altq/altq/altq_hfsc.c b/sys/contrib/altq/altq/altq_hfsc.c index 0363016..0ec0054 100644 --- a/sys/contrib/altq/altq/altq_hfsc.c +++ b/sys/contrib/altq/altq/altq_hfsc.c @@ -391,6 +391,14 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, return (NULL); } #endif +#ifndef ALTQ_CODEL + if (flags & HFCF_CODEL) { +#ifdef ALTQ_DEBUG + printf("hfsc_class_create: CODEL not configured for HFSC!\n"); +#endif + return (NULL); + } +#endif cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_NOWAIT | M_ZERO); if (cl == NULL) @@ -407,6 +415,7 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, qlimit(cl->cl_q) = qlimit; qtype(cl->cl_q) = Q_DROPTAIL; qlen(cl->cl_q) = 0; + qsize(cl->cl_q) = 0; cl->cl_flags = flags; #ifdef ALTQ_RED if (flags & (HFCF_RED|HFCF_RIO)) { @@ -451,6 +460,12 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, #endif } #endif /* ALTQ_RED */ +#ifdef ALTQ_CODEL + if (flags & HFCF_CODEL) { + cl->cl_codel = codel_alloc(5, 100, 0); + qtype(cl->cl_q) = Q_CODEL; + } +#endif if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) { cl->cl_rsc = malloc(sizeof(struct internal_sc), @@ -543,6 +558,10 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_destroy(cl->cl_codel); +#endif } if (cl->cl_fsc != NULL) free(cl->cl_fsc, M_DEVBUF); @@ -617,6 +636,10 @@ hfsc_class_destroy(struct hfsc_class *cl) if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_destroy(cl->cl_codel); +#endif } IFQ_LOCK(cl->cl_hif->hif_ifq); @@ -844,6 +867,10 @@ hfsc_addq(struct hfsc_class *cl, struct mbuf *m) if (q_is_red(cl->cl_q)) return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + return codel_addq(cl->cl_codel, cl->cl_q, m); +#endif if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { m_freem(m); return (-1); @@ -868,6 +895,10 @@ hfsc_getq(struct hfsc_class *cl) if (q_is_red(cl->cl_q)) return red_getq(cl->cl_red, cl->cl_q); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + return codel_getq(cl->cl_codel, cl->cl_q); +#endif return _getq(cl->cl_q); } @@ -1652,6 +1683,10 @@ get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl) if (q_is_rio(cl->cl_q)) rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_getstats(cl->cl_codel, &sp->codel); +#endif } /* convert a class handle to the corresponding class pointer */ diff --git a/sys/contrib/altq/altq/altq_hfsc.h b/sys/contrib/altq/altq/altq_hfsc.h index e5595cb..c8e9b13 100644 --- a/sys/contrib/altq/altq/altq_hfsc.h +++ b/sys/contrib/altq/altq/altq_hfsc.h @@ -36,6 +36,7 @@ #include <altq/altq_classq.h> #include <altq/altq_red.h> #include <altq/altq_rio.h> +#include <altq/altq_codel.h> #ifdef __cplusplus extern "C" { @@ -55,6 +56,7 @@ struct service_curve { #define HFCF_RED 0x0001 /* use RED */ #define HFCF_ECN 0x0002 /* use RED/ECN */ #define HFCF_RIO 0x0004 /* use RIO */ +#define HFCF_CODEL 0x0008 /* use CODEL */ #define HFCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */ #define HFCF_DEFAULTCLASS 0x1000 /* default class */ @@ -104,6 +106,7 @@ struct hfsc_classstats { /* red and rio related info */ int qtype; struct redstats red[3]; + struct codel_stats codel; }; #ifdef ALTQ3_COMPAT @@ -229,7 +232,10 @@ struct hfsc_class { struct hfsc_class *cl_children; /* child classes */ class_queue_t *cl_q; /* class queue structure */ - struct red *cl_red; /* RED state */ + union { + struct red *cl_red; /* RED state */ + struct codel *cl_codel; /* CoDel state */ + } cl_aqm; struct altq_pktattr *cl_pktattr; /* saved header used by ECN */ u_int64_t cl_total; /* total work in bytes */ @@ -278,6 +284,8 @@ struct hfsc_class { u_int period; } cl_stats; }; +#define cl_red cl_aqm.cl_red +#define cl_codel cl_aqm.cl_codel /* * hfsc interface state diff --git a/sys/contrib/altq/altq/altq_priq.c b/sys/contrib/altq/altq/altq_priq.c index 3ce65dc..576b9c6 100644 --- a/sys/contrib/altq/altq/altq_priq.c +++ b/sys/contrib/altq/altq/altq_priq.c @@ -297,6 +297,15 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) return (NULL); } #endif +#ifndef ALTQ_CODEL + if (flags & PRCF_CODEL) { +#ifdef ALTQ_DEBUG + printf("priq_class_create: CODEL not configured for PRIQ!\n"); +#endif + return (NULL); + } +#endif + if ((cl = pif->pif_classes[pri]) != NULL) { /* modify the class instead of creating a new one */ @@ -318,6 +327,10 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_destroy(cl->cl_codel); +#endif } else { cl = malloc(sizeof(struct priq_class), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -338,6 +351,7 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) qlimit(cl->cl_q) = qlimit; qtype(cl->cl_q) = Q_DROPTAIL; qlen(cl->cl_q) = 0; + qsize(cl->cl_q) = 0; cl->cl_flags = flags; cl->cl_pri = pri; if (pri > pif->pif_maxpri) @@ -381,6 +395,12 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) } } #endif /* ALTQ_RED */ +#ifdef ALTQ_CODEL + if (flags & PRCF_CODEL) { + cl->cl_codel = codel_alloc(5, 100, 0); + qtype(cl->cl_q) = Q_CODEL; + } +#endif return (cl); @@ -394,6 +414,10 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_destroy(cl->cl_codel); +#endif } if (cl->cl_q != NULL) free(cl->cl_q, M_DEVBUF); @@ -445,6 +469,10 @@ priq_class_destroy(struct priq_class *cl) if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_destroy(cl->cl_codel); +#endif } free(cl->cl_q, M_DEVBUF); free(cl, M_DEVBUF); @@ -560,6 +588,10 @@ priq_addq(struct priq_class *cl, struct mbuf *m) if (q_is_red(cl->cl_q)) return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + return codel_addq(cl->cl_codel, cl->cl_q, m); +#endif if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { m_freem(m); return (-1); @@ -584,6 +616,10 @@ priq_getq(struct priq_class *cl) if (q_is_red(cl->cl_q)) return red_getq(cl->cl_red, cl->cl_q); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + return codel_getq(cl->cl_codel, cl->cl_q); +#endif return _getq(cl->cl_q); } @@ -628,6 +664,10 @@ get_class_stats(struct priq_classstats *sp, struct priq_class *cl) if (q_is_rio(cl->cl_q)) rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->cl_q)) + codel_getstats(cl->cl_codel, &sp->codel); +#endif } diff --git a/sys/contrib/altq/altq/altq_priq.h b/sys/contrib/altq/altq/altq_priq.h index 481d31b..b5b062f 100644 --- a/sys/contrib/altq/altq/altq_priq.h +++ b/sys/contrib/altq/altq/altq_priq.h @@ -32,6 +32,7 @@ #include <altq/altq_classq.h> #include <altq/altq_red.h> #include <altq/altq_rio.h> +#include <altq/altq_codel.h> #ifdef __cplusplus extern "C" { @@ -59,6 +60,7 @@ struct priq_add_class { #define PRCF_RED 0x0001 /* use RED */ #define PRCF_ECN 0x0002 /* use RED/ECN */ #define PRCF_RIO 0x0004 /* use RIO */ +#define PRCF_CODEL 0x0008 /* use CODEL */ #define PRCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */ #define PRCF_DEFAULTCLASS 0x1000 /* default class */ @@ -105,6 +107,7 @@ struct priq_classstats { /* red and rio related info */ int qtype; struct redstats red[3]; /* rio has 3 red stats */ + struct codel_stats codel; }; #ifdef ALTQ3_COMPAT @@ -134,7 +137,10 @@ struct priq_class_stats { struct priq_class { u_int32_t cl_handle; /* class handle */ class_queue_t *cl_q; /* class queue structure */ - struct red *cl_red; /* RED state */ + union { + struct red *cl_red; /* RED state */ + struct codel *cl_codel; /* CoDel state */ + } cl_aqm; int cl_pri; /* priority */ int cl_flags; /* class flags */ struct priq_if *cl_pif; /* back pointer to pif */ @@ -145,7 +151,8 @@ struct priq_class { struct pktcntr cl_xmitcnt; /* transmitted packet counter */ struct pktcntr cl_dropcnt; /* dropped packet counter */ }; - +#define cl_red cl_aqm.cl_red +#define cl_codel cl_aqm.cl_codel /* * priq interface state */ diff --git a/sys/contrib/altq/altq/altq_rmclass.c b/sys/contrib/altq/altq/altq_rmclass.c index c433024..74db423 100644 --- a/sys/contrib/altq/altq/altq_rmclass.c +++ b/sys/contrib/altq/altq/altq_rmclass.c @@ -72,6 +72,7 @@ #include <altq/altq_rmclass_debug.h> #include <altq/altq_red.h> #include <altq/altq_rio.h> +#include <altq/altq_codel.h> /* * Local Macros @@ -218,6 +219,14 @@ rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte, return (NULL); } #endif +#ifndef ALTQ_CODEL + if (flags & RMCF_CODEL) { +#ifdef ALTQ_DEBUG + printf("rmc_newclass: CODEL not configured for CBQ!\n"); +#endif + return (NULL); + } +#endif cl = malloc(sizeof(struct rm_class), M_DEVBUF, M_NOWAIT | M_ZERO); if (cl == NULL) @@ -302,6 +311,12 @@ rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte, #endif } #endif /* ALTQ_RED */ +#ifdef ALTQ_CODEL + if (flags & RMCF_CODEL) { + cl->codel_ = codel_alloc(5, 100, 0); + qtype(cl->q_) = Q_CODEL; + } +#endif /* * put the class into the class tree @@ -652,6 +667,10 @@ rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl) if (q_is_red(cl->q_)) red_destroy(cl->red_); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->q_)) + codel_destroy(cl->codel_); +#endif } free(cl->q_, M_DEVBUF); free(cl, M_DEVBUF); @@ -1618,6 +1637,10 @@ _rmc_addq(rm_class_t *cl, mbuf_t *m) if (q_is_red(cl->q_)) return red_addq(cl->red_, cl->q_, m, cl->pktattr_); #endif /* ALTQ_RED */ +#ifdef ALTQ_CODEL + if (q_is_codel(cl->q_)) + return codel_addq(cl->codel_, cl->q_, m); +#endif /* ALTQ_RED */ if (cl->flags_ & RMCF_CLEARDSCP) write_dsfield(m, cl->pktattr_, 0); @@ -1647,6 +1670,10 @@ _rmc_getq(rm_class_t *cl) if (q_is_red(cl->q_)) return red_getq(cl->red_, cl->q_); #endif +#ifdef ALTQ_CODEL + if (q_is_codel(cl->q_)) + return codel_getq(cl->codel_, cl->q_); +#endif return _getq(cl->q_); } @@ -1717,7 +1744,7 @@ void cbqtrace_dump(int counter) #endif /* CBQ_TRACE */ #endif /* ALTQ_CBQ */ -#if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ) +#if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ) || defined(ALTQ_CODEL) #if !defined(__GNUC__) || defined(ALTQ_DEBUG) void diff --git a/sys/contrib/altq/altq/altq_rmclass.h b/sys/contrib/altq/altq/altq_rmclass.h index cf0ddf4..bd87591 100644 --- a/sys/contrib/altq/altq/altq_rmclass.h +++ b/sys/contrib/altq/altq/altq_rmclass.h @@ -53,6 +53,7 @@ typedef struct rm_ifdat rm_ifdat_t; typedef struct rm_class rm_class_t; struct red; +struct codel; /* * Macros for dealing with time values. We assume all times are @@ -164,7 +165,10 @@ struct rm_class { void (*overlimit)(struct rm_class *, struct rm_class *); void (*drop)(struct rm_class *); /* Class drop action. */ - struct red *red_; /* RED state pointer */ + union { + struct red *red_; /* RED state pointer */ + struct codel *codel; + } cl_aqm; struct altq_pktattr *pktattr_; /* saved hdr used by RED/ECN */ int flags_; @@ -176,6 +180,8 @@ struct rm_class { rm_class_stats_t stats_; /* Class Statistics */ }; +#define red_ cl_aqm.red_ +#define codel_ cl_aqm.codel /* * CBQ Interface state @@ -233,6 +239,7 @@ struct rm_ifdat { #define RMCF_RIO 0x0004 #define RMCF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */ #define RMCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */ +#define RMCF_CODEL 0x0040 /* flags for rmc_init */ #define RMCF_WRR 0x0100 diff --git a/sys/contrib/altq/altq/altq_subr.c b/sys/contrib/altq/altq/altq_subr.c index d59751a..fff1b49 100644 --- a/sys/contrib/altq/altq/altq_subr.c +++ b/sys/contrib/altq/altq/altq_subr.c @@ -542,6 +542,11 @@ altq_pfattach(struct pf_altq *a) error = fairq_pfattach(a); break; #endif +#ifdef ALTQ_CODEL + case ALTQT_CODEL: + error = codel_pfattach(a); + break; +#endif default: error = ENXIO; } @@ -622,6 +627,11 @@ altq_add(struct pf_altq *a) error = fairq_add_altq(a); break; #endif +#ifdef ALTQ_CODEL + case ALTQT_CODEL: + error = codel_add_altq(a); + break; +#endif default: error = ENXIO; } @@ -663,6 +673,11 @@ altq_remove(struct pf_altq *a) error = fairq_remove_altq(a); break; #endif +#ifdef ALTQ_CODEL + case ALTQT_CODEL: + error = codel_remove_altq(a); + break; +#endif default: error = ENXIO; } @@ -777,6 +792,11 @@ altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) error = fairq_getqstats(a, ubuf, nbytes); break; #endif +#ifdef ALTQ_CODEL + case ALTQT_CODEL: + error = codel_getqstats(a, ubuf, nbytes); + break; +#endif default: error = ENXIO; } diff --git a/sys/contrib/altq/altq/altq_var.h b/sys/contrib/altq/altq/altq_var.h index eb603ea..6ea7b7c 100644 --- a/sys/contrib/altq/altq/altq_var.h +++ b/sys/contrib/altq/altq/altq_var.h @@ -250,6 +250,11 @@ int priq_add_queue(struct pf_altq *); int priq_remove_queue(struct pf_altq *); int priq_getqstats(struct pf_altq *, void *, int *); +int codel_pfattach(struct pf_altq *); +int codel_add_altq(struct pf_altq *); +int codel_remove_altq(struct pf_altq *); +int codel_getqstats(struct pf_altq *, void *, int *); + int hfsc_pfattach(struct pf_altq *); int hfsc_add_altq(struct pf_altq *); int hfsc_remove_altq(struct pf_altq *); diff --git a/sys/netpfil/pf/pf_altq.h b/sys/netpfil/pf/pf_altq.h index db681fb..184e453 100644 --- a/sys/netpfil/pf/pf_altq.h +++ b/sys/netpfil/pf/pf_altq.h @@ -79,6 +79,12 @@ struct fairq_opts { u_int lssc_m2; }; +struct codel_opts { + u_int target; + u_int interval; + int ecn; +}; + struct pf_altq { char ifname[IFNAMSIZ]; @@ -106,6 +112,7 @@ struct pf_altq { struct priq_opts priq_opts; struct hfsc_opts hfsc_opts; struct fairq_opts fairq_opts; + struct codel_opts codel_opts; } pq_u; uint32_t qid; /* return value */ diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 4a09810..3a87ca6 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -128,6 +128,7 @@ struct pkthdr { uint32_t flowid; /* packet's 4-tuple system */ uint64_t csum_flags; /* checksum and offload features */ uint16_t fibnum; /* this packet should use this fib */ + uint64_t enqueue_time; uint8_t cosqos; /* class/quality of service */ uint8_t rsstype; /* hash type */ uint8_t l2hlen; /* layer 2 header length */ |