@@ -865,8 +865,9 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
865865}
866866
867867static int tcf_fill_node (struct net * net , struct sk_buff * skb ,
868- struct tcf_proto * tp , struct Qdisc * q , u32 parent ,
869- void * fh , u32 portid , u32 seq , u16 flags , int event )
868+ struct tcf_proto * tp , struct tcf_block * block ,
869+ struct Qdisc * q , u32 parent , void * fh ,
870+ u32 portid , u32 seq , u16 flags , int event )
870871{
871872 struct tcmsg * tcm ;
872873 struct nlmsghdr * nlh ;
@@ -879,8 +880,13 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
879880 tcm -> tcm_family = AF_UNSPEC ;
880881 tcm -> tcm__pad1 = 0 ;
881882 tcm -> tcm__pad2 = 0 ;
882- tcm -> tcm_ifindex = qdisc_dev (q )-> ifindex ;
883- tcm -> tcm_parent = parent ;
883+ if (q ) {
884+ tcm -> tcm_ifindex = qdisc_dev (q )-> ifindex ;
885+ tcm -> tcm_parent = parent ;
886+ } else {
887+ tcm -> tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK ;
888+ tcm -> tcm_block_index = block -> index ;
889+ }
884890 tcm -> tcm_info = TC_H_MAKE (tp -> prio , tp -> protocol );
885891 if (nla_put_string (skb , TCA_KIND , tp -> ops -> kind ))
886892 goto nla_put_failure ;
@@ -903,8 +909,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
903909
904910static int tfilter_notify (struct net * net , struct sk_buff * oskb ,
905911 struct nlmsghdr * n , struct tcf_proto * tp ,
906- struct Qdisc * q , u32 parent ,
907- void * fh , int event , bool unicast )
912+ struct tcf_block * block , struct Qdisc * q ,
913+ u32 parent , void * fh , int event , bool unicast )
908914{
909915 struct sk_buff * skb ;
910916 u32 portid = oskb ? NETLINK_CB (oskb ).portid : 0 ;
@@ -913,8 +919,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
913919 if (!skb )
914920 return - ENOBUFS ;
915921
916- if (tcf_fill_node (net , skb , tp , q , parent , fh , portid , n -> nlmsg_seq ,
917- n -> nlmsg_flags , event ) <= 0 ) {
922+ if (tcf_fill_node (net , skb , tp , block , q , parent , fh , portid ,
923+ n -> nlmsg_seq , n -> nlmsg_flags , event ) <= 0 ) {
918924 kfree_skb (skb );
919925 return - EINVAL ;
920926 }
@@ -928,8 +934,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
928934
929935static int tfilter_del_notify (struct net * net , struct sk_buff * oskb ,
930936 struct nlmsghdr * n , struct tcf_proto * tp ,
931- struct Qdisc * q , u32 parent ,
932- void * fh , bool unicast , bool * last )
937+ struct tcf_block * block , struct Qdisc * q ,
938+ u32 parent , void * fh , bool unicast , bool * last )
933939{
934940 struct sk_buff * skb ;
935941 u32 portid = oskb ? NETLINK_CB (oskb ).portid : 0 ;
@@ -939,8 +945,8 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
939945 if (!skb )
940946 return - ENOBUFS ;
941947
942- if (tcf_fill_node (net , skb , tp , q , parent , fh , portid , n -> nlmsg_seq ,
943- n -> nlmsg_flags , RTM_DELTFILTER ) <= 0 ) {
948+ if (tcf_fill_node (net , skb , tp , block , q , parent , fh , portid ,
949+ n -> nlmsg_seq , n -> nlmsg_flags , RTM_DELTFILTER ) <= 0 ) {
944950 kfree_skb (skb );
945951 return - EINVAL ;
946952 }
@@ -959,15 +965,16 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
959965}
960966
961967static void tfilter_notify_chain (struct net * net , struct sk_buff * oskb ,
962- struct Qdisc * q , u32 parent ,
963- struct nlmsghdr * n ,
968+ struct tcf_block * block , struct Qdisc * q ,
969+ u32 parent , struct nlmsghdr * n ,
964970 struct tcf_chain * chain , int event )
965971{
966972 struct tcf_proto * tp ;
967973
968974 for (tp = rtnl_dereference (chain -> filter_chain );
969975 tp ; tp = rtnl_dereference (tp -> next ))
970- tfilter_notify (net , oskb , n , tp , q , parent , 0 , event , false);
976+ tfilter_notify (net , oskb , n , tp , block ,
977+ q , parent , 0 , event , false);
971978}
972979
973980/* Add/change/delete/get a filter node */
@@ -983,13 +990,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
983990 bool prio_allocate ;
984991 u32 parent ;
985992 u32 chain_index ;
986- struct net_device * dev ;
987- struct Qdisc * q ;
993+ struct Qdisc * q = NULL ;
988994 struct tcf_chain_info chain_info ;
989995 struct tcf_chain * chain = NULL ;
990996 struct tcf_block * block ;
991997 struct tcf_proto * tp ;
992- const struct Qdisc_class_ops * cops ;
993998 unsigned long cl ;
994999 void * fh ;
9951000 int err ;
@@ -1036,41 +1041,58 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
10361041
10371042 /* Find head of filter chain. */
10381043
1039- /* Find link */
1040- dev = __dev_get_by_index (net , t -> tcm_ifindex );
1041- if (dev == NULL )
1042- return - ENODEV ;
1043-
1044- /* Find qdisc */
1045- if (!parent ) {
1046- q = dev -> qdisc ;
1047- parent = q -> handle ;
1044+ if (t -> tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK ) {
1045+ block = tcf_block_lookup (net , t -> tcm_block_index );
1046+ if (!block ) {
1047+ NL_SET_ERR_MSG (extack , "Block of given index was not found" );
1048+ err = - EINVAL ;
1049+ goto errout ;
1050+ }
10481051 } else {
1049- q = qdisc_lookup (dev , TC_H_MAJ (t -> tcm_parent ));
1050- if (q == NULL )
1051- return - EINVAL ;
1052- }
1052+ const struct Qdisc_class_ops * cops ;
1053+ struct net_device * dev ;
10531054
1054- /* Is it classful? */
1055- cops = q -> ops -> cl_ops ;
1056- if (!cops )
1057- return - EINVAL ;
1055+ /* Find link */
1056+ dev = __dev_get_by_index ( net , t -> tcm_ifindex ) ;
1057+ if (!dev )
1058+ return - ENODEV ;
10581059
1059- if (!cops -> tcf_block )
1060- return - EOPNOTSUPP ;
1060+ /* Find qdisc */
1061+ if (!parent ) {
1062+ q = dev -> qdisc ;
1063+ parent = q -> handle ;
1064+ } else {
1065+ q = qdisc_lookup (dev , TC_H_MAJ (t -> tcm_parent ));
1066+ if (!q )
1067+ return - EINVAL ;
1068+ }
10611069
1062- /* Do we search for filter, attached to class? */
1063- if (TC_H_MIN (parent )) {
1064- cl = cops -> find (q , parent );
1065- if (cl == 0 )
1066- return - ENOENT ;
1067- }
1070+ /* Is it classful? */
1071+ cops = q -> ops -> cl_ops ;
1072+ if (!cops )
1073+ return - EINVAL ;
10681074
1069- /* And the last stroke */
1070- block = cops -> tcf_block (q , cl , extack );
1071- if (!block ) {
1072- err = - EINVAL ;
1073- goto errout ;
1075+ if (!cops -> tcf_block )
1076+ return - EOPNOTSUPP ;
1077+
1078+ /* Do we search for filter, attached to class? */
1079+ if (TC_H_MIN (parent )) {
1080+ cl = cops -> find (q , parent );
1081+ if (cl == 0 )
1082+ return - ENOENT ;
1083+ }
1084+
1085+ /* And the last stroke */
1086+ block = cops -> tcf_block (q , cl , extack );
1087+ if (!block ) {
1088+ err = - EINVAL ;
1089+ goto errout ;
1090+ }
1091+ if (tcf_block_shared (block )) {
1092+ NL_SET_ERR_MSG (extack , "This filter block is shared. Please use the block index to manipulate the filters" );
1093+ err = - EOPNOTSUPP ;
1094+ goto errout ;
1095+ }
10741096 }
10751097
10761098 chain_index = tca [TCA_CHAIN ] ? nla_get_u32 (tca [TCA_CHAIN ]) : 0 ;
@@ -1086,7 +1108,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
10861108 }
10871109
10881110 if (n -> nlmsg_type == RTM_DELTFILTER && prio == 0 ) {
1089- tfilter_notify_chain (net , skb , q , parent , n ,
1111+ tfilter_notify_chain (net , skb , block , q , parent , n ,
10901112 chain , RTM_DELTFILTER );
10911113 tcf_chain_flush (chain );
10921114 err = 0 ;
@@ -1134,7 +1156,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
11341156 if (!fh ) {
11351157 if (n -> nlmsg_type == RTM_DELTFILTER && t -> tcm_handle == 0 ) {
11361158 tcf_chain_tp_remove (chain , & chain_info , tp );
1137- tfilter_notify (net , skb , n , tp , q , parent , fh ,
1159+ tfilter_notify (net , skb , n , tp , block , q , parent , fh ,
11381160 RTM_DELTFILTER , false);
11391161 tcf_proto_destroy (tp );
11401162 err = 0 ;
@@ -1159,8 +1181,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
11591181 }
11601182 break ;
11611183 case RTM_DELTFILTER :
1162- err = tfilter_del_notify (net , skb , n , tp , q , parent ,
1163- fh , false, & last );
1184+ err = tfilter_del_notify (net , skb , n , tp , block ,
1185+ q , parent , fh , false, & last );
11641186 if (err )
11651187 goto errout ;
11661188 if (last ) {
@@ -1169,8 +1191,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
11691191 }
11701192 goto errout ;
11711193 case RTM_GETTFILTER :
1172- err = tfilter_notify (net , skb , n , tp , q , parent , fh ,
1173- RTM_NEWTFILTER , true);
1194+ err = tfilter_notify (net , skb , n , tp , block , q , parent ,
1195+ fh , RTM_NEWTFILTER , true);
11741196 goto errout ;
11751197 default :
11761198 err = - EINVAL ;
@@ -1183,7 +1205,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
11831205 if (err == 0 ) {
11841206 if (tp_created )
11851207 tcf_chain_tp_insert (chain , & chain_info , tp );
1186- tfilter_notify (net , skb , n , tp , q , parent , fh ,
1208+ tfilter_notify (net , skb , n , tp , block , q , parent , fh ,
11871209 RTM_NEWTFILTER , false);
11881210 } else {
11891211 if (tp_created )
@@ -1203,6 +1225,7 @@ struct tcf_dump_args {
12031225 struct tcf_walker w ;
12041226 struct sk_buff * skb ;
12051227 struct netlink_callback * cb ;
1228+ struct tcf_block * block ;
12061229 struct Qdisc * q ;
12071230 u32 parent ;
12081231};
@@ -1212,7 +1235,7 @@ static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
12121235 struct tcf_dump_args * a = (void * )arg ;
12131236 struct net * net = sock_net (a -> skb -> sk );
12141237
1215- return tcf_fill_node (net , a -> skb , tp , a -> q , a -> parent ,
1238+ return tcf_fill_node (net , a -> skb , tp , a -> block , a -> q , a -> parent ,
12161239 n , NETLINK_CB (a -> cb -> skb ).portid ,
12171240 a -> cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
12181241 RTM_NEWTFILTER );
@@ -1223,6 +1246,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
12231246 long index_start , long * p_index )
12241247{
12251248 struct net * net = sock_net (skb -> sk );
1249+ struct tcf_block * block = chain -> block ;
12261250 struct tcmsg * tcm = nlmsg_data (cb -> nlh );
12271251 struct tcf_dump_args arg ;
12281252 struct tcf_proto * tp ;
@@ -1241,7 +1265,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
12411265 memset (& cb -> args [1 ], 0 ,
12421266 sizeof (cb -> args ) - sizeof (cb -> args [0 ]));
12431267 if (cb -> args [1 ] == 0 ) {
1244- if (tcf_fill_node (net , skb , tp , q , parent , 0 ,
1268+ if (tcf_fill_node (net , skb , tp , block , q , parent , 0 ,
12451269 NETLINK_CB (cb -> skb ).portid ,
12461270 cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
12471271 RTM_NEWTFILTER ) <= 0 )
@@ -1254,6 +1278,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
12541278 arg .w .fn = tcf_node_dump ;
12551279 arg .skb = skb ;
12561280 arg .cb = cb ;
1281+ arg .block = block ;
12571282 arg .q = q ;
12581283 arg .parent = parent ;
12591284 arg .w .stop = 0 ;
@@ -1272,13 +1297,10 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
12721297{
12731298 struct net * net = sock_net (skb -> sk );
12741299 struct nlattr * tca [TCA_MAX + 1 ];
1275- struct net_device * dev ;
1276- struct Qdisc * q ;
1300+ struct Qdisc * q = NULL ;
12771301 struct tcf_block * block ;
12781302 struct tcf_chain * chain ;
12791303 struct tcmsg * tcm = nlmsg_data (cb -> nlh );
1280- unsigned long cl = 0 ;
1281- const struct Qdisc_class_ops * cops ;
12821304 long index_start ;
12831305 long index ;
12841306 u32 parent ;
@@ -1291,32 +1313,44 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
12911313 if (err )
12921314 return err ;
12931315
1294- dev = __dev_get_by_index (net , tcm -> tcm_ifindex );
1295- if (!dev )
1296- return skb -> len ;
1297-
1298- parent = tcm -> tcm_parent ;
1299- if (!parent ) {
1300- q = dev -> qdisc ;
1301- parent = q -> handle ;
1316+ if (tcm -> tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK ) {
1317+ block = tcf_block_lookup (net , tcm -> tcm_block_index );
1318+ if (!block )
1319+ goto out ;
13021320 } else {
1303- q = qdisc_lookup (dev , TC_H_MAJ (tcm -> tcm_parent ));
1304- }
1305- if (!q )
1306- goto out ;
1307- cops = q -> ops -> cl_ops ;
1308- if (!cops )
1309- goto out ;
1310- if (!cops -> tcf_block )
1311- goto out ;
1312- if (TC_H_MIN (tcm -> tcm_parent )) {
1313- cl = cops -> find (q , tcm -> tcm_parent );
1314- if (cl == 0 )
1321+ const struct Qdisc_class_ops * cops ;
1322+ struct net_device * dev ;
1323+ unsigned long cl = 0 ;
1324+
1325+ dev = __dev_get_by_index (net , tcm -> tcm_ifindex );
1326+ if (!dev )
1327+ return skb -> len ;
1328+
1329+ parent = tcm -> tcm_parent ;
1330+ if (!parent ) {
1331+ q = dev -> qdisc ;
1332+ parent = q -> handle ;
1333+ } else {
1334+ q = qdisc_lookup (dev , TC_H_MAJ (tcm -> tcm_parent ));
1335+ }
1336+ if (!q )
13151337 goto out ;
1338+ cops = q -> ops -> cl_ops ;
1339+ if (!cops )
1340+ goto out ;
1341+ if (!cops -> tcf_block )
1342+ goto out ;
1343+ if (TC_H_MIN (tcm -> tcm_parent )) {
1344+ cl = cops -> find (q , tcm -> tcm_parent );
1345+ if (cl == 0 )
1346+ goto out ;
1347+ }
1348+ block = cops -> tcf_block (q , cl , NULL );
1349+ if (!block )
1350+ goto out ;
1351+ if (tcf_block_shared (block ))
1352+ q = NULL ;
13161353 }
1317- block = cops -> tcf_block (q , cl , NULL );
1318- if (!block )
1319- goto out ;
13201354
13211355 index_start = cb -> args [0 ];
13221356 index = 0 ;
0 commit comments