diff --git a/include/spdk/dif.h b/include/spdk/dif.h new file mode 100644 index 0000000000..0391ef4c4a --- /dev/null +++ b/include/spdk/dif.h @@ -0,0 +1,103 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPDK_DIF_H +#define SPDK_DIF_H + +#include "spdk/stdinc.h" +#include "spdk/assert.h" + +#define SPDK_DIF_REFTAG_CHECK (1U << 26) +#define SPDK_DIF_APPTAG_CHECK (1U << 27) +#define SPDK_DIF_GUARD_CHECK (1U << 28) + +enum spdk_dif_type { + SPDK_DIF_TYPE1 = 1, + SPDK_DIF_TYPE2, + SPDK_DIF_TYPE3, +}; + +struct spdk_dif { + uint16_t guard; + uint16_t app_tag; + uint32_t ref_tag; +}; +SPDK_STATIC_ASSERT(sizeof(struct spdk_dif) == 8, "Incorrect size"); + +/** + * Generate DIF for extended LBA payload. + * + * \param iovs iovec array describing the extended LBA payload. + * \param iovcnt Number of elements in the iovec array. + * \param block_size Block size in a block. + * \param md_size Metadata size in a block. + * \param num_blocks Number of blocks of the payload. + * \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata. + * If false, DIF is in the first 8 bytes of metadata. + * \param dif_type Type of DIF. + * \param dif_flags Flag to specify the DIF action. + * \param init_ref_tag Initial Reference Tag. For type 1, this is the + * starting block address. + * \param app_tag Application Tag. + * + * \return 0 on success and negated errno otherwise. + */ +int spdk_dif_generate(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t app_tag); + +/** + * Verify DIF for extended LBA payload. + * + * \param iovs iovec array describing the extended LBA payload. + * \param iovcnt Number of elements in the iovec array. + * \param block_size Block size in a block. + * \param md_size Metadata size in a block. + * \param num_blocks Number of blocks of the payload. + * \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata. + * If false, DIF is set in the first 8 bytes of metadata. + * \param dif_type Type of DIF. + * \param dif_flags Flag to specify the DIF action. + * \param init_ref_tag Initial Reference Tag. For type 1, this is the + * starting block address. + * \param apptag_mask Application Tag Mask. + * \param app_tag Application Tag. + * + * \return 0 on success and negated errno otherwise. + */ +int spdk_dif_verify(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag); +#endif /* SPDK_DIF_H */ diff --git a/lib/util/Makefile b/lib/util/Makefile index c31a506beb..ce9182583b 100644 --- a/lib/util/Makefile +++ b/lib/util/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c fd.c strerror_tls.c string.c uuid.c +C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c dif.c fd.c strerror_tls.c string.c uuid.c LIBNAME = util LOCAL_SYS_LIBS = -luuid diff --git a/lib/util/dif.c b/lib/util/dif.c new file mode 100644 index 0000000000..a152b9272e --- /dev/null +++ b/lib/util/dif.c @@ -0,0 +1,509 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/dif.h" +#include "spdk/crc16.h" +#include "spdk/endian.h" +#include "spdk/log.h" +#include "spdk/util.h" + +static bool +_are_iovs_bytes_multiple(struct iovec *iovs, int iovcnt, uint32_t bytes) +{ + int i; + + for (i = 0; i < iovcnt; i++) { + if (iovs[i].iov_len % bytes) { + return false; + } + } + + return true; +} + +static bool +_are_iovs_valid(struct iovec *iovs, int iovcnt, uint32_t bytes) +{ + uint64_t total = 0; + int i; + + for (i = 0; i < iovcnt; i++) { + total += iovs[i].iov_len; + } + + return total >= bytes; +} + +static bool +_dif_type_is_valid(enum spdk_dif_type dif_type, uint32_t dif_flags) +{ + switch (dif_type) { + case SPDK_DIF_TYPE1: + case SPDK_DIF_TYPE2: + break; + case SPDK_DIF_TYPE3: + if (dif_flags & SPDK_DIF_REFTAG_CHECK) { + SPDK_ERRLOG("Reference Tag should not be checked for Type 3\n"); + return false; + } + break; + default: + SPDK_ERRLOG("Unknown DIF Type: %d\n", dif_type); + return false; + } + + return true; +} + +static uint32_t +_get_dif_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc) +{ + if (dif_loc) { + /* For metadata formats with more than 8 bytes, if the DIF is + * contained in the last 8 bytes of metadata, then the CRC + * covers all metadata up to but excluding these last 8 bytes. + */ + return block_size - sizeof(struct spdk_dif); + } else { + /* For metadata formats with more than 8 bytes, if the DIF is + * contained in the first 8 bytes of metadata, then the CRC + * does not cover any metadata. + */ + return block_size - md_size; + } +} + +static void +_dif_generate(void *_dif, uint32_t dif_flags, + uint16_t guard, uint32_t ref_tag, uint16_t app_tag) +{ + struct spdk_dif *dif = _dif; + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + to_be16(&dif->guard, guard); + } + + if (dif_flags & SPDK_DIF_APPTAG_CHECK) { + to_be16(&dif->app_tag, app_tag); + } + + if (dif_flags & SPDK_DIF_REFTAG_CHECK) { + to_be32(&dif->ref_tag, ref_tag); + } +} + +static void +dif_generate(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, + enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t app_tag) +{ + uint32_t offset_blocks, iov_offset, ref_tag; + int iovpos; + void *buf; + uint16_t guard = 0; + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + /* For type 1 and 2, the reference tag is incremented for each + * subsequent logical block. For type 3, the reference tag + * remains the same as the initial reference tag. + */ + if (dif_type != SPDK_DIF_TYPE3) { + ref_tag = init_ref_tag + offset_blocks; + } else { + ref_tag = init_ref_tag; + } + + buf = iovs[iovpos].iov_base + iov_offset; + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + guard = spdk_crc16_t10dif(0, buf, guard_interval); + } + + _dif_generate(buf + guard_interval, dif_flags, guard, ref_tag, + app_tag); + + iov_offset += block_size; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_blocks++; + } +} + +static void +dif_generate_split(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, + enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t app_tag) +{ + uint32_t offset_blocks, offset_in_block, offset_in_dif; + uint32_t iov_offset, buf_len, ref_tag; + int iovpos; + void *buf; + uint16_t guard; + struct spdk_dif dif = {}; + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + /* For type 1 and 2, the reference tag is incremented for each + * subsequent logical block. For type 3, the reference tag + * remains the same as the initial reference tag. + */ + if (dif_type != SPDK_DIF_TYPE3) { + ref_tag = init_ref_tag + offset_blocks; + } else { + ref_tag = init_ref_tag; + } + + guard = 0; + offset_in_block = 0; + + while (offset_in_block < block_size && iovpos < iovcnt) { + buf = iovs[iovpos].iov_base + iov_offset; + buf_len = iovs[iovpos].iov_len - iov_offset; + + if (offset_in_block < guard_interval) { + buf_len = spdk_min(buf_len, guard_interval - offset_in_block); + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + /* Compute CRC over split logical block data. */ + guard = spdk_crc16_t10dif(guard, buf, buf_len); + } + + if (offset_in_block + buf_len == guard_interval) { + /* If a whole logical block data is parsed, generate DIF + * and save it to the temporary DIF area. + */ + _dif_generate(&dif, dif_flags, guard, ref_tag, app_tag); + } + } else if (offset_in_block < guard_interval + sizeof(struct spdk_dif)) { + /* Copy generated DIF to the split DIF field. */ + offset_in_dif = offset_in_block - guard_interval; + buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); + + memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len); + } else { + /* Skip metadata field after DIF field. */ + buf_len = spdk_min(buf_len, block_size - offset_in_block); + } + + iov_offset += buf_len; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_in_block += buf_len; + } + offset_blocks++; + } +} + +int +spdk_dif_generate(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t app_tag) +{ + uint32_t guard_interval; + + if (md_size == 0) { + return -EINVAL; + } + + if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) { + SPDK_ERRLOG("Size of iovec array is not valid.\n"); + return -EINVAL; + } + + if (!_dif_type_is_valid(dif_type, dif_flags)) { + SPDK_ERRLOG("DIF type is invalid.\n"); + return -EINVAL; + } + + guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc); + + if (_are_iovs_bytes_multiple(iovs, iovcnt, block_size)) { + dif_generate(iovs, iovcnt, block_size, guard_interval, num_blocks, + dif_type, dif_flags, init_ref_tag, app_tag); + } else { + dif_generate_split(iovs, iovcnt, block_size, guard_interval, num_blocks, + dif_type, dif_flags, init_ref_tag, app_tag); + } + + return 0; +} + +static int +_dif_verify(void *_dif, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint16_t guard, uint32_t ref_tag, uint16_t apptag_mask, uint16_t app_tag) +{ + struct spdk_dif *dif = _dif; + uint16_t _guard; + uint16_t _app_tag; + uint32_t _ref_tag; + + switch (dif_type) { + case SPDK_DIF_TYPE1: + case SPDK_DIF_TYPE2: + /* If Type 1 or 2 is used, then all DIF checks are disabled when + * the Application Tag is 0xFFFF. + */ + if (dif->app_tag == 0xFFFF) { + return 0; + } + break; + case SPDK_DIF_TYPE3: + /* If Type 3 is used, then all DIF checks are disabled when the + * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF. + */ + if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) { + return 0; + } + } + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + /* Compare the DIF Guard field to the CRC computed over the logical + * block data. + */ + _guard = from_be16(&dif->guard); + if (_guard != guard) { + SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \ + " Expected=%x, Actual=%x\n", + ref_tag, _guard, guard); + return -1; + } + } + + if (dif_flags & SPDK_DIF_APPTAG_CHECK) { + /* Compare unmasked bits in the DIF Application Tag field to the + * passed Application Tag. + */ + _app_tag = from_be16(&dif->app_tag); + if ((_app_tag & apptag_mask) != app_tag) { + SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \ + " Expected=%x, Actual=%x\n", + ref_tag, app_tag, (_app_tag & apptag_mask)); + return -1; + } + } + + if (dif_flags & SPDK_DIF_REFTAG_CHECK) { + switch (dif_type) { + case SPDK_DIF_TYPE1: + case SPDK_DIF_TYPE2: + /* Compare the DIF Reference Tag field to the passed Reference Tag. + * The passed Reference Tag will be the least significant 4 bytes + * of the LBA when Type 1 is used, and application specific value + * if Type 2 is used, + */ + _ref_tag = from_be32(&dif->ref_tag); + if (_ref_tag != ref_tag) { + SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ + " Expected=%x, Actual=%x\n", + ref_tag, ref_tag, _ref_tag); + return -1; + } + break; + case SPDK_DIF_TYPE3: + /* For Type 3, computed Reference Tag remains unchanged. + * Hence ignore the Reference Tag field. + */ + break; + } + } + + return 0; +} + +static int +dif_verify(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, + enum spdk_dif_type dif_type, uint32_t dif_flags, uint32_t init_ref_tag, + uint16_t apptag_mask, uint16_t app_tag) +{ + uint32_t offset_blocks, iov_offset, ref_tag; + int iovpos, rc; + void *buf; + uint16_t guard = 0; + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + /* For type 1 and 2, the reference tag is incremented for each + * subsequent logical block. For type 3, the reference tag + * remains the same as the initial reference tag. + */ + if (dif_type != SPDK_DIF_TYPE3) { + ref_tag = init_ref_tag + offset_blocks; + } else { + ref_tag = init_ref_tag; + } + + buf = iovs[iovpos].iov_base + iov_offset; + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + guard = spdk_crc16_t10dif(0, buf, guard_interval); + } + + rc = _dif_verify(buf + guard_interval, dif_type, dif_flags, + guard, ref_tag, apptag_mask, app_tag); + if (rc != 0) { + return rc; + } + + iov_offset += block_size; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_blocks++; + } + + return 0; +} + +static int +dif_verify_split(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, + enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag) +{ + uint32_t offset_blocks, offset_in_block, offset_in_dif; + uint32_t iov_offset, buf_len, ref_tag = 0; + int iovpos, rc; + void *buf; + uint16_t guard; + struct spdk_dif dif = {}; + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + /* For type 1 and 2, the reference tag is incremented for each + * subsequent logical block. For type 3, the reference tag + * remains the same as the initial reference tag. + */ + if (dif_type != SPDK_DIF_TYPE3) { + ref_tag = init_ref_tag + offset_blocks; + } else { + ref_tag = init_ref_tag; + } + + guard = 0; + offset_in_block = 0; + + while (offset_in_block < block_size && iovpos < iovcnt) { + buf = iovs[iovpos].iov_base + iov_offset; + buf_len = iovs[iovpos].iov_len - iov_offset; + + if (offset_in_block < guard_interval) { + buf_len = spdk_min(buf_len, guard_interval - offset_in_block); + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + /* Compute CRC over split logical block data. */ + guard = spdk_crc16_t10dif(guard, buf, buf_len); + } + } else if (offset_in_block < guard_interval + sizeof(struct spdk_dif)) { + /* Copy the split DIF field to the temporary DIF buffer. */ + offset_in_dif = offset_in_block - guard_interval; + buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); + + memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len); + } else { + /* Skip metadata field after DIF field. */ + buf_len = spdk_min(buf_len, block_size - offset_in_block); + } + + iov_offset += buf_len; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_in_block += buf_len; + } + + rc = _dif_verify(&dif, dif_type, dif_flags, guard, ref_tag, apptag_mask, app_tag); + if (rc != 0) { + return 0; + } + + offset_blocks++; + } + + return 0; +} + +int +spdk_dif_verify(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag) +{ + uint32_t guard_interval; + + if (md_size == 0) { + return -EINVAL; + } + + if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) { + SPDK_ERRLOG("Size of iovec array is not valid.\n"); + return -EINVAL; + } + + if (!_dif_type_is_valid(dif_type, dif_flags)) { + SPDK_ERRLOG("DIF type is invalid.\n"); + return -EINVAL; + } + + guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc); + + if (_are_iovs_bytes_multiple(iovs, iovcnt, block_size)) { + return dif_verify(iovs, iovcnt, block_size, guard_interval, num_blocks, + dif_type, dif_flags, init_ref_tag, apptag_mask, app_tag); + } else { + return dif_verify_split(iovs, iovcnt, block_size, guard_interval, num_blocks, + dif_type, dif_flags, init_ref_tag, apptag_mask, app_tag); + } +} diff --git a/test/unit/lib/util/Makefile b/test/unit/lib/util/Makefile index 4813e63b75..a84d446499 100644 --- a/test/unit/lib/util/Makefile +++ b/test/unit/lib/util/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -DIRS-y = base64.c bit_array.c cpuset.c crc16.c crc32_ieee.c crc32c.c string.c +DIRS-y = base64.c bit_array.c cpuset.c crc16.c crc32_ieee.c crc32c.c dif.c string.c .PHONY: all clean $(DIRS-y) diff --git a/test/unit/lib/util/dif.c/.gitignore b/test/unit/lib/util/dif.c/.gitignore new file mode 100644 index 0000000000..040b296b73 --- /dev/null +++ b/test/unit/lib/util/dif.c/.gitignore @@ -0,0 +1 @@ +dif_ut diff --git a/test/unit/lib/util/dif.c/Makefile b/test/unit/lib/util/dif.c/Makefile new file mode 100644 index 0000000000..a27be1d7cd --- /dev/null +++ b/test/unit/lib/util/dif.c/Makefile @@ -0,0 +1,39 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +TEST_FILE = dif_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/test/unit/lib/util/dif.c/dif_ut.c b/test/unit/lib/util/dif.c/dif_ut.c new file mode 100644 index 0000000000..2acb85cf91 --- /dev/null +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -0,0 +1,613 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" + +#include "util/dif.c" + +#define DATA_PATTERN 0xAB + +static int +ut_data_pattern_generate(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks) +{ + uint32_t offset_blocks, offset_in_block, iov_offset, buf_len; + int iovpos; + void *buf; + + if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) { + return -1; + } + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + offset_in_block = 0; + while (offset_in_block < block_size && iovpos < iovcnt) { + buf = iovs[iovpos].iov_base + iov_offset; + buf_len = iovs[iovpos].iov_len - iov_offset; + if (offset_in_block < block_size - md_size) { + buf_len = spdk_min(buf_len, + block_size - md_size - offset_in_block); + memset(buf, DATA_PATTERN, buf_len); + } else { + buf_len = spdk_min(buf_len, block_size - offset_in_block); + memset(buf, 0, buf_len); + } + iov_offset += buf_len; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_in_block += buf_len; + } + offset_blocks++; + } + + return 0; +} + +static int +ut_data_pattern_verify(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks) +{ + uint32_t offset_blocks, offset_in_block, iov_offset, buf_len, i; + int iovpos; + uint8_t *buf; + + if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) { + return -1; + } + + offset_blocks = 0; + iov_offset = 0; + iovpos = 0; + + while (offset_blocks < num_blocks && iovpos < iovcnt) { + offset_in_block = 0; + while (offset_in_block < block_size && iovpos < iovcnt) { + buf = iovs[iovpos].iov_base + iov_offset; + buf_len = iovs[iovpos].iov_len - iov_offset; + + if (offset_in_block < block_size - md_size) { + buf_len = spdk_min(buf_len, + block_size - md_size - offset_in_block); + for (i = 0; i < buf_len; i++) { + if (buf[i] != DATA_PATTERN) { + return -1; + } + } + } else { + buf_len = spdk_min(buf_len, block_size - offset_in_block); + } + iov_offset += buf_len; + if (iov_offset == iovs[iovpos].iov_len) { + iovpos++; + iov_offset = 0; + } + offset_in_block += buf_len; + } + offset_blocks++; + } + + return 0; +} + +static void +_iov_alloc_buf(struct iovec *iov, uint32_t len) +{ + iov->iov_base = calloc(1, len); + iov->iov_len = len; + SPDK_CU_ASSERT_FATAL(iov->iov_base != NULL); +} + +static void +_iov_free_buf(struct iovec *iov) +{ + free(iov->iov_base); +} + +static void +_dif_generate_and_verify(struct iovec *iov, + uint32_t block_size, uint32_t md_size, uint32_t guard_interval, + enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t ref_tag, uint32_t e_ref_tag, + uint16_t app_tag, uint16_t apptag_mask, uint16_t e_app_tag, + bool expect_pass) +{ + int rc; + uint16_t guard = 0; + + rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1); + CU_ASSERT(rc == 0); + + if (dif_flags & SPDK_DIF_GUARD_CHECK) { + guard = spdk_crc16_t10dif(0, iov->iov_base, guard_interval); + } + + _dif_generate(iov->iov_base + guard_interval, dif_flags, guard, ref_tag, app_tag); + + rc = _dif_verify(iov->iov_base + guard_interval, dif_type, dif_flags, + guard, e_ref_tag, apptag_mask, e_app_tag); + CU_ASSERT((expect_pass && rc == 0) || (!expect_pass && rc != 0)); + + rc = ut_data_pattern_verify(iov, 1, block_size, md_size, 1); + CU_ASSERT(rc == 0); +} + +static void +dif_generate_and_verify_test(void) +{ + struct iovec iov; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iov, 4096 + 128); + + /* Positive cases */ + + /* The case that DIF is contained in the first 8 bytes of metadata. */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE1, dif_flags, + 22, 22, + 0x22, 0xFFFF, 0x22, + true); + + /* The case that DIF is contained in the last 8 bytes of metadata. */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096 + 128 - 8, + SPDK_DIF_TYPE1, dif_flags, + 22, 22, + 0x22, 0xFFFF, 0x22, + true); + + /* Negative cases */ + + /* Reference tag doesn't match. */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE1, dif_flags, + 22, 23, + 0x22, 0xFFFF, 0x22, + false); + + /* Application tag doesn't match. */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE1, dif_flags, + 22, 22, + 0x22, 0xFFFF, 0x23, + false); + + _iov_free_buf(&iov); +} + +static void +dif_disable_check_test(void) +{ + struct iovec iov; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iov, 4096 + 128); + + /* The case that DIF check is disabled when the Application Tag is 0xFFFF for + * Type 1. DIF check is disabled and pass is expected. + */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE1, dif_flags, + 22, 22, + 0xFFFF, 0xFFFF, 0x22, + true); + + /* The case that DIF check is not disabled when the Application Tag is 0xFFFF but + * the Reference Tag is not 0xFFFFFFFF for Type 3. DIF check is not disabled and + * fail is expected. + */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE3, dif_flags, + 22, 22, + 0xFFFF, 0xFFFF, 0x22, + false); + + /* The case that DIF check is disabled when the Application Tag is 0xFFFF and + * the Reference Tag is 0xFFFFFFFF for Type 3. DIF check is disabled and + * pass is expected. + */ + _dif_generate_and_verify(&iov, + 4096 + 128, 128, 4096, + SPDK_DIF_TYPE3, dif_flags, + 0xFFFFFFFF, 22, + 0xFFFF, 0xFFFF, 0x22, + true); + + _iov_free_buf(&iov); +} + +static void +dif_sec_512_md_0_error_test(void) +{ + struct iovec iov = {}; + int rc; + + /* Metadata size is 0. */ + rc = spdk_dif_generate(&iov, 1, 512, 0, 1, false, SPDK_DIF_TYPE1, 0, 0, 0); + CU_ASSERT(rc != 0); + + rc = spdk_dif_verify(&iov, 1, 512, 0, 1, false, SPDK_DIF_TYPE1, 0, 0, 0, 0); + CU_ASSERT(rc != 0); +} + +static void +dif_generate_and_verify(struct iovec *iovs, int iovcnt, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, + uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag) +{ + int rc; + + rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate(iovs, iovcnt, block_size, md_size, num_blocks, + dif_loc, dif_type, dif_flags, + init_ref_tag, app_tag); + CU_ASSERT(rc == 0); + + rc = spdk_dif_verify(iovs, iovcnt, block_size, md_size, num_blocks, + dif_loc, dif_type, dif_flags, + init_ref_tag, apptag_mask, app_tag); + CU_ASSERT(rc == 0); + + rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks); + CU_ASSERT(rc == 0); +} + +static void +dif_sec_512_md_8_prchk_0_single_iov_test(void) +{ + struct iovec iov; + + _iov_alloc_buf(&iov, (512 + 8) * 4); + + dif_generate_and_verify(&iov, 1, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, 0, 0, 0, 0); + + _iov_free_buf(&iov); +} + +static void +dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test(void) +{ + struct iovec iovs[4]; + int i, num_blocks; + + num_blocks = 0; + + for (i = 0; i < 4; i++) { + _iov_alloc_buf(&iovs[i], (512 + 8) * (i + 1)); + num_blocks += i + 1; + } + + dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1, + 0, 22, 0xFFFF, 0x22); + + dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1, + SPDK_DIF_GUARD_CHECK, 22, 0xFFFF, 0x22); + + dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1, + SPDK_DIF_APPTAG_CHECK, 22, 0xFFFF, 0x22); + + dif_generate_and_verify(iovs, 4, 512 + 8, 8, num_blocks, false, SPDK_DIF_TYPE1, + SPDK_DIF_REFTAG_CHECK, 22, 0xFFFF, 0x22); + + for (i = 0; i < 4; i++) { + _iov_free_buf(&iovs[i]); + } +} + +static void +dif_sec_4096_md_128_prchk_7_multi_iovs_test(void) +{ + struct iovec iovs[4]; + int i, num_blocks; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + num_blocks = 0; + + for (i = 0; i < 4; i++) { + _iov_alloc_buf(&iovs[i], (4096 + 128) * (i + 1)); + num_blocks += i + 1; + } + + dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + dif_generate_and_verify(iovs, 4, 4096 + 128, 128, num_blocks, true, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + for (i = 0; i < 4; i++) { + _iov_free_buf(&iovs[i]); + } +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test(void) +{ + struct iovec iovs[2]; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iovs[0], 512); + _iov_alloc_buf(&iovs[1], 8); + + dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + _iov_free_buf(&iovs[0]); + _iov_free_buf(&iovs[1]); +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test(void) +{ + struct iovec iovs[2]; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iovs[0], 256); + _iov_alloc_buf(&iovs[1], 264); + + dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + _iov_free_buf(&iovs[0]); + _iov_free_buf(&iovs[1]); +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test(void) +{ + struct iovec iovs[2]; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iovs[0], 513); + _iov_alloc_buf(&iovs[1], 7); + + dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + _iov_free_buf(&iovs[0]); + _iov_free_buf(&iovs[1]); +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test(void) +{ + struct iovec iovs[2]; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iovs[0], 515); + _iov_alloc_buf(&iovs[1], 5); + + dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + _iov_free_buf(&iovs[0]); + _iov_free_buf(&iovs[1]); +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test(void) +{ + struct iovec iovs[2]; + uint32_t dif_flags; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + _iov_alloc_buf(&iovs[0], 518); + _iov_alloc_buf(&iovs[1], 2); + + dif_generate_and_verify(iovs, 2, 512 + 8, 8, 1, false, SPDK_DIF_TYPE1, + dif_flags, 22, 0xFFFF, 0x22); + + _iov_free_buf(&iovs[0]); + _iov_free_buf(&iovs[1]); +} + +static void +dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test(void) +{ + struct iovec iovs[9]; + uint32_t dif_flags; + int i; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + /* data[0][255:0] */ + _iov_alloc_buf(&iovs[0], 256); + + /* data[0][511:256], guard[0][0] */ + _iov_alloc_buf(&iovs[1], 256 + 1); + + /* guard[0][1], apptag[0][0] */ + _iov_alloc_buf(&iovs[2], 1 + 1); + + /* apptag[0][1], reftag[0][0] */ + _iov_alloc_buf(&iovs[3], 1 + 1); + + /* reftag[0][3:1], data[1][255:0] */ + _iov_alloc_buf(&iovs[4], 3 + 256); + + /* data[1][511:256], guard[1][0] */ + _iov_alloc_buf(&iovs[5], 256 + 1); + + /* guard[1][1], apptag[1][0] */ + _iov_alloc_buf(&iovs[6], 1 + 1); + + /* apptag[1][1], reftag[1][0] */ + _iov_alloc_buf(&iovs[7], 1 + 1); + + /* reftag[1][3:1] */ + _iov_alloc_buf(&iovs[8], 3); + + dif_generate_and_verify(iovs, 9, 512 + 8, 8, 2, false, SPDK_DIF_TYPE1, dif_flags, + 22, 0xFFFF, 0x22); + + for (i = 0; i < 9; i++) { + _iov_free_buf(&iovs[i]); + } +} + +static void +dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test(void) +{ + struct iovec iovs[11]; + uint32_t dif_flags; + int i; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + /* data[0][1000:0] */ + _iov_alloc_buf(&iovs[0], 1000); + + /* data[0][3095:1000], guard[0][0] */ + _iov_alloc_buf(&iovs[1], 3096 + 1); + + /* guard[0][1], apptag[0][0] */ + _iov_alloc_buf(&iovs[2], 1 + 1); + + /* apptag[0][1], reftag[0][0] */ + _iov_alloc_buf(&iovs[3], 1 + 1); + + /* reftag[0][3:1], ignore[0][59:0] */ + _iov_alloc_buf(&iovs[4], 3 + 60); + + /* ignore[119:60], data[1][3050:0] */ + _iov_alloc_buf(&iovs[5], 60 + 3051); + + /* data[1][4095:3050], guard[1][0] */ + _iov_alloc_buf(&iovs[6], 1045 + 1); + + /* guard[1][1], apptag[1][0] */ + _iov_alloc_buf(&iovs[7], 1 + 1); + + /* apptag[1][1], reftag[1][0] */ + _iov_alloc_buf(&iovs[8], 1 + 1); + + /* reftag[1][3:1], ignore[1][9:0] */ + _iov_alloc_buf(&iovs[9], 3 + 10); + + /* ignore[1][127:9] */ + _iov_alloc_buf(&iovs[10], 118); + + dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, false, SPDK_DIF_TYPE1, dif_flags, + 22, 0xFFFF, 0x22); + dif_generate_and_verify(iovs, 11, 4096 + 128, 128, 2, true, SPDK_DIF_TYPE1, dif_flags, + 22, 0xFFFF, 0x22); + + for (i = 0; i < 11; i++) { + _iov_free_buf(&iovs[i]); + } +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("dif", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "dif_generate_and_verify_test", dif_generate_and_verify_test) == NULL || + CU_add_test(suite, "dif_disable_check_test", dif_disable_check_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_0_error_test", dif_sec_512_md_0_error_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_0_single_iov_test", + dif_sec_512_md_8_prchk_0_single_iov_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test", + dif_sec_512_md_8_prchk_0_1_2_4_multi_iovs_test) == NULL || + CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_test", + dif_sec_4096_md_128_prchk_7_multi_iovs_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test", + dif_sec_512_md_8_prchk_7_multi_iovs_split_data_and_md_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test", + dif_sec_512_md_8_prchk_7_multi_iovs_split_data_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test", + dif_sec_512_md_8_prchk_7_multi_iovs_split_guard_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test", + dif_sec_512_md_8_prchk_7_multi_iovs_split_apptag_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test", + dif_sec_512_md_8_prchk_7_multi_iovs_split_reftag_test) == NULL || + CU_add_test(suite, "dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test", + dif_sec_512_md_8_prchk_7_multi_iovs_complex_splits_test) == NULL || + CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test", + dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_test) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + + CU_basic_run_tests(); + + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/test/unit/unittest.sh b/test/unit/unittest.sh index df5f4f4ef6..7a079a4f79 100755 --- a/test/unit/unittest.sh +++ b/test/unit/unittest.sh @@ -137,6 +137,7 @@ $valgrind $testdir/lib/util/crc16.c/crc16_ut $valgrind $testdir/lib/util/crc32_ieee.c/crc32_ieee_ut $valgrind $testdir/lib/util/crc32c.c/crc32c_ut $valgrind $testdir/lib/util/string.c/string_ut +$valgrind $testdir/lib/util/dif.c/dif_ut if [ $(uname -s) = Linux ]; then $valgrind $testdir/lib/vhost/vhost.c/vhost_ut