Commit 80e425b6 authored by Coco Li's avatar Coco Li Committed by David S. Miller

ipv6: Add hop-by-hop header to jumbograms in ip6_output

Instead of simply forcing a 0 payload_len in IPv6 header,
implement RFC 2675 and insert a custom extension header.

Note that only TCP stack is currently potentially generating
jumbograms, and that this extension header is purely local,
it wont be sent on a physical link.

This is needed so that packet capture (tcpdump and friends)
can properly dissect these large packets.
Signed-off-by: default avatarCoco Li <lixiaoyan@google.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarAlexander Duyck <alexanderduyck@fb.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0fe79f28
...@@ -145,6 +145,7 @@ struct inet6_skb_parm { ...@@ -145,6 +145,7 @@ struct inet6_skb_parm {
#define IP6SKB_L3SLAVE 64 #define IP6SKB_L3SLAVE 64
#define IP6SKB_JUMBOGRAM 128 #define IP6SKB_JUMBOGRAM 128
#define IP6SKB_SEG6 256 #define IP6SKB_SEG6 256
#define IP6SKB_FAKEJUMBO 512
}; };
#if defined(CONFIG_NET_L3_MASTER_DEV) #if defined(CONFIG_NET_L3_MASTER_DEV)
......
...@@ -182,7 +182,9 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff ...@@ -182,7 +182,9 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff
#endif #endif
mtu = ip6_skb_dst_mtu(skb); mtu = ip6_skb_dst_mtu(skb);
if (skb_is_gso(skb) && !skb_gso_validate_network_len(skb, mtu)) if (skb_is_gso(skb) &&
!(IP6CB(skb)->flags & IP6SKB_FAKEJUMBO) &&
!skb_gso_validate_network_len(skb, mtu))
return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu); return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu);
if ((skb->len > mtu && !skb_is_gso(skb)) || if ((skb->len > mtu && !skb_is_gso(skb)) ||
...@@ -252,6 +254,8 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, ...@@ -252,6 +254,8 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev; struct net_device *dev = dst->dev;
struct inet6_dev *idev = ip6_dst_idev(dst); struct inet6_dev *idev = ip6_dst_idev(dst);
struct hop_jumbo_hdr *hop_jumbo;
int hoplen = sizeof(*hop_jumbo);
unsigned int head_room; unsigned int head_room;
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
u8 proto = fl6->flowi6_proto; u8 proto = fl6->flowi6_proto;
...@@ -259,7 +263,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, ...@@ -259,7 +263,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
int hlimit = -1; int hlimit = -1;
u32 mtu; u32 mtu;
head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dev); head_room = sizeof(struct ipv6hdr) + hoplen + LL_RESERVED_SPACE(dev);
if (opt) if (opt)
head_room += opt->opt_nflen + opt->opt_flen; head_room += opt->opt_nflen + opt->opt_flen;
...@@ -282,6 +286,20 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, ...@@ -282,6 +286,20 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
&fl6->saddr); &fl6->saddr);
} }
if (unlikely(seg_len > IPV6_MAXPLEN)) {
hop_jumbo = skb_push(skb, hoplen);
hop_jumbo->nexthdr = proto;
hop_jumbo->hdrlen = 0;
hop_jumbo->tlv_type = IPV6_TLV_JUMBO;
hop_jumbo->tlv_len = 4;
hop_jumbo->jumbo_payload_len = htonl(seg_len + hoplen);
proto = IPPROTO_HOPOPTS;
seg_len = 0;
IP6CB(skb)->flags |= IP6SKB_FAKEJUMBO;
}
skb_push(skb, sizeof(struct ipv6hdr)); skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb); skb_reset_network_header(skb);
hdr = ipv6_hdr(skb); hdr = ipv6_hdr(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment