aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/pf/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/pf/pf.c')
-rw-r--r--sys/netpfil/pf/pf.c129
1 files changed, 81 insertions, 48 deletions
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;