Skip to content

Commit

Permalink
netfilter: nf_tables: use new transaction infrastructure to handle el…
Browse files Browse the repository at this point in the history
…ements

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: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed May 19, 2014
1 parent 55dd6f9 commit 60319eb
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 14 deletions.
10 changes: 10 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,16 @@ struct nft_trans_table {
#define nft_trans_table_enable(trans) \
(((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)
{
return (struct nft_expr *)&rule->data[0];
Expand Down
82 changes: 68 additions & 14 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2993,14 +2993,29 @@ static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
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)
{
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_data_desc d1, d2;
struct nft_set_elem elem;
struct nft_set_binding *binding;
enum nft_registers dreg;
struct nft_trans *trans;
int err;

if (set->size && set->nelems == set->size)
Expand Down Expand Up @@ -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);
if (err < 0)
goto err3;
set->nelems++;
goto err4;

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;

err4:
kfree(trans);
err3:
if (nla[NFTA_SET_ELEM_DATA] != NULL)
nft_data_uninit(&elem.data, d2.type);
Expand All @@ -3093,7 +3114,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
int rem, err;
int rem, err = 0;

err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true);
if (err < 0)
Expand All @@ -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) {
err = nft_add_set_elem(&ctx, set, attr);
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)
{
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_data_desc desc;
struct nft_set_elem elem;
struct nft_trans *trans;
int err;

err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
Expand All @@ -3149,10 +3171,12 @@ static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
if (err < 0)
goto err2;

set->ops->remove(set, &elem);
set->nelems--;
trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
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);
if (set->flags & NFT_SET_MAP)
Expand All @@ -3171,7 +3195,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
int rem, err;
int rem, err = 0;

err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
if (err < 0)
Expand All @@ -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) {
err = nft_del_setelem(&ctx, set, attr);
if (err < 0)
return err;
break;
}
return 0;
return err;
}

static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
Expand Down Expand Up @@ -3294,6 +3318,7 @@ static int nf_tables_commit(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
struct nft_trans *trans, *next;
struct nft_set *set;

/* Bump generation counter, invalidate any dump in progress */
net->nft.genctr++;
Expand Down Expand Up @@ -3385,6 +3410,25 @@ static int nf_tables_commit(struct sk_buff *skb)
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_DELSET);
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;
}
}

Expand Down Expand Up @@ -3418,6 +3462,7 @@ static int nf_tables_abort(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
struct nft_trans *trans, *next;
struct nft_set *set;

list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
switch (trans->msg_type) {
Expand Down Expand Up @@ -3473,6 +3518,15 @@ static int nf_tables_abort(struct sk_buff *skb)
&trans->ctx.table->sets);
nft_trans_destroy(trans);
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;
}
}

Expand Down

0 comments on commit 60319eb

Please sign in to comment.