17
17
#include <linux/skbuff.h>
18
18
#include <linux/filter.h>
19
19
#include <linux/bpf.h>
20
+ #include <linux/idr.h>
20
21
21
22
#include <net/rtnetlink.h>
22
23
#include <net/pkt_cls.h>
@@ -32,7 +33,7 @@ MODULE_DESCRIPTION("TC BPF based classifier");
32
33
33
34
struct cls_bpf_head {
34
35
struct list_head plist ;
35
- u32 hgen ;
36
+ struct idr handle_idr ;
36
37
struct rcu_head rcu ;
37
38
};
38
39
@@ -238,6 +239,7 @@ static int cls_bpf_init(struct tcf_proto *tp)
238
239
return - ENOBUFS ;
239
240
240
241
INIT_LIST_HEAD_RCU (& head -> plist );
242
+ idr_init (& head -> handle_idr );
241
243
rcu_assign_pointer (tp -> root , head );
242
244
243
245
return 0 ;
@@ -264,6 +266,9 @@ static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
264
266
265
267
static void __cls_bpf_delete (struct tcf_proto * tp , struct cls_bpf_prog * prog )
266
268
{
269
+ struct cls_bpf_head * head = rtnl_dereference (tp -> root );
270
+
271
+ idr_remove_ext (& head -> handle_idr , prog -> handle );
267
272
cls_bpf_stop_offload (tp , prog );
268
273
list_del_rcu (& prog -> link );
269
274
tcf_unbind_filter (tp , & prog -> res );
@@ -287,6 +292,7 @@ static void cls_bpf_destroy(struct tcf_proto *tp)
287
292
list_for_each_entry_safe (prog , tmp , & head -> plist , link )
288
293
__cls_bpf_delete (tp , prog );
289
294
295
+ idr_destroy (& head -> handle_idr );
290
296
kfree_rcu (head , rcu );
291
297
}
292
298
@@ -421,27 +427,6 @@ static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp,
421
427
return 0 ;
422
428
}
423
429
424
- static u32 cls_bpf_grab_new_handle (struct tcf_proto * tp ,
425
- struct cls_bpf_head * head )
426
- {
427
- unsigned int i = 0x80000000 ;
428
- u32 handle ;
429
-
430
- do {
431
- if (++ head -> hgen == 0x7FFFFFFF )
432
- head -> hgen = 1 ;
433
- } while (-- i > 0 && cls_bpf_get (tp , head -> hgen ));
434
-
435
- if (unlikely (i == 0 )) {
436
- pr_err ("Insufficient number of handles\n" );
437
- handle = 0 ;
438
- } else {
439
- handle = head -> hgen ;
440
- }
441
-
442
- return handle ;
443
- }
444
-
445
430
static int cls_bpf_change (struct net * net , struct sk_buff * in_skb ,
446
431
struct tcf_proto * tp , unsigned long base ,
447
432
u32 handle , struct nlattr * * tca ,
@@ -451,6 +436,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
451
436
struct cls_bpf_prog * oldprog = * arg ;
452
437
struct nlattr * tb [TCA_BPF_MAX + 1 ];
453
438
struct cls_bpf_prog * prog ;
439
+ unsigned long idr_index ;
454
440
int ret ;
455
441
456
442
if (tca [TCA_OPTIONS ] == NULL )
@@ -476,21 +462,30 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
476
462
}
477
463
}
478
464
479
- if (handle == 0 )
480
- prog -> handle = cls_bpf_grab_new_handle (tp , head );
481
- else
465
+ if (handle == 0 ) {
466
+ ret = idr_alloc_ext (& head -> handle_idr , prog , & idr_index ,
467
+ 1 , 0x7FFFFFFF , GFP_KERNEL );
468
+ if (ret )
469
+ goto errout ;
470
+ prog -> handle = idr_index ;
471
+ } else {
472
+ if (!oldprog ) {
473
+ ret = idr_alloc_ext (& head -> handle_idr , prog , & idr_index ,
474
+ handle , handle + 1 , GFP_KERNEL );
475
+ if (ret )
476
+ goto errout ;
477
+ }
482
478
prog -> handle = handle ;
483
- if (prog -> handle == 0 ) {
484
- ret = - EINVAL ;
485
- goto errout ;
486
479
}
487
480
488
481
ret = cls_bpf_set_parms (net , tp , prog , base , tb , tca [TCA_RATE ], ovr );
489
482
if (ret < 0 )
490
- goto errout ;
483
+ goto errout_idr ;
491
484
492
485
ret = cls_bpf_offload (tp , prog , oldprog );
493
486
if (ret ) {
487
+ if (!oldprog )
488
+ idr_remove_ext (& head -> handle_idr , prog -> handle );
494
489
__cls_bpf_delete_prog (prog );
495
490
return ret ;
496
491
}
@@ -499,6 +494,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
499
494
prog -> gen_flags |= TCA_CLS_FLAGS_NOT_IN_HW ;
500
495
501
496
if (oldprog ) {
497
+ idr_replace_ext (& head -> handle_idr , prog , handle );
502
498
list_replace_rcu (& oldprog -> link , & prog -> link );
503
499
tcf_unbind_filter (tp , & oldprog -> res );
504
500
call_rcu (& oldprog -> rcu , cls_bpf_delete_prog_rcu );
@@ -509,6 +505,9 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
509
505
* arg = prog ;
510
506
return 0 ;
511
507
508
+ errout_idr :
509
+ if (!oldprog )
510
+ idr_remove_ext (& head -> handle_idr , prog -> handle );
512
511
errout :
513
512
tcf_exts_destroy (& prog -> exts );
514
513
kfree (prog );
0 commit comments