From fa827800568df3c91b0c7dd66cda24ee2cd45d1c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Jan 2024 15:56:31 +0000 Subject: [PATCH] Revert "ipv6: remove max_size check inline with ipv4" This reverts commit 584756c3d75a1722a868a1d22602251385bee798 which is commit af6d10345ca76670c1b7c37799f0d5576ccef277 upstream. It breaks the Android kernel abi and can be brought back in the future in an abi-safe way if it is really needed. Bug: 161946584 Change-Id: I7e768b45f1b301807a89234d2af0fd025a13396e Signed-off-by: Greg Kroah-Hartman --- include/net/dst_ops.h | 2 +- net/core/dst.c | 8 ++++++-- net/ipv6/route.c | 13 ++++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h index 632086b2f644..88ff7bb2bb9b 100644 --- a/include/net/dst_ops.h +++ b/include/net/dst_ops.h @@ -16,7 +16,7 @@ struct dst_ops { unsigned short family; unsigned int gc_thresh; - void (*gc)(struct dst_ops *ops); + int (*gc)(struct dst_ops *ops); struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); unsigned int (*default_advmss)(const struct dst_entry *); unsigned int (*mtu)(const struct dst_entry *); diff --git a/net/core/dst.c b/net/core/dst.c index 107aea25a564..d6b6ced0d451 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -83,8 +83,12 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, if (ops->gc && !(flags & DST_NOCOUNT) && - dst_entries_get_fast(ops) > ops->gc_thresh) - ops->gc(ops); + dst_entries_get_fast(ops) > ops->gc_thresh) { + if (ops->gc(ops)) { + pr_notice_ratelimited("Route cache is full: consider increasing sysctl net.ipv6.route.max_size.\n"); + return NULL; + } + } dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 16fbe7a74224..4657d6a45b22 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -88,7 +88,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *); static void ip6_dst_destroy(struct dst_entry *); static void ip6_dst_ifdown(struct dst_entry *, struct net_device *dev, int how); -static void ip6_dst_gc(struct dst_ops *ops); +static int ip6_dst_gc(struct dst_ops *ops); static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); @@ -3207,10 +3207,11 @@ out: return dst; } -static void ip6_dst_gc(struct dst_ops *ops) +static int ip6_dst_gc(struct dst_ops *ops) { struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; + int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; @@ -3218,10 +3219,11 @@ static void ip6_dst_gc(struct dst_ops *ops) int entries; entries = dst_entries_get_fast(ops); - if (entries > ops->gc_thresh) + if (entries > rt_max_size) entries = dst_entries_get_slow(ops); - if (time_after(rt_last_gc + rt_min_interval, jiffies)) + if (time_after(rt_last_gc + rt_min_interval, jiffies) && + entries <= rt_max_size) goto out; fib6_run_gc(atomic_inc_return(&net->ipv6.ip6_rt_gc_expire), net, true); @@ -3231,6 +3233,7 @@ static void ip6_dst_gc(struct dst_ops *ops) out: val = atomic_read(&net->ipv6.ip6_rt_gc_expire); atomic_set(&net->ipv6.ip6_rt_gc_expire, val - (val >> rt_elasticity)); + return entries > rt_max_size; } static int ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg, @@ -6276,7 +6279,7 @@ static int __net_init ip6_route_net_init(struct net *net) #endif net->ipv6.sysctl.flush_delay = 0; - net->ipv6.sysctl.ip6_rt_max_size = INT_MAX; + net->ipv6.sysctl.ip6_rt_max_size = 4096; net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;