Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'big-tcp-without-hbh-in-ipv6'

Alice Mikityanska says:

====================
BIG TCP without HBH in IPv6

Resubmitting after the grace period.

This series is part 1 of "BIG TCP for UDP tunnels". Due to the number of
patches, I'm splitting it into two logical parts:

* Remove hop-by-hop header for BIG TCP IPv6 to align with BIG TCP IPv4.
* Fix up things that prevent BIG TCP from working with UDP tunnels.

The current BIG TCP IPv6 code inserts a hop-by-hop extension header with
32-bit length of the packet. When the packet is encapsulated, and either
the outer or the inner protocol is IPv6, or both are IPv6, there will be
1 or 2 HBH headers that need to be dealt with. The issues that arise:

1. The drivers don't strip it, and they'd all need to know the structure
of each tunnel protocol in order to strip it correctly, also taking into
account all combinations of IPv4/IPv6 inner/outer protocols.

2. Even if (1) is implemented, it would be an additional performance
penalty per aggregated packet.

3. The skb_gso_validate_network_len check is skipped in
ip6_finish_output_gso when IP6SKB_FAKEJUMBO is set, but it seems that it
would make sense to do the actual validation, just taking into account
the length of the HBH header. When the support for tunnels is added, it
becomes trickier, because there may be one or two HBH headers, depending
on whether it's IPv6 in IPv6 or not.

At the same time, having an HBH header to store the 32-bit length is not
strictly necessary, as BIG TCP IPv4 doesn't do anything like this and
just restores the length from skb->len. The same thing can be done for
BIG TCP IPv6. Removing HBH from BIG TCP would allow to simplify the
implementation significantly, and align it with BIG TCP IPv4, which has
been a long-standing goal.
====================

