|
@@ -29,6 +29,9 @@ struct nft_xt {
|
|
|
struct nft_expr_ops ops;
|
|
struct nft_expr_ops ops;
|
|
|
refcount_t refcnt;
|
|
refcount_t refcnt;
|
|
|
|
|
|
|
|
|
|
+ /* used only when transaction mutex is locked */
|
|
|
|
|
+ unsigned int listcnt;
|
|
|
|
|
+
|
|
|
/* Unlike other expressions, ops doesn't have static storage duration.
|
|
/* Unlike other expressions, ops doesn't have static storage duration.
|
|
|
* nft core assumes they do. We use kfree_rcu so that nft core can
|
|
* nft core assumes they do. We use kfree_rcu so that nft core can
|
|
|
* can check expr->ops->size even after nft_compat->destroy() frees
|
|
* can check expr->ops->size even after nft_compat->destroy() frees
|
|
@@ -61,7 +64,7 @@ static struct nft_compat_net *nft_compat_pernet(struct net *net)
|
|
|
static bool nft_xt_put(struct nft_xt *xt)
|
|
static bool nft_xt_put(struct nft_xt *xt)
|
|
|
{
|
|
{
|
|
|
if (refcount_dec_and_test(&xt->refcnt)) {
|
|
if (refcount_dec_and_test(&xt->refcnt)) {
|
|
|
- list_del(&xt->head);
|
|
|
|
|
|
|
+ WARN_ON_ONCE(!list_empty(&xt->head));
|
|
|
kfree_rcu(xt, rcu_head);
|
|
kfree_rcu(xt, rcu_head);
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -537,6 +540,43 @@ nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
|
|
__nft_match_destroy(ctx, expr, nft_expr_priv(expr));
|
|
__nft_match_destroy(ctx, expr, nft_expr_priv(expr));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void nft_compat_activate(const struct nft_ctx *ctx,
|
|
|
|
|
+ const struct nft_expr *expr,
|
|
|
|
|
+ struct list_head *h)
|
|
|
|
|
+{
|
|
|
|
|
+ struct nft_xt *xt = container_of(expr->ops, struct nft_xt, ops);
|
|
|
|
|
+
|
|
|
|
|
+ if (xt->listcnt == 0)
|
|
|
|
|
+ list_add(&xt->head, h);
|
|
|
|
|
+
|
|
|
|
|
+ xt->listcnt++;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void nft_compat_activate_mt(const struct nft_ctx *ctx,
|
|
|
|
|
+ const struct nft_expr *expr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct nft_compat_net *cn = nft_compat_pernet(ctx->net);
|
|
|
|
|
+
|
|
|
|
|
+ nft_compat_activate(ctx, expr, &cn->nft_match_list);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void nft_compat_activate_tg(const struct nft_ctx *ctx,
|
|
|
|
|
+ const struct nft_expr *expr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct nft_compat_net *cn = nft_compat_pernet(ctx->net);
|
|
|
|
|
+
|
|
|
|
|
+ nft_compat_activate(ctx, expr, &cn->nft_target_list);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void nft_compat_deactivate(const struct nft_ctx *ctx,
|
|
|
|
|
+ const struct nft_expr *expr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct nft_xt *xt = container_of(expr->ops, struct nft_xt, ops);
|
|
|
|
|
+
|
|
|
|
|
+ if (--xt->listcnt == 0)
|
|
|
|
|
+ list_del_init(&xt->head);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void
|
|
static void
|
|
|
nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
|
nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
|
|
{
|
|
{
|
|
@@ -789,6 +829,8 @@ nft_match_select_ops(const struct nft_ctx *ctx,
|
|
|
nft_match->ops.eval = nft_match_eval;
|
|
nft_match->ops.eval = nft_match_eval;
|
|
|
nft_match->ops.init = nft_match_init;
|
|
nft_match->ops.init = nft_match_init;
|
|
|
nft_match->ops.destroy = nft_match_destroy;
|
|
nft_match->ops.destroy = nft_match_destroy;
|
|
|
|
|
+ nft_match->ops.activate = nft_compat_activate_mt;
|
|
|
|
|
+ nft_match->ops.deactivate = nft_compat_deactivate;
|
|
|
nft_match->ops.dump = nft_match_dump;
|
|
nft_match->ops.dump = nft_match_dump;
|
|
|
nft_match->ops.validate = nft_match_validate;
|
|
nft_match->ops.validate = nft_match_validate;
|
|
|
nft_match->ops.data = match;
|
|
nft_match->ops.data = match;
|
|
@@ -805,6 +847,7 @@ nft_match_select_ops(const struct nft_ctx *ctx,
|
|
|
|
|
|
|
|
nft_match->ops.size = matchsize;
|
|
nft_match->ops.size = matchsize;
|
|
|
|
|
|
|
|
|
|
+ nft_match->listcnt = 1;
|
|
|
list_add(&nft_match->head, &cn->nft_match_list);
|
|
list_add(&nft_match->head, &cn->nft_match_list);
|
|
|
|
|
|
|
|
return &nft_match->ops;
|
|
return &nft_match->ops;
|
|
@@ -891,6 +934,8 @@ nft_target_select_ops(const struct nft_ctx *ctx,
|
|
|
nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
|
|
nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
|
|
|
nft_target->ops.init = nft_target_init;
|
|
nft_target->ops.init = nft_target_init;
|
|
|
nft_target->ops.destroy = nft_target_destroy;
|
|
nft_target->ops.destroy = nft_target_destroy;
|
|
|
|
|
+ nft_target->ops.activate = nft_compat_activate_tg;
|
|
|
|
|
+ nft_target->ops.deactivate = nft_compat_deactivate;
|
|
|
nft_target->ops.dump = nft_target_dump;
|
|
nft_target->ops.dump = nft_target_dump;
|
|
|
nft_target->ops.validate = nft_target_validate;
|
|
nft_target->ops.validate = nft_target_validate;
|
|
|
nft_target->ops.data = target;
|
|
nft_target->ops.data = target;
|
|
@@ -900,6 +945,7 @@ nft_target_select_ops(const struct nft_ctx *ctx,
|
|
|
else
|
|
else
|
|
|
nft_target->ops.eval = nft_target_eval_xt;
|
|
nft_target->ops.eval = nft_target_eval_xt;
|
|
|
|
|
|
|
|
|
|
+ nft_target->listcnt = 1;
|
|
|
list_add(&nft_target->head, &cn->nft_target_list);
|
|
list_add(&nft_target->head, &cn->nft_target_list);
|
|
|
|
|
|
|
|
return &nft_target->ops;
|
|
return &nft_target->ops;
|