diff options
author | Eric Dumazet <edumazet@google.com> | 2014-06-02 08:26:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-02 14:00:41 -0400 |
commit | 73f156a6e8c1074ac6327e0abd1169e95eb66463 (patch) | |
tree | 2c8b222f21784e738c397ba95dee70a8f256ea64 /include/net/inetpeer.h | |
parent | e067ee336a9d3f038ffa9699c59f2abec3376bf7 (diff) |
inetpeer: get rid of ip_id_count
Ideally, we would need to generate IP ID using a per destination IP
generator.
linux kernels used inet_peer cache for this purpose, but this had a huge
cost on servers disabling MTU discovery.
1) each inet_peer struct consumes 192 bytes
2) inetpeer cache uses a binary tree of inet_peer structs,
with a nominal size of ~66000 elements under load.
3) lookups in this tree are hitting a lot of cache lines, as tree depth
is about 20.
4) If server deals with many tcp flows, we have a high probability of
not finding the inet_peer, allocating a fresh one, inserting it in
the tree with same initial ip_id_count, (cf secure_ip_id())
5) We garbage collect inet_peer aggressively.
IP ID generation do not have to be 'perfect'
Goal is trying to avoid duplicates in a short period of time,
so that reassembly units have a chance to complete reassembly of
fragments belonging to one message before receiving other fragments
with a recycled ID.
We simply use an array of generators, and a Jenkin hash using the dst IP
as a key.
ipv6_select_ident() is put back into net/ipv6/ip6_output.c where it
belongs (it is only used from this file)
secure_ip_id() and secure_ipv6_id() no longer are needed.
Rename ip_select_ident_more() to ip_select_ident_segs() to avoid
unnecessary decrement/increment of the number of segments.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/inetpeer.h')
-rw-r--r-- | include/net/inetpeer.h | 23 |
1 files changed, 3 insertions, 20 deletions
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 6efe73c79c52..823ec7bb9c67 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h | |||
@@ -41,14 +41,13 @@ struct inet_peer { | |||
41 | struct rcu_head gc_rcu; | 41 | struct rcu_head gc_rcu; |
42 | }; | 42 | }; |
43 | /* | 43 | /* |
44 | * Once inet_peer is queued for deletion (refcnt == -1), following fields | 44 | * Once inet_peer is queued for deletion (refcnt == -1), following field |
45 | * are not available: rid, ip_id_count | 45 | * is not available: rid |
46 | * We can share memory with rcu_head to help keep inet_peer small. | 46 | * We can share memory with rcu_head to help keep inet_peer small. |
47 | */ | 47 | */ |
48 | union { | 48 | union { |
49 | struct { | 49 | struct { |
50 | atomic_t rid; /* Frag reception counter */ | 50 | atomic_t rid; /* Frag reception counter */ |
51 | atomic_t ip_id_count; /* IP ID for the next packet */ | ||
52 | }; | 51 | }; |
53 | struct rcu_head rcu; | 52 | struct rcu_head rcu; |
54 | struct inet_peer *gc_next; | 53 | struct inet_peer *gc_next; |
@@ -165,7 +164,7 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); | |||
165 | void inetpeer_invalidate_tree(struct inet_peer_base *); | 164 | void inetpeer_invalidate_tree(struct inet_peer_base *); |
166 | 165 | ||
167 | /* | 166 | /* |
168 | * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, | 167 | * temporary check to make sure we dont access rid, tcp_ts, |
169 | * tcp_ts_stamp if no refcount is taken on inet_peer | 168 | * tcp_ts_stamp if no refcount is taken on inet_peer |
170 | */ | 169 | */ |
171 | static inline void inet_peer_refcheck(const struct inet_peer *p) | 170 | static inline void inet_peer_refcheck(const struct inet_peer *p) |
@@ -173,20 +172,4 @@ static inline void inet_peer_refcheck(const struct inet_peer *p) | |||
173 | WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); | 172 | WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); |
174 | } | 173 | } |
175 | 174 | ||
176 | |||
177 | /* can be called with or without local BH being disabled */ | ||
178 | static inline int inet_getid(struct inet_peer *p, int more) | ||
179 | { | ||
180 | int old, new; | ||
181 | more++; | ||
182 | inet_peer_refcheck(p); | ||
183 | do { | ||
184 | old = atomic_read(&p->ip_id_count); | ||
185 | new = old + more; | ||
186 | if (!new) | ||
187 | new = 1; | ||
188 | } while (atomic_cmpxchg(&p->ip_id_count, old, new) != old); | ||
189 | return new; | ||
190 | } | ||
191 | |||
192 | #endif /* _NET_INETPEER_H */ | 175 | #endif /* _NET_INETPEER_H */ |