Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables_offload: remove rules when the device unregisters

If the net_device unregisters, clean up the offload rules before the
chain is destroy.

Signed-off-by: wenxu <wenxu@ucloud.cn>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

wenxu and committed by
Pablo Neira Ayuso
06d392cb e211aab7

+52 -6
+1 -1
include/net/netfilter/nf_tables_offload.h
··· 77 77 78 78 int nft_chain_offload_priority(struct nft_base_chain *basechain); 79 79 80 - void nft_offload_init(void); 80 + int nft_offload_init(void); 81 81 void nft_offload_exit(void); 82 82 83 83 #endif
+9 -4
net/netfilter/nf_tables_api.c
··· 7694 7694 if (err < 0) 7695 7695 goto err4; 7696 7696 7697 - /* must be last */ 7698 - err = nfnetlink_subsys_register(&nf_tables_subsys); 7697 + err = nft_offload_init(); 7699 7698 if (err < 0) 7700 7699 goto err5; 7701 7700 7701 + /* must be last */ 7702 + err = nfnetlink_subsys_register(&nf_tables_subsys); 7703 + if (err < 0) 7704 + goto err6; 7705 + 7702 7706 nft_chain_route_init(); 7703 - nft_offload_init(); 7704 7707 7705 7708 return err; 7709 + err6: 7710 + nft_offload_exit(); 7706 7711 err5: 7707 7712 rhltable_destroy(&nft_objname_ht); 7708 7713 err4: ··· 7723 7718 7724 7719 static void __exit nf_tables_module_exit(void) 7725 7720 { 7726 - nft_offload_exit(); 7727 7721 nfnetlink_subsys_unregister(&nf_tables_subsys); 7722 + nft_offload_exit(); 7728 7723 unregister_netdevice_notifier(&nf_tables_flowtable_notifier); 7729 7724 nft_chain_filter_fini(); 7730 7725 nft_chain_route_fini();
+42 -1
net/netfilter/nf_tables_offload.c
··· 426 426 mutex_unlock(&net->nft.commit_mutex); 427 427 } 428 428 429 + static void nft_offload_chain_clean(struct nft_chain *chain) 430 + { 431 + struct nft_rule *rule; 432 + 433 + list_for_each_entry(rule, &chain->rules, list) { 434 + nft_flow_offload_rule(chain, rule, 435 + NULL, FLOW_CLS_DESTROY); 436 + } 437 + 438 + nft_flow_offload_chain(chain, NULL, FLOW_BLOCK_UNBIND); 439 + } 440 + 441 + static int nft_offload_netdev_event(struct notifier_block *this, 442 + unsigned long event, void *ptr) 443 + { 444 + struct net_device *dev = netdev_notifier_info_to_dev(ptr); 445 + struct net *net = dev_net(dev); 446 + struct nft_chain *chain; 447 + 448 + mutex_lock(&net->nft.commit_mutex); 449 + chain = __nft_offload_get_chain(dev); 450 + if (chain) 451 + nft_offload_chain_clean(chain); 452 + mutex_unlock(&net->nft.commit_mutex); 453 + 454 + return NOTIFY_DONE; 455 + } 456 + 429 457 static struct flow_indr_block_ing_entry block_ing_entry = { 430 458 .cb = nft_indr_block_cb, 431 459 .list = LIST_HEAD_INIT(block_ing_entry.list), 432 460 }; 433 461 434 - void nft_offload_init(void) 462 + static struct notifier_block nft_offload_netdev_notifier = { 463 + .notifier_call = nft_offload_netdev_event, 464 + }; 465 + 466 + int nft_offload_init(void) 435 467 { 468 + int err; 469 + 470 + err = register_netdevice_notifier(&nft_offload_netdev_notifier); 471 + if (err < 0) 472 + return err; 473 + 436 474 flow_indr_add_block_ing_cb(&block_ing_entry); 475 + 476 + return 0; 437 477 } 438 478 439 479 void nft_offload_exit(void) 440 480 { 441 481 flow_indr_del_block_ing_cb(&block_ing_entry); 482 + unregister_netdevice_notifier(&nft_offload_netdev_notifier); 442 483 }