projects/linux·blob assoc-array-fixes · refs

154 lines · 3.3 KiB

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