When generic_xdp_tx() fails to transmit an skb, it reports the drop
through trace_xdp_exception() with the action hardcoded to XDP_TX.
That was right when generic XDP was added, and XDP_TX was the only
caller. Since then, two XDP_REDIRECT paths have started to transmit
through generic_xdp_tx() as well:

- xdp_do_generic_redirect(), for a redirect to an ifindex
- dev_map_generic_redirect(), for DEVMAP and DEVMAP_HASH redirects,
  including broadcast

Drops on those paths are reported as XDP_TX, an action which the
program never returned. Tools which count xdp:xdp_exception events per
action, such as the samples/bpf programs built on xdp_sample, therefore
attribute generic XDP redirect drops to the wrong action. Drivers with
native XDP already report XDP_TX and XDP_REDIRECT drops separately.

Add an "act" argument to generic_xdp_tx(), and have each caller pass
the action that led to the transmission: XDP_TX from do_xdp_generic(),
XDP_REDIRECT from the two redirect paths. generic_xdp_tx() is not
exported, so these are all of its users.

Fixes: 6103aa96ec07 ("net: implement XDP_REDIRECT for xdp generic")
Fixes: 6d5fc1957989 ("xdp: Fix handling of devmap in generic XDP")
Signed-off-by: Vladimir Oltean <[email protected]>
---
 include/linux/netdevice.h | 3 ++-
 kernel/bpf/devmap.c       | 2 +-
 net/core/dev.c            | 7 ++++---
 net/core/filter.c         | 2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c0ae442c4344..b988afe797c3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4355,7 +4355,8 @@ static inline void dev_consume_skb_any(struct sk_buff 
*skb)
 
 u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
                             const struct bpf_prog *xdp_prog);
-void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog);
+void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog,
+                   u32 act);
 int do_xdp_generic(const struct bpf_prog *xdp_prog, struct sk_buff **pskb);
 int netif_rx(struct sk_buff *skb);
 int __netif_rx(struct sk_buff *skb);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 1b8f0d7f8455..c73e8797c0fc 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -731,7 +731,7 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, 
struct sk_buff *skb,
                return 0;
 
        skb->dev = dst->dev;
-       generic_xdp_tx(skb, xdp_prog);
+       generic_xdp_tx(skb, xdp_prog, XDP_REDIRECT);
 
        return 0;
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index 3ac700d37e59..88860185f583 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5851,7 +5851,8 @@ static u32 netif_receive_generic_xdp(struct sk_buff 
**pskb,
  * and DDOS attacks will be more effective. In-driver-XDP use dedicated TX
  * queues, so they do not have this starvation issue.
  */
-void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog)
+void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog,
+                   u32 act)
 {
        struct net_device *dev = skb->dev;
        struct netdev_queue *txq;
@@ -5868,7 +5869,7 @@ void generic_xdp_tx(struct sk_buff *skb, const struct 
bpf_prog *xdp_prog)
        }
        HARD_TX_UNLOCK(dev, txq);
        if (free_skb) {
-               trace_xdp_exception(dev, xdp_prog, XDP_TX);
+               trace_xdp_exception(dev, xdp_prog, act);
                dev_core_stats_tx_dropped_inc(dev);
                kfree_skb(skb);
        }
@@ -5896,7 +5897,7 @@ int do_xdp_generic(const struct bpf_prog *xdp_prog, 
struct sk_buff **pskb)
                                        goto out_redir;
                                break;
                        case XDP_TX:
-                               generic_xdp_tx(*pskb, xdp_prog);
+                               generic_xdp_tx(*pskb, xdp_prog, XDP_TX);
                                break;
                        }
                        bpf_net_ctx_clear(bpf_net_ctx);
diff --git a/net/core/filter.c b/net/core/filter.c
index 09c60a58c82a..7c6f8bcc6c29 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4821,7 +4821,7 @@ int xdp_do_generic_redirect(struct net_device *dev, 
struct sk_buff *skb,
 
                skb->dev = fwd;
                _trace_xdp_redirect(dev, xdp_prog, ri->tgt_index);
-               generic_xdp_tx(skb, xdp_prog);
+               generic_xdp_tx(skb, xdp_prog, XDP_REDIRECT);
                return 0;
        }
 
-- 
2.43.0


Reply via email to