@@ -158,6 +158,7 @@ static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
158158
159159static const struct nla_policy nft_table_policy [NFTA_TABLE_MAX + 1 ] = {
160160 [NFTA_TABLE_NAME ] = { .type = NLA_STRING },
161+ [NFTA_TABLE_FLAGS ] = { .type = NLA_U32 },
161162};
162163
163164static int nf_tables_fill_table_info (struct sk_buff * skb , u32 portid , u32 seq ,
@@ -177,7 +178,8 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
177178 nfmsg -> version = NFNETLINK_V0 ;
178179 nfmsg -> res_id = 0 ;
179180
180- if (nla_put_string (skb , NFTA_TABLE_NAME , table -> name ))
181+ if (nla_put_string (skb , NFTA_TABLE_NAME , table -> name ) ||
182+ nla_put_be32 (skb , NFTA_TABLE_FLAGS , htonl (table -> flags )))
181183 goto nla_put_failure ;
182184
183185 return nlmsg_end (skb , nlh );
@@ -301,6 +303,74 @@ static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
301303 return err ;
302304}
303305
306+ static int nf_tables_table_enable (struct nft_table * table )
307+ {
308+ struct nft_chain * chain ;
309+ int err , i = 0 ;
310+
311+ list_for_each_entry (chain , & table -> chains , list ) {
312+ err = nf_register_hook (& nft_base_chain (chain )-> ops );
313+ if (err < 0 )
314+ goto err ;
315+
316+ i ++ ;
317+ }
318+ return 0 ;
319+ err :
320+ list_for_each_entry (chain , & table -> chains , list ) {
321+ if (i -- <= 0 )
322+ break ;
323+
324+ nf_unregister_hook (& nft_base_chain (chain )-> ops );
325+ }
326+ return err ;
327+ }
328+
329+ static int nf_tables_table_disable (struct nft_table * table )
330+ {
331+ struct nft_chain * chain ;
332+
333+ list_for_each_entry (chain , & table -> chains , list )
334+ nf_unregister_hook (& nft_base_chain (chain )-> ops );
335+
336+ return 0 ;
337+ }
338+
339+ static int nf_tables_updtable (struct sock * nlsk , struct sk_buff * skb ,
340+ const struct nlmsghdr * nlh ,
341+ const struct nlattr * const nla [],
342+ struct nft_af_info * afi , struct nft_table * table )
343+ {
344+ const struct nfgenmsg * nfmsg = nlmsg_data (nlh );
345+ int family = nfmsg -> nfgen_family , ret = 0 ;
346+
347+ if (nla [NFTA_TABLE_FLAGS ]) {
348+ __be32 flags ;
349+
350+ flags = ntohl (nla_get_be32 (nla [NFTA_TABLE_FLAGS ]));
351+ if (flags & ~NFT_TABLE_F_DORMANT )
352+ return - EINVAL ;
353+
354+ if ((flags & NFT_TABLE_F_DORMANT ) &&
355+ !(table -> flags & NFT_TABLE_F_DORMANT )) {
356+ ret = nf_tables_table_disable (table );
357+ if (ret >= 0 )
358+ table -> flags |= NFT_TABLE_F_DORMANT ;
359+ } else if (!(flags & NFT_TABLE_F_DORMANT ) &&
360+ table -> flags & NFT_TABLE_F_DORMANT ) {
361+ ret = nf_tables_table_enable (table );
362+ if (ret >= 0 )
363+ table -> flags &= ~NFT_TABLE_F_DORMANT ;
364+ }
365+ if (ret < 0 )
366+ goto err ;
367+ }
368+
369+ nf_tables_table_notify (skb , nlh , table , NFT_MSG_NEWTABLE , family );
370+ err :
371+ return ret ;
372+ }
373+
304374static int nf_tables_newtable (struct sock * nlsk , struct sk_buff * skb ,
305375 const struct nlmsghdr * nlh ,
306376 const struct nlattr * const nla [])
@@ -328,7 +398,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
328398 return - EEXIST ;
329399 if (nlh -> nlmsg_flags & NLM_F_REPLACE )
330400 return - EOPNOTSUPP ;
331- return 0 ;
401+ return nf_tables_updtable ( nlsk , skb , nlh , nla , afi , table ) ;
332402 }
333403
334404 table = kzalloc (sizeof (* table ) + nla_len (name ), GFP_KERNEL );
@@ -339,6 +409,18 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
339409 INIT_LIST_HEAD (& table -> chains );
340410 INIT_LIST_HEAD (& table -> sets );
341411
412+ if (nla [NFTA_TABLE_FLAGS ]) {
413+ __be32 flags ;
414+
415+ flags = ntohl (nla_get_be32 (nla [NFTA_TABLE_FLAGS ]));
416+ if (flags & ~NFT_TABLE_F_DORMANT ) {
417+ kfree (table );
418+ return - EINVAL ;
419+ }
420+
421+ table -> flags |= flags ;
422+ }
423+
342424 list_add_tail (& table -> list , & afi -> tables );
343425 nf_tables_table_notify (skb , nlh , table , NFT_MSG_NEWTABLE , family );
344426 return 0 ;
@@ -890,17 +972,17 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
890972 chain -> handle = nf_tables_alloc_handle (table );
891973 nla_strlcpy (chain -> name , name , NFT_CHAIN_MAXNAMELEN );
892974
893- list_add_tail (& chain -> list , & table -> chains );
894- table -> use ++ ;
895-
896- if (chain -> flags & NFT_BASE_CHAIN ) {
975+ if (!(table -> flags & NFT_TABLE_F_DORMANT ) &&
976+ chain -> flags & NFT_BASE_CHAIN ) {
897977 err = nf_register_hook (& nft_base_chain (chain )-> ops );
898978 if (err < 0 ) {
899979 free_percpu (basechain -> stats );
900980 kfree (basechain );
901981 return err ;
902982 }
903983 }
984+ list_add_tail (& chain -> list , & table -> chains );
985+ table -> use ++ ;
904986notify :
905987 nf_tables_chain_notify (skb , nlh , table , chain , NFT_MSG_NEWCHAIN ,
906988 family );
@@ -948,7 +1030,8 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
9481030 list_del (& chain -> list );
9491031 table -> use -- ;
9501032
951- if (chain -> flags & NFT_BASE_CHAIN )
1033+ if (!(table -> flags & NFT_TABLE_F_DORMANT ) &&
1034+ chain -> flags & NFT_BASE_CHAIN )
9521035 nf_unregister_hook (& nft_base_chain (chain )-> ops );
9531036
9541037 nf_tables_chain_notify (skb , nlh , table , chain , NFT_MSG_DELCHAIN ,
0 commit comments