lin
2025-01-10 2e0fe69425adee0529756dc3381ac1838197f3ac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 *        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>
#include <linux/rtnetlink.h>
#include <net/ipv6.h>
#include <linux/atomic.h>
 
/* IPv4 address key for cache lookups */
struct ipv4_addr_key {
   __be32    addr;
   int    vif;
};
 
#define INETPEER_MAXKEYSZ   (sizeof(struct in6_addr) / sizeof(u32))
 
struct inetpeer_addr {
   union {
       struct ipv4_addr_key    a4;
       struct in6_addr        a6;
       u32            key[INETPEER_MAXKEYSZ];
   };
   __u16                family;
};
 
struct inet_peer {
   /* group together avl_left,avl_right,v4daddr to speedup lookups */
   struct inet_peer __rcu    *avl_left, *avl_right;
   struct inetpeer_addr    daddr;
   __u32            avl_height;
 
   u32            metrics[RTAX_MAX];
   u32            rate_tokens;    /* rate limiting for ICMP */
   u32            n_redirects;
   unsigned long        rate_last;
   union {
       struct list_head    gc_list;
       struct rcu_head     gc_rcu;
   };
   /*
    * Once inet_peer is queued for deletion (refcnt == -1), following field
    * is not available: rid
    * We can share memory with rcu_head to help keep inet_peer small.
    */
   union {
       struct {
           atomic_t            rid;        /* Frag reception counter */
       };
       struct rcu_head         rcu;
       struct inet_peer    *gc_next;
   };
 
   /* following fields might be frequently dirtied */
   __u32            dtime;    /* the time of last use of not referenced entries */
   atomic_t        refcnt;
};
 
struct inet_peer_base {
   struct inet_peer __rcu    *root;
   seqlock_t        lock;
   int            total;
};
 
void inet_peer_base_init(struct inet_peer_base *);
 
void inet_initpeers(void) __init;
 
#define INETPEER_METRICS_NEW    (~(u32) 0)
 
static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip)
{
   iaddr->a4.addr = ip;
   iaddr->a4.vif = 0;
   iaddr->family = AF_INET;
}
 
static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr)
{
   return iaddr->a4.addr;
}
 
static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr,
                   struct in6_addr *in6)
{
   iaddr->a6 = *in6;
   iaddr->family = AF_INET6;
}
 
static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr)
{
   return &iaddr->a6;
}
 
/* can be called with or without local BH being disabled */
struct inet_peer *inet_getpeer(struct inet_peer_base *base,
                  const struct inetpeer_addr *daddr,
                  int create);
 
static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base,
                       __be32 v4daddr,
                       int vif, int create)
{
   struct inetpeer_addr daddr;
 
   daddr.a4.addr = v4daddr;
   daddr.a4.vif = vif;
   daddr.family = AF_INET;
   return inet_getpeer(base, &daddr, create);
}
 
static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base,
                       const struct in6_addr *v6daddr,
                       int create)
{
   struct inetpeer_addr daddr;
 
   daddr.a6 = *v6daddr;
   daddr.family = AF_INET6;
   return inet_getpeer(base, &daddr, create);
}
 
static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a,
                   const struct inetpeer_addr *b)
{
   int i, n;
 
   if (a->family == AF_INET)
       n = sizeof(a->a4) / sizeof(u32);
   else
       n = sizeof(a->a6) / sizeof(u32);
 
   for (i = 0; i < n; i++) {
       if (a->key[i] == b->key[i])
           continue;
       if (a->key[i] < b->key[i])
           return -1;
       return 1;
   }
 
   return 0;
}
 
/* can be called from BH context or outside */
void inet_putpeer(struct inet_peer *p);
bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
 
void inetpeer_invalidate_tree(struct inet_peer_base *);
 
#endif /* _NET_INETPEER_H */