header.
        Default: INT_MAX (unlimited)
 
+skip_notify_on_dev_down - BOOLEAN
+       Controls whether an RTM_DELROUTE message is generated for routes
+       removed when a device is taken down or deleted. IPv4 does not
+       generate this message; IPv6 does by default. Setting this sysctl
+       to true skips the message, making IPv4 and IPv6 on par in relying
+       on userspace caches to track link events and evict routes.
+       Default: false (generate message)
+
 IPv6 Fragmentation:
 
 ip6frag_high_thresh - INTEGER
 
 
 void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *arg),
                    void *arg);
+void fib6_clean_all_skip_notify(struct net *net,
+                               int (*func)(struct fib6_info *, void *arg),
+                               void *arg);
 
 int fib6_add(struct fib6_node *root, struct fib6_info *rt,
             struct nl_info *info, struct netlink_ext_ack *extack);
 
        int (*func)(struct fib6_info *, void *arg);
        int sernum;
        void *arg;
+       bool skip_notify;
 };
 
 #ifdef CONFIG_IPV6_SUBTREES
        struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w);
        struct nl_info info = {
                .nl_net = c->net,
+               .skip_notify = c->skip_notify,
        };
 
        if (c->sernum != FIB6_NO_SERNUM_CHANGE &&
 
 static void fib6_clean_tree(struct net *net, struct fib6_node *root,
                            int (*func)(struct fib6_info *, void *arg),
-                           int sernum, void *arg)
+                           int sernum, void *arg, bool skip_notify)
 {
        struct fib6_cleaner c;
 
        c.sernum = sernum;
        c.arg = arg;
        c.net = net;
+       c.skip_notify = skip_notify;
 
        fib6_walk(net, &c.w);
 }
 
 static void __fib6_clean_all(struct net *net,
                             int (*func)(struct fib6_info *, void *),
-                            int sernum, void *arg)
+                            int sernum, void *arg, bool skip_notify)
 {
        struct fib6_table *table;
        struct hlist_head *head;
                hlist_for_each_entry_rcu(table, head, tb6_hlist) {
                        spin_lock_bh(&table->tb6_lock);
                        fib6_clean_tree(net, &table->tb6_root,
-                                       func, sernum, arg);
+                                       func, sernum, arg, skip_notify);
                        spin_unlock_bh(&table->tb6_lock);
                }
        }
 void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *),
                    void *arg)
 {
-       __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg);
+       __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, false);
+}
+
+void fib6_clean_all_skip_notify(struct net *net,
+                               int (*func)(struct fib6_info *, void *),
+                               void *arg)
+{
+       __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, true);
 }
 
 static void fib6_flush_trees(struct net *net)
 {
        int new_sernum = fib6_new_sernum(net);
 
-       __fib6_clean_all(net, NULL, new_sernum, NULL);
+       __fib6_clean_all(net, NULL, new_sernum, NULL, false);
 }
 
 /*
 
                        .event = event,
                },
        };
+       struct net *net = dev_net(dev);
 
-       fib6_clean_all(dev_net(dev), fib6_ifdown, &arg);
+       if (net->ipv6.sysctl.skip_notify_on_dev_down)
+               fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
+       else
+               fib6_clean_all(net, fib6_ifdown, &arg);
 }
 
 void rt6_disable_ip(struct net_device *dev, unsigned long event)
        return 0;
 }
 
+static int zero;
+static int one = 1;
+
 static struct ctl_table ipv6_route_table_template[] = {
        {
                .procname       =       "flush",
                .mode           =       0644,
                .proc_handler   =       proc_dointvec_ms_jiffies,
        },
+       {
+               .procname       =       "skip_notify_on_dev_down",
+               .data           =       &init_net.ipv6.sysctl.skip_notify_on_dev_down,
+               .maxlen         =       sizeof(int),
+               .mode           =       0644,
+               .proc_handler   =       proc_dointvec,
+               .extra1         =       &zero,
+               .extra2         =       &one,
+       },
        { }
 };
 
                table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
                table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
                table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
+               table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
 
                /* Don't export sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns)
        net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
        net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
        net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
+       net->ipv6.sysctl.skip_notify_on_dev_down = 0;
 
        net->ipv6.ip6_rt_gc_expire = 30*HZ;