diff options
Diffstat (limited to 'sys/netpfil/ipfw/ip_fw_dynamic.c')
| -rw-r--r-- | sys/netpfil/ipfw/ip_fw_dynamic.c | 105 |
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 |
