@@ -63,6 +63,7 @@ struct bpf_cpu_map_entry {
63
63
struct task_struct * kthread ;
64
64
65
65
struct bpf_cpumap_val value ;
66
+ struct bpf_prog * prog ;
66
67
67
68
atomic_t refcnt ; /* Control when this struct can be free'ed */
68
69
struct rcu_head rcu ;
@@ -82,6 +83,7 @@ static int bq_flush_to_queue(struct xdp_bulk_queue *bq);
82
83
83
84
static struct bpf_map * cpu_map_alloc (union bpf_attr * attr )
84
85
{
86
+ u32 value_size = attr -> value_size ;
85
87
struct bpf_cpu_map * cmap ;
86
88
int err = - ENOMEM ;
87
89
u64 cost ;
@@ -92,7 +94,9 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
92
94
93
95
/* check sanity of attributes */
94
96
if (attr -> max_entries == 0 || attr -> key_size != 4 ||
95
- attr -> value_size != 4 || attr -> map_flags & ~BPF_F_NUMA_NODE )
97
+ (value_size != offsetofend (struct bpf_cpumap_val , qsize ) &&
98
+ value_size != offsetofend (struct bpf_cpumap_val , bpf_prog .fd )) ||
99
+ attr -> map_flags & ~BPF_F_NUMA_NODE )
96
100
return ERR_PTR (- EINVAL );
97
101
98
102
cmap = kzalloc (sizeof (* cmap ), GFP_USER );
@@ -214,6 +218,8 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring)
214
218
static void put_cpu_map_entry (struct bpf_cpu_map_entry * rcpu )
215
219
{
216
220
if (atomic_dec_and_test (& rcpu -> refcnt )) {
221
+ if (rcpu -> prog )
222
+ bpf_prog_put (rcpu -> prog );
217
223
/* The queue should be empty at this point */
218
224
__cpu_map_ring_cleanup (rcpu -> queue );
219
225
ptr_ring_cleanup (rcpu -> queue , NULL );
@@ -222,6 +228,62 @@ static void put_cpu_map_entry(struct bpf_cpu_map_entry *rcpu)
222
228
}
223
229
}
224
230
231
+ static int cpu_map_bpf_prog_run_xdp (struct bpf_cpu_map_entry * rcpu ,
232
+ void * * frames , int n ,
233
+ struct xdp_cpumap_stats * stats )
234
+ {
235
+ struct xdp_rxq_info rxq ;
236
+ struct xdp_buff xdp ;
237
+ int i , nframes = 0 ;
238
+
239
+ if (!rcpu -> prog )
240
+ return n ;
241
+
242
+ rcu_read_lock ();
243
+
244
+ xdp_set_return_frame_no_direct ();
245
+ xdp .rxq = & rxq ;
246
+
247
+ for (i = 0 ; i < n ; i ++ ) {
248
+ struct xdp_frame * xdpf = frames [i ];
249
+ u32 act ;
250
+ int err ;
251
+
252
+ rxq .dev = xdpf -> dev_rx ;
253
+ rxq .mem = xdpf -> mem ;
254
+ /* TODO: report queue_index to xdp_rxq_info */
255
+
256
+ xdp_convert_frame_to_buff (xdpf , & xdp );
257
+
258
+ act = bpf_prog_run_xdp (rcpu -> prog , & xdp );
259
+ switch (act ) {
260
+ case XDP_PASS :
261
+ err = xdp_update_frame_from_buff (& xdp , xdpf );
262
+ if (err < 0 ) {
263
+ xdp_return_frame (xdpf );
264
+ stats -> drop ++ ;
265
+ } else {
266
+ frames [nframes ++ ] = xdpf ;
267
+ stats -> pass ++ ;
268
+ }
269
+ break ;
270
+ default :
271
+ bpf_warn_invalid_xdp_action (act );
272
+ /* fallthrough */
273
+ case XDP_DROP :
274
+ xdp_return_frame (xdpf );
275
+ stats -> drop ++ ;
276
+ break ;
277
+ }
278
+ }
279
+
280
+ xdp_clear_return_frame_no_direct ();
281
+
282
+ rcu_read_unlock ();
283
+
284
+ return nframes ;
285
+ }
286
+
225
287
#define CPUMAP_BATCH 8
226
288
227
289
static int cpu_map_kthread_run (void * data )
@@ -236,11 +298,12 @@ static int cpu_map_kthread_run(void *data)
236
298
* kthread_stop signal until queue is empty.
237
299
*/
238
300
while (!kthread_should_stop () || !__ptr_ring_empty (rcpu -> queue )) {
301
+ struct xdp_cpumap_stats stats = {}; /* zero stats */
302
+ gfp_t gfp = __GFP_ZERO | GFP_ATOMIC ;
239
303
unsigned int drops = 0 , sched = 0 ;
240
304
void * frames [CPUMAP_BATCH ];
241
305
void * skbs [CPUMAP_BATCH ];
242
- gfp_t gfp = __GFP_ZERO | GFP_ATOMIC ;
243
- int i , n , m ;
306
+ int i , n , m , nframes ;
244
307
245
308
/* Release CPU reschedule checks */
246
309
if (__ptr_ring_empty (rcpu -> queue )) {
@@ -261,8 +324,8 @@ static int cpu_map_kthread_run(void *data)
261
324
* kthread CPU pinned. Lockless access to ptr_ring
262
325
* consume side valid as no-resize allowed of queue.
263
326
*/
264
- n = __ptr_ring_consume_batched (rcpu -> queue , frames , CPUMAP_BATCH );
265
-
327
+ n = __ptr_ring_consume_batched (rcpu -> queue , frames ,
328
+ CPUMAP_BATCH );
266
329
for (i = 0 ; i < n ; i ++ ) {
267
330
void * f = frames [i ];
268
331
struct page * page = virt_to_page (f );
@@ -274,15 +337,19 @@ static int cpu_map_kthread_run(void *data)
274
337
prefetchw (page );
275
338
}
276
339
277
- m = kmem_cache_alloc_bulk (skbuff_head_cache , gfp , n , skbs );
278
- if (unlikely (m == 0 )) {
279
- for (i = 0 ; i < n ; i ++ )
280
- skbs [i ] = NULL ; /* effect: xdp_return_frame */
281
- drops = n ;
340
+ /* Support running another XDP prog on this CPU */
341
+ nframes = cpu_map_bpf_prog_run_xdp (rcpu , frames , n , & stats );
342
+ if (nframes ) {
343
+ m = kmem_cache_alloc_bulk (skbuff_head_cache , gfp , nframes , skbs );
344
+ if (unlikely (m == 0 )) {
345
+ for (i = 0 ; i < nframes ; i ++ )
346
+ skbs [i ] = NULL ; /* effect: xdp_return_frame */
347
+ drops += nframes ;
348
+ }
282
349
}
283
350
284
351
local_bh_disable ();
285
- for (i = 0 ; i < n ; i ++ ) {
352
+ for (i = 0 ; i < nframes ; i ++ ) {
286
353
struct xdp_frame * xdpf = frames [i ];
287
354
struct sk_buff * skb = skbs [i ];
288
355
int ret ;
@@ -299,7 +366,7 @@ static int cpu_map_kthread_run(void *data)
299
366
drops ++ ;
300
367
}
301
368
/* Feedback loop via tracepoint */
302
- trace_xdp_cpumap_kthread (rcpu -> map_id , n , drops , sched );
369
+ trace_xdp_cpumap_kthread (rcpu -> map_id , n , drops , sched , & stats );
303
370
304
371
local_bh_enable (); /* resched point, may call do_softirq() */
305
372
}
@@ -309,13 +376,38 @@ static int cpu_map_kthread_run(void *data)
309
376
return 0 ;
310
377
}
311
378
379
+ bool cpu_map_prog_allowed (struct bpf_map * map )
380
+ {
381
+ return map -> map_type == BPF_MAP_TYPE_CPUMAP &&
382
+ map -> value_size != offsetofend (struct bpf_cpumap_val , qsize );
383
+ }
384
+
385
+ static int __cpu_map_load_bpf_program (struct bpf_cpu_map_entry * rcpu , int fd )
386
+ {
387
+ struct bpf_prog * prog ;
388
+
389
+ prog = bpf_prog_get_type (fd , BPF_PROG_TYPE_XDP );
390
+ if (IS_ERR (prog ))
391
+ return PTR_ERR (prog );
392
+
393
+ if (prog -> expected_attach_type != BPF_XDP_CPUMAP ) {
394
+ bpf_prog_put (prog );
395
+ return - EINVAL ;
396
+ }
397
+
398
+ rcpu -> value .bpf_prog .id = prog -> aux -> id ;
399
+ rcpu -> prog = prog ;
400
+
401
+ return 0 ;
402
+ }
403
+
312
404
static struct bpf_cpu_map_entry *
313
405
__cpu_map_entry_alloc (struct bpf_cpumap_val * value , u32 cpu , int map_id )
314
406
{
407
+ int numa , err , i , fd = value -> bpf_prog .fd ;
315
408
gfp_t gfp = GFP_KERNEL | __GFP_NOWARN ;
316
409
struct bpf_cpu_map_entry * rcpu ;
317
410
struct xdp_bulk_queue * bq ;
318
- int numa , err , i ;
319
411
320
412
/* Have map->numa_node, but choose node of redirect target CPU */
321
413
numa = cpu_to_node (cpu );
@@ -357,6 +449,9 @@ __cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
357
449
get_cpu_map_entry (rcpu ); /* 1-refcnt for being in cmap->cpu_map[] */
358
450
get_cpu_map_entry (rcpu ); /* 1-refcnt for kthread */
359
451
452
+ if (fd > 0 && __cpu_map_load_bpf_program (rcpu , fd ))
453
+ goto free_ptr_ring ;
454
+
360
455
/* Make sure kthread runs on a single CPU */
361
456
kthread_bind (rcpu -> kthread , cpu );
362
457
wake_up_process (rcpu -> kthread );
0 commit comments