From aeb709c767aeca996e6011133e4f7bdb2a4af652 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Sep 2026 09:59:20 +0000 Subject: selftests/bpf: Add a test for objects stuck in free_by_rcu_ttrace Delete all elements of BPF_F_NO_PREALLOC hash map in one batch. The first free_bulk() starts RCU tasks trace GP and the rest of the elements are freed while it's in flight. Wait for call_rcu_ttrace_in_progress to clear in bpf_mem_cache of every cpu and check that free_by_rcu_ttrace and waiting_for_gp_ttrace lists are empty. Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20260930095920.601738-4-alexei.starovoitov@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi --- include/net/inetpeer.h | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 include/net/inetpeer.h (limited to 'include/net/inetpeer.h') diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h new file mode 100644 index 000000000..414e9adf4 --- /dev/null +++ b/include/net/inetpeer.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * INETPEER - A storage for permanent information about peers + * + * Authors: Andrey V. Savochkin + */ + +#ifndef _NET_INETPEER_H +#define _NET_INETPEER_H + +#include +#include +#include +#include +#include +#include +#include + +/* IPv4 address key for cache lookups */ +struct ipv4_addr_key { + __be32 addr; + int vif; +}; + +#define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) + +struct inetpeer_addr { + union { + struct ipv4_addr_key a4; + struct in6_addr a6; + u32 key[INETPEER_MAXKEYSZ]; + }; + __u16 family; +}; + +struct inet_peer { + struct rb_node rb_node; + u64 hash; + struct inetpeer_addr daddr; + + u32 metrics[RTAX_MAX]; + u32 rate_tokens; /* rate limiting for ICMP */ + u32 n_redirects; + unsigned long rate_last; + /* + * Once inet_peer is queued for deletion (refcnt == 0), following field + * is not available: rid + * We can share memory with rcu_head to help keep inet_peer small. + */ + union { + struct { + atomic_t rid; /* Frag reception counter */ + }; + struct rcu_head rcu; + }; + + /* following fields might be frequently dirtied */ + __u32 dtime; /* the time of last use of not referenced entries */ + refcount_t refcnt; +}; + +struct inet_peer_base { + struct rb_root rb_root; + seqlock_t lock; + int total; +}; + +void inet_peer_base_init(struct inet_peer_base *); + +void inet_initpeers(void) __init; + +#define INETPEER_METRICS_NEW (~(u32) 0) + +static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) +{ + iaddr->a4.addr = ip; + iaddr->a4.vif = 0; + iaddr->family = AF_INET; +} + +static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) +{ + return iaddr->a4.addr; +} + +static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, + struct in6_addr *in6) +{ + iaddr->a6 = *in6; + iaddr->family = AF_INET6; +} + +static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) +{ + return &iaddr->a6; +} + +/* can be called with or without local BH being disabled */ +struct inet_peer *inet_getpeer(struct inet_peer_base *base, + const struct inetpeer_addr *daddr); + +static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, + __be32 v4daddr, + int vif) +{ + struct inetpeer_addr daddr; + + daddr.a4.addr = v4daddr; + daddr.a4.vif = vif; + daddr.family = AF_INET; + return inet_getpeer(base, &daddr); +} + +static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, + const struct in6_addr *v6daddr) +{ + struct inetpeer_addr daddr; + + daddr.a6 = *v6daddr; + daddr.family = AF_INET6; + return inet_getpeer(base, &daddr); +} + +static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, + const struct inetpeer_addr *b) +{ + int i, n; + + if (a->family != b->family) + return a->family < b->family ? -1 : 1; + + if (a->family == AF_INET) + n = sizeof(a->a4) / sizeof(u32); + else + n = sizeof(a->a6) / sizeof(u32); + + for (i = 0; i < n; i++) { + if (a->key[i] == b->key[i]) + continue; + if (a->key[i] < b->key[i]) + return -1; + return 1; + } + + return 0; +} + +/* can be called from BH context or outside */ +void inet_putpeer(struct inet_peer *p); +bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); + +void inetpeer_invalidate_tree(struct inet_peer_base *); + +#endif /* _NET_INETPEER_H */ -- cgit v1.3.1