Skip to content

Commit ed5356b

Browse files
haiyangzdavem330
authored andcommitted
net: mana: Add XDP support
Add support of XDP for the MANA driver. Supported XDP actions: XDP_PASS, XDP_TX, XDP_DROP, XDP_ABORTED XDP actions not yet supported: XDP_REDIRECT Signed-off-by: Haiyang Zhang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b8ac21d commit ed5356b

File tree

4 files changed

+235
-11
lines changed

4 files changed

+235
-11
lines changed

drivers/net/ethernet/microsoft/mana/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
# Makefile for the Microsoft Azure Network Adapter driver
44

55
obj-$(CONFIG_MICROSOFT_MANA) += mana.o
6-
mana-objs := gdma_main.o shm_channel.o hw_channel.o mana_en.o mana_ethtool.o
6+
mana-objs := gdma_main.o shm_channel.o hw_channel.o mana_en.o mana_ethtool.o mana_bpf.o

drivers/net/ethernet/microsoft/mana/mana.h

+13
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ struct mana_rxq {
298298

299299
struct mana_stats stats;
300300

301+
struct bpf_prog __rcu *bpf_prog;
302+
struct xdp_rxq_info xdp_rxq;
303+
301304
/* MUST BE THE LAST MEMBER:
302305
* Each receive buffer has an associated mana_recv_buf_oob.
303306
*/
@@ -353,6 +356,8 @@ struct mana_port_context {
353356
/* This points to an array of num_queues of RQ pointers. */
354357
struct mana_rxq **rxqs;
355358

359+
struct bpf_prog *bpf_prog;
360+
356361
/* Create num_queues EQs, SQs, SQ-CQs, RQs and RQ-CQs, respectively. */
357362
unsigned int max_queues;
358363
unsigned int num_queues;
@@ -367,6 +372,7 @@ struct mana_port_context {
367372
struct mana_ethtool_stats eth_stats;
368373
};
369374

375+
int mana_start_xmit(struct sk_buff *skb, struct net_device *ndev);
370376
int mana_config_rss(struct mana_port_context *ac, enum TRI_STATE rx,
371377
bool update_hash, bool update_tab);
372378

@@ -377,6 +383,13 @@ int mana_detach(struct net_device *ndev, bool from_close);
377383
int mana_probe(struct gdma_dev *gd, bool resuming);
378384
void mana_remove(struct gdma_dev *gd, bool suspending);
379385

386+
void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev);
387+
u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
388+
struct xdp_buff *xdp, void *buf_va, uint pkt_len);
389+
struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
390+
void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
391+
int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
392+
380393
extern const struct ethtool_ops mana_ethtool_ops;
381394

