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:
parent
cc7a099c0c
commit
8b6c22b1a0
103
include/spdk/dif.h
Normal file
103
include/spdk/dif.h
Normal 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 */
|
@ -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
509
lib/util/dif.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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
1
test/unit/lib/util/dif.c/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dif_ut
|
39
test/unit/lib/util/dif.c/Makefile
Normal file
39
test/unit/lib/util/dif.c/Makefile
Normal 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
|
613
test/unit/lib/util/dif.c/dif_ut.c
Normal file
613
test/unit/lib/util/dif.c/dif_ut.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user