mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
Merge branch 'net-faster-and-simpler-crc32c-computation'
Eric Biggers says: ==================== net: faster and simpler CRC32C computation Update networking code that computes the CRC32C of packets to just call crc32c() without unnecessary abstraction layers. The result is faster and simpler code. Patches 1-7 add skb_crc32c() and remove the overly-abstracted and inefficient __skb_checksum(). Patches 8-10 replace skb_copy_and_hash_datagram_iter() with skb_copy_and_crc32c_datagram_iter(), eliminating the unnecessary use of the crypto layer. This unblocks the conversion of nvme-tcp to call crc32c() directly instead of using the crypto layer, which patch 9 does. v1: https://lore.kernel.org/20250511004110.145171-1-ebiggers@kernel.org ==================== Link: https://patch.msgid.link/20250519175012.36581-1-ebiggers@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c6634c98e6
|
|
@ -3,6 +3,7 @@ config RDMA_SIW
|
|||
depends on INET && INFINIBAND
|
||||
depends on INFINIBAND_VIRT_DMA
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
help
|
||||
This driver implements the iWARP RDMA transport over
|
||||
the Linux TCP/IP network stack. It enables a system with a
|
||||
|
|
|
|||
|
|
@ -693,29 +693,9 @@ static inline void siw_crc_oneshot(const void *data, size_t len, u8 out[4])
|
|||
return siw_crc_final(&crc, out);
|
||||
}
|
||||
|
||||
static inline __wsum siw_csum_update(const void *buff, int len, __wsum sum)
|
||||
{
|
||||
return (__force __wsum)crc32c((__force __u32)sum, buff, len);
|
||||
}
|
||||
|
||||
static inline __wsum siw_csum_combine(__wsum csum, __wsum csum2, int offset,
|
||||
int len)
|
||||
{
|
||||
return (__force __wsum)crc32c_combine((__force __u32)csum,
|
||||
(__force __u32)csum2, len);
|
||||
}
|
||||
|
||||
static inline void siw_crc_skb(struct siw_rx_stream *srx, unsigned int len)
|
||||
{
|
||||
const struct skb_checksum_ops siw_cs_ops = {
|
||||
.update = siw_csum_update,
|
||||
.combine = siw_csum_combine,
|
||||
};
|
||||
__wsum crc = (__force __wsum)srx->mpa_crc;
|
||||
|
||||
crc = __skb_checksum(srx->skb, srx->skb_offset, len, crc,
|
||||
&siw_cs_ops);
|
||||
srx->mpa_crc = (__force u32)crc;
|
||||
srx->mpa_crc = skb_crc32c(srx->skb, srx->skb_offset, len, srx->mpa_crc);
|
||||
}
|
||||
|
||||
#define siw_dbg(ibdev, fmt, ...) \
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@ config NVME_TCP
|
|||
tristate "NVM Express over Fabrics TCP host driver"
|
||||
depends on INET
|
||||
depends on BLOCK
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
select NVME_FABRICS
|
||||
select CRYPTO
|
||||
select CRYPTO_CRC32C
|
||||
help
|
||||
This provides support for the NVMe over Fabrics protocol using
|
||||
the TCP transport. This allows you to use remote block devices
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/nvme-tcp.h>
|
||||
#include <linux/nvme-keyring.h>
|
||||
#include <net/sock.h>
|
||||
|
|
@ -16,7 +17,6 @@
|
|||
#include <net/tls_prot.h>
|
||||
#include <net/handshake.h>
|
||||
#include <linux/blk-mq.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <trace/events/sock.h>
|
||||
|
||||
|
|
@ -168,8 +168,8 @@ struct nvme_tcp_queue {
|
|||
bool hdr_digest;
|
||||
bool data_digest;
|
||||
bool tls_enabled;
|
||||
struct ahash_request *rcv_hash;
|
||||
struct ahash_request *snd_hash;
|
||||
u32 rcv_crc;
|
||||
u32 snd_crc;
|
||||
__le32 exp_ddgst;
|
||||
__le32 recv_ddgst;
|
||||
struct completion tls_complete;
|
||||
|
|
@ -456,32 +456,38 @@ nvme_tcp_fetch_request(struct nvme_tcp_queue *queue)
|
|||
return req;
|
||||
}
|
||||
|
||||
static inline void nvme_tcp_ddgst_final(struct ahash_request *hash,
|
||||
__le32 *dgst)
|
||||
#define NVME_TCP_CRC_SEED (~0)
|
||||
|
||||
static inline void nvme_tcp_ddgst_update(u32 *crcp,
|
||||
struct page *page, size_t off, size_t len)
|
||||
{
|
||||
ahash_request_set_crypt(hash, NULL, (u8 *)dgst, 0);
|
||||
crypto_ahash_final(hash);
|
||||
page += off / PAGE_SIZE;
|
||||
off %= PAGE_SIZE;
|
||||
while (len) {
|
||||
const void *vaddr = kmap_local_page(page);
|
||||
size_t n = min(len, (size_t)PAGE_SIZE - off);
|
||||
|
||||
*crcp = crc32c(*crcp, vaddr + off, n);
|
||||
kunmap_local(vaddr);
|
||||
page++;
|
||||
off = 0;
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void nvme_tcp_ddgst_update(struct ahash_request *hash,
|
||||
struct page *page, off_t off, size_t len)
|
||||
static inline __le32 nvme_tcp_ddgst_final(u32 crc)
|
||||
{
|
||||
struct scatterlist sg;
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_set_page(&sg, page, len, off);
|
||||
ahash_request_set_crypt(hash, &sg, NULL, len);
|
||||
crypto_ahash_update(hash);
|
||||
return cpu_to_le32(~crc);
|
||||
}
|
||||
|
||||
static inline void nvme_tcp_hdgst(struct ahash_request *hash,
|
||||
void *pdu, size_t len)
|
||||
static inline __le32 nvme_tcp_hdgst(const void *pdu, size_t len)
|
||||
{
|
||||
struct scatterlist sg;
|
||||
return cpu_to_le32(~crc32c(NVME_TCP_CRC_SEED, pdu, len));
|
||||
}
|
||||
|
||||
sg_init_one(&sg, pdu, len);
|
||||
ahash_request_set_crypt(hash, &sg, pdu + len, len);
|
||||
crypto_ahash_digest(hash);
|
||||
static inline void nvme_tcp_set_hdgst(void *pdu, size_t len)
|
||||
{
|
||||
*(__le32 *)(pdu + len) = nvme_tcp_hdgst(pdu, len);
|
||||
}
|
||||
|
||||
static int nvme_tcp_verify_hdgst(struct nvme_tcp_queue *queue,
|
||||
|
|
@ -499,8 +505,7 @@ static int nvme_tcp_verify_hdgst(struct nvme_tcp_queue *queue,
|
|||
}
|
||||
|
||||
recv_digest = *(__le32 *)(pdu + hdr->hlen);
|
||||
nvme_tcp_hdgst(queue->rcv_hash, pdu, pdu_len);
|
||||
exp_digest = *(__le32 *)(pdu + hdr->hlen);
|
||||
exp_digest = nvme_tcp_hdgst(pdu, pdu_len);
|
||||
if (recv_digest != exp_digest) {
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"header digest error: recv %#x expected %#x\n",
|
||||
|
|
@ -526,7 +531,7 @@ static int nvme_tcp_check_ddgst(struct nvme_tcp_queue *queue, void *pdu)
|
|||
nvme_tcp_queue_id(queue));
|
||||
return -EPROTO;
|
||||
}
|
||||
crypto_ahash_init(queue->rcv_hash);
|
||||
queue->rcv_crc = NVME_TCP_CRC_SEED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -926,8 +931,8 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
|
|||
iov_iter_count(&req->iter));
|
||||
|
||||
if (queue->data_digest)
|
||||
ret = skb_copy_and_hash_datagram_iter(skb, *offset,
|
||||
&req->iter, recv_len, queue->rcv_hash);
|
||||
ret = skb_copy_and_crc32c_datagram_iter(skb, *offset,
|
||||
&req->iter, recv_len, &queue->rcv_crc);
|
||||
else
|
||||
ret = skb_copy_datagram_iter(skb, *offset,
|
||||
&req->iter, recv_len);
|
||||
|
|
@ -945,7 +950,7 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
|
|||
|
||||
if (!queue->data_remaining) {
|
||||
if (queue->data_digest) {
|
||||
nvme_tcp_ddgst_final(queue->rcv_hash, &queue->exp_ddgst);
|
||||
queue->exp_ddgst = nvme_tcp_ddgst_final(queue->rcv_crc);
|
||||
queue->ddgst_remaining = NVME_TCP_DIGEST_LENGTH;
|
||||
} else {
|
||||
if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
|
||||
|
|
@ -1147,7 +1152,7 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
|
|||
return ret;
|
||||
|
||||
if (queue->data_digest)
|
||||
nvme_tcp_ddgst_update(queue->snd_hash, page,
|
||||
nvme_tcp_ddgst_update(&queue->snd_crc, page,
|
||||
offset, ret);
|
||||
|
||||
/*
|
||||
|
|
@ -1161,8 +1166,8 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
|
|||
/* fully successful last send in current PDU */
|
||||
if (last && ret == len) {
|
||||
if (queue->data_digest) {
|
||||
nvme_tcp_ddgst_final(queue->snd_hash,
|
||||
&req->ddgst);
|
||||
req->ddgst =
|
||||
nvme_tcp_ddgst_final(queue->snd_crc);
|
||||
req->state = NVME_TCP_SEND_DDGST;
|
||||
req->offset = 0;
|
||||
} else {
|
||||
|
|
@ -1194,7 +1199,7 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
|
|||
msg.msg_flags |= MSG_EOR;
|
||||
|
||||
if (queue->hdr_digest && !req->offset)
|
||||
nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
|
||||
nvme_tcp_set_hdgst(pdu, sizeof(*pdu));
|
||||
|
||||
bvec_set_virt(&bvec, (void *)pdu + req->offset, len);
|
||||
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len);
|
||||
|
|
@ -1207,7 +1212,7 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
|
|||
if (inline_data) {
|
||||
req->state = NVME_TCP_SEND_DATA;
|
||||
if (queue->data_digest)
|
||||
crypto_ahash_init(queue->snd_hash);
|
||||
queue->snd_crc = NVME_TCP_CRC_SEED;
|
||||
} else {
|
||||
nvme_tcp_done_send_req(queue);
|
||||
}
|
||||
|
|
@ -1229,7 +1234,7 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
|
|||
int ret;
|
||||
|
||||
if (queue->hdr_digest && !req->offset)
|
||||
nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
|
||||
nvme_tcp_set_hdgst(pdu, sizeof(*pdu));
|
||||
|
||||
if (!req->h2cdata_left)
|
||||
msg.msg_flags |= MSG_SPLICE_PAGES;
|
||||
|
|
@ -1244,7 +1249,7 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
|
|||
if (!len) {
|
||||
req->state = NVME_TCP_SEND_DATA;
|
||||
if (queue->data_digest)
|
||||
crypto_ahash_init(queue->snd_hash);
|
||||
queue->snd_crc = NVME_TCP_CRC_SEED;
|
||||
return 1;
|
||||
}
|
||||
req->offset += ret;
|
||||
|
|
@ -1384,41 +1389,6 @@ static void nvme_tcp_io_work(struct work_struct *w)
|
|||
queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
|
||||
}
|
||||
|
||||
static void nvme_tcp_free_crypto(struct nvme_tcp_queue *queue)
|
||||
{
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(queue->rcv_hash);
|
||||
|
||||
ahash_request_free(queue->rcv_hash);
|
||||
ahash_request_free(queue->snd_hash);
|
||||
crypto_free_ahash(tfm);
|
||||
}
|
||||
|
||||
static int nvme_tcp_alloc_crypto(struct nvme_tcp_queue *queue)
|
||||
{
|
||||
struct crypto_ahash *tfm;
|
||||
|
||||
tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
queue->snd_hash = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!queue->snd_hash)
|
||||
goto free_tfm;
|
||||
ahash_request_set_callback(queue->snd_hash, 0, NULL, NULL);
|
||||
|
||||
queue->rcv_hash = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!queue->rcv_hash)
|
||||
goto free_snd_hash;
|
||||
ahash_request_set_callback(queue->rcv_hash, 0, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
free_snd_hash:
|
||||
ahash_request_free(queue->snd_hash);
|
||||
free_tfm:
|
||||
crypto_free_ahash(tfm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void nvme_tcp_free_async_req(struct nvme_tcp_ctrl *ctrl)
|
||||
{
|
||||
struct nvme_tcp_request *async = &ctrl->async_req;
|
||||
|
|
@ -1451,9 +1421,6 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
|
|||
if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags))
|
||||
return;
|
||||
|
||||
if (queue->hdr_digest || queue->data_digest)
|
||||
nvme_tcp_free_crypto(queue);
|
||||
|
||||
page_frag_cache_drain(&queue->pf_cache);
|
||||
|
||||
noreclaim_flag = memalloc_noreclaim_save();
|
||||
|
|
@ -1867,21 +1834,13 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
|
|||
|
||||
queue->hdr_digest = nctrl->opts->hdr_digest;
|
||||
queue->data_digest = nctrl->opts->data_digest;
|
||||
if (queue->hdr_digest || queue->data_digest) {
|
||||
ret = nvme_tcp_alloc_crypto(queue);
|
||||
if (ret) {
|
||||
dev_err(nctrl->device,
|
||||
"failed to allocate queue %d crypto\n", qid);
|
||||
goto err_sock;
|
||||
}
|
||||
}
|
||||
|
||||
rcv_pdu_size = sizeof(struct nvme_tcp_rsp_pdu) +
|
||||
nvme_tcp_hdgst_len(queue);
|
||||
queue->pdu = kmalloc(rcv_pdu_size, GFP_KERNEL);
|
||||
if (!queue->pdu) {
|
||||
ret = -ENOMEM;
|
||||
goto err_crypto;
|
||||
goto err_sock;
|
||||
}
|
||||
|
||||
dev_dbg(nctrl->device, "connecting queue %d\n",
|
||||
|
|
@ -1914,9 +1873,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
|
|||
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
|
||||
err_rcv_pdu:
|
||||
kfree(queue->pdu);
|
||||
err_crypto:
|
||||
if (queue->hdr_digest || queue->data_digest)
|
||||
nvme_tcp_free_crypto(queue);
|
||||
err_sock:
|
||||
/* ->sock will be released by fput() */
|
||||
fput(queue->sock->file);
|
||||
|
|
|
|||
|
|
@ -76,29 +76,6 @@ static inline u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2)
|
|||
return crc32_le_shift(crc1, len2) ^ crc2;
|
||||
}
|
||||
|
||||
u32 crc32c_shift(u32 crc, size_t len);
|
||||
|
||||
/**
|
||||
* crc32c_combine - Combine two crc32c check values into one. For two sequences
|
||||
* of bytes, seq1 and seq2 with lengths len1 and len2, crc32c()
|
||||
* check values were calculated for each, crc1 and crc2.
|
||||
*
|
||||
* @crc1: crc32c of the first block
|
||||
* @crc2: crc32c of the second block
|
||||
* @len2: length of the second block
|
||||
*
|
||||
* Return: The crc32c() check value of seq1 and seq2 concatenated, requiring
|
||||
* only crc1, crc2, and len2. Note: If seq_full denotes the concatenated
|
||||
* memory area of seq1 with seq2, and crc_full the crc32c() value of
|
||||
* seq_full, then crc_full == crc32c_combine(crc1, crc2, len2) when
|
||||
* crc_full was seeded with the same initializer as crc1, and crc2 seed
|
||||
* was 0. See also crc_combine_test().
|
||||
*/
|
||||
static inline u32 crc32c_combine(u32 crc1, u32 crc2, size_t len2)
|
||||
{
|
||||
return crc32c_shift(crc1, len2) ^ crc2;
|
||||
}
|
||||
|
||||
#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -274,7 +274,6 @@
|
|||
SKB_DATA_ALIGN(sizeof(struct sk_buff)) + \
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
|
||||
struct ahash_request;
|
||||
struct net_device;
|
||||
struct scatterlist;
|
||||
struct pipe_inode_info;
|
||||
|
|
@ -4134,9 +4133,8 @@ static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
|
|||
}
|
||||
int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
|
||||
struct msghdr *msg);
|
||||
int skb_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
|
||||
struct iov_iter *to, int len,
|
||||
struct ahash_request *hash);
|
||||
int skb_copy_and_crc32c_datagram_iter(const struct sk_buff *skb, int offset,
|
||||
struct iov_iter *to, int len, u32 *crcp);
|
||||
int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
|
||||
struct iov_iter *from, int len);
|
||||
int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
|
||||
|
|
@ -4192,17 +4190,9 @@ static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
|
|||
return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
|
||||
}
|
||||
|
||||
struct skb_checksum_ops {
|
||||
__wsum (*update)(const void *mem, int len, __wsum wsum);
|
||||
__wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
|
||||
};
|
||||
|
||||
extern const struct skb_checksum_ops *crc32c_csum_stub __read_mostly;
|
||||
|
||||
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
||||
__wsum csum, const struct skb_checksum_ops *ops);
|
||||
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
|
||||
__wsum csum);
|
||||
u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc);
|
||||
|
||||
static inline void * __must_check
|
||||
__skb_header_pointer(const struct sk_buff *skb, int offset, int len,
|
||||
|
|
|
|||
|
|
@ -98,12 +98,6 @@ csum_block_add(__wsum csum, __wsum csum2, int offset)
|
|||
return csum_add(csum, csum_shift(csum2, offset));
|
||||
}
|
||||
|
||||
static __always_inline __wsum
|
||||
csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
|
||||
{
|
||||
return csum_block_add(csum, csum2, offset);
|
||||
}
|
||||
|
||||
static __always_inline __wsum
|
||||
csum_block_sub(__wsum csum, __wsum csum2, int offset)
|
||||
{
|
||||
|
|
@ -115,12 +109,6 @@ static __always_inline __wsum csum_unfold(__sum16 n)
|
|||
return (__force __wsum)n;
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
__wsum csum_partial_ext(const void *buff, int len, __wsum sum)
|
||||
{
|
||||
return csum_partial(buff, len, sum);
|
||||
}
|
||||
|
||||
#define CSUM_MANGLED_0 ((__force __sum16)0xffff)
|
||||
|
||||
static __always_inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
* Dinakaran Joseph
|
||||
* Jon Grimm <jgrimm@us.ibm.com>
|
||||
* Sridhar Samudrala <sri@us.ibm.com>
|
||||
*
|
||||
* Rewritten to use libcrc32c by:
|
||||
* Vlad Yasevich <vladislav.yasevich@hp.com>
|
||||
*/
|
||||
|
||||
|
|
@ -25,39 +23,18 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/crc32c.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
static inline __wsum sctp_csum_update(const void *buff, int len, __wsum sum)
|
||||
{
|
||||
return (__force __wsum)crc32c((__force __u32)sum, buff, len);
|
||||
}
|
||||
|
||||
static inline __wsum sctp_csum_combine(__wsum csum, __wsum csum2,
|
||||
int offset, int len)
|
||||
{
|
||||
return (__force __wsum)crc32c_combine((__force __u32)csum,
|
||||
(__force __u32)csum2, len);
|
||||
}
|
||||
|
||||
static const struct skb_checksum_ops sctp_csum_ops = {
|
||||
.update = sctp_csum_update,
|
||||
.combine = sctp_csum_combine,
|
||||
};
|
||||
|
||||
static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
|
||||
__le32 old = sh->checksum;
|
||||
__wsum new;
|
||||
u32 new;
|
||||
|
||||
sh->checksum = 0;
|
||||
new = ~__skb_checksum(skb, offset, skb->len - offset, ~(__wsum)0,
|
||||
&sctp_csum_ops);
|
||||
new = ~skb_crc32c(skb, offset, skb->len - offset, ~0);
|
||||
sh->checksum = old;
|
||||
|
||||
return cpu_to_le32((__force __u32)new);
|
||||
return cpu_to_le32(new);
|
||||
}
|
||||
|
||||
#endif /* __sctp_checksum_h__ */
|
||||
|
|
|
|||
|
|
@ -119,12 +119,6 @@ u32 crc32_le_shift(u32 crc, size_t len)
|
|||
}
|
||||
EXPORT_SYMBOL(crc32_le_shift);
|
||||
|
||||
u32 crc32c_shift(u32 crc, size_t len)
|
||||
{
|
||||
return crc32_generic_shift(crc, len, CRC32C_POLY_LE);
|
||||
}
|
||||
EXPORT_SYMBOL(crc32c_shift);
|
||||
|
||||
u32 crc32_be_base(u32 crc, const u8 *p, size_t len)
|
||||
{
|
||||
while (len--)
|
||||
|
|
|
|||
|
|
@ -391,17 +391,11 @@ static u64 crc32c_wrapper(u64 crc, const u8 *p, size_t len)
|
|||
return crc32c(crc, p, len);
|
||||
}
|
||||
|
||||
static u64 crc32c_combine_wrapper(u64 crc1, u64 crc2, size_t len2)
|
||||
{
|
||||
return crc32c_combine(crc1, crc2, len2);
|
||||
}
|
||||
|
||||
static const struct crc_variant crc_variant_crc32c = {
|
||||
.bits = 32,
|
||||
.le = true,
|
||||
.poly = 0x82f63b78,
|
||||
.func = crc32c_wrapper,
|
||||
.combine_func = crc32c_combine_wrapper,
|
||||
};
|
||||
|
||||
static void crc32c_test(struct kunit *test)
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ config NET_DEVMEM
|
|||
config NET_SHAPER
|
||||
bool
|
||||
|
||||
config NET_CRC32C
|
||||
bool
|
||||
select CRC32
|
||||
|
||||
menu "Networking options"
|
||||
|
||||
source "net/packet/Kconfig"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/iov_iter.h>
|
||||
#include <linux/indirect_call_wrapper.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
|
@ -61,7 +62,6 @@
|
|||
#include <net/tcp_states.h>
|
||||
#include <trace/events/skb.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#include "devmem.h"
|
||||
|
||||
|
|
@ -483,41 +483,37 @@ static int __skb_datagram_iter(const struct sk_buff *skb, int offset,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
|
||||
struct iov_iter *i)
|
||||
#ifdef CONFIG_NET_CRC32C
|
||||
static size_t crc32c_and_copy_to_iter(const void *addr, size_t bytes,
|
||||
void *_crcp, struct iov_iter *i)
|
||||
{
|
||||
#ifdef CONFIG_CRYPTO_HASH
|
||||
struct ahash_request *hash = hashp;
|
||||
struct scatterlist sg;
|
||||
u32 *crcp = _crcp;
|
||||
size_t copied;
|
||||
|
||||
copied = copy_to_iter(addr, bytes, i);
|
||||
sg_init_one(&sg, addr, copied);
|
||||
ahash_request_set_crypt(hash, &sg, NULL, copied);
|
||||
crypto_ahash_update(hash);
|
||||
*crcp = crc32c(*crcp, addr, copied);
|
||||
return copied;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_copy_and_hash_datagram_iter - Copy datagram to an iovec iterator
|
||||
* and update a hash.
|
||||
* skb_copy_and_crc32c_datagram_iter - Copy datagram to an iovec iterator
|
||||
* and update a CRC32C value.
|
||||
* @skb: buffer to copy
|
||||
* @offset: offset in the buffer to start copying from
|
||||
* @to: iovec iterator to copy to
|
||||
* @len: amount of data to copy from buffer to iovec
|
||||
* @hash: hash request to update
|
||||
* @crcp: pointer to CRC32C value to update
|
||||
*
|
||||
* Return: 0 on success, -EFAULT if there was a fault during copy.
|
||||
*/
|
||||
int skb_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
|
||||
struct iov_iter *to, int len,
|
||||
struct ahash_request *hash)
|
||||
int skb_copy_and_crc32c_datagram_iter(const struct sk_buff *skb, int offset,
|
||||
struct iov_iter *to, int len, u32 *crcp)
|
||||
{
|
||||
return __skb_datagram_iter(skb, offset, to, len, true,
|
||||
hash_and_copy_to_iter, hash);
|
||||
crc32c_and_copy_to_iter, crcp);
|
||||
}
|
||||
EXPORT_SYMBOL(skb_copy_and_hash_datagram_iter);
|
||||
EXPORT_SYMBOL(skb_copy_and_crc32c_datagram_iter);
|
||||
#endif /* CONFIG_NET_CRC32C */
|
||||
|
||||
static size_t simple_copy_to_iter(const void *addr, size_t bytes,
|
||||
void *data __always_unused, struct iov_iter *i)
|
||||
|
|
|
|||
|
|
@ -3596,9 +3596,10 @@ int skb_checksum_help(struct sk_buff *skb)
|
|||
}
|
||||
EXPORT_SYMBOL(skb_checksum_help);
|
||||
|
||||
#ifdef CONFIG_NET_CRC32C
|
||||
int skb_crc32c_csum_help(struct sk_buff *skb)
|
||||
{
|
||||
__le32 crc32c_csum;
|
||||
u32 crc;
|
||||
int ret = 0, offset, start;
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
|
|
@ -3626,15 +3627,14 @@ int skb_crc32c_csum_help(struct sk_buff *skb)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
crc32c_csum = cpu_to_le32(~__skb_checksum(skb, start,
|
||||
skb->len - start, ~(__u32)0,
|
||||
crc32c_csum_stub));
|
||||
*(__le32 *)(skb->data + offset) = crc32c_csum;
|
||||
crc = ~skb_crc32c(skb, start, skb->len - start, ~0);
|
||||
*(__le32 *)(skb->data + offset) = cpu_to_le32(crc);
|
||||
skb_reset_csum_not_inet(skb);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_crc32c_csum_help);
|
||||
#endif /* CONFIG_NET_CRC32C */
|
||||
|
||||
__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
#include <linux/mpls.h>
|
||||
#include <linux/kcov.h>
|
||||
#include <linux/iov_iter.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <net/dst.h>
|
||||
|
|
@ -3444,8 +3445,7 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
|
|||
EXPORT_SYMBOL(skb_store_bits);
|
||||
|
||||
/* Checksum skb data. */
|
||||
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
||||
__wsum csum, const struct skb_checksum_ops *ops)
|
||||
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum)
|
||||
{
|
||||
int start = skb_headlen(skb);
|
||||
int i, copy = start - offset;
|
||||
|
|
@ -3456,8 +3456,7 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
|||
if (copy > 0) {
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
csum = INDIRECT_CALL_1(ops->update, csum_partial_ext,
|
||||
skb->data + offset, copy, csum);
|
||||
csum = csum_partial(skb->data + offset, copy, csum);
|
||||
if ((len -= copy) == 0)
|
||||
return csum;
|
||||
offset += copy;
|
||||
|
|
@ -3487,13 +3486,9 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
|||
skb_frag_off(frag) + offset - start,
|
||||
copy, p, p_off, p_len, copied) {
|
||||
vaddr = kmap_atomic(p);
|
||||
csum2 = INDIRECT_CALL_1(ops->update,
|
||||
csum_partial_ext,
|
||||
vaddr + p_off, p_len, 0);
|
||||
csum2 = csum_partial(vaddr + p_off, p_len, 0);
|
||||
kunmap_atomic(vaddr);
|
||||
csum = INDIRECT_CALL_1(ops->combine,
|
||||
csum_block_add_ext, csum,
|
||||
csum2, pos, p_len);
|
||||
csum = csum_block_add(csum, csum2, pos);
|
||||
pos += p_len;
|
||||
}
|
||||
|
||||
|
|
@ -3514,10 +3509,9 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
|||
__wsum csum2;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
csum2 = __skb_checksum(frag_iter, offset - start,
|
||||
copy, 0, ops);
|
||||
csum = INDIRECT_CALL_1(ops->combine, csum_block_add_ext,
|
||||
csum, csum2, pos, copy);
|
||||
csum2 = skb_checksum(frag_iter, offset - start, copy,
|
||||
0);
|
||||
csum = csum_block_add(csum, csum2, pos);
|
||||
if ((len -= copy) == 0)
|
||||
return csum;
|
||||
offset += copy;
|
||||
|
|
@ -3529,18 +3523,6 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
|
|||
|
||||
return csum;
|
||||
}
|
||||
EXPORT_SYMBOL(__skb_checksum);
|
||||
|
||||
__wsum skb_checksum(const struct sk_buff *skb, int offset,
|
||||
int len, __wsum csum)
|
||||
{
|
||||
const struct skb_checksum_ops ops = {
|
||||
.update = csum_partial_ext,
|
||||
.combine = csum_block_add_ext,
|
||||
};
|
||||
|
||||
return __skb_checksum(skb, offset, len, csum, &ops);
|
||||
}
|
||||
EXPORT_SYMBOL(skb_checksum);
|
||||
|
||||
/* Both of above in one bottle. */
|
||||
|
|
@ -3633,6 +3615,78 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
|
|||
}
|
||||
EXPORT_SYMBOL(skb_copy_and_csum_bits);
|
||||
|
||||
#ifdef CONFIG_NET_CRC32C
|
||||
u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc)
|
||||
{
|
||||
int start = skb_headlen(skb);
|
||||
int i, copy = start - offset;
|
||||
struct sk_buff *frag_iter;
|
||||
|
||||
if (copy > 0) {
|
||||
copy = min(copy, len);
|
||||
crc = crc32c(crc, skb->data + offset, copy);
|
||||
len -= copy;
|
||||
if (len == 0)
|
||||
return crc;
|
||||
offset += copy;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!skb_frags_readable(skb)))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
int end;
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||
|
||||
WARN_ON(start > offset + len);
|
||||
|
||||
end = start + skb_frag_size(frag);
|
||||
copy = end - offset;
|
||||
if (copy > 0) {
|
||||
u32 p_off, p_len, copied;
|
||||
struct page *p;
|
||||
u8 *vaddr;
|
||||
|
||||
copy = min(copy, len);
|
||||
skb_frag_foreach_page(frag,
|
||||
skb_frag_off(frag) + offset - start,
|
||||
copy, p, p_off, p_len, copied) {
|
||||
vaddr = kmap_atomic(p);
|
||||
crc = crc32c(crc, vaddr + p_off, p_len);
|
||||
kunmap_atomic(vaddr);
|
||||
}
|
||||
len -= copy;
|
||||
if (len == 0)
|
||||
return crc;
|
||||
offset += copy;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
|
||||
skb_walk_frags(skb, frag_iter) {
|
||||
int end;
|
||||
|
||||
WARN_ON(start > offset + len);
|
||||
|
||||
end = start + frag_iter->len;
|
||||
copy = end - offset;
|
||||
if (copy > 0) {
|
||||
copy = min(copy, len);
|
||||
crc = skb_crc32c(frag_iter, offset - start, copy, crc);
|
||||
len -= copy;
|
||||
if (len == 0)
|
||||
return crc;
|
||||
offset += copy;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
BUG_ON(len);
|
||||
|
||||
return crc;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_crc32c);
|
||||
#endif /* CONFIG_NET_CRC32C */
|
||||
|
||||
__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
|
||||
{
|
||||
__sum16 sum;
|
||||
|
|
@ -3692,32 +3746,6 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
|
|||
}
|
||||
EXPORT_SYMBOL(__skb_checksum_complete);
|
||||
|
||||
static __wsum warn_crc32c_csum_update(const void *buff, int len, __wsum sum)
|
||||
{
|
||||
net_warn_ratelimited(
|
||||
"%s: attempt to compute crc32c without libcrc32c.ko\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __wsum warn_crc32c_csum_combine(__wsum csum, __wsum csum2,
|
||||
int offset, int len)
|
||||
{
|
||||
net_warn_ratelimited(
|
||||
"%s: attempt to compute crc32c without libcrc32c.ko\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct skb_checksum_ops default_crc32c_ops = {
|
||||
.update = warn_crc32c_csum_update,
|
||||
.combine = warn_crc32c_csum_combine,
|
||||
};
|
||||
|
||||
const struct skb_checksum_ops *crc32c_csum_stub __read_mostly =
|
||||
&default_crc32c_ops;
|
||||
EXPORT_SYMBOL(crc32c_csum_stub);
|
||||
|
||||
/**
|
||||
* skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
|
||||
* @from: source buffer
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ config NF_CT_PROTO_SCTP
|
|||
bool 'SCTP protocol connection tracking support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
default y
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
help
|
||||
With this option enabled, the layer 3 independent connection
|
||||
tracking code will be able to do state tracking on SCTP connections.
|
||||
|
|
@ -475,7 +475,7 @@ endif # NF_CONNTRACK
|
|||
|
||||
config NF_TABLES
|
||||
select NETFILTER_NETLINK
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
tristate "Netfilter nf_tables support"
|
||||
help
|
||||
nftables is the new packet classification framework that intends to
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ config IP_VS_PROTO_AH
|
|||
|
||||
config IP_VS_PROTO_SCTP
|
||||
bool "SCTP load balancing support"
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
help
|
||||
This option enables support for load balancing SCTP transport
|
||||
protocol. Say Y if unsure.
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ config OPENVSWITCH
|
|||
(!NF_NAT || NF_NAT) && \
|
||||
(!NETFILTER_CONNCOUNT || NETFILTER_CONNCOUNT)))
|
||||
depends on PSAMPLE || !PSAMPLE
|
||||
select CRC32
|
||||
select MPLS
|
||||
select NET_CRC32C
|
||||
select NET_MPLS_GSO
|
||||
select DST_CACHE
|
||||
select NET_NSH
|
||||
|
|
|
|||
|
|
@ -796,7 +796,7 @@ config NET_ACT_SKBEDIT
|
|||
config NET_ACT_CSUM
|
||||
tristate "Checksum Updating"
|
||||
depends on NET_CLS_ACT && INET
|
||||
select CRC32
|
||||
select NET_CRC32C
|
||||
help
|
||||
Say Y here to update some common checksum after some direct
|
||||
packet alterations.
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ menuconfig IP_SCTP
|
|||
tristate "The SCTP Protocol"
|
||||
depends on INET
|
||||
depends on IPV6 || IPV6=n
|
||||
select CRC32
|
||||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
select NET_CRC32C
|
||||
select NET_UDP_TUNNEL
|
||||
help
|
||||
Stream Control Transmission Protocol
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ int __init sctp_offload_init(void)
|
|||
if (ret)
|
||||
goto ipv4;
|
||||
|
||||
crc32c_csum_stub = &sctp_csum_ops;
|
||||
return ret;
|
||||
|
||||
ipv4:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user