382395
struct mana_obj_spec {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2+
/* Copyright (c) 2021, Microsoft Corporation. */
3+
4+
#include <linux/inetdevice.h>
5+
#include <linux/etherdevice.h>
6+
#include <linux/mm.h>
7+
#include <linux/bpf.h>
8+
#include <linux/bpf_trace.h>
9+
#include <net/xdp.h>
10+
11+
#include "mana.h"
12+
13+
void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev)
14+
{
15+
u16 txq_idx = skb_get_queue_mapping(skb);
16+
struct netdev_queue *ndevtxq;
17+
int rc;
18+
19+
__skb_push(skb, ETH_HLEN);
20+
21+
ndevtxq = netdev_get_tx_queue(ndev, txq_idx);
22+
__netif_tx_lock(ndevtxq, smp_processor_id());
23+
24+
rc = mana_start_xmit(skb, ndev);
25+
26+
__netif_tx_unlock(ndevtxq);
27+
28+
if (dev_xmit_complete(rc))
29+
return;
30+
31+
dev_kfree_skb_any(skb);
32+
ndev->stats.tx_dropped++;
33+
}
34+
35+
u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
36+
struct xdp_buff *xdp, void *buf_va, uint pkt_len)
37+
{
38+
struct bpf_prog *prog;
39+
u32 act = XDP_PASS;
40+
41+
rcu_read_lock();
42+
prog = rcu_dereference(rxq->bpf_prog);
43+
44+
if (!prog)
45+
goto out;
46+
47+
xdp_init_buff(xdp, PAGE_SIZE, &rxq->xdp_rxq);
48+
xdp_prepare_buff(xdp, buf_va, XDP_PACKET_HEADROOM, pkt_len, false);
49+
50+
act = bpf_prog_run_xdp(prog, xdp);
51+
52+
switch (act) {
53+
case XDP_PASS:
54+
case XDP_TX:
55+
case XDP_DROP:
56+
break;
57+
58+
case XDP_ABORTED:
59+
trace_xdp_exception(ndev, prog, act);
60+
break;
61+
62+
default:
63+
bpf_warn_invalid_xdp_action(act);
64+
}
65+
66+
out:
67+
rcu_read_unlock();
68+
69+
return act;
70+
}
71+
72+
static unsigned int mana_xdp_fraglen(unsigned int len)
73+
{
74+
return SKB_DATA_ALIGN(len) +
75+
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
76+
}
77+
78+
struct bpf_prog *mana_xdp_get(struct mana_port_context *apc)
79+
{
80+
ASSERT_RTNL();
81+
82+
return apc->bpf_prog;
83+
}
84+
85+
static struct bpf_prog *mana_chn_xdp_get(struct mana_port_context *apc)
86+
{
87+
return rtnl_dereference(apc->rxqs[0]->bpf_prog);
88+
}
89+
90+
/* Set xdp program on channels */
91+
void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog)
92+
{
93+
struct bpf_prog *old_prog = mana_chn_xdp_get(apc);
94+
unsigned int num_queues = apc->num_queues;
95+
int i;
96+
97+
ASSERT_RTNL();
98+
99+
if (old_prog == prog)
100+
return;
101+
102+
if (prog)
103+
bpf_prog_add(prog, num_queues);
104+
105+
for (i = 0; i < num_queues; i++)
106+
rcu_assign_pointer(apc->rxqs[i]->bpf_prog, prog);
107+
108+
if (old_prog)
109+
for (i = 0; i < num_queues; i++)
110+
bpf_prog_put(old_prog);
111+
}
112+
113+
static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
114+
struct netlink_ext_ack *extack)
115+
{
116+
struct mana_port_context *apc = netdev_priv(ndev);
117+
struct bpf_prog *old_prog;
118+
int buf_max;
119+
120+
old_prog = mana_xdp_get(apc);
121+
122+
if (!old_prog && !prog)
123+
return 0;
124+
125+
buf_max = XDP_PACKET_HEADROOM + mana_xdp_fraglen(ndev->mtu + ETH_HLEN);
126+
if (prog && buf_max > PAGE_SIZE) {
127+
netdev_err(ndev, "XDP: mtu:%u too large, buf_max:%u\n",
128+
ndev->mtu, buf_max);
129+
NL_SET_ERR_MSG_MOD(extack, "XDP: mtu too large");
130+
131+
return -EOPNOTSUPP;
132+
}
133+
134+
/* One refcnt of the prog is hold by the caller already, so
135+
* don't increase refcnt for this one.
136+
*/
137+
apc->bpf_prog = prog;
138+
139+
if (old_prog)
140+
bpf_prog_put(old_prog);
141+
142+
if (apc->port_is_up)
143+
mana_chn_setxdp(apc, prog);
144+
145+
return 0;
146+
}
147+
148+
int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf)
149+
{
150+
struct netlink_ext_ack *extack = bpf->extack;
151+
int ret;
152+
153+
switch (bpf->command) {
154+
case XDP_SETUP_PROG:
155+
return mana_xdp_set(ndev, bpf->prog, extack);
156+
157+
default:
158+
return -EOPNOTSUPP;
159+
}
160+
161+
return ret;
162+
}

drivers/net/ethernet/microsoft/mana/mana_en.c

+59-10
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static int mana_map_skb(struct sk_buff *skb, struct mana_port_context *apc,
125125
return -ENOMEM;
126126
}
127127

128-
static int mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
128+
int mana_start_xmit(struct sk_buff *skb, struct net_device *ndev)
129129
{
130130
enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT;
131131
struct mana_port_context *apc = netdev_priv(ndev);
@@ -378,6 +378,7 @@ static const struct net_device_ops mana_devops = {
378378
.ndo_start_xmit = mana_start_xmit,
379379
.ndo_validate_addr = eth_validate_addr,
380380
.ndo_get_stats64 = mana_get_stats64,
381+
.ndo_bpf = mana_bpf,
381382
};
382383

383384
static void mana_cleanup_port_context(struct mana_port_context *apc)
@@ -906,6 +907,25 @@ static void mana_post_pkt_rxq(struct mana_rxq *rxq)
906907
WARN_ON_ONCE(recv_buf_oob->wqe_inf.wqe_size_in_bu != 1);
907908
}
908909

910+
static struct sk_buff *mana_build_skb(void *buf_va, uint pkt_len,
911+
struct xdp_buff *xdp)
912+
{
913+
struct sk_buff *skb = build_skb(buf_va, PAGE_SIZE);
914+
915+
if (!skb)
916+
return NULL;
917+
918+
if (xdp->data_hard_start) {
919+
skb_reserve(skb, xdp->data - xdp->data_hard_start);
920+
skb_put(skb, xdp->data_end - xdp->data);
921+
} else {
922+
skb_reserve(skb, XDP_PACKET_HEADROOM);
923+
skb_put(skb, pkt_len);
924+
}
925+
926+
return skb;
927+
}
928+
909929
static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
910930
struct mana_rxq *rxq)
911931
{
@@ -914,8 +934,10 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
914934
uint pkt_len = cqe->ppi[0].pkt_len;
915935
u16 rxq_idx = rxq->rxq_idx;
916936
struct napi_struct *napi;
937+
struct xdp_buff xdp = {};
917938
struct sk_buff *skb;
918939
u32 hash_value;
940+
u32 act;
919941

920942
rxq->rx_cq.work_done++;
921943
napi = &rxq->rx_cq.napi;
@@ -925,15 +947,16 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
925947
return;
926948
}
927949

