net/sched: act_api: conditional notification of events

As of today tc-action events are unconditionally built and sent to
RTNLGRP_TC. As with the introduction of rtnl_notify_needed we can check
before-hand if they are really needed.

Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20231208192847.714940-6-pctammela@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Pedro Tammela 2023-12-08 16:28:45 -03:00 committed by Jakub Kicinski
parent c73724bfde
commit 8d4390f519

View File

@ -1785,30 +1785,45 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[])
return 0;
}
static int
tcf_reoffload_del_notify(struct net *net, struct tc_action *action)
static struct sk_buff *tcf_reoffload_del_notify_msg(struct net *net,
struct tc_action *action)
{
size_t attr_size = tcf_action_fill_size(action);
struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
[0] = action,
};
struct sk_buff *skb;
skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOBUFS);
if (tca_get_fill(skb, actions, 0, 0, 0, RTM_DELACTION, 0, 1, NULL) <= 0) {
kfree_skb(skb);
return ERR_PTR(-EINVAL);
}
return skb;
}
static int tcf_reoffload_del_notify(struct net *net, struct tc_action *action)
{
const struct tc_action_ops *ops = action->ops;
struct sk_buff *skb;
int ret;
skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
if (!skb)
return -ENOBUFS;
if (tca_get_fill(skb, actions, 0, 0, 0, RTM_DELACTION, 0, 1, NULL) <= 0) {
kfree_skb(skb);
return -EINVAL;
if (!rtnl_notify_needed(net, 0, RTNLGRP_TC)) {
skb = NULL;
} else {
skb = tcf_reoffload_del_notify_msg(net, action);
if (IS_ERR(skb))
return PTR_ERR(skb);
}
ret = tcf_idr_release_unsafe(action);
if (ret == ACT_P_DELETED) {
module_put(ops->owner);
ret = rtnetlink_send(skb, net, 0, RTNLGRP_TC, 0);
ret = rtnetlink_maybe_send(skb, net, 0, RTNLGRP_TC, 0);
} else {
kfree_skb(skb);
}
@ -1874,22 +1889,41 @@ int tcf_action_reoffload_cb(flow_indr_block_bind_cb_t *cb,
return 0;
}
static int
tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
u32 portid, size_t attr_size, struct netlink_ext_ack *extack)
static struct sk_buff *tcf_del_notify_msg(struct net *net, struct nlmsghdr *n,
struct tc_action *actions[],
u32 portid, size_t attr_size,
struct netlink_ext_ack *extack)
{
int ret;
struct sk_buff *skb;
skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
if (!skb)
return -ENOBUFS;
return ERR_PTR(-ENOBUFS);
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
0, 2, extack) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes");
kfree_skb(skb);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
return skb;
}
static int tcf_del_notify(struct net *net, struct nlmsghdr *n,
struct tc_action *actions[], u32 portid,
size_t attr_size, struct netlink_ext_ack *extack)
{
struct sk_buff *skb;
int ret;
if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) {
skb = NULL;
} else {
skb = tcf_del_notify_msg(net, n, actions, portid, attr_size,
extack);
if (IS_ERR(skb))
return PTR_ERR(skb);
}
/* now do the delete */
@ -1900,9 +1934,8 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
return ret;
}
ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO);
return ret;
return rtnetlink_maybe_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO);
}
static int
@ -1953,25 +1986,44 @@ err:
return ret;
}
static int
tcf_add_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
u32 portid, size_t attr_size, struct netlink_ext_ack *extack)
static struct sk_buff *tcf_add_notify_msg(struct net *net, struct nlmsghdr *n,
struct tc_action *actions[],
u32 portid, size_t attr_size,
struct netlink_ext_ack *extack)
{
struct sk_buff *skb;
skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
if (!skb)
return -ENOBUFS;
return ERR_PTR(-ENOBUFS);
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
RTM_NEWACTION, 0, 0, extack) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
kfree_skb(skb);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO);
return skb;
}
static int tcf_add_notify(struct net *net, struct nlmsghdr *n,
struct tc_action *actions[], u32 portid,
size_t attr_size, struct netlink_ext_ack *extack)
{
struct sk_buff *skb;
if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) {
skb = NULL;
} else {
skb = tcf_add_notify_msg(net, n, actions, portid, attr_size,
extack);
if (IS_ERR(skb))
return PTR_ERR(skb);
}
return rtnetlink_maybe_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO);
}
static int tcf_action_add(struct net *net, struct nlattr *nla,