Add the matching route returned in fib_result as a new, nested attribute,
RTA_ROUTE_GET, to the GETROUTE response. The rtmsg struct is added use a
new attribute, RTA_ROUTE_GET_RTM. These attributes allow userspace to show
which route was matched for a GETROUTE request.

Signed-off-by: David Ahern <d...@cumulusnetworks.com>
---
 include/uapi/linux/rtnetlink.h |  2 ++
 net/ipv4/route.c               | 36 ++++++++++++++++++++++++++++++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 8c93ad1ef9ab..471384b72cea 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -319,6 +319,8 @@ enum rtattr_type_t {
        RTA_EXPIRES,
        RTA_PAD,
        RTA_UID,
+       RTA_ROUTE_GET,  /* nested attribute; route spec for RTM_GETROUTE */
+       RTA_ROUTE_GET_RTM, /* struct rtmsg for nested spec */
        __RTA_MAX
 };
 
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 03ddc03c185a..9f44b869b8a6 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -113,6 +113,7 @@
 #include <net/secure_seq.h>
 #include <net/ip_tunnels.h>
 #include <net/l3mdev.h>
+#include "fib_lookup.h"
 
 #define RT_FL_TOS(oldflp4) \
        ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
@@ -2470,7 +2471,8 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
 /* called with rcu_read_lock held */
 static int rt_fill_info(struct net *net,  __be32 dst, __be32 src, u32 table_id,
                        struct flowi4 *fl4, struct sk_buff *skb, u32 portid,
-                       u32 seq, int event, struct rtable *rt)
+                       u32 seq, int event, struct rtable *rt,
+                       struct fib_result *res)
 {
        struct rtmsg *r;
        struct nlmsghdr *nlh;
@@ -2572,6 +2574,36 @@ static int rt_fill_info(struct net *net,  __be32 dst, 
__be32 src, u32 table_id,
        if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, error) < 0)
                goto nla_put_failure;
 
+       if (res->fi) {
+               struct nlattr *get_rt;
+               struct rtmsg r_match;
+
+               /* Add data for matching route */
+               get_rt = nla_nest_start(skb, RTA_ROUTE_GET);
+               if (!get_rt)
+                       goto nla_put_failure;
+
+               r_match.rtm_family = AF_INET;
+               r_match.rtm_dst_len = res->prefixlen;
+               r_match.rtm_src_len = 0;
+               r_match.rtm_tos  = fl4->flowi4_tos;
+               r_match.rtm_type = rt->rt_type;
+               r_match.rtm_flags = res->fi->fib_flags;
+               r_match.rtm_scope = res->fi->fib_scope;
+               r_match.rtm_protocol = res->fi->fib_protocol;
+               r_match.rtm_table = table_id;
+               if (nla_put_u32(skb, RTA_TABLE, table_id))
+                       goto nla_put_failure;
+
+               if (fib_dump_add_attrs_rcu(skb, res->prefix, &r_match, res->fi))
+                       goto nla_put_failure;
+
+               if (nla_put(skb, RTA_ROUTE_GET_RTM, sizeof(r_match), &r_match))
+                       goto nla_put_failure;
+
+               nla_nest_end(skb, get_rt);
+       }
+
        nlmsg_end(skb, nlh);
        return 0;
 
@@ -2680,7 +2712,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, 
struct nlmsghdr *nlh)
 
        err = rt_fill_info(net, dst, src, table_id, &fl4, skb,
                           NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
-                          RTM_NEWROUTE, rt);
+                          RTM_NEWROUTE, rt, &res);
        if (err < 0)
                goto errout_free;
 
-- 
2.1.4

Reply via email to