162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *		INETPEER - A storage for permanent information about peers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Authors:	Andrey V. Savochkin <saw@msu.ru>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef _NET_INETPEER_H
962306a36Sopenharmony_ci#define _NET_INETPEER_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci#include <linux/spinlock.h>
1562306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1662306a36Sopenharmony_ci#include <net/ipv6.h>
1762306a36Sopenharmony_ci#include <linux/atomic.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* IPv4 address key for cache lookups */
2062306a36Sopenharmony_cistruct ipv4_addr_key {
2162306a36Sopenharmony_ci	__be32	addr;
2262306a36Sopenharmony_ci	int	vif;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define INETPEER_MAXKEYSZ   (sizeof(struct in6_addr) / sizeof(u32))
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct inetpeer_addr {
2862306a36Sopenharmony_ci	union {
2962306a36Sopenharmony_ci		struct ipv4_addr_key	a4;
3062306a36Sopenharmony_ci		struct in6_addr		a6;
3162306a36Sopenharmony_ci		u32			key[INETPEER_MAXKEYSZ];
3262306a36Sopenharmony_ci	};
3362306a36Sopenharmony_ci	__u16				family;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct inet_peer {
3762306a36Sopenharmony_ci	struct rb_node		rb_node;
3862306a36Sopenharmony_ci	struct inetpeer_addr	daddr;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	u32			metrics[RTAX_MAX];
4162306a36Sopenharmony_ci	u32			rate_tokens;	/* rate limiting for ICMP */
4262306a36Sopenharmony_ci	u32			n_redirects;
4362306a36Sopenharmony_ci	unsigned long		rate_last;
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Once inet_peer is queued for deletion (refcnt == 0), following field
4662306a36Sopenharmony_ci	 * is not available: rid
4762306a36Sopenharmony_ci	 * We can share memory with rcu_head to help keep inet_peer small.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	union {
5062306a36Sopenharmony_ci		struct {
5162306a36Sopenharmony_ci			atomic_t			rid;		/* Frag reception counter */
5262306a36Sopenharmony_ci		};
5362306a36Sopenharmony_ci		struct rcu_head         rcu;
5462306a36Sopenharmony_ci	};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* following fields might be frequently dirtied */
5762306a36Sopenharmony_ci	__u32			dtime;	/* the time of last use of not referenced entries */
5862306a36Sopenharmony_ci	refcount_t		refcnt;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct inet_peer_base {
6262306a36Sopenharmony_ci	struct rb_root		rb_root;
6362306a36Sopenharmony_ci	seqlock_t		lock;
6462306a36Sopenharmony_ci	int			total;
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_civoid inet_peer_base_init(struct inet_peer_base *);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_civoid inet_initpeers(void) __init;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define INETPEER_METRICS_NEW	(~(u32) 0)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	iaddr->a4.addr = ip;
7662306a36Sopenharmony_ci	iaddr->a4.vif = 0;
7762306a36Sopenharmony_ci	iaddr->family = AF_INET;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return iaddr->a4.addr;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr,
8662306a36Sopenharmony_ci					struct in6_addr *in6)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	iaddr->a6 = *in6;
8962306a36Sopenharmony_ci	iaddr->family = AF_INET6;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return &iaddr->a6;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* can be called with or without local BH being disabled */
9862306a36Sopenharmony_cistruct inet_peer *inet_getpeer(struct inet_peer_base *base,
9962306a36Sopenharmony_ci			       const struct inetpeer_addr *daddr,
10062306a36Sopenharmony_ci			       int create);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base,
10362306a36Sopenharmony_ci						__be32 v4daddr,
10462306a36Sopenharmony_ci						int vif, int create)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct inetpeer_addr daddr;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	daddr.a4.addr = v4daddr;
10962306a36Sopenharmony_ci	daddr.a4.vif = vif;
11062306a36Sopenharmony_ci	daddr.family = AF_INET;
11162306a36Sopenharmony_ci	return inet_getpeer(base, &daddr, create);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base,
11562306a36Sopenharmony_ci						const struct in6_addr *v6daddr,
11662306a36Sopenharmony_ci						int create)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct inetpeer_addr daddr;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	daddr.a6 = *v6daddr;
12162306a36Sopenharmony_ci	daddr.family = AF_INET6;
12262306a36Sopenharmony_ci	return inet_getpeer(base, &daddr, create);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic inline int inetpeer_addr_cmp(const struct inetpeer_addr *a,
12662306a36Sopenharmony_ci				    const struct inetpeer_addr *b)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	int i, n;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (a->family == AF_INET)
13162306a36Sopenharmony_ci		n = sizeof(a->a4) / sizeof(u32);
13262306a36Sopenharmony_ci	else
13362306a36Sopenharmony_ci		n = sizeof(a->a6) / sizeof(u32);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
13662306a36Sopenharmony_ci		if (a->key[i] == b->key[i])
13762306a36Sopenharmony_ci			continue;
13862306a36Sopenharmony_ci		if (a->key[i] < b->key[i])
13962306a36Sopenharmony_ci			return -1;
14062306a36Sopenharmony_ci		return 1;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return 0;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* can be called from BH context or outside */
14762306a36Sopenharmony_civoid inet_putpeer(struct inet_peer *p);
14862306a36Sopenharmony_cibool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_civoid inetpeer_invalidate_tree(struct inet_peer_base *);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#endif /* _NET_INETPEER_H */
153