@@ -129,7 +129,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
129129
130130static struct tcf_proto * tcf_proto_create (const char * kind , u32 protocol ,
131131 u32 prio , u32 parent , struct Qdisc * q ,
132- struct tcf_block * block )
132+ struct tcf_chain * chain )
133133{
134134 struct tcf_proto * tp ;
135135 int err ;
@@ -165,7 +165,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
165165 tp -> prio = prio ;
166166 tp -> classid = parent ;
167167 tp -> q = q ;
168- tp -> block = block ;
168+ tp -> chain = chain ;
169169
170170 err = tp -> ops -> init (tp );
171171 if (err ) {
@@ -186,22 +186,57 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
186186 kfree_rcu (tp , rcu );
187187}
188188
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 )
190191{
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 ;
192202}
193203
194204static void tcf_chain_destroy (struct tcf_chain * chain )
195205{
196206 struct tcf_proto * tp ;
197207
208+ list_del (& chain -> list );
198209 while ((tp = rtnl_dereference (chain -> filter_chain )) != NULL ) {
199210 RCU_INIT_POINTER (chain -> filter_chain , tp -> next );
200211 tcf_proto_destroy (tp );
201212 }
202213 kfree (chain );
203214}
204215
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+
205240static void
206241tcf_chain_filter_chain_ptr_set (struct tcf_chain * chain ,
207242 struct tcf_proto __rcu * * p_filter_chain )
@@ -213,16 +248,19 @@ int tcf_block_get(struct tcf_block **p_block,
213248 struct tcf_proto __rcu * * p_filter_chain )
214249{
215250 struct tcf_block * block = kzalloc (sizeof (* block ), GFP_KERNEL );
251+ struct tcf_chain * chain ;
216252 int err ;
217253
218254 if (!block )
219255 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 ) {
222260 err = - ENOMEM ;
223261 goto err_chain_create ;
224262 }
225- tcf_chain_filter_chain_ptr_set (block -> chain , p_filter_chain );
263+ tcf_chain_filter_chain_ptr_set (chain , p_filter_chain );
226264 * p_block = block ;
227265 return 0 ;
228266
@@ -234,9 +272,13 @@ EXPORT_SYMBOL(tcf_block_get);
234272
235273void tcf_block_put (struct tcf_block * block )
236274{
275+ struct tcf_chain * chain , * tmp ;
276+
237277 if (!block )
238278 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 );
240282 kfree (block );
241283}
242284EXPORT_SYMBOL (tcf_block_put );
@@ -360,10 +402,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
360402 u32 prio ;
361403 bool prio_allocate ;
362404 u32 parent ;
405+ u32 chain_index ;
363406 struct net_device * dev ;
364407 struct Qdisc * q ;
365408 struct tcf_chain_info chain_info ;
366- struct tcf_chain * chain ;
409+ struct tcf_chain * chain = NULL ;
367410 struct tcf_block * block ;
368411 struct tcf_proto * tp ;
369412 const struct Qdisc_class_ops * cops ;
@@ -449,7 +492,17 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
449492 err = - EINVAL ;
450493 goto errout ;
451494 }
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+ }
453506
454507 if (n -> nlmsg_type == RTM_DELTFILTER && prio == 0 ) {
455508 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,
483536 prio = tcf_auto_prio (tcf_chain_tp_prev (& chain_info ));
484537
485538 tp = tcf_proto_create (nla_data (tca [TCA_KIND ]),
486- protocol , prio , parent , q , block );
539+ protocol , prio , parent , q , chain );
487540 if (IS_ERR (tp )) {
488541 err = PTR_ERR (tp );
489542 goto errout ;
@@ -556,6 +609,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
556609 }
557610
558611errout :
612+ if (chain )
613+ tcf_chain_put (chain );
559614 if (cl )
560615 cops -> put (q , cl );
561616 if (err == - EAGAIN )
@@ -584,6 +639,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
584639 tcm -> tcm_info = TC_H_MAKE (tp -> prio , tp -> protocol );
585640 if (nla_put_string (skb , TCA_KIND , tp -> ops -> kind ))
586641 goto nla_put_failure ;
642+ if (nla_put_u32 (skb , TCA_CHAIN , tp -> chain -> index ))
643+ goto nla_put_failure ;
587644 tcm -> tcm_handle = fh ;
588645 if (RTM_DELTFILTER != event ) {
589646 tcm -> tcm_handle = 0 ;
@@ -640,7 +697,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
640697 RTM_NEWTFILTER );
641698}
642699
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 ,
644701 struct netlink_callback * cb ,
645702 long index_start , long * p_index )
646703{
@@ -667,7 +724,7 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
667724 NETLINK_CB (cb -> skb ).portid ,
668725 cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
669726 RTM_NEWTFILTER ) <= 0 )
670- break ;
727+ return false ;
671728
672729 cb -> args [1 ] = 1 ;
673730 }
@@ -682,14 +739,16 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
682739 tp -> ops -> walk (tp , & arg .w );
683740 cb -> args [1 ] = arg .w .count + 1 ;
684741 if (arg .w .stop )
685- break ;
742+ return false ;
686743 }
744+ return true;
687745}
688746
689747/* called with RTNL */
690748static int tc_dump_tfilter (struct sk_buff * skb , struct netlink_callback * cb )
691749{
692750 struct net * net = sock_net (skb -> sk );
751+ struct nlattr * tca [TCA_MAX + 1 ];
693752 struct net_device * dev ;
694753 struct Qdisc * q ;
695754 struct tcf_block * block ;
@@ -699,9 +758,15 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
699758 const struct Qdisc_class_ops * cops ;
700759 long index_start ;
701760 long index ;
761+ int err ;
702762
703763 if (nlmsg_len (cb -> nlh ) < sizeof (* tcm ))
704764 return skb -> len ;
765+
766+ err = nlmsg_parse (cb -> nlh , sizeof (* tcm ), tca , TCA_MAX , NULL , NULL );
767+ if (err )
768+ return err ;
769+
705770 dev = __dev_get_by_index (net , tcm -> tcm_ifindex );
706771 if (!dev )
707772 return skb -> len ;
@@ -725,11 +790,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
725790 block = cops -> tcf_block (q , cl );
726791 if (!block )
727792 goto errout ;
728- chain = block -> chain ;
729793
730794 index_start = cb -> args [0 ];
731795 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+
733805 cb -> args [0 ] = index ;
734806
735807errout :
0 commit comments