diff options
author | Eric Dumazet <edumazet@google.com> | 2024-08-29 16:46:40 +0200 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-08-30 20:14:06 +0200 |
commit | b056b4cd9178f7a1d5d57f7b48b073c29729ddaa (patch) | |
tree | c52e88f67befd08e2f9c751d342c850029ebfd73 /net/ipv4/icmp.c | |
parent | icmp: change the order of rate limits (diff) | |
download | linux-b056b4cd9178f7a1d5d57f7b48b073c29729ddaa.tar.xz linux-b056b4cd9178f7a1d5d57f7b48b073c29729ddaa.zip |
icmp: move icmp_global.credit and icmp_global.stamp to per netns storage
Host wide ICMP ratelimiter should be per netns, to provide better isolation.
Following patch in this series makes the sysctl per netns.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20240829144641.3880376-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r-- | net/ipv4/icmp.c | 26 |
1 files changed, 11 insertions, 15 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 0078e8fb2e86..2e1d81dbdbb6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -223,19 +223,15 @@ static inline void icmp_xmit_unlock(struct sock *sk) int sysctl_icmp_msgs_per_sec __read_mostly = 1000; int sysctl_icmp_msgs_burst __read_mostly = 50; -static struct { - atomic_t credit; - u32 stamp; -} icmp_global; - /** * icmp_global_allow - Are we allowed to send one more ICMP message ? + * @net: network namespace * * Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec. * Returns false if we reached the limit and can not send another packet. * Works in tandem with icmp_global_consume(). */ -bool icmp_global_allow(void) +bool icmp_global_allow(struct net *net) { u32 delta, now, oldstamp; int incr, new, old; @@ -244,11 +240,11 @@ bool icmp_global_allow(void) * Then later icmp_global_consume() could consume more credits, * this is an acceptable race. */ - if (atomic_read(&icmp_global.credit) > 0) + if (atomic_read(&net->ipv4.icmp_global_credit) > 0) return true; now = jiffies; - oldstamp = READ_ONCE(icmp_global.stamp); + oldstamp = READ_ONCE(net->ipv4.icmp_global_stamp); delta = min_t(u32, now - oldstamp, HZ); if (delta < HZ / 50) return false; @@ -257,23 +253,23 @@ bool icmp_global_allow(void) if (!incr) return false; - if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) { - old = atomic_read(&icmp_global.credit); + if (cmpxchg(&net->ipv4.icmp_global_stamp, oldstamp, now) == oldstamp) { + old = atomic_read(&net->ipv4.icmp_global_credit); do { new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst)); - } while (!atomic_try_cmpxchg(&icmp_global.credit, &old, new)); + } while (!atomic_try_cmpxchg(&net->ipv4.icmp_global_credit, &old, new)); } return true; } EXPORT_SYMBOL(icmp_global_allow); -void icmp_global_consume(void) +void icmp_global_consume(struct net *net) { int credits = get_random_u32_below(3); /* Note: this might make icmp_global.credit negative. */ if (credits) - atomic_sub(credits, &icmp_global.credit); + atomic_sub(credits, &net->ipv4.icmp_global_credit); } EXPORT_SYMBOL(icmp_global_consume); @@ -299,7 +295,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code, if (icmpv4_mask_allow(net, type, code)) return true; - if (icmp_global_allow()) { + if (icmp_global_allow(net)) { *apply_ratelimit = true; return true; } @@ -337,7 +333,7 @@ out: if (!rc) __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST); else - icmp_global_consume(); + icmp_global_consume(net); return rc; } |