@@ -129,7 +129,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
129
129
130
130
static struct tcf_proto * tcf_proto_create (const char * kind , u32 protocol ,
131
131
u32 prio , u32 parent , struct Qdisc * q ,
132
- struct tcf_block * block )
132
+ struct tcf_chain * chain )
133
133
{
134
134
struct tcf_proto * tp ;
135
135
int err ;
@@ -165,7 +165,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
165
165
tp -> prio = prio ;
166
166
tp -> classid = parent ;
167
167
tp -> q = q ;
168
- tp -> block = block ;
168
+ tp -> chain = chain ;
169
169
170
170
err = tp -> ops -> init (tp );
171
171
if (err ) {
@@ -186,22 +186,57 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
186
186
kfree_rcu (tp , rcu );
187
187
}
188
188
189
- static struct tcf_chain * tcf_chain_create (void )
189
+ static struct tcf_chain * tcf_chain_create (struct tcf_block * block ,
190
+ u32 chain_index )
190
191
{
191
- return kzalloc (sizeof (struct tcf_chain ), GFP_KERNEL );
192
+ struct tcf_chain * chain ;
193
+
194
+ chain = kzalloc (sizeof (* chain ), GFP_KERNEL );
195
+ if (!chain )
196
+ return NULL ;
197
+ list_add_tail (& chain -> list , & block -> chain_list );
198
+ chain -> block = block ;
199
+ chain -> index = chain_index ;
200
+ chain -> refcnt = 1 ;
201
+ return chain ;
192
202
}
193
203
194
204
static void tcf_chain_destroy (struct tcf_chain * chain )
195
205
{
196
206
struct tcf_proto * tp ;
197
207
208
+ list_del (& chain -> list );
198
209
while ((tp = rtnl_dereference (chain -> filter_chain )) != NULL ) {
199
210
RCU_INIT_POINTER (chain -> filter_chain , tp -> next );
200
211
tcf_proto_destroy (tp );
201
212
}
202
213
kfree (chain );
203
214
}
204
215
216
+ struct tcf_chain * tcf_chain_get (struct tcf_block * block , u32 chain_index )
217
+ {
218
+ struct tcf_chain * chain ;
219
+
220
+ list_for_each_entry (chain , & block -> chain_list , list ) {
221
+ if (chain -> index == chain_index ) {
222
+ chain -> refcnt ++ ;
223
+ return chain ;
224
+ }
225
+ }
226
+ return tcf_chain_create (block , chain_index );
227
+ }
228
+ EXPORT_SYMBOL (tcf_chain_get );
229
+
230
+ void tcf_chain_put (struct tcf_chain * chain )
231
+ {
232
+ /* Destroy unused chain, with exception of chain 0, which is the
233
+ * default one and has to be always present.
234
+ */
235
+ if (-- chain -> refcnt == 0 && !chain -> filter_chain && chain -> index != 0 )
236
+ tcf_chain_destroy (chain );
237
+ }
238
+ EXPORT_SYMBOL (tcf_chain_put );
239
+
205
240
static void
206
241
tcf_chain_filter_chain_ptr_set (struct tcf_chain * chain ,
207
242
struct tcf_proto __rcu * * p_filter_chain )
@@ -213,16 +248,19 @@ int tcf_block_get(struct tcf_block **p_block,
213
248
struct tcf_proto __rcu * * p_filter_chain )
214
249
{
215
250
struct tcf_block * block = kzalloc (sizeof (* block ), GFP_KERNEL );
251
+ struct tcf_chain * chain ;
216
252
int err ;
217
253
218
254
if (!block )
219
255
return - ENOMEM ;
220
- block -> chain = tcf_chain_create ();
221
- if (!block -> chain ) {
256
+ INIT_LIST_HEAD (& block -> chain_list );
257
+ /* Create chain 0 by default, it has to be always present. */
258
+ chain = tcf_chain_create (block , 0 );
259
+ if (!chain ) {
222
260
err = - ENOMEM ;
223
261
goto err_chain_create ;
224
262
}
225
- tcf_chain_filter_chain_ptr_set (block -> chain , p_filter_chain );
263
+ tcf_chain_filter_chain_ptr_set (chain , p_filter_chain );
226
264
* p_block = block ;
227
265
return 0 ;
228
266
@@ -234,9 +272,13 @@ EXPORT_SYMBOL(tcf_block_get);
234
272
235
273
void tcf_block_put (struct tcf_block * block )
236
274
{
275
+ struct tcf_chain * chain , * tmp ;
276
+
237
277
if (!block )
238
278
return ;
239
- tcf_chain_destroy (block -> chain );
279
+
280
+ list_for_each_entry_safe (chain , tmp , & block -> chain_list , list )
281
+ tcf_chain_destroy (chain );
240
282
kfree (block );
241
283
}
242
284
EXPORT_SYMBOL (tcf_block_put );
@@ -360,10 +402,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
360
402
u32 prio ;
361
403
bool prio_allocate ;
362
404
u32 parent ;
405
+ u32 chain_index ;
363
406
struct net_device * dev ;
364
407
struct Qdisc * q ;
365
408
struct tcf_chain_info chain_info ;
366
- struct tcf_chain * chain ;
409
+ struct tcf_chain * chain = NULL ;
367
410
struct tcf_block * block ;
368
411
struct tcf_proto * tp ;
369
412
const struct Qdisc_class_ops * cops ;
@@ -449,7 +492,17 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
449
492
err = - EINVAL ;
450
493
goto errout ;
451
494
}
452
- chain = block -> chain ;
495
+
496
+ chain_index = tca [TCA_CHAIN ] ? nla_get_u32 (tca [TCA_CHAIN ]) : 0 ;
497
+ if (chain_index > TC_ACT_EXT_VAL_MASK ) {
498
+ err = - EINVAL ;
499
+ goto errout ;
500
+ }
501
+ chain = tcf_chain_get (block , chain_index );
502
+ if (!chain ) {
503
+ err = - ENOMEM ;
504
+ goto errout ;
505
+ }
453
506
454
507
if (n -> nlmsg_type == RTM_DELTFILTER && prio == 0 ) {
455
508
tfilter_notify_chain (net , skb , n , chain , RTM_DELTFILTER );
@@ -483,7 +536,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
483
536
prio = tcf_auto_prio (tcf_chain_tp_prev (& chain_info ));
484
537
485
538
tp = tcf_proto_create (nla_data (tca [TCA_KIND ]),
486
- protocol , prio , parent , q , block );
539
+ protocol , prio , parent , q , chain );
487
540
if (IS_ERR (tp )) {
488
541
err = PTR_ERR (tp );
489
542
goto errout ;
@@ -556,6 +609,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
556
609
}
557
610
558
611
errout :
612
+ if (chain )
613
+ tcf_chain_put (chain );
559
614
if (cl )
560
615
cops -> put (q , cl );
561
616
if (err == - EAGAIN )
@@ -584,6 +639,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
584
639
tcm -> tcm_info = TC_H_MAKE (tp -> prio , tp -> protocol );
585
640
if (nla_put_string (skb , TCA_KIND , tp -> ops -> kind ))
586
641
goto nla_put_failure ;
642
+ if (nla_put_u32 (skb , TCA_CHAIN , tp -> chain -> index ))
643
+ goto nla_put_failure ;
587
644
tcm -> tcm_handle = fh ;
588
645
if (RTM_DELTFILTER != event ) {
589
646
tcm -> tcm_handle = 0 ;
@@ -640,7 +697,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
640
697
RTM_NEWTFILTER );
641
698
}
642
699
643
- static void tcf_chain_dump (struct tcf_chain * chain , struct sk_buff * skb ,
700
+ static bool tcf_chain_dump (struct tcf_chain * chain , struct sk_buff * skb ,
644
701
struct netlink_callback * cb ,
645
702
long index_start , long * p_index )
646
703
{
@@ -667,7 +724,7 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
667
724
NETLINK_CB (cb -> skb ).portid ,
668
725
cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
669
726
RTM_NEWTFILTER ) <= 0 )
670
- break ;
727
+ return false ;
671
728
672
729
cb -> args [1 ] = 1 ;
673
730
}
@@ -682,14 +739,16 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
682
739
tp -> ops -> walk (tp , & arg .w );
683
740
cb -> args [1 ] = arg .w .count + 1 ;
684
741
if (arg .w .stop )
685
- break ;
742
+ return false ;
686
743
}
744
+ return true;
687
745
}
688
746
689
747
/* called with RTNL */
690
748
static int tc_dump_tfilter (struct sk_buff * skb , struct netlink_callback * cb )
691
749
{
692
750
struct net * net = sock_net (skb -> sk );
751
+ struct nlattr * tca [TCA_MAX + 1 ];
693
752
struct net_device * dev ;
694
753
struct Qdisc * q ;
695
754
struct tcf_block * block ;
@@ -699,9 +758,15 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
699
758
const struct Qdisc_class_ops * cops ;
700
759
long index_start ;
701
760
long index ;
761
+ int err ;
702
762
703
763
if (nlmsg_len (cb -> nlh ) < sizeof (* tcm ))
704
764
return skb -> len ;
765
+
766
+ err = nlmsg_parse (cb -> nlh , sizeof (* tcm ), tca , TCA_MAX , NULL , NULL );
767
+ if (err )
768
+ return err ;
769
+
705
770
dev = __dev_get_by_index (net , tcm -> tcm_ifindex );
706
771
if (!dev )
707
772
return skb -> len ;
@@ -725,11 +790,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
725
790
block = cops -> tcf_block (q , cl );
726
791
if (!block )
727
792
goto errout ;
728
- chain = block -> chain ;
729
793
730
794
index_start = cb -> args [0 ];
731
795
index = 0 ;
732
- tcf_chain_dump (chain , skb , cb , index_start , & index );
796
+
797
+ list_for_each_entry (chain , & block -> chain_list , list ) {
798
+ if (tca [TCA_CHAIN ] &&
799
+ nla_get_u32 (tca [TCA_CHAIN ]) != chain -> index )
800
+ continue ;
801
+ if (!tcf_chain_dump (chain , skb , cb , index_start , & index ))
802
+ break ;
803
+ }
804
+
733
805
cb -> args [0 ] = index ;
734
806
735
807
errout :
0 commit comments