mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
netfilter: nf_dup_netdev: add nf_dev_xmit_recursion*() helpers and use them
Update nft_dup and nft_fwd to use the nf_dev_xmit_recursion() helpers. This patch also disables BH when transmitting the skb to address a possible migration to different CPU leading to imbalanced decrementation of the recursion counters. This is modeled after Florian Westphal's dev_xmit_recursion*() API available since commit97cdcf37b5("net: place xmit recursion in softnet data") according to its current state in the tree. Fixes:1d47b55b36("netfilter: nft_fwd_netdev: use recursion counter in neigh egress path") Fixes:f37ad91270("netfilter: nf_dup_netdev: Move the recursion counter struct netdev_xmit") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
0e2a5d02f1
commit
2354e97593
|
|
@ -11,15 +11,39 @@ void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
|||
|
||||
#define NF_RECURSION_LIMIT 2
|
||||
|
||||
static inline u8 *nf_get_nf_dup_skb_recursion(void)
|
||||
{
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion);
|
||||
#else
|
||||
return ¤t->net_xmit.nf_dup_skb_recursion;
|
||||
#endif
|
||||
static inline bool nf_dev_xmit_recursion(void)
|
||||
{
|
||||
return unlikely(__this_cpu_read(softnet_data.xmit.nf_dup_skb_recursion) >
|
||||
NF_RECURSION_LIMIT);
|
||||
}
|
||||
|
||||
static inline void nf_dev_xmit_recursion_inc(void)
|
||||
{
|
||||
__this_cpu_inc(softnet_data.xmit.nf_dup_skb_recursion);
|
||||
}
|
||||
|
||||
static inline void nf_dev_xmit_recursion_dec(void)
|
||||
{
|
||||
__this_cpu_dec(softnet_data.xmit.nf_dup_skb_recursion);
|
||||
}
|
||||
#else
|
||||
static inline bool nf_dev_xmit_recursion(void)
|
||||
{
|
||||
return unlikely(current->net_xmit.nf_dup_skb_recursion > NF_RECURSION_LIMIT);
|
||||
}
|
||||
|
||||
static inline void nf_dev_xmit_recursion_inc(void)
|
||||
{
|
||||
current->net_xmit.nf_dup_skb_recursion++;
|
||||
}
|
||||
|
||||
static inline void nf_dev_xmit_recursion_dec(void)
|
||||
{
|
||||
current->net_xmit.nf_dup_skb_recursion--;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct nft_offload_ctx;
|
||||
struct nft_flow_rule;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,6 @@
|
|||
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
||||
enum nf_dev_hooks hook)
|
||||
{
|
||||
u8 *nf_dup_skb_recursion = nf_get_nf_dup_skb_recursion();
|
||||
|
||||
if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT)
|
||||
goto err;
|
||||
|
||||
if (hook == NF_NETDEV_INGRESS && skb_mac_header_was_set(skb)) {
|
||||
if (skb_cow_head(skb, skb->mac_len))
|
||||
goto err;
|
||||
|
|
@ -30,9 +25,15 @@ static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
|||
|
||||
skb->dev = dev;
|
||||
skb_clear_tstamp(skb);
|
||||
(*nf_dup_skb_recursion)++;
|
||||
local_bh_disable();
|
||||
if (nf_dev_xmit_recursion()) {
|
||||
local_bh_enable();
|
||||
goto err;
|
||||
}
|
||||
nf_dev_xmit_recursion_inc();
|
||||
dev_queue_xmit(skb);
|
||||
(*nf_dup_skb_recursion)--;
|
||||
nf_dev_xmit_recursion_dec();
|
||||
local_bh_enable();
|
||||
return;
|
||||
err:
|
||||
kfree_skb(skb);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
u8 *nf_dup_skb_recursion = nf_get_nf_dup_skb_recursion();
|
||||
struct nft_fwd_neigh *priv = nft_expr_priv(expr);
|
||||
void *addr = ®s->data[priv->sreg_addr];
|
||||
int oif = regs->data[priv->sreg_dev];
|
||||
|
|
@ -154,13 +153,15 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT) {
|
||||
dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
||||
if (!dev) {
|
||||
verdict = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
||||
if (dev == NULL) {
|
||||
local_bh_disable();
|
||||
if (nf_dev_xmit_recursion()) {
|
||||
local_bh_enable();
|
||||
verdict = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -169,16 +170,18 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|||
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
|
||||
skb = skb_expand_head(skb, hh_len);
|
||||
if (!skb) {
|
||||
verdict = NF_STOLEN;
|
||||
local_bh_enable();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
skb->dev = dev;
|
||||
skb_clear_tstamp(skb);
|
||||
(*nf_dup_skb_recursion)++;
|
||||
|
||||
nf_dev_xmit_recursion_inc();
|
||||
neigh_xmit(neigh_table, dev, addr, skb);
|
||||
(*nf_dup_skb_recursion)--;
|
||||
nf_dev_xmit_recursion_dec();
|
||||
local_bh_enable();
|
||||
out:
|
||||
regs->verdict.code = verdict;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user