Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xsk: exit NAPI loop when AF_XDP Rx ring is full #6

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
23 changes: 16 additions & 7 deletions drivers/net/ethernet/intel/i40e/i40e_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,15 @@ int i40e_xsk_pool_setup(struct i40e_vsi *vsi, struct xsk_buff_pool *pool,
* i40e_run_xdp_zc - Executes an XDP program on an xdp_buff
* @rx_ring: Rx ring
* @xdp: xdp_buff used as input to the XDP program
* @early_exit: true means that the napi loop should exit early
*
* Returns any of I40E_XDP_{PASS, CONSUMED, TX, REDIR}
**/
static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp, bool *early_exit)
{
int err, result = I40E_XDP_PASS;
struct i40e_ring *xdp_ring;
enum bpf_map_type map_type;
struct bpf_prog *xdp_prog;
u32 act;

Expand All @@ -167,8 +169,13 @@ static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
break;
case XDP_REDIRECT:
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
result = !err ? I40E_XDP_REDIR : I40E_XDP_CONSUMED;
err = xdp_do_redirect_ext(rx_ring->netdev, xdp, xdp_prog, &map_type);
if (err) {
*early_exit = xsk_do_redirect_rx_full(err, map_type);
result = I40E_XDP_CONSUMED;
} else {
result = I40E_XDP_REDIR;
}
break;
default:
bpf_warn_invalid_xdp_action(act);
Expand Down Expand Up @@ -268,8 +275,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
bool early_exit = false, failure = false;
unsigned int xdp_res, xdp_xmit = 0;
bool failure = false;
struct sk_buff *skb;

while (likely(total_rx_packets < (unsigned int)budget)) {
Expand Down Expand Up @@ -316,7 +323,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
(*bi)->data_end = (*bi)->data + size;
xsk_buff_dma_sync_for_cpu(*bi, rx_ring->xsk_pool);

xdp_res = i40e_run_xdp_zc(rx_ring, *bi);
xdp_res = i40e_run_xdp_zc(rx_ring, *bi, &early_exit);
if (xdp_res) {
if (xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR))
xdp_xmit |= xdp_res;
Expand All @@ -329,6 +336,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)

cleaned_count++;
i40e_inc_ntc(rx_ring);
if (early_exit)
break;
continue;
}

Expand Down Expand Up @@ -363,12 +372,12 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets);

if (xsk_uses_need_wakeup(rx_ring->xsk_pool)) {
if (failure || rx_ring->next_to_clean == rx_ring->next_to_use)
if (early_exit || failure || rx_ring->next_to_clean == rx_ring->next_to_use)
xsk_set_rx_need_wakeup(rx_ring->xsk_pool);
else
xsk_clear_rx_need_wakeup(rx_ring->xsk_pool);

return (int)total_rx_packets;
return early_exit ? 0 : (int)total_rx_packets;
}
return failure ? budget : (int)total_rx_packets;
}
Expand Down
23 changes: 16 additions & 7 deletions drivers/net/ethernet/intel/ice/ice_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,13 +502,15 @@ ice_construct_skb_zc(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf)
* ice_run_xdp_zc - Executes an XDP program in zero-copy path
* @rx_ring: Rx ring
* @xdp: xdp_buff used as input to the XDP program
* @early_exit: true means that the napi loop should exit early
*
* Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR}
*/
static int
ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp)
ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp, bool *early_exit)
{
int err, result = ICE_XDP_PASS;
enum bpf_map_type map_type;
struct bpf_prog *xdp_prog;
struct ice_ring *xdp_ring;
u32 act;
Expand All @@ -529,8 +531,13 @@ ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp)
result = ice_xmit_xdp_buff(xdp, xdp_ring);
break;
case XDP_REDIRECT:
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
result = !err ? ICE_XDP_REDIR : ICE_XDP_CONSUMED;
err = xdp_do_redirect_ext(rx_ring->netdev, xdp, xdp_prog, &map_type);
if (err) {
*early_exit = xsk_do_redirect_rx_full(err, map_type);
result = ICE_XDP_CONSUMED;
} else {
result = ICE_XDP_REDIR;
}
break;
default:
bpf_warn_invalid_xdp_action(act);
Expand Down Expand Up @@ -558,8 +565,8 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
u16 cleaned_count = ICE_DESC_UNUSED(rx_ring);
bool early_exit = false, failure = false;
unsigned int xdp_xmit = 0;
bool failure = false;

