[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/2] net: TX SCTP checksum offload
From: |
Tomasz Dzieciol |
Subject: |
[PATCH 1/2] net: TX SCTP checksum offload |
Date: |
Wed, 5 Apr 2023 16:23:24 +0200 |
Modern NICs are able to offload SCTP checksumming. SCTP calculates
checksums differently than TCP / UDP: no pseudo-header and CRC32C
algorithm are used.
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
---
hw/net/net_tx_pkt.c | 22 ++++++++++++++++++++++
hw/net/net_tx_pkt.h | 8 ++++++++
include/net/checksum.h | 12 ++++++++++++
include/net/eth.h | 8 ++++++++
net/checksum.c | 24 ++++++++++++++++++++++++
5 files changed, 74 insertions(+)
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 986a3adfe9..1b97249000 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -510,6 +510,27 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt,
iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
}
+void net_tx_pkt_update_sctp_crc(struct NetTxPkt *pkt)
+{
+ struct iovec *iov = &pkt->vec[NET_TX_PKT_L2HDR_FRAG];
+ uint32_t csum_cntr = 0;
+ /* num of iovec without vhdr */
+ uint32_t iov_len = pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1;
+ size_t csum_offset = pkt->hdr_len + offsetof(struct sctp_hdr, sh_sum);
+
+ if (pkt->l4proto != IP_PROTO_SCTP) {
+ return;
+ }
+
+ /* Put zero to checksum field */
+ iov_from_buf(iov, iov_len, csum_offset, &csum_cntr, sizeof csum_cntr);
+
+ csum_cntr = net_sctp_checksum_add_iov(iov, iov_len,
+ pkt->hdr_len,
+ pkt->payload_len);
+ iov_from_buf(iov, iov_len, csum_offset, &csum_cntr, sizeof csum_cntr);
+}
+
#define NET_MAX_FRAG_SG_LIST (64)
static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt,
@@ -846,3 +867,4 @@ void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt)
}
}
}
+
diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h
index f57b4e034b..56475b462c 100644
--- a/hw/net/net_tx_pkt.h
+++ b/hw/net/net_tx_pkt.h
@@ -204,4 +204,12 @@ bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt);
*/
void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt);
+/**
+* Update SCTP CRC32C value.
+*
+* @pkt: packet
+*
+*/
+void net_tx_pkt_update_sctp_crc(struct NetTxPkt *pkt);
+
#endif
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 7dec37e56c..987d66546d 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -64,6 +64,18 @@ uint32_t net_checksum_add_iov(const struct iovec *iov,
uint32_t iov_off, uint32_t size,
uint32_t csum_offset);
+/**
+ * net_sctp_checksum_add_iov: scatter-gather vector checksumming for SCTP
+ *
+ * @iov: input scatter-gather array
+ * @iov_cnt: number of array elements
+ * @iov_off: starting iov offset for checksumming
+ * @size: length of data to be checksummed
+ */
+uint32_t net_sctp_checksum_add_iov(const struct iovec *iov,
+ const unsigned int iov_cnt,
+ uint32_t iov_off, uint32_t size);
+
typedef struct toeplitz_key_st {
uint32_t leftmost_32_bits;
uint8_t *next_byte;
diff --git a/include/net/eth.h b/include/net/eth.h
index c5ae4493b4..a946de1250 100644
--- a/include/net/eth.h
+++ b/include/net/eth.h
@@ -147,6 +147,13 @@ struct ip6_option_hdr {
uint8_t len;
};
+struct sctp_hdr {
+ uint16_t sh_sport; /* source port */
+ uint16_t sh_dport; /* destination port */
+ uint32_t sh_vtag; /* verification tag */
+ uint32_t sh_sum; /* sctp checksum */
+};
+
struct udp_hdr {
uint16_t uh_sport; /* source port */
uint16_t uh_dport; /* destination port */
@@ -222,6 +229,7 @@ struct tcp_hdr {
#define IP_HEADER_VERSION_6 (6)
#define IP_PROTO_TCP (6)
#define IP_PROTO_UDP (17)
+#define IP_PROTO_SCTP (132)
#define IPTOS_ECN_MASK 0x03
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
#define IPTOS_ECN_CE 0x03
diff --git a/net/checksum.c b/net/checksum.c
index 68245fd748..4869b1ef14 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "net/checksum.h"
#include "net/eth.h"
+#include "qemu/crc32c.h"
uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq)
{
@@ -206,3 +207,26 @@ net_checksum_add_iov(const struct iovec *iov, const
unsigned int iov_cnt,
}
return res;
}
+
+uint32_t
+net_sctp_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt,
+ uint32_t iov_off, uint32_t size)
+{
+ size_t iovec_off;
+ unsigned int i;
+ uint32_t res = 0xffffffff;
+
+ iovec_off = 0;
+ for (i = 0; i < iov_cnt && size; i++) {
+ if (iov_off < (iovec_off + iov[i].iov_len)) {
+ size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
+ void *chunk_buf = iov[i].iov_base + (iov_off - iovec_off);
+
+ res = crc32c(res, chunk_buf, len);
+ iov_off += len;
+ size -= len;
+ }
+ iovec_off += iov[i].iov_len;
+ }
+ return res;
+}
--
2.25.1