At some point after b5d2d75e079a ("net/ipv6: Do not allow device only routes via the multipath API"), the IPv6 stack was updated such that device-only multipath routes can be installed and work correctly. This change removes checks that prevent them from being installed, and adds a fib6_explicit_ecmp flag to fib6_info. The flag is only checked in rt6_qualify_for_ecmp() and exists to prevent regressions. Signed-off-by: azey --- Changes in v2: - Added fib6_explicit_ecmp flag to fib6_info to prevent regressions. Very simple (and naive) fix, all it does is flag routes created as multipath and check for the flag in rt6_qualify_for_ecmp(). I'm not sure whether it should be an RTF_ flag in fib6_flags instead, but there aren't any unused bits in that field so I made it separate. - Removed hanging has_gateway as reported by bot Link to v1: https://lore.kernel.org/netdev/a6vmtv3ylu224fnj5awi6xrgnjoib5r2jm3kny672hemsk5ifi@ychcxqnmy5us/ --- include/net/ip6_fib.h | 3 ++- include/net/ip6_route.h | 5 +++-- net/ipv6/route.c | 11 ++--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 88b0dd4d8e09..da9d03cbbab4 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -196,7 +196,8 @@ struct fib6_info { dst_nocount:1, dst_nopolicy:1, fib6_destroying:1, - unused:4; + fib6_explicit_ecmp:1, + unused:3; struct list_head purge_link; struct rcu_head rcu; diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 7c5512baa4b2..5f00e9e252c2 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -73,8 +73,9 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr) static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i) { /* the RTF_ADDRCONF flag filters out RA's */ - return !(f6i->fib6_flags & RTF_ADDRCONF) && !f6i->nh && - f6i->fib6_nh->fib_nh_gw_family; + return f6i->fib6_explicit_ecmp || + (!(f6i->fib6_flags & RTF_ADDRCONF) && !f6i->nh && + f6i->fib6_nh->fib_nh_gw_family); } void ip6_route_input(struct sk_buff *skb); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aee6a10b112a..7ac69bf5ccf2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5119,7 +5119,6 @@ static int rtm_to_fib6_multipath_config(struct fib6_config *cfg, } do { - bool has_gateway = cfg->fc_flags & RTF_GATEWAY; int attrlen = rtnh_attrlen(rtnh); if (attrlen > 0) { @@ -5133,17 +5132,9 @@ static int rtm_to_fib6_multipath_config(struct fib6_config *cfg, "Invalid IPv6 address in RTA_GATEWAY"); return -EINVAL; } - - has_gateway = true; } } - if (newroute && (cfg->fc_nh_id || !has_gateway)) { - NL_SET_ERR_MSG(extack, - "Device only routes can not be added for IPv6 using the multipath API."); - return -EINVAL; - } - rtnh = rtnh_next(rtnh, &remaining); } while (rtnh_ok(rtnh, remaining)); @@ -5448,6 +5439,8 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, goto cleanup; } + rt->fib6_explicit_ecmp = true; + err = ip6_route_info_create_nh(rt, &r_cfg, GFP_KERNEL, extack); if (err) { rt = NULL; base-commit: bd10acae08aeb9cd2f555acdbacb98b9fbb02a27 -- 2.51.0