All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

inetpeer.h 4.52 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *		INETPEER - A storage for permanent information about peers
 *
 *  Authors:	Andrey V. Savochkin <saw@msu.ru>
 */

#ifndef _NET_INETPEER_H
#define _NET_INETPEER_H

#include <linux/types.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
14
#include <linux/rtnetlink.h>
15
#include <net/ipv6.h>
Arun Sharma's avatar
Arun Sharma committed
16
#include <linux/atomic.h>
Linus Torvalds's avatar
Linus Torvalds committed
17

18
struct inetpeer_addr_base {
19
	union {
20 21
		__be32			a4;
		__be32			a6[4];
22
	};
23 24 25 26 27
};

struct inetpeer_addr {
	struct inetpeer_addr_base	addr;
	__u16				family;
28
};
29

Eric Dumazet's avatar
Eric Dumazet committed
30
struct inet_peer {
31
	/* group together avl_left,avl_right,v4daddr to speedup lookups */
Eric Dumazet's avatar
Eric Dumazet committed
32
	struct inet_peer __rcu	*avl_left, *avl_right;
33
	struct inetpeer_addr	daddr;
Eric Dumazet's avatar
Eric Dumazet committed
34
	__u32			avl_height;
35 36 37 38

	u32			metrics[RTAX_MAX];
	u32			rate_tokens;	/* rate limiting for ICMP */
	unsigned long		rate_last;
39 40 41 42
	union {
		struct list_head	gc_list;
		struct rcu_head     gc_rcu;
	};
43 44
	/*
	 * Once inet_peer is queued for deletion (refcnt == -1), following fields
45
	 * are not available: rid, ip_id_count
46
	 * We can share memory with rcu_head to help keep inet_peer small.
47 48 49
	 */
	union {
		struct {
50 51
			atomic_t			rid;		/* Frag reception counter */
			atomic_t			ip_id_count;	/* IP ID for the next packet */
52 53
		};
		struct rcu_head         rcu;
Eric Dumazet's avatar
Eric Dumazet committed
54
		struct inet_peer	*gc_next;
55
	};
56 57 58 59

	/* following fields might be frequently dirtied */
	__u32			dtime;	/* the time of last use of not referenced entries */
	atomic_t		refcnt;
Linus Torvalds's avatar
Linus Torvalds committed
60 61
};

62 63 64
struct inet_peer_base {
	struct inet_peer __rcu	*root;
	seqlock_t		lock;
65
	u32			flush_seq;
66 67 68
	int			total;
};

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
#define INETPEER_BASE_BIT	0x1UL

static inline struct inet_peer *inetpeer_ptr(unsigned long val)
{
	BUG_ON(val & INETPEER_BASE_BIT);
	return (struct inet_peer *) val;
}

static inline struct inet_peer_base *inetpeer_base_ptr(unsigned long val)
{
	if (!(val & INETPEER_BASE_BIT))
		return NULL;
	val &= ~INETPEER_BASE_BIT;
	return (struct inet_peer_base *) val;
}

static inline bool inetpeer_ptr_is_peer(unsigned long val)
{
	return !(val & INETPEER_BASE_BIT);
}

static inline void __inetpeer_ptr_set_peer(unsigned long *val, struct inet_peer *peer)
{
	/* This implicitly clears INETPEER_BASE_BIT */
	*val = (unsigned long) peer;
}

static inline bool inetpeer_ptr_set_peer(unsigned long *ptr, struct inet_peer *peer)
{
	unsigned long val = (unsigned long) peer;
	unsigned long orig = *ptr;

101
	if (!(orig & INETPEER_BASE_BIT) ||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	    cmpxchg(ptr, orig, val) != orig)
		return false;
	return true;
}

static inline void inetpeer_init_ptr(unsigned long *ptr, struct inet_peer_base *base)
{
	*ptr = (unsigned long) base | INETPEER_BASE_BIT;
}

static inline void inetpeer_transfer_peer(unsigned long *to, unsigned long *from)
{
	unsigned long val = *from;

	*to = val;
	if (inetpeer_ptr_is_peer(val)) {
		struct inet_peer *peer = inetpeer_ptr(val);
		atomic_inc(&peer->refcnt);
	}
}

123
void inet_peer_base_init(struct inet_peer_base *);
124

125
void inet_initpeers(void) __init;
Linus Torvalds's avatar
Linus Torvalds committed
126

127 128 129 130 131 132 133
#define INETPEER_METRICS_NEW	(~(u32) 0)

static inline bool inet_metrics_new(const struct inet_peer *p)
{
	return p->metrics[RTAX_LOCK-1] == INETPEER_METRICS_NEW;
}

Linus Torvalds's avatar
Linus Torvalds committed
134
/* can be called with or without local BH being disabled */
135
struct inet_peer *inet_getpeer(struct inet_peer_base *base,
136 137
			       const struct inetpeer_addr *daddr,
			       int create);
138

139
static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base,
140 141
						__be32 v4daddr,
						int create)
142
{
143
	struct inetpeer_addr daddr;
144

145
	daddr.addr.a4 = v4daddr;
146
	daddr.family = AF_INET;
147
	return inet_getpeer(base, &daddr, create);
148
}
Linus Torvalds's avatar
Linus Torvalds committed
149

150
static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base,
151 152
						const struct in6_addr *v6daddr,
						int create)
153
{
154
	struct inetpeer_addr daddr;
155

Alexey Dobriyan's avatar
Alexey Dobriyan committed
156
	*(struct in6_addr *)daddr.addr.a6 = *v6daddr;
157
	daddr.family = AF_INET6;
158
	return inet_getpeer(base, &daddr, create);
159 160
}

Linus Torvalds's avatar
Linus Torvalds committed
161
/* can be called from BH context or outside */
162 163
void inet_putpeer(struct inet_peer *p);
bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
Linus Torvalds's avatar
Linus Torvalds committed
164

165 166
void inetpeer_invalidate_tree(struct inet_peer_base *);
void inetpeer_invalidate_family(int family);
167

168 169 170 171 172 173 174 175 176 177
/*
 * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
 * tcp_ts_stamp if no refcount is taken on inet_peer
 */
static inline void inet_peer_refcheck(const struct inet_peer *p)
{
	WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0);
}


Linus Torvalds's avatar
Linus Torvalds committed
178
/* can be called with or without local BH being disabled */
179
static inline int inet_getid(struct inet_peer *p, int more)
Linus Torvalds's avatar
Linus Torvalds committed
180
{
181
	int old, new;
Eric Dumazet's avatar
Eric Dumazet committed
182
	more++;
183
	inet_peer_refcheck(p);
184 185 186 187 188 189 190
	do {
		old = atomic_read(&p->ip_id_count);
		new = old + more;
		if (!new)
			new = 1;
	} while (atomic_cmpxchg(&p->ip_id_count, old, new) != old);
	return new;
Linus Torvalds's avatar
Linus Torvalds committed
191 192 193
}

#endif /* _NET_INETPEER_H */