Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92d86829 authored by David S. Miller's avatar David S. Miller
Browse files

inetpeer: Move ICMP rate limiting state into inet_peer entries.



Like metrics, the ICMP rate limiting bits are cached state about
a destination.  So move it into the inet_peer entries.

If an inet_peer cannot be bound (the reason is memory allocation
failure or similar), the policy is to allow.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0131ba45
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -78,8 +78,6 @@ struct dst_entry {
	atomic_t		__refcnt;	/* client references	*/
	int			__use;
	unsigned long		lastuse;
	unsigned long		rate_last;	/* rate limiting for ICMP */
	unsigned int		rate_tokens;
	int			flags;
#define DST_HOST		0x0001
#define DST_NOXFRM		0x0002
+0 −3
Original line number Diff line number Diff line
@@ -45,7 +45,4 @@ extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern int	icmp_init(void);
extern void	icmp_out_count(struct net *net, unsigned char type);

/* Move into dst.h ? */
extern int 	xrlim_allow(struct dst_entry *dst, int timeout);

#endif	/* _ICMP_H */
+3 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ struct inet_peer {
			__u32		tcp_ts;
			__u32		tcp_ts_stamp;
			u32		metrics[RTAX_MAX];
			u32		rate_tokens;	/* rate limiting for ICMP */
			unsigned long	rate_last;
		};
		struct rcu_head         rcu;
	};
@@ -81,6 +83,7 @@ static inline struct inet_peer *inet_getpeer_v6(struct in6_addr *v6daddr, int cr

/* can be called from BH context or outside */
extern void inet_putpeer(struct inet_peer *p);
extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);

/*
 * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
+8 −41
Original line number Diff line number Diff line
@@ -233,48 +233,11 @@ static inline void icmp_xmit_unlock(struct sock *sk)
 *	Send an ICMP frame.
 */

/*
 *	Check transmit rate limitation for given message.
 *	The rate information is held in the destination cache now.
 *	This function is generic and could be used for other purposes
 *	too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
 *
 *	Note that the same dst_entry fields are modified by functions in
 *	route.c too, but these work for packet destinations while xrlim_allow
 *	works for icmp destinations. This means the rate limiting information
 *	for one "ip object" is shared - and these ICMPs are twice limited:
 *	by source and by destination.
 *
 *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
 *			  SHOULD allow setting of rate limits
 *
 * 	Shared between ICMPv4 and ICMPv6.
 */
#define XRLIM_BURST_FACTOR 6
int xrlim_allow(struct dst_entry *dst, int timeout)
{
	unsigned long now, token = dst->rate_tokens;
	int rc = 0;

	now = jiffies;
	token += now - dst->rate_last;
	dst->rate_last = now;
	if (token > XRLIM_BURST_FACTOR * timeout)
		token = XRLIM_BURST_FACTOR * timeout;
	if (token >= timeout) {
		token -= timeout;
		rc = 1;
	}
	dst->rate_tokens = token;
	return rc;
}
EXPORT_SYMBOL(xrlim_allow);

static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
		int type, int code)
{
	struct dst_entry *dst = &rt->dst;
	int rc = 1;
	bool rc = true;

	if (type > NR_ICMP_TYPES)
		goto out;
@@ -288,8 +251,12 @@ static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
		goto out;

	/* Limit if icmp type is enabled in ratemask. */
	if ((1 << type) & net->ipv4.sysctl_icmp_ratemask)
		rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit);
	if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) {
		if (!rt->peer)
			rt_bind_peer(rt, 1);
		rc = inet_peer_xrlim_allow(rt->peer,
					   net->ipv4.sysctl_icmp_ratelimit);
	}
out:
	return rc;
}
+43 −0
Original line number Diff line number Diff line
@@ -513,6 +513,8 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
		atomic_set(&p->ip_id_count, secure_ip_id(daddr->a4));
		p->tcp_ts_stamp = 0;
		p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
		p->rate_tokens = 0;
		p->rate_last = 0;
		INIT_LIST_HEAD(&p->unused);


@@ -580,3 +582,44 @@ void inet_putpeer(struct inet_peer *p)
	local_bh_enable();
}
EXPORT_SYMBOL_GPL(inet_putpeer);

/*
 *	Check transmit rate limitation for given message.
 *	The rate information is held in the inet_peer entries now.
 *	This function is generic and could be used for other purposes
 *	too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
 *
 *	Note that the same inet_peer fields are modified by functions in
 *	route.c too, but these work for packet destinations while xrlim_allow
 *	works for icmp destinations. This means the rate limiting information
 *	for one "ip object" is shared - and these ICMPs are twice limited:
 *	by source and by destination.
 *
 *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
 *			  SHOULD allow setting of rate limits
 *
 * 	Shared between ICMPv4 and ICMPv6.
 */
#define XRLIM_BURST_FACTOR 6
bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout)
{
	unsigned long now, token;
	bool rc = false;

	if (!peer)
		return true;

	token = peer->rate_tokens;
	now = jiffies;
	token += now - peer->rate_last;
	peer->rate_last = now;
	if (token > XRLIM_BURST_FACTOR * timeout)
		token = XRLIM_BURST_FACTOR * timeout;
	if (token >= timeout) {
		token -= timeout;
		rc = true;
	}
	peer->rate_tokens = token;
	return rc;
}
EXPORT_SYMBOL(inet_peer_xrlim_allow);
Loading