mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
Merge branch 'net-sched-tc_dump_qdisc-optimizations'
Eric Dumazet says: ==================== net/sched: tc_dump_qdisc() optimizations Before converting tc_dump_qdisc() to RCU, we make the following changes: - Use for_each_netdev_dump() instead of for_each_netdev() - Only dump qdiscs of a single device at user space request. ==================== Link: https://patch.msgid.link/20260430023628.3216283-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
edf4bee421
|
|
@ -976,7 +976,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
|
|||
out_nlmsg_trim:
|
||||
nla_put_failure:
|
||||
nlmsg_trim(skb, b);
|
||||
return -1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static bool tc_qdisc_dump_ignore(struct Qdisc *q, bool dump_invisible)
|
||||
|
|
@ -1836,11 +1836,13 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
|
|||
if (q_idx < s_q_idx) {
|
||||
q_idx++;
|
||||
} else {
|
||||
if (!tc_qdisc_dump_ignore(q, dump_invisible) &&
|
||||
tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
RTM_NEWQDISC, NULL) <= 0)
|
||||
goto done;
|
||||
if (!tc_qdisc_dump_ignore(q, dump_invisible))
|
||||
ret = tc_fill_qdisc(skb, q, q->parent,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
RTM_NEWQDISC, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
q_idx++;
|
||||
}
|
||||
|
||||
|
|
@ -1858,79 +1860,81 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
|
|||
q_idx++;
|
||||
continue;
|
||||
}
|
||||
if (!tc_qdisc_dump_ignore(q, dump_invisible) &&
|
||||
tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
RTM_NEWQDISC, NULL) <= 0)
|
||||
goto done;
|
||||
if (!tc_qdisc_dump_ignore(q, dump_invisible))
|
||||
ret = tc_fill_qdisc(skb, q, q->parent,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
RTM_NEWQDISC, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
q_idx++;
|
||||
}
|
||||
|
||||
out:
|
||||
*q_idx_p = q_idx;
|
||||
return ret;
|
||||
done:
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int idx, q_idx;
|
||||
int s_idx, s_q_idx;
|
||||
struct net_device *dev;
|
||||
const struct nlmsghdr *nlh = cb->nlh;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct nlattr *tca[TCA_MAX + 1];
|
||||
struct {
|
||||
unsigned long ifindex;
|
||||
int q_idx;
|
||||
} *ctx = (void *)cb->ctx;
|
||||
const struct tcmsg *tcm;
|
||||
struct net_device *dev;
|
||||
int s_q_idx, q_idx;
|
||||
int err;
|
||||
|
||||
s_idx = cb->args[0];
|
||||
s_q_idx = q_idx = cb->args[1];
|
||||
|
||||
idx = 0;
|
||||
ASSERT_RTNL();
|
||||
|
||||
err = nlmsg_parse_deprecated(nlh, sizeof(struct tcmsg), tca, TCA_MAX,
|
||||
rtm_tca_policy, cb->extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
tcm = nlmsg_data(nlh);
|
||||
if (tcm->tcm_ifindex && !ctx->ifindex)
|
||||
ctx->ifindex = tcm->tcm_ifindex;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
s_q_idx = ctx->q_idx;
|
||||
|
||||
for_each_netdev_dump(net, dev, ctx->ifindex) {
|
||||
struct netdev_queue *dev_queue;
|
||||
struct Qdisc *q;
|
||||
|
||||
if (tcm->tcm_ifindex && ctx->ifindex != tcm->tcm_ifindex)
|
||||
break;
|
||||
|
||||
if (idx < s_idx)
|
||||
goto cont;
|
||||
if (idx > s_idx)
|
||||
s_q_idx = 0;
|
||||
q_idx = 0;
|
||||
|
||||
netdev_lock_ops(dev);
|
||||
if (tc_dump_qdisc_root(rtnl_dereference(dev->qdisc),
|
||||
skb, cb, &q_idx, s_q_idx,
|
||||
true, tca[TCA_DUMP_INVISIBLE]) < 0) {
|
||||
netdev_unlock_ops(dev);
|
||||
goto done;
|
||||
}
|
||||
q = rtnl_dereference(dev->qdisc);
|
||||
err = tc_dump_qdisc_root(q, skb, cb, &q_idx, s_q_idx,
|
||||
true, tca[TCA_DUMP_INVISIBLE]);
|
||||
if (err < 0)
|
||||
goto error_unlock;
|
||||
|
||||
dev_queue = dev_ingress_queue(dev);
|
||||
if (dev_queue &&
|
||||
tc_dump_qdisc_root(rtnl_dereference(dev_queue->qdisc_sleeping),
|
||||
skb, cb, &q_idx, s_q_idx, false,
|
||||
tca[TCA_DUMP_INVISIBLE]) < 0) {
|
||||
netdev_unlock_ops(dev);
|
||||
goto done;
|
||||
if (dev_queue) {
|
||||
q = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
err = tc_dump_qdisc_root(q, skb, cb, &q_idx, s_q_idx,
|
||||
false, tca[TCA_DUMP_INVISIBLE]);
|
||||
if (err < 0)
|
||||
goto error_unlock;
|
||||
}
|
||||
netdev_unlock_ops(dev);
|
||||
|
||||
cont:
|
||||
idx++;
|
||||
s_q_idx = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
cb->args[0] = idx;
|
||||
cb->args[1] = q_idx;
|
||||
|
||||
return skb->len;
|
||||
|
||||
error_unlock:
|
||||
netdev_unlock_ops(dev);
|
||||
ctx->q_idx = q_idx;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1987,15 +1991,16 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
|
|||
out_nlmsg_trim:
|
||||
nla_put_failure:
|
||||
nlmsg_trim(skb, b);
|
||||
return -1;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int tclass_notify(struct net *net, struct sk_buff *oskb,
|
||||
struct nlmsghdr *n, struct Qdisc *q,
|
||||
unsigned long cl, int event, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC))
|
||||
return 0;
|
||||
|
|
@ -2004,9 +2009,10 @@ static int tclass_notify(struct net *net, struct sk_buff *oskb,
|
|||
if (!skb)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0, event, extack) < 0) {
|
||||
ret = tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0, event, extack);
|
||||
if (ret < 0) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
|
||||
|
|
@ -2017,17 +2023,19 @@ static int tclass_get_notify(struct net *net, struct sk_buff *oskb,
|
|||
struct nlmsghdr *n, struct Qdisc *q,
|
||||
unsigned long cl, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0, RTM_NEWTCLASS,
|
||||
extack) < 0) {
|
||||
ret = tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0,
|
||||
RTM_NEWTCLASS, extack);
|
||||
if (ret < 0) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
|
||||
|
|
@ -2041,7 +2049,7 @@ static int tclass_del_notify(struct net *net,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (!cops->delete)
|
||||
|
|
@ -2052,13 +2060,12 @@ static int tclass_del_notify(struct net *net,
|
|||
if (!skb)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0,
|
||||
RTM_DELTCLASS, extack) < 0) {
|
||||
err = tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0,
|
||||
RTM_DELTCLASS, extack);
|
||||
if (err < 0) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
err = cops->delete(q, cl, extack);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user