Skip to content

Commit 94b4775

Browse files
net: ip6mr: add RTM_GETROUTE netlink op
JIRA: https://issues.redhat.com/browse/RHEL-50554 Upstream Status: net.git commit d7c31cb Author: David Lamparter <equinox@diac24.net> Date: Tue Jul 12 14:10:02 2022 +0200 net: ip6mr: add RTM_GETROUTE netlink op The IPv6 multicast routing code previously implemented only the dump variant of RTM_GETROUTE. Implement single MFC item retrieval by copying and adapting the respective IPv4 code. Tested against FRRouting's IPv6 PIM stack. Signed-off-by: David Lamparter <equinox@diac24.net> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Reviewed-by: David Ahern <dsahern@kernel.org> Cc: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
1 parent 080ae15 commit 94b4775

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

net/ipv6/ip6mr.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
9090
static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
9191
int cmd);
9292
static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
93+
static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
94+
struct netlink_ext_ack *extack);
9395
static int ip6mr_rtm_dumproute(struct sk_buff *skb,
9496
struct netlink_callback *cb);
9597
static void mroute_clean_tables(struct mr_table *mrt, int flags);
@@ -1388,7 +1390,7 @@ int __init ip6_mr_init(void)
13881390
}
13891391
#endif
13901392
err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1391-
NULL, ip6mr_rtm_dumproute, 0);
1393+
ip6mr_rtm_getroute, ip6mr_rtm_dumproute, 0);
13921394
if (err == 0)
13931395
return 0;
13941396

@@ -2488,6 +2490,95 @@ static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
24882490
rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
24892491
}
24902492

2493+
static const struct nla_policy ip6mr_getroute_policy[RTA_MAX + 1] = {
2494+
[RTA_SRC] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
2495+
[RTA_DST] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
2496+
[RTA_TABLE] = { .type = NLA_U32 },
2497+
};
2498+
2499+
static int ip6mr_rtm_valid_getroute_req(struct sk_buff *skb,
2500+
const struct nlmsghdr *nlh,
2501+
struct nlattr **tb,
2502+
struct netlink_ext_ack *extack)
2503+
{
2504+
struct rtmsg *rtm;
2505+
int err;
2506+
2507+
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, ip6mr_getroute_policy,
2508+
extack);
2509+
if (err)
2510+
return err;
2511+
2512+
rtm = nlmsg_data(nlh);
2513+
if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
2514+
(rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
2515+
rtm->rtm_tos || rtm->rtm_table || rtm->rtm_protocol ||
2516+
rtm->rtm_scope || rtm->rtm_type || rtm->rtm_flags) {
2517+
NL_SET_ERR_MSG_MOD(extack,
2518+
"Invalid values in header for multicast route get request");
2519+
return -EINVAL;
2520+
}
2521+
2522+
if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
2523+
(tb[RTA_DST] && !rtm->rtm_dst_len)) {
2524+
NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
2525+
return -EINVAL;
2526+
}
2527+
2528+
return 0;
2529+
}
2530+
2531+
static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2532+
struct netlink_ext_ack *extack)
2533+
{
2534+
struct net *net = sock_net(in_skb->sk);
2535+
struct in6_addr src = {}, grp = {};
2536+
struct nlattr *tb[RTA_MAX + 1];
2537+
struct mfc6_cache *cache;
2538+
struct mr_table *mrt;
2539+
struct sk_buff *skb;
2540+
u32 tableid;
2541+
int err;
2542+
2543+
err = ip6mr_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
2544+
if (err < 0)
2545+
return err;
2546+
2547+
if (tb[RTA_SRC])
2548+
src = nla_get_in6_addr(tb[RTA_SRC]);
2549+
if (tb[RTA_DST])
2550+
grp = nla_get_in6_addr(tb[RTA_DST]);
2551+
tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
2552+
2553+
mrt = ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
2554+
if (!mrt) {
2555+
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
2556+
return -ENOENT;
2557+
}
2558+
2559+
/* entries are added/deleted only under RTNL */
2560+
rcu_read_lock();
2561+
cache = ip6mr_cache_find(mrt, &src, &grp);
2562+
rcu_read_unlock();
2563+
if (!cache) {
2564+
NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found");
2565+
return -ENOENT;
2566+
}
2567+
2568+
skb = nlmsg_new(mr6_msgsize(false, mrt->maxvif), GFP_KERNEL);
2569+
if (!skb)
2570+
return -ENOBUFS;
2571+
2572+
err = ip6mr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid,
2573+
nlh->nlmsg_seq, cache, RTM_NEWROUTE, 0);
2574+
if (err < 0) {
2575+
kfree_skb(skb);
2576+
return err;
2577+
}
2578+
2579+
return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
2580+
}
2581+
24912582
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
24922583
{
24932584
const struct nlmsghdr *nlh = cb->nlh;

0 commit comments

Comments
 (0)