dif: Generate DIF for extended LBA payload

DIF and DIX will be supported in SPDK throughout, e.g., NVMe
driver, NVMe-oF initiator and target, NVMe block device, malloc
block device, SCSI, iSCSI target, FIO plugin, and Perf.

Generic and common APIs to generate and verify DIF and inject
bit flip error to any field will be helpful for them.

This patch is the first in the patch series.

This patch adds APIs to generate and verify DIF for SGL extended
LBA payload as byte alignement and granularity.

Change-Id: Ie6588d960113761f10efbf2d2a3cae004af37ce8
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/432261
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Shuhei Matsumoto 2018-11-27 14:23:38 +09:00 committed by Jim Harris
parent cc7a099c0c
commit 8b6c22b1a0
8 changed files with 1268 additions and 2 deletions

103
include/spdk/dif.h Normal file
View File

@ -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 */

View File

@ -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

509
lib/util/dif.c Normal file
View File

@ -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);
}
}

View File

@ -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)

1
test/unit/lib/util/dif.c/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dif_ut

View File

@ -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

View File

@ -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;
}

View File

@ -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