[Intel-wired-lan] [PATCH 3/3] i40e: Don't reset/rebuild rings on XDP program swap
Björn Töpel
bjorn.topel at gmail.com
Thu Dec 8 17:00:22 UTC 2016
From: Björn Töpel <bjorn.topel at intel.com>
Previously, when swapping from one XDP program to another, a
reset/rebuild rings was triggered. Now, the XDP program is simply
changed without that requirement.
Acked-by: John Fastabend <john.r.fastabend at intel.com>
Signed-off-by: Björn Töpel <bjorn.topel at intel.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 4 +--
drivers/net/ethernet/intel/i40e/i40e_main.c | 41 ++++++++++++++++++-----------
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 25 +++++++++++-------
drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 +-
4 files changed, 44 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index adc1f3f32729..9bc2a8cf5c2e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -549,7 +549,7 @@ struct i40e_vsi {
* regular rings, i.e. alloc_queue_pairs/num_queue_pairs
*/
struct i40e_ring **xdp_rings;
- struct bpf_prog *xdp_prog;
+ bool xdp_enabled;
u32 active_filters;
u32 promisc_threshold;
@@ -920,6 +920,6 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup);
**/
static inline bool i40e_enabled_xdp_vsi(const struct i40e_vsi *vsi)
{
- return vsi->xdp_prog;
+ return vsi->xdp_enabled;
}
#endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 9310a5712ae3..7cac13d1c244 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3116,15 +3116,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
writel(0, ring->tail);
- if (i40e_enabled_xdp_vsi(vsi)) {
- struct bpf_prog *prog;
-
- prog = bpf_prog_add(vsi->xdp_prog, 1);
- if (IS_ERR(prog))
- return PTR_ERR(prog);
- ring->xdp_prog = prog;
- }
-
i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
return 0;
@@ -9428,7 +9419,9 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi,
{
struct i40e_pf *pf = vsi->back;
struct net_device *netdev = vsi->netdev;
- int frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+ int i, frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+ bool need_reset;
+ struct bpf_prog *old_prog;
if (frame_size > I40E_RXBUFFER_2048)
return -EINVAL;
@@ -9439,13 +9432,29 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi,
if (!i40e_enabled_xdp_vsi(vsi) && !prog)
return 0;
- i40e_prep_for_reset(pf);
+ if (prog) {
+ prog = bpf_prog_add(prog, vsi->num_queue_pairs - 1);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+ }
- if (vsi->xdp_prog)
- bpf_prog_put(vsi->xdp_prog);
- vsi->xdp_prog = prog;
+ /* When turning XDP on->off/off->on we reset and rebuild the rings. */
+ need_reset = (i40e_enabled_xdp_vsi(vsi) != !!prog);
- i40e_reset_and_rebuild(pf, true);
+ if (need_reset)
+ i40e_prep_for_reset(pf);
+
+ vsi->xdp_enabled = !!prog;
+
+ if (need_reset)
+ i40e_reset_and_rebuild(pf, true);
+
+ for (i = 0; i < vsi->num_queue_pairs; i++) {
+ old_prog = rtnl_dereference(vsi->rx_rings[i]->xdp_prog);
+ rcu_assign_pointer(vsi->rx_rings[i]->xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+ }
return 0;
}
@@ -11740,7 +11749,9 @@ static void i40e_remove(struct pci_dev *pdev)
pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
}
+ rtnl_lock();
i40e_fdir_teardown(pf);
+ rtnl_unlock();
/* If there is a switch structure or any orphans, remove them.
* This will leave only the PF's VSI remaining.
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index fccdec7ae102..338b4c4c0199 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1112,6 +1112,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
struct device *dev = rx_ring->dev;
unsigned long bi_size;
u16 i;
+ struct bpf_prog *old_prog;
/* ring already cleared, nothing to do */
if (!rx_ring->rx_bi)
@@ -1145,10 +1146,10 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
- if (rx_ring->xdp_prog) {
- bpf_prog_put(rx_ring->xdp_prog);
- rx_ring->xdp_prog = NULL;
- }
+ old_prog = rtnl_dereference(rx_ring->xdp_prog);
+ RCU_INIT_POINTER(rx_ring->xdp_prog, NULL);
+ if (old_prog)
+ bpf_prog_put(old_prog);
}
/**
@@ -1880,6 +1881,7 @@ bool i40e_fetch_rx_buffer(struct i40e_ring *rx_ring,
{
struct i40e_rx_buffer *rx_buffer;
struct page *page;
+ struct bpf_prog *xdp_prog;
rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
page = rx_buffer->page;
@@ -1892,14 +1894,17 @@ bool i40e_fetch_rx_buffer(struct i40e_ring *rx_ring,
I40E_RXBUFFER_2048,
DMA_FROM_DEVICE);
- if (rx_ring->xdp_prog) {
- bool xdp_consumed;
-
- xdp_consumed = i40e_run_xdp(rx_ring, rx_buffer,
- rx_desc, rx_ring->xdp_prog);
- if (xdp_consumed)
+ rcu_read_lock();
+ xdp_prog = rcu_dereference(rx_ring->xdp_prog);
+ if (xdp_prog) {
+ bool xdp_consumed = i40e_run_xdp(rx_ring, rx_buffer,
+ rx_desc, xdp_prog);
+ if (xdp_consumed) {
+ rcu_read_unlock();
return true;
+ }
}
+ rcu_read_unlock();
*skb = rx_buffer->skb;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 4d9459134e69..cfb2c1016242 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -344,7 +344,7 @@ struct i40e_ring {
struct rcu_head rcu; /* to avoid race on free */
u16 next_to_alloc;
- struct bpf_prog *xdp_prog;
+ struct bpf_prog __rcu *xdp_prog;
struct i40e_ring *xdp_sibling; /* rx to xdp, and xdp to rx */
bool xdp_needs_tail_bump;
u16 curr_in_use;
--
2.9.3
More information about the Intel-wired-lan
mailing list