net_sched: walk through all child classes in tc_bind_tclass()
[ Upstream commit760d228e32
] In a complex TC class hierarchy like this: tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit \ avpkt 1000 cell 8 tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit \ rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 \ avpkt 1000 bounded tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \ sport 80 0xffff flowid 1:3 tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \ sport 25 0xffff flowid 1:4 tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit \ rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 \ avpkt 1000 tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit \ rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 \ avpkt 1000 where filters are installed on qdisc 1:0, so we can't merely search from class 1:1 when creating class 1:3 and class 1:4. We have to walk through all the child classes of the direct parent qdisc. Otherwise we would miss filters those need reverse binding. Fixes:07d79fc7d9
("net_sched: add reverse binding for tc class") Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
55ec468d30
commit
717abad864
|
@ -1910,22 +1910,24 @@ static int tcf_node_bind(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
|
||||
unsigned long new_cl)
|
||||
struct tc_bind_class_args {
|
||||
struct qdisc_walker w;
|
||||
unsigned long new_cl;
|
||||
u32 portid;
|
||||
u32 clid;
|
||||
};
|
||||
|
||||
static int tc_bind_class_walker(struct Qdisc *q, unsigned long cl,
|
||||
struct qdisc_walker *w)
|
||||
{
|
||||
struct tc_bind_class_args *a = (struct tc_bind_class_args *)w;
|
||||
const struct Qdisc_class_ops *cops = q->ops->cl_ops;
|
||||
struct tcf_block *block;
|
||||
struct tcf_chain *chain;
|
||||
unsigned long cl;
|
||||
|
||||
cl = cops->find(q, portid);
|
||||
if (!cl)
|
||||
return;
|
||||
if (!cops->tcf_block)
|
||||
return;
|
||||
block = cops->tcf_block(q, cl, NULL);
|
||||
if (!block)
|
||||
return;
|
||||
return 0;
|
||||
for (chain = tcf_get_next_chain(block, NULL);
|
||||
chain;
|
||||
chain = tcf_get_next_chain(block, chain)) {
|
||||
|
@ -1936,12 +1938,29 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
|
|||
struct tcf_bind_args arg = {};
|
||||
|
||||
arg.w.fn = tcf_node_bind;
|
||||
arg.classid = clid;
|
||||
arg.classid = a->clid;
|
||||
arg.base = cl;
|
||||
arg.cl = new_cl;
|
||||
arg.cl = a->new_cl;
|
||||
tp->ops->walk(tp, &arg.w, true);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
|
||||
unsigned long new_cl)
|
||||
{
|
||||
const struct Qdisc_class_ops *cops = q->ops->cl_ops;
|
||||
struct tc_bind_class_args args = {};
|
||||
|
||||
if (!cops->tcf_block)
|
||||
return;
|
||||
args.portid = portid;
|
||||
args.clid = clid;
|
||||
args.new_cl = new_cl;
|
||||
args.w.fn = tc_bind_class_walker;
|
||||
q->ops->cl_ops->walk(q, &args.w);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue