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

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.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 9f927527
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -95,6 +95,8 @@ enum
	ICMP_MIB_OUTADDRMASKS,			/* OutAddrMasks */
	ICMP_MIB_OUTADDRMASKREPS,		/* OutAddrMaskReps */
	ICMP_MIB_CSUMERRORS,			/* InCsumErrors */
	ICMP_MIB_RATELIMITGLOBAL,		/* OutRateLimitGlobal */
	ICMP_MIB_RATELIMITHOST,			/* OutRateLimitHost */
	__ICMP_MIB_MAX
};

@@ -112,6 +114,7 @@ enum
	ICMP6_MIB_OUTMSGS,			/* OutMsgs */
	ICMP6_MIB_OUTERRORS,			/* OutErrors */
	ICMP6_MIB_CSUMERRORS,			/* InCsumErrors */
	ICMP6_MIB_RATELIMITHOST,		/* OutRateLimitHost */
	__ICMP6_MIB_MAX
};

+3 −0
Original line number Diff line number Diff line
@@ -296,6 +296,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code)
	if (icmp_global_allow())
		return true;

	__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
	return false;
}

@@ -325,6 +326,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
	if (peer)
		inet_putpeer(peer);
out:
	if (!rc)
		__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
	return rc;
}

+5 −3
Original line number Diff line number Diff line
@@ -353,7 +353,7 @@ static void icmp_put(struct seq_file *seq)
	seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
	for (i = 0; icmpmibmap[i].name; i++)
		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++)
		seq_printf(seq, " Out%s", icmpmibmap[i].name);
	seq_printf(seq, "\nIcmp: %lu %lu %lu",
@@ -363,9 +363,11 @@ static void icmp_put(struct seq_file *seq)
	for (i = 0; icmpmibmap[i].name; i++)
		seq_printf(seq, " %lu",
			   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_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++)
		seq_printf(seq, " %lu",
			   atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
+4 −0
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ static bool icmpv6_global_allow(struct net *net, int type)
	if (icmp_global_allow())
		return true;

	__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
	return false;
}

@@ -224,6 +225,9 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
		if (peer)
			inet_putpeer(peer);
	}
	if (!res)
		__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
				  ICMP6_MIB_RATELIMITHOST);
	dst_release(dst);
	return res;
}
+1 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
	SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
	SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
	SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS),
	SNMP_MIB_ITEM("Icmp6OutRateLimitHost", ICMP6_MIB_RATELIMITHOST),
	SNMP_MIB_SENTINEL
};