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>
This commit is contained in:
parent
abc9a29d6b
commit
907209e311
@ -1114,6 +1114,11 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (l4hdr_proto != ETH_L4_HDR_PROTO_TCP &&
|
||||||
|
l4hdr_proto != ETH_L4_HDR_PROTO_UDP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
|
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
|
||||||
trace_e1000e_rx_metadata_l4_csum_validation_failed();
|
trace_e1000e_rx_metadata_l4_csum_validation_failed();
|
||||||
return;
|
return;
|
||||||
|
@ -1220,7 +1220,7 @@ igb_build_rx_metadata(IGBCore *core,
|
|||||||
uint16_t *vlan_tag)
|
uint16_t *vlan_tag)
|
||||||
{
|
{
|
||||||
struct virtio_net_hdr *vhdr;
|
struct virtio_net_hdr *vhdr;
|
||||||
bool hasip4, hasip6;
|
bool hasip4, hasip6, csum_valid;
|
||||||
EthL4HdrProto l4hdr_proto;
|
EthL4HdrProto l4hdr_proto;
|
||||||
|
|
||||||
*status_flags = E1000_RXD_STAT_DD;
|
*status_flags = E1000_RXD_STAT_DD;
|
||||||
@ -1280,6 +1280,10 @@ igb_build_rx_metadata(IGBCore *core,
|
|||||||
*pkt_info |= E1000_ADVRXD_PKT_UDP;
|
*pkt_info |= E1000_ADVRXD_PKT_UDP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ETH_L4_HDR_PROTO_SCTP:
|
||||||
|
*pkt_info |= E1000_ADVRXD_PKT_SCTP;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1312,6 +1316,15 @@ igb_build_rx_metadata(IGBCore *core,
|
|||||||
|
|
||||||
if (igb_rx_l4_cso_enabled(core)) {
|
if (igb_rx_l4_cso_enabled(core)) {
|
||||||
switch (l4hdr_proto) {
|
switch (l4hdr_proto) {
|
||||||
|
case ETH_L4_HDR_PROTO_SCTP:
|
||||||
|
if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
|
||||||
|
trace_e1000e_rx_metadata_l4_csum_validation_failed();
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
if (!csum_valid) {
|
||||||
|
*status_flags |= E1000_RXDEXT_STATERR_TCPE;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
case ETH_L4_HDR_PROTO_TCP:
|
case ETH_L4_HDR_PROTO_TCP:
|
||||||
*status_flags |= E1000_RXD_STAT_TCPCS;
|
*status_flags |= E1000_RXD_STAT_TCPCS;
|
||||||
break;
|
break;
|
||||||
|
@ -670,6 +670,7 @@ union e1000_adv_rx_desc {
|
|||||||
#define E1000_ADVRXD_PKT_IP6 BIT(6)
|
#define E1000_ADVRXD_PKT_IP6 BIT(6)
|
||||||
#define E1000_ADVRXD_PKT_TCP BIT(8)
|
#define E1000_ADVRXD_PKT_TCP BIT(8)
|
||||||
#define E1000_ADVRXD_PKT_UDP BIT(9)
|
#define E1000_ADVRXD_PKT_UDP BIT(9)
|
||||||
|
#define E1000_ADVRXD_PKT_SCTP BIT(10)
|
||||||
|
|
||||||
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
|
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/crc32c.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "net_rx_pkt.h"
|
#include "net_rx_pkt.h"
|
||||||
#include "net/checksum.h"
|
#include "net/checksum.h"
|
||||||
@ -554,32 +555,73 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
|
|||||||
return csum;
|
return csum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt)
|
||||||
|
{
|
||||||
|
size_t csum_off;
|
||||||
|
size_t off = pkt->l4hdr_off;
|
||||||
|
size_t vec_len = pkt->vec_len;
|
||||||
|
struct iovec *vec;
|
||||||
|
uint32_t calculated = 0;
|
||||||
|
uint32_t original;
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
for (vec = pkt->vec; vec->iov_len < off; vec++) {
|
||||||
|
off -= vec->iov_len;
|
||||||
|
vec_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
csum_off = off + 8;
|
||||||
|
|
||||||
|
if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iov_from_buf(vec, vec_len, csum_off,
|
||||||
|
&calculated, sizeof(calculated))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculated = crc32c(0xffffffff,
|
||||||
|
(uint8_t *)vec->iov_base + off, vec->iov_len - off);
|
||||||
|
calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1);
|
||||||
|
valid = calculated == le32_to_cpu(original);
|
||||||
|
iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original));
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
|
bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
|
||||||
{
|
{
|
||||||
uint16_t csum;
|
uint32_t csum;
|
||||||
|
|
||||||
trace_net_rx_pkt_l4_csum_validate_entry();
|
trace_net_rx_pkt_l4_csum_validate_entry();
|
||||||
|
|
||||||
if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
|
|
||||||
pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
|
|
||||||
trace_net_rx_pkt_l4_csum_validate_not_xxp();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
|
|
||||||
pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
|
|
||||||
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
|
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
|
||||||
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
|
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
csum = _net_rx_pkt_calc_l4_csum(pkt);
|
switch (pkt->l4hdr_info.proto) {
|
||||||
|
case ETH_L4_HDR_PROTO_UDP:
|
||||||
|
if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
|
||||||
|
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case ETH_L4_HDR_PROTO_TCP:
|
||||||
|
csum = _net_rx_pkt_calc_l4_csum(pkt);
|
||||||
|
*csum_valid = ((csum == 0) || (csum == 0xFFFF));
|
||||||
|
break;
|
||||||
|
|
||||||
*csum_valid = ((csum == 0) || (csum == 0xFFFF));
|
case ETH_L4_HDR_PROTO_SCTP:
|
||||||
|
*csum_valid = _net_rx_pkt_validate_sctp_sum(pkt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
trace_net_rx_pkt_l4_csum_validate_not_xxp();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
|
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
|
||||||
|
|
||||||
|
@ -224,6 +224,7 @@ struct tcp_hdr {
|
|||||||
#define IP_HEADER_VERSION_6 (6)
|
#define IP_HEADER_VERSION_6 (6)
|
||||||
#define IP_PROTO_TCP (6)
|
#define IP_PROTO_TCP (6)
|
||||||
#define IP_PROTO_UDP (17)
|
#define IP_PROTO_UDP (17)
|
||||||
|
#define IP_PROTO_SCTP (132)
|
||||||
#define IPTOS_ECN_MASK 0x03
|
#define IPTOS_ECN_MASK 0x03
|
||||||
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
|
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
|
||||||
#define IPTOS_ECN_CE 0x03
|
#define IPTOS_ECN_CE 0x03
|
||||||
@ -379,7 +380,8 @@ typedef struct eth_ip4_hdr_info_st {
|
|||||||
typedef enum EthL4HdrProto {
|
typedef enum EthL4HdrProto {
|
||||||
ETH_L4_HDR_PROTO_INVALID,
|
ETH_L4_HDR_PROTO_INVALID,
|
||||||
ETH_L4_HDR_PROTO_TCP,
|
ETH_L4_HDR_PROTO_TCP,
|
||||||
ETH_L4_HDR_PROTO_UDP
|
ETH_L4_HDR_PROTO_UDP,
|
||||||
|
ETH_L4_HDR_PROTO_SCTP
|
||||||
} EthL4HdrProto;
|
} EthL4HdrProto;
|
||||||
|
|
||||||
typedef struct eth_l4_hdr_info_st {
|
typedef struct eth_l4_hdr_info_st {
|
||||||
|
@ -30,5 +30,6 @@
|
|||||||
|
|
||||||
|
|
||||||
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
|
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
|
||||||
|
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -211,6 +211,10 @@ void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
|
|||||||
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
|
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IP_PROTO_SCTP:
|
||||||
|
l4hdr_info->proto = ETH_L4_HDR_PROTO_SCTP;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,3 +113,11 @@ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
|
|||||||
return crc^0xffffffff;
|
return crc^0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt)
|
||||||
|
{
|
||||||
|
while (iov_cnt--) {
|
||||||
|
crc = crc32c(crc, iov->iov_base, iov->iov_len) ^ 0xffffffff;
|
||||||
|
iov++;
|
||||||
|
}
|
||||||
|
return crc ^ 0xffffffff;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user