From ff4a4153cb70c584a50faea34d9f49f35e2aa7e1 Mon Sep 17 00:00:00 2001 From: Matt Benjamin Date: Mon, 17 Feb 2025 20:26:33 -0500 Subject: [PATCH] rgw_cksum: prototype support for CRC64NVME Support uses conditionally compiled implementations from spdk and ISA-L. Validated against SPDK test vectors and one example generated and passed via awscliv2 (AWS SDK) version 2.24.5. Restored the ability of unittest_rgw_cksum to create a binary input file for external checksum testing, but only when requested via cmdline option. Fixes: https://tracker.ceph.com/issues/70040 Signed-off-by: Matt Benjamin --- src/crypto/isa-l/CMakeLists.txt | 2 + src/rgw/CMakeLists.txt | 6 +++ src/rgw/rgw_cksum.h | 4 +- src/rgw/rgw_cksum_digest.h | 8 ++- src/rgw/rgw_cksum_pipe.cc | 4 +- src/rgw/rgw_crc_digest.h | 26 ++++++++++ src/rgw/spdk/crc64.c | 2 +- src/rgw/spdk/crc64.h | 5 ++ src/rgw/spdk/crc_internal.h | 2 + src/test/rgw/test_rgw_cksum.cc | 86 ++++++++++++++++++++++++++++++++- 10 files changed, 139 insertions(+), 6 deletions(-) diff --git a/src/crypto/isa-l/CMakeLists.txt b/src/crypto/isa-l/CMakeLists.txt index af8f7e185c8..b7b2e3006c7 100644 --- a/src/crypto/isa-l/CMakeLists.txt +++ b/src/crypto/isa-l/CMakeLists.txt @@ -1,4 +1,6 @@ # build isa-l_crypto from its makefile and expose as target ISAL::Crypto +set(CEPH_HAVE_ISAL, TRUE) + include(BuildISALCrypto) build_isal_crypto() diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 41e473e23f0..a4f154b6190 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -19,6 +19,11 @@ if(WITH_RADOSGW_ARROW_FLIGHT) message("-- arrow flight is installed") endif(WITH_RADOSGW_ARROW_FLIGHT) +if(CEPH_HAVE_ISAL) + message("-- building RGW with ISA-L support") + add_definitions(-DSPDK_CONFIG_ISAL) +endif() + function(gperf_generate input output) add_custom_command( OUTPUT ${output} @@ -51,6 +56,7 @@ set(librgw_common_srcs services/svc_user_rados.cc services/svc_zone.cc services/svc_zone_utils.cc + spdk/crc64.c rgw_account.cc rgw_acl.cc rgw_acl_s3.cc diff --git a/src/rgw/rgw_cksum.h b/src/rgw/rgw_cksum.h index 955b553f27d..900a1046d19 100644 --- a/src/rgw/rgw_cksum.h +++ b/src/rgw/rgw_cksum.h @@ -45,6 +45,7 @@ namespace rgw { namespace cksum { sha256, sha512, blake3, + crc64nvme, }; static constexpr uint16_t FLAG_NONE = 0x0000; @@ -80,7 +81,7 @@ namespace rgw { namespace cksum { class Cksum { public: - static constexpr std::array checksums = + static constexpr std::array checksums = { Desc(Type::none, "none", 0, FLAG_NONE), Desc(Type::crc32, "crc32", 4, FLAG_AWS_CKSUM), @@ -90,6 +91,7 @@ namespace rgw { namespace cksum { Desc(Type::sha256, "sha256", 32, FLAG_AWS_CKSUM), Desc(Type::sha512, "sha512", 64, FLAG_NONE), Desc(Type::blake3, "blake3", 32, FLAG_NONE), + Desc(Type::crc64nvme, "crc64nvme", 8, FLAG_AWS_CKSUM), }; static constexpr uint16_t max_digest_size = 64; diff --git a/src/rgw/rgw_cksum_digest.h b/src/rgw/rgw_cksum_digest.h index ba7e3bd58c6..33f9a629519 100644 --- a/src/rgw/rgw_cksum_digest.h +++ b/src/rgw/rgw_cksum_digest.h @@ -63,6 +63,7 @@ namespace rgw { namespace cksum { typedef TDigest SHA1; typedef TDigest SHA256; typedef TDigest SHA512; + typedef TDigest Crc64Nvme; typedef boost::variant DigestVariant; + SHA512, + Crc64Nvme> DigestVariant; struct get_digest_ptr : public boost::static_visitor { @@ -84,6 +86,7 @@ namespace rgw { namespace cksum { Digest* operator()(SHA1& digest) const { return &digest; } Digest* operator()(SHA256& digest) const { return &digest; } Digest* operator()(SHA512& digest) const { return &digest; } + Digest* operator()(Crc64Nvme& digest) const { return &digest; } }; static inline Digest* get_digest(DigestVariant& ev) @@ -106,6 +109,9 @@ namespace rgw { namespace cksum { case Type::crc32c: return Crc32c(); break; + case Type::crc64nvme: + return Crc64Nvme(); + break; case Type::xxh3: return XXH3(); break; diff --git a/src/rgw/rgw_cksum_pipe.cc b/src/rgw/rgw_cksum_pipe.cc index 32b93755f5d..da60c2071f9 100644 --- a/src/rgw/rgw_cksum_pipe.cc +++ b/src/rgw/rgw_cksum_pipe.cc @@ -49,7 +49,8 @@ namespace rgw::putobj { std::make_unique( next, cksum_type, std::move(algo_header)); } else { - return std::unique_ptr(); + /* unknown checksum type requested */ + throw rgw::io::Exception(EINVAL, std::system_category()); } } /* malformed checksum algorithm header(s) */ @@ -63,6 +64,7 @@ namespace rgw::putobj { std::make_unique( next, override_type, std::move(algo_header)); } + /* no checksum requested */ return std::unique_ptr(); } diff --git a/src/rgw/rgw_crc_digest.h b/src/rgw/rgw_crc_digest.h index 8e97df56b48..15e488152cd 100644 --- a/src/rgw/rgw_crc_digest.h +++ b/src/rgw/rgw_crc_digest.h @@ -22,6 +22,7 @@ #include #include "include/crc32c.h" #include +#include "spdk/crc64.h" namespace rgw { namespace digest { @@ -90,4 +91,29 @@ namespace rgw { namespace digest { memcpy((char*) digest, &crc, sizeof(crc)); } }; /* Crc32c */ + + class Crc64Nvme { + private: + uint64_t crc; + + public: + static constexpr uint16_t digest_size = 8; + static constexpr uint64_t initial_value = 0x0; + + Crc64Nvme() { Restart(); } + + void Restart() { crc = initial_value; } + + void Update(const unsigned char *data, uint64_t len) { + crc = spdk_crc64_nvme(data, len, crc); + } + + void Final(unsigned char* digest) { + if constexpr (std::endian::native != std::endian::big) { + crc = rgw::digest::byteswap(crc); + } + memcpy((char*) digest, &crc, sizeof(crc)); + } + }; /* Crc64Nvme */ + }} /* namespace */ diff --git a/src/rgw/spdk/crc64.c b/src/rgw/spdk/crc64.c index b1a37af35be..305d8392508 100644 --- a/src/rgw/spdk/crc64.c +++ b/src/rgw/spdk/crc64.c @@ -4,7 +4,7 @@ */ #include "crc_internal.h" -#include "spdk/crc64.h" +#include "crc64.h" #ifdef SPDK_CONFIG_ISAL #include "isa-l/include/crc64.h" diff --git a/src/rgw/spdk/crc64.h b/src/rgw/spdk/crc64.h index 5a3d31915b3..a108acf1639 100644 --- a/src/rgw/spdk/crc64.h +++ b/src/rgw/spdk/crc64.h @@ -11,8 +11,13 @@ #ifndef SPDK_CRC64_H #define SPDK_CRC64_H +#if 0 #include "spdk/stdinc.h" #include "spdk/config.h" +#else +#include +#include +#endif #ifdef __cplusplus extern "C" { diff --git a/src/rgw/spdk/crc_internal.h b/src/rgw/spdk/crc_internal.h index b432d0d7bb4..81836dce0b9 100644 --- a/src/rgw/spdk/crc_internal.h +++ b/src/rgw/spdk/crc_internal.h @@ -6,7 +6,9 @@ #ifndef SPDK_CRC_INTERNAL_H #define SPDK_CRC_INTERNAL_H +#if 0 #include "spdk/config.h" +#endif #ifdef SPDK_CONFIG_ISAL #define SPDK_HAVE_ISAL diff --git a/src/test/rgw/test_rgw_cksum.cc b/src/test/rgw/test_rgw_cksum.cc index 3572f5994fa..4167d8779e9 100644 --- a/src/test/rgw/test_rgw_cksum.cc +++ b/src/test/rgw/test_rgw_cksum.cc @@ -36,6 +36,7 @@ namespace { using namespace rgw::cksum; bool verbose = false; + bool gen_test_data = false; cksum::Type t1 = cksum::Type::blake3; cksum::Type t2 = cksum::Type::sha1; @@ -51,6 +52,24 @@ namespace { std::string dolor = R"(Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.)"; +TEST(RGWCksum, Output) +{ + if (gen_test_data) { + auto o_mode = std::ios::out|std::ios::trunc; + std::ofstream of; + + std::cout << "writing lorem text to /tmp/lorem " << std::endl; + of.open("/tmp/lorem", o_mode); + of << lorem; + of.close(); + + std::cout << "writing dolor text to /tmp/dolor " << std::endl; + of.open("/tmp/dolor", o_mode); + of << dolor; + of.close(); + } +} + TEST(RGWCksum, Ctor) { cksum::Cksum ck1; @@ -328,10 +347,71 @@ TEST(RGWCksum, DigestBL) } /* for t1, ... */ } +TEST(RGWCksum, CRC64NVME1) +{ + /* from SPDK crc64_ut.c */ + unsigned int buf_size = 4096; + char buf[buf_size]; + uint64_t crc; + unsigned int i, j; + + /* All the expected CRC values are compliant with + * the NVM Command Set Specification 1.0c */ + + /* Input buffer = 0s */ + memset(buf, 0, buf_size); + crc = spdk_crc64_nvme(buf, buf_size, 0); + ASSERT_TRUE(crc == 0x6482D367EB22B64E); + + /* Input buffer = 1s */ + memset(buf, 0xFF, buf_size); + crc = spdk_crc64_nvme(buf, buf_size, 0); + ASSERT_TRUE(crc == 0xC0DDBA7302ECA3AC); + + /* Input buffer = 0x00, 0x01, 0x02, ... */ + memset(buf, 0, buf_size); + j = 0; + for (i = 0; i < buf_size; i++) { + buf[i] = (char)j; + if (j == 0xFF) { + j = 0; + } else { + j++; + } + } + crc = spdk_crc64_nvme(buf, buf_size, 0); + ASSERT_TRUE(crc == 0x3E729F5F6750449C); + + /* Input buffer = 0xFF, 0xFE, 0xFD, ... */ + memset(buf, 0, buf_size); + j = 0xFF; + for (i = 0; i < buf_size ; i++) { + buf[i] = (char)j; + if (j == 0) { + j = 0xFF; + } else { + j--; + } + } + crc = spdk_crc64_nvme(buf, buf_size, 0); + ASSERT_TRUE(crc == 0x9A2DF64B8E9E517E); +} +TEST(RGWCksum, CRC64NVME2) +{ + auto t = cksum::Type::crc64nvme; + DigestVariant dv = rgw::cksum::digest_factory(t); + Digest *digest = get_digest(dv); + ASSERT_NE(digest, nullptr); + + digest->Update((const unsigned char *)dolor.c_str(), dolor.length()); + + auto cksum = rgw::cksum::finalize_digest(digest, t); + /* the armored value produced by awscliv2 2.24.5 */ + ASSERT_EQ(cksum.to_armor(), "wiBA+PSv41M="); +} - //foop TEST(RGWCksum, CtorUnarmor) { auto t = cksum::Type::sha256; @@ -357,11 +437,13 @@ int main(int argc, char *argv[]) auto args = argv_to_vec(argc, argv); env_to_vec(args); - std::string val; for (auto arg_iter = args.begin(); arg_iter != args.end();) { if (ceph_argparse_flag(args, arg_iter, "--verbose", (char*) nullptr)) { verbose = true; + } else if (ceph_argparse_flag(args, arg_iter, "--gen_test_data", + (char*) nullptr)) { + gen_test_data = true; } else { ++arg_iter; } -- 2.47.3