|
|
@@ -112,6 +112,23 @@ static void nft_trans_destroy(struct nft_trans *trans)
|
|
|
kfree(trans);
|
|
|
}
|
|
|
|
|
|
+static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
|
|
|
+{
|
|
|
+ struct net *net = ctx->net;
|
|
|
+ struct nft_trans *trans;
|
|
|
+
|
|
|
+ if (!nft_set_is_anonymous(set))
|
|
|
+ return;
|
|
|
+
|
|
|
+ list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
|
|
|
+ if (trans->msg_type == NFT_MSG_NEWSET &&
|
|
|
+ nft_trans_set(trans) == set) {
|
|
|
+ nft_trans_set_bound(trans) = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int nf_tables_register_hook(struct net *net,
|
|
|
const struct nft_table *table,
|
|
|
struct nft_chain *chain)
|
|
|
@@ -207,18 +224,6 @@ static int nft_delchain(struct nft_ctx *ctx)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-/* either expr ops provide both activate/deactivate, or neither */
|
|
|
-static bool nft_expr_check_ops(const struct nft_expr_ops *ops)
|
|
|
-{
|
|
|
- if (!ops)
|
|
|
- return true;
|
|
|
-
|
|
|
- if (WARN_ON_ONCE((!ops->activate ^ !ops->deactivate)))
|
|
|
- return false;
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
|
|
|
struct nft_rule *rule)
|
|
|
{
|
|
|
@@ -234,14 +239,15 @@ static void nft_rule_expr_activate(const struct nft_ctx *ctx,
|
|
|
}
|
|
|
|
|
|
static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
|
|
|
- struct nft_rule *rule)
|
|
|
+ struct nft_rule *rule,
|
|
|
+ enum nft_trans_phase phase)
|
|
|
{
|
|
|
struct nft_expr *expr;
|
|
|
|
|
|
expr = nft_expr_first(rule);
|
|
|
while (expr != nft_expr_last(rule) && expr->ops) {
|
|
|
if (expr->ops->deactivate)
|
|
|
- expr->ops->deactivate(ctx, expr);
|
|
|
+ expr->ops->deactivate(ctx, expr, phase);
|
|
|
|
|
|
expr = nft_expr_next(expr);
|
|
|
}
|
|
|
@@ -292,7 +298,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
|
|
|
nft_trans_destroy(trans);
|
|
|
return err;
|
|
|
}
|
|
|
- nft_rule_expr_deactivate(ctx, rule);
|
|
|
+ nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_PREPARE);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -1926,9 +1932,6 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
|
|
|
*/
|
|
|
int nft_register_expr(struct nft_expr_type *type)
|
|
|
{
|
|
|
- if (!nft_expr_check_ops(type->ops))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
|
|
if (type->family == NFPROTO_UNSPEC)
|
|
|
list_add_tail_rcu(&type->list, &nf_tables_expressions);
|
|
|
@@ -2076,10 +2079,6 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
|
|
|
err = PTR_ERR(ops);
|
|
|
goto err1;
|
|
|
}
|
|
|
- if (!nft_expr_check_ops(ops)) {
|
|
|
- err = -EINVAL;
|
|
|
- goto err1;
|
|
|
- }
|
|
|
} else
|
|
|
ops = type->ops;
|
|
|
|
|
|
@@ -2477,7 +2476,7 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
|
|
|
static void nf_tables_rule_release(const struct nft_ctx *ctx,
|
|
|
struct nft_rule *rule)
|
|
|
{
|
|
|
- nft_rule_expr_deactivate(ctx, rule);
|
|
|
+ nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE);
|
|
|
nf_tables_rule_destroy(ctx, rule);
|
|
|
}
|
|
|
|
|
|
@@ -3677,39 +3676,30 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
bind:
|
|
|
binding->chain = ctx->chain;
|
|
|
list_add_tail_rcu(&binding->list, &set->bindings);
|
|
|
+ nft_set_trans_bind(ctx, set);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nf_tables_bind_set);
|
|
|
|
|
|
-void nf_tables_rebind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
- struct nft_set_binding *binding)
|
|
|
-{
|
|
|
- if (list_empty(&set->bindings) && nft_set_is_anonymous(set) &&
|
|
|
- nft_is_active(ctx->net, set))
|
|
|
- list_add_tail_rcu(&set->list, &ctx->table->sets);
|
|
|
-
|
|
|
- list_add_tail_rcu(&binding->list, &set->bindings);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(nf_tables_rebind_set);
|
|
|
-
|
|
|
void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|
|
- struct nft_set_binding *binding)
|
|
|
+ struct nft_set_binding *binding, bool event)
|
|
|
{
|
|
|
list_del_rcu(&binding->list);
|
|
|
|
|
|
- if (list_empty(&set->bindings) && nft_set_is_anonymous(set) &&
|
|
|
- nft_is_active(ctx->net, set))
|
|
|
+ if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) {
|
|
|
list_del_rcu(&set->list);
|
|
|
+ if (event)
|
|
|
+ nf_tables_set_notify(ctx, set, NFT_MSG_DELSET,
|
|
|
+ GFP_KERNEL);
|
|
|
+ }
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nf_tables_unbind_set);
|
|
|
|
|
|
void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set)
|
|
|
{
|
|
|
- if (list_empty(&set->bindings) && nft_set_is_anonymous(set) &&
|
|
|
- nft_is_active(ctx->net, set)) {
|
|
|
- nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC);
|
|
|
+ if (list_empty(&set->bindings) && nft_set_is_anonymous(set))
|
|
|
nft_set_destroy(set);
|
|
|
- }
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nf_tables_destroy_set);
|
|
|
|
|
|
@@ -6462,6 +6452,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
|
|
|
nf_tables_rule_notify(&trans->ctx,
|
|
|
nft_trans_rule(trans),
|
|
|
NFT_MSG_DELRULE);
|
|
|
+ nft_rule_expr_deactivate(&trans->ctx,
|
|
|
+ nft_trans_rule(trans),
|
|
|
+ NFT_TRANS_COMMIT);
|
|
|
break;
|
|
|
case NFT_MSG_NEWSET:
|
|
|
nft_clear(net, nft_trans_set(trans));
|
|
|
@@ -6549,7 +6542,8 @@ static void nf_tables_abort_release(struct nft_trans *trans)
|
|
|
nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
|
|
|
break;
|
|
|
case NFT_MSG_NEWSET:
|
|
|
- nft_set_destroy(nft_trans_set(trans));
|
|
|
+ if (!nft_trans_set_bound(trans))
|
|
|
+ nft_set_destroy(nft_trans_set(trans));
|
|
|
break;
|
|
|
case NFT_MSG_NEWSETELEM:
|
|
|
nft_set_elem_destroy(nft_trans_elem_set(trans),
|
|
|
@@ -6610,7 +6604,9 @@ static int __nf_tables_abort(struct net *net)
|
|
|
case NFT_MSG_NEWRULE:
|
|
|
trans->ctx.chain->use--;
|
|
|
list_del_rcu(&nft_trans_rule(trans)->list);
|
|
|
- nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans));
|
|
|
+ nft_rule_expr_deactivate(&trans->ctx,
|
|
|
+ nft_trans_rule(trans),
|
|
|
+ NFT_TRANS_ABORT);
|
|
|
break;
|
|
|
case NFT_MSG_DELRULE:
|
|
|
trans->ctx.chain->use++;
|
|
|
@@ -6620,7 +6616,8 @@ static int __nf_tables_abort(struct net *net)
|
|
|
break;
|
|
|
case NFT_MSG_NEWSET:
|
|
|
trans->ctx.table->use--;
|
|
|
- list_del_rcu(&nft_trans_set(trans)->list);
|
|
|
+ if (!nft_trans_set_bound(trans))
|
|
|
+ list_del_rcu(&nft_trans_set(trans)->list);
|
|
|
break;
|
|
|
case NFT_MSG_DELSET:
|
|
|
trans->ctx.table->use++;
|