Commit b056b4cd authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski

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: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20240829144641.3880376-3-edumazet@google.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 8c2bd38b
...@@ -794,8 +794,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) ...@@ -794,8 +794,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
ip_cmsg_recv_offset(msg, skb->sk, skb, 0, 0); ip_cmsg_recv_offset(msg, skb->sk, skb, 0, 0);
} }
bool icmp_global_allow(void); bool icmp_global_allow(struct net *net);
void icmp_global_consume(void); void icmp_global_consume(struct net *net);
extern int sysctl_icmp_msgs_per_sec; extern int sysctl_icmp_msgs_per_sec;
extern int sysctl_icmp_msgs_burst; extern int sysctl_icmp_msgs_burst;
......
...@@ -122,7 +122,8 @@ struct netns_ipv4 { ...@@ -122,7 +122,8 @@ struct netns_ipv4 {
u8 sysctl_icmp_errors_use_inbound_ifaddr; u8 sysctl_icmp_errors_use_inbound_ifaddr;
int sysctl_icmp_ratelimit; int sysctl_icmp_ratelimit;
int sysctl_icmp_ratemask; int sysctl_icmp_ratemask;
atomic_t icmp_global_credit;
u32 icmp_global_stamp;
u32 ip_rt_min_pmtu; u32 ip_rt_min_pmtu;
int ip_rt_mtu_expires; int ip_rt_mtu_expires;
int ip_rt_min_advmss; int ip_rt_min_advmss;
......
...@@ -223,19 +223,15 @@ static inline void icmp_xmit_unlock(struct sock *sk) ...@@ -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_per_sec __read_mostly = 1000;
int sysctl_icmp_msgs_burst __read_mostly = 50; 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 ? * 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. * 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. * Returns false if we reached the limit and can not send another packet.
* Works in tandem with icmp_global_consume(). * Works in tandem with icmp_global_consume().
*/ */
bool icmp_global_allow(void) bool icmp_global_allow(struct net *net)
{ {
u32 delta, now, oldstamp; u32 delta, now, oldstamp;
int incr, new, old; int incr, new, old;
...@@ -244,11 +240,11 @@ bool icmp_global_allow(void) ...@@ -244,11 +240,11 @@ bool icmp_global_allow(void)
* Then later icmp_global_consume() could consume more credits, * Then later icmp_global_consume() could consume more credits,
* this is an acceptable race. * this is an acceptable race.
*/ */
if (atomic_read(&icmp_global.credit) > 0) if (atomic_read(&net->ipv4.icmp_global_credit) > 0)
return true; return true;
now = jiffies; now = jiffies;
oldstamp = READ_ONCE(icmp_global.stamp); oldstamp = READ_ONCE(net->ipv4.icmp_global_stamp);
delta = min_t(u32, now - oldstamp, HZ); delta = min_t(u32, now - oldstamp, HZ);
if (delta < HZ / 50) if (delta < HZ / 50)
return false; return false;
...@@ -257,23 +253,23 @@ bool icmp_global_allow(void) ...@@ -257,23 +253,23 @@ bool icmp_global_allow(void)
if (!incr) if (!incr)
return false; return false;
if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) { if (cmpxchg(&net->ipv4.icmp_global_stamp, oldstamp, now) == oldstamp) {
old = atomic_read(&icmp_global.credit); old = atomic_read(&net->ipv4.icmp_global_credit);
do { do {
new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst)); 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; return true;
} }
EXPORT_SYMBOL(icmp_global_allow); EXPORT_SYMBOL(icmp_global_allow);
void icmp_global_consume(void) void icmp_global_consume(struct net *net)
{ {
int credits = get_random_u32_below(3); int credits = get_random_u32_below(3);
/* Note: this might make icmp_global.credit negative. */ /* Note: this might make icmp_global.credit negative. */
if (credits) if (credits)
atomic_sub(credits, &icmp_global.credit); atomic_sub(credits, &net->ipv4.icmp_global_credit);
} }
EXPORT_SYMBOL(icmp_global_consume); EXPORT_SYMBOL(icmp_global_consume);
...@@ -299,7 +295,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code, ...@@ -299,7 +295,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code,
if (icmpv4_mask_allow(net, type, code)) if (icmpv4_mask_allow(net, type, code))
return true; return true;
if (icmp_global_allow()) { if (icmp_global_allow(net)) {
*apply_ratelimit = true; *apply_ratelimit = true;
return true; return true;
} }
...@@ -337,7 +333,7 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, ...@@ -337,7 +333,7 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
if (!rc) if (!rc)
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST); __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
else else
icmp_global_consume(); icmp_global_consume(net);
return rc; return rc;
} }
......
...@@ -181,7 +181,7 @@ static bool icmpv6_global_allow(struct net *net, int type, ...@@ -181,7 +181,7 @@ static bool icmpv6_global_allow(struct net *net, int type,
if (icmpv6_mask_allow(net, type)) if (icmpv6_mask_allow(net, type))
return true; return true;
if (icmp_global_allow()) { if (icmp_global_allow(net)) {
*apply_ratelimit = true; *apply_ratelimit = true;
return true; return true;
} }
...@@ -231,7 +231,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, ...@@ -231,7 +231,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
__ICMP6_INC_STATS(net, ip6_dst_idev(dst), __ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST); ICMP6_MIB_RATELIMITHOST);
else else
icmp_global_consume(); icmp_global_consume(net);
dst_release(dst); dst_release(dst);
return res; return res;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment