diff options
Diffstat (limited to 'kernel/bpf/devmap.c')
-rw-r--r-- | kernel/bpf/devmap.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index a9cd5c93dd2b..77908311ec98 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c | |||
@@ -232,24 +232,31 @@ static int bq_xmit_all(struct bpf_dtab_netdev *obj, | |||
232 | prefetch(xdpf); | 232 | prefetch(xdpf); |
233 | } | 233 | } |
234 | 234 | ||
235 | for (i = 0; i < bq->count; i++) { | 235 | sent = dev->netdev_ops->ndo_xdp_xmit(dev, bq->count, bq->q); |
236 | struct xdp_frame *xdpf = bq->q[i]; | 236 | if (sent < 0) { |
237 | int err; | 237 | sent = 0; |
238 | 238 | goto error; | |
239 | err = dev->netdev_ops->ndo_xdp_xmit(dev, xdpf); | ||
240 | if (err) { | ||
241 | drops++; | ||
242 | xdp_return_frame_rx_napi(xdpf); | ||
243 | } else { | ||
244 | sent++; | ||
245 | } | ||
246 | } | 239 | } |
240 | drops = bq->count - sent; | ||
241 | out: | ||
247 | bq->count = 0; | 242 | bq->count = 0; |
248 | 243 | ||
249 | trace_xdp_devmap_xmit(&obj->dtab->map, obj->bit, | 244 | trace_xdp_devmap_xmit(&obj->dtab->map, obj->bit, |
250 | sent, drops, bq->dev_rx, dev); | 245 | sent, drops, bq->dev_rx, dev); |
251 | bq->dev_rx = NULL; | 246 | bq->dev_rx = NULL; |
252 | return 0; | 247 | return 0; |
248 | error: | ||
249 | /* If ndo_xdp_xmit fails with an errno, no frames have been | ||
250 | * xmit'ed and it's our responsibility to them free all. | ||
251 | */ | ||
252 | for (i = 0; i < bq->count; i++) { | ||
253 | struct xdp_frame *xdpf = bq->q[i]; | ||
254 | |||
255 | /* RX path under NAPI protection, can return frames faster */ | ||
256 | xdp_return_frame_rx_napi(xdpf); | ||
257 | drops++; | ||
258 | } | ||
259 | goto out; | ||
253 | } | 260 | } |
254 | 261 | ||
255 | /* __dev_map_flush is called from xdp_do_flush_map() which _must_ be signaled | 262 | /* __dev_map_flush is called from xdp_do_flush_map() which _must_ be signaled |