From: reyk Date: Fri, 19 Dec 2014 13:04:07 +0000 (+0000) Subject: Support source-hash and random with tables and dynifs; not just pools. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=252a05523f8b93e11ba02b8ef3b3a195bb685de2;p=openbsd Support source-hash and random with tables and dynifs; not just pools. This finally allows to use source-hash for dynamic loadbalancing, eg. "rdr-to source-hash", instead of just round-robin and least-states. An older pre-siphash version of this diff was tested by many people. OK tedu@ benno@ --- diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index db77052e997..083c2ddbb73 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.642 2014/11/20 05:51:20 jsg Exp $ */ +/* $OpenBSD: parse.y,v 1.643 2014/12/19 13:04:07 reyk Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -1805,13 +1805,9 @@ pfrule : action dir logquick interface af proto fromto DYNIF_MULTIADDR($8.route.host->addr))) r.route.opts |= PF_POOL_ROUNDROBIN; if ($8.route.host->next != NULL) { - if (((r.route.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) && - ((r.route.opts & PF_POOL_TYPEMASK) != - PF_POOL_LEASTSTATES)) { - yyerror("r.route.opts must " - "be PF_POOL_ROUNDROBIN " - "or PF_POOL_LEASTSTATES"); + if (!PF_POOL_DYNTYPE(r.route.opts)) { + yyerror("address pool option " + "not supported by type"); YYERROR; } } @@ -4387,10 +4383,8 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, hprev = h; /* in case we need to conver to a table */ } else { /* multiple hosts */ if (rs->pool_opts.type && - (rs->pool_opts.type != PF_POOL_ROUNDROBIN) && - (rs->pool_opts.type != PF_POOL_LEASTSTATES)) { - yyerror("only round-robin or " - "least-states valid for multiple " + !PF_POOL_DYNTYPE(rs->pool_opts.type)) { + yyerror("pool type is not valid for multiple " "translation or routing addresses"); return (1); } @@ -4488,16 +4482,16 @@ apply_redirspec(struct pf_pool *rpool, struct pf_rule *r, struct redirspec *rs, } rpool->opts = rs->pool_opts.type; - if (rpool->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR(rpool->addr)) + if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_NONE && + (rpool->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR(rpool->addr))) rpool->opts |= PF_POOL_ROUNDROBIN; - if (((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) && - ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES) && - (disallow_table(rs->rdr->host, "tables are only supported " - "in round-robin or least-states address pools") || - disallow_alias(rs->rdr->host, "interface (%s) is only supported " - "in round-robin or least-states address pools"))) + if (!PF_POOL_DYNTYPE(rpool->opts) && + (disallow_table(rs->rdr->host, + "tables are not supported by pool type") || + disallow_alias(rs->rdr->host, + "interface (%s) is not supported by pool type"))) return (1); if (rs->pool_opts.key != NULL) diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 index 2ca907fe35e..4c6b2c8cd1c 100644 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.conf.5,v 1.539 2014/10/23 20:38:37 kspillner Exp $ +.\" $OpenBSD: pf.conf.5,v 1.540 2014/12/19 13:04:08 reyk Exp $ .\" .\" Copyright (c) 2002, Daniel Hartmeier .\" Copyright (c) 2003 - 2013 Henning Brauer @@ -28,7 +28,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: October 23 2014 $ +.Dd $Mdocdate: December 19 2014 $ .Dt PF.CONF 5 .Os .Sh NAME @@ -1034,10 +1034,8 @@ from modifying the source port on TCP and UDP packets. .El .Pp When more than one redirection address or a table is specified, -.Ar round-robin -and -.Ar least-states -are the only permitted pool types. +.Ar bitmask +is not permitted as a pool type. .Ss Routing If a packet matches a rule with one of the following route options set, the packet filter will route the packet according to the type of route option. @@ -1566,10 +1564,8 @@ They can also be used for the redirect address of .Ar nat-to and .Ar rdr-to -and in the routing options of filter rules, but only for -.Ar least-states -and -.Ar round-robin +and in the routing options of filter rules, but not for +.Ar bitmask pools. .Pp Tables can be defined with any of the following diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c index e08b4092e94..bd7180c02c0 100644 --- a/sys/net/pf_lb.c +++ b/sys/net/pf_lb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_lb.c,v 1.38 2014/12/19 12:31:03 mcbride Exp $ */ +/* $OpenBSD: pf_lb.c,v 1.39 2014/12/19 13:04:08 reyk Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -92,7 +92,7 @@ * Global variables */ -void pf_hash(struct pf_addr *, struct pf_addr *, +u_int64_t pf_hash(struct pf_addr *, struct pf_addr *, struct pf_poolhashkey *, sa_family_t); int pf_get_sport(struct pf_pdesc *, struct pf_rule *, struct pf_addr *, u_int16_t *, u_int16_t, @@ -104,10 +104,11 @@ int pf_map_addr_sticky(sa_family_t, struct pf_rule *, struct pf_src_node **, struct pf_pool *, enum pf_sn_types); -void +u_int64_t pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, struct pf_poolhashkey *key, sa_family_t af) { + uint64_t res = 0; #ifdef INET6 union { uint64_t hash64; @@ -118,14 +119,16 @@ pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, switch (af) { #ifdef INET case AF_INET: - hash->addr32[0] = SipHash24((SIPHASH_KEY *)key, + res = SipHash24((SIPHASH_KEY *)key, &inaddr->addr32[0], sizeof(inaddr->addr32[0])); + hash->addr32[0] = res; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - h.hash64 = SipHash24((SIPHASH_KEY *)key, &inaddr->addr32[0], + res = SipHash24((SIPHASH_KEY *)key, &inaddr->addr32[0], 4 * sizeof(inaddr->addr32[0])); + h.hash64 = res; hash->addr32[0] = h.hash32[0]; hash->addr32[1] = h.hash32[1]; /* @@ -137,6 +140,7 @@ pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, break; #endif /* INET6 */ } + return (res); } int @@ -337,6 +341,8 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, u_int16_t weight; u_int64_t load; u_int64_t cload; + u_int64_t hashidx; + int cnt; if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE && @@ -350,10 +356,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, #ifdef INET case AF_INET: if (rpool->addr.p.dyn->pfid_acnt4 < 1 && - ((rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) && - ((rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_LEASTSTATES)) + !PF_POOL_DYNTYPE(rpool->opts)) return (1); raddr = &rpool->addr.p.dyn->pfid_addr4; rmask = &rpool->addr.p.dyn->pfid_mask4; @@ -362,10 +365,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, #ifdef INET6 case AF_INET6: if (rpool->addr.p.dyn->pfid_acnt6 < 1 && - ((rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) && - ((rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_LEASTSTATES)) + !PF_POOL_DYNTYPE(rpool->opts)) return (1); raddr = &rpool->addr.p.dyn->pfid_addr6; rmask = &rpool->addr.p.dyn->pfid_mask6; @@ -373,8 +373,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, #endif /* INET6 */ } } else if (rpool->addr.type == PF_ADDR_TABLE) { - if (((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) && - ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES)) + if (!PF_POOL_DYNTYPE(rpool->opts)) return (1); /* unsupported */ } else { raddr = &rpool->addr.v.a.addr; @@ -389,7 +388,21 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, PF_POOLMASK(naddr, raddr, rmask, saddr, af); break; case PF_POOL_RANDOM: - if (init_addr != NULL && PF_AZERO(init_addr, af)) { + if (rpool->addr.type == PF_ADDR_TABLE) { + cnt = rpool->addr.p.tbl->pfrkt_cnt; + rpool->tblidx = (int)arc4random_uniform(cnt); + memset(&rpool->counter, 0, sizeof(rpool->counter)); + if (pfr_pool_get(rpool, &raddr, &rmask, af)) + return (1); + PF_ACPY(naddr, &rpool->counter, af); + } else if (rpool->addr.type == PF_ADDR_DYNIFTL) { + cnt = rpool->addr.p.dyn->pfid_kt->pfrkt_cnt; + rpool->tblidx = (int)arc4random_uniform(cnt); + memset(&rpool->counter, 0, sizeof(rpool->counter)); + if (pfr_pool_get(rpool, &raddr, &rmask, af)) + return (1); + PF_ACPY(naddr, &rpool->counter, af); + } else if (init_addr != NULL && PF_AZERO(init_addr, af)) { switch (af) { #ifdef INET case AF_INET: @@ -428,8 +441,26 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, } break; case PF_POOL_SRCHASH: - pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); - PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af); + hashidx = + pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); + if (rpool->addr.type == PF_ADDR_TABLE) { + cnt = rpool->addr.p.tbl->pfrkt_cnt; + rpool->tblidx = (int)(hashidx % cnt); + memset(&rpool->counter, 0, sizeof(rpool->counter)); + if (pfr_pool_get(rpool, &raddr, &rmask, af)) + return (1); + PF_ACPY(naddr, &rpool->counter, af); + } else if (rpool->addr.type == PF_ADDR_DYNIFTL) { + cnt = rpool->addr.p.dyn->pfid_kt->pfrkt_cnt; + rpool->tblidx = (int)(hashidx % cnt); + memset(&rpool->counter, 0, sizeof(rpool->counter)); + if (pfr_pool_get(rpool, &raddr, &rmask, af)) + return (1); + PF_ACPY(naddr, &rpool->counter, af); + } else { + PF_POOLMASK(naddr, raddr, rmask, + (struct pf_addr *)&hash, af); + } break; case PF_POOL_ROUNDROBIN: if (rpool->addr.type == PF_ADDR_TABLE || diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 25700e1f95c..08f6a98534e 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.404 2014/12/19 05:36:28 tedu Exp $ */ +/* $OpenBSD: pfvar.h,v 1.405 2014/12/19 13:04:08 reyk Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -118,6 +118,12 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, #define PF_WSCALE_FLAG 0x80 #define PF_WSCALE_MASK 0x0f +#define PF_POOL_DYNTYPE(_o) \ + ((((_o) & PF_POOL_TYPEMASK) == PF_POOL_ROUNDROBIN) || \ + (((_o) & PF_POOL_TYPEMASK) == PF_POOL_LEASTSTATES) || \ + (((_o) & PF_POOL_TYPEMASK) == PF_POOL_RANDOM) || \ + (((_o) & PF_POOL_TYPEMASK) == PF_POOL_SRCHASH)) + #define PF_LOG 0x01 #define PF_LOG_ALL 0x02 #define PF_LOG_SOCKET_LOOKUP 0x04