Commit 7bdf4de1 authored by Donald Sharp's avatar Donald Sharp Committed by David S. Miller

net: Properly update v4 routes with v6 nexthop

When creating a v4 route that uses a v6 nexthop from a nexthop group.
Allow the kernel to properly send the nexthop as v6 via the RTA_VIA
attribute.

Broken behavior:

$ ip nexthop add via fe80::9 dev eth0
$ ip nexthop show
id 1 via fe80::9 dev eth0 scope link
$ ip route add 4.5.6.7/32 nhid 1
$ ip route show
default via 10.0.2.2 dev eth0
4.5.6.7 nhid 1 via 254.128.0.0 dev eth0
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
$

Fixed behavior:

$ ip nexthop add via fe80::9 dev eth0
$ ip nexthop show
id 1 via fe80::9 dev eth0 scope link
$ ip route add 4.5.6.7/32 nhid 1
$ ip route show
default via 10.0.2.2 dev eth0
4.5.6.7 nhid 1 via inet6 fe80::9 dev eth0
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
$

v2, v3: Addresses code review comments from David Ahern

Fixes: dcb1ecb5 (“ipv4: Prepare for fib6_nh from a nexthop object”)
Signed-off-by: default avatarDonald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9752c83
...@@ -513,7 +513,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, ...@@ -513,7 +513,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct netlink_callback *cb); struct netlink_callback *cb);
int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh, int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh,
unsigned char *flags, bool skip_oif); u8 rt_family, unsigned char *flags, bool skip_oif);
int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh, int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh,
int nh_weight); int nh_weight, u8 rt_family);
#endif /* _NET_FIB_H */ #endif /* _NET_FIB_H */
...@@ -161,7 +161,8 @@ struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel) ...@@ -161,7 +161,8 @@ struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
} }
static inline static inline
int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh) int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
u8 rt_family)
{ {
struct nh_group *nhg = rtnl_dereference(nh->nh_grp); struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
int i; int i;
...@@ -172,7 +173,7 @@ int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh) ...@@ -172,7 +173,7 @@ int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
struct fib_nh_common *nhc = &nhi->fib_nhc; struct fib_nh_common *nhc = &nhi->fib_nhc;
int weight = nhg->nh_entries[i].weight; int weight = nhg->nh_entries[i].weight;
if (fib_add_nexthop(skb, nhc, weight) < 0) if (fib_add_nexthop(skb, nhc, weight, rt_family) < 0)
return -EMSGSIZE; return -EMSGSIZE;
} }
......
...@@ -1582,7 +1582,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, ...@@ -1582,7 +1582,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
} }
int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc, int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
unsigned char *flags, bool skip_oif) u8 rt_family, unsigned char *flags, bool skip_oif)
{ {
if (nhc->nhc_flags & RTNH_F_DEAD) if (nhc->nhc_flags & RTNH_F_DEAD)
*flags |= RTNH_F_DEAD; *flags |= RTNH_F_DEAD;
...@@ -1613,7 +1613,7 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc, ...@@ -1613,7 +1613,7 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
/* if gateway family does not match nexthop family /* if gateway family does not match nexthop family
* gateway is encoded as RTA_VIA * gateway is encoded as RTA_VIA
*/ */
if (nhc->nhc_gw_family != nhc->nhc_family) { if (rt_family != nhc->nhc_gw_family) {
int alen = sizeof(struct in6_addr); int alen = sizeof(struct in6_addr);
struct nlattr *nla; struct nlattr *nla;
struct rtvia *via; struct rtvia *via;
...@@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(fib_nexthop_info); ...@@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(fib_nexthop_info);
#if IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) || IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) || IS_ENABLED(CONFIG_IPV6)
int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc, int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
int nh_weight) int nh_weight, u8 rt_family)
{ {
const struct net_device *dev = nhc->nhc_dev; const struct net_device *dev = nhc->nhc_dev;
struct rtnexthop *rtnh; struct rtnexthop *rtnh;
...@@ -1667,7 +1667,7 @@ int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc, ...@@ -1667,7 +1667,7 @@ int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
rtnh->rtnh_hops = nh_weight - 1; rtnh->rtnh_hops = nh_weight - 1;
rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
if (fib_nexthop_info(skb, nhc, &flags, true) < 0) if (fib_nexthop_info(skb, nhc, rt_family, &flags, true) < 0)
goto nla_put_failure; goto nla_put_failure;
rtnh->rtnh_flags = flags; rtnh->rtnh_flags = flags;
...@@ -1693,13 +1693,14 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi) ...@@ -1693,13 +1693,14 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi)
goto nla_put_failure; goto nla_put_failure;
if (unlikely(fi->nh)) { if (unlikely(fi->nh)) {
if (nexthop_mpath_fill_node(skb, fi->nh) < 0) if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0)
goto nla_put_failure; goto nla_put_failure;
goto mp_end; goto mp_end;
} }
for_nexthops(fi) { for_nexthops(fi) {
if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight) < 0) if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight,
AF_INET) < 0)
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
if (nh->nh_tclassid && if (nh->nh_tclassid &&
...@@ -1775,7 +1776,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -1775,7 +1776,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
const struct fib_nh_common *nhc = fib_info_nhc(fi, 0); const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
unsigned char flags = 0; unsigned char flags = 0;
if (fib_nexthop_info(skb, nhc, &flags, false) < 0) if (fib_nexthop_info(skb, nhc, AF_INET, &flags, false) < 0)
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_flags = flags; rtm->rtm_flags = flags;
......
...@@ -5333,7 +5333,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh, ...@@ -5333,7 +5333,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
if (!mp) if (!mp)
goto nla_put_failure; goto nla_put_failure;
if (nexthop_mpath_fill_node(skb, nh)) if (nexthop_mpath_fill_node(skb, nh, AF_INET6))
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, mp); nla_nest_end(skb, mp);
...@@ -5341,7 +5341,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh, ...@@ -5341,7 +5341,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
struct fib6_nh *fib6_nh; struct fib6_nh *fib6_nh;
fib6_nh = nexthop_fib6_nh(nh); fib6_nh = nexthop_fib6_nh(nh);
if (fib_nexthop_info(skb, &fib6_nh->nh_common, if (fib_nexthop_info(skb, &fib6_nh->nh_common, AF_INET6,
flags, false) < 0) flags, false) < 0)
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -5470,13 +5470,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -5470,13 +5470,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common, if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common,
rt->fib6_nh->fib_nh_weight) < 0) rt->fib6_nh->fib_nh_weight, AF_INET6) < 0)
goto nla_put_failure; goto nla_put_failure;
list_for_each_entry_safe(sibling, next_sibling, list_for_each_entry_safe(sibling, next_sibling,
&rt->fib6_siblings, fib6_siblings) { &rt->fib6_siblings, fib6_siblings) {
if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common, if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
sibling->fib6_nh->fib_nh_weight) < 0) sibling->fib6_nh->fib_nh_weight,
AF_INET6) < 0)
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -5493,7 +5494,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -5493,7 +5494,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
rtm->rtm_flags |= nh_flags; rtm->rtm_flags |= nh_flags;
} else { } else {
if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6,
&nh_flags, false) < 0) &nh_flags, false) < 0)
goto nla_put_failure; goto nla_put_failure;
......
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