net: mpls: Add extack messages for route add and delete failures

Add error messages for failures in adding and deleting mpls routes.
This covers most of the annoying EINVAL errors.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David Ahern 2017-05-27 16:19:31 -06:00 committed by David S. Miller
parent b7b386f42f
commit 074350e2eb
2 changed files with 87 additions and 40 deletions

View File

@ -720,7 +720,8 @@ errout:
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
struct mpls_nh *nh, int oif, struct nlattr *via,
struct nlattr *newdst, u8 max_labels)
struct nlattr *newdst, u8 max_labels,
struct netlink_ext_ack *extack)
{
int err = -ENOMEM;
@ -729,14 +730,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
if (newdst) {
err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
nh->nh_label, NULL);
nh->nh_label, extack);
if (err)
goto errout;
}
if (via) {
err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
__mpls_nh_via(rt, nh));
__mpls_nh_via(rt, nh), extack);
if (err)
goto errout;
} else {
@ -803,7 +804,8 @@ static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
}
static int mpls_nh_build_multi(struct mpls_route_config *cfg,
struct mpls_route *rt, u8 max_labels)
struct mpls_route *rt, u8 max_labels,
struct netlink_ext_ack *extack)
{
struct rtnexthop *rtnh = cfg->rc_mp;
struct nlattr *nla_via, *nla_newdst;
@ -837,7 +839,7 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
rtnh->rtnh_ifindex, nla_via, nla_newdst,
max_labels);
max_labels, extack);
if (err)
goto errout;
@ -856,20 +858,28 @@ errout:
return err;
}
static bool mpls_label_ok(struct net *net, unsigned int index)
static bool mpls_label_ok(struct net *net, unsigned int index,
struct netlink_ext_ack *extack)
{
/* Reserved labels may not be set */
if (index < MPLS_LABEL_FIRST_UNRESERVED)
if (index < MPLS_LABEL_FIRST_UNRESERVED) {
NL_SET_ERR_MSG(extack,
"Invalid label - must be MPLS_LABEL_FIRST_UNRESERVED or higher");
return false;
}
/* The full 20 bit range may not be supported. */
if (index >= net->mpls.platform_labels)
if (index >= net->mpls.platform_labels) {
NL_SET_ERR_MSG(extack,
"Label >= configured maximum in platform_labels");
return false;
}
return true;
}
static int mpls_route_add(struct mpls_route_config *cfg)
static int mpls_route_add(struct mpls_route_config *cfg,
struct netlink_ext_ack *extack)
{
struct mpls_route __rcu **platform_label;
struct net *net = cfg->rc_nlinfo.nl_net;
@ -888,13 +898,15 @@ static int mpls_route_add(struct mpls_route_config *cfg)
index = find_free_label(net);
}
if (!mpls_label_ok(net, index))
if (!mpls_label_ok(net, index, extack))
goto errout;
/* Append makes no sense with mpls */
err = -EOPNOTSUPP;
if (cfg->rc_nlflags & NLM_F_APPEND)
if (cfg->rc_nlflags & NLM_F_APPEND) {
NL_SET_ERR_MSG(extack, "MPLS does not support route append");
goto errout;
}
err = -EEXIST;
platform_label = rtnl_dereference(net->mpls.platform_label);
@ -921,8 +933,10 @@ static int mpls_route_add(struct mpls_route_config *cfg)
nhs = 1;
}
if (nhs == 0)
if (nhs == 0) {
NL_SET_ERR_MSG(extack, "Route does not contain a nexthop");
goto errout;
}
err = -ENOMEM;
rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
@ -936,7 +950,7 @@ static int mpls_route_add(struct mpls_route_config *cfg)
rt->rt_ttl_propagate = cfg->rc_ttl_propagate;
if (cfg->rc_mp)
err = mpls_nh_build_multi(cfg, rt, max_labels);
err = mpls_nh_build_multi(cfg, rt, max_labels, extack);
else
err = mpls_nh_build_from_cfg(cfg, rt);
if (err)
@ -952,7 +966,8 @@ errout:
return err;
}
static int mpls_route_del(struct mpls_route_config *cfg)
static int mpls_route_del(struct mpls_route_config *cfg,
struct netlink_ext_ack *extack)
{
struct net *net = cfg->rc_nlinfo.nl_net;
unsigned index;
@ -960,7 +975,7 @@ static int mpls_route_del(struct mpls_route_config *cfg)
index = cfg->rc_label;
if (!mpls_label_ok(net, index))
if (!mpls_label_ok(net, index, extack))
goto errout;
mpls_route_update(net, index, NULL, &cfg->rc_nlinfo);
@ -1626,19 +1641,25 @@ out:
}
EXPORT_SYMBOL_GPL(nla_get_labels);
int nla_get_via(const struct nlattr *nla, u8 *via_alen,
u8 *via_table, u8 via_addr[])
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
u8 via_addr[], struct netlink_ext_ack *extack)
{
struct rtvia *via = nla_data(nla);
int err = -EINVAL;
int alen;
if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
NL_SET_ERR_MSG_ATTR(extack, nla,
"Invalid attribute length for RTA_VIA");
goto errout;
}
alen = nla_len(nla) -
offsetof(struct rtvia, rtvia_addr);
if (alen > MAX_VIA_ALEN)
if (alen > MAX_VIA_ALEN) {
NL_SET_ERR_MSG_ATTR(extack, nla,
"Invalid address length for RTA_VIA");
goto errout;
}
/* Validate the address family */
switch (via->rtvia_family) {
@ -1668,8 +1689,10 @@ errout:
return err;
}
static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
struct mpls_route_config *cfg)
static int rtm_to_route_config(struct sk_buff *skb,
struct nlmsghdr *nlh,
struct mpls_route_config *cfg,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
struct nlattr *tb[RTA_MAX+1];
@ -1677,35 +1700,54 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy,
NULL);
extack);
if (err < 0)
goto errout;
err = -EINVAL;
rtm = nlmsg_data(nlh);
if (rtm->rtm_family != AF_MPLS)
if (rtm->rtm_family != AF_MPLS) {
NL_SET_ERR_MSG(extack, "Invalid address family in rtmsg");
goto errout;
if (rtm->rtm_dst_len != 20)
}
if (rtm->rtm_dst_len != 20) {
NL_SET_ERR_MSG(extack, "rtm_dst_len must be 20 for MPLS");
goto errout;
if (rtm->rtm_src_len != 0)
}
if (rtm->rtm_src_len != 0) {
NL_SET_ERR_MSG(extack, "rtm_src_len must be 0 for MPLS");
goto errout;
if (rtm->rtm_tos != 0)
}
if (rtm->rtm_tos != 0) {
NL_SET_ERR_MSG(extack, "rtm_tos must be 0 for MPLS");
goto errout;
if (rtm->rtm_table != RT_TABLE_MAIN)
}
if (rtm->rtm_table != RT_TABLE_MAIN) {
NL_SET_ERR_MSG(extack,
"MPLS only supports the main route table");
goto errout;
}
/* Any value is acceptable for rtm_protocol */
/* As mpls uses destination specific addresses
* (or source specific address in the case of multicast)
* all addresses have universal scope.
*/
if (rtm->rtm_scope != RT_SCOPE_UNIVERSE)
if (rtm->rtm_scope != RT_SCOPE_UNIVERSE) {
NL_SET_ERR_MSG(extack,
"Invalid route scope - MPLS only supports UNIVERSE");
goto errout;
if (rtm->rtm_type != RTN_UNICAST)
}
if (rtm->rtm_type != RTN_UNICAST) {
NL_SET_ERR_MSG(extack,
"Invalid route type - MPLS only supports UNICAST");
goto errout;
if (rtm->rtm_flags != 0)
}
if (rtm->rtm_flags != 0) {
NL_SET_ERR_MSG(extack, "rtm_flags must be 0 for MPLS");
goto errout;
}
cfg->rc_label = LABEL_NOT_SPECIFIED;
cfg->rc_protocol = rtm->rtm_protocol;
@ -1728,25 +1770,26 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_NEWDST:
if (nla_get_labels(nla, MAX_NEW_LABELS,
&cfg->rc_output_labels,
cfg->rc_output_label, NULL))
cfg->rc_output_label, extack))
goto errout;
break;
case RTA_DST:
{
u8 label_count;
if (nla_get_labels(nla, 1, &label_count,
&cfg->rc_label, NULL))
&cfg->rc_label, extack))
goto errout;
if (!mpls_label_ok(cfg->rc_nlinfo.nl_net,
cfg->rc_label))
cfg->rc_label, extack))
goto errout;
break;
}
case RTA_VIA:
{
if (nla_get_via(nla, &cfg->rc_via_alen,
&cfg->rc_via_table, cfg->rc_via))
&cfg->rc_via_table, cfg->rc_via,
extack))
goto errout;
break;
}
@ -1760,14 +1803,18 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
{
u8 ttl_propagate = nla_get_u8(nla);
if (ttl_propagate > 1)
if (ttl_propagate > 1) {
NL_SET_ERR_MSG_ATTR(extack, nla,
"RTA_TTL_PROPAGATE can only be 0 or 1");
goto errout;
}
cfg->rc_ttl_propagate = ttl_propagate ?
MPLS_TTL_PROP_ENABLED :
MPLS_TTL_PROP_DISABLED;
break;
}
default:
NL_SET_ERR_MSG_ATTR(extack, nla, "Unknown attribute");
/* Unsupported attribute */
goto errout;
}
@ -1788,11 +1835,11 @@ static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!cfg)
return -ENOMEM;
err = rtm_to_route_config(skb, nlh, cfg);
err = rtm_to_route_config(skb, nlh, cfg, extack);
if (err < 0)
goto out;
err = mpls_route_del(cfg);
err = mpls_route_del(cfg, extack);
out:
kfree(cfg);
@ -1810,11 +1857,11 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!cfg)
return -ENOMEM;
err = rtm_to_route_config(skb, nlh, cfg);
err = rtm_to_route_config(skb, nlh, cfg, extack);
if (err < 0)
goto out;
err = mpls_route_add(cfg);
err = mpls_route_add(cfg, extack);
out:
kfree(cfg);

View File

@ -205,7 +205,7 @@ int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
u32 label[], struct netlink_ext_ack *extack);
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
u8 via[]);
u8 via[], struct netlink_ext_ack *extack);
bool mpls_output_possible(const struct net_device *dev);
unsigned int mpls_dev_mtu(const struct net_device *dev);
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);