mirror of https://gitee.com/openkylin/linux.git
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:
parent
b7b386f42f
commit
074350e2eb
|
@ -720,7 +720,8 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
|
||||||
|
|
||||||
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
|
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
|
||||||
struct mpls_nh *nh, int oif, struct nlattr *via,
|
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;
|
int err = -ENOMEM;
|
||||||
|
|
||||||
|
@ -729,14 +730,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
|
||||||
|
|
||||||
if (newdst) {
|
if (newdst) {
|
||||||
err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
|
err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
|
||||||
nh->nh_label, NULL);
|
nh->nh_label, extack);
|
||||||
if (err)
|
if (err)
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (via) {
|
if (via) {
|
||||||
err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
|
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)
|
if (err)
|
||||||
goto errout;
|
goto errout;
|
||||||
} else {
|
} 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,
|
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 rtnexthop *rtnh = cfg->rc_mp;
|
||||||
struct nlattr *nla_via, *nla_newdst;
|
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,
|
err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
|
||||||
rtnh->rtnh_ifindex, nla_via, nla_newdst,
|
rtnh->rtnh_ifindex, nla_via, nla_newdst,
|
||||||
max_labels);
|
max_labels, extack);
|
||||||
if (err)
|
if (err)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
|
@ -856,20 +858,28 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
|
||||||
return err;
|
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 */
|
/* 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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* The full 20 bit range may not be supported. */
|
/* 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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 mpls_route __rcu **platform_label;
|
||||||
struct net *net = cfg->rc_nlinfo.nl_net;
|
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);
|
index = find_free_label(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpls_label_ok(net, index))
|
if (!mpls_label_ok(net, index, extack))
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
/* Append makes no sense with mpls */
|
/* Append makes no sense with mpls */
|
||||||
err = -EOPNOTSUPP;
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
platform_label = rtnl_dereference(net->mpls.platform_label);
|
platform_label = rtnl_dereference(net->mpls.platform_label);
|
||||||
|
@ -921,8 +933,10 @@ static int mpls_route_add(struct mpls_route_config *cfg)
|
||||||
nhs = 1;
|
nhs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nhs == 0)
|
if (nhs == 0) {
|
||||||
|
NL_SET_ERR_MSG(extack, "Route does not contain a nexthop");
|
||||||
goto errout;
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
|
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;
|
rt->rt_ttl_propagate = cfg->rc_ttl_propagate;
|
||||||
|
|
||||||
if (cfg->rc_mp)
|
if (cfg->rc_mp)
|
||||||
err = mpls_nh_build_multi(cfg, rt, max_labels);
|
err = mpls_nh_build_multi(cfg, rt, max_labels, extack);
|
||||||
else
|
else
|
||||||
err = mpls_nh_build_from_cfg(cfg, rt);
|
err = mpls_nh_build_from_cfg(cfg, rt);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -952,7 +966,8 @@ static int mpls_route_add(struct mpls_route_config *cfg)
|
||||||
return err;
|
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;
|
struct net *net = cfg->rc_nlinfo.nl_net;
|
||||||
unsigned index;
|
unsigned index;
|
||||||
|
@ -960,7 +975,7 @@ static int mpls_route_del(struct mpls_route_config *cfg)
|
||||||
|
|
||||||
index = cfg->rc_label;
|
index = cfg->rc_label;
|
||||||
|
|
||||||
if (!mpls_label_ok(net, index))
|
if (!mpls_label_ok(net, index, extack))
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
mpls_route_update(net, index, NULL, &cfg->rc_nlinfo);
|
mpls_route_update(net, index, NULL, &cfg->rc_nlinfo);
|
||||||
|
@ -1626,19 +1641,25 @@ int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nla_get_labels);
|
EXPORT_SYMBOL_GPL(nla_get_labels);
|
||||||
|
|
||||||
int nla_get_via(const struct nlattr *nla, u8 *via_alen,
|
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
|
||||||
u8 *via_table, u8 via_addr[])
|
u8 via_addr[], struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct rtvia *via = nla_data(nla);
|
struct rtvia *via = nla_data(nla);
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
int alen;
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
alen = nla_len(nla) -
|
alen = nla_len(nla) -
|
||||||
offsetof(struct rtvia, rtvia_addr);
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate the address family */
|
/* Validate the address family */
|
||||||
switch (via->rtvia_family) {
|
switch (via->rtvia_family) {
|
||||||
|
@ -1668,8 +1689,10 @@ int nla_get_via(const struct nlattr *nla, u8 *via_alen,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
|
static int rtm_to_route_config(struct sk_buff *skb,
|
||||||
struct mpls_route_config *cfg)
|
struct nlmsghdr *nlh,
|
||||||
|
struct mpls_route_config *cfg,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct rtmsg *rtm;
|
struct rtmsg *rtm;
|
||||||
struct nlattr *tb[RTA_MAX+1];
|
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;
|
int err;
|
||||||
|
|
||||||
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy,
|
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy,
|
||||||
NULL);
|
extack);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
rtm = nlmsg_data(nlh);
|
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;
|
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;
|
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;
|
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;
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
/* Any value is acceptable for rtm_protocol */
|
/* Any value is acceptable for rtm_protocol */
|
||||||
|
|
||||||
/* As mpls uses destination specific addresses
|
/* As mpls uses destination specific addresses
|
||||||
* (or source specific address in the case of multicast)
|
* (or source specific address in the case of multicast)
|
||||||
* all addresses have universal scope.
|
* 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;
|
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;
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
cfg->rc_label = LABEL_NOT_SPECIFIED;
|
cfg->rc_label = LABEL_NOT_SPECIFIED;
|
||||||
cfg->rc_protocol = rtm->rtm_protocol;
|
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:
|
case RTA_NEWDST:
|
||||||
if (nla_get_labels(nla, MAX_NEW_LABELS,
|
if (nla_get_labels(nla, MAX_NEW_LABELS,
|
||||||
&cfg->rc_output_labels,
|
&cfg->rc_output_labels,
|
||||||
cfg->rc_output_label, NULL))
|
cfg->rc_output_label, extack))
|
||||||
goto errout;
|
goto errout;
|
||||||
break;
|
break;
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
{
|
{
|
||||||
u8 label_count;
|
u8 label_count;
|
||||||
if (nla_get_labels(nla, 1, &label_count,
|
if (nla_get_labels(nla, 1, &label_count,
|
||||||
&cfg->rc_label, NULL))
|
&cfg->rc_label, extack))
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
if (!mpls_label_ok(cfg->rc_nlinfo.nl_net,
|
if (!mpls_label_ok(cfg->rc_nlinfo.nl_net,
|
||||||
cfg->rc_label))
|
cfg->rc_label, extack))
|
||||||
goto errout;
|
goto errout;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RTA_VIA:
|
case RTA_VIA:
|
||||||
{
|
{
|
||||||
if (nla_get_via(nla, &cfg->rc_via_alen,
|
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;
|
goto errout;
|
||||||
break;
|
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);
|
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;
|
goto errout;
|
||||||
|
}
|
||||||
cfg->rc_ttl_propagate = ttl_propagate ?
|
cfg->rc_ttl_propagate = ttl_propagate ?
|
||||||
MPLS_TTL_PROP_ENABLED :
|
MPLS_TTL_PROP_ENABLED :
|
||||||
MPLS_TTL_PROP_DISABLED;
|
MPLS_TTL_PROP_DISABLED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
NL_SET_ERR_MSG_ATTR(extack, nla, "Unknown attribute");
|
||||||
/* Unsupported attribute */
|
/* Unsupported attribute */
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
@ -1788,11 +1835,11 @@ static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
if (!cfg)
|
if (!cfg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = rtm_to_route_config(skb, nlh, cfg);
|
err = rtm_to_route_config(skb, nlh, cfg, extack);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = mpls_route_del(cfg);
|
err = mpls_route_del(cfg, extack);
|
||||||
out:
|
out:
|
||||||
kfree(cfg);
|
kfree(cfg);
|
||||||
|
|
||||||
|
@ -1810,11 +1857,11 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
if (!cfg)
|
if (!cfg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = rtm_to_route_config(skb, nlh, cfg);
|
err = rtm_to_route_config(skb, nlh, cfg, extack);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = mpls_route_add(cfg);
|
err = mpls_route_add(cfg, extack);
|
||||||
out:
|
out:
|
||||||
kfree(cfg);
|
kfree(cfg);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
|
||||||
u32 label[], struct netlink_ext_ack *extack);
|
u32 label[], struct netlink_ext_ack *extack);
|
||||||
int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
|
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);
|
bool mpls_output_possible(const struct net_device *dev);
|
||||||
unsigned int mpls_dev_mtu(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);
|
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
|
||||||
|
|
Loading…
Reference in New Issue