mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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>
This commit is contained in:
parent
8c2bd38b95
commit
b056b4cd91
|
|
@ -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 {
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
__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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user