Commit d0941130 authored by Jamie Bainbridge's avatar Jamie Bainbridge Committed by Paolo Abeni

icmp: Add counters for rate limits

There are multiple ICMP rate limiting mechanisms:

* Global limits: net.ipv4.icmp_msgs_burst/icmp_msgs_per_sec
* v4 per-host limits: net.ipv4.icmp_ratelimit/ratemask
* v6 per-host limits: net.ipv6.icmp_ratelimit/ratemask

However, when ICMP output is limited, there is no way to tell
which limit has been hit or even if the limits are responsible
for the lack of ICMP output.

Add counters for each of the cases above. As we are within
local_bh_disable(), use the __INC stats variant.

Example output:

 # nstat -sz "*RateLimit*"
 IcmpOutRateLimitGlobal          134                0.0
 IcmpOutRateLimitHost            770                0.0
 Icmp6OutRateLimitHost           84                 0.0
Signed-off-by: default avatarJamie Bainbridge <jamie.bainbridge@gmail.com>
Suggested-by: default avatarAbhishek Rawal <rawal.abhishek92@gmail.com>
Link: https://lore.kernel.org/r/273b32241e6b7fdc5c609e6f5ebc68caf3994342.1674605770.git.jamie.bainbridge@gmail.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 9f927527
...@@ -95,6 +95,8 @@ enum ...@@ -95,6 +95,8 @@ enum
ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */ ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */
ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */ ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */
ICMP_MIB_CSUMERRORS, /* InCsumErrors */ ICMP_MIB_CSUMERRORS, /* InCsumErrors */
ICMP_MIB_RATELIMITGLOBAL, /* OutRateLimitGlobal */
ICMP_MIB_RATELIMITHOST, /* OutRateLimitHost */
__ICMP_MIB_MAX __ICMP_MIB_MAX
}; };
...@@ -112,6 +114,7 @@ enum ...@@ -112,6 +114,7 @@ enum
ICMP6_MIB_OUTMSGS, /* OutMsgs */ ICMP6_MIB_OUTMSGS, /* OutMsgs */
ICMP6_MIB_OUTERRORS, /* OutErrors */ ICMP6_MIB_OUTERRORS, /* OutErrors */
ICMP6_MIB_CSUMERRORS, /* InCsumErrors */ ICMP6_MIB_CSUMERRORS, /* InCsumErrors */
ICMP6_MIB_RATELIMITHOST, /* OutRateLimitHost */
__ICMP6_MIB_MAX __ICMP6_MIB_MAX
}; };
......
...@@ -296,6 +296,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code) ...@@ -296,6 +296,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code)
if (icmp_global_allow()) if (icmp_global_allow())
return true; return true;
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
return false; return false;
} }
...@@ -325,6 +326,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, ...@@ -325,6 +326,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
if (peer) if (peer)
inet_putpeer(peer); inet_putpeer(peer);
out: out:
if (!rc)
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
return rc; return rc;
} }
......
...@@ -353,7 +353,7 @@ static void icmp_put(struct seq_file *seq) ...@@ -353,7 +353,7 @@ static void icmp_put(struct seq_file *seq)
seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors"); seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " In%s", icmpmibmap[i].name); seq_printf(seq, " In%s", icmpmibmap[i].name);
seq_puts(seq, " OutMsgs OutErrors"); seq_puts(seq, " OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost");
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " Out%s", icmpmibmap[i].name); seq_printf(seq, " Out%s", icmpmibmap[i].name);
seq_printf(seq, "\nIcmp: %lu %lu %lu", seq_printf(seq, "\nIcmp: %lu %lu %lu",
...@@ -363,9 +363,11 @@ static void icmp_put(struct seq_file *seq) ...@@ -363,9 +363,11 @@ static void icmp_put(struct seq_file *seq)
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " %lu", seq_printf(seq, " %lu",
atomic_long_read(ptr + icmpmibmap[i].index)); atomic_long_read(ptr + icmpmibmap[i].index));
seq_printf(seq, " %lu %lu", seq_printf(seq, " %lu %lu %lu %lu",
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_RATELIMITGLOBAL),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_RATELIMITHOST));
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " %lu", seq_printf(seq, " %lu",
atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
......
...@@ -183,6 +183,7 @@ static bool icmpv6_global_allow(struct net *net, int type) ...@@ -183,6 +183,7 @@ static bool icmpv6_global_allow(struct net *net, int type)
if (icmp_global_allow()) if (icmp_global_allow())
return true; return true;
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
return false; return false;
} }
...@@ -224,6 +225,9 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, ...@@ -224,6 +225,9 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
if (peer) if (peer)
inet_putpeer(peer); inet_putpeer(peer);
} }
if (!res)
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST);
dst_release(dst); dst_release(dst);
return res; return res;
} }
......
...@@ -94,6 +94,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = { ...@@ -94,6 +94,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS), SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS), SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS),
SNMP_MIB_ITEM("Icmp6OutRateLimitHost", ICMP6_MIB_RATELIMITHOST),
SNMP_MIB_SENTINEL SNMP_MIB_SENTINEL
}; };
......
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