Skip to content

Commit 92552d3

Browse files
khalidm96Saeed Mahameed
authored andcommitted
net/mlx5e: HW_GRO cqe handler implementation
this patch updates the SHAMPO CQE handler to support HW_GRO, changes in the SHAMPO CQE handler: - CQE match and flush fields are used to determine if to build new skb using the new received packet, or to add the received packet data to the existing RQ.hw_gro_skb, also this fields are used to determine when to flush the skb. - in the end of the function mlx5e_poll_rx_cq the RQ.hw_gro_skb is flushed. Signed-off-by: Khalid Manaa <khalidm@nvidia.com> Signed-off-by: Ben Ben-Ishay <benishay@nvidia.com> Reviewed-by: Tariq Toukan <tariqt@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
1 parent 64509b0 commit 92552d3

File tree

3 files changed

+242
-11
lines changed

3 files changed

+242
-11
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,12 @@ struct mlx5e_shampo_hd {
655655
u64 last_addr;
656656
};
657657

658+
struct mlx5e_hw_gro_data {
659+
struct sk_buff *skb;
660+
struct flow_keys fk;
661+
int second_ip_id;
662+
};
663+
658664
struct mlx5e_rq {
659665
/* data path */
660666
union {
@@ -696,6 +702,8 @@ struct mlx5e_rq {
696702
struct mlx5e_icosq *icosq;
697703
struct mlx5e_priv *priv;
698704

705+
struct mlx5e_hw_gro_data *hw_gro_data;
706+
699707
mlx5e_fp_handle_rx_cqe handle_rx_cqe;
700708
mlx5e_fp_post_rx_wqes post_wqes;
701709
mlx5e_fp_dealloc_wqe dealloc_wqe;

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
513513
err = mlx5e_rq_shampo_hd_info_alloc(rq, node);
514514
if (err)
515515
goto err_shampo_info;
516+
rq->hw_gro_data = kvzalloc_node(sizeof(*rq->hw_gro_data), GFP_KERNEL, node);
517+
if (!rq->hw_gro_data) {
518+
err = -ENOMEM;
519+
goto err_hw_gro_data;
520+
}
516521
rq->mpwqe.shampo->key =
517522
cpu_to_be32(rq->mpwqe.shampo->mkey.key);
518523
rq->mpwqe.shampo->hd_per_wqe =
@@ -522,6 +527,8 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
522527
MLX5E_SHAMPO_WQ_HEADER_PER_PAGE;
523528
return 0;
524529

530+
err_hw_gro_data:
531+
mlx5e_rq_shampo_hd_info_free(rq);
525532
err_shampo_info:
526533
mlx5_core_destroy_mkey(mdev, &rq->mpwqe.shampo->mkey);
527534
err_shampo_hd:
@@ -534,6 +541,8 @@ static void mlx5e_rq_free_shampo(struct mlx5e_rq *rq)
534541
{
535542
if (!test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state))
536543
return;
544+
545+
kvfree(rq->hw_gro_data);
537546
mlx5e_rq_shampo_hd_info_free(rq);
538547
mlx5_core_destroy_mkey(rq->mdev, &rq->mpwqe.shampo->mkey);
539548
mlx5e_rq_shampo_hd_free(rq);

drivers/net/ethernet/mellanox/mlx5/core/en_rx.c

Lines changed: 225 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
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+
10691207
static 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+
13181475
static 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
17301887
mlx5e_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

17781969
static 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);
18342045
free_hd_entry:
18352046
mlx5e_free_rx_shampo_hd_entry(rq, header_index);
18362047
mpwrq_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

19432154
out:
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

Comments
 (0)