@@ -300,47 +300,72 @@ void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
300
300
static int nft_netdev_register_hooks (struct net * net ,
301
301
struct list_head * hook_list )
302
302
{
303
+ struct nf_hook_ops * ops ;
303
304
struct nft_hook * hook ;
304
305
int err , j ;
305
306
306
307
j = 0 ;
307
308
list_for_each_entry (hook , hook_list , list ) {
308
- err = nf_register_net_hook (net , & hook -> ops );
309
- if (err < 0 )
310
- goto err_register ;
309
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
310
+ err = nf_register_net_hook (net , ops );
311
+ if (err < 0 )
312
+ goto err_register ;
311
313
312
- j ++ ;
314
+ j ++ ;
315
+ }
313
316
}
314
317
return 0 ;
315
318
316
319
err_register :
317
320
list_for_each_entry (hook , hook_list , list ) {
318
- if (j -- <= 0 )
319
- break ;
321
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
322
+ if (j -- <= 0 )
323
+ break ;
320
324
321
- nf_unregister_net_hook (net , & hook -> ops );
325
+ nf_unregister_net_hook (net , ops );
326
+ }
322
327
}
323
328
return err ;
324
329
}
325
330
331
+ static void nft_netdev_hook_free_ops (struct nft_hook * hook )
332
+ {
333
+ struct nf_hook_ops * ops , * next ;
334
+
335
+ list_for_each_entry_safe (ops , next , & hook -> ops_list , list ) {
336
+ list_del (& ops -> list );
337
+ kfree (ops );
338
+ }
339
+ }
340
+
326
341
static void nft_netdev_hook_free (struct nft_hook * hook )
327
342
{
343
+ nft_netdev_hook_free_ops (hook );
328
344
kfree (hook );
329
345
}
330
346
347
+ static void __nft_netdev_hook_free_rcu (struct rcu_head * rcu )
348
+ {
349
+ struct nft_hook * hook = container_of (rcu , struct nft_hook , rcu );
350
+
351
+ nft_netdev_hook_free (hook );
352
+ }
353
+
331
354
static void nft_netdev_hook_free_rcu (struct nft_hook * hook )
332
355
{
333
- kfree_rcu ( hook , rcu );
356
+ call_rcu ( & hook -> rcu , __nft_netdev_hook_free_rcu );
334
357
}
335
358
336
359
static void nft_netdev_unregister_hooks (struct net * net ,
337
360
struct list_head * hook_list ,
338
361
bool release_netdev )
339
362
{
340
363
struct nft_hook * hook , * next ;
364
+ struct nf_hook_ops * ops ;
341
365
342
366
list_for_each_entry_safe (hook , next , hook_list , list ) {
343
- nf_unregister_net_hook (net , & hook -> ops );
367
+ list_for_each_entry (ops , & hook -> ops_list , list )
368
+ nf_unregister_net_hook (net , ops );
344
369
if (release_netdev ) {
345
370
list_del (& hook -> list );
346
371
nft_netdev_hook_free_rcu (hook );
@@ -2284,6 +2309,7 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
2284
2309
static struct nft_hook * nft_netdev_hook_alloc (struct net * net ,
2285
2310
const struct nlattr * attr )
2286
2311
{
2312
+ struct nf_hook_ops * ops ;
2287
2313
struct net_device * dev ;
2288
2314
struct nft_hook * hook ;
2289
2315
int err ;
@@ -2293,6 +2319,7 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
2293
2319
err = - ENOMEM ;
2294
2320
goto err_hook_alloc ;
2295
2321
}
2322
+ INIT_LIST_HEAD (& hook -> ops_list );
2296
2323
2297
2324
err = nla_strscpy (hook -> ifname , attr , IFNAMSIZ );
2298
2325
if (err < 0 )
@@ -2309,7 +2336,14 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
2309
2336
err = - ENOENT ;
2310
2337
goto err_hook_dev ;
2311
2338
}
2312
- hook -> ops .dev = dev ;
2339
+
2340
+ ops = kzalloc (sizeof (struct nf_hook_ops ), GFP_KERNEL_ACCOUNT );
2341
+ if (!ops ) {
2342
+ err = - ENOMEM ;
2343
+ goto err_hook_dev ;
2344
+ }
2345
+ ops -> dev = dev ;
2346
+ list_add_tail (& ops -> list , & hook -> ops_list );
2313
2347
2314
2348
return hook ;
2315
2349
@@ -2569,6 +2603,7 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
2569
2603
struct nft_chain_hook * hook , u32 flags )
2570
2604
{
2571
2605
struct nft_chain * chain ;
2606
+ struct nf_hook_ops * ops ;
2572
2607
struct nft_hook * h ;
2573
2608
2574
2609
basechain -> type = hook -> type ;
@@ -2577,8 +2612,10 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
2577
2612
2578
2613
if (nft_base_chain_netdev (family , hook -> num )) {
2579
2614
list_splice_init (& hook -> list , & basechain -> hook_list );
2580
- list_for_each_entry (h , & basechain -> hook_list , list )
2581
- nft_basechain_hook_init (& h -> ops , family , hook , chain );
2615
+ list_for_each_entry (h , & basechain -> hook_list , list ) {
2616
+ list_for_each_entry (ops , & h -> ops_list , list )
2617
+ nft_basechain_hook_init (ops , family , hook , chain );
2618
+ }
2582
2619
}
2583
2620
nft_basechain_hook_init (& basechain -> ops , family , hook , chain );
2584
2621
@@ -2797,11 +2834,13 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
2797
2834
2798
2835
if (nft_base_chain_netdev (ctx -> family , basechain -> ops .hooknum )) {
2799
2836
list_for_each_entry_safe (h , next , & hook .list , list ) {
2800
- h -> ops .pf = basechain -> ops .pf ;
2801
- h -> ops .hooknum = basechain -> ops .hooknum ;
2802
- h -> ops .priority = basechain -> ops .priority ;
2803
- h -> ops .priv = basechain -> ops .priv ;
2804
- h -> ops .hook = basechain -> ops .hook ;
2837
+ list_for_each_entry (ops , & h -> ops_list , list ) {
2838
+ ops -> pf = basechain -> ops .pf ;
2839
+ ops -> hooknum = basechain -> ops .hooknum ;
2840
+ ops -> priority = basechain -> ops .priority ;
2841
+ ops -> priv = basechain -> ops .priv ;
2842
+ ops -> hook = basechain -> ops .hook ;
2843
+ }
2805
2844
2806
2845
if (nft_hook_list_find (& basechain -> hook_list , h )) {
2807
2846
list_del (& h -> list );
@@ -2923,8 +2962,10 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
2923
2962
err_hooks :
2924
2963
if (nla [NFTA_CHAIN_HOOK ]) {
2925
2964
list_for_each_entry_safe (h , next , & hook .list , list ) {
2926
- if (unregister )
2927
- nf_unregister_net_hook (ctx -> net , & h -> ops );
2965
+ if (unregister ) {
2966
+ list_for_each_entry (ops , & h -> ops_list , list )
2967
+ nf_unregister_net_hook (ctx -> net , ops );
2968
+ }
2928
2969
list_del (& h -> list );
2929
2970
nft_netdev_hook_free_rcu (h );
2930
2971
}
@@ -8795,6 +8836,7 @@ static int nft_flowtable_parse_hook(const struct nft_ctx *ctx,
8795
8836
struct netlink_ext_ack * extack , bool add )
8796
8837
{
8797
8838
struct nlattr * tb [NFTA_FLOWTABLE_HOOK_MAX + 1 ];
8839
+ struct nf_hook_ops * ops ;
8798
8840
struct nft_hook * hook ;
8799
8841
int hooknum , priority ;
8800
8842
int err ;
@@ -8849,11 +8891,13 @@ static int nft_flowtable_parse_hook(const struct nft_ctx *ctx,
8849
8891
}
8850
8892
8851
8893
list_for_each_entry (hook , & flowtable_hook -> list , list ) {
8852
- hook -> ops .pf = NFPROTO_NETDEV ;
8853
- hook -> ops .hooknum = flowtable_hook -> num ;
8854
- hook -> ops .priority = flowtable_hook -> priority ;
8855
- hook -> ops .priv = & flowtable -> data ;
8856
- hook -> ops .hook = flowtable -> data .type -> hook ;
8894
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
8895
+ ops -> pf = NFPROTO_NETDEV ;
8896
+ ops -> hooknum = flowtable_hook -> num ;
8897
+ ops -> priority = flowtable_hook -> priority ;
8898
+ ops -> priv = & flowtable -> data ;
8899
+ ops -> hook = flowtable -> data .type -> hook ;
8900
+ }
8857
8901
}
8858
8902
8859
8903
return err ;
@@ -8910,9 +8954,11 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
8910
8954
bool release_netdev )
8911
8955
{
8912
8956
struct nft_hook * hook , * next ;
8957
+ struct nf_hook_ops * ops ;
8913
8958
8914
8959
list_for_each_entry_safe (hook , next , hook_list , list ) {
8915
- nft_unregister_flowtable_ops (net , flowtable , & hook -> ops );
8960
+ list_for_each_entry (ops , & hook -> ops_list , list )
8961
+ nft_unregister_flowtable_ops (net , flowtable , ops );
8916
8962
if (release_netdev ) {
8917
8963
list_del (& hook -> list );
8918
8964
nft_netdev_hook_free_rcu (hook );
@@ -8954,6 +9000,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,
8954
9000
{
8955
9001
struct nft_hook * hook , * next ;
8956
9002
struct nft_flowtable * ft ;
9003
+ struct nf_hook_ops * ops ;
8957
9004
int err , i = 0 ;
8958
9005
8959
9006
list_for_each_entry (hook , hook_list , list ) {
@@ -8967,21 +9014,25 @@ static int nft_register_flowtable_net_hooks(struct net *net,
8967
9014
}
8968
9015
}
8969
9016
8970
- err = nft_register_flowtable_ops (net , flowtable , & hook -> ops );
8971
- if (err < 0 )
8972
- goto err_unregister_net_hooks ;
9017
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
9018
+ err = nft_register_flowtable_ops (net , flowtable , ops );
9019
+ if (err < 0 )
9020
+ goto err_unregister_net_hooks ;
8973
9021
8974
- i ++ ;
9022
+ i ++ ;
9023
+ }
8975
9024
}
8976
9025
8977
9026
return 0 ;
8978
9027
8979
9028
err_unregister_net_hooks :
8980
9029
list_for_each_entry_safe (hook , next , hook_list , list ) {
8981
- if (i -- <= 0 )
8982
- break ;
9030
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
9031
+ if (i -- <= 0 )
9032
+ break ;
8983
9033
8984
- nft_unregister_flowtable_ops (net , flowtable , & hook -> ops );
9034
+ nft_unregister_flowtable_ops (net , flowtable , ops );
9035
+ }
8985
9036
list_del_rcu (& hook -> list );
8986
9037
nft_netdev_hook_free_rcu (hook );
8987
9038
}
@@ -9006,6 +9057,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
9006
9057
const struct nlattr * const * nla = ctx -> nla ;
9007
9058
struct nft_flowtable_hook flowtable_hook ;
9008
9059
struct nft_hook * hook , * next ;
9060
+ struct nf_hook_ops * ops ;
9009
9061
struct nft_trans * trans ;
9010
9062
bool unregister = false;
9011
9063
u32 flags ;
@@ -9063,8 +9115,11 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
9063
9115
9064
9116
err_flowtable_update_hook :
9065
9117
list_for_each_entry_safe (hook , next , & flowtable_hook .list , list ) {
9066
- if (unregister )
9067
- nft_unregister_flowtable_ops (ctx -> net , flowtable , & hook -> ops );
9118
+ if (unregister ) {
9119
+ list_for_each_entry (ops , & hook -> ops_list , list )
9120
+ nft_unregister_flowtable_ops (ctx -> net ,
9121
+ flowtable , ops );
9122
+ }
9068
9123
list_del_rcu (& hook -> list );
9069
9124
nft_netdev_hook_free_rcu (hook );
9070
9125
}
@@ -9611,17 +9666,26 @@ static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
9611
9666
struct nf_hook_ops * nft_hook_find_ops (const struct nft_hook * hook ,
9612
9667
const struct net_device * dev )
9613
9668
{
9614
- if (hook -> ops .dev == dev )
9615
- return (struct nf_hook_ops * )& hook -> ops ;
9669
+ struct nf_hook_ops * ops ;
9616
9670
9671
+ list_for_each_entry (ops , & hook -> ops_list , list ) {
9672
+ if (ops -> dev == dev )
9673
+ return ops ;
9674
+ }
9617
9675
return NULL ;
9618
9676
}
9619
9677
EXPORT_SYMBOL_GPL (nft_hook_find_ops );
9620
9678
9621
9679
struct nf_hook_ops * nft_hook_find_ops_rcu (const struct nft_hook * hook ,
9622
9680
const struct net_device * dev )
9623
9681
{
9624
- return nft_hook_find_ops (hook , dev );
9682
+ struct nf_hook_ops * ops ;
9683
+
9684
+ list_for_each_entry_rcu (ops , & hook -> ops_list , list ) {
9685
+ if (ops -> dev == dev )
9686
+ return ops ;
9687
+ }
9688
+ return NULL ;
9625
9689
}
9626
9690
EXPORT_SYMBOL_GPL (nft_hook_find_ops_rcu );
9627
9691
@@ -9638,8 +9702,8 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
9638
9702
9639
9703
/* flow_offload_netdev_event() cleans up entries for us. */
9640
9704
nft_unregister_flowtable_ops (dev_net (dev ), flowtable , ops );
9641
- list_del_rcu (& hook -> list );
9642
- kfree_rcu (hook , rcu );
9705
+ list_del_rcu (& ops -> list );
9706
+ kfree_rcu (ops , rcu );
9643
9707
break ;
9644
9708
}
9645
9709
}
0 commit comments