diff options
53 files changed, 340 insertions, 102 deletions
diff --git a/drivers/infiniband/core/lag.c b/drivers/infiniband/core/lag.c index 8fd80adfe833..00fe241737ff 100644 --- a/drivers/infiniband/core/lag.c +++ b/drivers/infiniband/core/lag.c @@ -36,7 +36,7 @@ static struct sk_buff *rdma_build_skb(struct net_device *netdev, uh->source = htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label)); uh->dest = htons(ROCE_V2_UDP_DPORT); - uh->len = htons(sizeof(struct udphdr)); + udp_set_len_short(uh, sizeof(struct udphdr)); if (is_ipv4) { skb_push(skb, sizeof(struct iphdr)); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 3741b2c4b0bb..53daaf4c1eb2 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -242,7 +242,7 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb) pkt->port_num = 1; pkt->hdr = (u8 *)(udph + 1); pkt->mask = RXE_GRH_MASK; - pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph); + pkt->paylen = udp_get_len_short(udph) - sizeof(*udph); /* remove udp header */ skb_pull(skb, sizeof(struct udphdr)); @@ -305,7 +305,7 @@ static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port, udph->dest = dst_port; udph->source = src_port; - udph->len = htons(skb->len); + udp_set_len_short(udph, skb->len); udph->check = 0; } diff --git a/drivers/net/amt.c b/drivers/net/amt.c index 02168862f676..f8169c5512a5 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -667,7 +667,7 @@ static void amt_send_discovery(struct amt_dev *amt) udph = udp_hdr(skb); udph->source = amt->gw_port; udph->dest = amt->relay_port; - udph->len = htons(sizeof(*udph) + sizeof(*amtd)); + udp_set_len_short(udph, sizeof(*udph) + sizeof(*amtd)); udph->check = 0; offset = skb_transport_offset(skb); skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); @@ -760,7 +760,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6) udph = udp_hdr(skb); udph->source = amt->gw_port; udph->dest = amt->relay_port; - udph->len = htons(sizeof(*amtrh) + sizeof(*udph)); + udp_set_len_short(udph, sizeof(*amtrh) + sizeof(*udph)); udph->check = 0; offset = skb_transport_offset(skb); skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); @@ -2611,7 +2611,7 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce, udph = udp_hdr(skb); udph->source = amt->relay_port; udph->dest = dport; - udph->len = htons(sizeof(*amta) + sizeof(*udph)); + udp_set_len_short(udph, sizeof(*amta) + sizeof(*udph)); udph->check = 0; offset = skb_transport_offset(skb); skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 894f2d06d39d..ef5e657816f0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -3129,7 +3129,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, SKB_GSO_UDP_TUNNEL_CSUM)) { if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) { - l4.udp->len = 0; + udp_set_len_short(l4.udp, 0); /* determine offset of outer transport header */ l4_offset = l4.hdr - skb->data; diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index 363c42bf3dcf..c30abf17cf5d 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -1774,7 +1774,7 @@ static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len, SKB_GSO_UDP_TUNNEL_CSUM)) { if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) { - l4.udp->len = 0; + udp_set_len_short(l4.udp, 0); /* determine offset of outer transport header */ l4_offset = l4.hdr - skb->data; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 4ca1a0602307..fdea2758adf1 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1893,7 +1893,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off) SKB_GSO_UDP_TUNNEL_CSUM)) { if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) { - l4.udp->len = 0; + udp_set_len_short(l4.udp, 0); /* determine offset of outer transport header */ l4_start = (u8)(l4.hdr - skb->data); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 7f9056404f64..566b08ca3a6c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2871,7 +2871,7 @@ int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off) (__force __wsum)htonl(paylen)); /* compute length of segmentation header */ off->tso_hdr_len = sizeof(struct udphdr) + l4_start; - l4.udp->len = htons(shinfo->gso_size + sizeof(struct udphdr)); + udp_set_len_short(l4.udp, shinfo->gso_size + sizeof(struct udphdr)); break; default: return -EINVAL; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index 625bb5a05344..8d2d607bc92f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -750,7 +750,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, ext->lso_format = pfvf->hw.lso_udpv6_idx; } - udph->len = htons(sizeof(struct udphdr)); + udp_set_len_short(udph, sizeof(struct udphdr)); } } else if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { ext->tstmp = 1; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 6fbc0441c4b8..04af54b704d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1081,7 +1081,7 @@ static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr * struct udphdr *uh; uh = (struct udphdr *)(skb->data + udp_off); - uh->len = htons(skb->len - udp_off); + udp_set_len_short(uh, skb->len - udp_off); if (uh->check) uh->check = ~udp_v4_check(skb->len - udp_off, ipv4->saddr, @@ -1100,7 +1100,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr struct udphdr *uh; uh = (struct udphdr *)(skb->data + udp_off); - uh->len = htons(skb->len - udp_off); + udp_set_len_short(uh, skb->len - udp_off); if (uh->check) uh->check = ~udp_v6_check(skb->len - udp_off, &ipv6->saddr, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index accc26d1a872..1dcdb86690bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -113,7 +113,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv) /* Fill UDP header */ udph->source = htons(9); udph->dest = htons(9); /* Discard Protocol */ - udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr)); + udp_set_len_short(udph, sizeof(struct mlx5ehdr) + sizeof(struct udphdr)); udph->check = 0; /* Fill IP header */ diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c index db4dd7fb77f5..4d29e0baf2eb 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.c +++ b/drivers/net/ethernet/sfc/falcon/selftest.c @@ -401,8 +401,8 @@ static void ef4_iterate_state(struct ef4_nic *efx) /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - - offsetof(struct ef4_loopback_payload, udp)); + udp_set_len_short(&payload->udp, sizeof(*payload) - + offsetof(struct ef4_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 8ec76329237a..dc716feb79cb 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -398,8 +398,8 @@ static void efx_iterate_state(struct efx_nic *efx) /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - - offsetof(struct efx_loopback_payload, udp)); + udp_set_len_short(&payload->udp, sizeof(*payload) - + offsetof(struct efx_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ diff --git a/drivers/net/ethernet/sfc/siena/selftest.c b/drivers/net/ethernet/sfc/siena/selftest.c index 930643612df5..c74cf5131364 100644 --- a/drivers/net/ethernet/sfc/siena/selftest.c +++ b/drivers/net/ethernet/sfc/siena/selftest.c @@ -399,8 +399,8 @@ static void efx_iterate_state(struct efx_nic *efx) /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - - offsetof(struct efx_loopback_payload, udp)); + udp_set_len_short(&payload->udp, sizeof(*payload) - + offsetof(struct efx_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index db222abef53b..c2ad3a358d20 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -311,7 +311,7 @@ static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len) encap->encap_hdr_len += sizeof(*udp); udp->dest = key->tp_dst; - udp->len = cpu_to_be16(sizeof(*udp) + len); + udp_set_len_short(udp, sizeof(*udp) + len); } static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c index a0c75886587c..29e824bd90ca 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c @@ -154,9 +154,9 @@ static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv, } else { uhdr->source = htons(attr->sport); uhdr->dest = htons(attr->dport); - uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size); + udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size); if (attr->max_size) - uhdr->len = htons(attr->max_size - + udp_set_len_short(uhdr, attr->max_size - (sizeof(*ihdr) + sizeof(*ehdr))); uhdr->check = 0; } diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 17bd3543d587..359d6da7348c 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -630,7 +630,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb, /* Adjust the nested UDP header len and checksum. */ uh = udp_hdr(skb); - uh->len = htons(skb->len - gro_hint->nested_tp_offset); + udp_set_len_short(uh, skb->len - gro_hint->nested_tp_offset); if (uh->check) { len = skb->len - gro_hint->nested_tp_offset; skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; @@ -1808,6 +1808,8 @@ static void geneve_setup(struct net_device *dev) dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len; netif_keep_dst(dev); + netif_set_tso_max_size(dev, GSO_MAX_SIZE); + dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; dev->lltx = true; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 49b2243a20b2..7f8851a734fc 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -1881,7 +1881,7 @@ static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len) udph = udp_hdr(skb); udph->source = htons(nt->local_port); udph->dest = htons(nt->remote_port); - udph->len = htons(udp_len); + udp_set_len_short(udph, udp_len); netpoll_udp_checksum(np, skb, len); } diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index aed9ad5f1b43..f65b4cf4ea39 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -845,7 +845,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); get_random_bytes(&udph->source, sizeof(u16)); get_random_bytes(&udph->dest, sizeof(u16)); - udph->len = htons(sizeof(struct udphdr) + data_len); + udp_set_len_short(udph, sizeof(struct udphdr) + data_len); return skb; } diff --git a/drivers/net/netdevsim/psample.c b/drivers/net/netdevsim/psample.c index 717d157c3ae2..1e71c3da4def 100644 --- a/drivers/net/netdevsim/psample.c +++ b/drivers/net/netdevsim/psample.c @@ -73,7 +73,7 @@ static struct sk_buff *nsim_dev_psample_skb_build(void) udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); get_random_bytes(&udph->source, sizeof(u16)); get_random_bytes(&udph->dest, sizeof(u16)); - udph->len = htons(sizeof(struct udphdr) + data_len); + udp_set_len_short(udph, sizeof(struct udphdr) + data_len); return skb; } diff --git a/drivers/net/netdevsim/psp.c b/drivers/net/netdevsim/psp.c index 59c990fdc79e..6b3532b5e360 100644 --- a/drivers/net/netdevsim/psp.c +++ b/drivers/net/netdevsim/psp.c @@ -84,6 +84,7 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns, struct iphdr *iph; struct udphdr *uh; __wsum csum; + int udplen; /* Do not decapsulate. Receive the skb with the udp and psp * headers still there as if this is a normal udp packet. @@ -91,19 +92,20 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns, * provide a valid checksum here, so the skb isn't dropped. */ uh = udp_hdr(skb); + udplen = udp_get_len(skb, uh, skb_transport_offset(skb)); csum = skb_checksum(skb, skb_transport_offset(skb), - ntohs(uh->len), 0); + udplen, 0); switch (skb->protocol) { case htons(ETH_P_IP): iph = ip_hdr(skb); - uh->check = udp_v4_check(ntohs(uh->len), iph->saddr, + uh->check = udp_v4_check(udplen, iph->saddr, iph->daddr, csum); break; #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): ip6h = ipv6_hdr(skb); - uh->check = udp_v6_check(ntohs(uh->len), &ip6h->saddr, + uh->check = udp_v6_check(udplen, &ip6h->saddr, &ip6h->daddr, csum); break; #endif diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 67c367cc5662..3a32f067e701 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -3370,6 +3370,8 @@ static void vxlan_setup(struct net_device *dev) dev->mangleid_features = NETIF_F_GSO_PARTIAL; netif_keep_dst(dev); + netif_set_tso_max_size(dev, GSO_MAX_SIZE); + dev->priv_flags |= IFF_NO_QUEUE; dev->change_proto_down = true; dev->lltx = true; diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c index eb8851113654..824bbefce61c 100644 --- a/drivers/net/wireguard/receive.c +++ b/drivers/net/wireguard/receive.c @@ -62,7 +62,7 @@ static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg) * to have UDP fields. */ return -EINVAL; - data_len = ntohs(udp->len); + data_len = udp_get_len_short(udp); if (unlikely(data_len < sizeof(struct udphdr) || data_len > skb->len - data_offset)) /* UDP packet is reporting too small of a size or lying about diff --git a/include/linux/udp.h b/include/linux/udp.h index ce56ebcee5cb..998906ec3b32 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -23,6 +23,33 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb) return (struct udphdr *)skb_transport_header(skb); } +static inline unsigned int udp_get_len(const struct sk_buff *skb, + const struct udphdr *uh, + unsigned int dataoff) +{ + if (uh->len) + return ntohs(uh->len); + if (skb_is_gso(skb)) /* BIG TCP */ + return skb->len - dataoff; + return 0; +} + +static inline unsigned int udp_get_len_short(const struct udphdr *uh) +{ + return ntohs(uh->len); +} + +static inline void udp_set_len(struct udphdr *uh, unsigned int len) +{ + uh->len = len < GRO_LEGACY_MAX_SIZE ? htons(len) : 0; +} + +static inline void udp_set_len_short(struct udphdr *uh, unsigned int len) +{ + DEBUG_NET_WARN_ON_ONCE(len >= GRO_LEGACY_MAX_SIZE); + uh->len = htons(len); +} + #define UDP_HTABLE_SIZE_MIN_PERNET 128 #define UDP_HTABLE_SIZE_MIN (IS_ENABLED(CONFIG_BASE_SMALL) ? 128 : 256) #define UDP_HTABLE_SIZE_MAX 65536 diff --git a/include/trace/events/icmp.h b/include/trace/events/icmp.h index 31559796949a..09ae115099df 100644 --- a/include/trace/events/icmp.h +++ b/include/trace/events/icmp.h @@ -44,7 +44,7 @@ TRACE_EVENT(icmp_send, } else { __entry->sport = ntohs(uh->source); __entry->dport = ntohs(uh->dest); - __entry->ulen = ntohs(uh->len); + __entry->ulen = udp_get_len_short(uh); } p32 = (__be32 *) __entry->saddr; diff --git a/lib/tests/blackhole_dev_kunit.c b/lib/tests/blackhole_dev_kunit.c index 06834ab35f43..fa3e0533038d 100644 --- a/lib/tests/blackhole_dev_kunit.c +++ b/lib/tests/blackhole_dev_kunit.c @@ -46,7 +46,7 @@ static void test_blackholedev(struct kunit *test) uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr)); skb_set_transport_header(skb, 0); uh->source = uh->dest = htons(UDP_PORT); - uh->len = htons(data_len); + udp_set_len_short(uh, data_len); uh->check = 0; /* (Network) IPv6 */ ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr)); diff --git a/net/6lowpan/nhc_udp.c b/net/6lowpan/nhc_udp.c index 0a506c77283d..ed4227e6db74 100644 --- a/net/6lowpan/nhc_udp.c +++ b/net/6lowpan/nhc_udp.c @@ -88,16 +88,16 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed) switch (lowpan_dev(skb->dev)->lltype) { case LOWPAN_LLTYPE_IEEE802154: if (lowpan_802154_cb(skb)->d_size) - uh.len = htons(lowpan_802154_cb(skb)->d_size - - sizeof(struct ipv6hdr)); + udp_set_len_short(&uh, lowpan_802154_cb(skb)->d_size - + sizeof(struct ipv6hdr)); else - uh.len = htons(skb->len + sizeof(struct udphdr)); + udp_set_len_short(&uh, skb->len + sizeof(struct udphdr)); break; default: - uh.len = htons(skb->len + sizeof(struct udphdr)); + udp_set_len_short(&uh, skb->len + sizeof(struct udphdr)); break; } - pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len)); + pr_debug("uncompressed UDP length: src = %d", udp_get_len_short(&uh)); /* replace the compressed UDP head by the uncompressed UDP * header diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8e185b318288..5b4dd04d6124 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3005,7 +3005,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, udph->source = htons(pkt_dev->cur_udp_src); udph->dest = htons(pkt_dev->cur_udp_dst); - udph->len = htons(datalen + 8); /* DATA + udphdr */ + udp_set_len_short(udph, datalen + 8); /* DATA + udphdr */ udph->check = 0; iph->ihl = 5; @@ -3138,7 +3138,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, udplen = datalen + sizeof(struct udphdr); udph->source = htons(pkt_dev->cur_udp_src); udph->dest = htons(pkt_dev->cur_udp_dst); - udph->len = htons(udplen); + udp_set_len_short(udph, udplen); udph->check = 0; *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ diff --git a/net/core/selftests.c b/net/core/selftests.c index 0a203d3fb9dc..36b949ae520b 100644 --- a/net/core/selftests.c +++ b/net/core/selftests.c @@ -72,9 +72,9 @@ struct sk_buff *net_test_get_skb(struct net_device *ndev, u8 id, } else { uhdr->source = htons(attr->sport); uhdr->dest = htons(attr->dport); - uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size); + udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size); if (attr->max_size) - uhdr->len = htons(attr->max_size - + udp_set_len_short(uhdr, attr->max_size - (sizeof(*ihdr) + sizeof(*ehdr))); uhdr->check = 0; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d798fbdc3da7..d7d53a7c58f6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4775,6 +4775,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, struct sk_buff *tail = NULL; struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list; unsigned int mss = skb_shinfo(head_skb)->gso_size; + bool gso_by_frags = mss == GSO_BY_FRAGS; unsigned int doffset = head_skb->data - skb_mac_header(head_skb); unsigned int offset = doffset; unsigned int tnl_hlen = skb_tnl_header_len(head_skb); @@ -4790,7 +4791,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, int nfrags, pos; if ((skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY) && - mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) { + !gso_by_frags && mss != skb_headlen(head_skb)) { struct sk_buff *check_skb; for (check_skb = list_skb; check_skb; check_skb = check_skb->next) { @@ -4818,7 +4819,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, sg = !!(features & NETIF_F_SG); csum = !!can_checksum_protocol(features, proto); - if (sg && csum && (mss != GSO_BY_FRAGS)) { + if (sg && csum && !gso_by_frags) { if (!(features & NETIF_F_GSO_PARTIAL)) { struct sk_buff *iter; unsigned int frag_len; @@ -4852,9 +4853,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, /* GSO partial only requires that we trim off any excess that * doesn't fit into an MSS sized block, so take care of that * now. - * Cap len to not accidentally hit GSO_BY_FRAGS. */ - partial_segs = min(len, GSO_BY_FRAGS - 1) / mss; + partial_segs = len / mss; if (partial_segs > 1) mss *= partial_segs; else @@ -4878,7 +4878,7 @@ normal: int hsize; int size; - if (unlikely(mss == GSO_BY_FRAGS)) { + if (unlikely(gso_by_frags)) { len = list_skb->len; } else { len = head_skb->len - offset; diff --git a/net/core/tso.c b/net/core/tso.c index 347b3856ddb9..d2934bcfa795 100644 --- a/net/core/tso.c +++ b/net/core/tso.c @@ -39,7 +39,8 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso, } else { struct udphdr *uh = (struct udphdr *)hdr; - uh->len = htons(sizeof(*uh) + size); + /* size is after segmentation. */ + udp_set_len_short(uh, sizeof(*uh) + size); } } EXPORT_SYMBOL(tso_build_hdr); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index dfc81ee969ae..a6c18aea7498 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -323,7 +323,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb, uh = (struct udphdr *)esp->esph; uh->source = sport; uh->dest = dport; - uh->len = htons(len); + udp_set_len_short(uh, len); uh->check = 0; /* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c index 865bd7205122..aef3ce1dec7a 100644 --- a/net/ipv4/fou_core.c +++ b/net/ipv4/fou_core.c @@ -1040,7 +1040,7 @@ static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, uh->dest = e->dport; uh->source = sport; - uh->len = htons(skb->len); + udp_set_len(uh, skb->len); udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb, fl4->saddr, fl4->daddr, skb->len); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index a35ffedacc7c..155db067eaec 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -847,7 +847,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d /* Construct UDP header */ b->udph.source = htons(68); b->udph.dest = htons(67); - b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr)); + udp_set_len_short(&b->udph, sizeof(struct bootp_pkt) - sizeof(struct iphdr)); /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */ /* Construct DHCP/BOOTP header */ @@ -1025,10 +1025,10 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str if (b->udph.source != htons(67) || b->udph.dest != htons(68)) goto drop; - if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr)) + if (ntohs(h->tot_len) < udp_get_len_short(&b->udph) + sizeof(struct iphdr)) goto drop; - len = ntohs(b->udph.len) - sizeof(struct udphdr); + len = udp_get_len_short(&b->udph) - sizeof(struct udphdr); ext_len = len - (sizeof(*b) - sizeof(struct iphdr) - sizeof(struct udphdr) - diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c index e540b86bd15b..4492bc548a66 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c @@ -127,7 +127,7 @@ static int snmp_translate(struct nf_conn *ct, int dir, struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); - u16 datalen = ntohs(udph->len) - sizeof(struct udphdr); + u16 datalen = udp_get_len_short(udph) - sizeof(struct udphdr); char *data = (unsigned char *)udph + sizeof(struct udphdr); struct snmp_ctx ctx; int ret; @@ -181,7 +181,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, * enough room for a UDP header. Just verify the UDP length field so we * can mess around with the payload. */ - if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) { + if (udp_get_len_short(udph) != skb->len - (iph->ihl << 2)) { nf_ct_helper_log(skb, ct, "dropping malformed packet\n"); return NF_DROP; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4fed07cae7da..ca4c3faa0b64 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3192,7 +3192,7 @@ static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst, udph = skb_put_zero(skb, sizeof(struct udphdr)); udph->source = sport; udph->dest = dport; - udph->len = htons(sizeof(struct udphdr)); + udp_set_len_short(udph, sizeof(struct udphdr)); udph->check = 0; break; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d3ddcbfc8477..af9603217444 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1108,7 +1108,8 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, uh = udp_hdr(skb); uh->source = inet_sk(sk)->inet_sport; uh->dest = fl4->fl4_dport; - uh->len = htons(len); + /* Datagram length checked in udp_sendmsg. */ + udp_set_len_short(uh, len); uh->check = 0; if (cork->gso_size) { @@ -2593,8 +2594,8 @@ int udp_rcv(struct sk_buff *skb) struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(skb->dev); struct sock *sk = NULL; - unsigned short ulen; __be32 saddr, daddr; + unsigned int ulen; struct udphdr *uh; bool refcounted; int drop_reason; @@ -2608,7 +2609,7 @@ int udp_rcv(struct sk_buff *skb) goto drop; /* No space for header. */ uh = udp_hdr(skb); - ulen = ntohs(uh->len); + ulen = udp_get_len(skb, uh, 0); saddr = ip_hdr(skb)->saddr; daddr = ip_hdr(skb)->daddr; diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 29651b1a0bc7..8f77c8788f6d 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -279,11 +279,11 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, * segment instead of the entire frame. */ if (gso_partial && skb_is_gso(skb)) { - uh->len = htons(skb_shinfo(skb)->gso_size + - SKB_GSO_CB(skb)->data_offset + - skb->head - (unsigned char *)uh); + udp_set_len_short(uh, skb_shinfo(skb)->gso_size + + SKB_GSO_CB(skb)->data_offset + + skb->head - (unsigned char *)uh); } else { - uh->len = htons(len); + udp_set_len_short(uh, len); } if (!need_csum) @@ -468,7 +468,7 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb, if (IS_ERR(skb)) return skb; - udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss); + udp_set_len_short(udp_hdr(skb), sizeof(struct udphdr) + mss); if (is_ipv6) return __udpv6_gso_segment_list_csum(skb); @@ -486,8 +486,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, unsigned int mss; bool copy_dtor; __sum16 check; - __be16 newlen; int ret = 0; + u16 newlen; mss = skb_shinfo(gso_skb)->gso_size; if (gso_skb->len <= sizeof(*uh) + mss) @@ -564,8 +564,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, (skb_shinfo(gso_skb)->tx_flags & SKBTX_ANY_TSTAMP); /* compute checksum adjustment based on old length versus new */ - newlen = htons(sizeof(*uh) + mss); - check = csum16_add(csum16_sub(uh->check, uh->len), newlen); + newlen = sizeof(*uh) + mss; + check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen)); for (;;) { if (copy_dtor) { @@ -577,7 +577,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, if (!seg->next) break; - uh->len = newlen; + udp_set_len_short(uh, newlen); uh->check = check; if (seg->ip_summed == CHECKSUM_PARTIAL) @@ -594,11 +594,10 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, * segment may not be full MSS, account for that in the checksum */ if (!skb_is_gso(seg)) - newlen = htons(skb_tail_pointer(seg) - - skb_transport_header(seg) + seg->data_len); - check = csum16_add(csum16_sub(uh->check, uh->len), newlen); + newlen = skb_tail_pointer(seg) - skb_transport_header(seg) + seg->data_len; + check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen)); - uh->len = newlen; + udp_set_len_short(uh, newlen); uh->check = check; if (seg->ip_summed == CHECKSUM_PARTIAL) @@ -708,12 +707,8 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head, return NULL; } - /* Do not deal with padded or malicious packets, sorry ! */ - ulen = ntohs(uh->len); - if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb)) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } + ulen = udp_get_len_short(uh); + /* pull encapsulating udp header */ skb_gro_pull(skb, sizeof(struct udphdr)); @@ -742,7 +737,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head, * On len mismatch merge the first packet shorter than gso_size, * otherwise complete the GRO packet. */ - if (ulen > ntohs(uh2->len) || flush) { + if (ulen > udp_get_len_short(uh2) || flush) { pp = p; } else { if (NAPI_GRO_CB(skb)->is_flist) { @@ -765,7 +760,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head, } } - if (ret || ulen != ntohs(uh2->len) || + if (ret || ulen != udp_get_len_short(uh2) || NAPI_GRO_CB(p)->count >= UDP_GRO_CNT_MAX) pp = p; @@ -783,8 +778,14 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb, struct sk_buff *p; struct udphdr *uh2; unsigned int off = skb_gro_offset(skb); + unsigned int ulen; int flush = 1; + /* Do not deal with padded or malicious packets, sorry! */ + ulen = udp_get_len_short(uh); + if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb)) + goto out; + /* We can do L4 aggregation only if the packet can't land in a tunnel * otherwise we could corrupt the inner stream. Detecting such packets * cannot be foolproof and the aggregation might still happen in some @@ -915,12 +916,12 @@ static int udp_gro_complete_segment(struct sk_buff *skb) int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup) { - __be16 newlen = htons(skb->len - nhoff); struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); + unsigned int newlen = skb->len - nhoff; struct sock *sk; int err; - uh->len = newlen; + udp_set_len(uh, newlen); sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb, udp4_lib_lookup_skb, skb, uh->source, uh->dest); @@ -957,7 +958,7 @@ INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff) /* do fraglist only if there is no outer UDP encap (or we already processed it) */ if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) { - uh->len = htons(skb->len - nhoff); + udp_set_len(uh, skb->len - nhoff); skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4); skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count; diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index 9ab3728f9630..a128fe85620d 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb uh->dest = dst_port; uh->source = src_port; - uh->len = htons(skb->len); + udp_set_len(uh, skb->len); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 296b57926abb..72ec0d7d1120 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -230,7 +230,8 @@ static void esp_output_encap_csum(struct sk_buff *skb) if (*skb_mac_header(skb) == IPPROTO_UDP) { struct udphdr *uh = udp_hdr(skb); struct ipv6hdr *ip6h = ipv6_hdr(skb); - int len = ntohs(uh->len); + /* esp6_output_udp_encap limits len to U16_MAX. */ + int len = udp_get_len_short(uh); unsigned int offset = skb_transport_offset(skb); __wsum csum = skb_checksum(skb, offset, skb->len - offset, 0); @@ -358,7 +359,7 @@ static struct ip_esp_hdr *esp6_output_udp_encap(struct sk_buff *skb, uh = (struct udphdr *)esp->esph; uh->source = sport; uh->dest = dport; - uh->len = htons(len); + udp_set_len_short(uh, len); uh->check = 0; *skb_mac_header(skb) = IPPROTO_UDP; diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index 157765259e2f..4b659ca60ba9 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c @@ -30,7 +30,7 @@ static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, uh->dest = e->dport; uh->source = sport; - uh->len = htons(skb->len); + udp_set_len(uh, skb->len); udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb, &fl6->saddr, &fl6->daddr, skb->len); diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index 9adb5775487f..32525a051a6f 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, uh->dest = dst_port; uh->source = src_port; - uh->len = htons(skb->len); + udp_set_len(uh, skb->len); skb_dst_set(skb, dst); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 0910cc171776..fd875908ac0c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1083,12 +1083,12 @@ INDIRECT_CALLABLE_SCOPE int udpv6_rcv(struct sk_buff *skb) daddr = &ipv6_hdr(skb)->daddr; uh = udp_hdr(skb); - ulen = ntohs(uh->len); + ulen = udp_get_len(skb, uh, 0); if (ulen > skb->len) goto short_packet; /* Check for jumbo payload */ - if (ulen == 0) + if (ulen == 0 && inet6_is_jumbogram(skb)) ulen = skb->len; if (ulen < sizeof(*uh)) @@ -1371,7 +1371,8 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, uh = udp_hdr(skb); uh->source = fl6->fl6_sport; uh->dest = fl6->fl6_dport; - uh->len = htons(len); + /* Datagram length checked in udpv6_sendmsg. */ + udp_set_len_short(uh, len); uh->check = 0; if (cork->gso_size) { diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 778afc7453ce..7370bcb80332 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -171,7 +171,7 @@ int udp6_gro_complete(struct sk_buff *skb, int nhoff) /* do fraglist only if there is no outer UDP encap (or we already processed it) */ if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) { - uh->len = htons(skb->len - nhoff); + udp_set_len(uh, skb->len - nhoff); skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4); skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index f940914959b1..4712cc41881a 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1296,7 +1296,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns ret = NET_XMIT_DROP; goto out_unlock; } - uh->len = htons(udp_len); + udp_set_len_short(uh, udp_len); /* Calculate UDP checksum if configured to do so */ #if IS_ENABLED(CONFIG_IPV6) diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 9fef4335da13..0ab161e7f8b2 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -1098,7 +1098,7 @@ ipvs_gue_encap(struct net *net, struct sk_buff *skb, dport = cp->dest->tun_port; udph->dest = dport; udph->source = sport; - udph->len = htons(skb->len); + udp_set_len(udph, skb->len); udph->check = 0; *next_protocol = IPPROTO_UDP; diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index cc9b7e5e1935..a7edfefd6fd1 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -41,11 +41,22 @@ static void udp_error_log(const struct sk_buff *skb, nf_l4proto_log_invalid(skb, state, IPPROTO_UDP, "%s", msg); } +static bool udp_validate_len(struct sk_buff *skb, + const struct udphdr *hdr, + unsigned int dataoff) +{ + unsigned int udplen = udp_get_len(skb, hdr, dataoff); + unsigned int skblen = skb->len - dataoff; + + if (udplen > skblen || udplen < sizeof(*hdr)) + return false; + return true; +} + static bool udp_error(struct sk_buff *skb, unsigned int dataoff, const struct nf_hook_state *state) { - unsigned int udplen = skb->len - dataoff; const struct udphdr *hdr; struct udphdr _hdr; @@ -57,7 +68,7 @@ static bool udp_error(struct sk_buff *skb, } /* Truncated/malformed packets */ - if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { + if (!udp_validate_len(skb, hdr, dataoff)) { udp_error_log(skb, state, "truncated/malformed packet"); return true; } diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c index e37b09b3203b..71dff0eb672c 100644 --- a/net/netfilter/nf_log_syslog.c +++ b/net/netfilter/nf_log_syslog.c @@ -301,7 +301,7 @@ nf_log_dump_udp_header(struct nf_log_buf *m, /* Max length: 20 "SPT=65535 DPT=65535 " */ nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", - ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); + ntohs(uh->source), ntohs(uh->dest), udp_get_len_short(uh)); out: return 0; diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c index bf591e6af005..3853f41db499 100644 --- a/net/netfilter/nf_nat_helper.c +++ b/net/netfilter/nf_nat_helper.c @@ -161,7 +161,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, /* update the length of the UDP packet */ datalen = skb->len - protoff; - udph->len = htons(datalen); + udp_set_len_short(udph, datalen); /* fix udp checksum if udp checksum was previously calculated */ if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL) diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c index 8b2f178e317c..c9c1a8826b7f 100644 --- a/net/psp/psp_main.c +++ b/net/psp/psp_main.c @@ -231,7 +231,7 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi, uh->source = udp_flow_src_port(net, skb, 0, 0, false); } uh->check = 0; - uh->len = htons(udp_len); + udp_set_len(uh, udp_len); psph->nexthdr = IPPROTO_TCP; psph->hdrlen = PSP_HDRLEN_NOOPT; diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 078d3a27130b..5fff52a8ca90 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -276,7 +276,7 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl, return 0; iph = ip_hdr(skb); - ul = ntohs(udph->len); + ul = udp_get_len_short(udph); if (udplite || udph->check) { @@ -334,7 +334,7 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl, return 0; ip6h = ipv6_hdr(skb); - ul = ntohs(udph->len); + ul = udp_get_len_short(udph); udph->check = 0; diff --git a/net/xfrm/xfrm_nat_keepalive.c b/net/xfrm/xfrm_nat_keepalive.c index eb1b6f67739e..0e21ab72f0fe 100644 --- a/net/xfrm/xfrm_nat_keepalive.c +++ b/net/xfrm/xfrm_nat_keepalive.c @@ -135,7 +135,7 @@ static void nat_keepalive_send(struct nat_keepalive *ka) uh = skb_push(skb, sizeof(*uh)); uh->source = ka->encap_sport; uh->dest = ka->encap_dport; - uh->len = htons(skb->len); + udp_set_len_short(uh, skb->len); uh->check = 0; skb->mark = ka->smark; diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 7e9ae937cffa..b43ddf192ecc 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -13,6 +13,7 @@ TEST_PROGS := \ arp_ndisc_untracked_subnets.sh \ bareudp.sh \ big_tcp.sh \ + big_tcp_tunnels.sh \ bind_bhash.sh \ bpf_offload.py \ bridge_stp_mode.sh \ diff --git a/tools/testing/selftests/net/big_tcp_tunnels.sh b/tools/testing/selftests/net/big_tcp_tunnels.sh new file mode 100755 index 000000000000..d6513ed8d4e8 --- /dev/null +++ b/tools/testing/selftests/net/big_tcp_tunnels.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Testing for IPv4 and IPv6 BIG TCP over VXLAN and GENEVE tunnels. + +SERVER_NS=$(mktemp -u server-XXXXXXXX) +SERVER_IP4="192.168.1.1" +SERVER_IP6="2001:db8::1:1" +SERVER_IP4_TUN="192.168.2.1" +SERVER_IP6_TUN="2001:db8::2:1" + +CLIENT_NS=$(mktemp -u client-XXXXXXXX) +CLIENT_IP4="192.168.1.2" +CLIENT_IP6="2001:db8::1:2" +CLIENT_IP4_TUN="192.168.2.2" +CLIENT_IP6_TUN="2001:db8::2:2" + +: "${PACKETS_THRESHOLD:=1000}" + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +setup() { + ip netns add "$SERVER_NS" + ip netns add "$CLIENT_NS" + ip -netns "$SERVER_NS" link add link1 type veth peer name link0 netns "$CLIENT_NS" + + ip -netns "$CLIENT_NS" link set link0 up + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4/24" dev link0 + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6/112" dev link0 nodad + ip -netns "$CLIENT_NS" link set link0 \ + gso_max_size 196608 gso_ipv4_max_size 196608 \ + gro_max_size 196608 gro_ipv4_max_size 196608 + ip -netns "$SERVER_NS" link set link1 up + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4/24" dev link1 + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6/112" dev link1 nodad + ip -netns "$SERVER_NS" link set link1 \ + gso_max_size 196608 gso_ipv4_max_size 196608 \ + gro_max_size 196608 gro_ipv4_max_size 196608 + + ip netns exec "$SERVER_NS" netserver >/dev/null +} + +setup_tunnel() { + if [ "$2" = 4 ]; then + SERVER_IP="$SERVER_IP4" + CLIENT_IP="$CLIENT_IP4" + echo "Setting up ${1^^} over IPv4, veth tx csum offload $3" + else + SERVER_IP="$SERVER_IP6" + CLIENT_IP="$CLIENT_IP6" + echo "Setting up ${1^^} over IPv6, veth tx csum offload $3" + fi + + if [ "$1" = vxlan ]; then + ip -netns "$CLIENT_NS" link add tun0 type vxlan \ + id 5001 remote "$SERVER_IP" local "$CLIENT_IP" dev link0 dstport 4789 + else + ip -netns "$CLIENT_NS" link add tun0 type geneve \ + id 5001 remote "$SERVER_IP" + fi + ip -netns "$CLIENT_NS" link set tun0 up + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4_TUN/24" dev tun0 + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6_TUN/112" dev tun0 nodad + ip -netns "$CLIENT_NS" link set tun0 \ + gso_max_size 196608 gso_ipv4_max_size 196608 \ + gro_max_size 196608 gro_ipv4_max_size 196608 + if [ "$1" = vxlan ]; then + ip -netns "$SERVER_NS" link add tun1 type vxlan \ + id 5001 remote "$CLIENT_IP" local "$SERVER_IP" dev link1 dstport 4789 + else + ip -netns "$SERVER_NS" link add tun1 type geneve \ + id 5001 remote "$CLIENT_IP" + fi + ip -netns "$SERVER_NS" link set tun1 up + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4_TUN/24" dev tun1 + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6_TUN/112" dev tun1 nodad + ip -netns "$SERVER_NS" link set tun1 \ + gso_max_size 196608 gso_ipv4_max_size 196608 \ + gro_max_size 196608 gro_ipv4_max_size 196608 + + ip netns exec "$CLIENT_NS" ethtool -K link0 tx-checksumming "$3" > /dev/null + ip netns exec "$SERVER_NS" ethtool -K link1 tx-checksumming "$3" > /dev/null +} + +cleanup_tunnel() { + ip -netns "$CLIENT_NS" link del tun0 + ip -netns "$SERVER_NS" link del tun1 +} + +cleanup() { + ip netns pids "$SERVER_NS" | xargs -r kill + ip netns pids "$CLIENT_NS" | xargs -r kill + ip netns del "$SERVER_NS" + ip netns del "$CLIENT_NS" + rm -rf "$WORKDIR" +} + +do_test() { + # When tx csum offload is off, software GSO is performed before passing the + # packet to veth. Check BIG TCP packets inside the VXLAN tunnel to verify + # the software checksum path: if the checksum code is broken, these packets + # will be dropped. + if [ "$3" = on ]; then + CAPTURE_IFACE='link' + if [ "$1" = 4 ]; then + IPTABLES=iptables + else + IPTABLES=ip6tables + fi + else + CAPTURE_IFACE='tun' + if [ "$2" = 4 ]; then + IPTABLES=iptables + else + IPTABLES=ip6tables + fi + fi + if [ "$2" = 4 ]; then + IPTABLES_SACK=iptables + else + IPTABLES_SACK=ip6tables + fi + + ip netns exec "$SERVER_NS" "$IPTABLES" -w -t raw -I PREROUTING -i "${CAPTURE_IFACE}1" -m length ! --length 0:65535 -m comment --comment "bigtcp" + ip netns exec "$CLIENT_NS" "$IPTABLES" -w -t raw -I OUTPUT -o "${CAPTURE_IFACE}0" -m length ! --length 0:65535 -m comment --comment "bigtcp" + ip netns exec "$SERVER_NS" "$IPTABLES_SACK" -w -t raw -I OUTPUT -o "tun1" -p tcp -m tcp --tcp-flags ACK ACK --tcp-option 5 -m comment --comment "sack" + + if [ "$2" = 4 ]; then + SERVER_IP="$SERVER_IP4_TUN" + echo "Running IPv4 traffic in the tunnel" + else + SERVER_IP="$SERVER_IP6_TUN" + echo "Running IPv6 traffic in the tunnel" + fi + + ip netns exec "$CLIENT_NS" netperf -t TCP_STREAM -l 5 -H "$SERVER_IP" -- \ + -m 80000 > /dev/null + + PACKETS_SERVER=$(ip netns exec "$SERVER_NS" "$IPTABLES-save" -c -t raw | sed -rn '/ --comment bigtcp/{s/^\[([0-9]+):.*/\1/p;q}') + PACKETS_CLIENT=$(ip netns exec "$CLIENT_NS" "$IPTABLES-save" -c -t raw | sed -rn '/ --comment bigtcp/{s/^\[([0-9]+):.*/\1/p;q}') + PACKETS_SACK=$(ip netns exec "$SERVER_NS" "$IPTABLES_SACK-save" -c -t raw | sed -rn '/ --comment sack/{s/^\[([0-9]+):.*/\1/p;q}') + ip netns exec "$SERVER_NS" "$IPTABLES" -w -t raw -D PREROUTING -i "${CAPTURE_IFACE}1" -m length ! --length 0:65535 -m comment --comment "bigtcp" + ip netns exec "$CLIENT_NS" "$IPTABLES" -w -t raw -D OUTPUT -o "${CAPTURE_IFACE}0" -m length ! --length 0:65535 -m comment --comment "bigtcp" + ip netns exec "$SERVER_NS" "$IPTABLES_SACK" -w -t raw -D OUTPUT -o "tun1" -p tcp -m tcp --tcp-flags ACK ACK --tcp-option 5 -m comment --comment "sack" + + echo "Captured BIG TCP RX packets: $PACKETS_SERVER" + echo "Captured BIG TCP TX packets: $PACKETS_CLIENT" + echo "Captured TCP SACK packets: $PACKETS_SACK" + [ "$PACKETS_SERVER" -gt "$PACKETS_THRESHOLD" ] || return 1 + [ "$PACKETS_CLIENT" -gt "$PACKETS_THRESHOLD" ] || return 1 + [ "$PACKETS_SACK" -lt "$(( PACKETS_CLIENT / 2 ))" ] || return 1 +} + +if ! netperf -V &> /dev/null; then + echo "SKIP: Could not run test without netperf tool" + exit "$ksft_skip" +fi + +if ! iptables --version &> /dev/null; then + echo "SKIP: Could not run test without iptables tool" + exit "$ksft_skip" +fi + +if ! ethtool --version &> /dev/null; then + echo "SKIP: Could not run test without ethtool tool" + exit "$ksft_skip" +fi + +if ! ip link help 2>&1 | grep gso_ipv4_max_size &> /dev/null; then + echo "SKIP: Could not run test without gso/gro_ipv4_max_size supported in ip-link" + exit "$ksft_skip" +fi + +WORKDIR=$(mktemp -d) +trap cleanup EXIT +setup +for tunnel in vxlan geneve; do + for tun_family in 4 6; do + for traffic_family in 4 6; do + for csum_offload in on off; do + setup_tunnel "$tunnel" "$tun_family" "$csum_offload" || exit "$?" + do_test "$tun_family" "$traffic_family" "$csum_offload" || exit "$?" + cleanup_tunnel + done + done + done +done |
