3737#include <net/ip6_checksum.h>
3838#include <net/page_pool.h>
3939#include <net/inet_ecn.h>
40+ #include <net/udp.h>
41+ #include <net/tcp.h>
4042#include "en.h"
4143#include "en/txrx.h"
4244#include "en_tc.h"
@@ -1066,6 +1068,142 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe,
10661068 }
10671069}
10681070
1071+ static void * mlx5e_shampo_get_packet_hd (struct mlx5e_rq * rq , u16 header_index )
1072+ {
1073+ struct mlx5e_dma_info * last_head = & rq -> mpwqe .shampo -> info [header_index ];
1074+ u16 head_offset = (last_head -> addr & (PAGE_SIZE - 1 )) + rq -> buff .headroom ;
1075+
1076+ return page_address (last_head -> page ) + head_offset ;
1077+ }
1078+
1079+ static void mlx5e_shampo_update_ipv4_udp_hdr (struct mlx5e_rq * rq , struct iphdr * ipv4 )
1080+ {
1081+ int udp_off = rq -> hw_gro_data -> fk .control .thoff ;
1082+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1083+ struct udphdr * uh ;
1084+
1085+ uh = (struct udphdr * )(skb -> data + udp_off );
1086+ uh -> len = htons (skb -> len - udp_off );
1087+
1088+ if (uh -> check )
1089+ uh -> check = ~udp_v4_check (skb -> len - udp_off , ipv4 -> saddr ,
1090+ ipv4 -> daddr , 0 );
1091+
1092+ skb -> csum_start = (unsigned char * )uh - skb -> head ;
1093+ skb -> csum_offset = offsetof(struct udphdr , check );
1094+
1095+ skb_shinfo (skb )-> gso_type |= SKB_GSO_UDP_L4 ;
1096+ }
1097+
1098+ static void mlx5e_shampo_update_ipv6_udp_hdr (struct mlx5e_rq * rq , struct ipv6hdr * ipv6 )
1099+ {
1100+ int udp_off = rq -> hw_gro_data -> fk .control .thoff ;
1101+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1102+ struct udphdr * uh ;
1103+
1104+ uh = (struct udphdr * )(skb -> data + udp_off );
1105+ uh -> len = htons (skb -> len - udp_off );
1106+
1107+ if (uh -> check )
1108+ uh -> check = ~udp_v6_check (skb -> len - udp_off , & ipv6 -> saddr ,
1109+ & ipv6 -> daddr , 0 );
1110+
1111+ skb -> csum_start = (unsigned char * )uh - skb -> head ;
1112+ skb -> csum_offset = offsetof(struct udphdr , check );
1113+
1114+ skb_shinfo (skb )-> gso_type |= SKB_GSO_UDP_L4 ;
1115+ }
1116+
1117+ static void mlx5e_shampo_update_fin_psh_flags (struct mlx5e_rq * rq , struct mlx5_cqe64 * cqe ,
1118+ struct tcphdr * skb_tcp_hd )
1119+ {
1120+ u16 header_index = be16_to_cpu (cqe -> shampo .header_entry_index );
1121+ struct tcphdr * last_tcp_hd ;
1122+ void * last_hd_addr ;
1123+
1124+ last_hd_addr = mlx5e_shampo_get_packet_hd (rq , header_index );
1125+ last_tcp_hd = last_hd_addr + ETH_HLEN + rq -> hw_gro_data -> fk .control .thoff ;
1126+ tcp_flag_word (skb_tcp_hd ) |= tcp_flag_word (last_tcp_hd ) & (TCP_FLAG_FIN | TCP_FLAG_PSH );
1127+ }
1128+
1129+ static void mlx5e_shampo_update_ipv4_tcp_hdr (struct mlx5e_rq * rq , struct iphdr * ipv4 ,
1130+ struct mlx5_cqe64 * cqe , bool match )
1131+ {
1132+ int tcp_off = rq -> hw_gro_data -> fk .control .thoff ;
1133+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1134+ struct tcphdr * tcp ;
1135+
1136+ tcp = (struct tcphdr * )(skb -> data + tcp_off );
1137+ if (match )
1138+ mlx5e_shampo_update_fin_psh_flags (rq , cqe , tcp );
1139+
1140+ tcp -> check = ~tcp_v4_check (skb -> len - tcp_off , ipv4 -> saddr ,
1141+ ipv4 -> daddr , 0 );
1142+ skb_shinfo (skb )-> gso_type |= SKB_GSO_TCPV4 ;
1143+ if (ntohs (ipv4 -> id ) == rq -> hw_gro_data -> second_ip_id )
1144+ skb_shinfo (skb )-> gso_type |= SKB_GSO_TCP_FIXEDID ;
1145+
1146+ skb -> csum_start = (unsigned char * )tcp - skb -> head ;
1147+ skb -> csum_offset = offsetof(struct tcphdr , check );
1148+
1149+ if (tcp -> cwr )
1150+ skb_shinfo (skb )-> gso_type |= SKB_GSO_TCP_ECN ;
1151+ }
1152+
1153+ static void mlx5e_shampo_update_ipv6_tcp_hdr (struct mlx5e_rq * rq , struct ipv6hdr * ipv6 ,
1154+ struct mlx5_cqe64 * cqe , bool match )
1155+ {
1156+ int tcp_off = rq -> hw_gro_data -> fk .control .thoff ;
1157+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1158+ struct tcphdr * tcp ;
1159+
1160+ tcp = (struct tcphdr * )(skb -> data + tcp_off );
1161+ if (match )
1162+ mlx5e_shampo_update_fin_psh_flags (rq , cqe , tcp );
1163+
1164+ tcp -> check = ~tcp_v6_check (skb -> len - tcp_off , & ipv6 -> saddr ,
1165+ & ipv6 -> daddr , 0 );
1166+ skb_shinfo (skb )-> gso_type |= SKB_GSO_TCPV6 ;
1167+ skb -> csum_start = (unsigned char * )tcp - skb -> head ;
1168+ skb -> csum_offset = offsetof(struct tcphdr , check );
1169+
1170+ if (tcp -> cwr )
1171+ skb_shinfo (skb )-> gso_type |= SKB_GSO_TCP_ECN ;
1172+ }
1173+
1174+ static void mlx5e_shampo_update_hdr (struct mlx5e_rq * rq , struct mlx5_cqe64 * cqe , bool match )
1175+ {
1176+ bool is_ipv4 = (rq -> hw_gro_data -> fk .basic .n_proto == htons (ETH_P_IP ));
1177+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1178+
1179+ skb_shinfo (skb )-> gso_segs = NAPI_GRO_CB (skb )-> count ;
1180+ skb -> ip_summed = CHECKSUM_PARTIAL ;
1181+
1182+ if (is_ipv4 ) {
1183+ int nhoff = rq -> hw_gro_data -> fk .control .thoff - sizeof (struct iphdr );
1184+ struct iphdr * ipv4 = (struct iphdr * )(skb -> data + nhoff );
1185+ __be16 newlen = htons (skb -> len - nhoff );
1186+
1187+ csum_replace2 (& ipv4 -> check , ipv4 -> tot_len , newlen );
1188+ ipv4 -> tot_len = newlen ;
1189+
1190+ if (ipv4 -> protocol == IPPROTO_TCP )
1191+ mlx5e_shampo_update_ipv4_tcp_hdr (rq , ipv4 , cqe , match );
1192+ else
1193+ mlx5e_shampo_update_ipv4_udp_hdr (rq , ipv4 );
1194+ } else {
1195+ int nhoff = rq -> hw_gro_data -> fk .control .thoff - sizeof (struct ipv6hdr );
1196+ struct ipv6hdr * ipv6 = (struct ipv6hdr * )(skb -> data + nhoff );
1197+
1198+ ipv6 -> payload_len = htons (skb -> len - nhoff - sizeof (* ipv6 ));
1199+
1200+ if (ipv6 -> nexthdr == IPPROTO_TCP )
1201+ mlx5e_shampo_update_ipv6_tcp_hdr (rq , ipv6 , cqe , match );
1202+ else
1203+ mlx5e_shampo_update_ipv6_udp_hdr (rq , ipv6 );
1204+ }
1205+ }
1206+
10691207static inline void mlx5e_skb_set_hash (struct mlx5_cqe64 * cqe ,
10701208 struct sk_buff * skb )
10711209{
@@ -1315,6 +1453,25 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
13151453 stats -> mcast_packets ++ ;
13161454}
13171455
1456+ static void mlx5e_shampo_complete_rx_cqe (struct mlx5e_rq * rq ,
1457+ struct mlx5_cqe64 * cqe ,
1458+ u32 cqe_bcnt ,
1459+ struct sk_buff * skb )
1460+ {
1461+ struct mlx5e_rq_stats * stats = rq -> stats ;
1462+
1463+ stats -> packets ++ ;
1464+ stats -> bytes += cqe_bcnt ;
1465+ if (NAPI_GRO_CB (skb )-> count != 1 )
1466+ return ;
1467+ mlx5e_build_rx_skb (cqe , cqe_bcnt , rq , skb );
1468+ skb_reset_network_header (skb );
1469+ if (!skb_flow_dissect_flow_keys (skb , & rq -> hw_gro_data -> fk , 0 )) {
1470+ napi_gro_receive (rq -> cq .napi , skb );
1471+ rq -> hw_gro_data -> skb = NULL ;
1472+ }
1473+ }
1474+
13181475static inline void mlx5e_complete_rx_cqe (struct mlx5e_rq * rq ,
13191476 struct mlx5_cqe64 * cqe ,
13201477 u32 cqe_bcnt ,
@@ -1726,7 +1883,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
17261883 return skb ;
17271884}
17281885
1729- static struct sk_buff *
1886+ static void
17301887mlx5e_skb_from_cqe_shampo (struct mlx5e_rq * rq , struct mlx5e_mpw_info * wi ,
17311888 struct mlx5_cqe64 * cqe , u16 header_index )
17321889{
@@ -1750,7 +1907,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
17501907 skb = mlx5e_build_linear_skb (rq , hdr , frag_size , rx_headroom , head_size );
17511908
17521909 if (unlikely (!skb ))
1753- return NULL ;
1910+ return ;
17541911
17551912 /* queue up for recycling/reuse */
17561913 page_ref_inc (head -> page );
@@ -1761,7 +1918,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
17611918 ALIGN (head_size , sizeof (long )));
17621919 if (unlikely (!skb )) {
17631920 rq -> stats -> buff_alloc_err ++ ;
1764- return NULL ;
1921+ return ;
17651922 }
17661923
17671924 prefetchw (skb -> data );
@@ -1772,7 +1929,41 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
17721929 skb -> tail += head_size ;
17731930 skb -> len += head_size ;
17741931 }
1775- return skb ;
1932+ rq -> hw_gro_data -> skb = skb ;
1933+ NAPI_GRO_CB (skb )-> count = 1 ;
1934+ skb_shinfo (skb )-> gso_size = mpwrq_get_cqe_byte_cnt (cqe ) - head_size ;
1935+ }
1936+
1937+ static void
1938+ mlx5e_shampo_align_fragment (struct sk_buff * skb , u8 log_stride_sz )
1939+ {
1940+ skb_frag_t * last_frag = & skb_shinfo (skb )-> frags [skb_shinfo (skb )-> nr_frags - 1 ];
1941+ unsigned int frag_size = skb_frag_size (last_frag );
1942+ unsigned int frag_truesize ;
1943+
1944+ frag_truesize = ALIGN (frag_size , BIT (log_stride_sz ));
1945+ skb -> truesize += frag_truesize - frag_size ;
1946+ }
1947+
1948+ static void
1949+ mlx5e_shampo_flush_skb (struct mlx5e_rq * rq , struct mlx5_cqe64 * cqe , bool match )
1950+ {
1951+ struct sk_buff * skb = rq -> hw_gro_data -> skb ;
1952+
1953+ if (likely (skb_shinfo (skb )-> nr_frags ))
1954+ mlx5e_shampo_align_fragment (skb , rq -> mpwqe .log_stride_sz );
1955+ if (NAPI_GRO_CB (skb )-> count > 1 )
1956+ mlx5e_shampo_update_hdr (rq , cqe , match );
1957+ napi_gro_receive (rq -> cq .napi , skb );
1958+ rq -> hw_gro_data -> skb = NULL ;
1959+ }
1960+
1961+ static bool
1962+ mlx5e_hw_gro_skb_has_enough_space (struct sk_buff * skb , u16 data_bcnt )
1963+ {
1964+ int nr_frags = skb_shinfo (skb )-> nr_frags ;
1965+
1966+ return PAGE_SIZE * nr_frags + data_bcnt <= GSO_MAX_SIZE ;
17761967}
17771968
17781969static void
@@ -1798,8 +1989,10 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
17981989 u32 cqe_bcnt = mpwrq_get_cqe_byte_cnt (cqe );
17991990 u16 wqe_id = be16_to_cpu (cqe -> wqe_id );
18001991 u32 page_idx = wqe_offset >> PAGE_SHIFT ;
1992+ struct sk_buff * * skb = & rq -> hw_gro_data -> skb ;
1993+ bool flush = cqe -> shampo .flush ;
1994+ bool match = cqe -> shampo .match ;
18011995 struct mlx5e_rx_wqe_ll * wqe ;
1802- struct sk_buff * skb = NULL ;
18031996 struct mlx5e_dma_info * di ;
18041997 struct mlx5e_mpw_info * wi ;
18051998 struct mlx5_wq_ll * wq ;
@@ -1821,16 +2014,34 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
18212014 goto mpwrq_cqe_out ;
18222015 }
18232016
1824- skb = mlx5e_skb_from_cqe_shampo (rq , wi , cqe , header_index );
2017+ if (* skb && (!match || !(mlx5e_hw_gro_skb_has_enough_space (* skb , data_bcnt )))) {
2018+ match = false;
2019+ mlx5e_shampo_flush_skb (rq , cqe , match );
2020+ }
18252021
1826- if (unlikely (!skb ))
1827- goto free_hd_entry ;
2022+ if (!* skb ) {
2023+ mlx5e_skb_from_cqe_shampo (rq , wi , cqe , header_index );
2024+ if (unlikely (!* skb ))
2025+ goto free_hd_entry ;
2026+ } else {
2027+ NAPI_GRO_CB (* skb )-> count ++ ;
2028+ if (NAPI_GRO_CB (* skb )-> count == 2 &&
2029+ rq -> hw_gro_data -> fk .basic .n_proto == htons (ETH_P_IP )) {
2030+ void * hd_addr = mlx5e_shampo_get_packet_hd (rq , header_index );
2031+ int nhoff = ETH_HLEN + rq -> hw_gro_data -> fk .control .thoff -
2032+ sizeof (struct iphdr );
2033+ struct iphdr * iph = (struct iphdr * )(hd_addr + nhoff );
2034+
2035+ rq -> hw_gro_data -> second_ip_id = ntohs (iph -> id );
2036+ }
2037+ }
18282038
18292039 di = & wi -> umr .dma_info [page_idx ];
1830- mlx5e_fill_skb_data (skb , rq , di , data_bcnt , data_offset );
2040+ mlx5e_fill_skb_data (* skb , rq , di , data_bcnt , data_offset );
18312041
1832- mlx5e_complete_rx_cqe (rq , cqe , cqe_bcnt , skb );
1833- napi_gro_receive (rq -> cq .napi , skb );
2042+ mlx5e_shampo_complete_rx_cqe (rq , cqe , cqe_bcnt , * skb );
2043+ if (flush )
2044+ mlx5e_shampo_flush_skb (rq , cqe , match );
18342045free_hd_entry :
18352046 mlx5e_free_rx_shampo_hd_entry (rq , header_index );
18362047mpwrq_cqe_out :
@@ -1941,6 +2152,9 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
19412152 } while ((++ work_done < budget ) && (cqe = mlx5_cqwq_get_cqe (cqwq )));
19422153
19432154out :
2155+ if (test_bit (MLX5E_RQ_STATE_SHAMPO , & rq -> state ) && rq -> hw_gro_data -> skb )
2156+ mlx5e_shampo_flush_skb (rq , NULL , false);
2157+
19442158 if (rcu_access_pointer (rq -> xdp_prog ))
19452159 mlx5e_xdp_rx_poll_complete (rq );
19462160
0 commit comments