Skip to content

Commit 7960d1d

Browse files
jpirkodavem330
authored andcommitted
net: sched: use block index as a handle instead of qdisc when block is shared
As the tcm_ifindex with value TCM_IFINDEX_MAGIC_BLOCK is invalid ifindex, use it to indicate that we work with block, instead of qdisc. So if tcm_ifindex is set to TCM_IFINDEX_MAGIC_BLOCK, tcm_parent is used to carry block_index. If the block is set to be shared between at least 2 qdiscs, it is forbidden to use the qdisc handle to add/delete filters. In that case, userspace has to pass block_index. Also, for dump of the filters, in case the block is shared in between at least 2 qdiscs, the each filter is dumped with tcm_ifindex value TCM_IFINDEX_MAGIC_BLOCK and tcm_parent set to block_index. That gives the user clear indication, that the filter belongs to a shared block and not only to one qdisc under which it is dumped. Suggested-by: David Ahern <dsahern@gmail.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Acked-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent caa7260 commit 7960d1d

File tree

2 files changed

+128
-84
lines changed

2 files changed

+128
-84
lines changed

include/uapi/linux/rtnetlink.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,19 @@ struct tcmsg {
541541
int tcm_ifindex;
542542
__u32 tcm_handle;
543543
__u32 tcm_parent;
544+
/* tcm_block_index is used instead of tcm_parent
545+
* in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK
546+
*/
547+
#define tcm_block_index tcm_parent
544548
__u32 tcm_info;
545549
};
546550

551+
/* For manipulation of filters in shared block, tcm_ifindex is set to
552+
* TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index
553+
* which is the block index.
554+
*/
555+
#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
556+
547557
enum {
548558
TCA_UNSPEC,
549559
TCA_KIND,

net/sched/cls_api.c

Lines changed: 118 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -865,8 +865,9 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
865865
}
866866

867867
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)
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

904910
static 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

929935
static 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

961967
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,
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

Comments
 (0)