net: sched: cls_api: handle generic cls errors
This patch adds extack support for generic cls handling. The extack will be set deeper to each called function which is not part of netdev core api. Cc: David Ahern <dsahern@gmail.com> Signed-off-by: Alexander Aring <aring@mojatatu.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8865fdd4e1
commit
c35a4acc29
|
@ -122,7 +122,8 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
|
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
|
||||||
u32 prio, struct tcf_chain *chain)
|
u32 prio, struct tcf_chain *chain,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct tcf_proto *tp;
|
struct tcf_proto *tp;
|
||||||
int err;
|
int err;
|
||||||
|
@ -148,6 +149,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
|
||||||
module_put(tp->ops->owner);
|
module_put(tp->ops->owner);
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
} else {
|
} else {
|
||||||
|
NL_SET_ERR_MSG(extack, "TC classifier not found");
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
}
|
}
|
||||||
goto errout;
|
goto errout;
|
||||||
|
@ -935,7 +937,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
|
||||||
static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
|
static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
|
||||||
struct nlmsghdr *n, struct tcf_proto *tp,
|
struct nlmsghdr *n, struct tcf_proto *tp,
|
||||||
struct tcf_block *block, struct Qdisc *q,
|
struct tcf_block *block, struct Qdisc *q,
|
||||||
u32 parent, void *fh, bool unicast, bool *last)
|
u32 parent, void *fh, bool unicast, bool *last,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
|
u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
|
||||||
|
@ -947,6 +950,7 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
|
||||||
|
|
||||||
if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
|
if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
|
||||||
n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER) <= 0) {
|
n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER) <= 0) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Failed to build del event notification");
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -960,8 +964,11 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
|
||||||
if (unicast)
|
if (unicast)
|
||||||
return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
|
return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
|
||||||
|
|
||||||
return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
|
err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
|
||||||
n->nlmsg_flags & NLM_F_ECHO);
|
n->nlmsg_flags & NLM_F_ECHO);
|
||||||
|
if (err < 0)
|
||||||
|
NL_SET_ERR_MSG(extack, "Failed to send filter delete notification");
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
|
static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
|
||||||
|
@ -1021,8 +1028,10 @@ replay:
|
||||||
if (prio == 0) {
|
if (prio == 0) {
|
||||||
switch (n->nlmsg_type) {
|
switch (n->nlmsg_type) {
|
||||||
case RTM_DELTFILTER:
|
case RTM_DELTFILTER:
|
||||||
if (protocol || t->tcm_handle || tca[TCA_KIND])
|
if (protocol || t->tcm_handle || tca[TCA_KIND]) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Cannot flush filters with protocol, handle or kind set");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RTM_NEWTFILTER:
|
case RTM_NEWTFILTER:
|
||||||
/* If no priority is provided by the user,
|
/* If no priority is provided by the user,
|
||||||
|
@ -1035,6 +1044,7 @@ replay:
|
||||||
}
|
}
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
default:
|
default:
|
||||||
|
NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,23 +1073,31 @@ replay:
|
||||||
parent = q->handle;
|
parent = q->handle;
|
||||||
} else {
|
} else {
|
||||||
q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
|
q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
|
||||||
if (!q)
|
if (!q) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is it classful? */
|
/* Is it classful? */
|
||||||
cops = q->ops->cl_ops;
|
cops = q->ops->cl_ops;
|
||||||
if (!cops)
|
if (!cops) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Qdisc not classful");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cops->tcf_block)
|
if (!cops->tcf_block) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Class doesn't support blocks");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do we search for filter, attached to class? */
|
/* Do we search for filter, attached to class? */
|
||||||
if (TC_H_MIN(parent)) {
|
if (TC_H_MIN(parent)) {
|
||||||
cl = cops->find(q, parent);
|
cl = cops->find(q, parent);
|
||||||
if (cl == 0)
|
if (cl == 0) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Specified class doesn't exist");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And the last stroke */
|
/* And the last stroke */
|
||||||
|
@ -1097,12 +1115,14 @@ replay:
|
||||||
|
|
||||||
chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
|
chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
|
||||||
if (chain_index > TC_ACT_EXT_VAL_MASK) {
|
if (chain_index > TC_ACT_EXT_VAL_MASK) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
chain = tcf_chain_get(block, chain_index,
|
chain = tcf_chain_get(block, chain_index,
|
||||||
n->nlmsg_type == RTM_NEWTFILTER);
|
n->nlmsg_type == RTM_NEWTFILTER);
|
||||||
if (!chain) {
|
if (!chain) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
|
||||||
err = n->nlmsg_type == RTM_NEWTFILTER ? -ENOMEM : -EINVAL;
|
err = n->nlmsg_type == RTM_NEWTFILTER ? -ENOMEM : -EINVAL;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1118,6 +1138,7 @@ replay:
|
||||||
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
|
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
|
||||||
prio, prio_allocate);
|
prio, prio_allocate);
|
||||||
if (IS_ERR(tp)) {
|
if (IS_ERR(tp)) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
|
||||||
err = PTR_ERR(tp);
|
err = PTR_ERR(tp);
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1126,12 +1147,14 @@ replay:
|
||||||
/* Proto-tcf does not exist, create new one */
|
/* Proto-tcf does not exist, create new one */
|
||||||
|
|
||||||
if (tca[TCA_KIND] == NULL || !protocol) {
|
if (tca[TCA_KIND] == NULL || !protocol) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Filter kind and protocol must be specified");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n->nlmsg_type != RTM_NEWTFILTER ||
|
if (n->nlmsg_type != RTM_NEWTFILTER ||
|
||||||
!(n->nlmsg_flags & NLM_F_CREATE)) {
|
!(n->nlmsg_flags & NLM_F_CREATE)) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Need both RTM_NEWTFILTER and NLM_F_CREATE to create a new filter");
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1140,13 +1163,14 @@ replay:
|
||||||
prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
|
prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
|
||||||
|
|
||||||
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
|
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
|
||||||
protocol, prio, chain);
|
protocol, prio, chain, extack);
|
||||||
if (IS_ERR(tp)) {
|
if (IS_ERR(tp)) {
|
||||||
err = PTR_ERR(tp);
|
err = PTR_ERR(tp);
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
tp_created = 1;
|
tp_created = 1;
|
||||||
} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
|
} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1165,6 +1189,7 @@ replay:
|
||||||
|
|
||||||
if (n->nlmsg_type != RTM_NEWTFILTER ||
|
if (n->nlmsg_type != RTM_NEWTFILTER ||
|
||||||
!(n->nlmsg_flags & NLM_F_CREATE)) {
|
!(n->nlmsg_flags & NLM_F_CREATE)) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Need both RTM_NEWTFILTER and NLM_F_CREATE to create a new filter");
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1176,13 +1201,15 @@ replay:
|
||||||
if (n->nlmsg_flags & NLM_F_EXCL) {
|
if (n->nlmsg_flags & NLM_F_EXCL) {
|
||||||
if (tp_created)
|
if (tp_created)
|
||||||
tcf_proto_destroy(tp);
|
tcf_proto_destroy(tp);
|
||||||
|
NL_SET_ERR_MSG(extack, "Filter already exists");
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RTM_DELTFILTER:
|
case RTM_DELTFILTER:
|
||||||
err = tfilter_del_notify(net, skb, n, tp, block,
|
err = tfilter_del_notify(net, skb, n, tp, block,
|
||||||
q, parent, fh, false, &last);
|
q, parent, fh, false, &last,
|
||||||
|
extack);
|
||||||
if (err)
|
if (err)
|
||||||
goto errout;
|
goto errout;
|
||||||
if (last) {
|
if (last) {
|
||||||
|
@ -1193,8 +1220,11 @@ replay:
|
||||||
case RTM_GETTFILTER:
|
case RTM_GETTFILTER:
|
||||||
err = tfilter_notify(net, skb, n, tp, block, q, parent,
|
err = tfilter_notify(net, skb, n, tp, block, q, parent,
|
||||||
fh, RTM_NEWTFILTER, true);
|
fh, RTM_NEWTFILTER, true);
|
||||||
|
if (err < 0)
|
||||||
|
NL_SET_ERR_MSG(extack, "Failed to send filter notify message");
|
||||||
goto errout;
|
goto errout;
|
||||||
default:
|
default:
|
||||||
|
NL_SET_ERR_MSG(extack, "Invalid netlink message type");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue