Skip to content

Commit 907209e

Browse files
akihikodakijasowang
authored andcommitted
igb: Implement Rx SCTP CSO
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech> Signed-off-by: Jason Wang <jasowang@redhat.com>
1 parent abc9a29 commit 907209e

File tree

8 files changed

+89
-13
lines changed

8 files changed

+89
-13
lines changed

hw/net/e1000e_core.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,11 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
11141114
return;
11151115
}
11161116

1117+
if (l4hdr_proto != ETH_L4_HDR_PROTO_TCP &&
1118+
l4hdr_proto != ETH_L4_HDR_PROTO_UDP) {
1119+
return;
1120+
}
1121+
11171122
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
11181123
trace_e1000e_rx_metadata_l4_csum_validation_failed();
11191124
return;

hw/net/igb_core.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,7 +1220,7 @@ igb_build_rx_metadata(IGBCore *core,
12201220
uint16_t *vlan_tag)
12211221
{
12221222
struct virtio_net_hdr *vhdr;
1223-
bool hasip4, hasip6;
1223+
bool hasip4, hasip6, csum_valid;
12241224
EthL4HdrProto l4hdr_proto;
12251225

12261226
*status_flags = E1000_RXD_STAT_DD;
@@ -1280,6 +1280,10 @@ igb_build_rx_metadata(IGBCore *core,
12801280
*pkt_info |= E1000_ADVRXD_PKT_UDP;
12811281
break;
12821282

1283+
case ETH_L4_HDR_PROTO_SCTP:
1284+
*pkt_info |= E1000_ADVRXD_PKT_SCTP;
1285+
break;
1286+
12831287
default:
12841288
break;
12851289
}
@@ -1312,6 +1316,15 @@ igb_build_rx_metadata(IGBCore *core,
13121316

13131317
if (igb_rx_l4_cso_enabled(core)) {
13141318
switch (l4hdr_proto) {
1319+
case ETH_L4_HDR_PROTO_SCTP:
1320+
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
1321+
trace_e1000e_rx_metadata_l4_csum_validation_failed();
1322+
goto func_exit;
1323+
}
1324+
if (!csum_valid) {
1325+
*status_flags |= E1000_RXDEXT_STATERR_TCPE;
1326+
}
1327+
/* fall through */
13151328
case ETH_L4_HDR_PROTO_TCP:
13161329
*status_flags |= E1000_RXD_STAT_TCPCS;
13171330
break;

hw/net/igb_regs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ union e1000_adv_rx_desc {
670670
#define E1000_ADVRXD_PKT_IP6 BIT(6)
671671
#define E1000_ADVRXD_PKT_TCP BIT(8)
672672
#define E1000_ADVRXD_PKT_UDP BIT(9)
673+
#define E1000_ADVRXD_PKT_SCTP BIT(10)
673674

674675
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
675676
{

hw/net/net_rx_pkt.c

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
#include "qemu/osdep.h"
19+
#include "qemu/crc32c.h"
1920
#include "trace.h"
2021
#include "net_rx_pkt.h"
2122
#include "net/checksum.h"
@@ -554,32 +555,73 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
554555
return csum;
555556
}
556557

557-
bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
558+
static bool
559+
_net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt)
558560
{
559-
uint16_t csum;
561+
size_t csum_off;
562+
size_t off = pkt->l4hdr_off;
563+
size_t vec_len = pkt->vec_len;
564+
struct iovec *vec;
565+
uint32_t calculated = 0;
566+
uint32_t original;
567+
bool valid;
560568

561-
trace_net_rx_pkt_l4_csum_validate_entry();
569+
for (vec = pkt->vec; vec->iov_len < off; vec++) {
570+
off -= vec->iov_len;
571+
vec_len--;
572+
}
562573

563-
if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
564-
pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
565-
trace_net_rx_pkt_l4_csum_validate_not_xxp();
574+
csum_off = off + 8;
575+
576+
if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) {
566577
return false;
567578
}
568579

569-
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
570-
pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
571-
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
580+
if (!iov_from_buf(vec, vec_len, csum_off,
581+
&calculated, sizeof(calculated))) {
572582
return false;
573583
}
574584

585+
calculated = crc32c(0xffffffff,
586+
(uint8_t *)vec->iov_base + off, vec->iov_len - off);
587+
calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1);
588+
valid = calculated == le32_to_cpu(original);
589+
iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original));
590+
591+
return valid;
592+
}
593+
594+
bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
595+
{
596+
uint32_t csum;
597+
598+
trace_net_rx_pkt_l4_csum_validate_entry();
599+
575600
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
576601
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
577602
return false;
578603
}
579604

580-
csum = _net_rx_pkt_calc_l4_csum(pkt);
605+
switch (pkt->l4hdr_info.proto) {
606+
case ETH_L4_HDR_PROTO_UDP:
607+
if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
608+
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
609+
return false;
610+
}
611+
/* fall through */
612+
case ETH_L4_HDR_PROTO_TCP:
613+
csum = _net_rx_pkt_calc_l4_csum(pkt);
614+
*csum_valid = ((csum == 0) || (csum == 0xFFFF));
615+
break;
616+
617+
case ETH_L4_HDR_PROTO_SCTP:
618+
*csum_valid = _net_rx_pkt_validate_sctp_sum(pkt);
619+
break;
581620

582-
*csum_valid = ((csum == 0) || (csum == 0xFFFF));
621+
default:
622+
trace_net_rx_pkt_l4_csum_validate_not_xxp();
623+
return false;
624+
}
583625

584626
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
585627

include/net/eth.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ struct tcp_hdr {
224224
#define IP_HEADER_VERSION_6 (6)
225225
#define IP_PROTO_TCP (6)
226226
#define IP_PROTO_UDP (17)
227+
#define IP_PROTO_SCTP (132)
227228
#define IPTOS_ECN_MASK 0x03
228229
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
229230
#define IPTOS_ECN_CE 0x03
@@ -379,7 +380,8 @@ typedef struct eth_ip4_hdr_info_st {
379380
typedef enum EthL4HdrProto {
380381
ETH_L4_HDR_PROTO_INVALID,
381382
ETH_L4_HDR_PROTO_TCP,
382-
ETH_L4_HDR_PROTO_UDP
383+
ETH_L4_HDR_PROTO_UDP,
384+
ETH_L4_HDR_PROTO_SCTP
383385
} EthL4HdrProto;
384386

385387
typedef struct eth_l4_hdr_info_st {

include/qemu/crc32c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@
3030

3131

3232
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
33+
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt);
3334

3435
#endif

net/eth.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
211211
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
212212
}
213213
break;
214+
215+
case IP_PROTO_SCTP:
216+
l4hdr_info->proto = ETH_L4_HDR_PROTO_SCTP;
217+
break;
214218
}
215219
}
216220

util/crc32c.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,11 @@ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
113113
return crc^0xffffffff;
114114
}
115115

116+
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt)
117+
{
118+
while (iov_cnt--) {
119+
crc = crc32c(crc, iov->iov_base, iov->iov_len) ^ 0xffffffff;
120+
iov++;
121+
}
122+
return crc ^ 0xffffffff;
123+
}

0 commit comments

Comments
 (0)