@@ -1934,6 +1934,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
19341934 [NFTA_SET_DATA_LEN ] = { .type = NLA_U32 },
19351935 [NFTA_SET_POLICY ] = { .type = NLA_U32 },
19361936 [NFTA_SET_DESC ] = { .type = NLA_NESTED },
1937+ [NFTA_SET_ID ] = { .type = NLA_U32 },
19371938};
19381939
19391940static const struct nla_policy nft_set_desc_policy [NFTA_SET_DESC_MAX + 1 ] = {
@@ -1984,6 +1985,20 @@ struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
19841985 return ERR_PTR (- ENOENT );
19851986}
19861987
1988+ struct nft_set * nf_tables_set_lookup_byid (const struct net * net ,
1989+ const struct nlattr * nla )
1990+ {
1991+ struct nft_trans * trans ;
1992+ u32 id = ntohl (nla_get_be32 (nla ));
1993+
1994+ list_for_each_entry (trans , & net -> nft .commit_list , list ) {
1995+ if (trans -> msg_type == NFT_MSG_NEWSET &&
1996+ id == nft_trans_set_id (trans ))
1997+ return nft_trans_set (trans );
1998+ }
1999+ return ERR_PTR (- ENOENT );
2000+ }
2001+
19872002static int nf_tables_set_alloc_name (struct nft_ctx * ctx , struct nft_set * set ,
19882003 const char * name )
19892004{
@@ -2259,6 +2274,8 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
22592274 return ret ;
22602275}
22612276
2277+ #define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */
2278+
22622279static int nf_tables_getset (struct sock * nlsk , struct sk_buff * skb ,
22632280 const struct nlmsghdr * nlh ,
22642281 const struct nlattr * const nla [])
@@ -2288,6 +2305,8 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
22882305 set = nf_tables_set_lookup (ctx .table , nla [NFTA_SET_NAME ]);
22892306 if (IS_ERR (set ))
22902307 return PTR_ERR (set );
2308+ if (set -> flags & NFT_SET_INACTIVE )
2309+ return - ENOENT ;
22912310
22922311 skb2 = alloc_skb (NLMSG_GOODSIZE , GFP_KERNEL );
22932312 if (skb2 == NULL )
@@ -2321,6 +2340,26 @@ static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
23212340 return 0 ;
23222341}
23232342
2343+ static int nft_trans_set_add (struct nft_ctx * ctx , int msg_type ,
2344+ struct nft_set * set )
2345+ {
2346+ struct nft_trans * trans ;
2347+
2348+ trans = nft_trans_alloc (ctx , msg_type , sizeof (struct nft_trans_set ));
2349+ if (trans == NULL )
2350+ return - ENOMEM ;
2351+
2352+ if (msg_type == NFT_MSG_NEWSET && ctx -> nla [NFTA_SET_ID ] != NULL ) {
2353+ nft_trans_set_id (trans ) =
2354+ ntohl (nla_get_be32 (ctx -> nla [NFTA_SET_ID ]));
2355+ set -> flags |= NFT_SET_INACTIVE ;
2356+ }
2357+ nft_trans_set (trans ) = set ;
2358+ list_add_tail (& trans -> list , & ctx -> net -> nft .commit_list );
2359+
2360+ return 0 ;
2361+ }
2362+
23242363static int nf_tables_newset (struct sock * nlsk , struct sk_buff * skb ,
23252364 const struct nlmsghdr * nlh ,
23262365 const struct nlattr * const nla [])
@@ -2341,7 +2380,8 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
23412380
23422381 if (nla [NFTA_SET_TABLE ] == NULL ||
23432382 nla [NFTA_SET_NAME ] == NULL ||
2344- nla [NFTA_SET_KEY_LEN ] == NULL )
2383+ nla [NFTA_SET_KEY_LEN ] == NULL ||
2384+ nla [NFTA_SET_ID ] == NULL )
23452385 return - EINVAL ;
23462386
23472387 memset (& desc , 0 , sizeof (desc ));
@@ -2458,8 +2498,11 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
24582498 if (err < 0 )
24592499 goto err2 ;
24602500
2501+ err = nft_trans_set_add (& ctx , NFT_MSG_NEWSET , set );
2502+ if (err < 0 )
2503+ goto err2 ;
2504+
24612505 list_add_tail (& set -> list , & table -> sets );
2462- nf_tables_set_notify (& ctx , set , NFT_MSG_NEWSET );
24632506 return 0 ;
24642507
24652508err2 :
@@ -2469,16 +2512,20 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
24692512 return err ;
24702513}
24712514
2472- static void nf_tables_set_destroy ( const struct nft_ctx * ctx , struct nft_set * set )
2515+ static void nft_set_destroy ( struct nft_set * set )
24732516{
2474- list_del (& set -> list );
2475- nf_tables_set_notify (ctx , set , NFT_MSG_DELSET );
2476-
24772517 set -> ops -> destroy (set );
24782518 module_put (set -> ops -> owner );
24792519 kfree (set );
24802520}
24812521
2522+ static void nf_tables_set_destroy (const struct nft_ctx * ctx , struct nft_set * set )
2523+ {
2524+ list_del (& set -> list );
2525+ nf_tables_set_notify (ctx , set , NFT_MSG_DELSET );
2526+ nft_set_destroy (set );
2527+ }
2528+
24822529static int nf_tables_delset (struct sock * nlsk , struct sk_buff * skb ,
24832530 const struct nlmsghdr * nlh ,
24842531 const struct nlattr * const nla [])
@@ -2500,10 +2547,16 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
25002547 set = nf_tables_set_lookup (ctx .table , nla [NFTA_SET_NAME ]);
25012548 if (IS_ERR (set ))
25022549 return PTR_ERR (set );
2550+ if (set -> flags & NFT_SET_INACTIVE )
2551+ return - ENOENT ;
25032552 if (!list_empty (& set -> bindings ))
25042553 return - EBUSY ;
25052554
2506- nf_tables_set_destroy (& ctx , set );
2555+ err = nft_trans_set_add (& ctx , NFT_MSG_DELSET , set );
2556+ if (err < 0 )
2557+ return err ;
2558+
2559+ list_del (& set -> list );
25072560 return 0 ;
25082561}
25092562
@@ -2563,7 +2616,8 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
25632616{
25642617 list_del (& binding -> list );
25652618
2566- if (list_empty (& set -> bindings ) && set -> flags & NFT_SET_ANONYMOUS )
2619+ if (list_empty (& set -> bindings ) && set -> flags & NFT_SET_ANONYMOUS &&
2620+ !(set -> flags & NFT_SET_INACTIVE ))
25672621 nf_tables_set_destroy (ctx , set );
25682622}
25692623
@@ -2581,6 +2635,7 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
25812635 [NFTA_SET_ELEM_LIST_TABLE ] = { .type = NLA_STRING },
25822636 [NFTA_SET_ELEM_LIST_SET ] = { .type = NLA_STRING },
25832637 [NFTA_SET_ELEM_LIST_ELEMENTS ] = { .type = NLA_NESTED },
2638+ [NFTA_SET_ELEM_LIST_SET_ID ] = { .type = NLA_U32 },
25842639};
25852640
25862641static int nft_ctx_init_from_elemattr (struct nft_ctx * ctx ,
@@ -2680,6 +2735,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
26802735 set = nf_tables_set_lookup (ctx .table , nla [NFTA_SET_ELEM_LIST_SET ]);
26812736 if (IS_ERR (set ))
26822737 return PTR_ERR (set );
2738+ if (set -> flags & NFT_SET_INACTIVE )
2739+ return - ENOENT ;
26832740
26842741 event = NFT_MSG_NEWSETELEM ;
26852742 event |= NFNL_SUBSYS_NFTABLES << 8 ;
@@ -2743,6 +2800,8 @@ static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
27432800 set = nf_tables_set_lookup (ctx .table , nla [NFTA_SET_ELEM_LIST_SET ]);
27442801 if (IS_ERR (set ))
27452802 return PTR_ERR (set );
2803+ if (set -> flags & NFT_SET_INACTIVE )
2804+ return - ENOENT ;
27462805
27472806 if (nlh -> nlmsg_flags & NLM_F_DUMP ) {
27482807 struct netlink_dump_control c = {
@@ -2928,6 +2987,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
29282987 const struct nlmsghdr * nlh ,
29292988 const struct nlattr * const nla [])
29302989{
2990+ struct net * net = sock_net (skb -> sk );
29312991 const struct nlattr * attr ;
29322992 struct nft_set * set ;
29332993 struct nft_ctx ctx ;
@@ -2938,8 +2998,15 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
29382998 return err ;
29392999
29403000 set = nf_tables_set_lookup (ctx .table , nla [NFTA_SET_ELEM_LIST_SET ]);
2941- if (IS_ERR (set ))
2942- return PTR_ERR (set );
3001+ if (IS_ERR (set )) {
3002+ if (nla [NFTA_SET_ELEM_LIST_SET_ID ]) {
3003+ set = nf_tables_set_lookup_byid (net ,
3004+ nla [NFTA_SET_ELEM_LIST_SET_ID ]);
3005+ }
3006+ if (IS_ERR (set ))
3007+ return PTR_ERR (set );
3008+ }
3009+
29433010 if (!list_empty (& set -> bindings ) && set -> flags & NFT_SET_CONSTANT )
29443011 return - EBUSY ;
29453012
@@ -3069,7 +3136,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
30693136 .policy = nft_rule_policy ,
30703137 },
30713138 [NFT_MSG_NEWSET ] = {
3072- .call = nf_tables_newset ,
3139+ .call_batch = nf_tables_newset ,
30733140 .attr_count = NFTA_SET_MAX ,
30743141 .policy = nft_set_policy ,
30753142 },
@@ -3079,12 +3146,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
30793146 .policy = nft_set_policy ,
30803147 },
30813148 [NFT_MSG_DELSET ] = {
3082- .call = nf_tables_delset ,
3149+ .call_batch = nf_tables_delset ,
30833150 .attr_count = NFTA_SET_MAX ,
30843151 .policy = nft_set_policy ,
30853152 },
30863153 [NFT_MSG_NEWSETELEM ] = {
3087- .call = nf_tables_newsetelem ,
3154+ .call_batch = nf_tables_newsetelem ,
30883155 .attr_count = NFTA_SET_ELEM_LIST_MAX ,
30893156 .policy = nft_set_elem_list_policy ,
30903157 },
@@ -3094,7 +3161,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
30943161 .policy = nft_set_elem_list_policy ,
30953162 },
30963163 [NFT_MSG_DELSETELEM ] = {
3097- .call = nf_tables_delsetelem ,
3164+ .call_batch = nf_tables_delsetelem ,
30983165 .attr_count = NFTA_SET_ELEM_LIST_MAX ,
30993166 .policy = nft_set_elem_list_policy ,
31003167 },
@@ -3136,6 +3203,16 @@ static int nf_tables_commit(struct sk_buff *skb)
31363203 nft_trans_rule (trans ), NFT_MSG_DELRULE , 0 ,
31373204 trans -> ctx .afi -> family );
31383205 break ;
3206+ case NFT_MSG_NEWSET :
3207+ nft_trans_set (trans )-> flags &= ~NFT_SET_INACTIVE ;
3208+ nf_tables_set_notify (& trans -> ctx , nft_trans_set (trans ),
3209+ NFT_MSG_NEWSET );
3210+ nft_trans_destroy (trans );
3211+ break ;
3212+ case NFT_MSG_DELSET :
3213+ nf_tables_set_notify (& trans -> ctx , nft_trans_set (trans ),
3214+ NFT_MSG_DELSET );
3215+ break ;
31393216 }
31403217 }
31413218
@@ -3148,9 +3225,12 @@ static int nf_tables_commit(struct sk_buff *skb)
31483225 case NFT_MSG_DELRULE :
31493226 nf_tables_rule_destroy (& trans -> ctx ,
31503227 nft_trans_rule (trans ));
3151- nft_trans_destroy (trans );
3228+ break ;
3229+ case NFT_MSG_DELSET :
3230+ nft_set_destroy (nft_trans_set (trans ));
31523231 break ;
31533232 }
3233+ nft_trans_destroy (trans );
31543234 }
31553235
31563236 return 0 ;
@@ -3170,6 +3250,14 @@ static int nf_tables_abort(struct sk_buff *skb)
31703250 nft_rule_clear (trans -> ctx .net , nft_trans_rule (trans ));
31713251 nft_trans_destroy (trans );
31723252 break ;
3253+ case NFT_MSG_NEWSET :
3254+ list_del (& nft_trans_set (trans )-> list );
3255+ break ;
3256+ case NFT_MSG_DELSET :
3257+ list_add_tail (& nft_trans_set (trans )-> list ,
3258+ & trans -> ctx .table -> sets );
3259+ nft_trans_destroy (trans );
3260+ break ;
31733261 }
31743262 }
31753263
@@ -3181,9 +3269,12 @@ static int nf_tables_abort(struct sk_buff *skb)
31813269 case NFT_MSG_NEWRULE :
31823270 nf_tables_rule_destroy (& trans -> ctx ,
31833271 nft_trans_rule (trans ));
3184- nft_trans_destroy (trans );
3272+ break ;
3273+ case NFT_MSG_NEWSET :
3274+ nft_set_destroy (nft_trans_set (trans ));
31853275 break ;
31863276 }
3277+ nft_trans_destroy (trans );
31873278 }
31883279
31893280 return 0 ;
0 commit comments