ipv6: add icmpv6_error_anycast_as_unicast for ICMPv6
authorMahesh Bandewar <maheshb@google.com>
Wed, 19 Apr 2023 01:32:38 +0000 (18:32 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 21 Apr 2023 03:07:50 +0000 (20:07 -0700)
ICMPv6 error packets are not sent to the anycast destinations and this
prevents things like traceroute from working. So create a setting similar
to ECHO when dealing with Anycast sources (icmpv6_echo_ignore_anycast).

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Maciej Żenczykowski <maze@google.com>
Link: https://lore.kernel.org/r/20230419013238.2691167-1-maheshb@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/networking/ip-sysctl.rst
include/net/netns/ipv6.h
net/ipv6/af_inet6.c
net/ipv6/icmp.c

index 58a78a3..6ec06a3 100644 (file)
@@ -2721,6 +2721,13 @@ echo_ignore_anycast - BOOLEAN
 
        Default: 0
 
+error_anycast_as_unicast - BOOLEAN
+       If set to 1, then the kernel will respond with ICMP Errors
+       resulting from requests sent to it over the IPv6 protocol destined
+       to anycast address essentially treating anycast as unicast.
+
+       Default: 0
+
 xfrm6_gc_thresh - INTEGER
        (Obsolete since linux-4.14)
        The threshold at which we will start garbage collecting for IPv6
index b4af483..3cceb3e 100644 (file)
@@ -55,6 +55,7 @@ struct netns_sysctl_ipv6 {
        u64 ioam6_id_wide;
        bool skip_notify_on_dev_down;
        u8 fib_notify_on_flag_change;
+       u8 icmpv6_error_anycast_as_unicast;
 };
 
 struct netns_ipv6 {
index e1b679a..2bbf132 100644 (file)
@@ -952,6 +952,7 @@ static int __net_init inet6_net_init(struct net *net)
        net->ipv6.sysctl.icmpv6_echo_ignore_all = 0;
        net->ipv6.sysctl.icmpv6_echo_ignore_multicast = 0;
        net->ipv6.sysctl.icmpv6_echo_ignore_anycast = 0;
+       net->ipv6.sysctl.icmpv6_error_anycast_as_unicast = 0;
 
        /* By default, rate limit error messages.
         * Except for pmtu discovery, it would break it.
index 1f53f2a..9edf1f4 100644 (file)
@@ -362,9 +362,10 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net,
 
        /*
         * We won't send icmp if the destination is known
-        * anycast.
+        * anycast unless we need to treat anycast as unicast.
         */
-       if (ipv6_anycast_destination(dst, &fl6->daddr)) {
+       if (!READ_ONCE(net->ipv6.sysctl.icmpv6_error_anycast_as_unicast) &&
+           ipv6_anycast_destination(dst, &fl6->daddr)) {
                net_dbg_ratelimited("icmp6_send: acast source\n");
                dst_release(dst);
                return ERR_PTR(-EINVAL);
@@ -1195,6 +1196,15 @@ static struct ctl_table ipv6_icmp_table_template[] = {
                .mode           = 0644,
                .proc_handler = proc_do_large_bitmap,
        },
+       {
+               .procname       = "error_anycast_as_unicast",
+               .data           = &init_net.ipv6.sysctl.icmpv6_error_anycast_as_unicast,
+               .maxlen         = sizeof(u8),
+               .mode           = 0644,
+               .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
        { },
 };
 
@@ -1212,6 +1222,7 @@ struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
                table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
                table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
                table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
+               table[5].data = &net->ipv6.sysctl.icmpv6_error_anycast_as_unicast;
        }
        return table;
 }