Skip to content

Commit 9a675ba

Browse files
Sebastian Andrzej Siewiorborkmann
Sebastian Andrzej Siewior
authored andcommitted
net, bpf: Add a warning if NAPI cb missed xdp_do_flush().
A few drivers were missing a xdp_do_flush() invocation after XDP_REDIRECT. Add three helper functions each for one of the per-CPU lists. Return true if the per-CPU list is non-empty and flush the list. Add xdp_do_check_flushed() which invokes each helper functions and creates a warning if one of the functions had a non-empty list. Hide everything behind CONFIG_DEBUG_NET. Suggested-by: Jesper Dangaard Brouer <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Reviewed-by: Toke Høiland-Jørgensen <[email protected]> Acked-by: Jakub Kicinski <[email protected]> Acked-by: John Fastabend <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 137df11 commit 9a675ba

File tree

8 files changed

+66
-0
lines changed

8 files changed

+66
-0
lines changed

include/linux/bpf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,6 +2478,9 @@ void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data,
24782478
enum bpf_dynptr_type type, u32 offset, u32 size);
24792479
void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr);
24802480
void bpf_dynptr_set_rdonly(struct bpf_dynptr_kern *ptr);
2481+
2482+
bool dev_check_flush(void);
2483+
bool cpu_map_check_flush(void);
24812484
#else /* !CONFIG_BPF_SYSCALL */
24822485
static inline struct bpf_prog *bpf_prog_get(u32 ufd)
24832486
{

include/net/xdp_sock.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,13 @@ static inline void __xsk_map_flush(void)
109109

110110
#endif /* CONFIG_XDP_SOCKETS */
111111

112+
#if defined(CONFIG_XDP_SOCKETS) && defined(CONFIG_DEBUG_NET)
113+
bool xsk_map_check_flush(void);
114+
#else
115+
static inline bool xsk_map_check_flush(void)
116+
{
117+
return false;
118+
}
119+
#endif
120+
112121
#endif /* _LINUX_XDP_SOCK_H */

kernel/bpf/cpumap.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,16 @@ void __cpu_map_flush(void)
764764
}
765765
}
766766

767+
#ifdef CONFIG_DEBUG_NET
768+
bool cpu_map_check_flush(void)
769+
{
770+
if (list_empty(this_cpu_ptr(&cpu_map_flush_list)))
771+
return false;
772+
__cpu_map_flush();
773+
return true;
774+
}
775+
#endif
776+
767777
static int __init cpu_map_init(void)
768778
{
769779
int cpu;

kernel/bpf/devmap.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,16 @@ void __dev_flush(void)
418418
}
419419
}
420420

421+
#ifdef CONFIG_DEBUG_NET
422+
bool dev_check_flush(void)
423+
{
424+
if (list_empty(this_cpu_ptr(&dev_flush_list)))
425+
return false;
426+
__dev_flush();
427+
return true;
428+
}
429+
#endif
430+
421431
/* Elements are kept alive by RCU; either by rcu_read_lock() (from syscall) or
422432
* by local_bh_disable() (from XDP calls inside NAPI). The
423433
* rcu_read_lock_bh_held() below makes lockdep accept both.

net/core/dev.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6535,6 +6535,8 @@ static int __napi_poll(struct napi_struct *n, bool *repoll)
65356535
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
65366536
work = n->poll(n, weight);
65376537
trace_napi_poll(n, work, weight);
6538+
6539+
xdp_do_check_flushed(n);
65386540
}
65396541

65406542
if (unlikely(work > weight))

net/core/dev.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,10 @@ static inline void netif_set_gro_ipv4_max_size(struct net_device *dev,
136136
}
137137

138138
int rps_cpumask_housekeeping(struct cpumask *mask);
139+
140+
#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_BPF_SYSCALL)
141+
void xdp_do_check_flushed(struct napi_struct *napi);
142+
#else
143+
static inline void xdp_do_check_flushed(struct napi_struct *napi) { }
144+
#endif
139145
#endif

net/core/filter.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
#include <net/netfilter/nf_conntrack_bpf.h>
8484
#include <linux/un.h>
8585

86+
#include "dev.h"
87+
8688
static const struct bpf_func_proto *
8789
bpf_sk_base_func_proto(enum bpf_func_id func_id);
8890

@@ -4208,6 +4210,20 @@ void xdp_do_flush(void)
42084210
}
42094211
EXPORT_SYMBOL_GPL(xdp_do_flush);
42104212

4213+
#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_BPF_SYSCALL)
4214+
void xdp_do_check_flushed(struct napi_struct *napi)
4215+
{
4216+
bool ret;
4217+
4218+
ret = dev_check_flush();
4219+
ret |= cpu_map_check_flush();
4220+
ret |= xsk_map_check_flush();
4221+
4222+
WARN_ONCE(ret, "Missing xdp_do_flush() invocation after NAPI by %ps\n",
4223+
napi->poll);
4224+
}
4225+
#endif
4226+
42114227
void bpf_clear_redirect_map(struct bpf_map *map)
42124228
{
42134229
struct bpf_redirect_info *ri;

net/xdp/xsk.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,16 @@ void __xsk_map_flush(void)
391391
}
392392
}
393393

394+
#ifdef CONFIG_DEBUG_NET
395+
bool xsk_map_check_flush(void)
396+
{
397+
if (list_empty(this_cpu_ptr(&xskmap_flush_list)))
398+
return false;
399+
__xsk_map_flush();
400+
return true;
401+
}
402+
#endif
403+
394404
void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
395405
{
396406
xskq_prod_submit_n(pool->cq, nb_entries);

0 commit comments

Comments
 (0)