Merge branch 'mpls-fixes'

Robert Shearman says:

====================
mpls: fixes for nexthops without via addresses

These four fixes all apply to the case of having an mpls route with an
output device, but without a nexthop.

Patches 2 and 3 could really have been combined in one patch, but I
wanted to separate the fix for some recent breakage from the fix for a
day-1 issue.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-12-12 00:43:44 -05:00
commit 6d13cab4ab
1 changed files with 31 additions and 12 deletions

View File

@ -27,6 +27,8 @@
*/ */
#define MAX_MP_SELECT_LABELS 4 #define MAX_MP_SELECT_LABELS 4
#define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
static int zero = 0; static int zero = 0;
static int label_limit = (1 << 20) - 1; static int label_limit = (1 << 20) - 1;
@ -317,7 +319,13 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
} }
} }
err = neigh_xmit(nh->nh_via_table, out_dev, mpls_nh_via(rt, nh), skb); /* If via wasn't specified then send out using device address */
if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
out_dev->dev_addr, skb);
else
err = neigh_xmit(nh->nh_via_table, out_dev,
mpls_nh_via(rt, nh), skb);
if (err) if (err)
net_dbg_ratelimited("%s: packet transmission failed: %d\n", net_dbg_ratelimited("%s: packet transmission failed: %d\n",
__func__, err); __func__, err);
@ -534,6 +542,10 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
if (!mpls_dev_get(dev)) if (!mpls_dev_get(dev))
goto errout; goto errout;
if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
(dev->addr_len != nh->nh_via_alen))
goto errout;
RCU_INIT_POINTER(nh->nh_dev, dev); RCU_INIT_POINTER(nh->nh_dev, dev);
return 0; return 0;
@ -592,10 +604,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
goto errout; goto errout;
} }
err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table, if (via) {
__mpls_nh_via(rt, nh)); err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
if (err) __mpls_nh_via(rt, nh));
goto errout; if (err)
goto errout;
} else {
nh->nh_via_table = MPLS_NEIGH_TABLE_UNSPEC;
}
err = mpls_nh_assign_dev(net, rt, nh, oif); err = mpls_nh_assign_dev(net, rt, nh, oif);
if (err) if (err)
@ -677,9 +693,6 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
nla_newdst = nla_find(attrs, attrlen, RTA_NEWDST); nla_newdst = nla_find(attrs, attrlen, RTA_NEWDST);
} }
if (!nla_via)
goto errout;
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, rtnh->rtnh_ifindex, nla_via,
nla_newdst); nla_newdst);
@ -1118,6 +1131,7 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
cfg->rc_label = LABEL_NOT_SPECIFIED; cfg->rc_label = LABEL_NOT_SPECIFIED;
cfg->rc_protocol = rtm->rtm_protocol; cfg->rc_protocol = rtm->rtm_protocol;
cfg->rc_via_table = MPLS_NEIGH_TABLE_UNSPEC;
cfg->rc_nlflags = nlh->nlmsg_flags; cfg->rc_nlflags = nlh->nlmsg_flags;
cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid; cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid;
cfg->rc_nlinfo.nlh = nlh; cfg->rc_nlinfo.nlh = nlh;
@ -1231,7 +1245,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
nla_put_labels(skb, RTA_NEWDST, nh->nh_labels, nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
nh->nh_label)) nh->nh_label))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh), if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
nh->nh_via_alen)) nh->nh_via_alen))
goto nla_put_failure; goto nla_put_failure;
dev = rtnl_dereference(nh->nh_dev); dev = rtnl_dereference(nh->nh_dev);
@ -1257,7 +1272,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
nh->nh_labels, nh->nh_labels,
nh->nh_label)) nh->nh_label))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_via(skb, nh->nh_via_table, if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
nla_put_via(skb, nh->nh_via_table,
mpls_nh_via(rt, nh), mpls_nh_via(rt, nh),
nh->nh_via_alen)) nh->nh_via_alen))
goto nla_put_failure; goto nla_put_failure;
@ -1319,7 +1335,8 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
if (nh->nh_dev) if (nh->nh_dev)
payload += nla_total_size(4); /* RTA_OIF */ payload += nla_total_size(4); /* RTA_OIF */
payload += nla_total_size(2 + nh->nh_via_alen); /* RTA_VIA */ if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC) /* RTA_VIA */
payload += nla_total_size(2 + nh->nh_via_alen);
if (nh->nh_labels) /* RTA_NEWDST */ if (nh->nh_labels) /* RTA_NEWDST */
payload += nla_total_size(nh->nh_labels * 4); payload += nla_total_size(nh->nh_labels * 4);
} else { } else {
@ -1328,7 +1345,9 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
for_nexthops(rt) { for_nexthops(rt) {
nhsize += nla_total_size(sizeof(struct rtnexthop)); nhsize += nla_total_size(sizeof(struct rtnexthop));
nhsize += nla_total_size(2 + nh->nh_via_alen); /* RTA_VIA */
if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC)
nhsize += nla_total_size(2 + nh->nh_via_alen);
if (nh->nh_labels) if (nh->nh_labels)
nhsize += nla_total_size(nh->nh_labels * 4); nhsize += nla_total_size(nh->nh_labels * 4);
} endfor_nexthops(rt); } endfor_nexthops(rt);