Page MenuHomeFreeBSD

D17532.id49053.diff
No OneTemporary

D17532.id49053.diff

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

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)

Event Timeline