Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netpfil/ipfw/ip_fw_dynamic.c
Show First 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | if (IS_IP6_FLOW_ID(id)) | ||||
i = hash_packet6(id); | i = hash_packet6(id); | ||||
else | else | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); | i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); | ||||
i &= (buckets - 1); | i &= (buckets - 1); | ||||
return i; | return i; | ||||
} | } | ||||
#if 0 | |||||
#define DYN_DEBUG(fmt, ...) do { \ | |||||
printf("%s: " fmt "\n", __func__, __VA_ARGS__); \ | |||||
} while (0) | |||||
#else | |||||
#define DYN_DEBUG(fmt, ...) | |||||
#endif | |||||
static char *default_state_name = "default"; | |||||
struct dyn_state_obj { | |||||
struct named_object no; | |||||
char name[64]; | |||||
}; | |||||
#define DYN_STATE_OBJ(ch, cmd) \ | |||||
((struct dyn_state_obj *)SRV_OBJECT(ch, (cmd)->arg1)) | |||||
/* | |||||
* Classifier callback. | |||||
* Return 0 if opcode contains object that should be referenced | |||||
* or rewritten. | |||||
*/ | |||||
static int | |||||
dyn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | |||||
{ | |||||
DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1); | |||||
/* Don't rewrite "check-state any" */ | |||||
if (cmd->arg1 == 0 && | |||||
cmd->opcode == O_CHECK_STATE) | |||||
return (1); | |||||
*puidx = cmd->arg1; | |||||
*ptype = 0; | |||||
return (0); | |||||
} | |||||
static void | |||||
dyn_update(ipfw_insn *cmd, uint16_t idx) | |||||
{ | |||||
cmd->arg1 = idx; | |||||
DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1); | |||||
} | |||||
static int | |||||
dyn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, | |||||
struct named_object **pno) | |||||
{ | |||||
ipfw_obj_ntlv *ntlv; | |||||
const char *name; | |||||
DYN_DEBUG("uidx %d", ti->uidx); | |||||
if (ti->uidx != 0) { | |||||
if (ti->tlvs == NULL) | |||||
return (EINVAL); | |||||
/* Search ntlv in the buffer provided by user */ | |||||
ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, | |||||
IPFW_TLV_STATE_NAME); | |||||
if (ntlv == NULL) | |||||
return (EINVAL); | |||||
name = ntlv->name; | |||||
} else | |||||
name = default_state_name; | |||||
/* | |||||
* Search named object with corresponding name. | |||||
* Since states objects are global - ignore the set value | |||||
* and use zero instead. | |||||
*/ | |||||
*pno = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch), 0, | |||||
IPFW_TLV_STATE_NAME, name); | |||||
/* | |||||
* We always return success here. | |||||
* The caller will check *pno and mark object as unresolved, | |||||
* then it will automatically create "default" object. | |||||
*/ | |||||
return (0); | |||||
} | |||||
static struct named_object * | |||||
dyn_findbykidx(struct ip_fw_chain *ch, uint16_t idx) | |||||
{ | |||||
DYN_DEBUG("kidx %d", idx); | |||||
return (ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), idx)); | |||||
} | |||||
static int | |||||
dyn_create(struct ip_fw_chain *ch, struct tid_info *ti, | |||||
uint16_t *pkidx) | |||||
{ | |||||
struct namedobj_instance *ni; | |||||
struct dyn_state_obj *obj; | |||||
struct named_object *no; | |||||
ipfw_obj_ntlv *ntlv; | |||||
char *name; | |||||
DYN_DEBUG("uidx %d", ti->uidx); | |||||
if (ti->uidx != 0) { | |||||
if (ti->tlvs == NULL) | |||||
return (EINVAL); | |||||
ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, | |||||
IPFW_TLV_STATE_NAME); | |||||
if (ntlv == NULL) | |||||
return (EINVAL); | |||||
name = ntlv->name; | |||||
} else | |||||
name = default_state_name; | |||||
ni = CHAIN_TO_SRV(ch); | |||||
obj = malloc(sizeof(*obj), M_IPFW, M_WAITOK | M_ZERO); | |||||
obj->no.name = obj->name; | |||||
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) { | |||||
/* | |||||
* Object is already created. | |||||
* Just return its kidx and bump refcount. | |||||
*/ | |||||
*pkidx = no->kidx; | |||||
no->refcnt++; | |||||
IPFW_UH_WUNLOCK(ch); | |||||
free(obj, M_IPFW); | |||||
DYN_DEBUG("\tfound kidx %d", *pkidx); | |||||
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); | |||||
} | |||||
ipfw_objhash_add(ni, &obj->no); | |||||
IPFW_WLOCK(ch); | |||||
SRV_OBJECT(ch, obj->no.kidx) = obj; | |||||
IPFW_WUNLOCK(ch); | |||||
obj->no.refcnt++; | |||||
*pkidx = obj->no.kidx; | |||||
IPFW_UH_WUNLOCK(ch); | |||||
DYN_DEBUG("\tcreated kidx %d", *pkidx); | |||||
return (0); | |||||
} | |||||
static void | |||||
dyn_destroy(struct ip_fw_chain *ch, struct named_object *no) | |||||
{ | |||||
struct dyn_state_obj *obj; | |||||
IPFW_UH_WLOCK_ASSERT(ch); | |||||
KASSERT(no->refcnt == 1, | |||||
("Destroying object '%s' (type %u, idx %u) with refcnt %u", | |||||
no->name, no->etlv, no->kidx, no->refcnt)); | |||||
DYN_DEBUG("kidx %d", no->kidx); | |||||
IPFW_WLOCK(ch); | |||||
obj = SRV_OBJECT(ch, no->kidx); | |||||
SRV_OBJECT(ch, no->kidx) = NULL; | |||||
IPFW_WUNLOCK(ch); | |||||
ipfw_objhash_del(CHAIN_TO_SRV(ch), no); | |||||
ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), no->kidx); | |||||
free(obj, M_IPFW); | |||||
} | |||||
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 | |||||
}, | |||||
{ | |||||
O_CHECK_STATE, IPFW_TLV_STATE_NAME, | |||||
dyn_classify, dyn_update, | |||||
dyn_findbyname, dyn_findbykidx, | |||||
dyn_create, dyn_destroy | |||||
}, | |||||
{ | |||||
O_PROBE_STATE, IPFW_TLV_STATE_NAME, | |||||
dyn_classify, dyn_update, | |||||
dyn_findbyname, dyn_findbykidx, | |||||
dyn_create, dyn_destroy | |||||
}, | |||||
{ | |||||
O_LIMIT, IPFW_TLV_STATE_NAME, | |||||
dyn_classify, dyn_update, | |||||
dyn_findbyname, dyn_findbykidx, | |||||
dyn_create, dyn_destroy | |||||
}, | |||||
}; | |||||
/** | /** | ||||
* Print customizable flow id description via log(9) facility. | * Print customizable flow id description via log(9) facility. | ||||
*/ | */ | ||||
static void | static void | ||||
print_dyn_rule_flags(struct ipfw_flow_id *id, int dyn_type, int log_flags, | print_dyn_rule_flags(struct ipfw_flow_id *id, int dyn_type, int log_flags, | ||||
char *prefix, char *postfix) | char *prefix, char *postfix) | ||||
{ | { | ||||
struct in_addr da; | struct in_addr da; | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Lookup a dynamic rule, locked version. | * Lookup a dynamic rule, locked version. | ||||
*/ | */ | ||||
static ipfw_dyn_rule * | static ipfw_dyn_rule * | ||||
lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int i, int *match_direction, | lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int i, int *match_direction, | ||||
struct tcphdr *tcp) | struct tcphdr *tcp, uint16_t kidx) | ||||
{ | { | ||||
/* | /* | ||||
* Stateful ipfw extensions. | * Stateful ipfw extensions. | ||||
* Lookup into dynamic session queue. | * Lookup into dynamic session queue. | ||||
*/ | */ | ||||
ipfw_dyn_rule *prev, *q = NULL; | ipfw_dyn_rule *prev, *q = NULL; | ||||
int dir; | int dir; | ||||
IPFW_BUCK_ASSERT(i); | IPFW_BUCK_ASSERT(i); | ||||
dir = MATCH_NONE; | dir = MATCH_NONE; | ||||
for (prev = NULL, q = V_ipfw_dyn_v[i].head; q; prev = q, q = q->next) { | for (prev = NULL, q = V_ipfw_dyn_v[i].head; q; prev = q, q = q->next) { | ||||
if (q->dyn_type == O_LIMIT_PARENT && q->count) | if (q->dyn_type == O_LIMIT_PARENT) | ||||
continue; | continue; | ||||
if (pkt->proto != q->id.proto || q->dyn_type == O_LIMIT_PARENT) | if (pkt->proto != q->id.proto) | ||||
continue; | continue; | ||||
if (kidx != 0 && kidx != q->kidx) | |||||
continue; | |||||
if (IS_IP6_FLOW_ID(pkt)) { | if (IS_IP6_FLOW_ID(pkt)) { | ||||
if (IN6_ARE_ADDR_EQUAL(&pkt->src_ip6, &q->id.src_ip6) && | if (IN6_ARE_ADDR_EQUAL(&pkt->src_ip6, &q->id.src_ip6) && | ||||
IN6_ARE_ADDR_EQUAL(&pkt->dst_ip6, &q->id.dst_ip6) && | IN6_ARE_ADDR_EQUAL(&pkt->dst_ip6, &q->id.dst_ip6) && | ||||
pkt->src_port == q->id.src_port && | pkt->src_port == q->id.src_port && | ||||
pkt->dst_port == q->id.dst_port) { | pkt->dst_port == q->id.dst_port) { | ||||
dir = MATCH_FORWARD; | dir = MATCH_FORWARD; | ||||
break; | break; | ||||
} | } | ||||
Show All 35 Lines | |||||
done: | done: | ||||
if (match_direction != NULL) | if (match_direction != NULL) | ||||
*match_direction = dir; | *match_direction = dir; | ||||
return (q); | return (q); | ||||
} | } | ||||
ipfw_dyn_rule * | ipfw_dyn_rule * | ||||
ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction, | ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction, | ||||
struct tcphdr *tcp) | struct tcphdr *tcp, uint16_t kidx) | ||||
{ | { | ||||
ipfw_dyn_rule *q; | ipfw_dyn_rule *q; | ||||
int i; | int i; | ||||
i = hash_packet(pkt, V_curr_dyn_buckets); | i = hash_packet(pkt, V_curr_dyn_buckets); | ||||
IPFW_BUCK_LOCK(i); | IPFW_BUCK_LOCK(i); | ||||
q = lookup_dyn_rule_locked(pkt, i, match_direction, tcp); | q = lookup_dyn_rule_locked(pkt, i, match_direction, tcp, kidx); | ||||
if (q == NULL) | if (q == NULL) | ||||
IPFW_BUCK_UNLOCK(i); | IPFW_BUCK_UNLOCK(i); | ||||
/* NB: return table locked when q is not NULL */ | /* NB: return table locked when q is not NULL */ | ||||
return q; | return q; | ||||
} | } | ||||
/* | /* | ||||
* Unlock bucket mtx | * Unlock bucket mtx | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
* - regular rules (O_KEEP_STATE) | * - regular rules (O_KEEP_STATE) | ||||
* - rules for sessions with limited number of sess per user | * - rules for sessions with limited number of sess per user | ||||
* (O_LIMIT). When they are created, the parent is | * (O_LIMIT). When they are created, the parent is | ||||
* increased by 1, and decreased on delete. In this case, | * increased by 1, and decreased on delete. In this case, | ||||
* the third parameter is the parent rule and not the chain. | * the third parameter is the parent rule and not the chain. | ||||
* - "parent" rules for the above (O_LIMIT_PARENT). | * - "parent" rules for the above (O_LIMIT_PARENT). | ||||
*/ | */ | ||||
static ipfw_dyn_rule * | static ipfw_dyn_rule * | ||||
add_dyn_rule(struct ipfw_flow_id *id, int i, u_int8_t dyn_type, struct ip_fw *rule) | add_dyn_rule(struct ipfw_flow_id *id, int i, uint8_t dyn_type, | ||||
struct ip_fw *rule, uint16_t kidx) | |||||
{ | { | ||||
ipfw_dyn_rule *r; | ipfw_dyn_rule *r; | ||||
IPFW_BUCK_ASSERT(i); | IPFW_BUCK_ASSERT(i); | ||||
r = uma_zalloc(V_ipfw_dyn_rule_zone, M_NOWAIT | M_ZERO); | r = uma_zalloc(V_ipfw_dyn_rule_zone, M_NOWAIT | M_ZERO); | ||||
if (r == NULL) { | if (r == NULL) { | ||||
if (last_log != time_uptime) { | if (last_log != time_uptime) { | ||||
Show All 19 Lines | add_dyn_rule(struct ipfw_flow_id *id, int i, uint8_t dyn_type, | ||||
} | } | ||||
r->id = *id; | r->id = *id; | ||||
r->expire = time_uptime + V_dyn_syn_lifetime; | r->expire = time_uptime + V_dyn_syn_lifetime; | ||||
r->rule = rule; | r->rule = rule; | ||||
r->dyn_type = dyn_type; | r->dyn_type = dyn_type; | ||||
IPFW_ZERO_DYN_COUNTER(r); | IPFW_ZERO_DYN_COUNTER(r); | ||||
r->count = 0; | r->count = 0; | ||||
r->kidx = kidx; | |||||
r->bucket = i; | r->bucket = i; | ||||
r->next = V_ipfw_dyn_v[i].head; | r->next = V_ipfw_dyn_v[i].head; | ||||
V_ipfw_dyn_v[i].head = r; | V_ipfw_dyn_v[i].head = r; | ||||
DEB(print_dyn_rule(id, dyn_type, "add dyn entry", "total");) | DEB(print_dyn_rule(id, dyn_type, "add dyn entry", "total");) | ||||
return r; | return r; | ||||
} | } | ||||
/** | /** | ||||
* lookup dynamic parent rule using pkt and rule as search keys. | * lookup dynamic parent rule using pkt and rule as search keys. | ||||
* If the lookup fails, then install one. | * If the lookup fails, then install one. | ||||
*/ | */ | ||||
static ipfw_dyn_rule * | static ipfw_dyn_rule * | ||||
lookup_dyn_parent(struct ipfw_flow_id *pkt, int *pindex, struct ip_fw *rule) | lookup_dyn_parent(struct ipfw_flow_id *pkt, int *pindex, struct ip_fw *rule, | ||||
uint16_t kidx) | |||||
{ | { | ||||
ipfw_dyn_rule *q; | ipfw_dyn_rule *q; | ||||
int i, is_v6; | int i, is_v6; | ||||
is_v6 = IS_IP6_FLOW_ID(pkt); | is_v6 = IS_IP6_FLOW_ID(pkt); | ||||
i = hash_packet( pkt, V_curr_dyn_buckets ); | i = hash_packet( pkt, V_curr_dyn_buckets ); | ||||
*pindex = i; | *pindex = i; | ||||
IPFW_BUCK_LOCK(i); | IPFW_BUCK_LOCK(i); | ||||
for (q = V_ipfw_dyn_v[i].head ; q != NULL ; q=q->next) | for (q = V_ipfw_dyn_v[i].head ; q != NULL ; q=q->next) | ||||
if (q->dyn_type == O_LIMIT_PARENT && | if (q->dyn_type == O_LIMIT_PARENT && | ||||
kidx == q->kidx && | |||||
rule== q->rule && | rule == q->rule && | ||||
pkt->proto == q->id.proto && | pkt->proto == q->id.proto && | ||||
pkt->src_port == q->id.src_port && | pkt->src_port == q->id.src_port && | ||||
pkt->dst_port == q->id.dst_port && | pkt->dst_port == q->id.dst_port && | ||||
( | ( | ||||
(is_v6 && | (is_v6 && | ||||
IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), | IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), | ||||
&(q->id.src_ip6)) && | &(q->id.src_ip6)) && | ||||
IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), | IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), | ||||
&(q->id.dst_ip6))) || | &(q->id.dst_ip6))) || | ||||
(!is_v6 && | (!is_v6 && | ||||
pkt->src_ip == q->id.src_ip && | pkt->src_ip == q->id.src_ip && | ||||
pkt->dst_ip == q->id.dst_ip) | pkt->dst_ip == q->id.dst_ip) | ||||
) | ) | ||||
) { | ) { | ||||
q->expire = time_uptime + V_dyn_short_lifetime; | q->expire = time_uptime + V_dyn_short_lifetime; | ||||
DEB(print_dyn_rule(pkt, q->dyn_type, | DEB(print_dyn_rule(pkt, q->dyn_type, | ||||
"lookup_dyn_parent found", "");) | "lookup_dyn_parent found", "");) | ||||
return q; | return q; | ||||
} | } | ||||
/* Add virtual limiting rule */ | /* Add virtual limiting rule */ | ||||
return add_dyn_rule(pkt, i, O_LIMIT_PARENT, rule); | return add_dyn_rule(pkt, i, O_LIMIT_PARENT, rule, kidx); | ||||
} | } | ||||
/** | /** | ||||
* Install dynamic state for rule type cmd->o.opcode | * Install dynamic state for rule type cmd->o.opcode | ||||
* | * | ||||
* Returns 1 (failure) if state is not installed because of errors or because | * Returns 1 (failure) if state is not installed because of errors or because | ||||
* session limitations are enforced. | * session limitations are enforced. | ||||
*/ | */ | ||||
int | int | ||||
ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule, | ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule, | ||||
ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg) | ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg) | ||||
{ | { | ||||
ipfw_dyn_rule *q; | ipfw_dyn_rule *q; | ||||
int i; | int i; | ||||
DEB(print_dyn_rule(&args->f_id, cmd->o.opcode, "install_state", "");) | DEB(print_dyn_rule(&args->f_id, cmd->o.opcode, "install_state", | ||||
(cmd->o.arg1 == 0 ? "": DYN_STATE_OBJ(chain, &cmd->o)->name));) | |||||
i = hash_packet(&args->f_id, V_curr_dyn_buckets); | i = hash_packet(&args->f_id, V_curr_dyn_buckets); | ||||
IPFW_BUCK_LOCK(i); | IPFW_BUCK_LOCK(i); | ||||
q = lookup_dyn_rule_locked(&args->f_id, i, NULL, NULL); | q = lookup_dyn_rule_locked(&args->f_id, i, NULL, NULL, cmd->o.arg1); | ||||
if (q != NULL) { /* should never occur */ | if (q != NULL) { /* should never occur */ | ||||
DEB( | DEB( | ||||
if (last_log != time_uptime) { | if (last_log != time_uptime) { | ||||
last_log = time_uptime; | last_log = time_uptime; | ||||
printf("ipfw: %s: entry already present, done\n", | printf("ipfw: %s: entry already present, done\n", | ||||
__func__); | __func__); | ||||
}) | }) | ||||
IPFW_BUCK_UNLOCK(i); | IPFW_BUCK_UNLOCK(i); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* State limiting is done via uma(9) zone limiting. | * State limiting is done via uma(9) zone limiting. | ||||
* Save pointer to newly-installed rule and reject | * Save pointer to newly-installed rule and reject | ||||
* packet if add_dyn_rule() returned NULL. | * packet if add_dyn_rule() returned NULL. | ||||
* Note q is currently set to NULL. | * Note q is currently set to NULL. | ||||
*/ | */ | ||||
switch (cmd->o.opcode) { | switch (cmd->o.opcode) { | ||||
case O_KEEP_STATE: /* bidir rule */ | case O_KEEP_STATE: /* bidir rule */ | ||||
q = add_dyn_rule(&args->f_id, i, O_KEEP_STATE, rule); | q = add_dyn_rule(&args->f_id, i, O_KEEP_STATE, rule, | ||||
cmd->o.arg1); | |||||
break; | break; | ||||
case O_LIMIT: { /* limit number of sessions */ | case O_LIMIT: { /* limit number of sessions */ | ||||
struct ipfw_flow_id id; | struct ipfw_flow_id id; | ||||
ipfw_dyn_rule *parent; | ipfw_dyn_rule *parent; | ||||
uint32_t conn_limit; | uint32_t conn_limit; | ||||
uint16_t limit_mask = cmd->limit_mask; | uint16_t limit_mask = cmd->limit_mask; | ||||
int pindex; | int pindex; | ||||
Show All 34 Lines | if (limit_mask & DYN_DST_PORT) | ||||
id.dst_port = args->f_id.dst_port; | id.dst_port = args->f_id.dst_port; | ||||
/* | /* | ||||
* We have to release lock for previous bucket to | * We have to release lock for previous bucket to | ||||
* avoid possible deadlock | * avoid possible deadlock | ||||
*/ | */ | ||||
IPFW_BUCK_UNLOCK(i); | IPFW_BUCK_UNLOCK(i); | ||||
if ((parent = lookup_dyn_parent(&id, &pindex, rule)) == NULL) { | parent = lookup_dyn_parent(&id, &pindex, rule, cmd->o.arg1); | ||||
if (parent == NULL) { | |||||
printf("ipfw: %s: add parent failed\n", __func__); | printf("ipfw: %s: add parent failed\n", __func__); | ||||
IPFW_BUCK_UNLOCK(pindex); | IPFW_BUCK_UNLOCK(pindex); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (parent->count >= conn_limit) { | if (parent->count >= conn_limit) { | ||||
if (V_fw_verbose && last_log != time_uptime) { | if (V_fw_verbose && last_log != time_uptime) { | ||||
last_log = time_uptime; | last_log = time_uptime; | ||||
Show All 11 Lines | if (parent->count >= conn_limit) { | ||||
return (1); | return (1); | ||||
} | } | ||||
/* Increment counter on parent */ | /* Increment counter on parent */ | ||||
parent->count++; | parent->count++; | ||||
IPFW_BUCK_UNLOCK(pindex); | IPFW_BUCK_UNLOCK(pindex); | ||||
IPFW_BUCK_LOCK(i); | IPFW_BUCK_LOCK(i); | ||||
q = add_dyn_rule(&args->f_id, i, O_LIMIT, | q = add_dyn_rule(&args->f_id, i, O_LIMIT, | ||||
(struct ip_fw *)parent); | (struct ip_fw *)parent, cmd->o.arg1); | ||||
if (q == NULL) { | if (q == NULL) { | ||||
/* Decrement index and notify caller */ | /* Decrement index and notify caller */ | ||||
IPFW_BUCK_UNLOCK(i); | IPFW_BUCK_UNLOCK(i); | ||||
IPFW_BUCK_LOCK(pindex); | IPFW_BUCK_LOCK(pindex); | ||||
parent->count--; | parent->count--; | ||||
IPFW_BUCK_UNLOCK(pindex); | IPFW_BUCK_UNLOCK(pindex); | ||||
return (1); | return (1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 600 Lines • ▼ Show 20 Lines | uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max); | ||||
callout_init(&V_ipfw_timeout, 1); | callout_init(&V_ipfw_timeout, 1); | ||||
/* | /* | ||||
* This can potentially be done on first dynamic rule | * This can potentially be done on first dynamic rule | ||||
* being added to chain. | * being added to chain. | ||||
*/ | */ | ||||
resize_dynamic_table(chain, V_curr_dyn_buckets); | resize_dynamic_table(chain, V_curr_dyn_buckets); | ||||
IPFW_ADD_OBJ_REWRITER(IS_DEFAULT_VNET(curvnet), dyn_opcodes); | |||||
} | } | ||||
void | void | ||||
ipfw_dyn_uninit(int pass) | ipfw_dyn_uninit(int pass) | ||||
{ | { | ||||
int i; | int i; | ||||
if (pass == 0) { | if (pass == 0) { | ||||
callout_drain(&V_ipfw_timeout); | callout_drain(&V_ipfw_timeout); | ||||
return; | return; | ||||
} | } | ||||
IPFW_DEL_OBJ_REWRITER(IS_DEFAULT_VNET(curvnet), dyn_opcodes); | |||||
if (V_ipfw_dyn_v != NULL) { | if (V_ipfw_dyn_v != NULL) { | ||||
/* | /* | ||||
* Skip deleting all dynamic states - | * Skip deleting all dynamic states - | ||||
* uma_zdestroy() does this more efficiently; | * uma_zdestroy() does this more efficiently; | ||||
*/ | */ | ||||
/* Destroy all mutexes */ | /* Destroy all mutexes */ | ||||
▲ Show 20 Lines • Show All 182 Lines • Show Last 20 Lines |