Commit 0508c07f5e0c94f38afd5434e8b2a55b84553077

Authored by Vlad Yasevich
Committed by David S. Miller
1 parent 42b5212fee

ipv6: Select fragment id during UFO segmentation if not set.

If the IPv6 fragment id has not been set and we perform
fragmentation due to UFO, select a new fragment id.
We now consider a fragment id of 0 as unset and if id selection
process returns 0 (after all the pertrubations), we set it to
0x80000000, thus giving us ample space not to create collisions
with the next packet we may have to fragment.

When doing UFO integrity checking, we also select the
fragment id if it has not be set yet.   This is stored into
the skb_shinfo() thus allowing UFO to function correclty.

This patch also removes duplicate fragment id generation code
and moves ipv6_select_ident() into the header as it may be
used during GSO.

Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 4 changed files with 47 additions and 21 deletions Side-by-side Diff

... ... @@ -671,6 +671,9 @@
671 671 return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
672 672 }
673 673  
  674 +u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst,
  675 + struct in6_addr *src);
  676 +void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
674 677 void ipv6_proxy_select_ident(struct sk_buff *skb);
675 678  
676 679 int ip6_dst_hoplimit(struct dst_entry *dst);
net/ipv6/ip6_output.c
... ... @@ -537,20 +537,6 @@
537 537 skb_copy_secmark(to, from);
538 538 }
539 539  
540   -static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
541   -{
542   - static u32 ip6_idents_hashrnd __read_mostly;
543   - u32 hash, id;
544   -
545   - net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
546   -
547   - hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
548   - hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash);
549   -
550   - id = ip_idents_reserve(hash, 1);
551   - fhdr->identification = htonl(id);
552   -}
553   -
554 540 int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
555 541 {
556 542 struct sk_buff *frag;
net/ipv6/output_core.c
... ... @@ -9,6 +9,24 @@
9 9 #include <net/addrconf.h>
10 10 #include <net/secure_seq.h>
11 11  
  12 +u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst, struct in6_addr *src)
  13 +{
  14 + u32 hash, id;
  15 +
  16 + hash = __ipv6_addr_jhash(dst, hashrnd);
  17 + hash = __ipv6_addr_jhash(src, hash);
  18 +
  19 + /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
  20 + * set the hight order instead thus minimizing possible future
  21 + * collisions.
  22 + */
  23 + id = ip_idents_reserve(hash, 1);
  24 + if (unlikely(!id))
  25 + id = 1 << 31;
  26 +
  27 + return id;
  28 +}
  29 +
12 30 /* This function exists only for tap drivers that must support broken
13 31 * clients requesting UFO without specifying an IPv6 fragment ID.
14 32 *
... ... @@ -22,7 +40,7 @@
22 40 static u32 ip6_proxy_idents_hashrnd __read_mostly;
23 41 struct in6_addr buf[2];
24 42 struct in6_addr *addrs;
25   - u32 hash, id;
  43 + u32 id;
26 44  
27 45 addrs = skb_header_pointer(skb,
28 46 skb_network_offset(skb) +
29 47  
... ... @@ -34,13 +52,24 @@
34 52 net_get_random_once(&ip6_proxy_idents_hashrnd,
35 53 sizeof(ip6_proxy_idents_hashrnd));
36 54  
37   - hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
38   - hash = __ipv6_addr_jhash(&addrs[0], hash);
39   -
40   - id = ip_idents_reserve(hash, 1);
41   - skb_shinfo(skb)->ip6_frag_id = htonl(id);
  55 + id = __ipv6_select_ident(ip6_proxy_idents_hashrnd,
  56 + &addrs[1], &addrs[0]);
  57 + skb_shinfo(skb)->ip6_frag_id = id;
42 58 }
43 59 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
  60 +
  61 +void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
  62 +{
  63 + static u32 ip6_idents_hashrnd __read_mostly;
  64 + u32 id;
  65 +
  66 + net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
  67 +
  68 + id = __ipv6_select_ident(ip6_idents_hashrnd, &rt->rt6i_dst.addr,
  69 + &rt->rt6i_src.addr);
  70 + fhdr->identification = htonl(id);
  71 +}
  72 +EXPORT_SYMBOL(ipv6_select_ident);
44 73  
45 74 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
46 75 {
net/ipv6/udp_offload.c
... ... @@ -52,6 +52,10 @@
52 52  
53 53 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
54 54  
  55 + /* Set the IPv6 fragment id if not set yet */
  56 + if (!skb_shinfo(skb)->ip6_frag_id)
  57 + ipv6_proxy_select_ident(skb);
  58 +
55 59 segs = NULL;
56 60 goto out;
57 61 }
... ... @@ -108,7 +112,11 @@
108 112 fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
109 113 fptr->nexthdr = nexthdr;
110 114 fptr->reserved = 0;
111   - fptr->identification = skb_shinfo(skb)->ip6_frag_id;
  115 + if (skb_shinfo(skb)->ip6_frag_id)
  116 + fptr->identification = skb_shinfo(skb)->ip6_frag_id;
  117 + else
  118 + ipv6_select_ident(fptr,
  119 + (struct rt6_info *)skb_dst(skb));
112 120  
113 121 /* Fragment the skb. ipv6 header and the remaining fields of the
114 122 * fragment header are updated in ipv6_gso_segment()