aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2014-02-19 22:02:15 +0000
committerMartin Matuska <mm@FreeBSD.org>2014-02-19 22:02:15 +0000
commit5748b897da441d1f10e1fe0c39155ea33d6d383a (patch)
tree7c8754b66fd2a59523982c11a17a367cbfcb1520 /sys/netpfil
parent654957c2c861b1483df873678439699c0dfeeb94 (diff)
parent2067168264b9ab5abb628187a3c56180e7767e7b (diff)
downloadsrc-5748b897da441d1f10e1fe0c39155ea33d6d383a.tar.gz
src-5748b897da441d1f10e1fe0c39155ea33d6d383a.zip
Merge head up to r262222 (last merge was incomplete).
Notes
Notes: svn path=/projects/pf/head/; revision=262234
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/ipfw/dn_sched.h1
-rw-r--r--sys/netpfil/ipfw/dummynet.txt4
-rw-r--r--sys/netpfil/ipfw/ip_dn_io.c30
-rw-r--r--sys/netpfil/ipfw/ip_dn_private.h1
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c49
-rw-r--r--sys/netpfil/ipfw/ip_fw_dynamic.c37
-rw-r--r--sys/netpfil/ipfw/ip_fw_log.c7
-rw-r--r--sys/netpfil/ipfw/ip_fw_nat.c2
-rw-r--r--sys/netpfil/ipfw/ip_fw_pfil.c8
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h18
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c4
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c8
-rw-r--r--sys/netpfil/pf/if_pfsync.c16
-rw-r--r--sys/netpfil/pf/pf.c129
-rw-r--r--sys/netpfil/pf/pf.h2
-rw-r--r--sys/netpfil/pf/pf_ioctl.c189
-rw-r--r--sys/netpfil/pf/pf_lb.c1
17 files changed, 332 insertions, 174 deletions
diff --git a/sys/netpfil/ipfw/dn_sched.h b/sys/netpfil/ipfw/dn_sched.h
index ab823fe7c806..0d2845427ab9 100644
--- a/sys/netpfil/ipfw/dn_sched.h
+++ b/sys/netpfil/ipfw/dn_sched.h
@@ -166,6 +166,7 @@ dn_dequeue(struct dn_queue *q)
if (m == NULL)
return NULL;
q->mq.head = m->m_nextpkt;
+ q->mq.count--;
/* Update stats for the queue */
q->ni.length--;
diff --git a/sys/netpfil/ipfw/dummynet.txt b/sys/netpfil/ipfw/dummynet.txt
index e8c97255aeff..b3b2ee9880e3 100644
--- a/sys/netpfil/ipfw/dummynet.txt
+++ b/sys/netpfil/ipfw/dummynet.txt
@@ -202,10 +202,10 @@ Almost all objects in this implementation are preceded by a structure
Files
-----
The dummynet code is split in several files.
-All kernel code is in sys/netinet/ipfw except ip_dummynet.h
+All kernel code is in sys/netpfil/ipfw except ip_dummynet.h
All userland code is in sbin/ipfw.
Files are
-- sys/netinet/ip_dummynet.h defines the kernel-userland API
+- sys/netpfil/ip_dummynet.h defines the kernel-userland API
- ip_dn_private.h contains the kernel-specific APIs
and data structures
- dn_sched.h defines the scheduler API
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index 7afa1e20bea8..1748194b1e25 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -260,10 +260,39 @@ dn_tag_get(struct mbuf *m)
static inline void
mq_append(struct mq *q, struct mbuf *m)
{
+#ifdef USERSPACE
+ // buffers from netmap need to be copied
+ // XXX note that the routine is not expected to fail
+ ND("append %p to %p", m, q);
+ if (m->m_flags & M_STACK) {
+ struct mbuf *m_new;
+ void *p;
+ int l, ofs;
+
+ ofs = m->m_data - m->__m_extbuf;
+ // XXX allocate
+ MGETHDR(m_new, M_NOWAIT, MT_DATA);
+ ND("*** WARNING, volatile buf %p ext %p %d dofs %d m_new %p",
+ m, m->__m_extbuf, m->__m_extlen, ofs, m_new);
+ p = m_new->__m_extbuf; /* new pointer */
+ l = m_new->__m_extlen; /* new len */
+ if (l <= m->__m_extlen) {
+ panic("extlen too large");
+ }
+
+ *m_new = *m; // copy
+ m_new->m_flags &= ~M_STACK;
+ m_new->__m_extbuf = p; // point to new buffer
+ pkt_copy(m->__m_extbuf, p, m->__m_extlen);
+ m_new->m_data = p + ofs;
+ m = m_new;
+ }
+#endif /* USERSPACE */
if (q->head == NULL)
q->head = m;
else
q->tail->m_nextpkt = m;
+ q->count++;
q->tail = m;
m->m_nextpkt = NULL;
}
@@ -455,6 +484,7 @@ transmit_event(struct mq *q, struct delay_line *dline, uint64_t now)
if (!DN_KEY_LEQ(pkt->output_time, now))
break;
dline->mq.head = m->m_nextpkt;
+ dline->mq.count--;
mq_append(q, m);
}
if (m != NULL) {
diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h
index 159ddc9ab8b2..958c8201412c 100644
--- a/sys/netpfil/ipfw/ip_dn_private.h
+++ b/sys/netpfil/ipfw/ip_dn_private.h
@@ -83,6 +83,7 @@ SLIST_HEAD(dn_alg_head, dn_alg);
struct mq { /* a basic queue of packets*/
struct mbuf *head, *tail;
+ int count;
};
static inline void
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index aa6d9e376d72..ecb0f2dc8169 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -370,7 +370,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, uin
return(1);
}
} else {
-#ifdef __FreeBSD__ /* and OSX too ? */
+#if !defined(USERSPACE) && defined(__FreeBSD__) /* and OSX too ? */
struct ifaddr *ia;
if_addr_rlock(ifp);
@@ -413,7 +413,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, uin
static int
verify_path(struct in_addr src, struct ifnet *ifp, u_int fib)
{
-#ifndef __FreeBSD__
+#if defined(USERSPACE) || !defined(__FreeBSD__)
return 0;
#else
struct route ro;
@@ -664,6 +664,9 @@ static int
check_uidgid(ipfw_insn_u32 *insn, struct ip_fw_args *args, int *ugid_lookupp,
struct ucred **uc)
{
+#if defined(USERSPACE)
+ return 0; // not supported in userspace
+#else
#ifndef __FreeBSD__
/* XXX */
return cred_check(insn, proto, oif,
@@ -766,6 +769,7 @@ check_uidgid(ipfw_insn_u32 *insn, struct ip_fw_args *args, int *ugid_lookupp,
match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
return (match);
#endif /* __FreeBSD__ */
+#endif /* not supported in userspace */
}
/*
@@ -1464,6 +1468,7 @@ do { \
key = htonl(dst_port);
else if (v == 3)
key = htonl(src_port);
+#ifndef USERSPACE
else if (v == 4 || v == 5) {
check_uidgid(
(ipfw_insn_u32 *)cmd,
@@ -1483,6 +1488,7 @@ do { \
#endif /* !__FreeBSD__ */
key = htonl(key);
} else
+#endif /* !USERSPACE */
break;
}
match = ipfw_lookup_table(chain,
@@ -1946,6 +1952,7 @@ do { \
break;
case O_SOCKARG: {
+#ifndef USERSPACE /* not supported in userspace */
struct inpcb *inp = args->inp;
struct inpcbinfo *pi;
@@ -1986,6 +1993,7 @@ do { \
match = 1;
}
}
+#endif /* !USERSPACE */
break;
}
@@ -2405,38 +2413,35 @@ do { \
}
case O_NAT:
+ l = 0; /* exit inner loop */
+ done = 1; /* exit outer loop */
if (!IPFW_NAT_LOADED) {
retval = IP_FW_DENY;
- } else {
- struct cfg_nat *t;
- int nat_id;
+ break;
+ }
- set_match(args, f_pos, chain);
- /* Check if this is 'global' nat rule */
- if (cmd->arg1 == 0) {
- retval = ipfw_nat_ptr(args, NULL, m);
- l = 0;
- done = 1;
- break;
- }
- t = ((ipfw_insn_nat *)cmd)->nat;
- if (t == NULL) {
+ struct cfg_nat *t;
+ int nat_id;
+
+ set_match(args, f_pos, chain);
+ /* Check if this is 'global' nat rule */
+ if (cmd->arg1 == 0) {
+ retval = ipfw_nat_ptr(args, NULL, m);
+ break;
+ }
+ t = ((ipfw_insn_nat *)cmd)->nat;
+ if (t == NULL) {
nat_id = IP_FW_ARG_TABLEARG(cmd->arg1);
t = (*lookup_nat_ptr)(&chain->nat, nat_id);
if (t == NULL) {
retval = IP_FW_DENY;
- l = 0; /* exit inner loop */
- done = 1; /* exit outer loop */
break;
}
if (cmd->arg1 != IP_FW_TABLEARG)
((ipfw_insn_nat *)cmd)->nat = t;
- }
- retval = ipfw_nat_ptr(args, t, m);
}
- l = 0; /* exit inner loop */
- done = 1; /* exit outer loop */
+ retval = ipfw_nat_ptr(args, t, m);
break;
case O_REASS: {
@@ -2661,7 +2666,7 @@ vnet_ipfw_init(const void *unused)
rule->set = RESVD_SET;
rule->cmd[0].len = 1;
rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
- chain->rules = chain->default_rule = chain->map[0] = rule;
+ chain->default_rule = chain->map[0] = rule;
chain->id = rule->id = 1;
IPFW_LOCK_INIT(chain);
diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
index 787fb15906fd..af546f43fc20 100644
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -106,7 +106,8 @@ __FBSDID("$FreeBSD$");
*
* Each dynamic rule holds a pointer to the parent ipfw rule so
* we know what action to perform. Dynamic rules are removed when
- * the parent rule is deleted. XXX we should make them survive.
+ * the parent rule is deleted. This can be changed by dyn_keep_states
+ * sysctl.
*
* There are some limitations with dynamic rules -- we do not
* obey the 'randomized match', and we do not do multiple
@@ -141,6 +142,10 @@ static VNET_DEFINE(uma_zone_t, ipfw_dyn_rule_zone);
#define IPFW_BUCK_UNLOCK(i) mtx_unlock(&V_ipfw_dyn_v[(i)].mtx)
#define IPFW_BUCK_ASSERT(i) mtx_assert(&V_ipfw_dyn_v[(i)].mtx, MA_OWNED)
+
+static VNET_DEFINE(int, dyn_keep_states);
+#define V_dyn_keep_states VNET(dyn_keep_states)
+
/*
* Timeouts for various events in handing dynamic rules.
*/
@@ -181,6 +186,13 @@ static VNET_DEFINE(u_int32_t, dyn_max); /* max # of dynamic rules */
#define DYN_COUNT uma_zone_get_cur(V_ipfw_dyn_rule_zone)
#define V_dyn_max VNET(dyn_max)
+/* for userspace, we emulate the uma_zone_counter with ipfw_dyn_count */
+static int ipfw_dyn_count; /* number of objects */
+
+#ifdef USERSPACE /* emulation of UMA object counters for userspace */
+#define uma_zone_get_cur(x) ipfw_dyn_count
+#endif /* USERSPACE */
+
static int last_log; /* Log ratelimiting */
static void ipfw_dyn_tick(void *vnetx);
@@ -227,12 +239,16 @@ SYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime,
SYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive,
CTLFLAG_RW, &VNET_NAME(dyn_keepalive), 0,
"Enable keepalives for dyn. rules");
+SYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_keep_states,
+ CTLFLAG_RW, &VNET_NAME(dyn_keep_states), 0,
+ "Do not flush dynamic states on rule deletion");
SYSEND
#endif /* SYSCTL_NODE */
+#ifdef INET6
static __inline int
hash_packet6(struct ipfw_flow_id *id)
{
@@ -244,6 +260,7 @@ hash_packet6(struct ipfw_flow_id *id)
(id->dst_port) ^ (id->src_port);
return i;
}
+#endif
/*
* IMPORTANT: the hash function for dynamic rules must be commutative
@@ -300,6 +317,7 @@ print_dyn_rule_flags(struct ipfw_flow_id *id, int dyn_type, int log_flags,
print_dyn_rule_flags(id, dtype, LOG_DEBUG, prefix, postfix)
#define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0)
+#define TIME_LE(a,b) ((int)((a)-(b)) < 0)
/*
* Lookup a dynamic rule, locked version.
@@ -579,6 +597,7 @@ add_dyn_rule(struct ipfw_flow_id *id, int i, u_int8_t dyn_type, struct ip_fw *ru
}
return NULL;
}
+ ipfw_dyn_count++;
/*
* refcount on parent is already incremented, so
@@ -1092,6 +1111,20 @@ check_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule,
if ((TIME_LEQ(q->expire, time_uptime)) ||
((rule != NULL) && (q->rule == rule)) ||
((set != RESVD_SET) && (q->rule->set == set))) {
+ if (TIME_LE(time_uptime, q->expire) &&
+ q->dyn_type == O_KEEP_STATE &&
+ V_dyn_keep_states != 0) {
+ /*
+ * Do not delete state if
+ * it is not expired and
+ * dyn_keep_states is ON.
+ * However we need to re-link it
+ * to any other stable rule
+ */
+ q->rule = chain->default_rule;
+ NEXT_RULE();
+ }
+
/* Unlink q from current list */
q_next = q->next;
if (q == V_ipfw_dyn_v[i].head)
@@ -1253,11 +1286,13 @@ check_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule,
for (q = exp_head; q != NULL; q = q_next) {
q_next = q->next;
uma_zfree(V_ipfw_dyn_rule_zone, q);
+ ipfw_dyn_count--;
}
for (q = exp_lhead; q != NULL; q = q_next) {
q_next = q->next;
uma_zfree(V_ipfw_dyn_rule_zone, q);
+ ipfw_dyn_count--;
}
/*
diff --git a/sys/netpfil/ipfw/ip_fw_log.c b/sys/netpfil/ipfw/ip_fw_log.c
index 13aa3e43c8ac..b9ef96dc0f99 100644
--- a/sys/netpfil/ipfw/ip_fw_log.c
+++ b/sys/netpfil/ipfw/ip_fw_log.c
@@ -85,8 +85,15 @@ __FBSDID("$FreeBSD$");
#define ICMP(p) ((struct icmphdr *)(p))
#define ICMP6(p) ((struct icmp6_hdr *)(p))
+#ifdef __APPLE__
+#undef snprintf
+#define snprintf sprintf
+#define SNPARGS(buf, len) buf + len
+#define SNP(buf) buf
+#else /* !__APPLE__ */
#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
#define SNP(buf) buf, sizeof(buf)
+#endif /* !__APPLE__ */
#ifdef WITHOUT_BPF
void
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
index 237b560978ea..427a55e46f6a 100644
--- a/sys/netpfil/ipfw/ip_fw_nat.c
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
@@ -676,7 +676,7 @@ static moduledata_t ipfw_nat_mod = {
};
/* Define startup order. */
-#define IPFW_NAT_SI_SUB_FIREWALL SI_SUB_PROTO_IFATTACHDOMAIN
+#define IPFW_NAT_SI_SUB_FIREWALL (SI_SUB_PROTO_IFATTACHDOMAIN + 1)
#define IPFW_NAT_MODEVENT_ORDER (SI_ORDER_ANY - 255)
#define IPFW_NAT_MODULE_ORDER (IPFW_NAT_MODEVENT_ORDER + 1)
#define IPFW_NAT_VNET_ORDER (IPFW_NAT_MODEVENT_ORDER + 2)
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
index 79973b1f05c7..dcef12a21669 100644
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -82,9 +82,9 @@ int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
/* Forward declarations. */
static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
-static int ipfw_check_packet(void *, struct mbuf **, struct ifnet *, int,
+int ipfw_check_packet(void *, struct mbuf **, struct ifnet *, int,
struct inpcb *);
-static int ipfw_check_frame(void *, struct mbuf **, struct ifnet *, int,
+int ipfw_check_frame(void *, struct mbuf **, struct ifnet *, int,
struct inpcb *);
#ifdef SYSCTL_NODE
@@ -116,7 +116,7 @@ SYSEND
* dummynet, divert, netgraph or other modules.
* The packet may be consumed.
*/
-static int
+int
ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
struct inpcb *inp)
{
@@ -292,7 +292,7 @@ again:
* Inteface is NULL from ether_demux, and ifp from
* ether_output_frame.
*/
-static int
+int
ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
struct inpcb *inp)
{
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index a8d7eea4edfd..e4a2f3195de5 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -213,25 +213,27 @@ VNET_DECLARE(unsigned int, fw_tables_max);
#define V_fw_tables_max VNET(fw_tables_max)
struct ip_fw_chain {
- struct ip_fw *rules; /* list of rules */
- struct ip_fw *reap; /* list of rules to reap */
- struct ip_fw *default_rule;
- int n_rules; /* number of static rules */
- int static_len; /* total len of static rules */
struct ip_fw **map; /* array of rule ptrs to ease lookup */
+ uint32_t id; /* ruleset id */
+ int n_rules; /* number of static rules */
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
struct radix_node_head **tables; /* IPv4 tables */
struct radix_node_head **xtables; /* extended tables */
uint8_t *tabletype; /* Array of table types */
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t rwmtx;
- spinlock_t uh_lock;
#else
struct rwlock rwmtx;
+#endif
+ int static_len; /* total len of static rules */
+ uint32_t gencnt; /* NAT generation count */
+ struct ip_fw *reap; /* list of rules to reap */
+ struct ip_fw *default_rule;
+#if defined( __linux__ ) || defined( _WIN32 )
+ spinlock_t uh_lock;
+#else
struct rwlock uh_lock; /* lock for upper half */
#endif
- uint32_t id; /* ruleset id */
- uint32_t gencnt; /* generation count */
};
struct sockopt; /* used by tcp_var.h */
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 64f09a56a2a9..0d619bc64a1c 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -159,7 +159,7 @@ ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
int i, l, insert_before;
struct ip_fw **map; /* the new array of pointers */
- if (chain->rules == NULL || input_rule->rulenum > IPFW_DEFAULT_RULE-1)
+ if (chain->map == NULL || input_rule->rulenum > IPFW_DEFAULT_RULE - 1)
return (EINVAL);
l = RULESIZE(input_rule);
@@ -653,7 +653,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_IP_SRC_LOOKUP:
case O_IP_DST_LOOKUP:
- if (cmd->arg1 >= IPFW_TABLES_MAX) {
+ if (cmd->arg1 >= V_fw_tables_max) {
printf("ipfw: invalid table number %d\n",
cmd->arg1);
return (EINVAL);
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index a22fff9240f2..31eebfe802ac 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -123,6 +123,7 @@ struct table_xentry {
#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
+#ifdef INET6
static inline void
ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
{
@@ -132,6 +133,7 @@ ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
*cp++ = 0xFFFFFFFF;
*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
}
+#endif
int
ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
@@ -542,7 +544,7 @@ ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
return (0);
KEY_LEN(sa) = KEY_LEN_INET;
sa.sin_addr.s_addr = addr;
- ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh));
+ ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
if (ent != NULL) {
*val = ent->value;
return (1);
@@ -568,7 +570,7 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
case IPFW_TABLE_CIDR:
KEY_LEN(sa6) = KEY_LEN_INET6;
memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
- xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
+ xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
break;
case IPFW_TABLE_INTERFACE:
@@ -576,7 +578,7 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
strlcpy(iface.ifname, (char *)paddr, IF_NAMESIZE) + 1;
/* Assume direct match */
/* FIXME: Add interface pattern matching */
- xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
+ xent = (struct table_xentry *)(rnh->rnh_matchaddr(&iface, rnh));
break;
default:
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 52ff02cb59fa..6ab0596adc5e 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -438,7 +438,8 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
else
r = &V_pf_default_rule;
- if ((r->max_states && r->states_cur >= r->max_states))
+ if ((r->max_states &&
+ counter_u64_fetch(r->states_cur) >= r->max_states))
goto cleanup;
/*
@@ -516,18 +517,15 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
st->pfsync_time = time_uptime;
st->sync_state = PFSYNC_S_NONE;
- /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
- r->states_cur++;
- r->states_tot++;
-
if (!(flags & PFSYNC_SI_IOCTL))
st->state_flags |= PFSTATE_NOSYNC;
- if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
- /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
- r->states_cur--;
+ if ((error = pf_state_insert(kif, skw, sks, st)) != 0)
goto cleanup_state;
- }
+
+ /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
+ counter_u64_add(r->states_cur, 1);
+ counter_u64_add(r->states_tot, 1);
if (!(flags & PFSYNC_SI_IOCTL)) {
st->state_flags &= ~PFSTATE_NOSYNC;
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 2f13e3b04476..ed0a35f8bc13 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -340,27 +340,27 @@ enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_SOLICITED, PF_ICMP_MULTI_LINK };
#define BOUND_IFACE(r, k) \
((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all
-#define STATE_INC_COUNTERS(s) \
- do { \
- s->rule.ptr->states_cur++; \
- s->rule.ptr->states_tot++; \
- if (s->anchor.ptr != NULL) { \
- s->anchor.ptr->states_cur++; \
- s->anchor.ptr->states_tot++; \
- } \
- if (s->nat_rule.ptr != NULL) { \
- s->nat_rule.ptr->states_cur++; \
- s->nat_rule.ptr->states_tot++; \
- } \
+#define STATE_INC_COUNTERS(s) \
+ do { \
+ counter_u64_add(s->rule.ptr->states_cur, 1); \
+ counter_u64_add(s->rule.ptr->states_tot, 1); \
+ if (s->anchor.ptr != NULL) { \
+ counter_u64_add(s->anchor.ptr->states_cur, 1); \
+ counter_u64_add(s->anchor.ptr->states_tot, 1); \
+ } \
+ if (s->nat_rule.ptr != NULL) { \
+ counter_u64_add(s->nat_rule.ptr->states_cur, 1);\
+ counter_u64_add(s->nat_rule.ptr->states_tot, 1);\
+ } \
} while (0)
-#define STATE_DEC_COUNTERS(s) \
- do { \
- if (s->nat_rule.ptr != NULL) \
- s->nat_rule.ptr->states_cur--; \
- if (s->anchor.ptr != NULL) \
- s->anchor.ptr->states_cur--; \
- s->rule.ptr->states_cur--; \
+#define STATE_DEC_COUNTERS(s) \
+ do { \
+ if (s->nat_rule.ptr != NULL) \
+ counter_u64_add(s->nat_rule.ptr->states_cur, -1);\
+ if (s->anchor.ptr != NULL) \
+ counter_u64_add(s->anchor.ptr->states_cur, -1); \
+ counter_u64_add(s->rule.ptr->states_cur, -1); \
} while (0)
static MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures");
@@ -650,7 +650,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
PF_HASHROW_ASSERT(sh);
if (!rule->max_src_nodes ||
- rule->src_nodes < rule->max_src_nodes)
+ counter_u64_fetch(rule->src_nodes) < rule->max_src_nodes)
(*sn) = uma_zalloc(V_pf_sources_z, M_NOWAIT | M_ZERO);
else
V_pf_status.lcounters[LCNT_SRCNODES]++;
@@ -670,7 +670,7 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
(*sn)->creation = time_uptime;
(*sn)->ruletype = rule->action;
if ((*sn)->rule.ptr != NULL)
- (*sn)->rule.ptr->src_nodes++;
+ counter_u64_add((*sn)->rule.ptr->src_nodes, 1);
PF_HASHROW_UNLOCK(sh);
V_pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
V_pf_status.src_nodes++;
@@ -684,20 +684,53 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
return (0);
}
-static void
-pf_remove_src_node(struct pf_src_node *src)
+void
+pf_unlink_src_node_locked(struct pf_src_node *src)
{
+#ifdef INVARIANTS
struct pf_srchash *sh;
sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)];
- PF_HASHROW_LOCK(sh);
+ PF_HASHROW_ASSERT(sh);
+#endif
LIST_REMOVE(src, entry);
- PF_HASHROW_UNLOCK(sh);
-
+ if (src->rule.ptr)
+ counter_u64_add(src->rule.ptr->src_nodes, -1);
V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
V_pf_status.src_nodes--;
+}
+
+void
+pf_unlink_src_node(struct pf_src_node *src)
+{
+ struct pf_srchash *sh;
- uma_zfree(V_pf_sources_z, src);
+ sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)];
+ PF_HASHROW_LOCK(sh);
+ pf_unlink_src_node_locked(src);
+ PF_HASHROW_UNLOCK(sh);
+}
+
+static void
+pf_free_src_node(struct pf_src_node *sn)
+{
+
+ KASSERT(sn->states == 0, ("%s: %p has refs", __func__, sn));
+ uma_zfree(V_pf_sources_z, sn);
+}
+
+u_int
+pf_free_src_nodes(struct pf_src_node_list *head)
+{
+ struct pf_src_node *sn, *tmp;
+ u_int count = 0;
+
+ LIST_FOREACH_SAFE(sn, head, entry, tmp) {
+ pf_free_src_node(sn);
+ count++;
+ }
+
+ return (count);
}
/* Data storage structures initialization. */
@@ -1440,7 +1473,7 @@ pf_state_expires(const struct pf_state *state)
start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
if (start) {
end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
- states = state->rule.ptr->states_cur; /* XXXGL */
+ states = counter_u64_fetch(state->rule.ptr->states_cur);
} else {
start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START];
end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END];
@@ -1459,24 +1492,24 @@ pf_state_expires(const struct pf_state *state)
void
pf_purge_expired_src_nodes()
{
+ struct pf_src_node_list freelist;
struct pf_srchash *sh;
struct pf_src_node *cur, *next;
int i;
+ LIST_INIT(&freelist);
for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next)
- if (cur->states <= 0 && cur->expire <= time_uptime) {
- if (cur->rule.ptr != NULL)
- cur->rule.ptr->src_nodes--;
- LIST_REMOVE(cur, entry);
- V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- V_pf_status.src_nodes--;
- uma_zfree(V_pf_sources_z, cur);
+ if (cur->states == 0 && cur->expire <= time_uptime) {
+ pf_unlink_src_node_locked(cur);
+ LIST_INSERT_HEAD(&freelist, cur, entry);
} else if (cur->rule.ptr != NULL)
cur->rule.ptr->rule_flag |= PFRULE_REFS;
PF_HASHROW_UNLOCK(sh);
}
+
+ pf_free_src_nodes(&freelist);
}
static void
@@ -1487,7 +1520,7 @@ pf_src_tree_remove_state(struct pf_state *s)
if (s->src_node != NULL) {
if (s->src.tcp_est)
--s->src_node->conn;
- if (--s->src_node->states <= 0) {
+ if (--s->src_node->states == 0) {
timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
if (!timeout)
timeout =
@@ -1496,7 +1529,7 @@ pf_src_tree_remove_state(struct pf_state *s)
}
}
if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
- if (--s->nat_src_node->states <= 0) {
+ if (--s->nat_src_node->states == 0) {
timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
if (!timeout)
timeout =
@@ -1549,11 +1582,7 @@ pf_unlink_state(struct pf_state *s, u_int flags)
if (pfsync_delete_state_ptr != NULL)
pfsync_delete_state_ptr(s);
- --s->rule.ptr->states_cur;
- if (s->nat_rule.ptr != NULL)
- --s->nat_rule.ptr->states_cur;
- if (s->anchor.ptr != NULL)
- --s->anchor.ptr->states_cur;
+ STATE_DEC_COUNTERS(s);
s->timeout = PFTM_UNLINKED;
@@ -3568,7 +3597,8 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
u_short reason;
/* check maximums */
- if (r->max_states && (r->states_cur >= r->max_states)) {
+ if (r->max_states &&
+ (counter_u64_fetch(r->states_cur) >= r->max_states)) {
V_pf_status.lcounters[LCNT_STATES]++;
REASON_SET(&reason, PFRES_MAXSTATES);
return (PF_DROP);
@@ -3766,11 +3796,15 @@ csfailed:
if (nk != NULL)
uma_zfree(V_pf_state_key_z, nk);
- if (sn != NULL && sn->states == 0 && sn->expire == 0)
- pf_remove_src_node(sn);
+ if (sn != NULL && sn->states == 0 && sn->expire == 0) {
+ pf_unlink_src_node(sn);
+ pf_free_src_node(sn);
+ }
- if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0)
- pf_remove_src_node(nsn);
+ if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) {
+ pf_unlink_src_node(nsn);
+ pf_free_src_node(nsn);
+ }
return (PF_DROP);
}
@@ -5451,7 +5485,6 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
PF_STATE_UNLOCK(s);
rt = rtalloc1_fib(sintosa(&dst), 0, 0, M_GETFIB(m0));
if (rt == NULL) {
- RTFREE_LOCKED(rt);
KMOD_IPSTAT_INC(ips_noroute);
error = EHOSTUNREACH;
goto bad;
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 8d2c0f73c7cc..d2d9f2ba49c9 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -31,7 +31,7 @@
*/
#ifndef _NET_PF_H_
-#define _NET_PFAR_H_
+#define _NET_PF_H_
#define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0)
#define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 7ecc016728a9..4541a5741b72 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -155,6 +155,7 @@ struct cdev *pf_dev;
static void pf_clear_states(void);
static int pf_clear_tables(void);
static void pf_clear_srcnodes(struct pf_src_node *);
+static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
static void pf_tbladdr_copyout(struct pf_addr_wrap *);
/*
@@ -231,6 +232,10 @@ pf_vnet_init(void)
V_pf_default_rule.nr = -1;
V_pf_default_rule.rtableid = -1;
+ V_pf_default_rule.states_cur = counter_u64_alloc(M_WAITOK);
+ V_pf_default_rule.states_tot = counter_u64_alloc(M_WAITOK);
+ V_pf_default_rule.src_nodes = counter_u64_alloc(M_WAITOK);
+
/* initialize default timeouts */
my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
@@ -400,6 +405,9 @@ pf_free_rule(struct pf_rule *rule)
pfi_kif_unref(rule->kif);
pf_anchor_remove(rule);
pf_empty_pool(&rule->rpool.list);
+ counter_u64_free(rule->states_cur);
+ counter_u64_free(rule->states_tot);
+ counter_u64_free(rule->src_nodes);
free(rule, M_PFRULE);
}
@@ -1151,6 +1159,9 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
bcopy(&pr->rule, rule, sizeof(struct pf_rule));
if (rule->ifname[0])
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
+ rule->states_cur = counter_u64_alloc(M_WAITOK);
+ rule->states_tot = counter_u64_alloc(M_WAITOK);
+ rule->src_nodes = counter_u64_alloc(M_WAITOK);
rule->cuid = td->td_ucred->cr_ruid;
rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
TAILQ_INIT(&rule->rpool.list);
@@ -1267,6 +1278,9 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
#undef ERROUT
DIOCADDRULE_error:
PF_RULES_WUNLOCK();
+ counter_u64_free(rule->states_cur);
+ counter_u64_free(rule->states_tot);
+ counter_u64_free(rule->src_nodes);
free(rule, M_PFRULE);
if (kif)
free(kif, PFI_MTYPE);
@@ -1338,6 +1352,16 @@ DIOCADDRULE_error:
break;
}
bcopy(rule, &pr->rule, sizeof(struct pf_rule));
+ /*
+ * XXXGL: this is what happens when internal kernel
+ * structures are used as ioctl API structures.
+ */
+ pr->rule.states_cur =
+ (counter_u64_t )counter_u64_fetch(rule->states_cur);
+ pr->rule.states_tot =
+ (counter_u64_t )counter_u64_fetch(rule->states_tot);
+ pr->rule.src_nodes =
+ (counter_u64_t )counter_u64_fetch(rule->src_nodes);
if (pf_anchor_copyout(ruleset, rule, pr)) {
PF_RULES_WUNLOCK();
error = EBUSY;
@@ -1356,7 +1380,7 @@ DIOCADDRULE_error:
rule->evaluations = 0;
rule->packets[0] = rule->packets[1] = 0;
rule->bytes[0] = rule->bytes[1] = 0;
- rule->states_tot = 0;
+ counter_u64_zero(rule->states_tot);
}
PF_RULES_WUNLOCK();
break;
@@ -1396,15 +1420,14 @@ DIOCADDRULE_error:
#endif /* INET6 */
newrule = malloc(sizeof(*newrule), M_PFRULE, M_WAITOK);
bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
+ if (newrule->ifname[0])
+ kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
+ newrule->states_cur = counter_u64_alloc(M_WAITOK);
+ newrule->states_tot = counter_u64_alloc(M_WAITOK);
+ newrule->src_nodes = counter_u64_alloc(M_WAITOK);
newrule->cuid = td->td_ucred->cr_ruid;
newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
TAILQ_INIT(&newrule->rpool.list);
- /* Initialize refcounting. */
- newrule->states_cur = 0;
- newrule->entries.tqe_prev = NULL;
-
- if (newrule->ifname[0])
- kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
}
#define ERROUT(x) { error = (x); goto DIOCCHANGERULE_error; }
@@ -1572,8 +1595,12 @@ DIOCADDRULE_error:
#undef ERROUT
DIOCCHANGERULE_error:
PF_RULES_WUNLOCK();
- if (newrule != NULL)
+ if (newrule != NULL) {
+ counter_u64_free(newrule->states_cur);
+ counter_u64_free(newrule->states_tot);
+ counter_u64_free(newrule->src_nodes);
free(newrule, M_PFRULE);
+ }
if (kif != NULL)
free(kif, PFI_MTYPE);
break;
@@ -2283,6 +2310,7 @@ DIOCGETSTATES_full:
bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
if (newpa->ifname[0])
kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
+ newpa->kif = NULL;
}
#define ERROUT(x) { error = (x); goto DIOCCHANGEADDR_error; }
@@ -2300,8 +2328,8 @@ DIOCGETSTATES_full:
if (newpa->ifname[0]) {
newpa->kif = pfi_kif_attach(kif, newpa->ifname);
pfi_kif_ref(newpa->kif);
- } else
- newpa->kif = NULL;
+ kif = NULL;
+ }
switch (newpa->addr.type) {
case PF_ADDR_DYNIFTL:
@@ -2315,32 +2343,24 @@ DIOCGETSTATES_full:
error = ENOMEM;
break;
}
- if (error) {
- if (newpa->kif)
- pfi_kif_unref(newpa->kif);
- PF_RULES_WUNLOCK();
- free(newpa, M_PFRULE);
- break;
- }
+ if (error)
+ goto DIOCCHANGEADDR_error;
}
- if (pca->action == PF_CHANGE_ADD_HEAD)
+ switch (pca->action) {
+ case PF_CHANGE_ADD_HEAD:
oldpa = TAILQ_FIRST(&pool->list);
- else if (pca->action == PF_CHANGE_ADD_TAIL)
+ break;
+ case PF_CHANGE_ADD_TAIL:
oldpa = TAILQ_LAST(&pool->list, pf_palist);
- else {
- int i = 0;
-
+ break;
+ default:
oldpa = TAILQ_FIRST(&pool->list);
- while ((oldpa != NULL) && (i < pca->nr)) {
+ for (int i = 0; oldpa && i < pca->nr; i++)
oldpa = TAILQ_NEXT(oldpa, entries);
- i++;
- }
- if (oldpa == NULL) {
- PF_RULES_WUNLOCK();
- error = EINVAL;
- break;
- }
+
+ if (oldpa == NULL)
+ ERROUT(EINVAL);
}
if (pca->action == PF_CHANGE_REMOVE) {
@@ -2368,13 +2388,14 @@ DIOCGETSTATES_full:
}
pool->cur = TAILQ_FIRST(&pool->list);
- PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
- pca->af);
+ PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, pca->af);
PF_RULES_WUNLOCK();
break;
#undef ERROUT
DIOCCHANGEADDR_error:
+ if (newpa->kif)
+ pfi_kif_unref(newpa->kif);
PF_RULES_WUNLOCK();
if (newpa != NULL)
free(newpa, M_PFRULE);
@@ -3084,7 +3105,7 @@ DIOCCHANGEADDR_error:
uint32_t i, nr = 0;
if (psn->psn_len == 0) {
- for (i = 0, sh = V_pf_srchash; i < pf_srchashmask;
+ for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH(n, &sh->nodes, entry)
@@ -3096,7 +3117,7 @@ DIOCCHANGEADDR_error:
}
p = pstore = malloc(psn->psn_len, M_TEMP, M_WAITOK);
- for (i = 0, sh = V_pf_srchash; i < pf_srchashmask;
+ for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH(n, &sh->nodes, entry) {
@@ -3146,45 +3167,9 @@ DIOCCHANGEADDR_error:
break;
}
- case DIOCKILLSRCNODES: {
- struct pfioc_src_node_kill *psnk =
- (struct pfioc_src_node_kill *)addr;
- struct pf_srchash *sh;
- struct pf_src_node *sn;
- u_int i, killed = 0;
-
- for (i = 0, sh = V_pf_srchash; i < pf_srchashmask;
- i++, sh++) {
- /*
- * XXXGL: we don't ever acquire sources hash lock
- * but if we ever do, the below call to pf_clear_srcnodes()
- * would lead to a LOR.
- */
- PF_HASHROW_LOCK(sh);
- LIST_FOREACH(sn, &sh->nodes, entry)
- if (PF_MATCHA(psnk->psnk_src.neg,
- &psnk->psnk_src.addr.v.a.addr,
- &psnk->psnk_src.addr.v.a.mask,
- &sn->addr, sn->af) &&
- PF_MATCHA(psnk->psnk_dst.neg,
- &psnk->psnk_dst.addr.v.a.addr,
- &psnk->psnk_dst.addr.v.a.mask,
- &sn->raddr, sn->af)) {
- /* Handle state to src_node linkage */
- if (sn->states != 0)
- pf_clear_srcnodes(sn);
- sn->expire = 1;
- killed++;
- }
- PF_HASHROW_UNLOCK(sh);
- }
-
- if (killed > 0)
- pf_purge_expired_src_nodes();
-
- psnk->psnk_killed = killed;
+ case DIOCKILLSRCNODES:
+ pf_kill_srcnodes((struct pfioc_src_node_kill *)addr);
break;
- }
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;
@@ -3388,7 +3373,7 @@ pf_clear_srcnodes(struct pf_src_node *n)
if (n == NULL) {
struct pf_srchash *sh;
- for (i = 0, sh = V_pf_srchash; i < pf_srchashmask;
+ for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
i++, sh++) {
PF_HASHROW_LOCK(sh);
LIST_FOREACH(n, &sh->nodes, entry) {
@@ -3403,6 +3388,59 @@ pf_clear_srcnodes(struct pf_src_node *n)
n->states = 0;
}
}
+
+static void
+pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
+{
+ struct pf_src_node_list kill;
+
+ LIST_INIT(&kill);
+ for (int i = 0; i <= pf_srchashmask; i++) {
+ struct pf_srchash *sh = &V_pf_srchash[i];
+ struct pf_src_node *sn, *tmp;
+
+ PF_HASHROW_LOCK(sh);
+ LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp)
+ if (PF_MATCHA(psnk->psnk_src.neg,
+ &psnk->psnk_src.addr.v.a.addr,
+ &psnk->psnk_src.addr.v.a.mask,
+ &sn->addr, sn->af) &&
+ PF_MATCHA(psnk->psnk_dst.neg,
+ &psnk->psnk_dst.addr.v.a.addr,
+ &psnk->psnk_dst.addr.v.a.mask,
+ &sn->raddr, sn->af)) {
+ pf_unlink_src_node_locked(sn);
+ LIST_INSERT_HEAD(&kill, sn, entry);
+ sn->expire = 1;
+ }
+ PF_HASHROW_UNLOCK(sh);
+ }
+
+ for (int i = 0; i <= pf_hashmask; i++) {
+ struct pf_idhash *ih = &V_pf_idhash[i];
+ struct pf_state *s;
+
+ PF_HASHROW_LOCK(ih);
+ LIST_FOREACH(s, &ih->states, entry) {
+ if (s->src_node && s->src_node->expire == 1) {
+#ifdef INVARIANTS
+ s->src_node->states--;
+#endif
+ s->src_node = NULL;
+ }
+ if (s->nat_src_node && s->nat_src_node->expire == 1) {
+#ifdef INVARIANTS
+ s->nat_src_node->states--;
+#endif
+ s->nat_src_node = NULL;
+ }
+ }
+ PF_HASHROW_UNLOCK(ih);
+ }
+
+ psnk->psnk_killed = pf_free_src_nodes(&kill);
+}
+
/*
* XXX - Check for version missmatch!!!
*/
@@ -3418,6 +3456,11 @@ shutdown_pf(void)
char nn = '\0';
V_pf_status.running = 0;
+
+ counter_u64_free(V_pf_default_rule.states_cur);
+ counter_u64_free(V_pf_default_rule.states_tot);
+ counter_u64_free(V_pf_default_rule.src_nodes);
+
do {
if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
!= 0) {
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index bc7cc09be5c0..62789f5da2b5 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -686,6 +686,7 @@ notrans:
uma_zfree(V_pf_state_key_z, *nkp);
uma_zfree(V_pf_state_key_z, *skp);
*skp = *nkp = NULL;
+ *sn = NULL;
return (NULL);
}