mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
Merge branch 'xdp-a-fistful-of-generic-changes-pt-i'
Alexander Lobakin says: ==================== xdp: a fistful of generic changes pt. I XDP for idpf is currently 6 chapters: * convert Rx to libeth; * convert Tx and stats to libeth; * generic XDP and XSk code changes (you are here); * generic XDP and XSk code additions; * actual XDP for idpf via new libeth_xdp; * XSk for idpf (via ^). Part III does the following: * improve &xdp_buff_xsk cacheline placement; * does some cleanups with marking read-only bpf_prog and xdp_buff arguments const for some generic functions; * allows attaching already registered XDP memory model to RxQ info; * makes system percpu page_pools valid XDP memory models; * starts using netmems in the XDP core code (1 function); * allows mixing pages from several page_pools within one XDP frame; * optimizes &xdp_frame layout and removes no-more-used field. Bullets 4-6 are the most important ones. All of them are prereqs to libeth_xdp. ==================== Link: https://patch.msgid.link/20241203173733.3181246-1-aleksander.lobakin@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
9d1a8c6f98
|
|
@ -2591,10 +2591,10 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_frame *xdpf,
|
|||
int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,
|
||||
struct bpf_map *map, bool exclude_ingress);
|
||||
int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog);
|
||||
const struct bpf_prog *xdp_prog);
|
||||
int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog, struct bpf_map *map,
|
||||
bool exclude_ingress);
|
||||
const struct bpf_prog *xdp_prog,
|
||||
struct bpf_map *map, bool exclude_ingress);
|
||||
|
||||
void __cpu_map_flush(struct list_head *flush_list);
|
||||
int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf,
|
||||
|
|
@ -2864,15 +2864,15 @@ struct sk_buff;
|
|||
|
||||
static inline int dev_map_generic_redirect(struct bpf_dtab_netdev *dst,
|
||||
struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog, struct bpf_map *map,
|
||||
bool exclude_ingress)
|
||||
const struct bpf_prog *xdp_prog,
|
||||
struct bpf_map *map, bool exclude_ingress)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1179,17 +1179,18 @@ static inline int xdp_ok_fwd_dev(const struct net_device *fwd,
|
|||
* This does not appear to be a real limitation for existing software.
|
||||
*/
|
||||
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
|
||||
struct xdp_buff *xdp, struct bpf_prog *prog);
|
||||
struct xdp_buff *xdp, const struct bpf_prog *prog);
|
||||
int xdp_do_redirect(struct net_device *dev,
|
||||
struct xdp_buff *xdp,
|
||||
struct bpf_prog *prog);
|
||||
const struct bpf_prog *prog);
|
||||
int xdp_do_redirect_frame(struct net_device *dev,
|
||||
struct xdp_buff *xdp,
|
||||
struct xdp_frame *xdpf,
|
||||
struct bpf_prog *prog);
|
||||
const struct bpf_prog *prog);
|
||||
void xdp_do_flush(void);
|
||||
|
||||
void bpf_warn_invalid_xdp_action(struct net_device *dev, struct bpf_prog *prog, u32 act);
|
||||
void bpf_warn_invalid_xdp_action(const struct net_device *dev,
|
||||
const struct bpf_prog *prog, u32 act);
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
struct sock *bpf_run_sk_reuseport(struct sock_reuseport *reuse, struct sock *sk,
|
||||
|
|
|
|||
|
|
@ -3322,6 +3322,7 @@ struct softnet_data {
|
|||
};
|
||||
|
||||
DECLARE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
|
||||
DECLARE_PER_CPU(struct page_pool *, system_page_pool);
|
||||
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
static inline int dev_recursion_level(void)
|
||||
|
|
@ -3958,9 +3959,9 @@ 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,
|
||||
struct bpf_prog *xdp_prog);
|
||||
void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog);
|
||||
int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff **pskb);
|
||||
const struct bpf_prog *xdp_prog);
|
||||
void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog);
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -3627,7 +3627,7 @@ static inline netmem_ref skb_frag_netmem(const skb_frag_t *frag)
|
|||
int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb,
|
||||
unsigned int headroom);
|
||||
int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb,
|
||||
struct bpf_prog *prog);
|
||||
const struct bpf_prog *prog);
|
||||
|
||||
/**
|
||||
* skb_frag_address - gets the address of the data contained in a paged fragment
|
||||
|
|
|
|||
|
|
@ -72,6 +72,22 @@ static inline bool netmem_is_net_iov(const netmem_ref netmem)
|
|||
return (__force unsigned long)netmem & NET_IOV;
|
||||
}
|
||||
|
||||
/**
|
||||
* __netmem_to_page - unsafely get pointer to the &page backing @netmem
|
||||
* @netmem: netmem reference to convert
|
||||
*
|
||||
* Unsafe version of netmem_to_page(). When @netmem is always page-backed,
|
||||
* e.g. when it's a header buffer, performs faster and generates smaller
|
||||
* object code (no check for the LSB, no WARN). When @netmem points to IOV,
|
||||
* provokes undefined behaviour.
|
||||
*
|
||||
* Return: pointer to the &page (garbage if @netmem is not page-backed).
|
||||
*/
|
||||
static inline struct page *__netmem_to_page(netmem_ref netmem)
|
||||
{
|
||||
return (__force struct page *)netmem;
|
||||
}
|
||||
|
||||
/* This conversion fails (returns NULL) if the netmem_ref is not struct page
|
||||
* backed.
|
||||
*/
|
||||
|
|
@ -80,7 +96,7 @@ static inline struct page *netmem_to_page(netmem_ref netmem)
|
|||
if (WARN_ON_ONCE(netmem_is_net_iov(netmem)))
|
||||
return NULL;
|
||||
|
||||
return (__force struct page *)netmem;
|
||||
return __netmem_to_page(netmem);
|
||||
}
|
||||
|
||||
static inline struct net_iov *netmem_to_net_iov(netmem_ref netmem)
|
||||
|
|
@ -103,6 +119,17 @@ static inline netmem_ref page_to_netmem(struct page *page)
|
|||
return (__force netmem_ref)page;
|
||||
}
|
||||
|
||||
/**
|
||||
* virt_to_netmem - convert virtual memory pointer to a netmem reference
|
||||
* @data: host memory pointer to convert
|
||||
*
|
||||
* Return: netmem reference to the &page backing this virtual address.
|
||||
*/
|
||||
static inline netmem_ref virt_to_netmem(const void *data)
|
||||
{
|
||||
return page_to_netmem(virt_to_page(data));
|
||||
}
|
||||
|
||||
static inline int netmem_ref_count(netmem_ref netmem)
|
||||
{
|
||||
/* The non-pp refcount of net_iov is always 1. On net_iov, we only
|
||||
|
|
@ -127,6 +154,22 @@ static inline struct net_iov *__netmem_clear_lsb(netmem_ref netmem)
|
|||
return (struct net_iov *)((__force unsigned long)netmem & ~NET_IOV);
|
||||
}
|
||||
|
||||
/**
|
||||
* __netmem_get_pp - unsafely get pointer to the &page_pool backing @netmem
|
||||
* @netmem: netmem reference to get the pointer from
|
||||
*
|
||||
* Unsafe version of netmem_get_pp(). When @netmem is always page-backed,
|
||||
* e.g. when it's a header buffer, performs faster and generates smaller
|
||||
* object code (avoids clearing the LSB). When @netmem points to IOV,
|
||||
* provokes invalid memory access.
|
||||
*
|
||||
* Return: pointer to the &page_pool (garbage if @netmem is not page-backed).
|
||||
*/
|
||||
static inline struct page_pool *__netmem_get_pp(netmem_ref netmem)
|
||||
{
|
||||
return __netmem_to_page(netmem)->pp;
|
||||
}
|
||||
|
||||
static inline struct page_pool *netmem_get_pp(netmem_ref netmem)
|
||||
{
|
||||
return __netmem_clear_lsb(netmem)->pp;
|
||||
|
|
@ -158,12 +201,43 @@ static inline netmem_ref netmem_compound_head(netmem_ref netmem)
|
|||
return page_to_netmem(compound_head(netmem_to_page(netmem)));
|
||||
}
|
||||
|
||||
/**
|
||||
* __netmem_address - unsafely get pointer to the memory backing @netmem
|
||||
* @netmem: netmem reference to get the pointer for
|
||||
*
|
||||
* Unsafe version of netmem_address(). When @netmem is always page-backed,
|
||||
* e.g. when it's a header buffer, performs faster and generates smaller
|
||||
* object code (no check for the LSB). When @netmem points to IOV, provokes
|
||||
* undefined behaviour.
|
||||
*
|
||||
* Return: pointer to the memory (garbage if @netmem is not page-backed).
|
||||
*/
|
||||
static inline void *__netmem_address(netmem_ref netmem)
|
||||
{
|
||||
return page_address(__netmem_to_page(netmem));
|
||||
}
|
||||
|
||||
static inline void *netmem_address(netmem_ref netmem)
|
||||
{
|
||||
if (netmem_is_net_iov(netmem))
|
||||
return NULL;
|
||||
|
||||
return page_address(netmem_to_page(netmem));
|
||||
return __netmem_address(netmem);
|
||||
}
|
||||
|
||||
/**
|
||||
* netmem_is_pfmemalloc - check if @netmem was allocated under memory pressure
|
||||
* @netmem: netmem reference to check
|
||||
*
|
||||
* Return: true if @netmem is page-backed and the page was allocated under
|
||||
* memory pressure, false otherwise.
|
||||
*/
|
||||
static inline bool netmem_is_pfmemalloc(netmem_ref netmem)
|
||||
{
|
||||
if (netmem_is_net_iov(netmem))
|
||||
return false;
|
||||
|
||||
return page_is_pfmemalloc(netmem_to_page(netmem));
|
||||
}
|
||||
|
||||
static inline unsigned long netmem_get_dma_addr(netmem_ref netmem)
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ void page_pool_disable_direct_recycling(struct page_pool *pool);
|
|||
void page_pool_destroy(struct page_pool *pool);
|
||||
void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *),
|
||||
const struct xdp_mem_info *mem);
|
||||
void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
||||
int count);
|
||||
void page_pool_put_netmem_bulk(struct page_pool *pool, netmem_ref *data,
|
||||
u32 count);
|
||||
#else
|
||||
static inline void page_pool_destroy(struct page_pool *pool)
|
||||
{
|
||||
|
|
@ -272,8 +272,8 @@ static inline void page_pool_use_xdp_mem(struct page_pool *pool,
|
|||
{
|
||||
}
|
||||
|
||||
static inline void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
||||
int count)
|
||||
static inline void page_pool_put_netmem_bulk(struct page_pool *pool,
|
||||
netmem_ref *data, u32 count)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ struct xdp_buff {
|
|||
u32 flags; /* supported values defined in xdp_buff_flags */
|
||||
};
|
||||
|
||||
static __always_inline bool xdp_buff_has_frags(struct xdp_buff *xdp)
|
||||
static __always_inline bool xdp_buff_has_frags(const struct xdp_buff *xdp)
|
||||
{
|
||||
return !!(xdp->flags & XDP_FLAGS_HAS_FRAGS);
|
||||
}
|
||||
|
|
@ -103,7 +103,8 @@ static __always_inline void xdp_buff_clear_frags_flag(struct xdp_buff *xdp)
|
|||
xdp->flags &= ~XDP_FLAGS_HAS_FRAGS;
|
||||
}
|
||||
|
||||
static __always_inline bool xdp_buff_is_frag_pfmemalloc(struct xdp_buff *xdp)
|
||||
static __always_inline bool
|
||||
xdp_buff_is_frag_pfmemalloc(const struct xdp_buff *xdp)
|
||||
{
|
||||
return !!(xdp->flags & XDP_FLAGS_FRAGS_PF_MEMALLOC);
|
||||
}
|
||||
|
|
@ -144,15 +145,16 @@ xdp_prepare_buff(struct xdp_buff *xdp, unsigned char *hard_start,
|
|||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
|
||||
static inline struct skb_shared_info *
|
||||
xdp_get_shared_info_from_buff(struct xdp_buff *xdp)
|
||||
xdp_get_shared_info_from_buff(const struct xdp_buff *xdp)
|
||||
{
|
||||
return (struct skb_shared_info *)xdp_data_hard_end(xdp);
|
||||
}
|
||||
|
||||
static __always_inline unsigned int xdp_get_buff_len(struct xdp_buff *xdp)
|
||||
static __always_inline unsigned int
|
||||
xdp_get_buff_len(const struct xdp_buff *xdp)
|
||||
{
|
||||
unsigned int len = xdp->data_end - xdp->data;
|
||||
struct skb_shared_info *sinfo;
|
||||
const struct skb_shared_info *sinfo;
|
||||
|
||||
if (likely(!xdp_buff_has_frags(xdp)))
|
||||
goto out;
|
||||
|
|
@ -177,12 +179,13 @@ struct xdp_frame {
|
|||
u32 flags; /* supported values defined in xdp_buff_flags */
|
||||
};
|
||||
|
||||
static __always_inline bool xdp_frame_has_frags(struct xdp_frame *frame)
|
||||
static __always_inline bool xdp_frame_has_frags(const struct xdp_frame *frame)
|
||||
{
|
||||
return !!(frame->flags & XDP_FLAGS_HAS_FRAGS);
|
||||
}
|
||||
|
||||
static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame)
|
||||
static __always_inline bool
|
||||
xdp_frame_is_frag_pfmemalloc(const struct xdp_frame *frame)
|
||||
{
|
||||
return !!(frame->flags & XDP_FLAGS_FRAGS_PF_MEMALLOC);
|
||||
}
|
||||
|
|
@ -191,7 +194,7 @@ static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame
|
|||
struct xdp_frame_bulk {
|
||||
int count;
|
||||
void *xa;
|
||||
void *q[XDP_BULK_QUEUE_SIZE];
|
||||
netmem_ref q[XDP_BULK_QUEUE_SIZE];
|
||||
};
|
||||
|
||||
static __always_inline void xdp_frame_bulk_init(struct xdp_frame_bulk *bq)
|
||||
|
|
@ -201,7 +204,7 @@ static __always_inline void xdp_frame_bulk_init(struct xdp_frame_bulk *bq)
|
|||
}
|
||||
|
||||
static inline struct skb_shared_info *
|
||||
xdp_get_shared_info_from_frame(struct xdp_frame *frame)
|
||||
xdp_get_shared_info_from_frame(const struct xdp_frame *frame)
|
||||
{
|
||||
void *data_hard_start = frame->data - frame->headroom - sizeof(*frame);
|
||||
|
||||
|
|
@ -249,7 +252,8 @@ int xdp_alloc_skb_bulk(void **skbs, int n_skb, gfp_t gfp);
|
|||
struct xdp_frame *xdpf_clone(struct xdp_frame *xdpf);
|
||||
|
||||
static inline
|
||||
void xdp_convert_frame_to_buff(struct xdp_frame *frame, struct xdp_buff *xdp)
|
||||
void xdp_convert_frame_to_buff(const struct xdp_frame *frame,
|
||||
struct xdp_buff *xdp)
|
||||
{
|
||||
xdp->data_hard_start = frame->data - frame->headroom - sizeof(*frame);
|
||||
xdp->data = frame->data;
|
||||
|
|
@ -260,7 +264,7 @@ void xdp_convert_frame_to_buff(struct xdp_frame *frame, struct xdp_buff *xdp)
|
|||
}
|
||||
|
||||
static inline
|
||||
int xdp_update_frame_from_buff(struct xdp_buff *xdp,
|
||||
int xdp_update_frame_from_buff(const struct xdp_buff *xdp,
|
||||
struct xdp_frame *xdp_frame)
|
||||
{
|
||||
int metasize, headroom;
|
||||
|
|
@ -317,9 +321,10 @@ void xdp_flush_frame_bulk(struct xdp_frame_bulk *bq);
|
|||
void xdp_return_frame_bulk(struct xdp_frame *xdpf,
|
||||
struct xdp_frame_bulk *bq);
|
||||
|
||||
static __always_inline unsigned int xdp_get_frame_len(struct xdp_frame *xdpf)
|
||||
static __always_inline unsigned int
|
||||
xdp_get_frame_len(const struct xdp_frame *xdpf)
|
||||
{
|
||||
struct skb_shared_info *sinfo;
|
||||
const struct skb_shared_info *sinfo;
|
||||
unsigned int len = xdpf->len;
|
||||
|
||||
if (likely(!xdp_frame_has_frags(xdpf)))
|
||||
|
|
@ -351,6 +356,38 @@ void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq);
|
|||
int xdp_reg_mem_model(struct xdp_mem_info *mem,
|
||||
enum xdp_mem_type type, void *allocator);
|
||||
void xdp_unreg_mem_model(struct xdp_mem_info *mem);
|
||||
int xdp_reg_page_pool(struct page_pool *pool);
|
||||
void xdp_unreg_page_pool(const struct page_pool *pool);
|
||||
void xdp_rxq_info_attach_page_pool(struct xdp_rxq_info *xdp_rxq,
|
||||
const struct page_pool *pool);
|
||||
|
||||
/**
|
||||
* xdp_rxq_info_attach_mem_model - attach registered mem info to RxQ info
|
||||
* @xdp_rxq: XDP RxQ info to attach the memory info to
|
||||
* @mem: already registered memory info
|
||||
*
|
||||
* If the driver registers its memory providers manually, it must use this
|
||||
* function instead of xdp_rxq_info_reg_mem_model().
|
||||
*/
|
||||
static inline void
|
||||
xdp_rxq_info_attach_mem_model(struct xdp_rxq_info *xdp_rxq,
|
||||
const struct xdp_mem_info *mem)
|
||||
{
|
||||
xdp_rxq->mem = *mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdp_rxq_info_detach_mem_model - detach registered mem info from RxQ info
|
||||
* @xdp_rxq: XDP RxQ info to detach the memory info from
|
||||
*
|
||||
* If the driver registers its memory providers manually and then attaches it
|
||||
* via xdp_rxq_info_attach_mem_model(), it must call this function before
|
||||
* xdp_rxq_info_unreg().
|
||||
*/
|
||||
static inline void xdp_rxq_info_detach_mem_model(struct xdp_rxq_info *xdp_rxq)
|
||||
{
|
||||
xdp_rxq->mem = (struct xdp_mem_info){ };
|
||||
}
|
||||
|
||||
/* Drivers not supporting XDP metadata can use this helper, which
|
||||
* rejects any room expansion for metadata as a result.
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool)
|
|||
return xp_alloc(pool);
|
||||
}
|
||||
|
||||
static inline bool xsk_is_eop_desc(struct xdp_desc *desc)
|
||||
static inline bool xsk_is_eop_desc(const struct xdp_desc *desc)
|
||||
{
|
||||
return !xp_mb_desc(desc);
|
||||
}
|
||||
|
|
@ -143,7 +143,7 @@ static inline void xsk_buff_add_frag(struct xdp_buff *xdp)
|
|||
list_add_tail(&frag->list_node, &frag->pool->xskb_list);
|
||||
}
|
||||
|
||||
static inline struct xdp_buff *xsk_buff_get_frag(struct xdp_buff *first)
|
||||
static inline struct xdp_buff *xsk_buff_get_frag(const struct xdp_buff *first)
|
||||
{
|
||||
struct xdp_buff_xsk *xskb = container_of(first, struct xdp_buff_xsk, xdp);
|
||||
struct xdp_buff *ret = NULL;
|
||||
|
|
@ -200,7 +200,8 @@ static inline void *xsk_buff_raw_get_data(struct xsk_buff_pool *pool, u64 addr)
|
|||
XDP_TXMD_FLAGS_CHECKSUM | \
|
||||
0)
|
||||
|
||||
static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta)
|
||||
static inline bool
|
||||
xsk_buff_valid_tx_metadata(const struct xsk_tx_metadata *meta)
|
||||
{
|
||||
return !(meta->flags & ~XDP_TXMD_FLAGS_VALID);
|
||||
}
|
||||
|
|
@ -337,7 +338,7 @@ static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool xsk_is_eop_desc(struct xdp_desc *desc)
|
||||
static inline bool xsk_is_eop_desc(const struct xdp_desc *desc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -360,7 +361,7 @@ static inline void xsk_buff_add_frag(struct xdp_buff *xdp)
|
|||
{
|
||||
}
|
||||
|
||||
static inline struct xdp_buff *xsk_buff_get_frag(struct xdp_buff *first)
|
||||
static inline struct xdp_buff *xsk_buff_get_frag(const struct xdp_buff *first)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ struct xdp_buff_xsk {
|
|||
dma_addr_t frame_dma;
|
||||
struct xsk_buff_pool *pool;
|
||||
struct list_head list_node;
|
||||
};
|
||||
} __aligned_largest;
|
||||
|
||||
#define XSK_CHECK_PRIV_TYPE(t) BUILD_BUG_ON(sizeof(t) > offsetofend(struct xdp_buff_xsk, cb))
|
||||
#define XSK_TX_COMPL_FITS(t) BUILD_BUG_ON(sizeof(struct xsk_tx_metadata_compl) > sizeof(t))
|
||||
|
|
@ -183,7 +183,7 @@ static inline bool xp_desc_crosses_non_contig_pg(struct xsk_buff_pool *pool,
|
|||
!(pool->dma_pages[addr >> PAGE_SHIFT] & XSK_NEXT_PG_CONTIG_MASK);
|
||||
}
|
||||
|
||||
static inline bool xp_mb_desc(struct xdp_desc *desc)
|
||||
static inline bool xp_mb_desc(const struct xdp_desc *desc)
|
||||
{
|
||||
return desc->options & XDP_PKT_CONTD;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -678,7 +678,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,
|
|||
}
|
||||
|
||||
int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
@ -701,7 +701,7 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
|
|||
|
||||
static int dev_map_redirect_clone(struct bpf_dtab_netdev *dst,
|
||||
struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
int err;
|
||||
|
|
@ -720,8 +720,8 @@ static int dev_map_redirect_clone(struct bpf_dtab_netdev *dst,
|
|||
}
|
||||
|
||||
int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
|
||||
struct bpf_prog *xdp_prog, struct bpf_map *map,
|
||||
bool exclude_ingress)
|
||||
const struct bpf_prog *xdp_prog,
|
||||
struct bpf_map *map, bool exclude_ingress)
|
||||
{
|
||||
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
|
||||
struct bpf_dtab_netdev *dst, *last_dst = NULL;
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ EXPORT_PER_CPU_SYMBOL(softnet_data);
|
|||
* PP consumers must pay attention to run APIs in the appropriate context
|
||||
* (e.g. NAPI context).
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct page_pool *, system_page_pool);
|
||||
DEFINE_PER_CPU(struct page_pool *, system_page_pool);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
/*
|
||||
|
|
@ -4931,7 +4931,7 @@ static struct netdev_rx_queue *netif_get_rxqueue(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
void *orig_data, *orig_data_end, *hard_start;
|
||||
struct netdev_rx_queue *rxqueue;
|
||||
|
|
@ -5033,7 +5033,7 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
|
|||
}
|
||||
|
||||
static int
|
||||
netif_skb_check_for_xdp(struct sk_buff **pskb, struct bpf_prog *prog)
|
||||
netif_skb_check_for_xdp(struct sk_buff **pskb, const struct bpf_prog *prog)
|
||||
{
|
||||
struct sk_buff *skb = *pskb;
|
||||
int err, hroom, troom;
|
||||
|
|
@ -5057,7 +5057,7 @@ netif_skb_check_for_xdp(struct sk_buff **pskb, struct bpf_prog *prog)
|
|||
|
||||
static u32 netif_receive_generic_xdp(struct sk_buff **pskb,
|
||||
struct xdp_buff *xdp,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct sk_buff *skb = *pskb;
|
||||
u32 mac_len, act = XDP_DROP;
|
||||
|
|
@ -5110,7 +5110,7 @@ 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, struct bpf_prog *xdp_prog)
|
||||
void generic_xdp_tx(struct sk_buff *skb, const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
struct netdev_queue *txq;
|
||||
|
|
@ -5135,7 +5135,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
|
|||
|
||||
static DEFINE_STATIC_KEY_FALSE(generic_xdp_needed_key);
|
||||
|
||||
int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff **pskb)
|
||||
int do_xdp_generic(const struct bpf_prog *xdp_prog, struct sk_buff **pskb)
|
||||
{
|
||||
struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
|
||||
|
||||
|
|
@ -12152,11 +12152,18 @@ static int net_page_pool_create(int cpuid)
|
|||
.nid = cpu_to_mem(cpuid),
|
||||
};
|
||||
struct page_pool *pp_ptr;
|
||||
int err;
|
||||
|
||||
pp_ptr = page_pool_create_percpu(&page_pool_params, cpuid);
|
||||
if (IS_ERR(pp_ptr))
|
||||
return -ENOMEM;
|
||||
|
||||
err = xdp_reg_page_pool(pp_ptr);
|
||||
if (err) {
|
||||
page_pool_destroy(pp_ptr);
|
||||
return err;
|
||||
}
|
||||
|
||||
per_cpu(system_page_pool, cpuid) = pp_ptr;
|
||||
#endif
|
||||
return 0;
|
||||
|
|
@ -12290,6 +12297,7 @@ static int __init net_dev_init(void)
|
|||
if (!pp_ptr)
|
||||
continue;
|
||||
|
||||
xdp_unreg_page_pool(pp_ptr);
|
||||
page_pool_destroy(pp_ptr);
|
||||
per_cpu(system_page_pool, i) = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4348,9 +4348,9 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)
|
|||
EXPORT_SYMBOL_GPL(xdp_master_redirect);
|
||||
|
||||
static inline int __xdp_do_redirect_xsk(struct bpf_redirect_info *ri,
|
||||
struct net_device *dev,
|
||||
const struct net_device *dev,
|
||||
struct xdp_buff *xdp,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
enum bpf_map_type map_type = ri->map_type;
|
||||
void *fwd = ri->tgt_value;
|
||||
|
|
@ -4371,10 +4371,10 @@ static inline int __xdp_do_redirect_xsk(struct bpf_redirect_info *ri,
|
|||
return err;
|
||||
}
|
||||
|
||||
static __always_inline int __xdp_do_redirect_frame(struct bpf_redirect_info *ri,
|
||||
struct net_device *dev,
|
||||
struct xdp_frame *xdpf,
|
||||
struct bpf_prog *xdp_prog)
|
||||
static __always_inline int
|
||||
__xdp_do_redirect_frame(struct bpf_redirect_info *ri, struct net_device *dev,
|
||||
struct xdp_frame *xdpf,
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
enum bpf_map_type map_type = ri->map_type;
|
||||
void *fwd = ri->tgt_value;
|
||||
|
|
@ -4443,7 +4443,7 @@ static __always_inline int __xdp_do_redirect_frame(struct bpf_redirect_info *ri,
|
|||
}
|
||||
|
||||
int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
|
||||
struct bpf_prog *xdp_prog)
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
enum bpf_map_type map_type = ri->map_type;
|
||||
|
|
@ -4457,7 +4457,8 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
|
|||
EXPORT_SYMBOL_GPL(xdp_do_redirect);
|
||||
|
||||
int xdp_do_redirect_frame(struct net_device *dev, struct xdp_buff *xdp,
|
||||
struct xdp_frame *xdpf, struct bpf_prog *xdp_prog)
|
||||
struct xdp_frame *xdpf,
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
enum bpf_map_type map_type = ri->map_type;
|
||||
|
|
@ -4472,9 +4473,9 @@ EXPORT_SYMBOL_GPL(xdp_do_redirect_frame);
|
|||
static int xdp_do_generic_redirect_map(struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct xdp_buff *xdp,
|
||||
struct bpf_prog *xdp_prog, void *fwd,
|
||||
enum bpf_map_type map_type, u32 map_id,
|
||||
u32 flags)
|
||||
const struct bpf_prog *xdp_prog,
|
||||
void *fwd, enum bpf_map_type map_type,
|
||||
u32 map_id, u32 flags)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
struct bpf_map *map;
|
||||
|
|
@ -4528,7 +4529,8 @@ static int xdp_do_generic_redirect_map(struct net_device *dev,
|
|||
}
|
||||
|
||||
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
|
||||
struct xdp_buff *xdp, struct bpf_prog *xdp_prog)
|
||||
struct xdp_buff *xdp,
|
||||
const struct bpf_prog *xdp_prog)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
enum bpf_map_type map_type = ri->map_type;
|
||||
|
|
@ -9075,7 +9077,8 @@ static bool xdp_is_valid_access(int off, int size,
|
|||
return __is_valid_xdp_access(off, size);
|
||||
}
|
||||
|
||||
void bpf_warn_invalid_xdp_action(struct net_device *dev, struct bpf_prog *prog, u32 act)
|
||||
void bpf_warn_invalid_xdp_action(const struct net_device *dev,
|
||||
const struct bpf_prog *prog, u32 act)
|
||||
{
|
||||
const u32 act_max = XDP_REDIRECT;
|
||||
|
||||
|
|
|
|||
|
|
@ -840,22 +840,22 @@ void page_pool_put_unrefed_page(struct page_pool *pool, struct page *page,
|
|||
EXPORT_SYMBOL(page_pool_put_unrefed_page);
|
||||
|
||||
/**
|
||||
* page_pool_put_page_bulk() - release references on multiple pages
|
||||
* page_pool_put_netmem_bulk() - release references on multiple netmems
|
||||
* @pool: pool from which pages were allocated
|
||||
* @data: array holding page pointers
|
||||
* @count: number of pages in @data
|
||||
* @data: array holding netmem references
|
||||
* @count: number of entries in @data
|
||||
*
|
||||
* Tries to refill a number of pages into the ptr_ring cache holding ptr_ring
|
||||
* producer lock. If the ptr_ring is full, page_pool_put_page_bulk()
|
||||
* will release leftover pages to the page allocator.
|
||||
* page_pool_put_page_bulk() is suitable to be run inside the driver NAPI tx
|
||||
* Tries to refill a number of netmems into the ptr_ring cache holding ptr_ring
|
||||
* producer lock. If the ptr_ring is full, page_pool_put_netmem_bulk()
|
||||
* will release leftover netmems to the memory provider.
|
||||
* page_pool_put_netmem_bulk() is suitable to be run inside the driver NAPI tx
|
||||
* completion loop for the XDP_REDIRECT use case.
|
||||
*
|
||||
* Please note the caller must not use data area after running
|
||||
* page_pool_put_page_bulk(), as this function overwrites it.
|
||||
* page_pool_put_netmem_bulk(), as this function overwrites it.
|
||||
*/
|
||||
void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
||||
int count)
|
||||
void page_pool_put_netmem_bulk(struct page_pool *pool, netmem_ref *data,
|
||||
u32 count)
|
||||
{
|
||||
int i, bulk_len = 0;
|
||||
bool allow_direct;
|
||||
|
|
@ -864,7 +864,7 @@ void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
|||
allow_direct = page_pool_napi_local(pool);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
netmem_ref netmem = page_to_netmem(virt_to_head_page(data[i]));
|
||||
netmem_ref netmem = netmem_compound_head(data[i]);
|
||||
|
||||
/* It is not the last user for the page frag case */
|
||||
if (!page_pool_is_last_ref(netmem))
|
||||
|
|
@ -873,7 +873,7 @@ void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
|||
netmem = __page_pool_put_page(pool, netmem, -1, allow_direct);
|
||||
/* Approved for bulk recycling in ptr_ring cache */
|
||||
if (netmem)
|
||||
data[bulk_len++] = (__force void *)netmem;
|
||||
data[bulk_len++] = netmem;
|
||||
}
|
||||
|
||||
if (!bulk_len)
|
||||
|
|
@ -882,7 +882,7 @@ void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
|||
/* Bulk producer into ptr_ring page_pool cache */
|
||||
in_softirq = page_pool_producer_lock(pool);
|
||||
for (i = 0; i < bulk_len; i++) {
|
||||
if (__ptr_ring_produce(&pool->ring, data[i])) {
|
||||
if (__ptr_ring_produce(&pool->ring, (__force void *)data[i])) {
|
||||
/* ring full */
|
||||
recycle_stat_inc(pool, ring_full);
|
||||
break;
|
||||
|
|
@ -899,9 +899,9 @@ void page_pool_put_page_bulk(struct page_pool *pool, void **data,
|
|||
* since put_page() with refcnt == 1 can be an expensive operation
|
||||
*/
|
||||
for (; i < bulk_len; i++)
|
||||
page_pool_return_page(pool, (__force netmem_ref)data[i]);
|
||||
page_pool_return_page(pool, data[i]);
|
||||
}
|
||||
EXPORT_SYMBOL(page_pool_put_page_bulk);
|
||||
EXPORT_SYMBOL(page_pool_put_netmem_bulk);
|
||||
|
||||
static netmem_ref page_pool_drain_frag(struct page_pool *pool,
|
||||
netmem_ref netmem)
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb,
|
|||
EXPORT_SYMBOL(skb_pp_cow_data);
|
||||
|
||||
int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb,
|
||||
struct bpf_prog *prog)
|
||||
const struct bpf_prog *prog)
|
||||
{
|
||||
if (!prog->aux->xdp_has_frags)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -358,6 +358,9 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq,
|
|||
if (IS_ERR(xdp_alloc))
|
||||
return PTR_ERR(xdp_alloc);
|
||||
|
||||
if (type == MEM_TYPE_XSK_BUFF_POOL && allocator)
|
||||
xsk_pool_set_rxq_info(allocator, xdp_rxq);
|
||||
|
||||
if (trace_mem_connect_enabled() && xdp_alloc)
|
||||
trace_mem_connect(xdp_alloc, xdp_rxq);
|
||||
return 0;
|
||||
|
|
@ -365,6 +368,62 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq,
|
|||
|
||||
EXPORT_SYMBOL_GPL(xdp_rxq_info_reg_mem_model);
|
||||
|
||||
/**
|
||||
* xdp_reg_page_pool - register &page_pool as a memory provider for XDP
|
||||
* @pool: &page_pool to register
|
||||
*
|
||||
* Can be used to register pools manually without connecting to any XDP RxQ
|
||||
* info, so that the XDP layer will be aware of them. Then, they can be
|
||||
* attached to an RxQ info manually via xdp_rxq_info_attach_page_pool().
|
||||
*
|
||||
* Return: %0 on success, -errno on error.
|
||||
*/
|
||||
int xdp_reg_page_pool(struct page_pool *pool)
|
||||
{
|
||||
struct xdp_mem_info mem;
|
||||
|
||||
return xdp_reg_mem_model(&mem, MEM_TYPE_PAGE_POOL, pool);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_reg_page_pool);
|
||||
|
||||
/**
|
||||
* xdp_unreg_page_pool - unregister &page_pool from the memory providers list
|
||||
* @pool: &page_pool to unregister
|
||||
*
|
||||
* A shorthand for manual unregistering page pools. If the pool was previously
|
||||
* attached to an RxQ info, it must be detached first.
|
||||
*/
|
||||
void xdp_unreg_page_pool(const struct page_pool *pool)
|
||||
{
|
||||
struct xdp_mem_info mem = {
|
||||
.type = MEM_TYPE_PAGE_POOL,
|
||||
.id = pool->xdp_mem_id,
|
||||
};
|
||||
|
||||
xdp_unreg_mem_model(&mem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_unreg_page_pool);
|
||||
|
||||
/**
|
||||
* xdp_rxq_info_attach_page_pool - attach registered pool to RxQ info
|
||||
* @xdp_rxq: XDP RxQ info to attach the pool to
|
||||
* @pool: pool to attach
|
||||
*
|
||||
* If the pool was registered manually, this function must be called instead
|
||||
* of xdp_rxq_info_reg_mem_model() to connect it to the RxQ info.
|
||||
*/
|
||||
void xdp_rxq_info_attach_page_pool(struct xdp_rxq_info *xdp_rxq,
|
||||
const struct page_pool *pool)
|
||||
{
|
||||
struct xdp_mem_info mem = {
|
||||
.type = MEM_TYPE_PAGE_POOL,
|
||||
.id = pool->xdp_mem_id,
|
||||
};
|
||||
|
||||
xdp_rxq_info_attach_mem_model(xdp_rxq, &mem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_rxq_info_attach_page_pool);
|
||||
|
||||
/* XDP RX runs under NAPI protection, and in different delivery error
|
||||
* scenarios (e.g. queue full), it is possible to return the xdp_frame
|
||||
* while still leveraging this protection. The @napi_direct boolean
|
||||
|
|
@ -459,7 +518,7 @@ void xdp_flush_frame_bulk(struct xdp_frame_bulk *bq)
|
|||
if (unlikely(!xa || !bq->count))
|
||||
return;
|
||||
|
||||
page_pool_put_page_bulk(xa->page_pool, bq->q, bq->count);
|
||||
page_pool_put_netmem_bulk(xa->page_pool, bq->q, bq->count);
|
||||
/* bq->xa is not cleared to save lookup, if mem.id same in next bulk */
|
||||
bq->count = 0;
|
||||
}
|
||||
|
|
@ -500,12 +559,12 @@ void xdp_return_frame_bulk(struct xdp_frame *xdpf,
|
|||
for (i = 0; i < sinfo->nr_frags; i++) {
|
||||
skb_frag_t *frag = &sinfo->frags[i];
|
||||
|
||||
bq->q[bq->count++] = skb_frag_address(frag);
|
||||
bq->q[bq->count++] = skb_frag_netmem(frag);
|
||||
if (bq->count == XDP_BULK_QUEUE_SIZE)
|
||||
xdp_flush_frame_bulk(bq);
|
||||
}
|
||||
}
|
||||
bq->q[bq->count++] = xdpf->data;
|
||||
bq->q[bq->count++] = virt_to_netmem(xdpf->data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_return_frame_bulk);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user