aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/ipfw/ip_fw_dynamic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/ipfw/ip_fw_dynamic.c')
-rw-r--r--sys/netpfil/ipfw/ip_fw_dynamic.c105
1 files changed, 51 insertions, 54 deletions
diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
index cfb686594c7c..d2bf4f4fc899 100644
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -663,6 +663,8 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti,
ipfw_obj_ntlv *ntlv;
char *name;
+ IPFW_UH_WLOCK_ASSERT(ch);
+
DYN_DEBUG("uidx %u", ti->uidx);
if (ti->uidx != 0) {
if (ti->tlvs == NULL)
@@ -681,7 +683,6 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti,
obj->no.etlv = IPFW_TLV_STATE_NAME;
strlcpy(obj->name, name, sizeof(obj->name));
- IPFW_UH_WLOCK(ch);
no = ipfw_objhash_lookup_name_type(ni, 0,
IPFW_TLV_STATE_NAME, name);
if (no != NULL) {
@@ -691,14 +692,12 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti,
*/
*pkidx = no->kidx;
no->refcnt++;
- IPFW_UH_WUNLOCK(ch);
free(obj, M_IPFW);
DYN_DEBUG("\tfound kidx %u for name '%s'", *pkidx, no->name);
return (0);
}
if (ipfw_objhash_alloc_idx(ni, &obj->no.kidx) != 0) {
DYN_DEBUG("\talloc_idx failed for %s", name);
- IPFW_UH_WUNLOCK(ch);
free(obj, M_IPFW);
return (ENOSPC);
}
@@ -706,7 +705,6 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti,
SRV_OBJECT(ch, obj->no.kidx) = obj;
obj->no.refcnt++;
*pkidx = obj->no.kidx;
- IPFW_UH_WUNLOCK(ch);
DYN_DEBUG("\tcreated kidx %u for name '%s'", *pkidx, name);
return (0);
}
@@ -734,28 +732,44 @@ dyn_destroy(struct ip_fw_chain *ch, struct named_object *no)
static struct opcode_obj_rewrite dyn_opcodes[] = {
{
- O_KEEP_STATE, IPFW_TLV_STATE_NAME,
- dyn_classify, dyn_update,
- dyn_findbyname, dyn_findbykidx,
- dyn_create, dyn_destroy
+ .opcode = O_KEEP_STATE,
+ .etlv = IPFW_TLV_STATE_NAME,
+ .classifier = dyn_classify,
+ .update = dyn_update,
+ .find_byname = dyn_findbyname,
+ .find_bykidx = dyn_findbykidx,
+ .create_object = dyn_create,
+ .destroy_object = dyn_destroy,
},
{
- O_CHECK_STATE, IPFW_TLV_STATE_NAME,
- dyn_classify, dyn_update,
- dyn_findbyname, dyn_findbykidx,
- dyn_create, dyn_destroy
+ .opcode = O_CHECK_STATE,
+ .etlv = IPFW_TLV_STATE_NAME,
+ .classifier = dyn_classify,
+ .update = dyn_update,
+ .find_byname = dyn_findbyname,
+ .find_bykidx = dyn_findbykidx,
+ .create_object = dyn_create,
+ .destroy_object = dyn_destroy,
},
{
- O_PROBE_STATE, IPFW_TLV_STATE_NAME,
- dyn_classify, dyn_update,
- dyn_findbyname, dyn_findbykidx,
- dyn_create, dyn_destroy
+ .opcode = O_PROBE_STATE,
+ .etlv = IPFW_TLV_STATE_NAME,
+ .classifier = dyn_classify,
+ .update = dyn_update,
+ .find_byname = dyn_findbyname,
+ .find_bykidx = dyn_findbykidx,
+ .create_object = dyn_create,
+ .destroy_object = dyn_destroy,
},
{
- O_LIMIT, IPFW_TLV_STATE_NAME,
- dyn_classify, dyn_update,
- dyn_findbyname, dyn_findbykidx,
- dyn_create, dyn_destroy
+ .opcode = O_LIMIT,
+ .etlv = IPFW_TLV_STATE_NAME,
+ .classifier = dyn_classify,
+ .update = dyn_update,
+ .find_byname = dyn_findbyname,
+ .find_bykidx = dyn_findbykidx,
+ .create_object = dyn_create,
+ .destroy_object = dyn_destroy,
},
};
@@ -2129,9 +2143,6 @@ dyn_free_states(struct ip_fw_chain *chain)
* Userland can invoke ipfw_expire_dyn_states() to delete
* specific states, this will lead to modification of expired
* lists.
- *
- * XXXAE: do we need DYN_EXPIRED_LOCK? We can just use
- * IPFW_UH_WLOCK to protect access to these lists.
*/
DYN_EXPIRED_LOCK();
DYN_FREE_STATES(s4, s4n, ipv4);
@@ -2290,8 +2301,6 @@ dyn_expire_states(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
void *rule;
int bucket, removed, length, max_length;
- IPFW_UH_WLOCK_ASSERT(ch);
-
/*
* Unlink expired states from each bucket.
* With acquired bucket lock iterate entries of each lists:
@@ -2489,13 +2498,8 @@ dyn_send_keepalive_ipv4(struct ip_fw_chain *chain)
uint32_t bucket;
mbufq_init(&q, INT_MAX);
- IPFW_UH_RLOCK(chain);
- /*
- * It is safe to not use hazard pointer and just do lockless
- * access to the lists, because states entries can not be deleted
- * while we hold IPFW_UH_RLOCK.
- */
for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+ DYN_BUCKET_LOCK(bucket);
CK_SLIST_FOREACH(s, &V_dyn_ipv4[bucket], entry) {
/*
* Only established TCP connections that will
@@ -2508,8 +2512,8 @@ dyn_send_keepalive_ipv4(struct ip_fw_chain *chain)
continue;
dyn_enqueue_keepalive_ipv4(&q, s);
}
+ DYN_BUCKET_UNLOCK(bucket);
}
- IPFW_UH_RUNLOCK(chain);
while ((m = mbufq_dequeue(&q)) != NULL)
ip_output(m, NULL, NULL, 0, NULL, NULL);
}
@@ -2596,13 +2600,8 @@ dyn_send_keepalive_ipv6(struct ip_fw_chain *chain)
uint32_t bucket;
mbufq_init(&q, INT_MAX);
- IPFW_UH_RLOCK(chain);
- /*
- * It is safe to not use hazard pointer and just do lockless
- * access to the lists, because states entries can not be deleted
- * while we hold IPFW_UH_RLOCK.
- */
for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+ DYN_BUCKET_LOCK(bucket);
CK_SLIST_FOREACH(s, &V_dyn_ipv6[bucket], entry) {
/*
* Only established TCP connections that will
@@ -2615,8 +2614,8 @@ dyn_send_keepalive_ipv6(struct ip_fw_chain *chain)
continue;
dyn_enqueue_keepalive_ipv6(&q, s);
}
+ DYN_BUCKET_UNLOCK(bucket);
}
- IPFW_UH_RUNLOCK(chain);
while ((m = mbufq_dequeue(&q)) != NULL)
ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
}
@@ -2718,10 +2717,6 @@ dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new, int flags)
} \
} while (0)
/*
- * Prevent rules changing from userland.
- */
- IPFW_UH_WLOCK(chain);
- /*
* Hold traffic processing until we finish resize to
* prevent access to states lists.
*/
@@ -2764,7 +2759,6 @@ dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new, int flags)
V_curr_dyn_buckets = new;
IPFW_WUNLOCK(chain);
- IPFW_UH_WUNLOCK(chain);
/* Release old resources */
while (bucket-- != 0)
@@ -2802,15 +2796,8 @@ dyn_tick(void *vnetx)
* First free states unlinked in previous passes.
*/
dyn_free_states(&V_layer3_chain);
- /*
- * Now unlink others expired states.
- * We use IPFW_UH_WLOCK to avoid concurrent call of
- * dyn_expire_states(). It is the only function that does
- * deletion of state entries from states lists.
- */
- IPFW_UH_WLOCK(&V_layer3_chain);
dyn_expire_states(&V_layer3_chain, NULL);
- IPFW_UH_WUNLOCK(&V_layer3_chain);
+
/*
* Send keepalives if they are enabled and the time has come.
*/
@@ -2847,14 +2834,24 @@ dyn_tick(void *vnetx)
void
ipfw_expire_dyn_states(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
{
+ IPFW_RLOCK_TRACKER;
+
/*
* Do not perform any checks if we currently have no dynamic states
*/
if (V_dyn_count == 0)
return;
- IPFW_UH_WLOCK_ASSERT(chain);
+ /*
+ * Acquire read lock to prevent race with dyn_grow_hashtable() called
+ * via dyn_tick(). Note that dyn_tick() also calls dyn_expire_states(),
+ * but doesn't acquire the chain lock. A race between dyn_tick() and
+ * this function should be safe, as dyn_expire_states() does all proper
+ * locking of buckets and expire lists.
+ */
+ IPFW_RLOCK(chain);
dyn_expire_states(chain, rt);
+ IPFW_RUNLOCK(chain);
}
/*
@@ -3175,7 +3172,7 @@ dyn_add_protected_rule(struct ip_fw_chain *chain)
cmd->opcode = O_COUNT;
rule->act_ofs = cmd - rule->cmd;
rule->cmd_len = rule->act_ofs + 1;
- ipfw_add_protected_rule(chain, rule, 0);
+ ipfw_add_protected_rule(chain, rule);
}
void