summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2011-07-27 00:26:11 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2011-07-27 00:26:11 +0000
commit68db64f6aa38ae259e5795c3322e6406af0b0879 (patch)
tree1efad0ea2cb6f49698ddd244204b7f56d3b084d4 /sbin
parent05eda0b2c9cbf976e3527833943b961079ab7cb8 (diff)
Add support for weighted round-robin in load balancing pools and tables.
Diff from zinke@ with a some minor cleanup. ok henning claudio deraadt
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pfctl/parse.y103
-rw-r--r--sbin/pfctl/pfctl.h5
-rw-r--r--sbin/pfctl/pfctl_optimize.c3
-rw-r--r--sbin/pfctl/pfctl_parser.c50
-rw-r--r--sbin/pfctl/pfctl_parser.h3
-rw-r--r--sbin/pfctl/pfctl_radix.c11
-rw-r--r--sbin/pfctl/pfctl_table.c19
7 files changed, 155 insertions, 39 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index de30e7c443e..11ffd536617 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.605 2011/07/13 20:57:10 mcbride Exp $ */
+/* $OpenBSD: parse.y,v 1.606 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -380,6 +380,7 @@ typedef struct {
int i;
char *string;
u_int rtableid;
+ u_int16_t weight;
struct {
u_int8_t b1;
u_int8_t b2;
@@ -451,6 +452,7 @@ int parseport(char *, struct range *r, int);
%token SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR INCLUDE MATCHES
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN LEASTSTATES STATICPORT PROBABILITY
+%token WEIGHT
%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
%token QUEUE PRIORITY QLIMIT RTABLE RDOMAIN
%token LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO
@@ -465,6 +467,7 @@ int parseport(char *, struct range *r, int);
%type <v.number> number icmptype icmp6type uid gid
%type <v.number> tos not yesno optnodf
%type <v.probability> probability
+%type <v.weight> optweight
%type <v.i> dir af optimizer
%type <v.i> sourcetrack flush unaryop statelock
%type <v.b> action
@@ -480,6 +483,7 @@ int parseport(char *, struct range *r, int);
%type <v.fromto> fromto
%type <v.peer> ipportspec from to
%type <v.host> ipspec xhost host dynaddr host_list
+%type <v.host> table_host_list tablespec
%type <v.host> redir_host_list redirspec
%type <v.host> route_host route_host_list routespec
%type <v.os> os xos os_list
@@ -1190,8 +1194,6 @@ table_opt : STRING {
table_opts.flags |= PFR_TFLAG_PERSIST;
else if (!strcmp($1, "counters"))
table_opts.flags |= PFR_TFLAG_COUNTERS;
- else if (!strcmp($1, "cost"))
- table_opts.flags |= PFR_TFLAG_COST;
else {
yyerror("invalid table option '%s'", $1);
free($1);
@@ -1200,7 +1202,7 @@ table_opt : STRING {
free($1);
}
| '{' optnl '}' { table_opts.init_addr = 1; }
- | '{' optnl host_list '}' {
+ | '{' optnl table_host_list '}' {
struct node_host *n;
struct node_tinit *ti;
@@ -1252,6 +1254,25 @@ table_opt : STRING {
}
;
+tablespec : xhost optweight {
+ if ($2 > 0) {
+ struct node_host *n;
+ for (n = $1; n != NULL; n = n->next)
+ n->weight = $2;
+ }
+ $$ = $1;
+ }
+ | '{' optnl table_host_list '}' { $$ = $3; }
+ ;
+
+table_host_list : tablespec optnl { $$ = $1; }
+ | table_host_list comma tablespec optnl {
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ ;
+
altqif : ALTQ interface queue_opts QUEUE qassign {
struct pf_altq a;
@@ -2269,6 +2290,8 @@ filter_opt : USER uids {
filter_opts.route.host = $2;
filter_opts.route.rt = PF_DUPTO;
filter_opts.route.pool_opts = $3.type | $3.opts;
+ memcpy(&filter_opts.rroute.pool_opts, &$3,
+ sizeof(filter_opts.rroute.pool_opts));
if ($3.key != NULL)
filter_opts.route.key = $3.key;
}
@@ -2675,6 +2698,7 @@ ipspec : ANY { $$ = NULL; }
| '{' optnl host_list '}' { $$ = $3; }
;
+
host_list : ipspec optnl { $$ = $1; }
| host_list comma ipspec optnl {
if ($1 == NULL) {
@@ -2717,6 +2741,16 @@ xhost : not host {
$$->tail = $$;
}
;
+
+optweight : WEIGHT NUMBER {
+ if ($2 < 1 || $2 > USHRT_MAX) {
+ yyerror("weight out of range");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ | /* empty */ { $$ = 0; }
+ ;
host : STRING {
if (($$ = host($1)) == NULL) {
@@ -3572,22 +3606,39 @@ portstar : numberstring {
}
;
-redirspec : host { $$ = $1; }
+redirspec : host optweight {
+ if ($2 > 0) {
+ struct node_host *n;
+ for (n = $1; n != NULL; n = n->next)
+ n->weight = $2;
+ }
+ $$ = $1;
+ }
| '{' optnl redir_host_list '}' { $$ = $3; }
;
-redir_host_list : host optnl {
+redir_host_list : host optweight optnl {
if ($1->addr.type != PF_ADDR_ADDRMASK) {
free($1);
yyerror("only addresses can be listed for"
"redirection pools ");
YYERROR;
}
+ if ($2 > 0) {
+ struct node_host *n;
+ for (n = $1; n != NULL; n = n->next)
+ n->weight = $2;
+ }
$$ = $1;
}
- | redir_host_list comma host optnl {
+ | redir_host_list comma host optweight optnl {
$1->tail->next = $3;
$1->tail = $3->tail;
+ if ($4 > 0) {
+ struct node_host *n;
+ for (n = $3; n != NULL; n = n->next)
+ n->weight = $4;
+ }
$$ = $1;
}
;
@@ -3804,8 +3855,15 @@ route_host : STRING {
}
;
-route_host_list : route_host optnl { $$ = $1; }
- | route_host_list comma route_host optnl {
+route_host_list : route_host optweight optnl {
+ if ($2 > 0) {
+ struct node_host *n;
+ for (n = $1; n != NULL; n = n->next)
+ n->weight = $2;
+ }
+ $$ = $1;
+ }
+ | route_host_list comma route_host optweight optnl {
if ($1->af == 0)
$1->af = $3->af;
if ($1->af != $3->af) {
@@ -3815,11 +3873,23 @@ route_host_list : route_host optnl { $$ = $1; }
}
$1->tail->next = $3;
$1->tail = $3->tail;
+ if ($4 > 0) {
+ struct node_host *n;
+ for (n = $3; n != NULL; n = n->next)
+ n->weight = $4;
+ }
$$ = $1;
}
;
-routespec : route_host { $$ = $1; }
+routespec : route_host optweight {
+ if ($2 > 0) {
+ struct node_host *n;
+ for (n = $1; n != NULL; n = n->next)
+ n->weight = $2;
+ }
+ $$ = $1;
+ }
| '{' optnl route_host_list '}' { $$ = $3; }
;
@@ -4057,7 +4127,7 @@ process_tabledef(char *name, struct table_opts *opts)
ab.pfrb_type = PFRB_ADDRS;
SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
if (ti->file)
- if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
+ if (pfr_buf_load(&ab, ti->file, 0)) {
if (errno)
yyerror("cannot load \"%s\": %s",
ti->file, strerror(errno));
@@ -4576,8 +4646,8 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r,
return (0);
} else { /* more than one address */
if (rs->pool_opts.type &&
- (rs->pool_opts.type != PF_POOL_ROUNDROBIN) &&
- (rs->pool_opts.type != PF_POOL_LEASTSTATES)) {
+ (rs->pool_opts.type != PF_POOL_ROUNDROBIN) &&
+ (rs->pool_opts.type != PF_POOL_LEASTSTATES)) {
yyerror("only round-robin or "
"least-states valid for multiple "
"translation or routing addresses");
@@ -4598,15 +4668,13 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r,
}
memset(&ra, 0, sizeof(ra));
ra.addr = h->addr;
+ ra.weight = h->weight;
if (add_opt_table(pf, &tbl,
h->af, &ra, h->ifname))
return (1);
- }
+ }
}
if (tbl) {
- if (rs->pool_opts.type == PF_POOL_LEASTSTATES)
- tbl->pt_flags |= PFR_TFLAG_COST;
-
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
pf_opt_create_table(pf, tbl))
return (1);
@@ -5150,6 +5218,7 @@ lookup(char *s)
{ "upperlimit", UPPERLIMIT},
{ "urpf-failed", URPFFAILED},
{ "user", USER},
+ { "weight", WEIGHT},
};
const struct keywords *p;
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index ad17fbde8b7..87e0362dca0 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.h,v 1.46 2010/11/12 13:14:41 claudio Exp $ */
+/* $OpenBSD: pfctl.h,v 1.47 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -69,8 +69,7 @@ void pfr_buf_clear(struct pfr_buffer *);
int pfr_buf_add(struct pfr_buffer *, const void *);
void *pfr_buf_next(struct pfr_buffer *, const void *);
int pfr_buf_grow(struct pfr_buffer *, int);
-int pfr_buf_load(struct pfr_buffer *, char *, int,
- int (*)(struct pfr_buffer *, char *, int));
+int pfr_buf_load(struct pfr_buffer *, char *, int);
char *pfr_strerror(int);
int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
int pfi_clr_istats(const char *, int *, int);
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index 72959bfdc95..2a333565ad4 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_optimize.c,v 1.28 2011/07/07 00:47:19 mcbride Exp $ */
+/* $OpenBSD: pfctl_optimize.c,v 1.29 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
@@ -1231,6 +1231,7 @@ add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
node_host.af = af;
node_host.addr = addr->addr;
node_host.ifname = ifname;
+ node_host.weight = addr->weight;
#ifdef OPT_DEBUG
DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af,
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 3e6d1064779..4ad8c50e9e9 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.278 2011/07/08 18:52:47 henning Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.279 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -1092,8 +1092,6 @@ print_tabledef(const char *name, int flags, int addrs,
printf(" persist");
if (flags & PFR_TFLAG_COUNTERS)
printf(" counters");
- if (flags & PFR_TFLAG_COST)
- printf(" cost");
SIMPLEQ_FOREACH(ti, nodes, entries) {
if (ti->file) {
printf(" file \"%s\"", ti->file);
@@ -1450,7 +1448,6 @@ ifa_skip_if(const char *filter, struct node_host *p)
return (p->ifname[n] < '0' || p->ifname[n] > '9');
}
-
struct node_host *
host(const char *s)
{
@@ -1509,8 +1506,10 @@ host(const char *s)
fprintf(stderr, "no IP address found for %s\n", s);
return (NULL);
}
- for (n = h; n != NULL; n = n->next)
+ for (n = h; n != NULL; n = n->next) {
n->addr.type = PF_ADDR_ADDRMASK;
+ n->weight = 0;
+ }
return (h);
}
@@ -1702,9 +1701,41 @@ host_dns(const char *s, int v4mask, int v6mask)
int
append_addr(struct pfr_buffer *b, char *s, int test)
{
- char *r;
+ static int previous = 0;
+ static int expect = 0;
+ struct pfr_addr *a;
struct node_host *h, *n;
- int rv, not = 0;
+ char *r;
+ const char *errstr;
+ int rv, not = 0, i = 0;
+ u_int16_t weight;
+
+ /* skip weight if given */
+ if (strcmp(s, "weight") == 0) {
+ expect = 1;
+ return (1); /* expecting further call */
+ }
+
+ /* check if previous host is set */
+ if (expect) {
+ /* parse and append load balancing weight */
+ weight = strtonum(s, 1, USHRT_MAX, &errstr);
+ if (errstr) {
+ fprintf(stderr, "failed to convert weight %s\n", s);
+ return (-1);
+ }
+ if (previous != -1) {
+ PFRB_FOREACH(a, b) {
+ if (++i >= previous) {
+ a->pfra_weight = weight;
+ a->pfra_type = PFRKE_COST;
+ }
+ }
+ }
+
+ expect = 0;
+ return (0);
+ }
for (r = s; *r == '!'; r++)
not = !not;
@@ -1713,6 +1744,7 @@ append_addr(struct pfr_buffer *b, char *s, int test)
return (-1);
}
rv = append_addr_host(b, n, test, not);
+ previous = b->pfrb_size;
do {
h = n;
n = n->next;
@@ -1744,6 +1776,10 @@ append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
errx(1, "append_addr_host: strlcpy");
addr.pfra_type = PFRKE_ROUTE;
}
+ if (n->weight > 0) {
+ addr.pfra_weight = n->weight;
+ addr.pfra_type = PFRKE_COST;
+ }
switch (n->af) {
case AF_INET:
addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 7d27dba9cf1..9359c4edff4 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.96 2011/07/03 23:37:55 zinke Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.97 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -117,6 +117,7 @@ struct node_host {
sa_family_t af;
u_int8_t not;
u_int32_t ifindex; /* link-local IPv6 addrs */
+ u_int16_t weight; /* load balancing weight */
char *ifname;
u_int ifa_flags;
struct node_host *next;
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index becd0305b83..1fced17e5c5 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_radix.c,v 1.28 2007/12/05 12:01:47 chl Exp $ */
+/* $OpenBSD: pfctl_radix.c,v 1.29 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -46,6 +46,7 @@
#include <err.h>
#include "pfctl.h"
+#include "pfctl_parser.h"
#define BUF_SIZE 256
@@ -505,12 +506,12 @@ pfr_buf_clear(struct pfr_buffer *b)
}
int
-pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
- int (*append_addr)(struct pfr_buffer *, char *, int))
+pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork)
{
FILE *fp;
char buf[BUF_SIZE];
int rv;
+ int ev = 0;
if (file == NULL)
return (0);
@@ -522,10 +523,12 @@ pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
return (-1);
}
while ((rv = pfr_next_token(buf, fp)) == 1)
- if (append_addr(b, buf, nonetwork)) {
+ if ((ev = append_addr(b, buf, nonetwork)) == -1) {
rv = -1;
break;
}
+ if (ev == 1) /* expected further append_addr call */
+ rv = -1;
if (fp != stdin)
fclose(fp);
return (rv);
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index bbdc4e660db..002da62c708 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_table.c,v 1.70 2011/07/03 23:37:55 zinke Exp $ */
+/* $OpenBSD: pfctl_table.c,v 1.71 2011/07/27 00:26:10 mcbride Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -411,13 +411,18 @@ int
load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
int nonetwork)
{
+ int ev = 0;
while (argc--)
- if (append_addr(b, *argv++, nonetwork)) {
+ if ((ev = append_addr(b, *argv++, nonetwork)) == -1) {
if (errno)
warn("cannot decode %s", argv[-1]);
return (-1);
}
- if (pfr_buf_load(b, file, nonetwork, append_addr)) {
+ if (ev == 1) { /* expected further append_addr call */
+ warnx("failed to decode %s", argv[-1]);
+ return (-1);
+ }
+ if (pfr_buf_load(b, file, nonetwork)) {
warn("cannot load %s", file);
return (-1);
}
@@ -479,12 +484,14 @@ print_astats(struct pfr_astats *as, int dns)
print_addrx(&as->pfras_a, NULL, dns);
printf("\tCleared: %s", ctime(&time));
- if (as->pfras_a.pfra_type == PFRKE_COST)
+ if (as->pfras_a.pfra_states)
printf("\tActive States: %d\n", as->pfras_a.pfra_states);
- if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT)
- return;
+ if (as->pfras_a.pfra_type == PFRKE_COST)
+ printf("\tWeight: %d\n", as->pfras_a.pfra_weight);
if (as->pfras_a.pfra_ifname[0])
printf("\tInterface: %s\n", as->pfras_a.pfra_ifname);
+ if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT)
+ return;
for (dir = 0; dir < PFR_DIR_MAX; dir++)
for (op = 0; op < PFR_OP_ADDR_MAX; op++)
printf("\t%-19s [ Packets: %-18llu Bytes: %-18llu ]\n",