| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | /* | 
|---|
| 3 | *		INETPEER - A storage for permanent information about peers | 
|---|
| 4 | * | 
|---|
| 5 | *  Authors:	Andrey V. Savochkin <saw@msu.ru> | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef _NET_INETPEER_H | 
|---|
| 9 | #define _NET_INETPEER_H | 
|---|
| 10 |  | 
|---|
| 11 | #include <linux/types.h> | 
|---|
| 12 | #include <linux/init.h> | 
|---|
| 13 | #include <linux/jiffies.h> | 
|---|
| 14 | #include <linux/spinlock.h> | 
|---|
| 15 | #include <linux/rtnetlink.h> | 
|---|
| 16 | #include <net/ipv6.h> | 
|---|
| 17 | #include <linux/atomic.h> | 
|---|
| 18 |  | 
|---|
| 19 | /* IPv4 address key for cache lookups */ | 
|---|
| 20 | struct ipv4_addr_key { | 
|---|
| 21 | __be32	addr; | 
|---|
| 22 | int	vif; | 
|---|
| 23 | }; | 
|---|
| 24 |  | 
|---|
| 25 | #define INETPEER_MAXKEYSZ   (sizeof(struct in6_addr) / sizeof(u32)) | 
|---|
| 26 |  | 
|---|
| 27 | struct inetpeer_addr { | 
|---|
| 28 | union { | 
|---|
| 29 | struct ipv4_addr_key	a4; | 
|---|
| 30 | struct in6_addr		a6; | 
|---|
| 31 | u32			key[INETPEER_MAXKEYSZ]; | 
|---|
| 32 | }; | 
|---|
| 33 | __u16				family; | 
|---|
| 34 | }; | 
|---|
| 35 |  | 
|---|
| 36 | struct inet_peer { | 
|---|
| 37 | struct rb_node		rb_node; | 
|---|
| 38 | struct inetpeer_addr	daddr; | 
|---|
| 39 |  | 
|---|
| 40 | u32			metrics[RTAX_MAX]; | 
|---|
| 41 | u32			rate_tokens;	/* rate limiting for ICMP */ | 
|---|
| 42 | u32			n_redirects; | 
|---|
| 43 | unsigned long		rate_last; | 
|---|
| 44 | /* | 
|---|
| 45 | * Once inet_peer is queued for deletion (refcnt == 0), following field | 
|---|
| 46 | * is not available: rid | 
|---|
| 47 | * We can share memory with rcu_head to help keep inet_peer small. | 
|---|
| 48 | */ | 
|---|
| 49 | union { | 
|---|
| 50 | struct { | 
|---|
| 51 | atomic_t			rid;		/* Frag reception counter */ | 
|---|
| 52 | }; | 
|---|
| 53 | struct rcu_head         rcu; | 
|---|
| 54 | }; | 
|---|
| 55 |  | 
|---|
| 56 | /* following fields might be frequently dirtied */ | 
|---|
| 57 | __u32			dtime;	/* the time of last use of not referenced entries */ | 
|---|
| 58 | refcount_t		refcnt; | 
|---|
| 59 | }; | 
|---|
| 60 |  | 
|---|
| 61 | struct inet_peer_base { | 
|---|
| 62 | struct rb_root		rb_root; | 
|---|
| 63 | seqlock_t		lock; | 
|---|
| 64 | int			total; | 
|---|
| 65 | }; | 
|---|
| 66 |  | 
|---|
| 67 | void inet_peer_base_init(struct inet_peer_base *); | 
|---|
| 68 |  | 
|---|
| 69 | void inet_initpeers(void) __init; | 
|---|
| 70 |  | 
|---|
| 71 | #define INETPEER_METRICS_NEW	(~(u32) 0) | 
|---|
| 72 |  | 
|---|
| 73 | static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) | 
|---|
| 74 | { | 
|---|
| 75 | iaddr->a4.addr = ip; | 
|---|
| 76 | iaddr->a4.vif = 0; | 
|---|
| 77 | iaddr->family = AF_INET; | 
|---|
| 78 | } | 
|---|
| 79 |  | 
|---|
| 80 | static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) | 
|---|
| 81 | { | 
|---|
| 82 | return iaddr->a4.addr; | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, | 
|---|
| 86 | struct in6_addr *in6) | 
|---|
| 87 | { | 
|---|
| 88 | iaddr->a6 = *in6; | 
|---|
| 89 | iaddr->family = AF_INET6; | 
|---|
| 90 | } | 
|---|
| 91 |  | 
|---|
| 92 | static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) | 
|---|
| 93 | { | 
|---|
| 94 | return &iaddr->a6; | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | /* can be called with or without local BH being disabled */ | 
|---|
| 98 | struct inet_peer *inet_getpeer(struct inet_peer_base *base, | 
|---|
| 99 | const struct inetpeer_addr *daddr); | 
|---|
| 100 |  | 
|---|
| 101 | static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, | 
|---|
| 102 | __be32 v4daddr, | 
|---|
| 103 | int vif) | 
|---|
| 104 | { | 
|---|
| 105 | struct inetpeer_addr daddr; | 
|---|
| 106 |  | 
|---|
| 107 | daddr.a4.addr = v4daddr; | 
|---|
| 108 | daddr.a4.vif = vif; | 
|---|
| 109 | daddr.family = AF_INET; | 
|---|
| 110 | return inet_getpeer(base, daddr: &daddr); | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 | static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, | 
|---|
| 114 | const struct in6_addr *v6daddr) | 
|---|
| 115 | { | 
|---|
| 116 | struct inetpeer_addr daddr; | 
|---|
| 117 |  | 
|---|
| 118 | daddr.a6 = *v6daddr; | 
|---|
| 119 | daddr.family = AF_INET6; | 
|---|
| 120 | return inet_getpeer(base, daddr: &daddr); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, | 
|---|
| 124 | const struct inetpeer_addr *b) | 
|---|
| 125 | { | 
|---|
| 126 | int i, n; | 
|---|
| 127 |  | 
|---|
| 128 | if (a->family == AF_INET) | 
|---|
| 129 | n = sizeof(a->a4) / sizeof(u32); | 
|---|
| 130 | else | 
|---|
| 131 | n = sizeof(a->a6) / sizeof(u32); | 
|---|
| 132 |  | 
|---|
| 133 | for (i = 0; i < n; i++) { | 
|---|
| 134 | if (a->key[i] == b->key[i]) | 
|---|
| 135 | continue; | 
|---|
| 136 | if (a->key[i] < b->key[i]) | 
|---|
| 137 | return -1; | 
|---|
| 138 | return 1; | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 | return 0; | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | /* can be called from BH context or outside */ | 
|---|
| 145 | void inet_putpeer(struct inet_peer *p); | 
|---|
| 146 | bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); | 
|---|
| 147 |  | 
|---|
| 148 | void inetpeer_invalidate_tree(struct inet_peer_base *); | 
|---|
| 149 |  | 
|---|
| 150 | #endif /* _NET_INETPEER_H */ | 
|---|
| 151 |  | 
|---|