* [PATCH net-next 1/6] tsnep: Add adapter down state
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 2/6] tsnep: Add XDP TX support Gerhard Engleder
` (4 subsequent siblings)
5 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
Add adapter state with flag for down state. This flag will be used by
the XDP TX path to deny TX if adapter is down.
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/tsnep.h | 1 +
drivers/net/ethernet/engleder/tsnep_main.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/net/ethernet/engleder/tsnep.h b/drivers/net/ethernet/engleder/tsnep.h
index f93ba48bac3f..f72c0c4da1a9 100644
--- a/drivers/net/ethernet/engleder/tsnep.h
+++ b/drivers/net/ethernet/engleder/tsnep.h
@@ -148,6 +148,7 @@ struct tsnep_adapter {
phy_interface_t phy_mode;
struct phy_device *phydev;
int msg_enable;
+ unsigned long state;
struct platform_device *pdev;
struct device *dmadev;
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index bf0190e1d2ea..a28fde9fb060 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -43,6 +43,10 @@
#define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \
ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1)
+enum {
+ __TSNEP_DOWN,
+};
+
static void tsnep_enable_irq(struct tsnep_adapter *adapter, u32 mask)
{
iowrite32(mask, adapter->addr + ECM_INT_ENABLE);
@@ -1143,6 +1147,8 @@ static int tsnep_netdev_open(struct net_device *netdev)
tsnep_enable_irq(adapter, adapter->queue[i].irq_mask);
}
+ clear_bit(__TSNEP_DOWN, &adapter->state);
+
return 0;
phy_failed:
@@ -1165,6 +1171,8 @@ static int tsnep_netdev_close(struct net_device *netdev)
struct tsnep_adapter *adapter = netdev_priv(netdev);
int i;
+ set_bit(__TSNEP_DOWN, &adapter->state);
+
tsnep_disable_irq(adapter, ECM_INT_LINK);
tsnep_phy_close(adapter);
@@ -1518,6 +1526,7 @@ static int tsnep_probe(struct platform_device *pdev)
adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
+ set_bit(__TSNEP_DOWN, &adapter->state);
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = TSNEP_MAX_FRAME_SIZE;
@@ -1614,6 +1623,8 @@ static int tsnep_remove(struct platform_device *pdev)
{
struct tsnep_adapter *adapter = platform_get_drvdata(pdev);
+ set_bit(__TSNEP_DOWN, &adapter->state);
+
unregister_netdev(adapter->netdev);
tsnep_rxnfc_cleanup(adapter);
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next 2/6] tsnep: Add XDP TX support
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 1/6] tsnep: Add adapter down state Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-07 10:24 ` Paolo Abeni
2022-12-07 10:26 ` Paolo Abeni
2022-12-03 21:54 ` [PATCH net-next 3/6] tsnep: Support XDP BPF program setup Gerhard Engleder
` (3 subsequent siblings)
5 siblings, 2 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
Implement ndo_xdp_xmit() for XDP TX support. Support for fragmented XDP
frames is included.
For complete TX support tsnep_xdp_xmit_back() is already added, which is
used later by the XDP RX path if BPF programs return XDP_TX.
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/tsnep.h | 12 +-
drivers/net/ethernet/engleder/tsnep_main.c | 231 ++++++++++++++++++++-
2 files changed, 234 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/engleder/tsnep.h b/drivers/net/ethernet/engleder/tsnep.h
index f72c0c4da1a9..29b04127f529 100644
--- a/drivers/net/ethernet/engleder/tsnep.h
+++ b/drivers/net/ethernet/engleder/tsnep.h
@@ -57,6 +57,12 @@ struct tsnep_rxnfc_rule {
int location;
};
+enum tsnep_tx_type {
+ TSNEP_TX_TYPE_SKB,
+ TSNEP_TX_TYPE_XDP_TX,
+ TSNEP_TX_TYPE_XDP_NDO,
+};
+
struct tsnep_tx_entry {
struct tsnep_tx_desc *desc;
struct tsnep_tx_desc_wb *desc_wb;
@@ -65,7 +71,11 @@ struct tsnep_tx_entry {
u32 properties;
- struct sk_buff *skb;
+ enum tsnep_tx_type type;
+ union {
+ struct sk_buff *skb;
+ struct xdp_frame *xdpf;
+ };
size_t len;
DEFINE_DMA_UNMAP_ADDR(dma);
};
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index a28fde9fb060..5b52c8005c20 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -310,10 +310,11 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length,
struct tsnep_tx_entry *entry = &tx->entry[index];
entry->properties = 0;
- if (entry->skb) {
+ if (entry->skb || entry->xdpf) {
entry->properties = length & TSNEP_DESC_LENGTH_MASK;
entry->properties |= TSNEP_DESC_INTERRUPT_FLAG;
- if (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS)
+ if (entry->type == TSNEP_TX_TYPE_SKB &&
+ skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS)
entry->properties |= TSNEP_DESC_EXTENDED_WRITEBACK_FLAG;
/* toggle user flag to prevent false acknowledge
@@ -400,6 +401,8 @@ static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count)
entry->desc->tx = __cpu_to_le64(dma);
+ entry->type = TSNEP_TX_TYPE_SKB;
+
map_len += len;
}
@@ -417,12 +420,13 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count)
entry = &tx->entry[(index + i) % TSNEP_RING_SIZE];
if (entry->len) {
- if (i == 0)
+ if (i == 0 && entry->type == TSNEP_TX_TYPE_SKB)
dma_unmap_single(dmadev,
dma_unmap_addr(entry, dma),
dma_unmap_len(entry, len),
DMA_TO_DEVICE);
- else
+ else if (entry->type == TSNEP_TX_TYPE_SKB ||
+ entry->type == TSNEP_TX_TYPE_XDP_NDO)
dma_unmap_page(dmadev,
dma_unmap_addr(entry, dma),
dma_unmap_len(entry, len),
@@ -505,6 +509,149 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+static int tsnep_xdp_tx_map(struct xdp_frame *xdpf, struct tsnep_tx *tx,
+ struct skb_shared_info *shinfo, int count,
+ bool dma_map)
+{
+ struct device *dmadev = tx->adapter->dmadev;
+ skb_frag_t *frag;
+ unsigned int len;
+ struct tsnep_tx_entry *entry;
+ void *data;
+ struct page *page;
+ dma_addr_t dma;
+ int map_len = 0;
+ int i;
+
+ frag = NULL;
+ len = xdpf->len;
+ for (i = 0; i < count; i++) {
+ entry = &tx->entry[(tx->write + i) % TSNEP_RING_SIZE];
+ if (dma_map) {
+ data = unlikely(frag) ? skb_frag_address(frag) :
+ xdpf->data;
+ dma = dma_map_single(dmadev, data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dmadev, dma))
+ return -ENOMEM;
+
+ entry->type = TSNEP_TX_TYPE_XDP_NDO;
+ } else {
+ page = unlikely(frag) ? skb_frag_page(frag) :
+ virt_to_page(xdpf->data);
+ dma = page_pool_get_dma_addr(page);
+ if (unlikely(frag))
+ dma += skb_frag_off(frag);
+ else
+ dma += sizeof(*xdpf) + xdpf->headroom;
+ dma_sync_single_for_device(dmadev, dma, len,
+ DMA_BIDIRECTIONAL);
+
+ entry->type = TSNEP_TX_TYPE_XDP_TX;
+ }
+
+ entry->len = len;
+ dma_unmap_addr_set(entry, dma, dma);
+
+ entry->desc->tx = __cpu_to_le64(dma);
+
+ map_len += len;
+
+ if ((i + 1) < count) {
+ frag = &shinfo->frags[i];
+ len = skb_frag_size(frag);
+ }
+ }
+
+ return map_len;
+}
+
+/* This function requires __netif_tx_lock is held by the caller. */
+static int tsnep_xdp_xmit_frame_ring(struct xdp_frame *xdpf,
+ struct tsnep_tx *tx, bool dma_map)
+{
+ struct skb_shared_info *shinfo = xdp_get_shared_info_from_frame(xdpf);
+ unsigned long flags;
+ int count = 1;
+ struct tsnep_tx_entry *entry;
+ int length;
+ int i;
+ int retval;
+
+ if (unlikely(xdp_frame_has_frags(xdpf)))
+ count += shinfo->nr_frags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (tsnep_tx_desc_available(tx) < (MAX_SKB_FRAGS + 1 + count)) {
+ /* prevent full TX ring due to XDP */
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ return -EBUSY;
+ }
+
+ entry = &tx->entry[tx->write];
+ entry->xdpf = xdpf;
+
+ retval = tsnep_xdp_tx_map(xdpf, tx, shinfo, count, dma_map);
+ if (retval < 0) {
+ tsnep_tx_unmap(tx, tx->write, count);
+ entry->xdpf = NULL;
+
+ tx->dropped++;
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ netdev_err(tx->adapter->netdev, "XDP TX DMA map failed\n");
+
+ return retval;
+ }
+ length = retval;
+
+ for (i = 0; i < count; i++)
+ tsnep_tx_activate(tx, (tx->write + i) % TSNEP_RING_SIZE, length,
+ i == (count - 1));
+ tx->write = (tx->write + count) % TSNEP_RING_SIZE;
+
+ /* descriptor properties shall be valid before hardware is notified */
+ dma_wmb();
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ return 0;
+}
+
+static void tsnep_xdp_xmit_flush(struct tsnep_tx *tx)
+{
+ iowrite32(TSNEP_CONTROL_TX_ENABLE, tx->addr + TSNEP_CONTROL);
+}
+
+static int tsnep_xdp_xmit_back(struct tsnep_adapter *adapter,
+ struct xdp_buff *xdp)
+{
+ struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
+ int cpu = smp_processor_id();
+ int queue;
+ struct netdev_queue *nq;
+ int retval;
+
+ if (unlikely(!xdpf))
+ return -EFAULT;
+
+ queue = cpu % adapter->num_tx_queues;
+ nq = netdev_get_tx_queue(adapter->netdev, queue);
+
+ __netif_tx_lock(nq, cpu);
+
+ /* Avoid transmit queue timeout since we share it with the slow path */
+ txq_trans_cond_update(nq);
+
+ retval = tsnep_xdp_xmit_frame_ring(xdpf, &adapter->tx[queue], false);
+
+ __netif_tx_unlock(nq);
+
+ return retval;
+}
+
static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
{
unsigned long flags;
@@ -512,6 +659,11 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
struct tsnep_tx_entry *entry;
int count;
int length;
+ struct xdp_frame_bulk bq;
+
+ xdp_frame_bulk_init(&bq);
+
+ rcu_read_lock(); /* need for xdp_return_frame_bulk */
spin_lock_irqsave(&tx->lock, flags);
@@ -531,12 +683,17 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
dma_rmb();
count = 1;
- if (skb_shinfo(entry->skb)->nr_frags > 0)
+ if (entry->type == TSNEP_TX_TYPE_SKB &&
+ skb_shinfo(entry->skb)->nr_frags > 0)
count += skb_shinfo(entry->skb)->nr_frags;
+ else if (entry->type != TSNEP_TX_TYPE_SKB &&
+ xdp_frame_has_frags(entry->xdpf))
+ count += xdp_get_shared_info_from_frame(entry->xdpf)->nr_frags;
length = tsnep_tx_unmap(tx, tx->read, count);
- if ((skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS) &&
+ if (entry->type == TSNEP_TX_TYPE_SKB &&
+ (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS) &&
(__le32_to_cpu(entry->desc_wb->properties) &
TSNEP_DESC_EXTENDED_WRITEBACK_FLAG)) {
struct skb_shared_hwtstamps hwtstamps;
@@ -556,8 +713,20 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
skb_tstamp_tx(entry->skb, &hwtstamps);
}
- napi_consume_skb(entry->skb, budget);
- entry->skb = NULL;
+ switch (entry->type) {
+ case TSNEP_TX_TYPE_SKB:
+ napi_consume_skb(entry->skb, budget);
+ entry->skb = NULL;
+ break;
+ case TSNEP_TX_TYPE_XDP_TX:
+ xdp_return_frame_rx_napi(entry->xdpf);
+ entry->xdpf = NULL;
+ break;
+ case TSNEP_TX_TYPE_XDP_NDO:
+ xdp_return_frame_bulk(entry->xdpf, &bq);
+ entry->xdpf = NULL;
+ break;
+ }
tx->read = (tx->read + count) % TSNEP_RING_SIZE;
@@ -574,6 +743,10 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
spin_unlock_irqrestore(&tx->lock, flags);
+ xdp_flush_frame_bulk(&bq);
+
+ rcu_read_unlock();
+
return (budget != 0);
}
@@ -1335,6 +1508,47 @@ static ktime_t tsnep_netdev_get_tstamp(struct net_device *netdev,
return ns_to_ktime(timestamp);
}
+static int tsnep_netdev_xdp_xmit(struct net_device *dev, int n,
+ struct xdp_frame **xdp, u32 flags)
+{
+ struct tsnep_adapter *adapter = netdev_priv(dev);
+ int cpu = smp_processor_id();
+ int queue;
+ struct netdev_queue *nq;
+ int nxmit = 0;
+ int i;
+ int retval;
+
+ if (unlikely(test_bit(__TSNEP_DOWN, &adapter->state)))
+ return -ENETDOWN;
+
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+ return -EINVAL;
+
+ queue = cpu % adapter->num_tx_queues;
+ nq = netdev_get_tx_queue(adapter->netdev, queue);
+
+ __netif_tx_lock(nq, cpu);
+
+ /* Avoid transmit queue timeout since we share it with the slow path */
+ txq_trans_cond_update(nq);
+
+ for (i = 0; i < n; i++) {
+ retval = tsnep_xdp_xmit_frame_ring(xdp[i], &adapter->tx[queue], true);
+ if (retval)
+ break;
+
+ nxmit++;
+ }
+
+ if (flags & XDP_XMIT_FLUSH)
+ tsnep_xdp_xmit_flush(&adapter->tx[queue]);
+
+ __netif_tx_unlock(nq);
+
+ return nxmit;
+}
+
static const struct net_device_ops tsnep_netdev_ops = {
.ndo_open = tsnep_netdev_open,
.ndo_stop = tsnep_netdev_close,
@@ -1346,6 +1560,7 @@ static const struct net_device_ops tsnep_netdev_ops = {
.ndo_set_features = tsnep_netdev_set_features,
.ndo_get_tstamp = tsnep_netdev_get_tstamp,
.ndo_setup_tc = tsnep_tc_setup,
+ .ndo_xdp_xmit = tsnep_netdev_xdp_xmit,
};
static int tsnep_mac_init(struct tsnep_adapter *adapter)
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH net-next 2/6] tsnep: Add XDP TX support
2022-12-03 21:54 ` [PATCH net-next 2/6] tsnep: Add XDP TX support Gerhard Engleder
@ 2022-12-07 10:24 ` Paolo Abeni
2022-12-07 20:05 ` Gerhard Engleder
2022-12-07 10:26 ` Paolo Abeni
1 sibling, 1 reply; 15+ messages in thread
From: Paolo Abeni @ 2022-12-07 10:24 UTC (permalink / raw)
To: Gerhard Engleder, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
[...]
> +/* This function requires __netif_tx_lock is held by the caller. */
> +static int tsnep_xdp_xmit_frame_ring(struct xdp_frame *xdpf,
> + struct tsnep_tx *tx, bool dma_map)
> +{
> + struct skb_shared_info *shinfo = xdp_get_shared_info_from_frame(xdpf);
> + unsigned long flags;
> + int count = 1;
> + struct tsnep_tx_entry *entry;
> + int length;
> + int i;
> + int retval;
> +
> + if (unlikely(xdp_frame_has_frags(xdpf)))
> + count += shinfo->nr_frags;
> +
> + spin_lock_irqsave(&tx->lock, flags);
Not strictily related to this patch, but why are you using the _irqsafe
variant? it looks like all the locak users are either in process or BH
context.
Thanks!
Paolo
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH net-next 2/6] tsnep: Add XDP TX support
2022-12-07 10:24 ` Paolo Abeni
@ 2022-12-07 20:05 ` Gerhard Engleder
0 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-07 20:05 UTC (permalink / raw)
To: Paolo Abeni, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On 07.12.22 11:24, Paolo Abeni wrote:
> On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
> [...]
>> +/* This function requires __netif_tx_lock is held by the caller. */
>> +static int tsnep_xdp_xmit_frame_ring(struct xdp_frame *xdpf,
>> + struct tsnep_tx *tx, bool dma_map)
>> +{
>> + struct skb_shared_info *shinfo = xdp_get_shared_info_from_frame(xdpf);
>> + unsigned long flags;
>> + int count = 1;
>> + struct tsnep_tx_entry *entry;
>> + int length;
>> + int i;
>> + int retval;
>> +
>> + if (unlikely(xdp_frame_has_frags(xdpf)))
>> + count += shinfo->nr_frags;
>> +
>> + spin_lock_irqsave(&tx->lock, flags);
>
> Not strictily related to this patch, but why are you using the _irqsafe
> variant? it looks like all the locak users are either in process or BH
> context.
You are right. I will check that and would post a patch later.
Thank you!
Gerhard
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 2/6] tsnep: Add XDP TX support
2022-12-03 21:54 ` [PATCH net-next 2/6] tsnep: Add XDP TX support Gerhard Engleder
2022-12-07 10:24 ` Paolo Abeni
@ 2022-12-07 10:26 ` Paolo Abeni
2022-12-07 20:06 ` Gerhard Engleder
1 sibling, 1 reply; 15+ messages in thread
From: Paolo Abeni @ 2022-12-07 10:26 UTC (permalink / raw)
To: Gerhard Engleder, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
> For complete TX support tsnep_xdp_xmit_back() is already added, which is
> used later by the XDP RX path if BPF programs return XDP_TX.
Oops, I almost forgot... It's better to introduce tsnep_xdp_xmit_back()
in the patch using it: this patch introduces a build warning fixed by
the later patch, and we want to avoid it.
Cheers,
Paolo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH net-next 2/6] tsnep: Add XDP TX support
2022-12-07 10:26 ` Paolo Abeni
@ 2022-12-07 20:06 ` Gerhard Engleder
0 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-07 20:06 UTC (permalink / raw)
To: Paolo Abeni, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On 07.12.22 11:26, Paolo Abeni wrote:
> On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
>> For complete TX support tsnep_xdp_xmit_back() is already added, which is
>> used later by the XDP RX path if BPF programs return XDP_TX.
>
> Oops, I almost forgot... It's better to introduce tsnep_xdp_xmit_back()
> in the patch using it: this patch introduces a build warning fixed by
> the later patch, and we want to avoid it.
Ok, I will move tsnep_xdp_xmit_back() to the RX patch.
Gerhard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH net-next 3/6] tsnep: Support XDP BPF program setup
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 1/6] tsnep: Add adapter down state Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 2/6] tsnep: Add XDP TX support Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support Gerhard Engleder
` (2 subsequent siblings)
5 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
Implement setup of BPF programs for XDP RX path with command
XDP_SETUP_PROG of ndo_bpf(). This is prework for XDP RX path support.
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/Makefile | 2 +-
drivers/net/ethernet/engleder/tsnep.h | 13 +++++++++++
drivers/net/ethernet/engleder/tsnep_main.c | 17 ++++++++++++--
drivers/net/ethernet/engleder/tsnep_xdp.c | 27 ++++++++++++++++++++++
4 files changed, 56 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/engleder/tsnep_xdp.c
diff --git a/drivers/net/ethernet/engleder/Makefile b/drivers/net/ethernet/engleder/Makefile
index b6e3b16623de..0901801cfcc9 100644
--- a/drivers/net/ethernet/engleder/Makefile
+++ b/drivers/net/ethernet/engleder/Makefile
@@ -6,5 +6,5 @@
obj-$(CONFIG_TSNEP) += tsnep.o
tsnep-objs := tsnep_main.o tsnep_ethtool.o tsnep_ptp.o tsnep_tc.o \
- tsnep_rxnfc.o $(tsnep-y)
+ tsnep_rxnfc.o tsnep_xdp.o $(tsnep-y)
tsnep-$(CONFIG_TSNEP_SELFTESTS) += tsnep_selftests.o
diff --git a/drivers/net/ethernet/engleder/tsnep.h b/drivers/net/ethernet/engleder/tsnep.h
index 29b04127f529..0e7fc36a64e1 100644
--- a/drivers/net/ethernet/engleder/tsnep.h
+++ b/drivers/net/ethernet/engleder/tsnep.h
@@ -183,6 +183,8 @@ struct tsnep_adapter {
int rxnfc_count;
int rxnfc_max;
+ struct bpf_prog *xdp_prog;
+
int num_tx_queues;
struct tsnep_tx tx[TSNEP_MAX_QUEUES];
int num_rx_queues;
@@ -192,6 +194,9 @@ struct tsnep_adapter {
struct tsnep_queue queue[TSNEP_MAX_QUEUES];
};
+int tsnep_netdev_open(struct net_device *netdev);
+int tsnep_netdev_close(struct net_device *netdev);
+
extern const struct ethtool_ops tsnep_ethtool_ops;
int tsnep_ptp_init(struct tsnep_adapter *adapter);
@@ -215,6 +220,14 @@ int tsnep_rxnfc_add_rule(struct tsnep_adapter *adapter,
int tsnep_rxnfc_del_rule(struct tsnep_adapter *adapter,
struct ethtool_rxnfc *cmd);
+int tsnep_xdp_setup_prog(struct tsnep_adapter *adapter, struct bpf_prog *prog,
+ struct netlink_ext_ack *extack);
+
+static inline bool tsnep_xdp_is_enabled(struct tsnep_adapter *adapter)
+{
+ return !!adapter->xdp_prog;
+}
+
#if IS_ENABLED(CONFIG_TSNEP_SELFTESTS)
int tsnep_ethtool_get_test_count(void);
void tsnep_ethtool_get_test_strings(u8 *data);
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index 5b52c8005c20..d9ba4a8deec5 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -1260,7 +1260,7 @@ static void tsnep_free_irq(struct tsnep_queue *queue, bool first)
memset(queue->name, 0, sizeof(queue->name));
}
-static int tsnep_netdev_open(struct net_device *netdev)
+int tsnep_netdev_open(struct net_device *netdev)
{
struct tsnep_adapter *adapter = netdev_priv(netdev);
int i;
@@ -1339,7 +1339,7 @@ static int tsnep_netdev_open(struct net_device *netdev)
return retval;
}
-static int tsnep_netdev_close(struct net_device *netdev)
+int tsnep_netdev_close(struct net_device *netdev)
{
struct tsnep_adapter *adapter = netdev_priv(netdev);
int i;
@@ -1508,6 +1508,18 @@ static ktime_t tsnep_netdev_get_tstamp(struct net_device *netdev,
return ns_to_ktime(timestamp);
}
+static int tsnep_netdev_bpf(struct net_device *dev, struct netdev_bpf *bpf)
+{
+ struct tsnep_adapter *adapter = netdev_priv(dev);
+
+ switch (bpf->command) {
+ case XDP_SETUP_PROG:
+ return tsnep_xdp_setup_prog(adapter, bpf->prog, bpf->extack);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int tsnep_netdev_xdp_xmit(struct net_device *dev, int n,
struct xdp_frame **xdp, u32 flags)
{
@@ -1560,6 +1572,7 @@ static const struct net_device_ops tsnep_netdev_ops = {
.ndo_set_features = tsnep_netdev_set_features,
.ndo_get_tstamp = tsnep_netdev_get_tstamp,
.ndo_setup_tc = tsnep_tc_setup,
+ .ndo_bpf = tsnep_netdev_bpf,
.ndo_xdp_xmit = tsnep_netdev_xdp_xmit,
};
diff --git a/drivers/net/ethernet/engleder/tsnep_xdp.c b/drivers/net/ethernet/engleder/tsnep_xdp.c
new file mode 100644
index 000000000000..02d84dfbdde4
--- /dev/null
+++ b/drivers/net/ethernet/engleder/tsnep_xdp.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2022 Gerhard Engleder <gerhard@engleder-embedded.com> */
+
+#include <linux/if_vlan.h>
+#include <net/xdp_sock_drv.h>
+
+#include "tsnep.h"
+
+int tsnep_xdp_setup_prog(struct tsnep_adapter *adapter, struct bpf_prog *prog,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = adapter->netdev;
+ bool if_running = netif_running(dev);
+ struct bpf_prog *old_prog;
+
+ if (if_running)
+ tsnep_netdev_close(dev);
+
+ old_prog = xchg(&adapter->xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+
+ if (if_running)
+ tsnep_netdev_open(dev);
+
+ return 0;
+}
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
` (2 preceding siblings ...)
2022-12-03 21:54 ` [PATCH net-next 3/6] tsnep: Support XDP BPF program setup Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-07 10:29 ` Paolo Abeni
2022-12-03 21:54 ` [PATCH net-next 5/6] tsnep: Add RX queue info " Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 6/6] tsnep: Add XDP RX support Gerhard Engleder
5 siblings, 1 reply; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
Reserve XDP_PACKET_HEADROOM in front of RX buffer if XDP is enabled.
Also set DMA direction properly in this case.
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/tsnep_main.c | 31 +++++++++++++++-------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index d9ba4a8deec5..d7dcac641180 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -26,9 +26,10 @@
#include <linux/etherdevice.h>
#include <linux/phy.h>
#include <linux/iopoll.h>
+#include <linux/bpf.h>
#define TSNEP_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
-#define TSNEP_HEADROOM ALIGN(TSNEP_SKB_PAD, 4)
+#define TSNEP_HEADROOM ALIGN(max(TSNEP_SKB_PAD, XDP_PACKET_HEADROOM), 4)
#define TSNEP_MAX_RX_BUF_SIZE (PAGE_SIZE - TSNEP_HEADROOM - \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
@@ -808,6 +809,16 @@ static void tsnep_tx_close(struct tsnep_tx *tx)
tsnep_tx_ring_cleanup(tx);
}
+static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
+{
+ struct tsnep_adapter *adapter = rx->adapter;
+
+ if (tsnep_xdp_is_enabled(adapter))
+ return XDP_PACKET_HEADROOM;
+
+ return TSNEP_SKB_PAD;
+}
+
static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
{
struct device *dmadev = rx->adapter->dmadev;
@@ -869,9 +880,10 @@ static int tsnep_rx_ring_init(struct tsnep_rx *rx)
pp_params.pool_size = TSNEP_RING_SIZE;
pp_params.nid = dev_to_node(dmadev);
pp_params.dev = dmadev;
- pp_params.dma_dir = DMA_FROM_DEVICE;
+ pp_params.dma_dir = tsnep_xdp_is_enabled(rx->adapter) ?
+ DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
pp_params.max_len = TSNEP_MAX_RX_BUF_SIZE;
- pp_params.offset = TSNEP_SKB_PAD;
+ pp_params.offset = tsnep_rx_offset(rx);
rx->page_pool = page_pool_create(&pp_params);
if (IS_ERR(rx->page_pool)) {
retval = PTR_ERR(rx->page_pool);
@@ -906,7 +918,7 @@ static void tsnep_rx_set_page(struct tsnep_rx *rx, struct tsnep_rx_entry *entry,
entry->page = page;
entry->len = TSNEP_MAX_RX_BUF_SIZE;
entry->dma = page_pool_get_dma_addr(entry->page);
- entry->desc->rx = __cpu_to_le64(entry->dma + TSNEP_SKB_PAD);
+ entry->desc->rx = __cpu_to_le64(entry->dma + tsnep_rx_offset(rx));
}
static int tsnep_rx_alloc_buffer(struct tsnep_rx *rx, int index)
@@ -1010,14 +1022,14 @@ static struct sk_buff *tsnep_build_skb(struct tsnep_rx *rx, struct page *page,
return NULL;
/* update pointers within the skb to store the data */
- skb_reserve(skb, TSNEP_SKB_PAD + TSNEP_RX_INLINE_METADATA_SIZE);
+ skb_reserve(skb, tsnep_rx_offset(rx) + TSNEP_RX_INLINE_METADATA_SIZE);
__skb_put(skb, length - TSNEP_RX_INLINE_METADATA_SIZE - ETH_FCS_LEN);
if (rx->adapter->hwtstamp_config.rx_filter == HWTSTAMP_FILTER_ALL) {
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
struct tsnep_rx_inline *rx_inline =
(struct tsnep_rx_inline *)(page_address(page) +
- TSNEP_SKB_PAD);
+ tsnep_rx_offset(rx));
skb_shinfo(skb)->tx_flags |=
SKBTX_HW_TSTAMP_NETDEV;
@@ -1077,11 +1089,12 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
*/
dma_rmb();
- prefetch(page_address(entry->page) + TSNEP_SKB_PAD);
+ prefetch(page_address(entry->page) + tsnep_rx_offset(rx));
length = __le32_to_cpu(entry->desc_wb->properties) &
TSNEP_DESC_LENGTH_MASK;
- dma_sync_single_range_for_cpu(dmadev, entry->dma, TSNEP_SKB_PAD,
- length, dma_dir);
+ dma_sync_single_range_for_cpu(dmadev, entry->dma,
+ tsnep_rx_offset(rx), length,
+ dma_dir);
rx->read = (rx->read + 1) % TSNEP_RING_SIZE;
desc_available++;
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support
2022-12-03 21:54 ` [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support Gerhard Engleder
@ 2022-12-07 10:29 ` Paolo Abeni
2022-12-07 20:09 ` Gerhard Engleder
0 siblings, 1 reply; 15+ messages in thread
From: Paolo Abeni @ 2022-12-07 10:29 UTC (permalink / raw)
To: Gerhard Engleder, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
> @@ -808,6 +809,16 @@ static void tsnep_tx_close(struct tsnep_tx *tx)
> tsnep_tx_ring_cleanup(tx);
> }
>
> +static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
> +{
> + struct tsnep_adapter *adapter = rx->adapter;
> +
> + if (tsnep_xdp_is_enabled(adapter))
> + return XDP_PACKET_HEADROOM;
> +
> + return TSNEP_SKB_PAD;
> +}
please, no 'inline' in .c files, thanks!
Paolo
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support
2022-12-07 10:29 ` Paolo Abeni
@ 2022-12-07 20:09 ` Gerhard Engleder
0 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-07 20:09 UTC (permalink / raw)
To: Paolo Abeni, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On 07.12.22 11:29, Paolo Abeni wrote:
> On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
>> @@ -808,6 +809,16 @@ static void tsnep_tx_close(struct tsnep_tx *tx)
>> tsnep_tx_ring_cleanup(tx);
>> }
>>
>> +static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
>> +{
>> + struct tsnep_adapter *adapter = rx->adapter;
>> +
>> + if (tsnep_xdp_is_enabled(adapter))
>> + return XDP_PACKET_HEADROOM;
>> +
>> + return TSNEP_SKB_PAD;
>> +}
>
> please, no 'inline' in .c files, thanks!
Will be fixed.
Gerhard
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH net-next 5/6] tsnep: Add RX queue info for XDP support
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
` (3 preceding siblings ...)
2022-12-03 21:54 ` [PATCH net-next 4/6] tsnep: Prepare RX buffer for XDP support Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-03 21:54 ` [PATCH net-next 6/6] tsnep: Add XDP RX support Gerhard Engleder
5 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
Register xdp_rxq_info with page_pool memory model. This is needed for
XDP buffer handling.
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/tsnep.h | 5 ++--
drivers/net/ethernet/engleder/tsnep_main.c | 34 +++++++++++++++++-----
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/engleder/tsnep.h b/drivers/net/ethernet/engleder/tsnep.h
index 0e7fc36a64e1..70bc133d4a9d 100644
--- a/drivers/net/ethernet/engleder/tsnep.h
+++ b/drivers/net/ethernet/engleder/tsnep.h
@@ -127,6 +127,7 @@ struct tsnep_rx {
u32 owner_counter;
int increment_owner_counter;
struct page_pool *page_pool;
+ struct xdp_rxq_info xdp_rxq;
u32 packets;
u32 bytes;
@@ -139,11 +140,11 @@ struct tsnep_queue {
struct tsnep_adapter *adapter;
char name[IFNAMSIZ + 9];
+ struct napi_struct napi;
+
struct tsnep_tx *tx;
struct tsnep_rx *rx;
- struct napi_struct napi;
-
int irq;
u32 irq_mask;
void __iomem *irq_delay_addr;
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index d7dcac641180..725b2a1e7be4 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -833,6 +833,9 @@ static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
entry->page = NULL;
}
+ if (xdp_rxq_info_is_reg(&rx->xdp_rxq))
+ xdp_rxq_info_unreg(&rx->xdp_rxq);
+
if (rx->page_pool)
page_pool_destroy(rx->page_pool);
@@ -848,7 +851,7 @@ static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
}
}
-static int tsnep_rx_ring_init(struct tsnep_rx *rx)
+static int tsnep_rx_ring_init(struct tsnep_rx *rx, unsigned int napi_id)
{
struct device *dmadev = rx->adapter->dmadev;
struct tsnep_rx_entry *entry;
@@ -891,6 +894,15 @@ static int tsnep_rx_ring_init(struct tsnep_rx *rx)
goto failed;
}
+ retval = xdp_rxq_info_reg(&rx->xdp_rxq, rx->adapter->netdev,
+ rx->queue_index, napi_id);
+ if (retval)
+ goto failed;
+ retval = xdp_rxq_info_reg_mem_model(&rx->xdp_rxq, MEM_TYPE_PAGE_POOL,
+ rx->page_pool);
+ if (retval)
+ goto failed;
+
for (i = 0; i < TSNEP_RING_SIZE; i++) {
entry = &rx->entry[i];
next_entry = &rx->entry[(i + 1) % TSNEP_RING_SIZE];
@@ -1139,7 +1151,8 @@ static bool tsnep_rx_pending(struct tsnep_rx *rx)
}
static int tsnep_rx_open(struct tsnep_adapter *adapter, void __iomem *addr,
- int queue_index, struct tsnep_rx *rx)
+ unsigned int napi_id, int queue_index,
+ struct tsnep_rx *rx)
{
dma_addr_t dma;
int retval;
@@ -1149,7 +1162,7 @@ static int tsnep_rx_open(struct tsnep_adapter *adapter, void __iomem *addr,
rx->addr = addr;
rx->queue_index = queue_index;
- retval = tsnep_rx_ring_init(rx);
+ retval = tsnep_rx_ring_init(rx, napi_id);
if (retval)
return retval;
@@ -1277,6 +1290,7 @@ int tsnep_netdev_open(struct net_device *netdev)
{
struct tsnep_adapter *adapter = netdev_priv(netdev);
int i;
+ unsigned int napi_id;
void __iomem *addr;
int tx_queue_index = 0;
int rx_queue_index = 0;
@@ -1284,6 +1298,11 @@ int tsnep_netdev_open(struct net_device *netdev)
for (i = 0; i < adapter->num_queues; i++) {
adapter->queue[i].adapter = adapter;
+
+ netif_napi_add(adapter->netdev, &adapter->queue[i].napi,
+ tsnep_poll);
+ napi_id = adapter->queue[i].napi.napi_id;
+
if (adapter->queue[i].tx) {
addr = adapter->addr + TSNEP_QUEUE(tx_queue_index);
retval = tsnep_tx_open(adapter, addr, tx_queue_index,
@@ -1294,7 +1313,7 @@ int tsnep_netdev_open(struct net_device *netdev)
}
if (adapter->queue[i].rx) {
addr = adapter->addr + TSNEP_QUEUE(rx_queue_index);
- retval = tsnep_rx_open(adapter, addr,
+ retval = tsnep_rx_open(adapter, addr, napi_id,
rx_queue_index,
adapter->queue[i].rx);
if (retval)
@@ -1326,8 +1345,6 @@ int tsnep_netdev_open(struct net_device *netdev)
goto phy_failed;
for (i = 0; i < adapter->num_queues; i++) {
- netif_napi_add(adapter->netdev, &adapter->queue[i].napi,
- tsnep_poll);
napi_enable(&adapter->queue[i].napi);
tsnep_enable_irq(adapter, adapter->queue[i].irq_mask);
@@ -1348,6 +1365,8 @@ int tsnep_netdev_open(struct net_device *netdev)
tsnep_rx_close(adapter->queue[i].rx);
if (adapter->queue[i].tx)
tsnep_tx_close(adapter->queue[i].tx);
+
+ netif_napi_del(&adapter->queue[i].napi);
}
return retval;
}
@@ -1366,7 +1385,6 @@ int tsnep_netdev_close(struct net_device *netdev)
tsnep_disable_irq(adapter, adapter->queue[i].irq_mask);
napi_disable(&adapter->queue[i].napi);
- netif_napi_del(&adapter->queue[i].napi);
tsnep_free_irq(&adapter->queue[i], i == 0);
@@ -1374,6 +1392,8 @@ int tsnep_netdev_close(struct net_device *netdev)
tsnep_rx_close(adapter->queue[i].rx);
if (adapter->queue[i].tx)
tsnep_tx_close(adapter->queue[i].tx);
+
+ netif_napi_del(&adapter->queue[i].napi);
}
return 0;
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next 6/6] tsnep: Add XDP RX support
2022-12-03 21:54 [PATCH net-next 0/6] tsnep: XDP support Gerhard Engleder
` (4 preceding siblings ...)
2022-12-03 21:54 ` [PATCH net-next 5/6] tsnep: Add RX queue info " Gerhard Engleder
@ 2022-12-03 21:54 ` Gerhard Engleder
2022-12-07 10:18 ` Paolo Abeni
5 siblings, 1 reply; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-03 21:54 UTC (permalink / raw)
To: netdev, bpf
Cc: davem, kuba, edumazet, pabeni, ast, daniel, hawk, john.fastabend,
Gerhard Engleder
If BPF program is set up, then run BPF program for every received frame
and execute the selected action.
Test results with A53 1.2GHz:
XDP_DROP (samples/bpf/xdp1)
proto 17: 865683 pkt/s
XDP_TX (samples/bpf/xdp2)
proto 17: 253594 pkt/s
XDP_REDIRECT (samples/bpf/xdpsock)
sock0@eth2:0 rxdrop xdp-drv
pps pkts 1.00
rx 862,258 4,514,166
tx 0 0
XDP_REDIRECT (samples/bpf/xdp_redirect)
eth2->eth1 608,895 rx/s 0 err,drop/s 608,895 xmit/s
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
---
drivers/net/ethernet/engleder/tsnep_main.c | 100 +++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index 725b2a1e7be4..4e3c6bd3dc9f 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -27,6 +27,7 @@
#include <linux/phy.h>
#include <linux/iopoll.h>
#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
#define TSNEP_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
#define TSNEP_HEADROOM ALIGN(max(TSNEP_SKB_PAD, XDP_PACKET_HEADROOM), 4)
@@ -44,6 +45,11 @@
#define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \
ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1)
+#define TSNEP_XDP_PASS 0
+#define TSNEP_XDP_CONSUMED BIT(0)
+#define TSNEP_XDP_TX BIT(1)
+#define TSNEP_XDP_REDIRECT BIT(2)
+
enum {
__TSNEP_DOWN,
};
@@ -819,6 +825,11 @@ static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
return TSNEP_SKB_PAD;
}
+static inline unsigned int tsnep_rx_offset_xdp(void)
+{
+ return XDP_PACKET_HEADROOM;
+}
+
static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
{
struct device *dmadev = rx->adapter->dmadev;
@@ -1024,6 +1035,65 @@ static int tsnep_rx_refill(struct tsnep_rx *rx, int count, bool reuse)
return i;
}
+static int tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog,
+ struct xdp_buff *xdp)
+{
+ unsigned int length;
+ unsigned int sync;
+ u32 act;
+
+ length = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
+
+ act = bpf_prog_run_xdp(prog, xdp);
+
+ /* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
+ sync = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
+ sync = max(sync, length);
+
+ switch (act) {
+ case XDP_PASS:
+ return TSNEP_XDP_PASS;
+ case XDP_TX:
+ if (tsnep_xdp_xmit_back(rx->adapter, xdp) < 0)
+ goto out_failure;
+ return TSNEP_XDP_TX;
+ case XDP_REDIRECT:
+ if (xdp_do_redirect(rx->adapter->netdev, xdp, prog) < 0)
+ goto out_failure;
+ return TSNEP_XDP_REDIRECT;
+ default:
+ bpf_warn_invalid_xdp_action(rx->adapter->netdev, prog, act);
+ fallthrough;
+ case XDP_ABORTED:
+out_failure:
+ trace_xdp_exception(rx->adapter->netdev, prog, act);
+ fallthrough;
+ case XDP_DROP:
+ page_pool_put_page(rx->page_pool, virt_to_head_page(xdp->data),
+ sync, true);
+ return TSNEP_XDP_CONSUMED;
+ }
+}
+
+static void tsnep_finalize_xdp(struct tsnep_adapter *adapter, int status)
+{
+ int cpu = smp_processor_id();
+ int queue;
+ struct netdev_queue *nq;
+
+ if (status & TSNEP_XDP_TX) {
+ queue = cpu % adapter->num_tx_queues;
+ nq = netdev_get_tx_queue(adapter->netdev, queue);
+
+ __netif_tx_lock(nq, cpu);
+ tsnep_xdp_xmit_flush(&adapter->tx[queue]);
+ __netif_tx_unlock(nq);
+ }
+
+ if (status & TSNEP_XDP_REDIRECT)
+ xdp_do_flush();
+}
+
static struct sk_buff *tsnep_build_skb(struct tsnep_rx *rx, struct page *page,
int length)
{
@@ -1062,12 +1132,17 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
int desc_available;
int done = 0;
enum dma_data_direction dma_dir;
+ struct bpf_prog *prog;
struct tsnep_rx_entry *entry;
+ struct xdp_buff xdp;
+ int xdp_status = 0;
struct sk_buff *skb;
int length;
+ int retval;
desc_available = tsnep_rx_desc_available(rx);
dma_dir = page_pool_get_dma_dir(rx->page_pool);
+ prog = READ_ONCE(rx->adapter->xdp_prog);
while (likely(done < budget) && (rx->read != rx->write)) {
entry = &rx->entry[rx->read];
@@ -1111,6 +1186,28 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
rx->read = (rx->read + 1) % TSNEP_RING_SIZE;
desc_available++;
+ if (prog) {
+ xdp_init_buff(&xdp, PAGE_SIZE, &rx->xdp_rxq);
+ xdp_prepare_buff(&xdp, page_address(entry->page),
+ tsnep_rx_offset_xdp() + TSNEP_RX_INLINE_METADATA_SIZE,
+ length - TSNEP_RX_INLINE_METADATA_SIZE,
+ false);
+ retval = tsnep_xdp_run_prog(rx, prog, &xdp);
+ } else {
+ retval = TSNEP_XDP_PASS;
+ }
+ if (retval) {
+ if (retval & (TSNEP_XDP_TX | TSNEP_XDP_REDIRECT))
+ xdp_status |= retval;
+
+ rx->packets++;
+ rx->bytes += length - TSNEP_RX_INLINE_METADATA_SIZE;
+
+ entry->page = NULL;
+
+ continue;
+ }
+
skb = tsnep_build_skb(rx, entry->page, length);
if (skb) {
page_pool_release_page(rx->page_pool, entry->page);
@@ -1129,6 +1226,9 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
entry->page = NULL;
}
+ if (xdp_status)
+ tsnep_finalize_xdp(rx->adapter, xdp_status);
+
if (desc_available)
tsnep_rx_refill(rx, desc_available, false);
--
2.30.2
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH net-next 6/6] tsnep: Add XDP RX support
2022-12-03 21:54 ` [PATCH net-next 6/6] tsnep: Add XDP RX support Gerhard Engleder
@ 2022-12-07 10:18 ` Paolo Abeni
2022-12-07 20:12 ` Gerhard Engleder
0 siblings, 1 reply; 15+ messages in thread
From: Paolo Abeni @ 2022-12-07 10:18 UTC (permalink / raw)
To: Gerhard Engleder, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
> If BPF program is set up, then run BPF program for every received frame
> and execute the selected action.
>
> Test results with A53 1.2GHz:
>
> XDP_DROP (samples/bpf/xdp1)
> proto 17: 865683 pkt/s
>
> XDP_TX (samples/bpf/xdp2)
> proto 17: 253594 pkt/s
>
> XDP_REDIRECT (samples/bpf/xdpsock)
> sock0@eth2:0 rxdrop xdp-drv
> pps pkts 1.00
> rx 862,258 4,514,166
> tx 0 0
>
> XDP_REDIRECT (samples/bpf/xdp_redirect)
> eth2->eth1 608,895 rx/s 0 err,drop/s 608,895 xmit/s
>
> Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
> ---
> drivers/net/ethernet/engleder/tsnep_main.c | 100 +++++++++++++++++++++
> 1 file changed, 100 insertions(+)
>
> diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
> index 725b2a1e7be4..4e3c6bd3dc9f 100644
> --- a/drivers/net/ethernet/engleder/tsnep_main.c
> +++ b/drivers/net/ethernet/engleder/tsnep_main.c
> @@ -27,6 +27,7 @@
> #include <linux/phy.h>
> #include <linux/iopoll.h>
> #include <linux/bpf.h>
> +#include <linux/bpf_trace.h>
>
> #define TSNEP_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
> #define TSNEP_HEADROOM ALIGN(max(TSNEP_SKB_PAD, XDP_PACKET_HEADROOM), 4)
> @@ -44,6 +45,11 @@
> #define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \
> ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1)
>
> +#define TSNEP_XDP_PASS 0
> +#define TSNEP_XDP_CONSUMED BIT(0)
> +#define TSNEP_XDP_TX BIT(1)
> +#define TSNEP_XDP_REDIRECT BIT(2)
> +
> enum {
> __TSNEP_DOWN,
> };
> @@ -819,6 +825,11 @@ static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
> return TSNEP_SKB_PAD;
> }
>
> +static inline unsigned int tsnep_rx_offset_xdp(void)
Please, no 'inline' in c files, the complier will do a better job
without.
> +{
> + return XDP_PACKET_HEADROOM;
> +}
> +
> static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
> {
> struct device *dmadev = rx->adapter->dmadev;
> @@ -1024,6 +1035,65 @@ static int tsnep_rx_refill(struct tsnep_rx *rx, int count, bool reuse)
> return i;
> }
>
> +static int tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog,
> + struct xdp_buff *xdp)
> +{
> + unsigned int length;
> + unsigned int sync;
> + u32 act;
> +
> + length = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
> +
> + act = bpf_prog_run_xdp(prog, xdp);
> +
> + /* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
> + sync = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
> + sync = max(sync, length);
> +
> + switch (act) {
> + case XDP_PASS:
> + return TSNEP_XDP_PASS;
> + case XDP_TX:
> + if (tsnep_xdp_xmit_back(rx->adapter, xdp) < 0)
> + goto out_failure;
> + return TSNEP_XDP_TX;
> + case XDP_REDIRECT:
> + if (xdp_do_redirect(rx->adapter->netdev, xdp, prog) < 0)
> + goto out_failure;
> + return TSNEP_XDP_REDIRECT;
> + default:
> + bpf_warn_invalid_xdp_action(rx->adapter->netdev, prog, act);
> + fallthrough;
> + case XDP_ABORTED:
> +out_failure:
> + trace_xdp_exception(rx->adapter->netdev, prog, act);
> + fallthrough;
> + case XDP_DROP:
> + page_pool_put_page(rx->page_pool, virt_to_head_page(xdp->data),
> + sync, true);
> + return TSNEP_XDP_CONSUMED;
> + }
> +}
> +
> +static void tsnep_finalize_xdp(struct tsnep_adapter *adapter, int status)
> +{
> + int cpu = smp_processor_id();
> + int queue;
> + struct netdev_queue *nq;
> +
> + if (status & TSNEP_XDP_TX) {
> + queue = cpu % adapter->num_tx_queues;
> + nq = netdev_get_tx_queue(adapter->netdev, queue);
> +
> + __netif_tx_lock(nq, cpu);
> + tsnep_xdp_xmit_flush(&adapter->tx[queue]);
> + __netif_tx_unlock(nq);
> + }
> +
> + if (status & TSNEP_XDP_REDIRECT)
> + xdp_do_flush();
> +}
> +
> static struct sk_buff *tsnep_build_skb(struct tsnep_rx *rx, struct page *page,
> int length)
> {
> @@ -1062,12 +1132,17 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
> int desc_available;
> int done = 0;
> enum dma_data_direction dma_dir;
> + struct bpf_prog *prog;
> struct tsnep_rx_entry *entry;
> + struct xdp_buff xdp;
> + int xdp_status = 0;
> struct sk_buff *skb;
> int length;
> + int retval;
>
> desc_available = tsnep_rx_desc_available(rx);
> dma_dir = page_pool_get_dma_dir(rx->page_pool);
> + prog = READ_ONCE(rx->adapter->xdp_prog);
>
> while (likely(done < budget) && (rx->read != rx->write)) {
> entry = &rx->entry[rx->read];
> @@ -1111,6 +1186,28 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
> rx->read = (rx->read + 1) % TSNEP_RING_SIZE;
> desc_available++;
>
> + if (prog) {
> + xdp_init_buff(&xdp, PAGE_SIZE, &rx->xdp_rxq);
> + xdp_prepare_buff(&xdp, page_address(entry->page),
> + tsnep_rx_offset_xdp() + TSNEP_RX_INLINE_METADATA_SIZE,
> + length - TSNEP_RX_INLINE_METADATA_SIZE,
> + false);
> + retval = tsnep_xdp_run_prog(rx, prog, &xdp);
> + } else {
> + retval = TSNEP_XDP_PASS;
> + }
> + if (retval) {
> + if (retval & (TSNEP_XDP_TX | TSNEP_XDP_REDIRECT))
> + xdp_status |= retval;
Here you could avoid a couple of conditionals passing xdp_status as an
additional tsnep_xdp_run_prog() argument, let the latter update it
under the existing switch, returning a single consumed/pass up bool and
testing such value just after tsnep_xdp_run_prog().
Mostly a matter of personal tasted I guess.
Cheers,
Paolo
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH net-next 6/6] tsnep: Add XDP RX support
2022-12-07 10:18 ` Paolo Abeni
@ 2022-12-07 20:12 ` Gerhard Engleder
0 siblings, 0 replies; 15+ messages in thread
From: Gerhard Engleder @ 2022-12-07 20:12 UTC (permalink / raw)
To: Paolo Abeni, netdev, bpf
Cc: davem, kuba, edumazet, ast, daniel, hawk, john.fastabend
On 07.12.22 11:18, Paolo Abeni wrote:
> On Sat, 2022-12-03 at 22:54 +0100, Gerhard Engleder wrote:
>> If BPF program is set up, then run BPF program for every received frame
>> and execute the selected action.
>>
>> Test results with A53 1.2GHz:
>>
>> XDP_DROP (samples/bpf/xdp1)
>> proto 17: 865683 pkt/s
>>
>> XDP_TX (samples/bpf/xdp2)
>> proto 17: 253594 pkt/s
>>
>> XDP_REDIRECT (samples/bpf/xdpsock)
>> sock0@eth2:0 rxdrop xdp-drv
>> pps pkts 1.00
>> rx 862,258 4,514,166
>> tx 0 0
>>
>> XDP_REDIRECT (samples/bpf/xdp_redirect)
>> eth2->eth1 608,895 rx/s 0 err,drop/s 608,895 xmit/s
>>
>> Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
>> ---
>> drivers/net/ethernet/engleder/tsnep_main.c | 100 +++++++++++++++++++++
>> 1 file changed, 100 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
>> index 725b2a1e7be4..4e3c6bd3dc9f 100644
>> --- a/drivers/net/ethernet/engleder/tsnep_main.c
>> +++ b/drivers/net/ethernet/engleder/tsnep_main.c
>> @@ -27,6 +27,7 @@
>> #include <linux/phy.h>
>> #include <linux/iopoll.h>
>> #include <linux/bpf.h>
>> +#include <linux/bpf_trace.h>
>>
>> #define TSNEP_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
>> #define TSNEP_HEADROOM ALIGN(max(TSNEP_SKB_PAD, XDP_PACKET_HEADROOM), 4)
>> @@ -44,6 +45,11 @@
>> #define TSNEP_COALESCE_USECS_MAX ((ECM_INT_DELAY_MASK >> ECM_INT_DELAY_SHIFT) * \
>> ECM_INT_DELAY_BASE_US + ECM_INT_DELAY_BASE_US - 1)
>>
>> +#define TSNEP_XDP_PASS 0
>> +#define TSNEP_XDP_CONSUMED BIT(0)
>> +#define TSNEP_XDP_TX BIT(1)
>> +#define TSNEP_XDP_REDIRECT BIT(2)
>> +
>> enum {
>> __TSNEP_DOWN,
>> };
>> @@ -819,6 +825,11 @@ static inline unsigned int tsnep_rx_offset(struct tsnep_rx *rx)
>> return TSNEP_SKB_PAD;
>> }
>>
>> +static inline unsigned int tsnep_rx_offset_xdp(void)
>
> Please, no 'inline' in c files, the complier will do a better job
> without.
Will be fixed.
>> +{
>> + return XDP_PACKET_HEADROOM;
>> +}
>> +
>> static void tsnep_rx_ring_cleanup(struct tsnep_rx *rx)
>> {
>> struct device *dmadev = rx->adapter->dmadev;
>> @@ -1024,6 +1035,65 @@ static int tsnep_rx_refill(struct tsnep_rx *rx, int count, bool reuse)
>> return i;
>> }
>>
>> +static int tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog,
>> + struct xdp_buff *xdp)
>> +{
>> + unsigned int length;
>> + unsigned int sync;
>> + u32 act;
>> +
>> + length = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
>> +
>> + act = bpf_prog_run_xdp(prog, xdp);
>> +
>> + /* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
>> + sync = xdp->data_end - xdp->data_hard_start - tsnep_rx_offset_xdp();
>> + sync = max(sync, length);
>> +
>> + switch (act) {
>> + case XDP_PASS:
>> + return TSNEP_XDP_PASS;
>> + case XDP_TX:
>> + if (tsnep_xdp_xmit_back(rx->adapter, xdp) < 0)
>> + goto out_failure;
>> + return TSNEP_XDP_TX;
>> + case XDP_REDIRECT:
>> + if (xdp_do_redirect(rx->adapter->netdev, xdp, prog) < 0)
>> + goto out_failure;
>> + return TSNEP_XDP_REDIRECT;
>> + default:
>> + bpf_warn_invalid_xdp_action(rx->adapter->netdev, prog, act);
>> + fallthrough;
>> + case XDP_ABORTED:
>> +out_failure:
>> + trace_xdp_exception(rx->adapter->netdev, prog, act);
>> + fallthrough;
>> + case XDP_DROP:
>> + page_pool_put_page(rx->page_pool, virt_to_head_page(xdp->data),
>> + sync, true);
>> + return TSNEP_XDP_CONSUMED;
>> + }
>> +}
>> +
>> +static void tsnep_finalize_xdp(struct tsnep_adapter *adapter, int status)
>> +{
>> + int cpu = smp_processor_id();
>> + int queue;
>> + struct netdev_queue *nq;
>> +
>> + if (status & TSNEP_XDP_TX) {
>> + queue = cpu % adapter->num_tx_queues;
>> + nq = netdev_get_tx_queue(adapter->netdev, queue);
>> +
>> + __netif_tx_lock(nq, cpu);
>> + tsnep_xdp_xmit_flush(&adapter->tx[queue]);
>> + __netif_tx_unlock(nq);
>> + }
>> +
>> + if (status & TSNEP_XDP_REDIRECT)
>> + xdp_do_flush();
>> +}
>> +
>> static struct sk_buff *tsnep_build_skb(struct tsnep_rx *rx, struct page *page,
>> int length)
>> {
>> @@ -1062,12 +1132,17 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
>> int desc_available;
>> int done = 0;
>> enum dma_data_direction dma_dir;
>> + struct bpf_prog *prog;
>> struct tsnep_rx_entry *entry;
>> + struct xdp_buff xdp;
>> + int xdp_status = 0;
>> struct sk_buff *skb;
>> int length;
>> + int retval;
>>
>> desc_available = tsnep_rx_desc_available(rx);
>> dma_dir = page_pool_get_dma_dir(rx->page_pool);
>> + prog = READ_ONCE(rx->adapter->xdp_prog);
>>
>> while (likely(done < budget) && (rx->read != rx->write)) {
>> entry = &rx->entry[rx->read];
>> @@ -1111,6 +1186,28 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
>> rx->read = (rx->read + 1) % TSNEP_RING_SIZE;
>> desc_available++;
>>
>> + if (prog) {
>> + xdp_init_buff(&xdp, PAGE_SIZE, &rx->xdp_rxq);
>> + xdp_prepare_buff(&xdp, page_address(entry->page),
>> + tsnep_rx_offset_xdp() + TSNEP_RX_INLINE_METADATA_SIZE,
>> + length - TSNEP_RX_INLINE_METADATA_SIZE,
>> + false);
>> + retval = tsnep_xdp_run_prog(rx, prog, &xdp);
>> + } else {
>> + retval = TSNEP_XDP_PASS;
>> + }
>> + if (retval) {
>> + if (retval & (TSNEP_XDP_TX | TSNEP_XDP_REDIRECT))
>> + xdp_status |= retval;
>
> Here you could avoid a couple of conditionals passing xdp_status as an
> additional tsnep_xdp_run_prog() argument, let the latter update it
> under the existing switch, returning a single consumed/pass up bool and
> testing such value just after tsnep_xdp_run_prog().
>
> Mostly a matter of personal tasted I guess.
I will try it.
Thanks for the review!
Gerhard
^ permalink raw reply [flat|nested] 15+ messages in thread