aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-04-03 21:36:42 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-05-19 06:06:12 -0400
commit60319eb1ca351aa36e29d58d2e60ba9a9836265a (patch)
tree730f96cdcbb54f61cd9b449bd6c5c68def0dcbf7 /net/netfilter
parent55dd6f93076bb82aa8911191125418dcfcbf2c9b (diff)
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: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_tables_api.c82
1 files changed, 68 insertions, 14 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 3e685dbb2921..cd002935e6b2 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2993,7 +2993,21 @@ err:
2993 return err; 2993 return err;
2994} 2994}
2995 2995
2996static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set, 2996static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
2997 int msg_type,
2998 struct nft_set *set)
2999{
3000 struct nft_trans *trans;
3001
3002 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_elem));
3003 if (trans == NULL)
3004 return NULL;
3005
3006 nft_trans_elem_set(trans) = set;
3007 return trans;
3008}
3009
3010static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
2997 const struct nlattr *attr) 3011 const struct nlattr *attr)
2998{ 3012{
2999 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; 3013 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 struct nft_set_elem elem; 3015 struct nft_set_elem elem;
3002 struct nft_set_binding *binding; 3016 struct nft_set_binding *binding;
3003 enum nft_registers dreg; 3017 enum nft_registers dreg;
3018 struct nft_trans *trans;
3004 int err; 3019 int err;
3005 3020
3006 if (set->size && set->nelems == set->size) 3021 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 } 3083 }
3069 } 3084 }
3070 3085
3086 trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
3087 if (trans == NULL)
3088 goto err3;
3089
3071 err = set->ops->insert(set, &elem); 3090 err = set->ops->insert(set, &elem);
3072 if (err < 0) 3091 if (err < 0)
3073 goto err3; 3092 goto err4;
3074 set->nelems++;
3075 3093
3076 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_NEWSETELEM, 0); 3094 nft_trans_elem(trans) = elem;
3095 list_add(&trans->list, &ctx->net->nft.commit_list);
3077 return 0; 3096 return 0;
3078 3097
3098err4:
3099 kfree(trans);
3079err3: 3100err3:
3080 if (nla[NFTA_SET_ELEM_DATA] != NULL) 3101 if (nla[NFTA_SET_ELEM_DATA] != NULL)
3081 nft_data_uninit(&elem.data, d2.type); 3102 nft_data_uninit(&elem.data, d2.type);
@@ -3093,7 +3114,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3093 const struct nlattr *attr; 3114 const struct nlattr *attr;
3094 struct nft_set *set; 3115 struct nft_set *set;
3095 struct nft_ctx ctx; 3116 struct nft_ctx ctx;
3096 int rem, err; 3117 int rem, err = 0;
3097 3118
3098 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true); 3119 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true);
3099 if (err < 0) 3120 if (err < 0)
@@ -3115,17 +3136,18 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3115 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 3136 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3116 err = nft_add_set_elem(&ctx, set, attr); 3137 err = nft_add_set_elem(&ctx, set, attr);
3117 if (err < 0) 3138 if (err < 0)
3118 return err; 3139 break;
3119 } 3140 }
3120 return 0; 3141 return err;
3121} 3142}
3122 3143
3123static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set, 3144static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
3124 const struct nlattr *attr) 3145 const struct nlattr *attr)
3125{ 3146{
3126 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; 3147 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
3127 struct nft_data_desc desc; 3148 struct nft_data_desc desc;
3128 struct nft_set_elem elem; 3149 struct nft_set_elem elem;
3150 struct nft_trans *trans;
3129 int err; 3151 int err;
3130 3152
3131 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr, 3153 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 if (err < 0) 3171 if (err < 0)
3150 goto err2; 3172 goto err2;
3151 3173
3152 set->ops->remove(set, &elem); 3174 trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
3153 set->nelems--; 3175 if (trans == NULL)
3176 goto err2;
3154 3177
3155 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_DELSETELEM, 0); 3178 nft_trans_elem(trans) = elem;
3179 list_add(&trans->list, &ctx->net->nft.commit_list);
3156 3180
3157 nft_data_uninit(&elem.key, NFT_DATA_VALUE); 3181 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
3158 if (set->flags & NFT_SET_MAP) 3182 if (set->flags & NFT_SET_MAP)
@@ -3171,7 +3195,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3171 const struct nlattr *attr; 3195 const struct nlattr *attr;
3172 struct nft_set *set; 3196 struct nft_set *set;
3173 struct nft_ctx ctx; 3197 struct nft_ctx ctx;
3174 int rem, err; 3198 int rem, err = 0;
3175 3199
3176 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false); 3200 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
3177 if (err < 0) 3201 if (err < 0)
@@ -3186,9 +3210,9 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3186 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 3210 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3187 err = nft_del_setelem(&ctx, set, attr); 3211 err = nft_del_setelem(&ctx, set, attr);
3188 if (err < 0) 3212 if (err < 0)
3189 return err; 3213 break;
3190 } 3214 }
3191 return 0; 3215 return err;
3192} 3216}
3193 3217
3194static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { 3218static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
@@ -3294,6 +3318,7 @@ static int nf_tables_commit(struct sk_buff *skb)
3294{ 3318{
3295 struct net *net = sock_net(skb->sk); 3319 struct net *net = sock_net(skb->sk);
3296 struct nft_trans *trans, *next; 3320 struct nft_trans *trans, *next;
3321 struct nft_set *set;
3297 3322
3298 /* Bump generation counter, invalidate any dump in progress */ 3323 /* Bump generation counter, invalidate any dump in progress */
3299 net->nft.genctr++; 3324 net->nft.genctr++;
@@ -3385,6 +3410,25 @@ static int nf_tables_commit(struct sk_buff *skb)
3385 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), 3410 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
3386 NFT_MSG_DELSET); 3411 NFT_MSG_DELSET);
3387 break; 3412 break;
3413 case NFT_MSG_NEWSETELEM:
3414 nft_trans_elem_set(trans)->nelems++;
3415 nf_tables_setelem_notify(&trans->ctx,
3416 nft_trans_elem_set(trans),
3417 &nft_trans_elem(trans),
3418 NFT_MSG_NEWSETELEM, 0);
3419 nft_trans_destroy(trans);
3420 break;
3421 case NFT_MSG_DELSETELEM:
3422 nft_trans_elem_set(trans)->nelems--;
3423 nf_tables_setelem_notify(&trans->ctx,
3424 nft_trans_elem_set(trans),
3425 &nft_trans_elem(trans),
3426 NFT_MSG_DELSETELEM, 0);
3427 set = nft_trans_elem_set(trans);
3428 set->ops->get(set, &nft_trans_elem(trans));
3429 set->ops->remove(set, &nft_trans_elem(trans));
3430 nft_trans_destroy(trans);
3431 break;
3388 } 3432 }
3389 } 3433 }
3390 3434
@@ -3418,6 +3462,7 @@ static int nf_tables_abort(struct sk_buff *skb)
3418{ 3462{
3419 struct net *net = sock_net(skb->sk); 3463 struct net *net = sock_net(skb->sk);
3420 struct nft_trans *trans, *next; 3464 struct nft_trans *trans, *next;
3465 struct nft_set *set;
3421 3466
3422 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { 3467 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
3423 switch (trans->msg_type) { 3468 switch (trans->msg_type) {
@@ -3473,6 +3518,15 @@ static int nf_tables_abort(struct sk_buff *skb)
3473 &trans->ctx.table->sets); 3518 &trans->ctx.table->sets);
3474 nft_trans_destroy(trans); 3519 nft_trans_destroy(trans);
3475 break; 3520 break;
3521 case NFT_MSG_NEWSETELEM:
3522 set = nft_trans_elem_set(trans);
3523 set->ops->get(set, &nft_trans_elem(trans));
3524 set->ops->remove(set, &nft_trans_elem(trans));
3525 nft_trans_destroy(trans);
3526 break;
3527 case NFT_MSG_DELSETELEM:
3528 nft_trans_destroy(trans);
3529 break;
3476 } 3530 }
3477 } 3531 }
3478 3532