Commit 18c3a61c authored by Roopa Prabhu's avatar Roopa Prabhu Committed by David S. Miller

net: ipv6: RTM_GETROUTE: return matched fib result when requested

This patch adds support to return matched fib result when RTM_F_FIB_MATCH
flag is specified in RTM_GETROUTE request. This is useful for user-space
applications/controllers wanting to query a matching route.
Signed-off-by: default avatarRoopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6179813
...@@ -3607,11 +3607,13 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -3607,11 +3607,13 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
{ {
struct net *net = sock_net(in_skb->sk); struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[RTA_MAX+1]; struct nlattr *tb[RTA_MAX+1];
int err, iif = 0, oif = 0;
struct dst_entry *dst;
struct rt6_info *rt; struct rt6_info *rt;
struct sk_buff *skb; struct sk_buff *skb;
struct rtmsg *rtm; struct rtmsg *rtm;
struct flowi6 fl6; struct flowi6 fl6;
int err, iif = 0, oif = 0; bool fibmatch;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy, err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
extack); extack);
...@@ -3622,6 +3624,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -3622,6 +3624,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
memset(&fl6, 0, sizeof(fl6)); memset(&fl6, 0, sizeof(fl6));
rtm = nlmsg_data(nlh); rtm = nlmsg_data(nlh);
fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0); fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
if (tb[RTA_SRC]) { if (tb[RTA_SRC]) {
if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
...@@ -3667,12 +3670,23 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -3667,12 +3670,23 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (!ipv6_addr_any(&fl6.saddr)) if (!ipv6_addr_any(&fl6.saddr))
flags |= RT6_LOOKUP_F_HAS_SADDR; flags |= RT6_LOOKUP_F_HAS_SADDR;
rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6, if (!fibmatch)
flags); dst = ip6_route_input_lookup(net, dev, &fl6, flags);
} else { } else {
fl6.flowi6_oif = oif; fl6.flowi6_oif = oif;
rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6); if (!fibmatch)
dst = ip6_route_output(net, NULL, &fl6);
}
if (fibmatch)
dst = ip6_route_lookup(net, &fl6, 0);
rt = container_of(dst, struct rt6_info, dst);
if (rt->dst.error) {
err = rt->dst.error;
ip6_rt_put(rt);
goto errout;
} }
if (rt == net->ipv6.ip6_null_entry) { if (rt == net->ipv6.ip6_null_entry) {
...@@ -3689,10 +3703,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -3689,10 +3703,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
} }
skb_dst_set(skb, &rt->dst); skb_dst_set(skb, &rt->dst);
if (fibmatch)
err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).portid, RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0); nlh->nlmsg_seq, 0);
else
err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto errout; goto errout;
......
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