Skip to content

Commit 84bce7b

Browse files
committed
Made crude port of Tofino dynamic hash to C++
Signed-off-by: Anton Korobeynikov <anton@korobeynikov.info>
1 parent dff5c34 commit 84bce7b

File tree

6 files changed

+1117
-14
lines changed

6 files changed

+1117
-14
lines changed

backends/tofino/CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ set (BF_P4C_IR_SRCS
234234
bf-p4c/parde/match_register.cpp
235235
bf-p4c/parde/clot/clot.cpp
236236
bf-p4c/phv/phv.cpp
237-
bf-utils/src/dynamic_hash/dynamic_hash.c
238-
bf-utils/src/dynamic_hash/bfn_hash_algorithm.c
237+
bf-utils/src/dynamic_hash/dynamic_hash.cpp
238+
bf-utils/src/dynamic_hash/bfn_hash_algorithm.cpp
239239
)
240240
add_cpplint_files(${CMAKE_CURRENT_SOURCE_DIR} "${BF_P4C_IR_SRCS}")
241241

backends/tofino/bf-p4c/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ target_include_directories(
970970
# FIXME: This should be pulled with FetchContent.
971971
PRIVATE "${BFN_P4C_SOURCE_DIR}/third_party/spdlog/include"
972972
)
973-
add_dependencies(tofinobackend ir-generated frontend genLogging bfn_p4runtime)
973+
add_dependencies(tofinobackend frontend genLogging bfn_p4runtime)
974974

975975
if(BUILD_STATIC_BFP4C_LIBS)
976976
add_library(bfp4c STATIC ${P4C_BAREFOOT_SRCS})

backends/tofino/bf-p4c/mau/hash_function.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ const IR::Expression *IR::MAU::HashFunction::convertHashAlgorithmInner(
253253
detected_algorithm = OTHER;
254254
mc_name = alg_name + "_hash";
255255
} else if (direct_crc_string_conversion(&hash_alg, alg_name, srcInfo)) {
256-
char *error_message;
256+
const char *error_message;
257257
if (!verify_algorithm(&hash_alg, &error_message)) {
258258
error("%s: Crc algorithm %s incorrect for the following reason : %s", srcInfo,
259259
algorithm.name, error_message);

backends/tofino/bf-utils/include/dynamic_hash/bfn_hash_algorithm.h

+2-10
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
#include <string.h>
88
#endif
99

10-
#ifdef __cplusplus
11-
extern "C" {
12-
#endif
13-
1410
#define BF_UTILS_ALGO_NAME_LEN 30
1511

1612
typedef enum {
@@ -375,7 +371,7 @@ static inline bfn_hash_alg_type_t hash_alg_str_to_type(const char *alg_name) {
375371
* algorithms
376372
*/
377373
typedef struct crc_alg_info_ {
378-
char *crc_name;
374+
const char *crc_name;
379375
uint64_t poly;
380376
bool reverse;
381377
uint64_t init;
@@ -403,7 +399,7 @@ typedef struct bfn_hash_algorithm_ {
403399
* ensures that the polynomial is odd, and that the sizes of the init and
404400
* final_xor values correctly fit within the size of the polynomial
405401
*/
406-
bool verify_algorithm(bfn_hash_algorithm_t *alg, char **error_message);
402+
bool verify_algorithm(bfn_hash_algorithm_t *alg, const char **error_message);
407403

408404
/**
409405
* Given a list of parameters, this will build an algorithm to be used in a
@@ -423,8 +419,4 @@ void initialize_crc_matrix(bfn_hash_algorithm_t *alg);
423419
void calculate_crc(bfn_hash_algorithm_t *alg, uint32_t hash_output_bits, uint8_t *stream,
424420
uint32_t stream_len, uint8_t *crc);
425421

426-
#ifdef __cplusplus
427-
}
428-
#endif
429-
430422
#endif /* BACKENDS_TOFINO_BF_UTILS_INCLUDE_DYNAMIC_HASH_BFN_HASH_ALGORITHM_H_ */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
#include "backends/tofino/bf-utils/include/dynamic_hash/bfn_hash_algorithm.h"
2+
3+
#include <errno.h>
4+
#include <limits.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
9+
/**
10+
* These values are based on the crc calculations provided at this url:
11+
* http://reveng.sourceforge.net/crc-catalogue/all.htm
12+
*
13+
* It is understood that the top bit of the the polynomial is known to be == 1,
14+
* but any polynomial over 64 bits would not fit. Thus the strings do not have
15+
* this value
16+
*/
17+
static crc_alg_info_t standard_crc_algs[CRC_INVALID] = {
18+
{"crc_8", 0x07, false, 0, 0},
19+
{"crc_8_darc", 0x39, true, 0, 0},
20+
{"crc_8_i_code", 0x1d, false, 0xfd, 0},
21+
{"crc_8_itu", 0x07, false, 0x55, 0x55},
22+
{"crc_8_maxim", 0x31, true, 0, 0},
23+
{"crc_8_rohc", 0x07, true, 0xff, 0},
24+
{"crc_8_wcdma", 0x9b, true, 0, 0},
25+
{"crc_16", 0x8005, true, 0, 0},
26+
{"crc_16_bypass", 0x8005, false, 0, 0},
27+
{"crc_16_dds_110", 0x8005, false, 0x800d, 0},
28+
// This one doesn't appear on the website, but kept to not break
29+
// regressions
30+
{"crc_16_dect", 0x0589, false, 1, 1},
31+
{"crc_16_dect_r", 0x0589, false, 0, 1},
32+
{"crc_16_dect_x", 0x0589, false, 0, 0},
33+
{"crc_16_dnp", 0x3d65, true, 0, 0xffff},
34+
{"crc_16_en_13757", 0x3d65, false, 0, 0xffff},
35+
{"crc_16_genibus", 0x1021, false, 0xffff, 0xffff},
36+
{"crc_16_maxim", 0x8005, true, 0, 0xffff},
37+
{"crc_16_mcrf4xx", 0x1021, true, 0xffff, 0},
38+
{"crc_16_riello", 0x1021, true, 0xb2aa, 0},
39+
{"crc_16_t10_dif", 0x8bb7, false, 0, 0},
40+
{"crc_16_teledisk", 0xa097, false, 0, 0},
41+
{"crc_16_usb", 0x8005, true, 0xffff, 0xffff},
42+
{"x_25", 0x1021, true, 0xffff, 0xffff},
43+
{"xmodem", 0x1021, false, 0, 0},
44+
{"modbus", 0x8005, true, 0xffff, 0},
45+
{"kermit", 0x1021, true, 0, 0},
46+
{"crc_ccitt_false", 0x1021, false, 0xffff, 0},
47+
{"crc_aug_ccitt", 0x1021, false, 0x1d0f, 0},
48+
{"crc_32", 0x04c11db7, true, 0xffffffff, 0xffffffff},
49+
{"crc_32_bzip2", 0x04c11db7, false, 0xffffffff, 0xffffffff},
50+
{"crc_32c", 0x1edc6f41, true, 0xffffffff, 0xffffffff},
51+
{"crc_32d", 0xa833982b, true, 0xffffffff, 0xffffffff},
52+
{"crc_32_mpeg", 0x04c11db7, false, 0xffffffff, 0},
53+
{"posix", 0x04c11db7, false, 0, 0xffffffff},
54+
{"crc_32q", 0x814141ab, false, 0, 0},
55+
{"jamcrc", 0x04c11db7, true, 0xffffffff, 0},
56+
{"xfer", 0x000000af, false, 0, 0},
57+
{"crc_64", 0x42f0e1eba9ea3693, false, 0, 0},
58+
{"crc_64_go_iso", 0x000000000000001b, true, 0xffffffffffffffff, 0xffffffffffffffff},
59+
{"crc_64_we", 0x42f0e1eba9ea3693, false, 0xffffffffffffffff, 0xffffffffffffffff},
60+
// This one doesn't appear on the website, but kept to not break
61+
// regressions
62+
{"crc_64_jones", 0xad93d23594c935a9, true, 0xffffffffffffffff, 0}};
63+
64+
int determine_msb(uint64_t value) {
65+
int rv = -1;
66+
#if defined(__GNUC__) || defined(__clang__)
67+
if (value) rv = 63 - __builtin_clzl(value);
68+
#else
69+
for (int i = 63; i >= 0; i--) {
70+
if (((1ULL << i) & value) != 0ULL) return i;
71+
}
72+
#endif
73+
return rv;
74+
}
75+
76+
#define BUILD_CRC_ERRORS
77+
78+
static const char *bfn_crc_errors[BUILD_CRC_ERRORS] = {
79+
"Polynomial is not odd",
80+
"Init value is larger than the polynomial",
81+
"Final xor value is larger than the polynomial",
82+
};
83+
84+
bool verify_algorithm(bfn_hash_algorithm_t *alg, const char **error_message) {
85+
if ((alg->poly & 1) == 0) {
86+
if (error_message) *error_message = bfn_crc_errors[0];
87+
return false;
88+
}
89+
if (alg->init && determine_msb(alg->init) + 1 > alg->hash_bit_width) {
90+
if (error_message) *error_message = bfn_crc_errors[1];
91+
return false;
92+
}
93+
if (alg->final_xor && determine_msb(alg->final_xor) + 1 > alg->hash_bit_width) {
94+
if (error_message) *error_message = bfn_crc_errors[2];
95+
return false;
96+
}
97+
return true;
98+
}
99+
100+
/**
101+
* Builds the algorithm from the standard crc algorithm position
102+
*/
103+
void build_standard_crc_algorithm(bfn_hash_algorithm_t *alg, bfn_crc_alg_t crc_alg) {
104+
if (crc_alg >= CRC_8 && crc_alg <= CRC_8_WCDMA)
105+
alg->hash_bit_width = 8;
106+
else if (crc_alg >= CRC_16 && crc_alg <= CRC_AUG_CCITT)
107+
alg->hash_bit_width = 16;
108+
else if (crc_alg >= CRC_32 && crc_alg <= XFER)
109+
alg->hash_bit_width = 32;
110+
else if (crc_alg >= CRC_64 && crc_alg <= CRC_64_JONES)
111+
alg->hash_bit_width = 64;
112+
113+
crc_alg_info_t crc_alg_info = standard_crc_algs[(int)crc_alg];
114+
alg->poly = crc_alg_info.poly;
115+
alg->reverse = crc_alg_info.reverse;
116+
alg->init = crc_alg_info.init;
117+
alg->final_xor = crc_alg_info.final_xor;
118+
alg->crc_type = crc_alg_str_to_type(crc_alg_info.crc_name);
119+
}
120+
121+
void initialize_algorithm(bfn_hash_algorithm_t *alg, bfn_hash_alg_type_t hash_alg, bool msb,
122+
bool extend, bfn_crc_alg_t crc_alg) {
123+
alg->hash_alg = hash_alg;
124+
alg->msb = msb;
125+
alg->extend = extend;
126+
if (crc_alg != CRC_INVALID) build_standard_crc_algorithm(alg, crc_alg);
127+
}
128+
129+
static uint64_t invert_poly(uint64_t poly, int bit_width) {
130+
uint64_t ret = 0, i = 0;
131+
while (poly > 0) {
132+
ret |= ((poly & 0x1) << (bit_width - i - 1));
133+
i++;
134+
poly >>= 1;
135+
}
136+
return ret;
137+
}
138+
139+
static void construct_stream(bfn_hash_algorithm_t *alg, uint64_t val, uint8_t *stream) {
140+
uint8_t width = (alg->hash_bit_width + 7) / 8;
141+
for (uint8_t i = 0; i < width; i++) {
142+
stream[width - i - 1] = (val >> (i * 8));
143+
}
144+
return;
145+
}
146+
147+
static void shift_right(uint8_t *stream, uint8_t bit_width) {
148+
uint8_t width = (bit_width + 7) / 8;
149+
for (int i = width - 1; i >= 0; i--) {
150+
stream[i] >>= 1;
151+
if (i > 0) {
152+
stream[i] |= (stream[i - 1] & 0x1) << 7;
153+
}
154+
}
155+
}
156+
157+
static void shift_left(uint8_t *stream, uint8_t bit_width) {
158+
uint8_t width = (bit_width + 7) / 8;
159+
for (uint8_t i = 0; i < width; i++) {
160+
stream[i] <<= 1;
161+
if (i < width - 1) {
162+
stream[i] |= (stream[i + 1] >> 7) & 0x1;
163+
}
164+
}
165+
}
166+
167+
void initialize_crc_matrix(bfn_hash_algorithm_t *alg) {
168+
if (alg->hash_alg != CRC_DYN) {
169+
return;
170+
}
171+
172+
uint32_t width = (alg->hash_bit_width + 7) / 8, i = 0;
173+
std::vector<uint8_t> poly(width, 0), rem(width, 0);
174+
175+
uint64_t poly_val = alg->poly;
176+
if (alg->reverse) {
177+
poly_val = invert_poly(poly_val, alg->hash_bit_width);
178+
}
179+
construct_stream(alg, poly_val, poly.data());
180+
uint32_t byte = 0, bit = 0;
181+
bool need_xor = false;
182+
if (alg->reverse) {
183+
for (byte = 0; byte < 256; byte++) {
184+
memset(rem.data(), 0, width * sizeof(uint8_t));
185+
rem[width - 1] = byte;
186+
for (bit = 0; bit < 8; bit++) {
187+
need_xor = rem[width - 1] & 0x1;
188+
shift_right(rem.data(), alg->hash_bit_width);
189+
if (need_xor) {
190+
for (i = 0; i < width; i++) {
191+
rem[i] ^= poly[i];
192+
}
193+
}
194+
}
195+
memcpy(alg->crc_matrix[byte], rem.data(), width);
196+
}
197+
} else {
198+
uint8_t offset = alg->hash_bit_width % 8;
199+
uint8_t top_bit = offset == 0 ? 0x80 : 1 << ((offset - 1) % 8);
200+
uint8_t top_mask = top_bit == 0x80 ? 0xff : (top_bit << 1) - 1;
201+
for (byte = 0; byte < 256; byte++) {
202+
memset(rem.data(), 0, width * sizeof(uint8_t));
203+
if (offset == 0) {
204+
rem[0] = byte;
205+
} else {
206+
rem[0] = byte >> (8 - offset);
207+
rem[1] = byte << offset;
208+
}
209+
for (bit = 0; bit < 8; bit++) {
210+
need_xor = rem[0] & top_bit;
211+
shift_left(rem.data(), alg->hash_bit_width);
212+
if (need_xor) {
213+
for (i = 0; i < width; i++) {
214+
rem[i] ^= poly[i];
215+
}
216+
}
217+
rem[0] &= top_mask;
218+
}
219+
memcpy(alg->crc_matrix[byte], rem.data(), width);
220+
}
221+
}
222+
223+
return;
224+
}
225+
226+
static uint8_t get_byte(uint8_t *stream, uint8_t index, uint8_t offset) {
227+
if (offset == 0) {
228+
return stream[index];
229+
}
230+
return ((stream[index] << (8 - offset)) | (stream[index + 1] >> offset));
231+
}
232+
233+
void calculate_crc(bfn_hash_algorithm_t *alg, uint32_t hash_output_bits, uint8_t *stream,
234+
uint32_t stream_len, uint8_t *crc) {
235+
uint32_t i = 0;
236+
uint8_t idx = 0;
237+
uint8_t width = (alg->hash_bit_width + 7) / 8;
238+
uint8_t hash_output_bytes = (hash_output_bits + 7) / 8;
239+
std::vector<uint8_t> final_xor(width, 0);
240+
memset(crc, 0, hash_output_bytes * sizeof(uint8_t));
241+
construct_stream(alg, alg->init, crc);
242+
construct_stream(alg, alg->final_xor, final_xor.data());
243+
uint8_t *crc_str = crc + hash_output_bytes - width;
244+
245+
for (i = 0; i < stream_len; i++) {
246+
if (alg->reverse) {
247+
idx = crc_str[width - 1] ^ stream[i];
248+
for (int j = width - 1; j > 0; j--) {
249+
crc_str[j] = crc_str[j - 1] ^ alg->crc_matrix[idx][j];
250+
}
251+
crc_str[0] = alg->crc_matrix[idx][0];
252+
} else {
253+
uint8_t offset = alg->hash_bit_width % 8;
254+
uint8_t mask = offset == 0 ? 0xff : (1 << offset) - 1;
255+
idx = get_byte(crc_str, 0, offset) ^ stream[i];
256+
for (uint8_t j = 0; j < width - 1; j++) {
257+
crc_str[j] = (crc_str[j + 1] ^ alg->crc_matrix[idx][j]) & mask;
258+
mask = 0xff;
259+
}
260+
crc_str[width - 1] = alg->crc_matrix[idx][width - 1];
261+
}
262+
}
263+
264+
for (i = 0; i < width; i++) {
265+
crc_str[i] ^= final_xor[i];
266+
}
267+
268+
if (alg->extend) {
269+
for (i = 0; i < (uint32_t)(hash_output_bytes - width); i++) {
270+
*(crc_str - i - 1) = crc_str[width - i % width - 1];
271+
}
272+
if (hash_output_bits % 8) {
273+
crc[0] &= (1 << (hash_output_bits % 8)) - 1;
274+
}
275+
}
276+
277+
return;
278+
}

0 commit comments

Comments
 (0)