svn commit: r287009 - in head: sbin/pfctl share/man/man4 sys/conf sys/net/altq sys/netpfil/pf
Ermal Luçi
ermal.luci at gmail.com
Sat Aug 22 09:18:39 UTC 2015
On Sat, Aug 22, 2015 at 12:02 AM, Luiz Otavio O Souza <loos at freebsd.org>
wrote:
> Author: loos
> Date: Fri Aug 21 22:02:22 2015
> New Revision: 287009
> URL: https://svnweb.freebsd.org/changeset/base/287009
>
> Log:
> Add ALTQ(9) support for the CoDel algorithm.
>
> CoDel is a parameterless queue discipline that handles variable bandwidth
> and RTT.
>
> It can be used as the single queue discipline on an interface or as a sub
> discipline of existing queue disciplines such as PRIQ, CBQ, HFSC, FAIRQ.
>
> Differential Revision: https://reviews.freebsd.org/D3272
> Reviewd by: rpaulo, gnn (previous version)
>
I thought part of this commit message was taken from me as a reviewer, no?
> Obtained from: pfSense
> Sponsored by: Rubicon Communications (Netgate)
>
> Added:
> head/sys/net/altq/altq_codel.c (contents, props changed)
> head/sys/net/altq/altq_codel.h (contents, props changed)
> Modified:
> head/sbin/pfctl/parse.y
> head/sbin/pfctl/pfctl_altq.c
> head/sbin/pfctl/pfctl_parser.h
> head/sbin/pfctl/pfctl_qstats.c
> head/share/man/man4/altq.4
> head/sys/conf/files
> head/sys/conf/options
> head/sys/net/altq/altq.h
> head/sys/net/altq/altq_cbq.c
> head/sys/net/altq/altq_cbq.h
> head/sys/net/altq/altq_classq.h
> head/sys/net/altq/altq_fairq.c
> head/sys/net/altq/altq_fairq.h
> head/sys/net/altq/altq_hfsc.c
> head/sys/net/altq/altq_hfsc.h
> head/sys/net/altq/altq_priq.c
> head/sys/net/altq/altq_priq.h
> head/sys/net/altq/altq_rmclass.c
> head/sys/net/altq/altq_rmclass.h
> head/sys/net/altq/altq_subr.c
> head/sys/net/altq/altq_var.h
> head/sys/netpfil/pf/pf_altq.h
>
> Modified: head/sbin/pfctl/parse.y
>
> ==============================================================================
> --- head/sbin/pfctl/parse.y Fri Aug 21 21:47:29 2015 (r287008)
> +++ head/sbin/pfctl/parse.y Fri Aug 21 22:02:22 2015 (r287009)
> @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
> #include <arpa/inet.h>
> #include <net/altq/altq.h>
> #include <net/altq/altq_cbq.h>
> +#include <net/altq/altq_codel.h>
> #include <net/altq/altq_priq.h>
> #include <net/altq/altq_hfsc.h>
> #include <net/altq/altq_fairq.h>
> @@ -299,7 +300,7 @@ struct pool_opts {
>
> } pool_opts;
>
> -
> +struct codel_opts codel_opts;
> struct node_hfsc_opts hfsc_opts;
> struct node_fairq_opts fairq_opts;
> struct node_state_opt *keep_state_defaults = NULL;
> @@ -425,6 +426,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;
> @@ -449,8 +451,8 @@ int parseport(char *, struct range *r, i
> %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 CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
> +%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET
> INTERVAL
> %token LOAD RULESET_OPTIMIZATION
> %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
> %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
> @@ -499,6 +501,7 @@ int parseport(char *, struct range *r, i
> %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
> @@ -1470,7 +1473,7 @@ altqif : ALTQ interface queue_opts QUEU
> 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;
> }
> @@ -1672,6 +1675,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; }
> @@ -1689,6 +1701,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);
> @@ -1711,6 +1725,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);
> @@ -1811,6 +1827,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);
> @@ -1866,6 +1884,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);
> @@ -1875,6 +1895,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 : INTERVAL number {
> + if (codel_opts.interval) {
> + yyerror("interval already specified");
> + YYERROR;
> + }
> + codel_opts.interval = $2;
> + }
> + | TARGET number {
> + if (codel_opts.target) {
> + yyerror("target already specified");
> + YYERROR;
> + }
> + codel_opts.target = $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; }
> @@ -4800,7 +4859,8 @@ expand_altq(struct pf_altq *a, struct no
>
> 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);
> }
>
> @@ -4891,7 +4951,8 @@ expand_altq(struct pf_altq *a, struct no
> }
> );
> FREE_LIST(struct node_if, interfaces);
> - FREE_LIST(struct node_queue, nqueues);
> + if (nqueues)
> + FREE_LIST(struct node_queue, nqueues);
>
> return (errs);
> }
> @@ -5297,6 +5358,7 @@ lookup(char *s)
> { "buckets", BUCKETS},
> { "cbq", CBQ},
> { "code", CODE},
> + { "codelq", CODEL},
> { "crop", FRAGCROP},
> { "debug", DEBUG},
> { "divert-reply", DIVERTREPLY},
> @@ -5326,6 +5388,7 @@ lookup(char *s)
> { "include", INCLUDE},
> { "inet", INET},
> { "inet6", INET6},
> + { "interval", INTERVAL},
> { "keep", KEEP},
> { "label", LABEL},
> { "limit", LIMIT},
> @@ -5395,6 +5458,7 @@ lookup(char *s)
> { "table", TABLE},
> { "tag", TAG},
> { "tagged", TAGGED},
> + { "target", TARGET},
> { "tbrsize", TBRSIZE},
> { "timeout", TIMEOUT},
> { "to", TO},
>
> Modified: head/sbin/pfctl/pfctl_altq.c
>
> ==============================================================================
> --- head/sbin/pfctl/pfctl_altq.c Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sbin/pfctl/pfctl_altq.c Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
>
> #include <net/altq/altq.h>
> #include <net/altq/altq_cbq.h>
> +#include <net/altq/altq_codel.h>
> #include <net/altq/altq_priq.h>
> #include <net/altq/altq_hfsc.h>
> #include <net/altq/altq_fairq.h>
> @@ -60,6 +61,9 @@ static int cbq_compute_idletime(struct p
> static int check_commit_cbq(int, int, struct pf_altq *);
> static int print_cbq_opts(const struct pf_altq *);
>
> +static int print_codel_opts(const struct pf_altq *,
> + const struct node_queue_opt *);
> +
> static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *);
> static int check_commit_priq(int, int, struct pf_altq *);
> static int print_priq_opts(const struct pf_altq *);
> @@ -185,6 +189,10 @@ print_altq(const struct pf_altq *a, unsi
> 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) {
> @@ -591,6 +599,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)
> @@ -678,6 +688,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)
> @@ -1010,6 +1022,8 @@ print_hfsc_opts(const struct pf_altq *a,
> 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)
> @@ -1032,6 +1046,28 @@ print_hfsc_opts(const struct pf_altq *a,
> }
>
> 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;
> @@ -1053,6 +1089,8 @@ print_fairq_opts(const struct pf_altq *a
> 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)
> @@ -1404,6 +1442,11 @@ eval_queue_opts(struct pf_altq *pa, stru
> 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);
>
> Modified: head/sbin/pfctl/pfctl_parser.h
>
> ==============================================================================
> --- head/sbin/pfctl/pfctl_parser.h Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sbin/pfctl/pfctl_parser.h Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -168,6 +168,7 @@ struct node_queue_opt {
> int qtype;
> union {
> struct cbq_opts cbq_opts;
> + struct codel_opts codel_opts;
> struct priq_opts priq_opts;
> struct node_hfsc_opts hfsc_opts;
> struct node_fairq_opts fairq_opts;
>
> Modified: head/sbin/pfctl/pfctl_qstats.c
>
> ==============================================================================
> --- head/sbin/pfctl/pfctl_qstats.c Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sbin/pfctl/pfctl_qstats.c Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
>
> #include <net/altq/altq.h>
> #include <net/altq/altq_cbq.h>
> +#include <net/altq/altq_codel.h>
> #include <net/altq/altq_priq.h>
> #include <net/altq/altq_hfsc.h>
> #include <net/altq/altq_fairq.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
> @@ -77,6 +79,7 @@ struct pf_altq_node *pfctl_find_altq_nod
> void pfctl_print_altq_node(int, const struct
> pf_altq_node *,
> unsigned, int);
> void print_cbqstats(struct queue_stats);
> +void print_codelstats(struct queue_stats);
> void print_priqstats(struct queue_stats);
> void print_hfscstats(struct queue_stats);
> void print_fairqstats(struct queue_stats);
> @@ -165,7 +168,7 @@ pfctl_update_qstats(int dev, struct pf_a
> 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 str
> 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
> case ALTQT_FAIRQ:
> print_fairqstats(a->qstats);
> break;
> + case ALTQT_CODEL:
> + print_codelstats(a->qstats);
> + break;
> }
> }
>
> @@ -348,6 +354,28 @@ print_cbqstats(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_priqstats(struct queue_stats cur)
> {
> printf(" [ pkts: %10llu bytes: %10llu "
> @@ -428,7 +456,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 +479,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;
>
> Modified: head/share/man/man4/altq.4
>
> ==============================================================================
> --- head/share/man/man4/altq.4 Fri Aug 21 21:47:29 2015 (r287008)
> +++ head/share/man/man4/altq.4 Fri Aug 21 22:02:22 2015 (r287009)
> @@ -25,7 +25,7 @@
> .\"
> .\" $FreeBSD$
> .\"
> -.Dd June 24, 2015
> +.Dd July 24, 2015
> .Dt ALTQ 4
> .Os
> .Sh NAME
> @@ -35,6 +35,7 @@
> .Cd options ALTQ
> .Pp
> .Cd options ALTQ_CBQ
> +.Cd options ALTQ_CODEL
> .Cd options ALTQ_RED
> .Cd options ALTQ_RIO
> .Cd options ALTQ_HFSC
> @@ -74,6 +75,10 @@ Enable
> Build the
> .Dq "Class Based Queuing"
> discipline.
> +.It Dv ALTQ_CODEL
> +Build the
> +.Dq "Controlled Delay"
> +discipline.
> .It Dv ALTQ_RED
> Build the
> .Dq "Random Early Detection"
>
> Modified: head/sys/conf/files
>
> ==============================================================================
> --- head/sys/conf/files Fri Aug 21 21:47:29 2015 (r287008)
> +++ head/sys/conf/files Fri Aug 21 22:02:22 2015 (r287009)
> @@ -3429,6 +3429,7 @@ libkern/zlib.c optional crypto |
> geom_
> ddb_ctf | gzio | geom_uncompress
> net/altq/altq_cbq.c optional altq
> net/altq/altq_cdnr.c optional altq
> +net/altq/altq_codel.c optional altq
> net/altq/altq_hfsc.c optional altq
> net/altq/altq_fairq.c optional altq
> net/altq/altq_priq.c optional altq
>
> Modified: head/sys/conf/options
>
> ==============================================================================
> --- head/sys/conf/options Fri Aug 21 21:47:29 2015 (r287008)
> +++ head/sys/conf/options Fri Aug 21 22:02:22 2015 (r287009)
> @@ -388,6 +388,7 @@ ACCEPT_FILTER_HTTP
> ALTQ opt_global.h
> ALTQ_CBQ opt_altq.h
> ALTQ_CDNR opt_altq.h
> +ALTQ_CODEL opt_altq.h
> ALTQ_DEBUG opt_altq.h
> ALTQ_HFSC opt_altq.h
> ALTQ_FAIRQ opt_altq.h
>
> Modified: head/sys/net/altq/altq.h
>
> ==============================================================================
> --- head/sys/net/altq/altq.h Fri Aug 21 21:47:29 2015 (r287008)
> +++ head/sys/net/altq/altq.h Fri Aug 21 22:02:22 2015 (r287009)
> @@ -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 /* CoDel */
> +#define ALTQT_MAX 15 /* should be max
> discipline type + 1 */
>
> #ifdef ALTQ3_COMPAT
> struct altqreq {
>
> Modified: head/sys/net/altq/altq_cbq.c
>
> ==============================================================================
> --- head/sys/net/altq/altq_cbq.c Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sys/net/altq/altq_cbq.c Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -237,6 +237,10 @@ get_class_stats(class_stats_t *statsp, s
> 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
>
> Modified: head/sys/net/altq/altq_cbq.h
>
> ==============================================================================
> --- head/sys/net/altq/altq_cbq.h Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sys/net/altq/altq_cbq.h Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -36,6 +36,7 @@
>
> #include <net/altq/altq.h>
> #include <net/altq/altq_rmclass.h>
> +#include <net/altq/altq_codel.h>
> #include <net/altq/altq_red.h>
> #include <net/altq/altq_rio.h>
>
> @@ -52,6 +53,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 */
> @@ -91,9 +93,10 @@ typedef struct _cbq_class_stats_ {
> int qcnt; /* # packets in queue */
> int avgidle;
>
> - /* red and rio related info */
> + /* codel, red and rio related info */
> int qtype;
> struct redstats red[3];
> + struct codel_stats codel;
> } class_stats_t;
>
> #ifdef ALTQ3_COMPAT
>
> Modified: head/sys/net/altq/altq_classq.h
>
> ==============================================================================
> --- head/sys/net/altq/altq_classq.h Fri Aug 21 21:47:29 2015
> (r287008)
> +++ head/sys/net/altq/altq_classq.h Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -50,6 +50,7 @@ extern "C" {
> #define Q_RED 0x01
> #define Q_RIO 0x02
> #define Q_DROPTAIL 0x03
> +#define Q_CODEL 0x04
>
> #ifdef _KERNEL
>
> @@ -60,6 +61,7 @@ struct _class_queue_ {
> struct mbuf *tail_; /* Tail of packet queue */
> int qlen_; /* Queue length (in number of packets) */
> int qlim_; /* Queue limit (in number of packets*) */
> + int qsize_; /* Queue size (in number of bytes*) */
> int qtype_; /* Queue type */
> };
>
> @@ -68,10 +70,12 @@ typedef struct _class_queue_ class_queue
> #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_codel(q) ((q)->qtype_ == Q_CODEL) /* Is the queue a
> codel queue */
> #define q_is_red(q) ((q)->qtype_ == Q_RED) /* Is the queue a
> red 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)
> @@ -101,6 +105,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 *
> @@ -115,6 +120,7 @@ _getq(class_queue_t *q)
> else
> qtail(q) = NULL;
> qlen(q)--;
> + qsize(q) -= m_pktlen(m0);
> m0->m_nextpkt = NULL;
> return (m0);
> }
>
> Added: head/sys/net/altq/altq_codel.c
>
> ==============================================================================
> --- /dev/null 00:00:00 1970 (empty, because file is newly added)
> +++ head/sys/net/altq/altq_codel.c Fri Aug 21 22:02:22 2015
> (r287009)
> @@ -0,0 +1,477 @@
> +/*
> + * CoDel - The Controlled-Delay Active Queue Management algorithm
> + *
> + * Copyright (C) 2013 Ermal Luci <eri at FreeBSD.org>
>
Can you correct my name?
> + * Copyright (C) 2011-2012 Kathleen Nichols <nichols at pollere.com>
> + * Copyright (C) 2011-2012 Van Jacobson <van at pollere.net>
> + * Copyright (C) 2012 Michael D. Taht <dave.taht at bufferbloat.net>
> + * Copyright (C) 2012 Eric Dumazet <edumazet at 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.
> + *
> + * $FreeBSD$
> + */
> +#include "opt_altq.h"
> +#include "opt_inet.h"
> +#include "opt_inet6.h"
> +
> +#ifdef ALTQ_CODEL /* CoDel is enabled by ALTQ_CODEL option in opt_altq.h
> */
> +
> +#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 <net/if_var.h>
> +#include <netinet/in.h>
> +
> +#include <netpfil/pf/pf.h>
> +#include <netpfil/pf/pf_altq.h>
> +#include <net/altq/if_altq.h>
> +#include <net/altq/altq.h>
> +#include <net/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;
> +
> + if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
> + return (EINVAL);
> +
> + return (altq_attach(&ifp->if_snd, ALTQT_CODEL, a->altq_disc,
> + codel_enqueue, codel_dequeue, codel_request, NULL, NULL));
> +}
> +
> +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 = 50; /* use default. */
> + 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 == 0)
> + opts->target = 5;
> + if (opts->interval == 0)
> + 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);
> + if (c != NULL) {
> + 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);
> +}
> +
> +#define MTAG_CODEL 1438031249
> +int
> +codel_addq(struct codel *c, class_queue_t *q, struct mbuf *m)
> +{
> + struct m_tag *mtag;
> + uint64_t *enqueue_time;
> +
> + if (qlen(q) < qlimit(q)) {
> + mtag = m_tag_locate(m, MTAG_CODEL, 0, NULL);
> + if (mtag == NULL)
> + mtag = m_tag_alloc(MTAG_CODEL, 0, sizeof(uint64_t),
> + M_NOWAIT);
> + if (mtag == NULL) {
> + m_freem(m);
> + return (-1);
> + }
> + enqueue_time = (uint64_t *)(mtag + 1);
> + *enqueue_time = read_machclk();
> + m_tag_prepend(m, mtag);
> + _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)
> +{
> + struct m_tag *mtag;
> + uint64_t *enqueue_time;
> +
> + if (m == NULL) {
> + c->vars.first_above_time = 0;
> + return (0);
> + }
> +
> + mtag = m_tag_locate(m, MTAG_CODEL, 0, NULL);
> + if (mtag == NULL) {
> + /* Only one warning per second. */
> + if (ppsratecheck(&c->last_log, &c->last_pps, 1))
> + printf("%s: could not found the packet mtag!\n",
> + __func__);
> + c->vars.first_above_time = 0;
> + return (0);
> + }
> + enqueue_time = (uint64_t *)(mtag + 1);
> + c->vars.ldelay = now - *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);
> +}
> +
> +/*
> + * Run a Newton method step:
> + * 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)
> +{
> + uint32_t invsqrt, invsqrt2;
> + uint64_t val;
> +
> +/* sizeof_in_bits(rec_inv_sqrt) */
> +#define REC_INV_SQRT_BITS (8 * sizeof(u_int16_t))
> +/* needed shift to get a Q0.32 number from rec_inv_sqrt */
> +#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
> +
> + invsqrt = ((u_int32_t)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
> + invsqrt2 = ((u_int64_t)invsqrt * invsqrt) >> 32;
> + 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))
>
> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
>
>
--
Ermal
More information about the svn-src-head
mailing list