Skip to content

Commit

Permalink
Add ALTQ(9) support for the CoDel algorithm.
Browse files Browse the repository at this point in the history
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)
Obtained from:	pfSense
Sponsored by:	Rubicon Communications (Netgate)
  • Loading branch information
loos-br committed Aug 21, 2015
1 parent 85b6362 commit 4986012
Show file tree
Hide file tree
Showing 24 changed files with 989 additions and 21 deletions.
76 changes: 70 additions & 6 deletions sbin/pfctl/parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -449,8 +451,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 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
Expand Down Expand Up @@ -499,6 +501,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
Expand Down Expand Up @@ -1470,7 +1473,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;
}
Expand Down Expand Up @@ -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; }
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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; }
Expand Down Expand Up @@ -4800,7 +4859,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);
}

Expand Down Expand Up @@ -4891,7 +4951,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
}
);
FREE_LIST(struct node_if, interfaces);
FREE_LIST(struct node_queue, nqueues);
if (nqueues)
FREE_LIST(struct node_queue, nqueues);

return (errs);
}
Expand Down Expand Up @@ -5297,6 +5358,7 @@ lookup(char *s)
{ "buckets", BUCKETS},
{ "cbq", CBQ},
{ "code", CODE},
{ "codelq", CODEL},
{ "crop", FRAGCROP},
{ "debug", DEBUG},
{ "divert-reply", DIVERTREPLY},
Expand Down Expand Up @@ -5326,6 +5388,7 @@ lookup(char *s)
{ "include", INCLUDE},
{ "inet", INET},
{ "inet6", INET6},
{ "interval", INTERVAL},
{ "keep", KEEP},
{ "label", LABEL},
{ "limit", LIMIT},
Expand Down Expand Up @@ -5395,6 +5458,7 @@ lookup(char *s)
{ "table", TABLE},
{ "tag", TAG},
{ "tagged", TAGGED},
{ "target", TARGET},
{ "tbrsize", TBRSIZE},
{ "timeout", TIMEOUT},
{ "to", TO},
Expand Down
43 changes: 43 additions & 0 deletions sbin/pfctl/pfctl_altq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -60,6 +61,9 @@ static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
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 *);
Expand Down Expand Up @@ -185,6 +189,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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1010,6 +1022,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)
Expand All @@ -1031,6 +1045,28 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
return (0);
}

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)
{
Expand All @@ -1053,6 +1089,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)
Expand Down Expand Up @@ -1404,6 +1442,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);
Expand Down
1 change: 1 addition & 0 deletions sbin/pfctl/pfctl_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 4986012

Please sign in to comment.