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

netfilter: nf_dup_netdev: Move the recursion counter struct netdev_xmit

nf_dup_skb_recursion is a per-CPU variable and relies on disabled BH for its
locking. Without per-CPU locking in local_bh_disable() on PREEMPT_RT
this data structure requires explicit locking.

Move nf_dup_skb_recursion to struct netdev_xmit, provide wrappers.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Sebastian Andrzej Siewior and committed by
Pablo Neira Ayuso
f37ad912 ba36fada

+21 -4
+3
include/linux/netdevice_xmit.h
··· 11 11 #if IS_ENABLED(CONFIG_NET_ACT_MIRRED) 12 12 u8 sched_mirred_nest; 13 13 #endif 14 + #if IS_ENABLED(CONFIG_NF_DUP_NETDEV) 15 + u8 nf_dup_skb_recursion; 16 + #endif 14 17 }; 15 18 16 19 #endif
+18 -4
net/netfilter/nf_dup_netdev.c
··· 15 15 16 16 #define NF_RECURSION_LIMIT 2 17 17 18 - static DEFINE_PER_CPU(u8, nf_dup_skb_recursion); 18 + #ifndef CONFIG_PREEMPT_RT 19 + static u8 *nf_get_nf_dup_skb_recursion(void) 20 + { 21 + return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion); 22 + } 23 + #else 24 + 25 + static u8 *nf_get_nf_dup_skb_recursion(void) 26 + { 27 + return &current->net_xmit.nf_dup_skb_recursion; 28 + } 29 + 30 + #endif 19 31 20 32 static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev, 21 33 enum nf_dev_hooks hook) 22 34 { 23 - if (__this_cpu_read(nf_dup_skb_recursion) > NF_RECURSION_LIMIT) 35 + u8 *nf_dup_skb_recursion = nf_get_nf_dup_skb_recursion(); 36 + 37 + if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT) 24 38 goto err; 25 39 26 40 if (hook == NF_NETDEV_INGRESS && skb_mac_header_was_set(skb)) { ··· 46 32 47 33 skb->dev = dev; 48 34 skb_clear_tstamp(skb); 49 - __this_cpu_inc(nf_dup_skb_recursion); 35 + (*nf_dup_skb_recursion)++; 50 36 dev_queue_xmit(skb); 51 - __this_cpu_dec(nf_dup_skb_recursion); 37 + (*nf_dup_skb_recursion)--; 52 38 return; 53 39 err: 54 40 kfree_skb(skb);