Commit 60319eb1 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nf_tables: use new transaction infrastructure to handle elements

Leave the set content in consistent state if we fail to load the
batch. Use the new generic transaction infrastructure to achieve
this.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 55dd6f93
...@@ -446,6 +446,16 @@ struct nft_trans_table { ...@@ -446,6 +446,16 @@ struct nft_trans_table {
#define nft_trans_table_enable(trans) \ #define nft_trans_table_enable(trans) \
(((struct nft_trans_table *)trans->data)->enable) (((struct nft_trans_table *)trans->data)->enable)
struct nft_trans_elem {
struct nft_set *set;
struct nft_set_elem elem;
};
#define nft_trans_elem_set(trans) \
(((struct nft_trans_elem *)trans->data)->set)
#define nft_trans_elem(trans) \
(((struct nft_trans_elem *)trans->data)->elem)
static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule) static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule)
{ {
return (struct nft_expr *)&rule->data[0]; return (struct nft_expr *)&rule->data[0];
......
...@@ -2993,7 +2993,21 @@ static int nf_tables_setelem_notify(const struct nft_ctx *ctx, ...@@ -2993,7 +2993,21 @@ static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
return err; return err;
} }
static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set, static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
int msg_type,
struct nft_set *set)
{
struct nft_trans *trans;
trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_elem));
if (trans == NULL)
return NULL;
nft_trans_elem_set(trans) = set;
return trans;
}
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr) const struct nlattr *attr)
{ {
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
...@@ -3001,6 +3015,7 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -3001,6 +3015,7 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_elem elem; struct nft_set_elem elem;
struct nft_set_binding *binding; struct nft_set_binding *binding;
enum nft_registers dreg; enum nft_registers dreg;
struct nft_trans *trans;
int err; int err;
if (set->size && set->nelems == set->size) if (set->size && set->nelems == set->size)
...@@ -3068,14 +3083,20 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -3068,14 +3083,20 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
} }
} }
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
if (trans == NULL)
goto err3;
err = set->ops->insert(set, &elem); err = set->ops->insert(set, &elem);
if (err < 0) if (err < 0)
goto err3; goto err4;
set->nelems++;
nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_NEWSETELEM, 0); nft_trans_elem(trans) = elem;
list_add(&trans->list, &ctx->net->nft.commit_list);
return 0; return 0;
err4:
kfree(trans);
err3: err3:
if (nla[NFTA_SET_ELEM_DATA] != NULL) if (nla[NFTA_SET_ELEM_DATA] != NULL)
nft_data_uninit(&elem.data, d2.type); nft_data_uninit(&elem.data, d2.type);
...@@ -3093,7 +3114,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb, ...@@ -3093,7 +3114,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
const struct nlattr *attr; const struct nlattr *attr;
struct nft_set *set; struct nft_set *set;
struct nft_ctx ctx; struct nft_ctx ctx;
int rem, err; int rem, err = 0;
err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true); err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true);
if (err < 0) if (err < 0)
...@@ -3115,17 +3136,18 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb, ...@@ -3115,17 +3136,18 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_add_set_elem(&ctx, set, attr); err = nft_add_set_elem(&ctx, set, attr);
if (err < 0) if (err < 0)
return err; break;
} }
return 0; return err;
} }
static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set, static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr) const struct nlattr *attr)
{ {
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_data_desc desc; struct nft_data_desc desc;
struct nft_set_elem elem; struct nft_set_elem elem;
struct nft_trans *trans;
int err; int err;
err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr, err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
...@@ -3149,10 +3171,12 @@ static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -3149,10 +3171,12 @@ static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
if (err < 0) if (err < 0)
goto err2; goto err2;
set->ops->remove(set, &elem); trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
set->nelems--; if (trans == NULL)
goto err2;
nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_DELSETELEM, 0); nft_trans_elem(trans) = elem;
list_add(&trans->list, &ctx->net->nft.commit_list);
nft_data_uninit(&elem.key, NFT_DATA_VALUE); nft_data_uninit(&elem.key, NFT_DATA_VALUE);
if (set->flags & NFT_SET_MAP) if (set->flags & NFT_SET_MAP)
...@@ -3171,7 +3195,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, ...@@ -3171,7 +3195,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
const struct nlattr *attr; const struct nlattr *attr;
struct nft_set *set; struct nft_set *set;
struct nft_ctx ctx; struct nft_ctx ctx;
int rem, err; int rem, err = 0;
err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false); err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
if (err < 0) if (err < 0)
...@@ -3186,9 +3210,9 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, ...@@ -3186,9 +3210,9 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_del_setelem(&ctx, set, attr); err = nft_del_setelem(&ctx, set, attr);
if (err < 0) if (err < 0)
return err; break;
} }
return 0; return err;
} }
static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
...@@ -3294,6 +3318,7 @@ static int nf_tables_commit(struct sk_buff *skb) ...@@ -3294,6 +3318,7 @@ static int nf_tables_commit(struct sk_buff *skb)
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct nft_trans *trans, *next; struct nft_trans *trans, *next;
struct nft_set *set;
/* Bump generation counter, invalidate any dump in progress */ /* Bump generation counter, invalidate any dump in progress */
net->nft.genctr++; net->nft.genctr++;
...@@ -3385,6 +3410,25 @@ static int nf_tables_commit(struct sk_buff *skb) ...@@ -3385,6 +3410,25 @@ static int nf_tables_commit(struct sk_buff *skb)
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_DELSET); NFT_MSG_DELSET);
break; break;
case NFT_MSG_NEWSETELEM:
nft_trans_elem_set(trans)->nelems++;
nf_tables_setelem_notify(&trans->ctx,
nft_trans_elem_set(trans),
&nft_trans_elem(trans),
NFT_MSG_NEWSETELEM, 0);
nft_trans_destroy(trans);
break;
case NFT_MSG_DELSETELEM:
nft_trans_elem_set(trans)->nelems--;
nf_tables_setelem_notify(&trans->ctx,
nft_trans_elem_set(trans),
&nft_trans_elem(trans),
NFT_MSG_DELSETELEM, 0);
set = nft_trans_elem_set(trans);
set->ops->get(set, &nft_trans_elem(trans));
set->ops->remove(set, &nft_trans_elem(trans));
nft_trans_destroy(trans);
break;
} }
} }
...@@ -3418,6 +3462,7 @@ static int nf_tables_abort(struct sk_buff *skb) ...@@ -3418,6 +3462,7 @@ static int nf_tables_abort(struct sk_buff *skb)
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct nft_trans *trans, *next; struct nft_trans *trans, *next;
struct nft_set *set;
list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
switch (trans->msg_type) { switch (trans->msg_type) {
...@@ -3473,6 +3518,15 @@ static int nf_tables_abort(struct sk_buff *skb) ...@@ -3473,6 +3518,15 @@ static int nf_tables_abort(struct sk_buff *skb)
&trans->ctx.table->sets); &trans->ctx.table->sets);
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWSETELEM:
set = nft_trans_elem_set(trans);
set->ops->get(set, &nft_trans_elem(trans));
set->ops->remove(set, &nft_trans_elem(trans));
nft_trans_destroy(trans);
break;
case NFT_MSG_DELSETELEM:
nft_trans_destroy(trans);
break;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment