From patchwork Thu Oct 10 12:33:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Medvedkin, Vladimir" X-Patchwork-Id: 145599 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id CBC2B45B04; Thu, 10 Oct 2024 14:33:47 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4C7F84066C; Thu, 10 Oct 2024 14:33:39 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.14]) by mails.dpdk.org (Postfix) with ESMTP id DD0DB4065A for ; Thu, 10 Oct 2024 14:33:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1728563616; x=1760099616; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uGctXpVvo3elJqYkPDVuDN6PAEHpgYqsz9hKc7eib4I=; b=kVdTM20gZGmQ6Yh2qcDC73dqiDaoPrfn1eD9plmZQuSiR0w7U4b6+Vmf qrS0Lrt+O/KGBJwP1zbaB8i4dp3oKtSs7Afj1eXe8CyZ5US43dvFOQZkI z2u6smkScfiEUJ0a9aUawc3bQp1/Okd2Vgy7uwASF3GtA8ghDX5MZlsVT UgjokqEwrqB7djU3UiFxY+nYTiSEl7GeZuueANCcFHGy9Kvmuv0bEIZE3 vEY6fUzMzkEPcnYJ8dlS2+G21BSKbhs4GNSPVJ1RrMZnB2g4vyHE0Jjkd Rq5cy6R7RPAaWFYiaQfXKVAyc/7Z3biqSznSQn3U/0OZmtkcrV6ZtN+bI Q==; X-CSE-ConnectionGUID: pWcpfChPQfOjSGO+0q/bFg== X-CSE-MsgGUID: 6IHB1c0oQJGA/DqQIa9yOw== X-IronPort-AV: E=McAfee;i="6700,10204,11220"; a="31712323" X-IronPort-AV: E=Sophos;i="6.11,193,1725346800"; d="scan'208";a="31712323" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2024 05:33:36 -0700 X-CSE-ConnectionGUID: jL+p1E5LS1K6rJ7wDdkTDA== X-CSE-MsgGUID: tv1NphWHRdiAT8EP+kEFNA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,193,1725346800"; d="scan'208";a="81101886" Received: from unknown (HELO silpixa00401176.ir.intel.com) ([10.243.22.170]) by fmviesa005.fm.intel.com with ESMTP; 10 Oct 2024 05:33:34 -0700 From: Vladimir Medvedkin To: dev@dpdk.org Cc: stephen@networkplumber.org, Yipeng Wang , Sameh Gobriel , Bruce Richardson Subject: [PATCH v2 2/4] hash: add dynamic polynomial calculation Date: Thu, 10 Oct 2024 12:33:29 +0000 Message-Id: <20241010123331.749004-3-vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241010123331.749004-1-vladimir.medvedkin@intel.com> References: <20241010123331.749004-1-vladimir.medvedkin@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Current polynomial table has the following limitations: 1. It has polynomials up to degree 16 2. For each degree there are only 4 polynomials The above results in less entropy when generating Toeplitz hash key subsequences. This patch replaces the current static table approach with dynamic polynomial calculation for polynomials of degree 7 or higher, resulting in better entropy of generated RSS hash key. Signed-off-by: Vladimir Medvedkin --- lib/hash/meson.build | 1 + lib/hash/rte_thash.c | 46 +----- lib/hash/rte_thash.h | 13 ++ lib/hash/rte_thash_gf2_poly_math.c | 253 +++++++++++++++++++++++++++++ lib/hash/version.map | 1 + 5 files changed, 274 insertions(+), 40 deletions(-) create mode 100644 lib/hash/rte_thash_gf2_poly_math.c diff --git a/lib/hash/meson.build b/lib/hash/meson.build index 277eb9fa93..7ce504ee8b 100644 --- a/lib/hash/meson.build +++ b/lib/hash/meson.build @@ -23,6 +23,7 @@ sources = files( 'rte_fbk_hash.c', 'rte_thash.c', 'rte_thash_gfni.c', + 'rte_thash_gf2_poly_math.c', ) deps += ['net'] diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c index df9b4960ce..f57b275a72 100644 --- a/lib/hash/rte_thash.c +++ b/lib/hash/rte_thash.c @@ -31,33 +31,6 @@ static struct rte_tailq_elem rte_thash_tailq = { }; EAL_REGISTER_TAILQ(rte_thash_tailq) -/** - * Table of some irreducible polinomials over GF(2). - * For lfsr they are represented in BE bit order, and - * x^0 is masked out. - * For example, poly x^5 + x^2 + 1 will be represented - * as (101001b & 11111b) = 01001b = 0x9 - */ -static const uint32_t irreducible_poly_table[][4] = { - {0, 0, 0, 0}, /** < degree 0 */ - {1, 1, 1, 1}, /** < degree 1 */ - {0x3, 0x3, 0x3, 0x3}, /** < degree 2 and so on... */ - {0x5, 0x3, 0x5, 0x3}, - {0x9, 0x3, 0x9, 0x3}, - {0x9, 0x1b, 0xf, 0x5}, - {0x21, 0x33, 0x1b, 0x2d}, - {0x41, 0x11, 0x71, 0x9}, - {0x71, 0xa9, 0xf5, 0x8d}, - {0x21, 0xd1, 0x69, 0x1d9}, - {0x81, 0x2c1, 0x3b1, 0x185}, - {0x201, 0x541, 0x341, 0x461}, - {0x941, 0x609, 0xe19, 0x45d}, - {0x1601, 0x1f51, 0x1171, 0x359}, - {0x2141, 0x2111, 0x2db1, 0x2109}, - {0x4001, 0x801, 0x101, 0x7301}, - {0x7781, 0xa011, 0x4211, 0x86d9}, -}; - struct thash_lfsr { uint32_t ref_cnt; uint32_t poly; @@ -159,28 +132,21 @@ get_rev_bit_lfsr(struct thash_lfsr *lfsr) return ret; } -static inline uint32_t -thash_get_rand_poly(uint32_t poly_degree) -{ - return irreducible_poly_table[poly_degree][rte_rand() % - RTE_DIM(irreducible_poly_table[poly_degree])]; -} - static struct thash_lfsr * -alloc_lfsr(struct rte_thash_ctx *ctx) +alloc_lfsr(uint32_t poly_degree) { struct thash_lfsr *lfsr; uint32_t i; - if (ctx == NULL) + if ((poly_degree > 32) || (poly_degree == 0)) return NULL; lfsr = rte_zmalloc(NULL, sizeof(struct thash_lfsr), 0); if (lfsr == NULL) return NULL; - lfsr->deg = ctx->reta_sz_log; - lfsr->poly = thash_get_rand_poly(lfsr->deg); + lfsr->deg = poly_degree; + lfsr->poly = rte_thash_get_rand_poly(lfsr->deg); do { lfsr->state = rte_rand() & ((1 << lfsr->deg) - 1); } while (lfsr->state == 0); @@ -460,7 +426,7 @@ insert_before(struct rte_thash_ctx *ctx, int ret; if (end < cur_ent->offset) { - ent->lfsr = alloc_lfsr(ctx); + ent->lfsr = alloc_lfsr(ctx->reta_sz_log); if (ent->lfsr == NULL) { rte_free(ent); return -ENOMEM; @@ -613,7 +579,7 @@ rte_thash_add_helper(struct rte_thash_ctx *ctx, const char *name, uint32_t len, continue; } - ent->lfsr = alloc_lfsr(ctx); + ent->lfsr = alloc_lfsr(ctx->reta_sz_log); if (ent->lfsr == NULL) { rte_free(ent); return -ENOMEM; diff --git a/lib/hash/rte_thash.h b/lib/hash/rte_thash.h index 560fc1de73..fca2924d93 100644 --- a/lib/hash/rte_thash.h +++ b/lib/hash/rte_thash.h @@ -108,6 +108,19 @@ union rte_thash_tuple { struct rte_ipv6_tuple v6; }; +/** @internal + * @brief Generates a random polynomial + * + * @param poly_degree + * degree of the polynomial + * + * @return + * random polynomial + */ +__rte_internal +uint32_t +rte_thash_get_rand_poly(uint32_t poly_degree); + /** * Prepare special converted key to use with rte_softrss_be() * @param orig diff --git a/lib/hash/rte_thash_gf2_poly_math.c b/lib/hash/rte_thash_gf2_poly_math.c new file mode 100644 index 0000000000..e6eb1ef3c5 --- /dev/null +++ b/lib/hash/rte_thash_gf2_poly_math.c @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Intel Corporation + */ +#include +#include +#include +#include +#include + +#define MAX_TOEPLITZ_KEY_LENGTH 64 + +/* + * Finite field math for field extensions with irreducing polynomial + * of degree <= 32. + * Polynomials are represented with 2 arguments - uint32_t poly and int degree. + * poly argument does not hold the highest degree coefficient, + * so full polynomial can be expressed as poly|(1ULL << degree). + * The algorithm to produce random irreducible polynomial was inspired by: + * "Computation in finite fields" by John Kerl, Chapter 10.4. + */ + +static const uint32_t irreducible_poly_table[][3] = { + {0, 0, 0}, /* degree 0 */ + {0x1, 0x1, 0x1}, /* degree 1 */ + {0x3, 0x3, 0x3}, /* degree 2 and so on.. */ + {0x3, 0x5, 0x3}, /* x^3+x^2+1(0x5) is reverted x^3+x+1(0x3) */ + {0x3, 0x9, 0x3}, /* x^4+x^3+1(0x9) is reverted x^4+x+1(0x3) */ + {0x5, 0xf, 0x17}, /* 0x5 <-> 0x9; 0xf <-> 0x1d; 0x17 <-> 0x1b */ + {0x3, 0x27, 0x1b}, /* 0x3 <-> 0x21; 0x27 <-> 0x33; 0x1b <-> 0x2d*/ +}; + +/* + * Table of the monic lowest weight irreducible polynomials over GF(2) + * starting from degree 7 up to degree 32. + * Taken from Handbook of Finite Fields by Gary L. Mullen and + * Daniel Penario p.33 Table 2.2.1. + * https://people.math.carleton.ca/~daniel/hff/irred/F2-2to10000.txt + */ +static const uint32_t default_irreducible_poly[] = { + 0x3, /* x^7 + x + 1*/ + 0x1b, /* x^8 + x^4 + x^3 + x + 1 */ + 0x3, /* x^9 + x + 1*/ + 0x9, /* x^10 + x^3 + 1 */ + 0x5, /* x^11 + x^2 + 1 */ + 0x9, /* x^12 + x^3 + 1 */ + 0x1b, /* x^13 + x^4 + x^3 + x + 1 */ + 0x33, /* x^14 + x^5 + 1 */ + 0x3, /* x^15 + x + 1 */ + 0x2b, /* x^16 + x^5 + x^3 + x + 1 */ + 0x9, /* x^17 + x^3 + 1 */ + 0x9, /* x^18 + x^3 + 1 */ + 0x27, /* x^19 + x^5 + x^2 + x + 1 */ + 0x9, /* x^20 + x^3 + 1 */ + 0x5, /* x^21 + x^2 + 1 */ + 0x3, /* x^22 + x + 1 */ + 0x21, /* x^23 + x^5 + 1 */ + 0x1b, /* x^24 + x^4 + x^3 + x + 1 */ + 0x9, /* x^25 + x^3 + 1 */ + 0x1b, /* x^26 + x^4 + x^3 + x + 1 */ + 0x27, /* x^27 + x^5 + x^2 + x + 1 */ + 0x3, /* x^28 + x + 1 */ + 0x5, /* x^29 + x^2 + 1 */ + 0x3, /* x^30 + x + 1 */ + 0x9, /* x^31 + x^3 + 1 */ + 0x8d, /* x^32 + x^7 + x^3 + x^2 + 1 */ +}; + +#define MAX_DIVISORS 28 /* 2^24 - 1 */ + +struct divisors { + uint32_t n; /* number of divisors */ + uint32_t div_arr[MAX_DIVISORS]; +}; + +/* divisors of (2^n - 1) less than MIN(512, 2^n - 1) for all n in [7, 32] */ +static const struct divisors divisors[] = { + { .n = 0, .div_arr = {} }, /* 2^7-1 is Mersenne prime */ + { .n = 6, .div_arr = {3, 5, 15, 17, 51, 85} }, + { .n = 2, .div_arr = {7, 73} }, + { .n = 6, .div_arr = {3, 11, 31, 33, 93, 341} }, + { .n = 2, .div_arr = {23, 89} }, + { .n = 19, .div_arr = {3, 5, 7, 9, 13, 15, 21, 35, 39, 45, 63, 65, 91, + 105, 117, 195, 273, 315, 455} }, + { .n = 0, .div_arr = {} }, /* 2^13-1 is Mersenne prime */ + { .n = 5, .div_arr = {3, 43, 127, 129, 381} }, + { .n = 4, .div_arr = {7, 31, 151, 217} }, + { .n = 8, .div_arr = {3, 5, 15, 17, 51, 85, 255, 257} }, + { .n = 0, .div_arr = {} }, /* 2^17-1 is Mersenne prime */ + { .n = 14, .div_arr = {3, 7, 9, 19, 21, 27, 57, 63, 73, 133, 171, 189, + 219, 399} }, + { .n = 0, .div_arr = {0} }, /* 2^19-1 is Mersenne prime */ + { .n = 19, .div_arr = {3, 5, 11, 15, 25, 31, 33, 41, 55, 75, 93, 123, + 155, 165, 205, 275, 341, 451, 465} }, + { .n = 4, .div_arr = {7, 49, 127, 337} }, + { .n = 5, .div_arr = {3, 23, 69, 89, 267} }, + { .n = 1, .div_arr = {47} }, + { .n = 28, .div_arr = {3, 5, 7, 9, 13, 15, 17, 21, 35, 39, 45, 51, 63, + 65, 85, 91, 105, 117, 119, 153, 195, 221, 241, 255, 273, 315, + 357, 455} }, + { .n = 1, .div_arr = {31} }, + { .n = 1, .div_arr = {3} }, + { .n = 2, .div_arr = {7, 73} }, + { .n = 14, .div_arr = {3, 5, 15, 29, 43, 87, 113, 127, 129, 145, 215, + 339, 381, 435} }, + { .n = 1, .div_arr = {233} }, + { .n = 18, .div_arr = {3, 7, 9, 11, 21, 31, 33, 63, 77, 93, 99, 151, + 217, 231, 279, 331, 341, 453} }, + { .n = 0, .div_arr = {} },/* 2^31-1 is Mersenne prime */ + { .n = 8, .div_arr = {3, 5, 15, 17, 51, 85, 255, 257} }, +}; + +static uint32_t +gf2_mul(uint32_t a, uint32_t b, uint32_t r, int degree) +{ + uint64_t product = 0; + uint64_t r_poly = r|(1ULL << degree); + + for (; b; b &= (b - 1)) + product ^= (uint64_t)a << (rte_bsf32(b)); + + for (int i = degree * 2 - 1; i >= degree; i--) + if (product & (1 << i)) + product ^= r_poly << (i - degree); + + return product; +} + +static uint32_t +gf2_pow(uint32_t a, uint32_t pow, uint32_t r, int degree) +{ + uint32_t result = 1; + unsigned int i; + + for (i = 0; i < (sizeof(pow)*CHAR_BIT - rte_clz32(pow)); i++) { + if (pow & (1 << i)) + result = gf2_mul(result, a, r, degree); + + a = gf2_mul(a, a, r, degree); + } + + return result; +} + +static uint32_t +__thash_get_rand_poly(int poly_degree) +{ + uint32_t roots[poly_degree]; + uint32_t rnd; + uint32_t ret_poly = 0; + int i, j; + bool short_orbit = false; + + /* special case for low degree */ + if (poly_degree < 7) + return irreducible_poly_table[poly_degree][rte_rand() % + RTE_DIM(irreducible_poly_table[poly_degree])]; + + uint32_t r = default_irreducible_poly[poly_degree - 7]; + + do { + short_orbit = false; + do { + rnd = rte_rand() & ((1 << poly_degree) - 1); + } while ((rnd == 0) || (rnd == 1)); + + /* + * Quick check if random returned one of the roots of + * the initial polynomial. + * In other words if we randomy got x, x^2, x^4, x^8 or x^16 + */ +#define ROOT_POLY_MSK ((1 << 1)|(1 << 2)|(1 << 4)|(1 << 8)|(1 << 16)) + if ((rte_popcount32(rnd) == 1) && (rnd & ROOT_POLY_MSK)) + return default_irreducible_poly[poly_degree - 7]; + + /* + * init array with some random polynomial roots + * applying Frobenius automorphism (i.e. squaring them) + * also checking for short orbits (i.e. if there are repeated roots) + */ + roots[0] = rnd; + for (i = 1; i < poly_degree; i++) { + roots[i] = gf2_pow(roots[i - 1], 2, r, poly_degree); + if (roots[i] == roots[0]) + short_orbit = true; + } + } while (short_orbit); + + /* + * Get coefficients of the polynomial for + * (x - roots[0])(x - roots[1])...(x - roots[n]) + */ + uint32_t poly_coefficients[poly_degree + 1]; + for (i = 0; i <= poly_degree; i++) + poly_coefficients[i] = 0; + + poly_coefficients[0] = 1; /* highest degree term coefficient in the end */ + for (i = 0; i < (int)poly_degree; i++) { + /* multiply by x */ + for (j = i; j >= 0; j--) + poly_coefficients[j + 1] = poly_coefficients[j]; + + poly_coefficients[0] = 0; + + /* multiply by root */ + for (j = 0; j <= i; j++) + poly_coefficients[j] ^= + gf2_mul(poly_coefficients[j + 1], + roots[i], r, poly_degree); + } + + for (i = 0; i < poly_degree; i++) { + if (poly_coefficients[i]) { + RTE_ASSERT(poly_coefficients[i] == 1); + ret_poly |= 1 << i; + } + } + + return ret_poly; +} + +/* test an order of the multiplicative subgroup generated by x */ +static int +thash_test_poly_order(uint32_t poly, int degree) +{ + unsigned int i; + int div_idx = degree - 7; + + if (degree < 7) + return 0; + + for (i = 0; i < divisors[div_idx].n; i++) { + if (gf2_pow(0x2, divisors[div_idx].div_arr[i], + poly, degree) == 1) + return 1; + } + + return 0; +} + +uint32_t +rte_thash_get_rand_poly(uint32_t poly_degree) +{ + uint32_t ret_poly; + + if (poly_degree > 32) + return 0; + + do + ret_poly = __thash_get_rand_poly(poly_degree); + while (thash_test_poly_order(ret_poly, poly_degree)); + + return ret_poly; +} diff --git a/lib/hash/version.map b/lib/hash/version.map index 4f13f1d5aa..7ce6ab1121 100644 --- a/lib/hash/version.map +++ b/lib/hash/version.map @@ -61,4 +61,5 @@ INTERNAL { rte_thash_gfni_stub; rte_thash_gfni_bulk_stub; + rte_thash_get_rand_poly; };