while (likely(total_rx_packets < (unsigned int)budget)) {
union ice_32b_rx_flex_desc *rx_desc;
Expand Down Expand Up @@ -597,7 +604,7 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget)
rx_buf->xdp->data_end = rx_buf->xdp->data + size;
xsk_buff_dma_sync_for_cpu(rx_buf->xdp, rx_ring->xsk_pool);

xdp_res = ice_run_xdp_zc(rx_ring, rx_buf->xdp);
xdp_res = ice_run_xdp_zc(rx_ring, rx_buf->xdp, &early_exit);
if (xdp_res) {
if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR))
xdp_xmit |= xdp_res;
Expand All @@ -610,6 +617,8 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget)
cleaned_count++;

ice_bump_ntc(rx_ring);
if (early_exit)
break;
continue;
}

Expand Down Expand Up @@ -646,12 +655,12 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget)
ice_update_rx_ring_stats(rx_ring, total_rx_packets, total_rx_bytes);

if (xsk_uses_need_wakeup(rx_ring->xsk_pool)) {
if (failure || rx_ring->next_to_clean == rx_ring->next_to_use)
if (early_exit || failure || rx_ring->next_to_clean == rx_ring->next_to_use)
xsk_set_rx_need_wakeup(rx_ring->xsk_pool);
else
xsk_clear_rx_need_wakeup(rx_ring->xsk_pool);

return (int)total_rx_packets;
return early_exit ? 0 : (int)total_rx_packets;
}

return failure ? budget : (int)total_rx_packets;
Expand Down
23 changes: 16 additions & 7 deletions drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ int ixgbe_xsk_pool_setup(struct ixgbe_adapter *adapter,

static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter,
struct ixgbe_ring *rx_ring,
struct xdp_buff *xdp)
struct xdp_buff *xdp,
bool *early_exit)
{
int err, result = IXGBE_XDP_PASS;
enum bpf_map_type map_type;
struct bpf_prog *xdp_prog;
struct xdp_frame *xdpf;
u32 act;
Expand All @@ -116,8 +118,13 @@ static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter,
result = ixgbe_xmit_xdp_ring(adapter, xdpf);
break;
case XDP_REDIRECT:
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
result = !err ? IXGBE_XDP_REDIR : IXGBE_XDP_CONSUMED;
err = xdp_do_redirect_ext(rx_ring->netdev, xdp, xdp_prog, &map_type);
if (err) {
*early_exit = xsk_do_redirect_rx_full(err, map_type);
result = IXGBE_XDP_CONSUMED;
} else {
result = IXGBE_XDP_REDIR;
}
break;
default:
bpf_warn_invalid_xdp_action(act);
Expand Down Expand Up @@ -235,8 +242,8 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
struct ixgbe_adapter *adapter = q_vector->adapter;
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
bool early_exit = false, failure = false;
unsigned int xdp_res, xdp_xmit = 0;
bool failure = false;
struct sk_buff *skb;

while (likely(total_rx_packets < budget)) {
Expand Down Expand Up @@ -288,7 +295,7 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,

bi->xdp->data_end = bi->xdp->data + size;
xsk_buff_dma_sync_for_cpu(bi->xdp, rx_ring->xsk_pool);
xdp_res = ixgbe_run_xdp_zc(adapter, rx_ring, bi->xdp);
xdp_res = ixgbe_run_xdp_zc(adapter, rx_ring, bi->xdp, &early_exit);

if (xdp_res) {
if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR))
Expand All @@ -302,6 +309,8 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,

cleaned_count++;
ixgbe_inc_ntc(rx_ring);
if (early_exit)
break;
continue;
}