928-
skb = build_skb(buf_va, PAGE_SIZE);
950+
act = mana_run_xdp(ndev, rxq, &xdp, buf_va, pkt_len);
929951

930-
if (!skb) {
931-
free_page((unsigned long)buf_va);
932-
++ndev->stats.rx_dropped;
933-
return;
934-
}
952+
if (act != XDP_PASS && act != XDP_TX)
953+
goto drop;
954+
955+
skb = mana_build_skb(buf_va, pkt_len, &xdp);
956+
957+
if (!skb)
958+
goto drop;
935959

936-
skb_put(skb, pkt_len);
937960
skb->dev = napi->dev;
938961

939962
skb->protocol = eth_type_trans(skb, ndev);
@@ -954,12 +977,24 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
954977
skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L3);
955978
}
956979

980+
if (act == XDP_TX) {
981+
skb_set_queue_mapping(skb, rxq_idx);
982+
mana_xdp_tx(skb, ndev);
983+
return;
984+
}
985+
957986
napi_gro_receive(napi, skb);
958987

959988
u64_stats_update_begin(&rx_stats->syncp);
960989
rx_stats->packets++;
961990
rx_stats->bytes += pkt_len;
962991
u64_stats_update_end(&rx_stats->syncp);
992+
return;
993+
994+
drop:
995+
free_page((unsigned long)buf_va);
996+
++ndev->stats.rx_dropped;
997+
return;
963998
}
964999

9651000
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
@@ -1016,7 +1051,7 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
10161051
new_page = alloc_page(GFP_ATOMIC);
10171052

10181053
if (new_page) {
1019-
da = dma_map_page(dev, new_page, 0, rxq->datasize,
1054+
da = dma_map_page(dev, new_page, XDP_PACKET_HEADROOM, rxq->datasize,
10201055
DMA_FROM_DEVICE);
10211056

10221057
if (dma_mapping_error(dev, da)) {
@@ -1291,6 +1326,9 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
12911326
napi_synchronize(napi);
12921327

12931328
napi_disable(napi);
1329+
1330+
xdp_rxq_info_unreg(&rxq->xdp_rxq);
1331+
12941332
netif_napi_del(napi);
12951333

12961334
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
@@ -1342,7 +1380,8 @@ static int mana_alloc_rx_wqe(struct mana_port_context *apc,
13421380
if (!page)
13431381
return -ENOMEM;
13441382

1345-
da = dma_map_page(dev, page, 0, rxq->datasize, DMA_FROM_DEVICE);
1383+
da = dma_map_page(dev, page, XDP_PACKET_HEADROOM, rxq->datasize,
1384+
DMA_FROM_DEVICE);
13461385

13471386
if (dma_mapping_error(dev, da)) {
13481387
__free_page(page);
@@ -1485,6 +1524,12 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
14851524
gc->cq_table[cq->gdma_id] = cq->gdma_cq;
14861525

14871526
netif_napi_add(ndev, &cq->napi, mana_poll, 1);
1527+
1528+
WARN_ON(xdp_rxq_info_reg(&rxq->xdp_rxq, ndev, rxq_idx,
1529+
cq->napi.napi_id));
1530+
WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq,
1531+
MEM_TYPE_PAGE_SHARED, NULL));
1532+
14881533
napi_enable(&cq->napi);
14891534

14901535
mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
@@ -1650,6 +1695,8 @@ int mana_alloc_queues(struct net_device *ndev)
16501695
if (err)
16511696
goto destroy_vport;
16521697

1698+
mana_chn_setxdp(apc, mana_xdp_get(apc));
1699+
16531700
return 0;
16541701

16551702
destroy_vport:
@@ -1698,6 +1745,8 @@ static int mana_dealloc_queues(struct net_device *ndev)
16981745
if (apc->port_is_up)
16991746
return -EINVAL;
17001747

1748+
mana_chn_setxdp(apc, NULL);
1749+
17011750
/* No packet can be transmitted now since apc->port_is_up is false.
17021751
* There is still a tiny chance that mana_poll_tx_cq() can re-enable
17031752
* a txq because it may not timely see apc->port_is_up being cleared

0 commit comments

Comments
 (0)