@@ -865,8 +865,9 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
865
865
}
866
866
867
867
static 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 )
870
871
{
871
872
struct tcmsg * tcm ;
872
873
struct nlmsghdr * nlh ;
@@ -879,8 +880,13 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
879
880
tcm -> tcm_family = AF_UNSPEC ;
880
881
tcm -> tcm__pad1 = 0 ;
881
882
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
+ }
884
890
tcm -> tcm_info = TC_H_MAKE (tp -> prio , tp -> protocol );
885
891
if (nla_put_string (skb , TCA_KIND , tp -> ops -> kind ))
886
892
goto nla_put_failure ;
@@ -903,8 +909,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
903
909
904
910
static int tfilter_notify (struct net * net , struct sk_buff * oskb ,
905
911
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 )
908
914
{
909
915
struct sk_buff * skb ;
910
916
u32 portid = oskb ? NETLINK_CB (oskb ).portid : 0 ;
@@ -913,8 +919,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
913
919
if (!skb )
914
920
return - ENOBUFS ;
915
921
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 ) {
918
924
kfree_skb (skb );
919
925
return - EINVAL ;
920
926
}
@@ -928,8 +934,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
928
934
929
935
static int tfilter_del_notify (struct net * net , struct sk_buff * oskb ,
930
936
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 )
933
939
{
934
940
struct sk_buff * skb ;
935
941
u32 portid = oskb ? NETLINK_CB (oskb ).portid : 0 ;
@@ -939,8 +945,8 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
939
945
if (!skb )
940
946
return - ENOBUFS ;
941
947
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 ) {
944
950
kfree_skb (skb );
945
951
return - EINVAL ;
946
952
}
@@ -959,15 +965,16 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
959
965
}
960
966
961
967
static 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 ,
964
970
struct tcf_chain * chain , int event )
965
971
{
966
972
struct tcf_proto * tp ;
967
973
968
974
for (tp = rtnl_dereference (chain -> filter_chain );
969
975
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);
971
978
}
972
979
973
980
/* Add/change/delete/get a filter node */
@@ -983,13 +990,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
983
990
bool prio_allocate ;
984
991
u32 parent ;
985
992
u32 chain_index ;
986
- struct net_device * dev ;
987
- struct Qdisc * q ;
993
+ struct Qdisc * q = NULL ;
988
994
struct tcf_chain_info chain_info ;
989
995
struct tcf_chain * chain = NULL ;
990
996
struct tcf_block * block ;
991
997
struct tcf_proto * tp ;
992
- const struct Qdisc_class_ops * cops ;
993
998
unsigned long cl ;
994
999
void * fh ;
995
1000
int err ;
@@ -1036,41 +1041,58 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1036
1041
1037
1042
/* Find head of filter chain. */
1038
1043
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
+ }
1048
1051
} 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 ;
1053
1054
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 ;
1058
1059
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
+ }
1061
1069
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 ;
1068
1074
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
+ }
1074
1096
}
1075
1097
1076
1098
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,
1086
1108
}
1087
1109
1088
1110
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 ,
1090
1112
chain , RTM_DELTFILTER );
1091
1113
tcf_chain_flush (chain );
1092
1114
err = 0 ;
@@ -1134,7 +1156,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1134
1156
if (!fh ) {
1135
1157
if (n -> nlmsg_type == RTM_DELTFILTER && t -> tcm_handle == 0 ) {
1136
1158
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 ,
1138
1160
RTM_DELTFILTER , false);
1139
1161
tcf_proto_destroy (tp );
1140
1162
err = 0 ;
@@ -1159,8 +1181,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1159
1181
}
1160
1182
break ;
1161
1183
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 );
1164
1186
if (err )
1165
1187
goto errout ;
1166
1188
if (last ) {
@@ -1169,8 +1191,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1169
1191
}
1170
1192
goto errout ;
1171
1193
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);
1174
1196
goto errout ;
1175
1197
default :
1176
1198
err = - EINVAL ;
@@ -1183,7 +1205,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
1183
1205
if (err == 0 ) {
1184
1206
if (tp_created )
1185
1207
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 ,
1187
1209
RTM_NEWTFILTER , false);
1188
1210
} else {
1189
1211
if (tp_created )
@@ -1203,6 +1225,7 @@ struct tcf_dump_args {
1203
1225
struct tcf_walker w ;
1204
1226
struct sk_buff * skb ;
1205
1227
struct netlink_callback * cb ;
1228
+ struct tcf_block * block ;
1206
1229
struct Qdisc * q ;
1207
1230
u32 parent ;
1208
1231
};
@@ -1212,7 +1235,7 @@ static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
1212
1235
struct tcf_dump_args * a = (void * )arg ;
1213
1236
struct net * net = sock_net (a -> skb -> sk );
1214
1237
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 ,
1216
1239
n , NETLINK_CB (a -> cb -> skb ).portid ,
1217
1240
a -> cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
1218
1241
RTM_NEWTFILTER );
@@ -1223,6 +1246,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
1223
1246
long index_start , long * p_index )
1224
1247
{
1225
1248
struct net * net = sock_net (skb -> sk );
1249
+ struct tcf_block * block = chain -> block ;
1226
1250
struct tcmsg * tcm = nlmsg_data (cb -> nlh );
1227
1251
struct tcf_dump_args arg ;
1228
1252
struct tcf_proto * tp ;
@@ -1241,7 +1265,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
1241
1265
memset (& cb -> args [1 ], 0 ,
1242
1266
sizeof (cb -> args ) - sizeof (cb -> args [0 ]));
1243
1267
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 ,
1245
1269
NETLINK_CB (cb -> skb ).portid ,
1246
1270
cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
1247
1271
RTM_NEWTFILTER ) <= 0 )
@@ -1254,6 +1278,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
1254
1278
arg .w .fn = tcf_node_dump ;
1255
1279
arg .skb = skb ;
1256
1280
arg .cb = cb ;
1281
+ arg .block = block ;
1257
1282
arg .q = q ;
1258
1283
arg .parent = parent ;
1259
1284
arg .w .stop = 0 ;
@@ -1272,13 +1297,10 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
1272
1297
{
1273
1298
struct net * net = sock_net (skb -> sk );
1274
1299
struct nlattr * tca [TCA_MAX + 1 ];
1275
- struct net_device * dev ;
1276
- struct Qdisc * q ;
1300
+ struct Qdisc * q = NULL ;
1277
1301
struct tcf_block * block ;
1278
1302
struct tcf_chain * chain ;
1279
1303
struct tcmsg * tcm = nlmsg_data (cb -> nlh );
1280
- unsigned long cl = 0 ;
1281
- const struct Qdisc_class_ops * cops ;
1282
1304
long index_start ;
1283
1305
long index ;
1284
1306
u32 parent ;
@@ -1291,32 +1313,44 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
1291
1313
if (err )
1292
1314
return err ;
1293
1315
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 ;
1302
1320
} 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 )
1315
1337
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 ;
1316
1353
}
1317
- block = cops -> tcf_block (q , cl , NULL );
1318
- if (!block )
1319
- goto out ;
1320
1354
1321
1355
index_start = cb -> args [0 ];
1322
1356
index = 0 ;
0 commit comments