* [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route()
@ 2026-11-11 9:45 Wenbo Sun
2026-11-12 2:14 ` Hangbin Liu
2026-11-15 10:07 ` netdev-bot+sashiko
0 siblings, 2 replies; 4+ messages in thread
From: Wenbo Sun @ 2026-11-11 9:45 UTC (permalink / raw)
To: David Ahern, Ido Schimmel, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, sunwenbo, 1342116488
When CONFIG_IPV6_MROUTE is enabled, rt6_fill_node() unconditionally calls
ip6mr_get_route() whenever an input interface is specified and the
destination address is multicast.
However, if multicast routing is not active (i.e. no multicast routing
daemon is running and mc_forwarding is 0), there is no matching (S,G)
multicast routing cache entry, and skb->dev is NULL in the synthetic route
query skb allocated by inet6_rtm_getroute(). As a result, ip6mr_get_route()
returns -ENODEV, which causes rt6_fill_node() to jump to nla_put_failure
and return -EMSGSIZE to userspace ("RTNETLINK answers: Message too long").
In contrast, IPv4 counterpart rt_fill_info() checks
IPV4_DEVCONF_ALL_RO(net, MC_FORWARDING) before attempting to query
ipmr_get_route(), and falls back to emitting RTA_IIF and normal local
delivery route attributes when multicast routing is not enabled.
This discrepancy was identified during code audit of multicast route get
handling. The failure was confirmed on a UML kernel: querying an IPv6
multicast route with an input interface ("ip -6 route get <mcast_addr>
from <src_addr> ...") failed with -EMSGSIZE on an unpatched kernel.
Align IPv6 behavior with IPv4 by checking whether mc_forwarding is active
(atomic_read(&net->ipv6.devconf_all->mc_forwarding)) before calling
ip6mr_get_route(). When mc_forwarding is 0, rt6_fill_node() proceeds to
output RTA_IIF and normal route attributes.
Tested:
- On a UML kernel with CONFIG_IPV6_MROUTE=y, verified that
"ip -6 route get ff0e::1 from 2001:db8::3 ..." with an input interface
now succeeds and outputs the route instead of failing with -EMSGSIZE.
- Verified that IPv6 unicast route get and multicast route get without
an input interface continue to work as expected.
- Built with W=1 on UML, x86_64 allmodconfig, and x86_64 allyesconfig with
zero new warnings or errors.
Signed-off-by: Wenbo Sun <sunwenbo@cmss.chinamobile.com>
---
net/ipv6/route.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 2eb884558c24..6dd4a70f6490 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5862,7 +5862,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
#endif
if (iif) {
#ifdef CONFIG_IPV6_MROUTE
- if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
+ if (ipv6_addr_is_multicast(&rt6_dst->addr) &&
+ atomic_read(&net->ipv6.devconf_all->mc_forwarding)) {
int err = ip6mr_get_route(net, skb, rtm, portid);
if (err == 0)
--
2.33.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route()
2026-11-11 9:45 [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route() Wenbo Sun
@ 2026-11-12 2:14 ` Hangbin Liu
2026-11-12 7:15 ` Wenbo Sun
2026-11-15 10:07 ` netdev-bot+sashiko
1 sibling, 1 reply; 4+ messages in thread
From: Hangbin Liu @ 2026-11-12 2:14 UTC (permalink / raw)
To: Wenbo Sun
Cc: David Ahern, Ido Schimmel, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
1342116488
Hi Wenbo,
On Wed, Nov 11, 2026 at 05:45:28PM +0800, Wenbo Sun wrote:
> When CONFIG_IPV6_MROUTE is enabled, rt6_fill_node() unconditionally calls
> ip6mr_get_route() whenever an input interface is specified and the
> destination address is multicast.
>
> However, if multicast routing is not active (i.e. no multicast routing
> daemon is running and mc_forwarding is 0), there is no matching (S,G)
> multicast routing cache entry, and skb->dev is NULL in the synthetic route
> query skb allocated by inet6_rtm_getroute(). As a result, ip6mr_get_route()
> returns -ENODEV, which causes rt6_fill_node() to jump to nla_put_failure
> and return -EMSGSIZE to userspace ("RTNETLINK answers: Message too long").
>
> In contrast, IPv4 counterpart rt_fill_info() checks
> IPV4_DEVCONF_ALL_RO(net, MC_FORWARDING) before attempting to query
> ipmr_get_route(), and falls back to emitting RTA_IIF and normal local
> delivery route attributes when multicast routing is not enabled.
>
> This discrepancy was identified during code audit of multicast route get
> handling. The failure was confirmed on a UML kernel: querying an IPv6
> multicast route with an input interface ("ip -6 route get <mcast_addr>
> from <src_addr> ...") failed with -EMSGSIZE on an unpatched kernel.
>
> Align IPv6 behavior with IPv4 by checking whether mc_forwarding is active
> (atomic_read(&net->ipv6.devconf_all->mc_forwarding)) before calling
> ip6mr_get_route(). When mc_forwarding is 0, rt6_fill_node() proceeds to
> output RTA_IIF and normal route attributes.
>
> Tested:
> - On a UML kernel with CONFIG_IPV6_MROUTE=y, verified that
> "ip -6 route get ff0e::1 from 2001:db8::3 ..." with an input interface
> now succeeds and outputs the route instead of failing with -EMSGSIZE.
> - Verified that IPv6 unicast route get and multicast route get without
> an input interface continue to work as expected.
> - Built with W=1 on UML, x86_64 allmodconfig, and x86_64 allyesconfig with
> zero new warnings or errors.
>
> Signed-off-by: Wenbo Sun <sunwenbo@cmss.chinamobile.com>
> ---
> net/ipv6/route.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 2eb884558c24..6dd4a70f6490 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -5862,7 +5862,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
> #endif
> if (iif) {
> #ifdef CONFIG_IPV6_MROUTE
> - if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
> + if (ipv6_addr_is_multicast(&rt6_dst->addr) &&
> + atomic_read(&net->ipv6.devconf_all->mc_forwarding)) {
> int err = ip6mr_get_route(net, skb, rtm, portid);
>
> if (err == 0)
In commit fd61c6ba313d ("net: ipv6: remove nowait arg to rt6_fill_node"),
David Ahern removed the nowait arg. Should we still return immediately
after err == 0? Also later if (err < 0), it still goto nla_put_failure
and return -EMSGSIZE. Maybe we can carry the err to the end and return
a more meaningful reason?
Anyway the added checking makes sense to me.
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route()
2026-11-12 2:14 ` Hangbin Liu
@ 2026-11-12 7:15 ` Wenbo Sun
0 siblings, 0 replies; 4+ messages in thread
From: Wenbo Sun @ 2026-11-12 7:15 UTC (permalink / raw)
To: Hangbin Liu
Cc: David Ahern, Ido Schimmel, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
sunwenbo, 1342116488
Hi Hangbin,
Thanks for the review and the Reviewed-by tag!
On Thu, Nov 12, 2026 at 02:14:50AM +0000, Hangbin Liu wrote:
> In commit fd61c6ba313d ("net: ipv6: remove nowait arg to rt6_fill_node"),
> David Ahern removed the nowait arg. Should we still return immediately
> after err == 0? Also later if (err < 0), it still goto nla_put_failure
> and return -EMSGSIZE. Maybe we can carry the err to the end and return
> a more meaningful reason?
>
> Anyway the added checking makes sense to me.
>
> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Both are very good observations on the existing ip6mr_get_route() error
handling in rt6_fill_node():
1) Regarding `if (err == 0) return 0;`:
Commit fd61c6ba313d only removed the unused `nowait` parameter (whose
value was always 0) and kept the pre-existing `!nowait && err == 0`
early return, mirroring IPv4 rt_fill_info(). Returning 0 from
ip6mr_get_route() means a cache miss was queued via
ip6mr_cache_unresolved() on nl_queries for asynchronous resolution;
falling through in rt6_fill_node() would append normal FIB attributes
without RTA_IIF.
That said, looking closely at inet6_rtm_getroute(), `skb->dev` is
currently never assigned there (unlike inet_rtm_getroute() in IPv4),
so on a cache miss ip6mr_get_route() takes `if (!dev || ...)` and
returns -ENODEV before ever reaching ip6mr_cache_unresolved(). Even
if `err == 0` were reached, returning 0 early skips nlmsg_end() while
inet6_rtm_getroute() still calls rtnl_unicast() when `err >= 0`.
Reworking that path would require changes in ip6mr.c and
inet6_rtm_getroute(), which goes beyond this patch's scope.
2) Regarding returning the real negative `err` instead of -EMSGSIZE:
Agreed -- ip6mr_get_route() can return -ENOENT, -ENODEV, -ENOMEM, or
-ENOBUFS, and jumping to nla_put_failure masks all of them as
-EMSGSIZE ("Message too long") even when mc_forwarding is enabled.
Among all callers of rt6_fill_node(), only inet6_rtm_getroute() passes
a non-zero iif and propagates negative errors back to userspace, so
initializing `int err = -EMSGSIZE;` and returning `err` at the failure
label looks safe and much cleaner.
To make it easy to review both together while keeping each change clear,
I plan to split this into a 2-patch [PATCH net-next v2 1/2] + [2/2]
series after the 24-hour resend window:
- Patch 1/2: check mc_forwarding before calling ip6mr_get_route()
(carrying your Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>).
- Patch 2/2: preserve and return the negative error from
ip6mr_get_route() in rt6_fill_node() instead of -EMSGSIZE.
Thanks,
Wenbo
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route()
2026-11-11 9:45 [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route() Wenbo Sun
2026-11-12 2:14 ` Hangbin Liu
@ 2026-11-15 10:07 ` netdev-bot+sashiko
1 sibling, 0 replies; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-11-15 10:07 UTC (permalink / raw)
To: sunwenbo
Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, netdev,
linux-kernel, 1342116488
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 2 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The fix only works when no multicast routing daemon is
running.
- [Medium] The patch says it aligns rt6_fill_node() with IPv4's
rt_fill_info(), but it copies only half of the IPv4 condition.
- [Low] The commit fixes a user-visible netlink failure ('RTNETLINK
answers: Message too long' from RTM_GETROUTE for an IPv6 multicast…
--
ipv6: check mc_forwarding before calling ip6mr_get_route()
With this patch, rt6_fill_node() calls ip6mr_get_route() only when
mc_forwarding is non-zero. A route get for a multicast destination with an
input interface then no longer fails with -EMSGSIZE when no multicast
routing daemon is running. The commit message says this aligns IPv6 with
the IPv4 rt_fill_info() behavior.
> Signed-off-by: Wenbo Sun <sunwenbo@cmss.chinamobile.com>
[Severity: Low]
Should this have a Fixes: tag, and possibly a Cc to stable?
The patch fixes a user-visible "RTNETLINK answers: Message too long" error
from RTM_GETROUTE. git blame shows that the ungated ip6mr_get_route() call
in rt6_fill_node() was added by:
commit 7bc570c8b4f7 ("[IPV6] MROUTE: Support multicast forwarding.")
The current err < 0 to nla_put_failure mapping came later, from
fd61c6ba313d ("net: ipv6: remove nowait arg to rt6_fill_node").
inet6_rtm_getroute() has never set skb->dev on the reply skb, so the
failure has been reachable since then.
Without a Fixes: tag, the stable tooling will not pick this up.
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 04098cf32eabe..cb8cfd8b5c8b7 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -5862,7 +5862,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
> #endif
> if (iif) {
> #ifdef CONFIG_IPV6_MROUTE
> - if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
> + if (ipv6_addr_is_multicast(&rt6_dst->addr) &&
> + atomic_read(&net->ipv6.devconf_all->mc_forwarding)) {
[Severity: Medium]
Doesn't this still return -EMSGSIZE whenever a multicast routing daemon is
running?
The commit message links "skb->dev is NULL" to multicast routing being
inactive. However, inet6_rtm_getroute() never sets skb->dev on the reply
skb, whatever the value of mc_forwarding:
net/ipv6/route.c:inet6_rtm_getroute() {
...
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
...
skb_dst_set(skb, &rt->dst);
...
}
The iif device is resolved earlier with dev_get_by_index_rcu(), but it is
only used for ip6_route_input_lookup().
Because skb->dev is NULL, ip6mr_get_route() skips the (*,G) fallback, and
every cache miss ends up here:
net/ipv6/ip6mr.c:ip6mr_get_route() {
...
cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
if (!cache && skb->dev) {
...
dev = skb->dev;
if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
rcu_read_unlock();
return -ENODEV;
}
...
}
A cache hit also looks unlikely. The lookup uses rt6i_src and rt6i_dst of
the pcpu route. ip6_rt_copy_init() copies those from the FIB prefix (for
example ff00::/8), not from the queried S,G:
rt->rt6i_dst = f6i->fib6_dst;
So when mc_forwarding != 0, the path is still:
inet6_rtm_getroute()
rt6_fill_node()
ip6mr_get_route() -> -ENODEV
goto nla_put_failure -> -EMSGSIZE
The IPv4 code that the commit says it aligns with sets skb->dev in
inet_rtm_getroute():
fl4.flowi4_iif = iif; /* for rt_fill_info */
skb->dev = dev;
For output lookups it uses net->loopback_dev. rt_fill_info() also passes
fl4->saddr and fl4->daddr to ipmr_get_route().
Would it make sense to also set skb->dev in inet6_rtm_getroute(), look up
the queried S,G, or stop mapping ip6mr_get_route() errors to -EMSGSIZE?
Any of these would also cover the case where a daemon is running.
[Severity: Medium]
Should this also exclude link-local and node-local multicast, as the IPv4
condition does?
rt_fill_info() in net/ipv4/route.c uses:
if (ipv4_is_multicast(dst) &&
!ipv4_is_local_multicast(dst) &&
IPV4_DEVCONF_ALL_RO(net, MC_FORWARDING)) {
On IPv6, ip6_mc_input() never forwards loopback-scope or link-local
groups:
if (atomic_read(&dev_net_rcu(skb->dev)->ipv6.devconf_all->mc_forwarding) &&
!(ipv6_addr_type(&hdr->daddr) &
(IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) &&
This means no MFC state can ever exist for those groups.
With this patch, a query such as "ip -6 route get ff02::1 from fe80::1 iif
eth0" still reaches ip6mr_get_route() whenever mc_forwarding != 0. It gets
-ENODEV there and returns -EMSGSIZE. For the same kind of query, IPv4
returns RTA_IIF and a normal local route.
Also, rt6_dst->addr is the route prefix (typically ff00::/8 from
addrconf), not the queried group. Would a scope check need to test dest
instead in order to work?
> int err = ip6mr_get_route(net, skb, rtm, portid);
>
> if (err == 0)
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261111094528.425826-1-sunwenbo%40cmss.chinamobile.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-15 10:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-11 9:45 [PATCH net-next] ipv6: check mc_forwarding before calling ip6mr_get_route() Wenbo Sun
2026-11-12 2:14 ` Hangbin Liu
2026-11-12 7:15 ` Wenbo Sun
2026-11-15 10:07 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®