Link: https://patch.msgid.link/20260205133925.526371-1-alice.kernel@fastmail.im
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+61 -282
-3
drivers/net/ethernet/broadcom/bnge/bnge_txrx.c
··· 1463 1463 return NETDEV_TX_BUSY; 1464 1464 } 1465 1465 1466 - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) 1467 - goto tx_free; 1468 - 1469 1466 last_frag = skb_shinfo(skb)->nr_frags; 1470 1467 1471 1468 txbd = &txr->tx_desc_ring[TX_RING(bn, prod)][TX_IDX(prod)];
-21
drivers/net/ethernet/broadcom/bnxt/bnxt.c
··· 517 517 return NETDEV_TX_BUSY; 518 518 } 519 519 520 - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) 521 - goto tx_free; 522 - 523 520 length = skb->len; 524 521 len = skb_headlen(skb); 525 522 last_frag = skb_shinfo(skb)->nr_frags; ··· 13878 13881 u8 **nextp) 13879 13882 { 13880 13883 struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + nw_off); 13881 - struct hop_jumbo_hdr *jhdr; 13882 13884 int hdr_count = 0; 13883 13885 u8 *nexthdr; 13884 13886 int start; ··· 13906 13910 if (hdrlen > 64) 13907 13911 return false; 13908 13912 13909 - /* The ext header may be a hop-by-hop header inserted for 13910 - * big TCP purposes. This will be removed before sending 13911 - * from NIC, so do not count it. 13912 - */ 13913 - if (*nexthdr == NEXTHDR_HOP) { 13914 - if (likely(skb->len <= GRO_LEGACY_MAX_SIZE)) 13915 - goto increment_hdr; 13916 - 13917 - jhdr = (struct hop_jumbo_hdr *)hp; 13918 - if (jhdr->tlv_type != IPV6_TLV_JUMBO || jhdr->hdrlen != 0 || 13919 - jhdr->nexthdr != IPPROTO_TCP) 13920 - goto increment_hdr; 13921 - 13922 - goto next_hdr; 13923 - } 13924 - increment_hdr: 13925 13913 hdr_count++; 13926 - next_hdr: 13927 13914 nexthdr = &hp->nexthdr; 13928 13915 start += hdrlen; 13929 13916 }
-3
drivers/net/ethernet/google/gve/gve_tx_dqo.c
··· 963 963 int num_buffer_descs; 964 964 int total_num_descs; 965 965 966 - if (skb_is_gso(skb) && unlikely(ipv6_hopopt_jumbo_remove(skb))) 967 - goto drop; 968 - 969 966 if (tx->dqo.qpl) { 970 967 /* We do not need to verify the number of buffers used per 971 968 * packet or per segment in case of TSO as with 2K size buffers
-3
drivers/net/ethernet/intel/ice/ice_txrx.c
··· 2156 2156 2157 2157 ice_trace(xmit_frame_ring, tx_ring, skb); 2158 2158 2159 - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) 2160 - goto out_drop; 2161 - 2162 2159 count = ice_xmit_desc_count(skb); 2163 2160 if (ice_chk_linearize(skb, count)) { 2164 2161 if (__skb_linearize(skb))
+8 -34
drivers/net/ethernet/mellanox/mlx4/en_tx.c
··· 636 636 struct net_device *dev, 637 637 int *lso_header_size, 638 638 bool *inline_ok, 639 - void **pfrag, 640 - int *hopbyhop) 639 + void **pfrag) 641 640 { 642 641 struct mlx4_en_priv *priv = netdev_priv(dev); 643 642 int real_size; 644 643 645 644 if (shinfo->gso_size) { 646 645 *inline_ok = false; 647 - *hopbyhop = 0; 648 646 if (skb->encapsulation) { 649 647 *lso_header_size = skb_inner_tcp_all_headers(skb); 650 648 } else { 651 - /* Detects large IPV6 TCP packets and prepares for removal of 652 - * HBH header that has been pushed by ip6_xmit(), 653 - * mainly so that tcpdump can dissect them. 654 - */ 655 - if (ipv6_has_hopopt_jumbo(skb)) 656 - *hopbyhop = sizeof(struct hop_jumbo_hdr); 657 649 *lso_header_size = skb_tcp_all_headers(skb); 658 650 } 659 651 real_size = CTRL_SIZE + shinfo->nr_frags * DS_SIZE + 660 - ALIGN(*lso_header_size - *hopbyhop + 4, DS_SIZE); 652 + ALIGN(*lso_header_size + 4, DS_SIZE); 661 653 if (unlikely(*lso_header_size != skb_headlen(skb))) { 662 654 /* We add a segment for the skb linear buffer only if 663 655 * it contains data */ ··· 876 884 int desc_size; 877 885 int real_size; 878 886 u32 index, bf_index; 879 - struct ipv6hdr *h6; 880 887 __be32 op_own; 881 888 int lso_header_size; 882 889 void *fragptr = NULL; ··· 884 893 bool stop_queue; 885 894 bool inline_ok; 886 895 u8 data_offset; 887 - int hopbyhop; 888 896 bool bf_ok; 889 897 890 898 tx_ind = skb_get_queue_mapping(skb); ··· 893 903 goto tx_drop; 894 904 895 905 real_size = get_real_size(skb, shinfo, dev, &lso_header_size, 896 - &inline_ok, &fragptr, &hopbyhop); 906 + &inline_ok, &fragptr); 897 907 if (unlikely(!real_size)) 898 908 goto tx_drop_count; 899 909 ··· 946 956 data = &tx_desc->data; 947 957 data_offset = offsetof(struct mlx4_en_tx_desc, data); 948 958 } else { 949 - int lso_align = ALIGN(lso_header_size - hopbyhop + 4, DS_SIZE); 959 + int lso_align = ALIGN(lso_header_size + 4, DS_SIZE); 950 960 951 961 data = (void *)&tx_desc->lso + lso_align; 952 962 data_offset = offsetof(struct mlx4_en_tx_desc, lso) + lso_align; ··· 1011 1021 ((ring->prod & ring->size) ? 1012 1022 cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); 1013 1023 1014 - lso_header_size -= hopbyhop; 1015 1024 /* Fill in the LSO prefix */ 1016 1025 tx_desc->lso.mss_hdr_size = cpu_to_be32( 1017 1026 shinfo->gso_size << 16 | lso_header_size); 1018 1027 1028 + /* Copy headers; 1029 + * note that we already verified that it is linear 1030 + */ 1031 + memcpy(tx_desc->lso.header, skb->data, lso_header_size); 1019 1032 1020 - if (unlikely(hopbyhop)) { 1021 - /* remove the HBH header. 1022 - * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 1023 - */ 1024 - memcpy(tx_desc->lso.header, skb->data, ETH_HLEN + sizeof(*h6)); 1025 - h6 = (struct ipv6hdr *)((char *)tx_desc->lso.header + ETH_HLEN); 1026 - h6->nexthdr = IPPROTO_TCP; 1027 - /* Copy the TCP header after the IPv6 one */ 1028 - memcpy(h6 + 1, 1029 - skb->data + ETH_HLEN + sizeof(*h6) + 1030 - sizeof(struct hop_jumbo_hdr), 1031 - tcp_hdrlen(skb)); 1032 - /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 1033 - } else { 1034 - /* Copy headers; 1035 - * note that we already verified that it is linear 1036 - */ 1037 - memcpy(tx_desc->lso.header, skb->data, lso_header_size); 1038 - } 1039 1033 ring->tso_packets++; 1040 1034 1041 1035 i = shinfo->gso_segs;
+12 -63
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
··· 152 152 * to inline later in the transmit descriptor 153 153 */ 154 154 static inline u16 155 - mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int *hopbyhop) 155 + mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb) 156 156 { 157 157 struct mlx5e_sq_stats *stats = sq->stats; 158 158 u16 ihs; 159 159 160 - *hopbyhop = 0; 161 160 if (skb->encapsulation) { 162 161 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 163 162 ihs = skb_inner_transport_offset(skb) + ··· 166 167 stats->tso_inner_packets++; 167 168 stats->tso_inner_bytes += skb->len - ihs; 168 169 } else { 169 - if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 170 + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 170 171 ihs = skb_transport_offset(skb) + sizeof(struct udphdr); 171 - } else { 172 + else 172 173 ihs = skb_tcp_all_headers(skb); 173 - if (ipv6_has_hopopt_jumbo(skb)) { 174 - *hopbyhop = sizeof(struct hop_jumbo_hdr); 175 - ihs -= sizeof(struct hop_jumbo_hdr); 176 - } 177 - } 178 174 stats->tso_packets++; 179 - stats->tso_bytes += skb->len - ihs - *hopbyhop; 175 + stats->tso_bytes += skb->len - ihs; 180 176 } 181 177 182 178 return ihs; ··· 233 239 __be16 mss; 234 240 u16 insz; 235 241 u8 opcode; 236 - u8 hopbyhop; 237 242 }; 238 243 239 244 struct mlx5e_tx_wqe_attr { ··· 268 275 struct mlx5e_sq_stats *stats = sq->stats; 269 276 270 277 if (skb_is_gso(skb)) { 271 - int hopbyhop; 272 - u16 ihs = mlx5e_tx_get_gso_ihs(sq, skb, &hopbyhop); 278 + u16 ihs = mlx5e_tx_get_gso_ihs(sq, skb); 273 279 274 280 *attr = (struct mlx5e_tx_attr) { 275 281 .opcode = MLX5_OPCODE_LSO, 276 282 .mss = cpu_to_be16(skb_shinfo(skb)->gso_size), 277 283 .ihs = ihs, 278 284 .num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs, 279 - .headlen = skb_headlen(skb) - ihs - hopbyhop, 280 - .hopbyhop = hopbyhop, 285 + .headlen = skb_headlen(skb) - ihs, 281 286 }; 282 287 283 288 stats->packets += skb_shinfo(skb)->gso_segs; ··· 430 439 struct mlx5_wqe_data_seg *dseg; 431 440 struct mlx5e_tx_wqe_info *wi; 432 441 u16 ihs = attr->ihs; 433 - struct ipv6hdr *h6; 434 442 struct mlx5e_sq_stats *stats = sq->stats; 435 443 int num_dma; 436 444 ··· 446 456 if (ihs) { 447 457 u8 *start = eseg->inline_hdr.start; 448 458 449 - if (unlikely(attr->hopbyhop)) { 450 - /* remove the HBH header. 451 - * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 452 - */ 453 - if (skb_vlan_tag_present(skb)) { 454 - mlx5e_insert_vlan(start, skb, ETH_HLEN + sizeof(*h6)); 455 - ihs += VLAN_HLEN; 456 - h6 = (struct ipv6hdr *)(start + sizeof(struct vlan_ethhdr)); 457 - } else { 458 - unsafe_memcpy(start, skb->data, 459 - ETH_HLEN + sizeof(*h6), 460 - MLX5_UNSAFE_MEMCPY_DISCLAIMER); 461 - h6 = (struct ipv6hdr *)(start + ETH_HLEN); 462 - } 463 - h6->nexthdr = IPPROTO_TCP; 464 - /* Copy the TCP header after the IPv6 one */ 465 - memcpy(h6 + 1, 466 - skb->data + ETH_HLEN + sizeof(*h6) + 467 - sizeof(struct hop_jumbo_hdr), 468 - tcp_hdrlen(skb)); 469 - /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 470 - } else if (skb_vlan_tag_present(skb)) { 459 + if (skb_vlan_tag_present(skb)) { 471 460 mlx5e_insert_vlan(start, skb, ihs); 472 461 ihs += VLAN_HLEN; 473 462 stats->added_vlan_packets++; ··· 460 491 } 461 492 462 493 dseg += wqe_attr->ds_cnt_ids; 463 - num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr->ihs + attr->hopbyhop, 494 + num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr->ihs, 464 495 attr->headlen, dseg); 465 496 if (unlikely(num_dma < 0)) 466 497 goto err_drop; ··· 988 1019 eseg->mss = attr.mss; 989 1020 990 1021 if (attr.ihs) { 991 - if (unlikely(attr.hopbyhop)) { 992 - struct ipv6hdr *h6; 993 - 994 - /* remove the HBH header. 995 - * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 996 - */ 997 - unsafe_memcpy(eseg->inline_hdr.start, skb->data, 998 - ETH_HLEN + sizeof(*h6), 999 - MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1000 - h6 = (struct ipv6hdr *)((char *)eseg->inline_hdr.start + ETH_HLEN); 1001 - h6->nexthdr = IPPROTO_TCP; 1002 - /* Copy the TCP header after the IPv6 one */ 1003 - unsafe_memcpy(h6 + 1, 1004 - skb->data + ETH_HLEN + sizeof(*h6) + 1005 - sizeof(struct hop_jumbo_hdr), 1006 - tcp_hdrlen(skb), 1007 - MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1008 - /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 1009 - } else { 1010 - unsafe_memcpy(eseg->inline_hdr.start, skb->data, 1011 - attr.ihs, 1012 - MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1013 - } 1022 + unsafe_memcpy(eseg->inline_hdr.start, skb->data, 1023 + attr.ihs, 1024 + MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1014 1025 eseg->inline_hdr.sz = cpu_to_be16(attr.ihs); 1015 1026 dseg += wqe_attr.ds_cnt_inl; 1016 1027 } 1017 1028 1018 - num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr.ihs + attr.hopbyhop, 1029 + num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr.ihs, 1019 1030 attr.headlen, dseg); 1020 1031 if (unlikely(num_dma < 0)) 1021 1032 goto err_drop;
-3
drivers/net/ethernet/microsoft/mana/mana_en.c
··· 355 355 if (skb_cow_head(skb, MANA_HEADROOM)) 356 356 goto tx_drop_count; 357 357 358 - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) 359 - goto tx_drop_count; 360 - 361 358 txq = &apc->tx_qp[txq_idx].txq; 362 359 gdma_sq = txq->gdma_sq; 363 360 cq = &apc->tx_qp[txq_idx].tx_cq;
+22 -1
include/linux/ipv6.h
··· 126 126 skb_network_header_len(skb); 127 127 } 128 128 129 + static inline unsigned int 130 + ipv6_payload_len(const struct sk_buff *skb, const struct ipv6hdr *ip6) 131 + { 132 + u32 len = ntohs(ip6->payload_len); 133 + 134 + return (len || !skb_is_gso(skb) || !skb_is_gso_tcp(skb)) ? 135 + len : 136 + skb->len - skb_network_offset(skb) - sizeof(struct ipv6hdr); 137 + } 138 + 139 + static inline unsigned int skb_ipv6_payload_len(const struct sk_buff *skb) 140 + { 141 + return ipv6_payload_len(skb, ipv6_hdr(skb)); 142 + } 143 + 144 + #define IPV6_MAXPLEN 65535 145 + 146 + static inline void ipv6_set_payload_len(struct ipv6hdr *ip6, unsigned int len) 147 + { 148 + ip6->payload_len = len <= IPV6_MAXPLEN ? htons(len) : 0; 149 + } 150 + 129 151 /* 130 152 This structure contains results of exthdrs parsing 131 153 as offsets from skb->nh. ··· 177 155 #define IP6SKB_L3SLAVE 64 178 156 #define IP6SKB_JUMBOGRAM 128 179 157 #define IP6SKB_SEG6 256 180 - #define IP6SKB_FAKEJUMBO 512 181 158 #define IP6SKB_MULTIPATH 1024 182 159 #define IP6SKB_MCROUTE 2048 183 160 };
-79
include/net/ipv6.h
··· 25 25 26 26 #define SIN6_LEN_RFC2133 24 27 27 28 - #define IPV6_MAXPLEN 65535 29 - 30 28 /* 31 29 * NextHeader field of IPv6 header 32 30 */ ··· 147 149 __u8 reserved; 148 150 __be16 frag_off; 149 151 __be32 identification; 150 - }; 151 - 152 - /* 153 - * Jumbo payload option, as described in RFC 2675 2. 154 - */ 155 - struct hop_jumbo_hdr { 156 - u8 nexthdr; 157 - u8 hdrlen; 158 - u8 tlv_type; /* IPV6_TLV_JUMBO, 0xC2 */ 159 - u8 tlv_len; /* 4 */ 160 - __be32 jumbo_payload_len; 161 152 }; 162 153 163 154 #define IP6_MF 0x0001 ··· 450 463 const struct inet6_skb_parm *opt); 451 464 struct ipv6_txoptions *ipv6_update_options(struct sock *sk, 452 465 struct ipv6_txoptions *opt); 453 - 454 - /* This helper is specialized for BIG TCP needs. 455 - * It assumes the hop_jumbo_hdr will immediately follow the IPV6 header. 456 - * It assumes headers are already in skb->head. 457 - * Returns: 0, or IPPROTO_TCP if a BIG TCP packet is there. 458 - */ 459 - static inline int ipv6_has_hopopt_jumbo(const struct sk_buff *skb) 460 - { 461 - const struct hop_jumbo_hdr *jhdr; 462 - const struct ipv6hdr *nhdr; 463 - 464 - if (likely(skb->len <= GRO_LEGACY_MAX_SIZE)) 465 - return 0; 466 - 467 - if (skb->protocol != htons(ETH_P_IPV6)) 468 - return 0; 469 - 470 - if (skb_network_offset(skb) + 471 - sizeof(struct ipv6hdr) + 472 - sizeof(struct hop_jumbo_hdr) > skb_headlen(skb)) 473 - return 0; 474 - 475 - nhdr = ipv6_hdr(skb); 476 - 477 - if (nhdr->nexthdr != NEXTHDR_HOP) 478 - return 0; 479 - 480 - jhdr = (const struct hop_jumbo_hdr *) (nhdr + 1); 481 - if (jhdr->tlv_type != IPV6_TLV_JUMBO || jhdr->hdrlen != 0 || 482 - jhdr->nexthdr != IPPROTO_TCP) 483 - return 0; 484 - return jhdr->nexthdr; 485 - } 486 - 487 - /* Return 0 if HBH header is successfully removed 488 - * Or if HBH removal is unnecessary (packet is not big TCP) 489 - * Return error to indicate dropping the packet 490 - */ 491 - static inline int ipv6_hopopt_jumbo_remove(struct sk_buff *skb) 492 - { 493 - const int hophdr_len = sizeof(struct hop_jumbo_hdr); 494 - int nexthdr = ipv6_has_hopopt_jumbo(skb); 495 - struct ipv6hdr *h6; 496 - 497 - if (!nexthdr) 498 - return 0; 499 - 500 - if (skb_cow_head(skb, 0)) 501 - return -1; 502 - 503 - /* Remove the HBH header. 504 - * Layout: [Ethernet header][IPv6 header][HBH][L4 Header] 505 - */ 506 - memmove(skb_mac_header(skb) + hophdr_len, skb_mac_header(skb), 507 - skb_network_header(skb) - skb_mac_header(skb) + 508 - sizeof(struct ipv6hdr)); 509 - 510 - __skb_pull(skb, hophdr_len); 511 - skb->network_header += hophdr_len; 512 - skb->mac_header += hophdr_len; 513 - 514 - h6 = ipv6_hdr(skb); 515 - h6->nexthdr = nexthdr; 516 - 517 - return 0; 518 - } 519 466 520 467 static inline bool ipv6_accept_ra(const struct inet6_dev *idev) 521 468 {
+2 -2
include/net/netfilter/nf_tables_ipv6.h
··· 42 42 if (ip6h->version != 6) 43 43 return -1; 44 44 45 - pkt_len = ntohs(ip6h->payload_len); 45 + pkt_len = ipv6_payload_len(pkt->skb, ip6h); 46 46 skb_len = pkt->skb->len - skb_network_offset(pkt->skb); 47 47 if (pkt_len + sizeof(*ip6h) > skb_len) 48 48 return -1; ··· 86 86 if (ip6h->version != 6) 87 87 goto inhdr_error; 88 88 89 - pkt_len = ntohs(ip6h->payload_len); 89 + pkt_len = ipv6_payload_len(pkt->skb, ip6h); 90 90 if (pkt_len + sizeof(*ip6h) > pkt->skb->len) { 91 91 idev = __in6_dev_get(nft_in(pkt)); 92 92 __IP6_INC_STATS(nft_net(pkt), idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+1 -1
net/bridge/br_netfilter_ipv6.c
··· 58 58 if (hdr->version != 6) 59 59 goto inhdr_error; 60 60 61 - pkt_len = ntohs(hdr->payload_len); 61 + pkt_len = ipv6_payload_len(skb, hdr); 62 62 if (hdr->nexthdr == NEXTHDR_HOP && nf_ip6_check_hbh_len(skb, &pkt_len)) 63 63 goto drop; 64 64
+2 -2
net/bridge/netfilter/nf_conntrack_bridge.c
··· 229 229 if (hdr->version != 6) 230 230 return -1; 231 231 232 - len = ntohs(hdr->payload_len) + sizeof(struct ipv6hdr) + nhoff; 232 + len = ipv6_payload_len(skb, hdr) + sizeof(struct ipv6hdr) + nhoff; 233 233 if (skb->len < len) 234 234 return -1; 235 235 ··· 269 269 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 270 270 return NF_ACCEPT; 271 271 272 - len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); 272 + len = sizeof(struct ipv6hdr) + skb_ipv6_payload_len(skb); 273 273 if (pskb_trim_rcsum(skb, len)) 274 274 return NF_ACCEPT; 275 275
+2 -4
net/core/dev.c
··· 3813 3813 (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && 3814 3814 vlan_get_protocol(skb) == htons(ETH_P_IPV6))) && 3815 3815 skb_transport_header_was_set(skb) && 3816 - skb_network_header_len(skb) != sizeof(struct ipv6hdr) && 3817 - !ipv6_has_hopopt_jumbo(skb)) 3816 + skb_network_header_len(skb) != sizeof(struct ipv6hdr)) 3818 3817 features &= ~(NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4); 3819 3818 3820 3819 return features; ··· 3916 3917 3917 3918 if (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { 3918 3919 if (vlan_get_protocol(skb) == htons(ETH_P_IPV6) && 3919 - skb_network_header_len(skb) != sizeof(struct ipv6hdr) && 3920 - !ipv6_has_hopopt_jumbo(skb)) 3920 + skb_network_header_len(skb) != sizeof(struct ipv6hdr)) 3921 3921 goto sw_checksum; 3922 3922 3923 3923 switch (skb->csum_offset) {
-2
net/core/gro.c
··· 115 115 116 116 if (unlikely(p->len + len >= GRO_LEGACY_MAX_SIZE)) { 117 117 if (NAPI_GRO_CB(skb)->proto != IPPROTO_TCP || 118 - (p->protocol == htons(ETH_P_IPV6) && 119 - skb_headroom(p) < sizeof(struct hop_jumbo_hdr)) || 120 118 p->encapsulation) 121 119 return -E2BIG; 122 120 }
+1 -1
net/ipv6/ip6_input.c
··· 262 262 skb->transport_header = skb->network_header + sizeof(*hdr); 263 263 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); 264 264 265 - pkt_len = ntohs(hdr->payload_len); 265 + pkt_len = ipv6_payload_len(skb, hdr); 266 266 267 267 /* pkt_len may be zero if Jumbo payload option is present */ 268 268 if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
+3 -33
net/ipv6/ip6_offload.c
··· 94 94 struct sk_buff *segs = ERR_PTR(-EINVAL); 95 95 struct ipv6hdr *ipv6h; 96 96 const struct net_offload *ops; 97 - int proto, err; 97 + int proto; 98 98 struct frag_hdr *fptr; 99 99 unsigned int payload_len; 100 100 u8 *prevhdr; ··· 104 104 bool gso_partial; 105 105 106 106 skb_reset_network_header(skb); 107 - err = ipv6_hopopt_jumbo_remove(skb); 108 - if (err) 109 - return ERR_PTR(err); 110 107 nhoff = skb_network_header(skb) - skb_mac_header(skb); 111 108 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) 112 109 goto out; ··· 333 336 const struct net_offload *ops; 334 337 struct ipv6hdr *iph; 335 338 int err = -ENOSYS; 336 - u32 payload_len; 337 339 338 340 if (skb->encapsulation) { 339 341 skb_set_inner_protocol(skb, cpu_to_be16(ETH_P_IPV6)); 340 342 skb_set_inner_network_header(skb, nhoff); 341 343 } 342 344 343 - payload_len = skb->len - nhoff - sizeof(*iph); 344 - if (unlikely(payload_len > IPV6_MAXPLEN)) { 345 - struct hop_jumbo_hdr *hop_jumbo; 346 - int hoplen = sizeof(*hop_jumbo); 347 - 348 - /* Move network header left */ 349 - memmove(skb_mac_header(skb) - hoplen, skb_mac_header(skb), 350 - skb->transport_header - skb->mac_header); 351 - skb->data -= hoplen; 352 - skb->len += hoplen; 353 - skb->mac_header -= hoplen; 354 - skb->network_header -= hoplen; 355 - iph = (struct ipv6hdr *)(skb->data + nhoff); 356 - hop_jumbo = (struct hop_jumbo_hdr *)(iph + 1); 357 - 358 - /* Build hop-by-hop options */ 359 - hop_jumbo->nexthdr = iph->nexthdr; 360 - hop_jumbo->hdrlen = 0; 361 - hop_jumbo->tlv_type = IPV6_TLV_JUMBO; 362 - hop_jumbo->tlv_len = 4; 363 - hop_jumbo->jumbo_payload_len = htonl(payload_len + hoplen); 364 - 365 - iph->nexthdr = NEXTHDR_HOP; 366 - iph->payload_len = 0; 367 - } else { 368 - iph = (struct ipv6hdr *)(skb->data + nhoff); 369 - iph->payload_len = htons(payload_len); 370 - } 345 + iph = (struct ipv6hdr *)(skb->data + nhoff); 346 + ipv6_set_payload_len(iph, skb->len - nhoff - sizeof(*iph)); 371 347 372 348 nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops); 373 349
+3 -17
net/ipv6/ip6_output.c
··· 179 179 static int ip6_finish_output_gso(struct net *net, struct sock *sk, 180 180 struct sk_buff *skb, unsigned int mtu) 181 181 { 182 - if (unlikely(!(IP6CB(skb)->flags & IP6SKB_FAKEJUMBO) && 183 - !skb_gso_validate_network_len(skb, mtu))) 182 + if (unlikely(!skb_gso_validate_network_len(skb, mtu))) 184 183 return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu); 185 184 186 185 return ip6_finish_output2(net, sk, skb); ··· 272 273 struct in6_addr *first_hop = &fl6->daddr; 273 274 struct dst_entry *dst = skb_dst(skb); 274 275 struct inet6_dev *idev = ip6_dst_idev(dst); 275 - struct hop_jumbo_hdr *hop_jumbo; 276 - int hoplen = sizeof(*hop_jumbo); 277 276 struct net *net = sock_net(sk); 278 277 unsigned int head_room; 279 278 struct net_device *dev; ··· 284 287 rcu_read_lock(); 285 288 286 289 dev = dst_dev_rcu(dst); 287 - head_room = sizeof(struct ipv6hdr) + hoplen + LL_RESERVED_SPACE(dev); 290 + head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dev); 288 291 if (opt) 289 292 head_room += opt->opt_nflen + opt->opt_flen; 290 293 ··· 310 313 &fl6->saddr); 311 314 } 312 315 313 - if (unlikely(seg_len > IPV6_MAXPLEN)) { 314 - hop_jumbo = __skb_push(skb, hoplen); 315 - 316 - hop_jumbo->nexthdr = proto; 317 - hop_jumbo->hdrlen = 0; 318 - hop_jumbo->tlv_type = IPV6_TLV_JUMBO; 319 - hop_jumbo->tlv_len = 4; 320 - hop_jumbo->jumbo_payload_len = htonl(seg_len + hoplen); 321 - 322 - proto = IPPROTO_HOPOPTS; 316 + if (unlikely(seg_len > IPV6_MAXPLEN)) 323 317 seg_len = 0; 324 - IP6CB(skb)->flags |= IP6SKB_FAKEJUMBO; 325 - } 326 318 327 319 __skb_push(skb, sizeof(struct ipv6hdr)); 328 320 skb_reset_network_header(skb);
+1 -6
net/ipv6/output_core.c
··· 125 125 126 126 int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) 127 127 { 128 - int len; 129 - 130 - len = skb->len - sizeof(struct ipv6hdr); 131 - if (len > IPV6_MAXPLEN) 132 - len = 0; 133 - ipv6_hdr(skb)->payload_len = htons(len); 128 + ipv6_set_payload_len(ipv6_hdr(skb), skb->len - sizeof(struct ipv6hdr)); 134 129 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); 135 130 136 131 /* if egress device is enslaved to an L3 master device pass the
+1 -1
net/netfilter/ipvs/ip_vs_xmit.c
··· 949 949 *next_protocol = IPPROTO_IPV6; 950 950 if (payload_len) 951 951 *payload_len = 952 - ntohs(old_ipv6h->payload_len) + 952 + ipv6_payload_len(skb, old_ipv6h) + 953 953 sizeof(*old_ipv6h); 954 954 old_dsfield = ipv6_get_dsfield(old_ipv6h); 955 955 *ttl = old_ipv6h->hop_limit;
+1 -1
net/netfilter/nf_conntrack_ovs.c
··· 121 121 len = skb_ip_totlen(skb); 122 122 break; 123 123 case NFPROTO_IPV6: 124 - len = ntohs(ipv6_hdr(skb)->payload_len); 124 + len = skb_ipv6_payload_len(skb); 125 125 if (ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP) { 126 126 int err = nf_ip6_check_hbh_len(skb, &len); 127 127
+1 -1
net/netfilter/nf_log_syslog.c
··· 561 561 562 562 /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ 563 563 nf_log_buf_add(m, "LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", 564 - ntohs(ih->payload_len) + sizeof(struct ipv6hdr), 564 + ipv6_payload_len(skb, ih) + sizeof(struct ipv6hdr), 565 565 (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, 566 566 ih->hop_limit, 567 567 (ntohl(*(__be32 *)ih) & 0x000fffff));
+1 -1
net/sched/sch_cake.c
··· 1279 1279 ipv6_addr_cmp(&ipv6h_check->daddr, &ipv6h->daddr)) 1280 1280 continue; 1281 1281 1282 - seglen = ntohs(ipv6h_check->payload_len); 1282 + seglen = ipv6_payload_len(skb, ipv6h_check); 1283 1283 } else { 1284 1284 WARN_ON(1); /* shouldn't happen */ 1285 1285 continue;