Expand Down Expand Up @@ -346,12 +355,12 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,
q_vector->rx.total_bytes += total_rx_bytes;

if (xsk_uses_need_wakeup(rx_ring->xsk_pool)) {
if (failure || rx_ring->next_to_clean == rx_ring->next_to_use)
if (early_exit || failure || rx_ring->next_to_clean == rx_ring->next_to_use)
xsk_set_rx_need_wakeup(rx_ring->xsk_pool);
else
xsk_clear_rx_need_wakeup(rx_ring->xsk_pool);

return (int)total_rx_packets;
return early_exit ? 0 : (int)total_rx_packets;
}
return failure ? budget : (int)total_rx_packets;
}
Expand Down
2 changes: 2 additions & 0 deletions include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,8 @@ static inline int xdp_ok_fwd_dev(const struct net_device *fwd,
*/
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
struct xdp_buff *xdp, struct bpf_prog *prog);
int xdp_do_redirect_ext(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog, enum bpf_map_type *map_type);
int xdp_do_redirect(struct net_device *dev,
struct xdp_buff *xdp,
struct bpf_prog *prog);
Expand Down
9 changes: 9 additions & 0 deletions include/net/xdp_sock_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ static inline void xsk_buff_raw_dma_sync_for_device(struct xsk_buff_pool *pool,
xp_dma_sync_for_device(pool, dma, size);
}

static inline bool xsk_do_redirect_rx_full(int err, enum bpf_map_type map_type)
{
return err == -ENOBUFS && map_type == BPF_MAP_TYPE_XSKMAP;
}

#else

static inline void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
Expand Down Expand Up @@ -235,6 +240,10 @@ static inline void xsk_buff_raw_dma_sync_for_device(struct xsk_buff_pool *pool,
{
}

static inline bool xsk_do_redirect_rx_full(int err, enum bpf_map_type map_type)
{
return false;
}
#endif /* CONFIG_XDP_SOCKETS */

#endif /* _LINUX_XDP_SOCK_DRV_H */
16 changes: 14 additions & 2 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3596,8 +3596,8 @@ void bpf_clear_redirect_map(struct bpf_map *map)
}
}

int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog)
int xdp_do_redirect_ext(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog, enum bpf_map_type *map_type)
{
struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
struct bpf_map *map = READ_ONCE(ri->map);
Expand All @@ -3609,6 +3609,8 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
ri->tgt_value = NULL;
WRITE_ONCE(ri->map, NULL);

*map_type = BPF_MAP_TYPE_UNSPEC;

if (unlikely(!map)) {
fwd = dev_get_by_index_rcu(dev_net(dev), index);
if (unlikely(!fwd)) {
Expand All @@ -3618,6 +3620,7 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,

err = dev_xdp_enqueue(fwd, xdp, dev);
} else {
*map_type = map->map_type;
err = __bpf_tx_xdp_map(dev, fwd, map, xdp);
}

Expand All @@ -3630,6 +3633,15 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
_trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
return err;
}
EXPORT_SYMBOL_GPL(xdp_do_redirect_ext);

int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog)
{
enum bpf_map_type dummy;

return xdp_do_redirect_ext(dev, xdp, xdp_prog, &dummy);
}
EXPORT_SYMBOL_GPL(xdp_do_redirect);

static int xdp_do_generic_redirect_map(struct net_device *dev,
Expand Down
2 changes: 1 addition & 1 deletion net/xdp/xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len,
xsk_xdp = xsk_buff_alloc(xs->pool);
if (!xsk_xdp) {
xs->rx_dropped++;
return -ENOSPC;
return -ENOMEM;
}

xsk_copy_xdp(xsk_xdp, xdp, len);
Expand Down
2 changes: 1 addition & 1 deletion net/xdp/xsk_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ static inline int xskq_prod_reserve_desc(struct xsk_queue *q,
u32 idx;

if (xskq_prod_is_full(q))
return -ENOSPC;
return -ENOBUFS;

/* A, matches D */
idx = q->cached_prod++ & q->ring_mask;
Expand Down
Loading