summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/pf_lb.c101
1 files changed, 78 insertions, 23 deletions
diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c
index 70e6d9dc3f0..d129a54eaf6 100644
--- a/sys/net/pf_lb.c
+++ b/sys/net/pf_lb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_lb.c,v 1.23 2012/12/29 14:54:45 markus Exp $ */
+/* $OpenBSD: pf_lb.c,v 1.24 2012/12/29 14:59:52 markus Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -106,6 +106,10 @@ int pf_get_sport(struct pf_pdesc *, struct pf_rule *,
u_int16_t, struct pf_src_node **);
int pf_get_transaddr_af(struct pf_rule *,
struct pf_pdesc *, struct pf_src_node **);
+int pf_map_addr_sticky(sa_family_t, struct pf_rule *,
+ struct pf_addr *, struct pf_addr *,
+ struct pf_src_node **, struct pf_pool *,
+ enum pf_sn_types);
#define mix(a,b,c) \
do { \
@@ -268,6 +272,76 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
}
int
+pf_map_addr_sticky(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
+ struct pf_addr *naddr, struct pf_src_node **sns, struct pf_pool *rpool,
+ enum pf_sn_types type)
+{
+ struct pf_addr *raddr, *rmask, *cached;
+ struct pf_state *s;
+ struct pf_src_node k;
+ int valid;
+
+ k.af = af;
+ k.type = type;
+ PF_ACPY(&k.addr, saddr, af);
+ k.rule.ptr = r;
+ pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
+ sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
+ if (sns[type] == NULL)
+ return (-1);
+
+ /* check if the cached entry is still valid */
+ cached = &(sns[type])->raddr;
+ valid = 0;
+ if (PF_AZERO(cached, af)) {
+ valid = 1;
+ } else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
+ if (pfr_kentry_byaddr(rpool->addr.p.dyn->pfid_kt, cached,
+ af, 0))
+ valid = 1;
+ } else if (rpool->addr.type == PF_ADDR_TABLE) {
+ if (pfr_kentry_byaddr(rpool->addr.p.tbl, cached, af, 0))
+ valid = 1;
+ } else if (rpool->addr.type != PF_ADDR_NOROUTE) {
+ raddr = &rpool->addr.v.a.addr;
+ rmask = &rpool->addr.v.a.mask;
+ valid = pf_match_addr(0, raddr, rmask, cached, af);
+ }
+ if (!valid) {
+ if (pf_status.debug >= LOG_DEBUG) {
+ log(LOG_DEBUG, "pf: pf_map_addr: "
+ "stale src tracking (%u) ", type);
+ pf_print_host(&k.addr, 0, af);
+ addlog(" to ");
+ pf_print_host(cached, 0, af);
+ addlog("\n");
+ }
+ if (sns[type]->states != 0) {
+ /* XXX expensive */
+ RB_FOREACH(s, pf_state_tree_id,
+ &tree_id)
+ pf_state_rm_src_node(s,
+ sns[type]);
+ }
+ sns[type]->expire = 1;
+ pf_remove_src_node(sns[type]);
+ sns[type] = NULL;
+ return (-1);
+ }
+ if (!PF_AZERO(cached, af))
+ PF_ACPY(naddr, cached, af);
+ if (pf_status.debug >= LOG_DEBUG) {
+ log(LOG_DEBUG, "pf: pf_map_addr: "
+ "src tracking (%u) maps ", type);
+ pf_print_host(&k.addr, 0, af);
+ addlog(" to ");
+ pf_print_host(naddr, 0, af);
+ addlog("\n");
+ }
+ return (0);
+}
+
+int
pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sns,
struct pf_pool *rpool, enum pf_sn_types type)
@@ -276,34 +350,15 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
struct pf_addr faddr;
struct pf_addr *raddr = &rpool->addr.v.a.addr;
struct pf_addr *rmask = &rpool->addr.v.a.mask;
- struct pf_src_node k;
u_int64_t states;
u_int16_t weight;
u_int64_t load;
u_int64_t cload;
if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR &&
- (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
- k.af = af;
- k.type = type;
- PF_ACPY(&k.addr, saddr, af);
- k.rule.ptr = r;
- pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
- sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
- if (sns[type] != NULL) {
- if (!PF_AZERO(&(sns[type])->raddr, af))
- PF_ACPY(naddr, &(sns[type])->raddr, af);
- if (pf_status.debug >= LOG_DEBUG) {
- log(LOG_DEBUG, "pf: pf_map_addr: "
- "src tracking (%u) maps ", type);
- pf_print_host(&k.addr, 0, af);
- addlog(" to ");
- pf_print_host(naddr, 0, af);
- addlog("\n");
- }
- return (0);
- }
- }
+ (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE &&
+ pf_map_addr_sticky(af, r, saddr, naddr, sns, rpool, type) == 0)
+ return (0);
if (rpool->addr.type == PF_ADDR_NOROUTE)
return (1);