Commit 84ae017a authored by Alexander Aring's avatar Alexander Aring Committed by David S. Miller

net: sched: act: handle generic action errors

This patch adds extack support for generic act handling. The extack
will be set deeper to each called function which is not part of netdev
core api.

Based on work by David Ahern <dsahern@gmail.com>

Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: default avatarAlexander Aring <aring@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aea0d727
...@@ -617,32 +617,41 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, ...@@ -617,32 +617,41 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
int err; int err;
if (name == NULL) { if (name == NULL) {
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL); err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
if (err < 0) if (err < 0)
goto err_out; goto err_out;
err = -EINVAL; err = -EINVAL;
kind = tb[TCA_ACT_KIND]; kind = tb[TCA_ACT_KIND];
if (!kind) if (!kind) {
NL_SET_ERR_MSG(extack, "TC action kind must be specified");
goto err_out; goto err_out;
if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) }
if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) {
NL_SET_ERR_MSG(extack, "TC action name too long");
goto err_out; goto err_out;
}
if (tb[TCA_ACT_COOKIE]) { if (tb[TCA_ACT_COOKIE]) {
int cklen = nla_len(tb[TCA_ACT_COOKIE]); int cklen = nla_len(tb[TCA_ACT_COOKIE]);
if (cklen > TC_COOKIE_MAX_SIZE) if (cklen > TC_COOKIE_MAX_SIZE) {
NL_SET_ERR_MSG(extack, "TC cookie size above the maximum");
goto err_out; goto err_out;
}
cookie = nla_memdup_cookie(tb); cookie = nla_memdup_cookie(tb);
if (!cookie) { if (!cookie) {
NL_SET_ERR_MSG(extack, "No memory to generate TC cookie");
err = -ENOMEM; err = -ENOMEM;
goto err_out; goto err_out;
} }
} }
} else { } else {
if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) {
NL_SET_ERR_MSG(extack, "TC action name too long");
err = -EINVAL; err = -EINVAL;
if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
goto err_out; goto err_out;
} }
}
a_o = tc_lookup_action_n(act_name); a_o = tc_lookup_action_n(act_name);
if (a_o == NULL) { if (a_o == NULL) {
...@@ -664,6 +673,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, ...@@ -664,6 +673,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
goto err_mod; goto err_mod;
} }
#endif #endif
NL_SET_ERR_MSG(extack, "Failed to load TC action module");
err = -ENOENT; err = -ENOENT;
goto err_out; goto err_out;
} }
...@@ -698,6 +708,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, ...@@ -698,6 +708,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
list_add_tail(&a->list, &actions); list_add_tail(&a->list, &actions);
tcf_action_destroy(&actions, bind); tcf_action_destroy(&actions, bind);
NL_SET_ERR_MSG(extack, "Failed to init TC action chain");
return ERR_PTR(err); return ERR_PTR(err);
} }
} }
...@@ -734,7 +745,7 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, ...@@ -734,7 +745,7 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
int err; int err;
int i; int i;
err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL); err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack);
if (err < 0) if (err < 0)
return err; return err;
...@@ -842,7 +853,8 @@ static int tca_get_fill(struct sk_buff *skb, struct list_head *actions, ...@@ -842,7 +853,8 @@ static int tca_get_fill(struct sk_buff *skb, struct list_head *actions,
static int static int
tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
struct list_head *actions, int event) struct list_head *actions, int event,
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -851,6 +863,7 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, ...@@ -851,6 +863,7 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
return -ENOBUFS; return -ENOBUFS;
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event,
0, 0) <= 0) { 0, 0) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
...@@ -859,7 +872,8 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, ...@@ -859,7 +872,8 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
} }
static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
struct nlmsghdr *n, u32 portid) struct nlmsghdr *n, u32 portid,
struct netlink_ext_ack *extack)
{ {
struct nlattr *tb[TCA_ACT_MAX + 1]; struct nlattr *tb[TCA_ACT_MAX + 1];
const struct tc_action_ops *ops; const struct tc_action_ops *ops;
...@@ -867,20 +881,24 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, ...@@ -867,20 +881,24 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
int index; int index;
int err; int err;
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL); err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
if (err < 0) if (err < 0)
goto err_out; goto err_out;
err = -EINVAL; err = -EINVAL;
if (tb[TCA_ACT_INDEX] == NULL || if (tb[TCA_ACT_INDEX] == NULL ||
nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) {
NL_SET_ERR_MSG(extack, "Invalid TC action index value");
goto err_out; goto err_out;
}
index = nla_get_u32(tb[TCA_ACT_INDEX]); index = nla_get_u32(tb[TCA_ACT_INDEX]);
err = -EINVAL; err = -EINVAL;
ops = tc_lookup_action(tb[TCA_ACT_KIND]); ops = tc_lookup_action(tb[TCA_ACT_KIND]);
if (!ops) /* could happen in batch of actions */ if (!ops) { /* could happen in batch of actions */
NL_SET_ERR_MSG(extack, "Specified TC action not found");
goto err_out; goto err_out;
}
err = -ENOENT; err = -ENOENT;
if (ops->lookup(net, &a, index) == 0) if (ops->lookup(net, &a, index) == 0)
goto err_mod; goto err_mod;
...@@ -895,7 +913,8 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, ...@@ -895,7 +913,8 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
} }
static int tca_action_flush(struct net *net, struct nlattr *nla, static int tca_action_flush(struct net *net, struct nlattr *nla,
struct nlmsghdr *n, u32 portid) struct nlmsghdr *n, u32 portid,
struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *b; unsigned char *b;
...@@ -909,35 +928,39 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, ...@@ -909,35 +928,39 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
int err = -ENOMEM; int err = -ENOMEM;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) { if (!skb)
pr_debug("tca_action_flush: failed skb alloc\n");
return err; return err;
}
b = skb_tail_pointer(skb); b = skb_tail_pointer(skb);
err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL); err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
if (err < 0) if (err < 0)
goto err_out; goto err_out;
err = -EINVAL; err = -EINVAL;
kind = tb[TCA_ACT_KIND]; kind = tb[TCA_ACT_KIND];
ops = tc_lookup_action(kind); ops = tc_lookup_action(kind);
if (!ops) /*some idjot trying to flush unknown action */ if (!ops) { /*some idjot trying to flush unknown action */
NL_SET_ERR_MSG(extack, "Cannot flush unknown TC action");
goto err_out; goto err_out;
}
nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION,
sizeof(*t), 0); sizeof(*t), 0);
if (!nlh) if (!nlh) {
NL_SET_ERR_MSG(extack, "Failed to create TC action flush notification");
goto out_module_put; goto out_module_put;
}
t = nlmsg_data(nlh); t = nlmsg_data(nlh);
t->tca_family = AF_UNSPEC; t->tca_family = AF_UNSPEC;
t->tca__pad1 = 0; t->tca__pad1 = 0;
t->tca__pad2 = 0; t->tca__pad2 = 0;
nest = nla_nest_start(skb, TCA_ACT_TAB); nest = nla_nest_start(skb, TCA_ACT_TAB);
if (!nest) if (!nest) {
NL_SET_ERR_MSG(extack, "Failed to add new netlink message");
goto out_module_put; goto out_module_put;
}
err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops); err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops);
if (err <= 0) { if (err <= 0) {
...@@ -954,6 +977,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, ...@@ -954,6 +977,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
n->nlmsg_flags & NLM_F_ECHO); n->nlmsg_flags & NLM_F_ECHO);
if (err > 0) if (err > 0)
return 0; return 0;
if (err < 0)
NL_SET_ERR_MSG(extack, "Failed to send TC action flush notification");
return err; return err;
...@@ -966,7 +991,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla, ...@@ -966,7 +991,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
static int static int
tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
u32 portid) u32 portid, struct netlink_ext_ack *extack)
{ {
int ret; int ret;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -977,6 +1002,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, ...@@ -977,6 +1002,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION, if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
0, 1) <= 0) { 0, 1) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes");
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
...@@ -984,6 +1010,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, ...@@ -984,6 +1010,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
/* now do the delete */ /* now do the delete */
ret = tcf_action_destroy(actions, 0); ret = tcf_action_destroy(actions, 0);
if (ret < 0) { if (ret < 0) {
NL_SET_ERR_MSG(extack, "Failed to delete TC action");
kfree_skb(skb); kfree_skb(skb);
return ret; return ret;
} }
...@@ -997,26 +1024,27 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, ...@@ -997,26 +1024,27 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
static int static int
tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
u32 portid, int event) u32 portid, int event, struct netlink_ext_ack *extack)
{ {
int i, ret; int i, ret;
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *act; struct tc_action *act;
LIST_HEAD(actions); LIST_HEAD(actions);
ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL); ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) { if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
if (tb[1]) if (tb[1])
return tca_action_flush(net, tb[1], n, portid); return tca_action_flush(net, tb[1], n, portid, extack);
NL_SET_ERR_MSG(extack, "Invalid netlink attributes while flushing TC action");
return -EINVAL; return -EINVAL;
} }
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
act = tcf_action_get_1(net, tb[i], n, portid); act = tcf_action_get_1(net, tb[i], n, portid, extack);
if (IS_ERR(act)) { if (IS_ERR(act)) {
ret = PTR_ERR(act); ret = PTR_ERR(act);
goto err; goto err;
...@@ -1026,9 +1054,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -1026,9 +1054,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
} }
if (event == RTM_GETACTION) if (event == RTM_GETACTION)
ret = tcf_get_notify(net, portid, n, &actions, event); ret = tcf_get_notify(net, portid, n, &actions, event, extack);
else { /* delete */ else { /* delete */
ret = tcf_del_notify(net, n, &actions, portid); ret = tcf_del_notify(net, n, &actions, portid, extack);
if (ret) if (ret)
goto err; goto err;
return ret; return ret;
...@@ -1041,7 +1069,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -1041,7 +1069,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
static int static int
tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
u32 portid) u32 portid, struct netlink_ext_ack *extack)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int err = 0; int err = 0;
...@@ -1052,6 +1080,7 @@ tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions, ...@@ -1052,6 +1080,7 @@ tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags, if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
RTM_NEWACTION, 0, 0) <= 0) { RTM_NEWACTION, 0, 0) <= 0) {
NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while deleting TC action");
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
...@@ -1075,7 +1104,7 @@ static int tcf_action_add(struct net *net, struct nlattr *nla, ...@@ -1075,7 +1104,7 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
if (ret) if (ret)
return ret; return ret;
return tcf_add_notify(net, n, &actions, portid); return tcf_add_notify(net, n, &actions, portid, extack);
} }
static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON; static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
...@@ -1103,7 +1132,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1103,7 +1132,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
return ret; return ret;
if (tca[TCA_ACT_TAB] == NULL) { if (tca[TCA_ACT_TAB] == NULL) {
pr_notice("tc_ctl_action: received NO action attribs\n"); NL_SET_ERR_MSG(extack, "Netlink action attributes missing");
return -EINVAL; return -EINVAL;
} }
...@@ -1126,11 +1155,11 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1126,11 +1155,11 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
break; break;
case RTM_DELACTION: case RTM_DELACTION:
ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
portid, RTM_DELACTION); portid, RTM_DELACTION, extack);
break; break;
case RTM_GETACTION: case RTM_GETACTION:
ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
portid, RTM_GETACTION); portid, RTM_GETACTION, extack);
break; break;
default: default:
BUG(); BUG();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment