ff1f69a89a
[ Upstream commit 73f156a6e8c1074ac6327e0abd1169e95eb66463 ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
49 lines
1.1 KiB
C
49 lines
1.1 KiB
C
/*
|
|
* IPv6 library code, needed by static components when full IPv6 support is
|
|
* not configured or static. These functions are needed by GSO/GRO implementation.
|
|
*/
|
|
#include <linux/export.h>
|
|
#include <net/ipv6.h>
|
|
#include <net/ip6_fib.h>
|
|
|
|
|
|
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
|
{
|
|
u16 offset = sizeof(struct ipv6hdr);
|
|
struct ipv6_opt_hdr *exthdr =
|
|
(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
|
|
unsigned int packet_len = skb->tail - skb->network_header;
|
|
int found_rhdr = 0;
|
|
*nexthdr = &ipv6_hdr(skb)->nexthdr;
|
|
|
|
while (offset + 1 <= packet_len) {
|
|
|
|
switch (**nexthdr) {
|
|
|
|
case NEXTHDR_HOP:
|
|
break;
|
|
case NEXTHDR_ROUTING:
|
|
found_rhdr = 1;
|
|
break;
|
|
case NEXTHDR_DEST:
|
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
|
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
|
|
break;
|
|
#endif
|
|
if (found_rhdr)
|
|
return offset;
|
|
break;
|
|
default :
|
|
return offset;
|
|
}
|
|
|
|
offset += ipv6_optlen(exthdr);
|
|
*nexthdr = &exthdr->nexthdr;
|
|
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
|
|
offset);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
EXPORT_SYMBOL(ip6_find_1stfragopt);
|