Commit 22d0bd82 authored by Xin Long's avatar Xin Long Committed by David S. Miller

ipv6: use rt6_info members when dst is set in rt6_fill_node

In inet6_rtm_getroute, since Commit 93531c67 ("net/ipv6: separate
handling of FIB entries from dst based routes"), it has used rt->from
to dump route info instead of rt.

However for some route like cache, some of its information like flags
or gateway is not the same as that of the 'from' one. It caused 'ip
route get' to dump the wrong route information.

In Jianlin's testing, the output information even lost the expiration
time for a pmtu route cache due to the wrong fib6_flags.

So change to use rt6_info members for dst addr, src addr, flags and
gateway when it tries to dump a route entry without fibmatch set.

v1->v2:
  - not use rt6i_prefsrc.
  - also fix the gw dump issue.

Fixes: 93531c67 ("net/ipv6: separate handling of FIB entries from dst based routes")
Reported-by: default avatarJianlin Shi <jishi@redhat.com>
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7428b2e5
...@@ -4670,20 +4670,31 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4670,20 +4670,31 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
int iif, int type, u32 portid, u32 seq, int iif, int type, u32 portid, u32 seq,
unsigned int flags) unsigned int flags)
{ {
struct rtmsg *rtm; struct rt6_info *rt6 = (struct rt6_info *)dst;
struct rt6key *rt6_dst, *rt6_src;
u32 *pmetrics, table, rt6_flags;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct rtmsg *rtm;
long expires = 0; long expires = 0;
u32 *pmetrics;
u32 table;
nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags); nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
if (!nlh) if (!nlh)
return -EMSGSIZE; return -EMSGSIZE;
if (rt6) {
rt6_dst = &rt6->rt6i_dst;
rt6_src = &rt6->rt6i_src;
rt6_flags = rt6->rt6i_flags;
} else {
rt6_dst = &rt->fib6_dst;
rt6_src = &rt->fib6_src;
rt6_flags = rt->fib6_flags;
}
rtm = nlmsg_data(nlh); rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET6; rtm->rtm_family = AF_INET6;
rtm->rtm_dst_len = rt->fib6_dst.plen; rtm->rtm_dst_len = rt6_dst->plen;
rtm->rtm_src_len = rt->fib6_src.plen; rtm->rtm_src_len = rt6_src->plen;
rtm->rtm_tos = 0; rtm->rtm_tos = 0;
if (rt->fib6_table) if (rt->fib6_table)
table = rt->fib6_table->tb6_id; table = rt->fib6_table->tb6_id;
...@@ -4698,7 +4709,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4698,7 +4709,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_protocol = rt->fib6_protocol; rtm->rtm_protocol = rt->fib6_protocol;
if (rt->fib6_flags & RTF_CACHE) if (rt6_flags & RTF_CACHE)
rtm->rtm_flags |= RTM_F_CLONED; rtm->rtm_flags |= RTM_F_CLONED;
if (dest) { if (dest) {
...@@ -4706,7 +4717,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4706,7 +4717,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_dst_len = 128; rtm->rtm_dst_len = 128;
} else if (rtm->rtm_dst_len) } else if (rtm->rtm_dst_len)
if (nla_put_in6_addr(skb, RTA_DST, &rt->fib6_dst.addr)) if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
if (src) { if (src) {
...@@ -4714,12 +4725,12 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4714,12 +4725,12 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_src_len = 128; rtm->rtm_src_len = 128;
} else if (rtm->rtm_src_len && } else if (rtm->rtm_src_len &&
nla_put_in6_addr(skb, RTA_SRC, &rt->fib6_src.addr)) nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
goto nla_put_failure; goto nla_put_failure;
#endif #endif
if (iif) { if (iif) {
#ifdef CONFIG_IPV6_MROUTE #ifdef CONFIG_IPV6_MROUTE
if (ipv6_addr_is_multicast(&rt->fib6_dst.addr)) { if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
int err = ip6mr_get_route(net, skb, rtm, portid); int err = ip6mr_get_route(net, skb, rtm, portid);
if (err == 0) if (err == 0)
...@@ -4754,7 +4765,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4754,7 +4765,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
/* For multipath routes, walk the siblings list and add /* For multipath routes, walk the siblings list and add
* each as a nexthop within RTA_MULTIPATH. * each as a nexthop within RTA_MULTIPATH.
*/ */
if (rt->fib6_nsiblings) { if (rt6) {
if (rt6_flags & RTF_GATEWAY &&
nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
goto nla_put_failure;
if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
goto nla_put_failure;
} else if (rt->fib6_nsiblings) {
struct fib6_info *sibling, *next_sibling; struct fib6_info *sibling, *next_sibling;
struct nlattr *mp; struct nlattr *mp;
...@@ -4777,7 +4795,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4777,7 +4795,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
} }
if (rt->fib6_flags & RTF_EXPIRES) { if (rt6_flags & RTF_EXPIRES) {
expires = dst ? dst->expires : rt->expires; expires = dst ? dst->expires : rt->expires;
expires -= jiffies; expires -= jiffies;
} }
...@@ -4785,7 +4803,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, ...@@ -4785,7 +4803,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0) if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->fib6_flags))) if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
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