summaryrefslogtreecommitdiff
path: root/sbin/pfctl
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2002-11-18 22:49:16 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2002-11-18 22:49:16 +0000
commit01ef9d16c38b163d3c0ff2b7acf62320a761e02e (patch)
treedc08b27c8ceac5342b0d765c949abca499288ec1 /sbin/pfctl
parent323c41ca9bc0986dc2a83bb659368c38dfaf02e1 (diff)
altq and pf merged
this isn't 100% done yet: the print_ stuff isn't finished, some features will be added later, and there is no documetation yet, but committing now enables a few more people to work on. print_altq_node stuff hacked by Daniel at euroBSDcon; lotsa stuff from kjc, debugging help also pb and camiel. lots of good ideas by theo. "commit now" theo philipp daniel
Diffstat (limited to 'sbin/pfctl')
-rw-r--r--sbin/pfctl/Makefile10
-rw-r--r--sbin/pfctl/parse.y334
-rw-r--r--sbin/pfctl/pfctl.c111
-rw-r--r--sbin/pfctl/pfctl_altq.c593
-rw-r--r--sbin/pfctl/pfctl_altq.h104
-rw-r--r--sbin/pfctl/pfctl_parser.c4
-rw-r--r--sbin/pfctl/pfctl_parser.h6
7 files changed, 1152 insertions, 10 deletions
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index bbf184e5364..57253ec473b 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -1,9 +1,13 @@
-# $OpenBSD: Makefile,v 1.8 2002/09/14 17:51:53 henning Exp $
+# $OpenBSD: Makefile,v 1.9 2002/11/18 22:49:15 henning Exp $
PROG= pfctl
-SRCS= pfctl.c parse.y pfctl_parser.c pf_print_state.c
-CFLAGS+= -Wall
+SRCS= pfctl.c parse.y pfctl_parser.c pf_print_state.c pfctl_altq.c
+CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
+CFLAGS+= -Wstrict-prototypes
YFLAGS=
MAN= pfctl.8
+
+LDADD+= -lm
+DPADD+= ${LIBM}
.include <bsd.prog.mk>
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index ecc9b9c1aca..60a9019ead0 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.186 2002/11/13 22:44:11 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.187 2002/11/18 22:49:15 henning Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -50,6 +50,7 @@
#include <grp.h>
#include "pfctl_parser.h"
+#include "pfctl_altq.h"
static struct pfctl *pf = NULL;
static FILE *fin = NULL;
@@ -153,6 +154,26 @@ struct peer {
struct node_port *port;
};
+struct node_queue {
+ char queue[PF_QNAME_SIZE];
+ char parent[PF_QNAME_SIZE];
+ char ifname[IFNAMSIZ];
+ struct node_queue *next;
+ struct node_queue *tail;
+} *queues = NULL;
+
+struct node_queue_opt {
+ int qtype;
+ union { /* options for other schedulers will follow */
+ struct cbq_opts cbq_opts;
+ } data;
+};
+
+struct node_queue_bw {
+ u_int32_t bw_absolute;
+ u_int16_t bw_percent;
+};
+
int yyerror(char *, ...);
int rule_consistent(struct pf_rule *);
int nat_consistent(struct pf_nat *);
@@ -176,6 +197,9 @@ void expand_rule(struct pf_rule *, struct node_if *, struct node_proto *,
struct node_host *, struct node_port *, struct node_host *,
struct node_port *, struct node_uid *, struct node_gid *,
struct node_icmp *);
+void expand_altq(struct pf_altq *, struct node_if *, struct node_queue *);
+int expand_queue(struct pf_altq *, struct node_queue *,
+ struct node_queue_bw);
int check_rulestate(int);
int kw_cmp(const void *, const void *);
int lookup(char *);
@@ -187,7 +211,6 @@ struct node_host *host(char *, int);
int atoul(char *, u_long *);
int getservice(char *);
-
struct sym {
struct sym *next;
int used;
@@ -251,6 +274,9 @@ typedef struct {
u_int8_t log;
u_int8_t quick;
} logquick;
+ struct node_queue *queue;
+ struct node_queue_opt queue_options;
+ struct node_queue_bw queue_bwspec;
} v;
int lineno;
} YYSTYPE;
@@ -266,6 +292,9 @@ typedef struct {
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY
%token REQUIREORDER YES
%token ANTISPOOF FOR
+%token ALTQ SCHEDULER CBQ BANDWIDTH TBRSIZE
+%token QUEUE PRIORITY QLIMIT
+%token DEFAULT CONTROL BORROW RED ECN RIO
%token <v.string> STRING
%token <v.i> PORTUNARY PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
@@ -289,6 +318,12 @@ typedef struct {
%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
%type <v.logquick> logquick
%type <v.interface> antispoof_ifspc antispoof_iflst
+%type <v.number> priority qlimit tbrsize
+%type <v.string> qname
+%type <v.queue> qassign qassign_list qassign_item
+%type <v.queue_options> schedtype
+%type <v.number> cbqflags_list cbqflags_item
+%type <v.queue_bwspec> bandwidth
%%
ruleset : /* empty */
@@ -299,6 +334,8 @@ ruleset : /* empty */
| ruleset binatrule '\n'
| ruleset rdrrule '\n'
| ruleset pfrule '\n'
+ | ruleset altqif '\n'
+ | ruleset queuespec '\n'
| ruleset varset '\n'
| ruleset antispoof '\n'
| ruleset error '\n' { errors++; }
@@ -467,8 +504,169 @@ antispoof_iflst : if_item { $$ = $1; }
}
;
+
+/* altq stuff */
+
+altqif : ALTQ interface SCHEDULER schedtype bandwidth tbrsize
+ qassign {
+ struct pf_altq a;
+
+ memset(&a, 0, sizeof(a));
+ if ($4.qtype == ALTQT_NONE) {
+ yyerror("no scheduler specified!");
+ YYERROR;
+ }
+ a.scheduler = $4.qtype;
+ a.pq_u.cbq_opts.flags = $4.data.cbq_opts.flags;
+ if ((a.ifbandwidth = $5.bw_absolute) == 0) {
+ yyerror("interface bandwidth must be absolute");
+ YYERROR;
+ }
+ a.tbrsize = $6;
+ expand_altq(&a, $2, $7);
+ }
+ ;
+
+qassign : /* empty */ { $$ = NULL; }
+ | QUEUE qassign_item { $$ = $2; }
+ | QUEUE '{' qassign_list '}' { $$ = $3; }
+ ;
+
+qassign_list : qassign_item { $$ = $1; }
+ | qassign_list comma qassign_item {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+qassign_item : STRING {
+ $$ = malloc(sizeof(struct node_queue));
+ if ($$ == NULL)
+ err(1, "queue_item: malloc");
+ strlcpy($$->queue, $1, PF_QNAME_SIZE);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+queuespec : QUEUE STRING bandwidth priority qlimit schedtype qassign {
+ struct pf_altq a;
+
+ memset(&a, 0, sizeof(a));
+
+ if (strlen($2) >= PF_QNAME_SIZE) {
+ yyerror("queue name too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ YYERROR;
+ }
+ strlcpy(a.qname, $2, sizeof(a.qname));
+ if ($4 > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ a.priority = $4;
+ a.qlimit = $5;
+ a.scheduler = $6.qtype;
+ a.pq_u.cbq_opts.flags = $6.data.cbq_opts.flags;
+ if (expand_queue(&a, $7, $3))
+ YYERROR;
+
+ }
+ ;
+
+schedtype : /* empty */ { $$.qtype = ALTQT_NONE; }
+ | CBQ { $$.qtype = ALTQT_CBQ; }
+ | CBQ '(' cbqflags_list ')' {
+ $$.qtype = ALTQT_CBQ;
+ $$.data.cbq_opts.flags = $3;
+ }
+ ;
+
+cbqflags_list : cbqflags_item { $$ |= $1; }
+ | cbqflags_list comma cbqflags_item { $$ |= $3; }
+ ;
+
+
+cbqflags_item : DEFAULT { $$ = CBQCLF_DEFCLASS; }
+ | CONTROL { $$ = CBQCLF_CTLCLASS; }
+ | BORROW { $$ = CBQCLF_BORROW; }
+ | RED { $$ = CBQCLF_RED; }
+ | ECN { $$ = CBQCLF_RED|CBQCLF_ECN; }
+ | RIO { $$ = CBQCLF_RIO; }
+ ;
+
+bandwidth : /* empty */ {
+ $$.bw_absolute = 0;
+ $$.bw_percent = 0;
+ }
+ | BANDWIDTH STRING {
+ double bps;
+ char *cp;
+
+ $$.bw_percent = 0;
+
+ bps = strtod($2, &cp);
+ if (cp != NULL) {
+ if (!strcmp(cp, "b")) {
+ /* nothing */
+ } else if (!strcmp(cp, "Kb"))
+ bps *= 1024;
+ else if (!strcmp(cp, "Mb"))
+ bps *= 1024 * 1024;
+ else if (!strcasecmp(cp, "Gb"))
+ bps *= 1024 * 1024 * 1024;
+ else if (*cp == '%') {
+ if (bps < 0 || bps > 100) {
+ yyerror("bandwidth spec "
+ "out of range");
+ YYERROR;
+ }
+ $$.bw_percent = bps;
+ bps = 0;
+ } else {
+ yyerror("unknown unit %s", cp);
+ YYERROR;
+ }
+ }
+ $$.bw_absolute = (u_int32_t)bps;
+ }
+ ;
+
+priority : /* empty */ { $$ = 0; }
+ | PRIORITY number {
+ if ($2 > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+qlimit : /* empty */ { $$ = 0; }
+ | QLIMIT number {
+ if ($2 > 65535) {
+ yyerror("qlimit out of range: max 65535");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+
+tbrsize : /* empty */ { $$ = 0; }
+ | number {
+ if ($1 > 65535) {
+ yyerror("tbrsize too big: max 65535");
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
pfrule : action dir logquick interface route af proto fromto
uids gids flags icmpspec tos keep fragment allowopts label
+ qname
{
struct pf_rule r;
struct node_state_opt *o;
@@ -585,6 +783,16 @@ pfrule : action dir logquick interface route af proto fromto
free($17);
}
+ if ($18) {
+ if (strlen($18) >= PF_QNAME_SIZE) {
+ yyerror("rule qname too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ YYERROR;
+ }
+ strlcpy(r.qname, $18, sizeof(r.qname));
+ free($18);
+ }
+
expand_rule(&r, $4, $7, $8.src.host, $8.src.port,
$8.dst.host, $8.dst.port, $9, $10, $12);
}
@@ -1328,6 +1536,14 @@ label : /* empty */ { $$ = NULL; }
}
}
;
+qname : /* empty */ { $$ = NULL; }
+ | QUEUE STRING {
+ if (($$ = strdup($2)) == NULL) {
+ yyerror("qname strdup() failed");
+ YYERROR;
+ }
+ }
+ ;
no : /* empty */ { $$ = 0; }
| NO { $$ = 1; }
@@ -2056,6 +2272,102 @@ expand_label(char *label, const char *ifname, sa_family_t af,
}
void
+expand_altq(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues)
+{
+ struct pf_altq pa, pb;
+ char qname[PF_QNAME_SIZE];
+ struct node_queue *n;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ memcpy(&pa, a, sizeof(struct pf_altq));
+ strlcpy(pa.ifname, interface->ifname, IFNAMSIZ);
+
+ if (interface->not)
+ yyerror("altq on ! <interface> is not supported");
+ else {
+ eval_pfaltq(pf, &pa);
+ pfctl_add_altq(pf, &pa);
+
+ /* now create a root queue */
+ memset(&pb, 0, sizeof(struct pf_altq));
+ strlcpy(qname, "root_", sizeof(qname));
+ strlcat(qname, interface->ifname, sizeof(qname));
+ strlcpy(pb.qname, qname, PF_QNAME_SIZE);
+ strlcpy(pb.ifname, interface->ifname, IFNAMSIZ);
+ pb.qlimit = pa.qlimit;
+ pb.scheduler = pa.scheduler;
+ pb.pq_u.cbq_opts.flags = pa.pq_u.cbq_opts.flags;
+ eval_pfqueue(pf, &pb, pa.ifbandwidth, 0);
+ pfctl_add_altq(pf, &pb);
+
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = calloc(1, sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_altq: malloc");
+ strlcpy(n->parent, qname, PF_QNAME_SIZE);
+ strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
+ strlcpy(n->ifname, interface->ifname, IFNAMSIZ);
+ 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);
+}
+
+int
+expand_queue(struct pf_altq *a, struct node_queue *nqueues,
+ struct node_queue_bw bwspec)
+{
+ struct node_queue *n;
+ u_int8_t added = 0;
+
+ LOOP_THROUGH(struct node_queue, tqueue, queues,
+ if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE)) {
+ /* found ourselve in queues */
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = malloc(sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_queue: malloc");
+ strlcpy(n->parent, a->qname, PF_QNAME_SIZE);
+ strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
+ strlcpy(n->ifname, tqueue->ifname, IFNAMSIZ);
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ );
+ FREE_LIST(struct node_queue, nqueues);
+ strlcpy(a->ifname, tqueue->ifname, IFNAMSIZ);
+ strlcpy(a->parent, tqueue->parent, PF_QNAME_SIZE);
+
+ eval_pfqueue(pf, a, bwspec.bw_absolute,
+ bwspec.bw_percent);
+ pfctl_add_altq(pf, a);
+ added++;
+ }
+ );
+
+ if (!added) {
+ yyerror("queue has no parent");
+ return (1);
+ } else
+ return (0);
+}
+
+void
expand_rule(struct pf_rule *r,
struct node_if *interfaces, struct node_proto *protos,
struct node_host *src_hosts, struct node_port *src_ports,
@@ -2067,9 +2379,11 @@ expand_rule(struct pf_rule *r,
int nomatch = 0, added = 0;
char ifname[IF_NAMESIZE];
char label[PF_RULE_LABEL_SIZE];
+ char qname[PF_QNAME_SIZE];
u_int8_t flags, flagset;
strlcpy(label, r->label, sizeof(label));
+ strlcpy(qname, r->qname, sizeof(qname));
flags = r->flags;
flagset = r->flagset;
@@ -2111,6 +2425,8 @@ expand_rule(struct pf_rule *r,
strlcpy(r->label, label, PF_RULE_LABEL_SIZE);
expand_label(r->label, r->ifname, r->af, src_host, src_port,
dst_host, dst_port, proto->proto);
+ strlcpy(r->qname, qname, PF_QNAME_SIZE);
+ r->qid = qname_to_qid(qname, r->ifname);
r->ifnot = interface->not;
r->proto = proto->proto;
r->src.addr = src_host->addr;
@@ -2343,16 +2659,23 @@ lookup(char *s)
static const struct keywords keywords[] = {
{ "all", ALL},
{ "allow-opts", ALLOWOPTS},
+ { "altq", ALTQ},
{ "antispoof", ANTISPOOF},
{ "any", ANY},
+ { "bandwidth", BANDWIDTH},
{ "binat", BINAT},
{ "block", BLOCK},
{ "block-policy", BLOCKPOLICY},
+ { "borrow", BORROW},
+ { "cbq", CBQ},
{ "code", CODE},
+ { "control", CONTROL},
{ "crop", FRAGCROP},
+ { "default", DEFAULT},
{ "drop", DROP},
{ "drop-ovl", FRAGDROP},
{ "dup-to", DUPTO},
+ { "ecn", ECN},
{ "fastroute", FASTROUTE},
{ "flags", FLAGS},
{ "for", FOR},
@@ -2383,20 +2706,27 @@ lookup(char *s)
{ "out", OUT},
{ "pass", PASS},
{ "port", PORT},
+ { "priority", PRIORITY},
{ "proto", PROTO},
+ { "qlimit", QLIMIT},
+ { "queue", QUEUE},
{ "quick", QUICK},
{ "rdr", RDR},
{ "reassemble", FRAGNORM},
+ { "red", RED},
{ "reply-to", REPLYTO},
{ "require-order", REQUIREORDER},
{ "return", RETURN},
{ "return-icmp",RETURNICMP},
{ "return-icmp6",RETURNICMP6},
{ "return-rst", RETURNRST},
+ { "rio", RIO},
{ "route-to", ROUTETO},
+ { "scheduler", SCHEDULER},
{ "scrub", SCRUB},
{ "set", SET},
{ "state", STATE},
+ { "tbrsize", TBRSIZE},
{ "timeout", TIMEOUT},
{ "to", TO},
{ "tos", TOS},
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 071b103cba1..2d4f1826279 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.85 2002/10/07 14:34:40 dhartmei Exp $ */
+/* $OpenBSD: pfctl.c,v 1.86 2002/11/18 22:49:15 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -51,6 +51,7 @@
#include "pfctl_parser.h"
#include "pf_print_state.h"
+#include "pfctl_altq.h"
void usage(void);
int pfctl_enable(int, int);
@@ -58,10 +59,12 @@ int pfctl_disable(int, int);
int pfctl_clear_stats(int, int);
int pfctl_clear_rules(int, int);
int pfctl_clear_nat(int, int);
+int pfctl_clear_altq(int, int);
int pfctl_clear_states(int, int);
int pfctl_kill_states(int, int);
int pfctl_show_rules(int, int, int);
int pfctl_show_nat(int);
+int pfctl_show_altq(int);
int pfctl_show_states(int, u_int8_t, int);
int pfctl_show_status(int);
int pfctl_show_timeouts(int);
@@ -148,7 +151,7 @@ usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-deqhnNrROvz] [-f file] ", __progname);
+ fprintf(stderr, "usage: %s [-AdeqhnNrROvz] [-f file] ", __progname);
fprintf(stderr, "[-F modifier] [-k host]\n");
fprintf(stderr, " ");
fprintf(stderr, "[-s modifier] [-x level]\n");
@@ -166,6 +169,16 @@ pfctl_enable(int dev, int opts)
}
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "pf enabled\n");
+
+ if (ioctl(dev, DIOCSTARTALTQ)) {
+ if (errno == EEXIST)
+ errx(1, "altq already enabled");
+ else
+ err(1, "DIOCSTARTALTQ");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "altq enabled\n");
+
return (0);
}
@@ -180,6 +193,16 @@ pfctl_disable(int dev, int opts)
}
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "pf disabled\n");
+
+ if (ioctl(dev, DIOCSTOPALTQ)) {
+ if (errno == ENOENT)
+ errx(1, "altq not enabled");
+ else
+ err(1, "DIOCSTOPALTQ");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "altq disabled\n");
+
return (0);
}
@@ -232,6 +255,20 @@ pfctl_clear_nat(int dev, int opts)
}
int
+pfctl_clear_altq(int dev, int opts)
+{
+ struct pfioc_altq pa;
+
+ if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
+ err(1, "DIOCBEGINALTQS");
+ else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
+ err(1, "DIOCCOMMITALTQS");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "altq cleared\n");
+ return (0);
+}
+
+int
pfctl_clear_states(int dev, int opts)
{
if (ioctl(dev, DIOCCLRSTATES))
@@ -384,6 +421,33 @@ pfctl_show_rules(int dev, int opts, int format)
}
int
+pfctl_show_altq(int dev)
+{
+ struct pf_altq_node *root = NULL;
+
+ struct pfioc_altq pa;
+ u_int32_t mnr, nr;
+
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ warnx("DIOCGETALTQS");
+ return (-1);
+ }
+ mnr = pa.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pa.nr = nr;
+ if (ioctl(dev, DIOCGETALTQ, &pa)) {
+ warnx("DIOCGETALTQ");
+ return (-1);
+ }
+ pfctl_insert_altq_node(&root, pa.altq);
+ }
+ for (; root != NULL; root = root->next)
+ pfctl_print_altq_node(root, 0);
+ pfctl_free_altq_node(root);
+ return (0);
+}
+
+int
pfctl_show_nat(int dev)
{
struct pfioc_nat pn;
@@ -583,6 +647,24 @@ pfctl_add_rdr(struct pfctl *pf, struct pf_rdr *r)
}
int
+pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
+{
+ if ((loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) != 0) {
+ memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq))
+ err(1, "DIOCADDALTQ");
+ }
+ pfaltq_store(&pf->paltq->altq);
+ if (pf->opts & PF_OPT_VERBOSE) {
+ print_altq(&pf->paltq->altq, 0);
+ printf("\n");
+ }
+ }
+ return (0);
+}
+
+int
pfctl_rules(int dev, char *filename, int opts)
{
FILE *fin;
@@ -590,6 +672,7 @@ pfctl_rules(int dev, char *filename, int opts)
struct pfioc_binat pb;
struct pfioc_rdr pr;
struct pfioc_rule pl;
+ struct pfioc_altq pa;
struct pfctl pf;
if (strcmp(filename, "-") == 0) {
@@ -612,6 +695,9 @@ pfctl_rules(int dev, char *filename, int opts)
if (ioctl(dev, DIOCBEGINBINATS, &pb.ticket))
err(1, "DIOCBEGINBINATS");
}
+ if (((loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) != 0) &&
+ ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
+ err(1, "DIOCBEGINALTQS");
if (((loadopt & (PFCTL_FLAG_FILTER | PFCTL_FLAG_ALL)) != 0) &&
ioctl(dev, DIOCBEGINRULES, &pl.ticket))
err(1, "DIOCBEGINRULES");
@@ -622,10 +708,14 @@ pfctl_rules(int dev, char *filename, int opts)
pf.pnat = &pn;
pf.pbinat = &pb;
pf.prdr = &pr;
+ pf.paltq = &pa;
pf.prule = &pl;
pf.rule_nr = 0;
if (parse_rules(fin, &pf) < 0)
errx(1, "Syntax error in file: pf rules not loaded");
+ if ((loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) != 0)
+ if (check_commit_altq(dev, opts) != 0)
+ errx(1, "errors in altq config");
if ((opts & PF_OPT_NOACTION) == 0) {
if ((loadopt & (PFCTL_FLAG_NAT | PFCTL_FLAG_ALL)) != 0) {
if (ioctl(dev, DIOCCOMMITNATS, &pn.ticket))
@@ -635,6 +725,9 @@ pfctl_rules(int dev, char *filename, int opts)
if (ioctl(dev, DIOCCOMMITBINATS, &pb.ticket))
err(1, "DIOCCOMMITBINATS");
}
+ if (((loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) != 0) &&
+ ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
+ err(1, "DIOCCOMMITALTQS");
if (((loadopt & (PFCTL_FLAG_FILTER | PFCTL_FLAG_ALL)) != 0) &&
ioctl(dev, DIOCCOMMITRULES, &pl.ticket))
err(1, "DIOCCOMMITRULES");
@@ -805,7 +898,7 @@ main(int argc, char *argv[])
if (argc < 2)
usage();
- while ((ch = getopt(argc, argv, "deqf:F:hk:nNOrRs:Svx:z")) != -1) {
+ while ((ch = getopt(argc, argv, "Adeqf:F:hk:nNOrRs:Svx:z")) != -1) {
switch (ch) {
case 'd':
opts |= PF_OPT_DISABLE;
@@ -845,6 +938,10 @@ main(int argc, char *argv[])
rulesopt = optarg;
mode = O_RDWR;
break;
+ case 'A':
+ loadopt &= ~PFCTL_FLAG_ALL;
+ loadopt |= PFCTL_FLAG_ALTQ;
+ break;
case 'R':
loadopt &= ~PFCTL_FLAG_ALL;
loadopt |= PFCTL_FLAG_FILTER;
@@ -905,6 +1002,9 @@ main(int argc, char *argv[])
case 'n':
pfctl_clear_nat(dev, opts);
break;
+ case 'q':
+ pfctl_clear_altq(dev, opts);
+ break;
case 's':
pfctl_clear_states(dev, opts);
break;
@@ -914,6 +1014,7 @@ main(int argc, char *argv[])
case 'a':
pfctl_clear_rules(dev, opts);
pfctl_clear_nat(dev, opts);
+ pfctl_clear_altq(dev, opts);
pfctl_clear_states(dev, opts);
pfctl_clear_stats(dev, opts);
break;
@@ -940,6 +1041,9 @@ main(int argc, char *argv[])
case 'n':
pfctl_show_nat(dev);
break;
+ case 'q':
+ pfctl_show_altq(dev);
+ break;
case 's':
pfctl_show_states(dev, 0, opts);
break;
@@ -955,6 +1059,7 @@ main(int argc, char *argv[])
case 'a':
pfctl_show_rules(dev, opts, 0);
pfctl_show_nat(dev);
+ pfctl_show_altq(dev);
pfctl_show_states(dev, 0, opts);
pfctl_show_status(dev);
pfctl_show_rules(dev, opts, 1);
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
new file mode 100644
index 00000000000..8ebcbc66443
--- /dev/null
+++ b/sbin/pfctl/pfctl_altq.c
@@ -0,0 +1,593 @@
+/* $OpenBSD: pfctl_altq.c,v 1.1 2002/11/18 22:49:15 henning Exp $ */
+/*
+ * Copyright (C) 2002
+ * Sony Computer Science Laboratories Inc. All rights reserved.
+ * Copyright (C) 2002 Henning Brauer. All rights reserved.
+ *
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <altq/altq.h>
+#include <altq/altq_cbq.h>
+
+#include "pfctl_parser.h"
+#include "pfctl_altq.h"
+
+static int eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *);
+static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
+static int check_commit_cbq(int, int, struct pf_altq *);
+static void print_cbq_opts(const struct pf_altq *);
+static char *rate2str(double);
+
+TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs);
+
+void
+pfaltq_store(struct pf_altq *a)
+{
+ struct pf_altq *altq;
+
+ if ((altq = malloc(sizeof(*altq))) == NULL)
+ err(1, "malloc");
+ memcpy(altq, a, sizeof(struct pf_altq));
+ TAILQ_INSERT_TAIL(&altqs, altq, entries);
+}
+
+void
+pfaltq_free(struct pf_altq *a)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0
+ && strncmp(a->qname, altq->qname, PF_QNAME_SIZE) == 0) {
+ TAILQ_REMOVE(&altqs, altq, entries);
+ free(altq);
+ return;
+ }
+ }
+}
+
+struct pf_altq *
+pfaltq_lookup(const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0
+ && altq->qname[0] == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+struct pf_altq *
+qname_to_pfaltq(const char *qname, const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+u_int32_t
+qname_to_qid(const char *qname, const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq->qid);
+ }
+ return (0);
+}
+
+char *
+qid_to_qname(u_int32_t qid, const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ altq->qid == qid)
+ return (altq->qname);
+ }
+ return (NULL);
+}
+
+void
+print_altq(const struct pf_altq *a, unsigned level)
+{
+ unsigned i;
+
+ if (a->qname[0] != NULL) {
+ print_queue(a, level);
+ return;
+ }
+
+ for (i = 0; i < level; ++i)
+ printf(" ");
+ printf("altq on %s scheduler %u bandwidth %s tbrsize %u",
+ a->ifname, a->scheduler, rate2str((double)a->ifbandwidth),
+ a->tbrsize);
+}
+
+void
+print_queue(const struct pf_altq *a, unsigned level)
+{
+ unsigned i;
+
+ for (i = 0; i < level; ++i)
+ printf(" ");
+ printf("queue %s bandwidth %s priority %u", a->qname,
+ rate2str((double)a->bandwidth), a->priority);
+/* printf("queue on %s %s parent 0x%x priority %u bandwidth %s"
+ " qlimit %u qid 0x%x\n",
+ a->ifname, a->qname, a->parent_qid, a->priority,
+ rate2str((double)a->bandwidth), a->qlimit, a->qid); */
+ switch (a->scheduler) {
+ case ALTQT_CBQ:
+ print_cbq_opts(a);
+ break;
+ }
+}
+
+int
+eval_pfaltq(struct pfctl *pf, struct pf_altq *pa)
+{
+ u_int rate, size;
+
+ /* if tbrsize is not specified, use heuristics */
+ if (pa->tbrsize == 0) {
+ rate = pa->ifbandwidth;
+ if (rate <= 1 * 1024 * 1024)
+ size = 1;
+ else if (rate <= 10 * 1024 * 1024)
+ size = 4;
+ else if (rate <= 200 * 1024 * 1024)
+ size = 8;
+ else
+ size = 24;
+ size = size * 1500; /* assume the default mtu is 1500 */
+ pa->tbrsize = size;
+ }
+ return (0);
+}
+
+int
+check_commit_altq(int dev, int opts)
+{
+ struct pf_altq *altq;
+ int error = 0;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (altq->qname[0] == 0) {
+ switch (altq->scheduler) {
+ case ALTQT_CBQ:
+ error = check_commit_cbq(dev, opts, altq);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return (error);
+}
+
+int
+eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, u_int32_t bw_absolute,
+ u_int16_t bw_percent)
+{
+ /* should be merged with expand_queue */
+ struct pf_altq *if_pa, *parent;
+ int error = 0;
+
+ /* find the corresponding interface and copy fields used by queues */
+ if_pa = pfaltq_lookup(pa->ifname);
+ if (if_pa == NULL)
+ errx(1, "altq not defined on %s", pa->ifname);
+ pa->scheduler = if_pa->scheduler;
+ pa->ifbandwidth = if_pa->ifbandwidth;
+
+ parent = NULL;
+ if (pa->parent[0] != 0) {
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s",
+ pa->parent, pa->qname);
+ pa->parent_qid = parent->qid;
+ }
+ if (pa->qlimit == 0)
+ pa->qlimit = 50;
+
+ if (bw_absolute > 0)
+ pa->bandwidth = bw_absolute;
+ else if (bw_percent > 0 && parent != NULL)
+ pa->bandwidth = parent->bandwidth / 100 * bw_percent;
+ else
+ errx(1, "bandwidth for %s invalid (%d / %d)", pa->qname, bw_absolute, bw_percent);
+
+ /*
+ * admission control: bandwidth should be smaller than the
+ * interface bandwidth and the parent bandwidth
+ */
+ if (pa->bandwidth > pa->ifbandwidth)
+ errx(1, "bandwidth for %s higher than interface", pa->qname);
+ if (parent != NULL && pa->bandwidth > parent->bandwidth)
+ errx(1, "bandwidth for %s higher than parent", pa->qname);
+
+ switch (pa->scheduler) {
+ case ALTQT_CBQ:
+ error = eval_pfqueue_cbq(pf, pa);
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/*
+ * CBQ support functions
+ */
+#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */
+#define RM_NS_PER_SEC (1000000000)
+
+static int
+eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ u_int ifmtu;
+
+#if 1
+ ifmtu = 1500; /* should be obtained from the interface */
+#endif
+ opts = &pa->pq_u.cbq_opts;
+
+ if (opts->pktsize == 0) { /* use default */
+ opts->pktsize = ifmtu;
+ if (opts->pktsize > MCLBYTES) /* do what TCP does */
+ opts->pktsize &= ~MCLBYTES;
+ } else if (opts->pktsize > ifmtu)
+ opts->pktsize = ifmtu;
+ if (opts->maxpktsize == 0) /* use default */
+ opts->maxpktsize = ifmtu;
+ else if (opts->maxpktsize > ifmtu)
+ opts->pktsize = ifmtu;
+
+ if (opts->pktsize > opts->maxpktsize)
+ opts->pktsize = opts->maxpktsize;
+
+ if (pa->parent[0] == 0 || strcasecmp("NULL", pa->parent) == 0)
+ opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
+
+ cbq_compute_idletime(pf, pa);
+
+ return (0);
+}
+
+/*
+ * compute ns_per_byte, maxidle, minidle, and offtime
+ */
+static int
+cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ double maxidle_s, maxidle, minidle,
+ offtime, nsPerByte, ifnsPerByte, ptime, cptime;
+ double z, g, f, gton, gtom, maxrate;
+ u_int minburst, maxburst;
+
+ opts = &pa->pq_u.cbq_opts;
+ ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8;
+ minburst = opts->minburst;
+ maxburst = opts->maxburst;
+
+ if (pa->bandwidth == 0)
+ f = 0.0001; /* small enough? */
+ else
+ f = ((double) pa->bandwidth / (double) pa->ifbandwidth);
+
+ nsPerByte = ifnsPerByte / f;
+ ptime = (double)opts->pktsize * ifnsPerByte;
+ maxrate = f * ((double)pa->ifbandwidth / 8.0);
+ cptime = ptime * (1.0 - f) / f;
+
+ if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) {
+ /*
+ * this causes integer overflow in kernel!
+ * (bandwidth < 6Kbps when max_pkt_size=1500)
+ */
+ if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "cbq: class %s is too slow!\n",
+ pa->qname);
+ nsPerByte = (double)(INT_MAX / opts->maxpktsize);
+ }
+
+ if (maxburst == 0) { /* use default */
+ if (cptime > 10.0 * 1000000)
+ maxburst = 4;
+ else
+ maxburst = 16;
+ }
+ if (minburst == 0) /* use default */
+ minburst = 2;
+ if (minburst > maxburst)
+ minburst = maxburst;
+
+ z = (double)(1 << RM_FILTER_GAIN);
+ g = (1.0 - 1.0 / z);
+ gton = pow(g, (double)maxburst);
+ gtom = pow(g, (double)(minburst-1));
+ maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
+ maxidle_s = (1.0 - g);
+ if (maxidle > maxidle_s)
+ maxidle = ptime * maxidle;
+ else
+ maxidle = ptime * maxidle_s;
+ if (minburst)
+ offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
+ else
+ offtime = cptime;
+ minidle = -((double)opts->maxpktsize * (double)nsPerByte);
+
+ /* scale parameters */
+ maxidle = ((maxidle * 8.0) / nsPerByte) * pow(2, RM_FILTER_GAIN);
+ offtime = (offtime * 8.0) / nsPerByte * pow(2, RM_FILTER_GAIN);
+ minidle = ((minidle * 8.0) / nsPerByte) * pow(2, RM_FILTER_GAIN);
+
+ maxidle = maxidle / 1000.0;
+ offtime = offtime / 1000.0;
+ minidle = minidle / 1000.0;
+
+ opts->minburst = minburst;
+ opts->maxburst = maxburst;
+ opts->ns_per_byte = (u_int) nsPerByte;
+ opts->maxidle = (u_int) fabs(maxidle);
+ opts->minidle = (int)minidle;
+ opts->offtime = (u_int) fabs(offtime);
+
+ return (0);
+}
+
+static int
+check_commit_cbq(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+ int root_class, default_class;
+ int error = 0;
+
+ /*
+ * check if cbq has one root class and one default class
+ * for this interface
+ */
+ root_class = default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
+ root_class++;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
+ default_class++;
+ }
+ if (root_class != 1) {
+ warnx("should have one root class on %s", pa->ifname);
+ error++;
+ }
+ if (default_class != 1) {
+ warnx("should have one default class on %s", pa->ifname);
+ error++;
+ }
+ return (error);
+}
+
+static void
+print_cbq_opts(const struct pf_altq *a)
+{
+ const struct cbq_opts *opts;
+
+ opts = &a->pq_u.cbq_opts;
+
+/* printf(" cbq options: minburst %u maxburst %u"
+ " pktsize %u maxpktsize %u\n",
+ opts->minburst, opts->maxburst,
+ opts->pktsize, opts->maxpktsize);
+
+ printf(" ns_per_byte %u maxidle %u minidle %d offtime %u\n",
+ opts->ns_per_byte, opts->maxidle, opts->minidle, opts->offtime);
+*/
+
+ if (opts->flags) {
+ printf(" cbq(");
+ if (opts->flags & CBQCLF_RED)
+ printf(" red");
+ if (opts->flags & CBQCLF_ECN)
+ printf(" ecn");
+ if (opts->flags & CBQCLF_RIO)
+ printf(" rio");
+ if (opts->flags & CBQCLF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & CBQCLF_FLOWVALVE)
+ printf(" flowvalve");
+ if (opts->flags & CBQCLF_BORROW)
+ printf(" borrow");
+ if (opts->flags & CBQCLF_WRR)
+ printf(" wrr");
+ if (opts->flags & CBQCLF_EFFICIENT)
+ printf(" efficient");
+ if (opts->flags & CBQCLF_ROOTCLASS)
+ printf(" root");
+ if (opts->flags & CBQCLF_DEFCLASS)
+ printf(" default");
+ printf(" )");
+ }
+}
+
+void
+pfctl_insert_altq_node(struct pf_altq_node **root,
+ const struct pf_altq altq)
+{
+ struct pf_altq_node *node;
+
+ node = calloc(1, sizeof(struct pf_altq_node));
+ if (node == NULL) {
+ errx(1, "pfctl_insert_altq_node: calloc");
+ return;
+ }
+ memcpy(&node->altq, &altq, sizeof(struct pf_altq));
+ node->next = node->children = NULL;
+
+ if (*root == NULL)
+ *root = node;
+ else if (!altq.parent[0]) {
+ struct pf_altq_node *prev = *root;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ } else {
+ struct pf_altq_node *parent;
+
+ parent = pfctl_find_altq_node(*root, altq.parent);
+ if (parent == NULL) {
+ errx(1, "parent %s not found", altq.parent);
+ return;
+ }
+ if (parent->children == NULL)
+ parent->children = node;
+ else {
+ struct pf_altq_node *prev = parent->children;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ }
+ }
+}
+
+struct pf_altq_node *
+pfctl_find_altq_node(struct pf_altq_node *root, const char *qname)
+{
+ struct pf_altq_node *node, *child;
+
+ for (node = root; node != NULL; node = node->next) {
+ if (!strcmp(node->altq.qname, qname))
+ return (node);
+ if (node->children != NULL) {
+ child = pfctl_find_altq_node(node->children, qname);
+ if (child != NULL)
+ return (child);
+ }
+ }
+ return (NULL);
+}
+
+void
+pfctl_print_altq_node(const struct pf_altq_node *node, unsigned level)
+{
+ const struct pf_altq_node *child;
+
+ if (node == NULL)
+ return;
+
+ if (node->altq.qname[0])
+ print_altq(&node->altq, level);
+ else
+ print_queue(&node->altq, level);
+
+ if (node->children != NULL) {
+ printf(" {");
+ for (child = node->children; child != NULL;
+ child = child->next) {
+ printf("%s", child->altq.qname);
+ if (child->next != NULL)
+ printf(", ");
+ }
+ printf("}");
+ }
+ printf("\n");
+ for (child = node->children; child != NULL;
+ child = child->next)
+ pfctl_print_altq_node(child, level+2);
+}
+
+void
+pfctl_free_altq_node(struct pf_altq_node *node)
+{
+ while (node != NULL) {
+ struct pf_altq_node *prev;
+
+ if (node->children != NULL)
+ pfctl_free_altq_node(node->children);
+ prev = node;
+ node = node->next;
+ free(prev);
+ }
+}
+
+/*
+ * misc utilities
+ */
+#define R2S_BUFS 8
+#define RATESTR_MAX 16
+static char *
+rate2str(double rate)
+{
+ char *buf;
+ static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
+ static int idx = 0;
+
+ buf = r2sbuf[idx++];
+ if (idx == R2S_BUFS)
+ idx = 0;
+
+ if (rate == 0.0)
+ snprintf(buf, RATESTR_MAX, "0");
+ else if (rate >= 1024 * 1024)
+ snprintf(buf, RATESTR_MAX, "%.2fMb", rate / (1024.0 * 1024.0));
+ else if (rate >= 1024)
+ snprintf(buf, RATESTR_MAX, "%.2fKb", rate / 1024.0);
+ else
+ snprintf(buf, RATESTR_MAX, "%db", (int)rate);
+ return (buf);
+}
diff --git a/sbin/pfctl/pfctl_altq.h b/sbin/pfctl/pfctl_altq.h
new file mode 100644
index 00000000000..a4288ad0449
--- /dev/null
+++ b/sbin/pfctl/pfctl_altq.h
@@ -0,0 +1,104 @@
+/* $OpenBSD: pfctl_altq.h,v 1.1 2002/11/18 22:49:15 henning Exp $ */
+/*
+ * Copyright (C) 2002
+ * Sony Computer Science Laboratories Inc. All rights reserved.
+ * Copyright (C) 2002 Henning Brauer. All rights reserved.
+ *
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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.
+ */
+
+/*
+ * misc defines needed by pfctl(8) for altq
+ * (copied from altq headers until we find a better way...)
+ */
+#ifndef ALTQT_NONE
+/* altq discipline type */
+#define ALTQT_NONE 0 /* reserved */
+#define ALTQT_CBQ 1 /* cbq */
+#define ALTQT_WFQ 2 /* wfq */
+#define ALTQT_AFMAP 3 /* afmap */
+#define ALTQT_FIFOQ 4 /* fifoq */
+#define ALTQT_RED 5 /* red */
+#define ALTQT_RIO 6 /* rio */
+#define ALTQT_LOCALQ 7 /* local use */
+#define ALTQT_HFSC 8 /* hfsc */
+#define ALTQT_CDNR 9 /* traffic conditioner */
+#define ALTQT_BLUE 10 /* blue */
+#define ALTQT_PRIQ 11 /* priority queue */
+#define ALTQT_MAX 12 /* should be max discipline type + 1 */
+#endif
+
+#ifndef CBQCLF_RED
+/* class flags shoud be same as class flags in rm_class.h */
+#define CBQCLF_RED 0x0001 /* use RED */
+#define CBQCLF_ECN 0x0002 /* use RED/ECN */
+#define CBQCLF_RIO 0x0004 /* use RIO */
+#define CBQCLF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */
+#define CBQCLF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
+#define CBQCLF_BORROW 0x0020 /* borrow from parent */
+
+/* class flags only for root class */
+#define CBQCLF_WRR 0x0100 /* weighted-round robin */
+#define CBQCLF_EFFICIENT 0x0200 /* work-conserving */
+
+/* class flags for special classes */
+#define CBQCLF_ROOTCLASS 0x1000 /* root class */
+#define CBQCLF_DEFCLASS 0x2000 /* default class */
+#define CBQCLF_CTLCLASS 0x4000 /* control class */
+#define CBQCLF_CLASSMASK 0xf000 /* class mask */
+#endif
+
+#ifndef REDF_ECN4
+/* red flags */
+#define REDF_ECN4 0x01 /* use packet marking for IPv4 packets */
+#define REDF_ECN6 0x02 /* use packet marking for IPv6 packets */
+#define REDF_ECN (REDF_ECN4 | REDF_ECN6)
+#define REDF_FLOWVALVE 0x04 /* use flowvalve (aka penalty-box) */
+#endif
+
+struct pf_altq_node {
+ struct pf_altq altq;
+ struct pf_altq_node *next;
+ struct pf_altq_node *children;
+};
+
+void pfctl_insert_altq_node(struct pf_altq_node **,
+ const struct pf_altq);
+struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
+ const char *);
+void pfctl_print_altq_node(const struct pf_altq_node *,
+ unsigned);
+void pfctl_free_altq_node(struct pf_altq_node *);
+
+int check_commit_altq(int, int);
+void pfaltq_store(struct pf_altq *);
+void pfaltq_free(struct pf_altq *);
+struct pf_altq *pfaltq_lookup(const char *);
+struct pf_altq *qname_to_pfaltq(const char *, const char *);
+u_int32_t qname_to_qid(const char *, const char *);
+char *qid_to_qname(u_int32_t, const char *);
+
+void print_altq(const struct pf_altq *, unsigned);
+void print_queue(const struct pf_altq *, unsigned);
+
+int eval_pfaltq(struct pfctl *, struct pf_altq *);
+int eval_pfqueue(struct pfctl *, struct pf_altq *, u_int32_t, u_int16_t);
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 6181a438eec..0400f34c4ae 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.102 2002/10/25 10:40:45 camield Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.103 2002/11/18 22:49:15 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -811,6 +811,8 @@ print_rule(struct pf_rule *r)
}
if (r->label[0])
printf("label %s", r->label);
+ if (r->qname[0])
+ printf("queue %s", r->qname);
printf("\n");
}
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 774a7dee882..29c30e3685f 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.26 2002/10/25 10:40:45 camield Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.27 2002/11/18 22:49:15 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -61,12 +61,15 @@ struct pfctl {
struct pfioc_nat *pnat;
struct pfioc_binat *pbinat;
struct pfioc_rdr *prdr;
+ struct pfioc_altq *paltq;
+ struct pfioc_queue *pqueue;
};
int pfctl_add_rule(struct pfctl *, struct pf_rule *);
int pfctl_add_nat(struct pfctl *, struct pf_nat *);
int pfctl_add_binat(struct pfctl *, struct pf_binat *);
int pfctl_add_rdr(struct pfctl *, struct pf_rdr *);
+int pfctl_add_altq(struct pfctl *, struct pf_altq *);
int pfctl_set_timeout(struct pfctl *, const char *, int);
int pfctl_set_optimization(struct pfctl *, const char *);
@@ -109,6 +112,7 @@ struct pf_timeout {
#define PFCTL_FLAG_FILTER 0x02
#define PFCTL_FLAG_NAT 0x04
#define PFCTL_FLAG_OPTION 0x08
+#define PFCTL_FLAG_ALTQ 0x10
extern const struct pf_timeout pf_timeouts[];