Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135446308
D17532.id49053.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D17532.id49053.diff
View Options
Index: sys/netpfil/ipfw/ip_fw_dynamic.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_dynamic.c
+++ sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -122,6 +122,12 @@
(d)->bcnt_ ## dir += pktlen; \
} while (0)
+#define DYN_REFERENCED 0x01
+/*
+ * DYN_REFERENCED flag is used to show that state keeps reference to named
+ * object, and this reference should be released when state becomes expired.
+ */
+
struct dyn_data {
void *parent; /* pointer to parent rule */
uint32_t chain_id; /* cached ruleset id */
@@ -129,7 +135,8 @@
uint32_t hashval; /* hash value used for hash resize */
uint16_t fibnum; /* fib used to send keepalives */
- uint8_t _pad[3];
+ uint8_t _pad[2];
+ uint8_t flags; /* internal flags */
uint8_t set; /* parent rule set number */
uint16_t rulenum; /* parent rule number */
uint32_t ruleid; /* parent rule id */
@@ -709,6 +716,8 @@
IPFW_UH_WLOCK_ASSERT(ch);
+ KASSERT(no->etlv == IPFW_TLV_STATE_NAME,
+ ("%s: wrong object type %u", __func__, no->etlv));
KASSERT(no->refcnt == 1,
("Destroying object '%s' (type %u, idx %u) with refcnt %u",
no->name, no->etlv, no->kidx, no->refcnt));
@@ -1397,20 +1406,29 @@
* should be deleted by dyn_expire_states().
*
* In case when dyn_keep_states is enabled, return
- * pointer to default rule and corresponding f_pos
- * value.
- * XXX: In this case we lose the cache efficiency,
- * since f_pos is not cached, because it seems
- * there is no easy way to atomically switch
- * all fields related to parent rule of given
- * state.
+ * pointer to deleted rule and f_pos value
+ * corresponding to penultimate rule.
+ * When we have enabled V_dyn_keep_states, states
+ * that become orphaned will get the DYN_REFERENCED
+ * flag and rule will keep around. So we can return
+ * it. But since it is not in the rules map, we need
+ * return such f_pos value, so after the state
+ * handling if the search will continue, the next rule
+ * will be the last one - the default rule.
*/
if (V_layer3_chain.map[data->f_pos] == rule) {
data->chain_id = V_layer3_chain.id;
info->f_pos = data->f_pos;
} else if (V_dyn_keep_states != 0) {
- rule = V_layer3_chain.default_rule;
- info->f_pos = V_layer3_chain.n_rules - 1;
+ /*
+ * The original rule pointer is still usable.
+ * So, we return it, but f_pos need to be
+ * changed to point to the penultimate rule.
+ */
+ MPASS(V_layer3_chain.n_rules > 1);
+ data->chain_id = V_layer3_chain.id;
+ data->f_pos = V_layer3_chain.n_rules - 2;
+ info->f_pos = data->f_pos;
} else {
rule = NULL;
info->direction = MATCH_NONE;
@@ -2110,40 +2128,94 @@
return (1);
}
+static void
+dyn_acquire_rule(struct ip_fw_chain *ch, struct dyn_data *data,
+ struct ip_fw *rule, uint16_t kidx)
+{
+ struct dyn_state_obj *obj;
+
+ /*
+ * Do not acquire reference twice.
+ * This can happen when rule deletion executed for
+ * the same range, but different ruleset id.
+ */
+ if (data->flags & DYN_REFERENCED)
+ return;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ MPASS(kidx != 0);
+
+ data->flags |= DYN_REFERENCED;
+ /* Reference the named object */
+ obj = SRV_OBJECT(ch, kidx);
+ obj->no.refcnt++;
+ MPASS(obj->no.etlv == IPFW_TLV_STATE_NAME);
+
+ /* Reference the parent rule */
+ rule->refcnt++;
+}
+
+static void
+dyn_release_rule(struct ip_fw_chain *ch, struct dyn_data *data,
+ struct ip_fw *rule, uint16_t kidx)
+{
+ struct dyn_state_obj *obj;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ MPASS(kidx != 0);
+
+ obj = SRV_OBJECT(ch, kidx);
+ if (obj->no.refcnt == 1)
+ dyn_destroy(ch, &obj->no);
+ else
+ obj->no.refcnt--;
+
+ if (--rule->refcnt == 1)
+ ipfw_free_rule(rule);
+}
+
static int
-dyn_match_ipv4_state(struct dyn_ipv4_state *s, const ipfw_range_tlv *rt)
+dyn_match_ipv4_state(struct ip_fw_chain *ch, struct dyn_ipv4_state *s,
+ const ipfw_range_tlv *rt)
{
+ struct ip_fw *rule;
+ int ret;
if (s->type == O_LIMIT_PARENT)
return (dyn_match_range(s->limit->rulenum,
s->limit->set, rt));
- if (s->type == O_LIMIT)
- return (dyn_match_range(s->data->rulenum, s->data->set, rt));
+ ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
+ if (ret == 0 || V_dyn_keep_states == 0)
+ return (ret);
- if (V_dyn_keep_states == 0 &&
- dyn_match_range(s->data->rulenum, s->data->set, rt))
- return (1);
-
+ rule = s->data->parent;
+ if (s->type == O_LIMIT)
+ rule = ((struct dyn_ipv4_state *)rule)->limit->parent;
+ dyn_acquire_rule(ch, s->data, rule, s->kidx);
return (0);
}
#ifdef INET6
static int
-dyn_match_ipv6_state(struct dyn_ipv6_state *s, const ipfw_range_tlv *rt)
+dyn_match_ipv6_state(struct ip_fw_chain *ch, struct dyn_ipv6_state *s,
+ const ipfw_range_tlv *rt)
{
+ struct ip_fw *rule;
+ int ret;
if (s->type == O_LIMIT_PARENT)
return (dyn_match_range(s->limit->rulenum,
s->limit->set, rt));
- if (s->type == O_LIMIT)
- return (dyn_match_range(s->data->rulenum, s->data->set, rt));
+ ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
+ if (ret == 0 || V_dyn_keep_states == 0)
+ return (ret);
- if (V_dyn_keep_states == 0 &&
- dyn_match_range(s->data->rulenum, s->data->set, rt))
- return (1);
-
+ rule = s->data->parent;
+ if (s->type == O_LIMIT)
+ rule = ((struct dyn_ipv6_state *)rule)->limit->parent;
+ dyn_acquire_rule(ch, s->data, rule, s->kidx);
return (0);
}
#endif
@@ -2153,7 +2225,7 @@
* @rt can be used to specify the range of states for deletion.
*/
static void
-dyn_expire_states(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
+dyn_expire_states(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
{
struct dyn_ipv4_slist expired_ipv4;
#ifdef INET6
@@ -2161,8 +2233,11 @@
struct dyn_ipv6_state *s6, *s6n, *s6p;
#endif
struct dyn_ipv4_state *s4, *s4n, *s4p;
+ 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:
@@ -2187,7 +2262,8 @@
while (s != NULL) { \
next = CK_SLIST_NEXT(s, entry); \
if ((TIME_LEQ((s)->exp, time_uptime) && extra) || \
- (rt != NULL && dyn_match_ ## af ## _state(s, rt))) {\
+ (rt != NULL && \
+ dyn_match_ ## af ## _state(ch, s, rt))) { \
if (prev != NULL) \
CK_SLIST_REMOVE_AFTER(prev, entry); \
else \
@@ -2199,6 +2275,14 @@
DYN_COUNT_DEC(dyn_parent_count); \
else { \
DYN_COUNT_DEC(dyn_count); \
+ if (s->data->flags & DYN_REFERENCED) { \
+ rule = s->data->parent; \
+ if (s->type == O_LIMIT) \
+ rule = ((__typeof(s)) \
+ rule)->limit->parent;\
+ dyn_release_rule(ch, s->data, \
+ rule, s->kidx); \
+ } \
if (s->type == O_LIMIT) { \
s = s->data->parent; \
DPARENT_COUNT_DEC(s->limit); \
@@ -2683,6 +2767,42 @@
}
/*
+ * Pass through all states and reset eaction for orphaned rules.
+ */
+void
+ipfw_dyn_reset_eaction(struct ip_fw_chain *ch, uint16_t eaction_id,
+ uint16_t default_id, uint16_t instance_id)
+{
+#ifdef INET6
+ struct dyn_ipv6_state *s6;
+#endif
+ struct dyn_ipv4_state *s4;
+ struct ip_fw *rule;
+ uint32_t bucket;
+
+#define DYN_RESET_EACTION(s, h, b) \
+ CK_SLIST_FOREACH(s, &V_dyn_ ## h[b], entry) { \
+ if ((s->data->flags & DYN_REFERENCED) == 0) \
+ continue; \
+ rule = s->data->parent; \
+ if (s->type == O_LIMIT) \
+ rule = ((__typeof(s))rule)->limit->parent; \
+ ipfw_reset_eaction(ch, rule, eaction_id, \
+ default_id, instance_id); \
+ }
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ if (V_dyn_count == 0)
+ return;
+ for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+ DYN_RESET_EACTION(s4, ipv4, bucket);
+#ifdef INET6
+ DYN_RESET_EACTION(s6, ipv6, bucket);
+#endif
+ }
+}
+
+/*
* Returns size of dynamic states in legacy format
*/
int
@@ -2694,11 +2814,42 @@
/*
* Returns number of dynamic states.
+ * Marks every named object index used by dynamic states with bit in @bmask.
+ * Returns number of named objects accounted in bmask via @nocnt.
* Used by dump format v1 (current).
*/
uint32_t
-ipfw_dyn_get_count(void)
+ipfw_dyn_get_count(uint32_t *bmask, int *nocnt)
{
+#ifdef INET6
+ struct dyn_ipv6_state *s6;
+#endif
+ struct dyn_ipv4_state *s4;
+ uint32_t bucket;
+
+#define DYN_COUNT_OBJECTS(s, h, b) \
+ CK_SLIST_FOREACH(s, &V_dyn_ ## h[b], entry) { \
+ MPASS(s->kidx != 0); \
+ if (ipfw_mark_object_kidx(bmask, IPFW_TLV_STATE_NAME, \
+ s->kidx) != 0) \
+ (*nocnt)++; \
+ }
+
+ IPFW_UH_RLOCK_ASSERT(&V_layer3_chain);
+
+ /* No need to pass through all the buckets. */
+ *nocnt = 0;
+ if (V_dyn_count + V_dyn_parent_count == 0)
+ return (0);
+
+ for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+ DYN_COUNT_OBJECTS(s4, ipv4, bucket);
+ DYN_COUNT_OBJECTS(s4, ipv4_parent, bucket);
+#ifdef INET6
+ DYN_COUNT_OBJECTS(s6, ipv6, bucket);
+ DYN_COUNT_OBJECTS(s6, ipv6_parent, bucket);
+#endif
+ }
return (V_dyn_count + V_dyn_parent_count);
}
Index: sys/netpfil/ipfw/ip_fw_eaction.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_eaction.c
+++ sys/netpfil/ipfw/ip_fw_eaction.c
@@ -252,11 +252,10 @@
* Resets all eaction opcodes to default handlers.
*/
static void
-reset_eaction_obj(struct ip_fw_chain *ch, uint16_t eaction_id)
+reset_eaction_rules(struct ip_fw_chain *ch, uint16_t eaction_id,
+ uint16_t instance_id, bool reset_rules)
{
struct named_object *no;
- struct ip_fw *rule;
- ipfw_insn *cmd;
int i;
IPFW_UH_WLOCK_ASSERT(ch);
@@ -267,35 +266,32 @@
panic("Default external action handler is not found");
if (eaction_id == no->kidx)
panic("Wrong eaction_id");
- EACTION_DEBUG("replace id %u with %u", eaction_id, no->kidx);
+
+ EACTION_DEBUG("Going to replace id %u with %u", eaction_id, no->kidx);
IPFW_WLOCK(ch);
- for (i = 0; i < ch->n_rules; i++) {
- rule = ch->map[i];
- cmd = ACTION_PTR(rule);
- if (cmd->opcode != O_EXTERNAL_ACTION)
- continue;
- if (cmd->arg1 != eaction_id)
- continue;
- cmd->arg1 = no->kidx; /* Set to default id */
- /*
- * XXX: we only bump refcount on default_eaction.
- * Refcount on the original object will be just
- * ignored on destroy. But on default_eaction it
- * will be decremented on rule deletion.
- */
- no->refcnt++;
- /*
- * Since named_object related to this instance will be
- * also destroyed, truncate the chain of opcodes to
- * remove the rest of cmd chain just after O_EXTERNAL_ACTION
- * opcode.
- */
- if (rule->act_ofs < rule->cmd_len - 1) {
- EACTION_DEBUG("truncate rule %d: len %u -> %u",
- rule->rulenum, rule->cmd_len, rule->act_ofs + 1);
- rule->cmd_len = rule->act_ofs + 1;
+ /*
+ * Reset eaction objects only if it is referenced by rules.
+ * But always reset objects for orphaned dynamic states.
+ */
+ if (reset_rules) {
+ for (i = 0; i < ch->n_rules; i++) {
+ /*
+ * Refcount on the original object will be just
+ * ignored on destroy. Refcount on default_eaction
+ * will be decremented on rule deletion, thus we
+ * need to reference default_eaction object.
+ */
+ if (ipfw_reset_eaction(ch, ch->map[i], eaction_id,
+ no->kidx, instance_id) != 0)
+ no->refcnt++;
}
}
+ /*
+ * Reset eaction opcodes for orphaned dynamic states.
+ * Since parent rules are already deleted, we don't need to
+ * reference named object of default_eaction.
+ */
+ ipfw_dyn_reset_eaction(ch, eaction_id, no->kidx, instance_id);
IPFW_WUNLOCK(ch);
}
@@ -368,12 +364,71 @@
IPFW_UH_WUNLOCK(ch);
return (EINVAL);
}
- if (no->refcnt > 1)
- reset_eaction_obj(ch, eaction_id);
+ reset_eaction_rules(ch, eaction_id, 0, (no->refcnt > 1));
EACTION_DEBUG("External action '%s' with id %u unregistered",
no->name, eaction_id);
destroy_eaction_obj(ch, no);
IPFW_UH_WUNLOCK(ch);
+ return (0);
+}
+
+int
+ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule,
+ uint16_t eaction_id, uint16_t default_id, uint16_t instance_id)
+{
+ ipfw_insn *cmd, *icmd;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ IPFW_WLOCK_ASSERT(ch);
+
+ cmd = ACTION_PTR(rule);
+ if (cmd->opcode != O_EXTERNAL_ACTION ||
+ cmd->arg1 != eaction_id)
+ return (0);
+
+ if (instance_id != 0 && rule->act_ofs < rule->cmd_len - 1) {
+ icmd = cmd + 1;
+ if (icmd->opcode != O_EXTERNAL_INSTANCE ||
+ icmd->arg1 != instance_id)
+ return (0);
+ /* FALLTHROUGH */
+ }
+
+ cmd->arg1 = default_id; /* Set to default id */
+ /*
+ * Since named_object related to this instance will be
+ * also destroyed, truncate the chain of opcodes to
+ * remove the rest of cmd chain just after O_EXTERNAL_ACTION
+ * opcode.
+ */
+ if (rule->act_ofs < rule->cmd_len - 1) {
+ EACTION_DEBUG("truncate rule %d: len %u -> %u",
+ rule->rulenum, rule->cmd_len, rule->act_ofs + 1);
+ rule->cmd_len = rule->act_ofs + 1;
+ }
+ /*
+ * Return 1 when reset successfully happened.
+ */
+ return (1);
+}
+
+/*
+ * This function should be called before external action instance is
+ * destroyed. It will reset eaction_id to default_id for rules, where
+ * eaction has instance with id == kidx.
+ */
+int
+ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint16_t eaction_id,
+ uint16_t kidx)
+{
+ struct named_object *no;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ no = ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), eaction_id);
+ if (no == NULL || no->etlv != IPFW_TLV_EACTION)
+ return (EINVAL);
+
+ reset_eaction_rules(ch, eaction_id, kidx, 0);
return (0);
}
Index: sys/netpfil/ipfw/ip_fw_private.h
===================================================================
--- sys/netpfil/ipfw/ip_fw_private.h
+++ sys/netpfil/ipfw/ip_fw_private.h
@@ -146,6 +146,9 @@
/*
* Function definitions.
*/
+int ipfw_chk(struct ip_fw_args *args);
+struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
+ u_int32_t, u_int32_t, int);
/* attach (arg = 1) or detach (arg = 0) hooks */
int ipfw_attach_hooks(int);
@@ -156,6 +159,7 @@
/* In ip_fw_log.c */
struct ip;
struct ip_fw_chain;
+
void ipfw_bpf_init(int);
void ipfw_bpf_uninit(int);
void ipfw_bpf_mtap2(void *, u_int, struct mbuf *);
@@ -168,6 +172,7 @@
#define V_verbose_limit VNET(verbose_limit)
/* In ip_fw_dynamic.c */
+struct sockopt_data;
enum { /* result for matching dynamic rules */
MATCH_REVERSE = 0,
@@ -177,19 +182,6 @@
};
/*
- * The lock for dynamic rules is only used once outside the file,
- * and only to release the result of lookup_dyn_rule().
- * Eventually we may implement it with a callback on the function.
- */
-struct ip_fw_chain;
-struct sockopt_data;
-int ipfw_is_dyn_rule(struct ip_fw *rule);
-void ipfw_expire_dyn_states(struct ip_fw_chain *, ipfw_range_tlv *);
-
-struct tcphdr;
-struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
- u_int32_t, u_int32_t, int);
-/*
* Macro to determine that we need to do or redo dynamic state lookup.
* direction == MATCH_UNKNOWN means that this is first lookup, then we need
* to do lookup.
@@ -219,13 +211,17 @@
const void *ulp, int pktlen, const ipfw_insn *cmd,
struct ipfw_dyn_info *info);
+int ipfw_is_dyn_rule(struct ip_fw *rule);
+void ipfw_expire_dyn_states(struct ip_fw_chain *, ipfw_range_tlv *);
void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
int ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd);
void ipfw_dyn_init(struct ip_fw_chain *); /* per-vnet initialization */
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
int ipfw_dyn_len(void);
-uint32_t ipfw_dyn_get_count(void);
+uint32_t ipfw_dyn_get_count(uint32_t *, int *);
+void ipfw_dyn_reset_eaction(struct ip_fw_chain *ch, uint16_t eaction_id,
+ uint16_t default_id, uint16_t instance_id);
/* common variables */
VNET_DECLARE(int, fw_one_pass);
@@ -280,7 +276,9 @@
uint32_t id; /* rule id */
uint32_t cached_id; /* used by jump_fast */
uint32_t cached_pos; /* used by jump_fast */
+ uint32_t refcnt; /* number of references */
+ struct ip_fw *next; /* linked list of deleted rules */
ipfw_insn cmd[1]; /* storage for commands */
};
@@ -650,7 +648,6 @@
void ipfw_destroy_skipto_cache(struct ip_fw_chain *chain);
int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
int ipfw_ctl3(struct sockopt *sopt);
-int ipfw_chk(struct ip_fw_args *args);
int ipfw_add_protected_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
int locked);
void ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
@@ -659,7 +656,9 @@
void ipfw_init_counters(void);
void ipfw_destroy_counters(void);
struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize);
+void ipfw_free_rule(struct ip_fw *rule);
int ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt);
+int ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx);
typedef int (sopt_handler_f)(struct ip_fw_chain *ch,
ip_fw3_opheader *op3, struct sockopt_data *sd);
@@ -758,6 +757,10 @@
int ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id);
int ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args,
ipfw_insn *cmd, int *done);
+int ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule,
+ uint16_t eaction_id, uint16_t default_id, uint16_t instance_id);
+int ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint16_t eaction_id,
+ uint16_t instance_id);
/* In ip_fw_table.c */
struct table_info;
Index: sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_sockopt.c
+++ sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -161,8 +161,6 @@
set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule);
static struct opcode_obj_rewrite *find_op_rw(ipfw_insn *cmd,
uint16_t *puidx, uint8_t *ptype);
-static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
- uint32_t *bmask);
static int ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti);
static int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd,
@@ -209,14 +207,23 @@
rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
rule->cntr = uma_zalloc_pcpu(V_ipfw_cntr_zone, M_WAITOK | M_ZERO);
+ rule->refcnt = 1;
return (rule);
}
-static void
-free_rule(struct ip_fw *rule)
+void
+ipfw_free_rule(struct ip_fw *rule)
{
+ /*
+ * We don't release refcnt here, since this function
+ * can be called without any locks held. The caller
+ * must release reference under IPFW_UH_WLOCK, and then
+ * call this function if refcount becomes 1.
+ */
+ if (rule->refcnt > 1)
+ return;
uma_zfree_pcpu(V_ipfw_cntr_zone, rule->cntr);
free(rule, M_IPFW);
}
@@ -827,7 +834,7 @@
/* Unlink rule from everywhere */
unref_rule_objects(chain, rule);
- *((struct ip_fw **)rule) = *head;
+ rule->next = *head;
*head = rule;
}
@@ -842,8 +849,8 @@
struct ip_fw *rule;
while ((rule = head) != NULL) {
- head = *((struct ip_fw **)head);
- free_rule(rule);
+ head = head->next;
+ ipfw_free_rule(rule);
}
}
@@ -2187,6 +2194,7 @@
uint32_t rsize; /* rules size */
uint32_t tcount; /* number of tables */
int rcounters; /* counters */
+ uint32_t *bmask; /* index bitmask of used named objects */
};
void
@@ -2223,6 +2231,49 @@
return (0);
}
+static int
+export_named_objects(struct namedobj_instance *ni, struct dump_args *da,
+ struct sockopt_data *sd)
+{
+ int error, i;
+
+ for (i = 0; i < IPFW_TABLES_MAX && da->tcount > 0; i++) {
+ if ((da->bmask[i / 32] & (1 << (i % 32))) == 0)
+ continue;
+ if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
+ return (error);
+ da->tcount--;
+ }
+ return (0);
+}
+
+static int
+dump_named_objects(struct ip_fw_chain *ch, struct dump_args *da,
+ struct sockopt_data *sd)
+{
+ ipfw_obj_ctlv *ctlv;
+ int error;
+
+ MPASS(da->tcount > 0);
+ /* Header first */
+ ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
+ if (ctlv == NULL)
+ return (ENOMEM);
+ ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
+ ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
+ sizeof(*ctlv);
+ ctlv->count = da->tcount;
+ ctlv->objsize = sizeof(ipfw_obj_ntlv);
+
+ /* Dump table names first (if any) */
+ error = export_named_objects(ipfw_get_table_objhash(ch), da, sd);
+ if (error != 0)
+ return (error);
+ /* Then dump another named objects */
+ da->bmask += IPFW_TABLES_MAX / 32;
+ return (export_named_objects(CHAIN_TO_SRV(ch), da, sd));
+}
+
/*
* Dumps static rules with table TLVs in buffer @sd.
*
@@ -2230,52 +2281,13 @@
*/
static int
dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
- uint32_t *bmask, struct sockopt_data *sd)
+ struct sockopt_data *sd)
{
- int error;
- int i, l;
- uint32_t tcount;
ipfw_obj_ctlv *ctlv;
struct ip_fw *krule;
- struct namedobj_instance *ni;
caddr_t dst;
+ int i, l;
- /* Dump table names first (if any) */
- if (da->tcount > 0) {
- /* Header first */
- ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
- if (ctlv == NULL)
- return (ENOMEM);
- ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
- ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
- sizeof(*ctlv);
- ctlv->count = da->tcount;
- ctlv->objsize = sizeof(ipfw_obj_ntlv);
- }
-
- i = 0;
- tcount = da->tcount;
- ni = ipfw_get_table_objhash(chain);
- while (tcount > 0) {
- if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
- i++;
- continue;
- }
-
- /* Jump to shared named object bitmask */
- if (i >= IPFW_TABLES_MAX) {
- ni = CHAIN_TO_SRV(chain);
- i -= IPFW_TABLES_MAX;
- bmask += IPFW_TABLES_MAX / 32;
- }
-
- if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
- return (error);
-
- i++;
- tcount--;
- }
-
/* Dump rules */
ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
if (ctlv == NULL)
@@ -2300,27 +2312,41 @@
return (0);
}
+int
+ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx)
+{
+ uint32_t bidx;
+
+ /*
+ * Maintain separate bitmasks for table and non-table objects.
+ */
+ bidx = (etlv == IPFW_TLV_TBL_NAME) ? 0: IPFW_TABLES_MAX / 32;
+ bidx += kidx / 32;
+ if ((bmask[bidx] & (1 << (kidx % 32))) != 0)
+ return (0);
+
+ bmask[bidx] |= 1 << (kidx % 32);
+ return (1);
+}
+
/*
* Marks every object index used in @rule with bit in @bmask.
* Used to generate bitmask of referenced tables/objects for given ruleset
* or its part.
- *
- * Returns number of newly-referenced objects.
*/
-static int
-mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
- uint32_t *bmask)
+static void
+mark_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
+ struct dump_args *da)
{
struct opcode_obj_rewrite *rw;
ipfw_insn *cmd;
- int bidx, cmdlen, l, count;
+ int cmdlen, l;
uint16_t kidx;
uint8_t subtype;
l = rule->cmd_len;
cmd = rule->cmd;
cmdlen = 0;
- count = 0;
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
@@ -2328,21 +2354,9 @@
if (rw == NULL)
continue;
- bidx = kidx / 32;
- /*
- * Maintain separate bitmasks for table and
- * non-table objects.
- */
- if (rw->etlv != IPFW_TLV_TBL_NAME)
- bidx += IPFW_TABLES_MAX / 32;
-
- if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
- count++;
-
- bmask[bidx] |= 1 << (kidx % 32);
+ if (ipfw_mark_object_kidx(da->bmask, rw->etlv, kidx))
+ da->tcount++;
}
-
- return (count);
}
/*
@@ -2366,13 +2380,12 @@
dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
struct sockopt_data *sd)
{
+ struct dump_args da;
ipfw_cfg_lheader *hdr;
struct ip_fw *rule;
size_t sz, rnum;
- uint32_t hdr_flags;
+ uint32_t hdr_flags, *bmask;
int error, i;
- struct dump_args da;
- uint32_t *bmask;
hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
if (hdr == NULL)
@@ -2380,9 +2393,14 @@
error = 0;
bmask = NULL;
- /* Allocate needed state. Note we allocate 2xspace mask, for table&srv */
- if (hdr->flags & IPFW_CFG_GET_STATIC)
- bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
+ memset(&da, 0, sizeof(da));
+ /*
+ * Allocate needed state.
+ * Note we allocate 2xspace mask, for table & srv
+ */
+ if (hdr->flags & (IPFW_CFG_GET_STATIC | IPFW_CFG_GET_STATES))
+ da.bmask = bmask = malloc(IPFW_TABLES_MAX / 16, M_TEMP,
+ M_WAITOK | M_ZERO);
IPFW_UH_RLOCK(chain);
@@ -2391,9 +2409,6 @@
* Prepare used tables bitmask.
*/
sz = sizeof(ipfw_cfg_lheader);
- memset(&da, 0, sizeof(da));
-
- da.b = 0;
da.e = chain->n_rules;
if (hdr->end_rule != 0) {
@@ -2412,24 +2427,25 @@
da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
da.rcount++;
/* Update bitmask of used objects for given range */
- da.tcount += mark_object_kidx(chain, rule, bmask);
+ mark_rule_objects(chain, rule, &da);
}
/* Add counters if requested */
if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
da.rcounters = 1;
}
-
- if (da.tcount > 0)
- sz += da.tcount * sizeof(ipfw_obj_ntlv) +
- sizeof(ipfw_obj_ctlv);
sz += da.rsize + sizeof(ipfw_obj_ctlv);
}
- if (hdr->flags & IPFW_CFG_GET_STATES)
- sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) +
- sizeof(ipfw_obj_ctlv);
+ if (hdr->flags & IPFW_CFG_GET_STATES) {
+ sz += sizeof(ipfw_obj_ctlv) +
+ ipfw_dyn_get_count(bmask, &i) * sizeof(ipfw_obj_dyntlv);
+ da.tcount += i;
+ }
+ if (da.tcount > 0)
+ sz += da.tcount * sizeof(ipfw_obj_ntlv) +
+ sizeof(ipfw_obj_ctlv);
/*
* Fill header anyway.
@@ -2447,8 +2463,14 @@
}
/* STAGE2: Store actual data */
+ if (da.tcount > 0) {
+ error = dump_named_objects(chain, &da, sd);
+ if (error != 0)
+ goto cleanup;
+ }
+
if (hdr_flags & IPFW_CFG_GET_STATIC) {
- error = dump_static_rules(chain, &da, bmask, sd);
+ error = dump_static_rules(chain, &da, sd);
if (error != 0)
goto cleanup;
}
@@ -3027,7 +3049,7 @@
if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
/* Free allocate krules */
for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
- free_rule(ci->krule);
+ ipfw_free_rule(ci->krule);
}
if (cbuf != NULL && cbuf != &rci)
@@ -3851,7 +3873,7 @@
import_rule0(&ci);
error = commit_rules(chain, &ci, 1);
if (error != 0)
- free_rule(ci.krule);
+ ipfw_free_rule(ci.krule);
else if (sopt->sopt_dir == SOPT_GET) {
if (is7) {
error = convert_rule_to_7(rule);
Index: sys/netpfil/ipfw/nat64/nat64lsn_control.c
===================================================================
--- sys/netpfil/ipfw/nat64/nat64lsn_control.c
+++ sys/netpfil/ipfw/nat64/nat64lsn_control.c
@@ -256,6 +256,7 @@
return (EBUSY);
}
+ ipfw_reset_eaction_instance(ch, V_nat64lsn_eid, cfg->no.kidx);
SRV_OBJECT(ch, cfg->no.kidx) = NULL;
nat64lsn_detach_config(ch, cfg);
IPFW_UH_WUNLOCK(ch);
Index: sys/netpfil/ipfw/nat64/nat64stl_control.c
===================================================================
--- sys/netpfil/ipfw/nat64/nat64stl_control.c
+++ sys/netpfil/ipfw/nat64/nat64stl_control.c
@@ -342,6 +342,7 @@
return (EBUSY);
}
+ ipfw_reset_eaction_instance(ch, V_nat64stl_eid, cfg->no.kidx);
SRV_OBJECT(ch, cfg->no.kidx) = NULL;
nat64stl_detach_config(ch, cfg);
IPFW_UH_WUNLOCK(ch);
Index: sys/netpfil/ipfw/nptv6/nptv6.c
===================================================================
--- sys/netpfil/ipfw/nptv6/nptv6.c
+++ sys/netpfil/ipfw/nptv6/nptv6.c
@@ -597,6 +597,7 @@
return (EBUSY);
}
+ ipfw_reset_eaction_instance(ch, V_nptv6_eid, cfg->no.kidx);
SRV_OBJECT(ch, cfg->no.kidx) = NULL;
ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no);
ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 10, 10:57 PM (16 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25124950
Default Alt Text
D17532.id49053.diff (27 KB)
Attached To
Mode
D17532: Implement net.inet.ip.fw.dyn_keep_states for all rule actions, not just for default_to_accept case
Attached
Detach File
Event Timeline
Log In to Comment