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

Configure Feed

Select the types of activity you want to include in your feed.

net: revert to lockless TC_SETUP_BLOCK and TC_SETUP_FT

There is a couple of places from which we can arrive to ndo_setup_tc
with TC_SETUP_BLOCK/TC_SETUP_FT:
- netlink
- netlink notifier
- netdev notifier

Locking netdev too deep in this call chain seems to be problematic
(especially assuming some/all of the call_netdevice_notifiers
NETDEV_UNREGISTER) might soon be running with the instance lock).
Revert to lockless ndo_setup_tc for TC_SETUP_BLOCK/TC_SETUP_FT. NFT
framework already takes care of most of the locking. Document
the assumptions.

ndo_setup_tc TC_SETUP_BLOCK
nft_block_offload_cmd
nft_chain_offload_cmd
nft_flow_block_chain
nft_flow_offload_chain
nft_flow_rule_offload_abort
nft_flow_rule_offload_commit
nft_flow_rule_offload_commit
nf_tables_commit
nfnetlink_rcv_batch
nfnetlink_rcv_skb_batch
nfnetlink_rcv
nft_offload_netdev_event
NETDEV_UNREGISTER notifier

ndo_setup_tc TC_SETUP_FT
nf_flow_table_offload_cmd
nf_flow_table_offload_setup
nft_unregister_flowtable_hook
nft_register_flowtable_net_hooks
nft_flowtable_update
nf_tables_newflowtable
nfnetlink_rcv_batch (.call NFNL_CB_BATCH)
nft_flowtable_update
nf_tables_newflowtable
nft_flowtable_event
nf_tables_flowtable_event
NETDEV_UNREGISTER notifier
__nft_unregister_flowtable_net_hooks
nft_unregister_flowtable_net_hooks
nf_tables_commit
nfnetlink_rcv_batch (.call NFNL_CB_BATCH)
__nf_tables_abort
nf_tables_abort
nfnetlink_rcv_batch
__nft_release_hook
__nft_release_hooks
nf_tables_pre_exit_net -> module unload
nft_rcv_nl_event
netlink_register_notifier (oh boy)
nft_register_flowtable_net_hooks
nft_flowtable_update
nf_tables_newflowtable
nf_tables_newflowtable

Fixes: c4f0f30b424e ("net: hold netdev instance lock during nft ndo_setup_tc")
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reported-by: syzbot+0afb4bcf91e5a1afdcad@syzkaller.appspotmail.com
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250308044726.1193222-1-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Stanislav Fomichev and committed by
Jakub Kicinski
0a13c1e0 0ea09cbf

+8 -23
+6
Documentation/networking/netdevices.rst
··· 290 290 Synchronization: netif_addr_lock spinlock. 291 291 Context: BHs disabled 292 292 293 + ndo_setup_tc: 294 + ``TC_SETUP_BLOCK`` and ``TC_SETUP_FT`` are running under NFT locks 295 + (i.e. no ``rtnl_lock`` and no device instance lock). The rest of 296 + ``tc_setup_type`` types run under netdev instance lock if the driver 297 + implements queue management or shaper API. 298 + 293 299 Most ndo callbacks not specified in the list above are running 294 300 under ``rtnl_lock``. In addition, netdev instance lock is taken as well if 295 301 the driver implements queue management or shaper API.
-2
include/linux/netdevice.h
··· 3316 3316 void netif_close(struct net_device *dev); 3317 3317 void dev_close(struct net_device *dev); 3318 3318 void dev_close_many(struct list_head *head, bool unlink); 3319 - int dev_setup_tc(struct net_device *dev, enum tc_setup_type type, 3320 - void *type_data); 3321 3319 void netif_disable_lro(struct net_device *dev); 3322 3320 void dev_disable_lro(struct net_device *dev); 3323 3321 int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb);
-19
net/core/dev.c
··· 1761 1761 } 1762 1762 } 1763 1763 1764 - int dev_setup_tc(struct net_device *dev, enum tc_setup_type type, 1765 - void *type_data) 1766 - { 1767 - const struct net_device_ops *ops = dev->netdev_ops; 1768 - int ret; 1769 - 1770 - ASSERT_RTNL(); 1771 - 1772 - if (!ops->ndo_setup_tc) 1773 - return -EOPNOTSUPP; 1774 - 1775 - netdev_lock_ops(dev); 1776 - ret = ops->ndo_setup_tc(dev, type, type_data); 1777 - netdev_unlock_ops(dev); 1778 - 1779 - return ret; 1780 - } 1781 - EXPORT_SYMBOL(dev_setup_tc); 1782 - 1783 1764 void netif_disable_lro(struct net_device *dev) 1784 1765 { 1785 1766 struct net_device *lower_dev;
+1 -1
net/netfilter/nf_flow_table_offload.c
··· 1175 1175 nf_flow_table_block_offload_init(bo, dev_net(dev), cmd, flowtable, 1176 1176 extack); 1177 1177 down_write(&flowtable->flow_block_lock); 1178 - err = dev_setup_tc(dev, TC_SETUP_FT, bo); 1178 + err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_FT, bo); 1179 1179 up_write(&flowtable->flow_block_lock); 1180 1180 if (err < 0) 1181 1181 return err;
+1 -1
net/netfilter/nf_tables_offload.c
··· 390 390 391 391 nft_flow_block_offload_init(&bo, dev_net(dev), cmd, chain, &extack); 392 392 393 - err = dev_setup_tc(dev, TC_SETUP_BLOCK, &bo); 393 + err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo); 394 394 if (err < 0) 395 395 return err; 396 396