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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ struct inet6_skb_parm {
#define IP6SKB_L3SLAVE         64
#define IP6SKB_JUMBOGRAM      128
#define IP6SKB_SEG6	      256
#define IP6SKB_FAKEJUMBO      512
};

#if defined(CONFIG_NET_L3_MASTER_DEV)
+20 −2
Original line number Diff line number Diff line
@@ -182,7 +182,9 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff
#endif

	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);

	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,
	struct dst_entry *dst = skb_dst(skb);
	struct net_device *dev = dst->dev;
	struct inet6_dev *idev = ip6_dst_idev(dst);
	struct hop_jumbo_hdr *hop_jumbo;
	int hoplen = sizeof(*hop_jumbo);
	unsigned int head_room;
	struct ipv6hdr *hdr;
	u8  proto = fl6->flowi6_proto;
@@ -259,7 +263,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
	int hlimit = -1;
	u32 mtu;

	head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dev);
	head_room = sizeof(struct ipv6hdr) + hoplen + LL_RESERVED_SPACE(dev);
	if (opt)
		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,
					     &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_reset_network_header(skb);
	hdr = ipv6_hdr(skb);