From 039e20faa03ceb9d93ec31946532e350e4f930dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Palim=C4=85ka?= <25018671+tatry@users.noreply.github.com> Date: Mon, 7 Nov 2022 12:13:11 +0100 Subject: [PATCH 1/3] ebpf/PSA: Checksum support for fields wider than 64 bits This commit adds support for fields wider than 64 bits in implemented checksum algorithms. --- .../ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp | 248 +++++++++++------- .../ebpf/tests/p4testdata/hash-wide-field.p4 | 136 ++++++++++ backends/ebpf/tests/ptf/checksum.py | 14 + 3 files changed, 302 insertions(+), 96 deletions(-) create mode 100644 backends/ebpf/tests/p4testdata/hash-wide-field.p4 diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp index bceed98df94..feae921e2ba 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp @@ -51,84 +51,105 @@ void EBPFHashAlgorithmPSA::emitAddData(CodeBuilder* builder, int dataPos, void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) { // Note that this update method is optimized for our CRC16 and CRC32, custom - // version may require other method of update. To deal with byte order data - // is read from the end of buffer. + // version may require other method of update. When data_size <= 64 bits, + // applies host byte order for input data, otherwise network byte order is expected. if (crcWidth == 16) { cstring code = "static __always_inline\n" - "void crc%w%_update(u%w% * reg, const u8 * data, u16 data_size, const u%w% poly) {\n" - " for (u16 i = data_size; i > 0; i--) {\n" - " bpf_trace_message(\"CRC%w%: data byte: %x\\n\", data[i-1]);\n" - " *reg ^= (u16) data[i-1];\n" + "void crc16_update(u16 * reg, const u8 * data, " + "u16 data_size, const u16 poly) {\n" + " if (data_size <= 8)\n" + " data += data_size - 1;\n" + " #pragma clang loop unroll(full)\n" + " for (u16 i = 0; i < data_size; i++) {\n" + " bpf_trace_message(\"CRC16: data byte: %x\\n\", *data);\n" + " *reg ^= *data;\n" " for (u8 bit = 0; bit < 8; bit++) {\n" " *reg = (*reg) & 1 ? ((*reg) >> 1) ^ poly : (*reg) >> 1;\n" " }\n" + " if (data_size <= 8)\n" + " data--;\n" + " else\n" + " data++;\n" " }\n" "}"; - code = code.replace("%w%", Util::printf_format("%d", crcWidth)); builder->appendLine(code); } else if (crcWidth == 32) { cstring code = "static __always_inline\n" - "void crc%w%_update(u%w% * reg, const u8 * data, u16 data_size, " - "const u%w% poly) {\n" - " data += data_size - 4;\n" - " u32* current = (u32*) data;\n" - " struct lookup_tbl_val* lookup_table;\n" - " u32 index = 0;\n" - " lookup_table = BPF_MAP_LOOKUP_ELEM(crc_lookup_tbl, &index);\n" - " u32 lookup_key = 0;\n" - " u32 lookup_value = 0;\n" - " u32 lookup_value1 = 0;\n" - " u32 lookup_value2 = 0;\n" - " u32 lookup_value3 = 0;\n" - " u32 lookup_value4 = 0;\n" - " u32 lookup_value5 = 0;\n" - " u32 lookup_value6 = 0;\n" - " u32 lookup_value7 = 0;\n" - " u32 lookup_value8 = 0;\n" - " u16 tmp = 0;\n" - " if (lookup_table != NULL) {\n" - " for (u16 i = data_size; i >= 8; i -= 8) {\n" - " bpf_trace_message(\"CRC32: data byte: %x\", *current);\n" - " u32 one = __builtin_bswap32(*current--) ^ *reg;\n" - " bpf_trace_message(\"CRC32: data byte: %x\", *current);\n" - " u32 two = __builtin_bswap32(*current--);\n" - " lookup_key = (one & 0x000000FF);\n" - " lookup_value8 = lookup_table->table[(u16)(1792 + (u8)lookup_key)];\n" - " lookup_key = (one >> 8) & 0x000000FF;\n" - " lookup_value7 = lookup_table->table[(u16)(1536 + (u8)lookup_key)];\n" - " lookup_key = (one >> 16) & 0x000000FF;\n" - " lookup_value6 = lookup_table->table[(u16)(1280 + (u8)lookup_key)];\n" - " lookup_key = one >> 24;\n" - " lookup_value5 = lookup_table->table[(u16)(1024 + (u8)(lookup_key))];\n" - " lookup_key = (two & 0x000000FF);\n" - " lookup_value4 = lookup_table->table[(u16)(768 + (u8)lookup_key)];\n" - " lookup_key = (two >> 8) & 0x000000FF;\n" - " lookup_value3 = lookup_table->table[(u16)(512 + (u8)lookup_key)];\n" - " lookup_key = (two >> 16) & 0x000000FF;\n" - " lookup_value2 = lookup_table->table[(u16)(256 + (u8)lookup_key)];\n" - " lookup_key = two >> 24;\n" - " lookup_value1 = lookup_table->table[(u8)(lookup_key)];\n" - " *reg = lookup_value8 ^ lookup_value7 ^ lookup_value6 ^ lookup_value5 ^\n" - " lookup_value4 ^ lookup_value3 ^ lookup_value2 ^ lookup_value1;\n" - " tmp += 8;\n" - " }\n" - " unsigned char *currentChar = (unsigned char *) current;\n" - " currentChar+= 3;\n" - " volatile int std_algo_lookup_key = 0;\n" - " for (u16 i = tmp; i < data_size; i++) {\n" - " bpf_trace_message(\"CRC32: data byte: %x\\n\", *current);\n" - " std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar--);\n" - " if (std_algo_lookup_key >= 0) {\n" - " lookup_value = " + "void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) {\n" + " u32* current = (u32*) data;\n" + " struct lookup_tbl_val* lookup_table;\n" + " u32 index = 0;\n" + " lookup_table = BPF_MAP_LOOKUP_ELEM(crc_lookup_tbl, &index);\n" + " u32 lookup_key = 0;\n" + " u32 lookup_value = 0;\n" + " u32 lookup_value1 = 0;\n" + " u32 lookup_value2 = 0;\n" + " u32 lookup_value3 = 0;\n" + " u32 lookup_value4 = 0;\n" + " u32 lookup_value5 = 0;\n" + " u32 lookup_value6 = 0;\n" + " u32 lookup_value7 = 0;\n" + " u32 lookup_value8 = 0;\n" + " u16 tmp = 0;\n" + " if (lookup_table != NULL) {\n" + " for (u16 i = data_size; i >= 8; i -= 8) {\n" + " if (data_size == 8) current = data + 4;\n" + " bpf_trace_message(\"CRC32: data dword: %x\\n\", *current);\n" + " u32 one = (data_size == 8 ? __builtin_bswap32(*current--) : *current++) ^ " + "*reg;\n" + " bpf_trace_message(\"CRC32: data dword: %x\\n\", *current);\n" + " u32 two = (data_size == 8 ? __builtin_bswap32(*current--) : *current++);\n" + " lookup_key = (one & 0x000000FF);\n" + " lookup_value8 = lookup_table->table[(u16)(1792 + (u8)lookup_key)];\n" + " lookup_key = (one >> 8) & 0x000000FF;\n" + " lookup_value7 = lookup_table->table[(u16)(1536 + (u8)lookup_key)];\n" + " lookup_key = (one >> 16) & 0x000000FF;\n" + " lookup_value6 = lookup_table->table[(u16)(1280 + (u8)lookup_key)];\n" + " lookup_key = one >> 24;\n" + " lookup_value5 = lookup_table->table[(u16)(1024 + (u8)(lookup_key))];\n" + " lookup_key = (two & 0x000000FF);\n" + " lookup_value4 = lookup_table->table[(u16)(768 + (u8)lookup_key)];\n" + " lookup_key = (two >> 8) & 0x000000FF;\n" + " lookup_value3 = lookup_table->table[(u16)(512 + (u8)lookup_key)];\n" + " lookup_key = (two >> 16) & 0x000000FF;\n" + " lookup_value2 = lookup_table->table[(u16)(256 + (u8)lookup_key)];\n" + " lookup_key = two >> 24;\n" + " lookup_value1 = lookup_table->table[(u8)(lookup_key)];\n" + " *reg = lookup_value8 ^ lookup_value7 ^ lookup_value6 ^ lookup_value5 ^\n" + " lookup_value4 ^ lookup_value3 ^ lookup_value2 ^ lookup_value1;\n" + " tmp += 8;\n" + " }\n" + " volatile int std_algo_lookup_key = 0;\n" + " if (data_size < 8) {\n" + " unsigned char *currentChar = (unsigned char *) current;\n" + " currentChar += data_size - 1;\n" + " for (u16 i = tmp; i < data_size; i++) {\n" + " bpf_trace_message(\"CRC32: data byte: %x\\n\", *currentChar);\n" + " std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar--);\n" + " if (std_algo_lookup_key >= 0) {\n" + " lookup_value = " + "lookup_table->table[(u8)(std_algo_lookup_key & 255)];\n" + " }\n" + " *reg = ((*reg) >> 8) ^ lookup_value;\n" + " }\n" + " } else {\n" + " /* Consume data not processed by slice-by-8 algorithm above, " + "these data are in network byte order */\n" + " unsigned char *currentChar = (unsigned char *) current;\n" + " for (u16 i = tmp; i < data_size; i++) {\n" + " bpf_trace_message(\"CRC32: data byte: %x\\n\", *currentChar);\n" + " std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar++);\n" + " if (std_algo_lookup_key >= 0) {\n" + " lookup_value = " "lookup_table->table[(u8)(std_algo_lookup_key & 255)];\n" - " }\n" - " *reg = ((*reg) >> 8) ^ lookup_value;\n" + " }\n" + " *reg = ((*reg) >> 8) ^ lookup_value;\n" + " }\n" + " }\n" " }\n" - " }\n" "}"; - code = code.replace("%w%", Util::printf_format("%d", crcWidth)); builder->appendLine(code); } } @@ -340,53 +361,88 @@ void InternetChecksumAlgorithm::updateChecksum(CodeBuilder* builder, const Argum bitsToRead = width; if (width > 64) { - BUG("Fields wider than 64 bits are not supported yet", field); - } - - while (bitsToRead > 0) { - if (remainingBits == 16) { - builder->emitIndent(); - builder->appendFormat("%s = ", tmpVar.c_str()); - } else { - builder->append(" | "); + if (remainingBits != 16) { + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: field wider than 64 bits must be aligned to 16 bits in input data", + field); + continue; } - - // TODO: add masks for fields, however they should not exceed declared width - if (bitsToRead < remainingBits) { - remainingBits -= bitsToRead; - builder->append("("); - visitor->visit(field); - builder->appendFormat(" << %d)", remainingBits); - bitsToRead = 0; - } else if (bitsToRead == remainingBits) { - remainingBits = 0; - visitor->visit(field); - bitsToRead = 0; - } else if (bitsToRead > remainingBits) { - bitsToRead -= remainingBits; - remainingBits = 0; - builder->append("("); - visitor->visit(field); - builder->appendFormat(" >> %d)", bitsToRead); + if (width % 16 != 0) { + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: field wider than 64 bits must have size in bits multiply of 16 bits", + field); + continue; } - if (remainingBits == 0) { - remainingBits = 16; + // Let's convert internal array into an array of u16 and calc csum for such entries. + // Byte order conversion is required, because scum is calculated in host byte order + // but data is preserved in network byte order + const unsigned arrayEntries = width / 16; + for (unsigned i = 0; i < arrayEntries; ++i) { + builder->emitIndent(); + builder->appendFormat("%s = htons(((u16 *)(", tmpVar.c_str()); + visitor->visit(field); + builder->appendFormat("))[%u])", i); builder->endOfStatement(true); // update checksum builder->target->emitTraceMessage(builder, "InternetChecksum: word=0x%llx", 1, tmpVar.c_str()); builder->emitIndent(); + builder->appendFormat("%s = ", stateVar.c_str()); if (addData) { - builder->appendFormat("%s = csum16_add(%s, %s)", stateVar.c_str(), - stateVar.c_str(), tmpVar.c_str()); + builder->appendFormat("csum16_add(%s, %s)", stateVar.c_str(), tmpVar.c_str()); } else { - builder->appendFormat("%s = csum16_sub(%s, %s)", stateVar.c_str(), - stateVar.c_str(), tmpVar.c_str()); + builder->appendFormat("csum16_sub(%s, %s)", stateVar.c_str(), tmpVar.c_str()); } builder->endOfStatement(true); } + } else { // fields smaller or equal than 64 bits + while (bitsToRead > 0) { + if (remainingBits == 16) { + builder->emitIndent(); + builder->appendFormat("%s = ", tmpVar.c_str()); + } else { + builder->append(" | "); + } + + // TODO: add masks for fields, however they should not exceed declared width + if (bitsToRead < remainingBits) { + remainingBits -= bitsToRead; + builder->append("("); + visitor->visit(field); + builder->appendFormat(" << %d)", remainingBits); + bitsToRead = 0; + } else if (bitsToRead == remainingBits) { + remainingBits = 0; + visitor->visit(field); + bitsToRead = 0; + } else if (bitsToRead > remainingBits) { + bitsToRead -= remainingBits; + remainingBits = 0; + builder->append("("); + visitor->visit(field); + builder->appendFormat(" >> %d)", bitsToRead); + } + + if (remainingBits == 0) { + remainingBits = 16; + builder->endOfStatement(true); + + // update checksum + builder->target->emitTraceMessage(builder, "InternetChecksum: word=0x%llx", 1, + tmpVar.c_str()); + builder->emitIndent(); + if (addData) { + builder->appendFormat("%s = csum16_add(%s, %s)", stateVar.c_str(), + stateVar.c_str(), tmpVar.c_str()); + } else { + builder->appendFormat("%s = csum16_sub(%s, %s)", stateVar.c_str(), + stateVar.c_str(), tmpVar.c_str()); + } + builder->endOfStatement(true); + } + } } } diff --git a/backends/ebpf/tests/p4testdata/hash-wide-field.p4 b/backends/ebpf/tests/p4testdata/hash-wide-field.p4 new file mode 100644 index 00000000000..d8614bc764b --- /dev/null +++ b/backends/ebpf/tests/p4testdata/hash-wide-field.p4 @@ -0,0 +1,136 @@ +/* +Copyright 2022-present Orange + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include "common_headers.p4" + +header crc_t { + bit<80> data0; + bit<64> data1; + bit<16> data2; + + bit<32> crc32; + bit<16> crc16; + bit<16> internet_checksum; + bit<8> crc_range; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + crc_t crc; +} + +parser IngressParserImpl( + packet_in buffer, + out headers parsed_hdr, + inout metadata user_meta, + in psa_ingress_parser_input_metadata_t istd, + in empty_t resubmit_meta, + in empty_t recirculate_meta) +{ + InternetChecksum() ck; + + state start { + transition parse_ethernet; + } + state parse_ethernet { + buffer.extract(parsed_hdr.ethernet); + transition parse_crc; + } + state parse_crc { + buffer.extract(parsed_hdr.crc); + ck.clear(); + ck.add({parsed_hdr.crc.data0, parsed_hdr.crc.data1, parsed_hdr.crc.data2}); + parsed_hdr.crc.internet_checksum = ck.get(); + transition accept; + } +} + + +control ingress(inout headers hdr, + inout metadata user_meta, + in psa_ingress_input_metadata_t istd, + inout psa_ingress_output_metadata_t ostd) +{ + Hash>(PSA_HashAlgorithm_t.CRC16) h16; + Hash>(PSA_HashAlgorithm_t.CRC16) h16_range; + Hash>(PSA_HashAlgorithm_t.CRC32) h32; + + apply { + send_to_port(ostd, (PortId_t) PORT1); + + hdr.crc.crc32 = h32.get_hash({hdr.crc.data0, hdr.crc.data1, hdr.crc.data2}); + hdr.crc.crc16 = h16.get_hash({hdr.crc.data0, hdr.crc.data1, hdr.crc.data2}); + hdr.crc.crc_range = (bit<8>) h16_range.get_hash(16w50, {hdr.crc.data0, hdr.crc.data1, hdr.crc.data2}, 16w200); + } +} + +control IngressDeparserImpl( + packet_out packet, + out empty_t clone_i2e_meta, + out empty_t resubmit_meta, + out metadata normal_meta, + inout headers parsed_hdr, + in metadata meta, + in psa_ingress_output_metadata_t istd) +{ + apply { + packet.emit(parsed_hdr.ethernet); + packet.emit(parsed_hdr.crc); + } +} + +parser EgressParserImpl( + packet_in buffer, + out headers parsed_hdr, + inout metadata user_meta, + in psa_egress_parser_input_metadata_t istd, + in metadata normal_meta, + in empty_t clone_i2e_meta, + in empty_t clone_e2e_meta) +{ + state start { + transition accept; + } +} + +control egress(inout headers hdr, + inout metadata user_meta, + in psa_egress_input_metadata_t istd, + inout psa_egress_output_metadata_t ostd) +{ + apply {} +} + +control EgressDeparserImpl( + packet_out packet, + out empty_t clone_e2e_meta, + out empty_t recirculate_meta, + inout headers parsed_hdr, + in metadata meta, + in psa_egress_output_metadata_t istd, + in psa_egress_deparser_input_metadata_t edstd) +{ + apply {} +} + +IngressPipeline(IngressParserImpl(), ingress(), IngressDeparserImpl()) ip; +EgressPipeline(EgressParserImpl(), egress(), EgressDeparserImpl()) ep; +PSA_Switch(ip, PacketReplicationEngine(), ep, BufferingQueueingEngine()) main; diff --git a/backends/ebpf/tests/ptf/checksum.py b/backends/ebpf/tests/ptf/checksum.py index 5f3a53619b6..651ed22bdc1 100644 --- a/backends/ebpf/tests/ptf/checksum.py +++ b/backends/ebpf/tests/ptf/checksum.py @@ -109,3 +109,17 @@ def runTest(self): exp_pkt = Ether() / bytes.fromhex('313233343536373839 {}'.format(format(res, 'x'))) testutils.send_packet(self, PORT0, pkt) testutils.verify_packet_any_port(self, exp_pkt, PTF_PORTS) + + +class HashWideField(P4EbpfTest): + # Tests support for fields wider than 64 bits + p4_file_path = "p4testdata/hash-wide-field.p4" + + def runTest(self): + # data0 data1 data2 + data = "1234567890" + "abcdefgh" + "XZ" + pkt = Ether() / data / (" " * 50) # data + room for check values + # crc32 crc16 ones_compl range + exp_pkt = Ether() / data / bytes.fromhex("6f7bf033 12e9 0c0b 5b") / (" " * 41) + testutils.send_packet(self, PORT0, pkt) + testutils.verify_packet_any_port(self, exp_pkt, PTF_PORTS) From 3d4882663ce23d9fefbc6c56200a0902e3391aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Palim=C4=85ka?= <25018671+tatry@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:54:08 +0100 Subject: [PATCH 2/3] assign state variable in one line and fix typo --- backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp index feae921e2ba..921b142d794 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp @@ -375,7 +375,7 @@ void InternetChecksumAlgorithm::updateChecksum(CodeBuilder* builder, const Argum } // Let's convert internal array into an array of u16 and calc csum for such entries. - // Byte order conversion is required, because scum is calculated in host byte order + // Byte order conversion is required, because csum is calculated in host byte order // but data is preserved in network byte order const unsigned arrayEntries = width / 16; for (unsigned i = 0; i < arrayEntries; ++i) { @@ -389,11 +389,12 @@ void InternetChecksumAlgorithm::updateChecksum(CodeBuilder* builder, const Argum builder->target->emitTraceMessage(builder, "InternetChecksum: word=0x%llx", 1, tmpVar.c_str()); builder->emitIndent(); - builder->appendFormat("%s = ", stateVar.c_str()); if (addData) { - builder->appendFormat("csum16_add(%s, %s)", stateVar.c_str(), tmpVar.c_str()); + builder->appendFormat("%s = csum16_add(%s, %s)", stateVar.c_str(), + stateVar.c_str(), tmpVar.c_str()); } else { - builder->appendFormat("csum16_sub(%s, %s)", stateVar.c_str(), tmpVar.c_str()); + builder->appendFormat("%s = csum16_sub(%s, %s)", stateVar.c_str(), + stateVar.c_str(), tmpVar.c_str()); } builder->endOfStatement(true); } From 00e35c06c63cd1313b536598441d227b7de4043a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Palim=C4=85ka?= <25018671+tatry@users.noreply.github.com> Date: Fri, 23 Dec 2022 13:45:46 +0100 Subject: [PATCH 3/3] add more documentation and comments on CRC calculation algorithms --- .../ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp index 921b142d794..d20cdee2b2d 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp @@ -54,6 +54,11 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) // version may require other method of update. When data_size <= 64 bits, // applies host byte order for input data, otherwise network byte order is expected. if (crcWidth == 16) { + // This function calculates CRC16 by definition, it is bit by bit. If input data has more + // than 64 bit, the outer loop process bytes in network byte order - data pointer is + // incremented. For data shorter than or equal 64 bits, bytes are processed in little endian + // byte order - data pointer is decremented by outer loop in this case. + // There is no need for lookup table. cstring code = "static __always_inline\n" "void crc16_update(u16 * reg, const u8 * data, " @@ -75,6 +80,17 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) "}"; builder->appendLine(code); } else if (crcWidth == 32) { + // This function calculates CRC32 using two optimisations: slice-by-8 and Standard + // Implementation. Both algorithms have to properly handle byte order depending on data + // length. There are four cases which must be handled: + // 1. Data size below 8 bytes - calculated using Standard Implementation in little endian + // byte order. + // 2. Data size equal to 8 bytes - calculated using slice-by-8 in little endian byte order. + // 3. Data size more than 8 bytes and multiply of 8 bytes - calculated using slice-by-8 in + // big endian byte order. + // 4. Data size more than 8 bytes and not multiply of 8 bytes - calculated using slice-by-8 + // and Standard Implementation both in big endian byte order. + // Lookup table is necessary for both algorithms. cstring code = "static __always_inline\n" "void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) {\n" @@ -95,6 +111,7 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) " u16 tmp = 0;\n" " if (lookup_table != NULL) {\n" " for (u16 i = data_size; i >= 8; i -= 8) {\n" + " /* Vars one and two will have swapped byte order if data_size == 8 */\n" " if (data_size == 8) current = data + 4;\n" " bpf_trace_message(\"CRC32: data dword: %x\\n\", *current);\n" " u32 one = (data_size == 8 ? __builtin_bswap32(*current--) : *current++) ^ " @@ -123,6 +140,7 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) " }\n" " volatile int std_algo_lookup_key = 0;\n" " if (data_size < 8) {\n" + // Standard Implementation for little endian byte order " unsigned char *currentChar = (unsigned char *) current;\n" " currentChar += data_size - 1;\n" " for (u16 i = tmp; i < data_size; i++) {\n" @@ -135,6 +153,7 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder* builder, int crcWidth) " *reg = ((*reg) >> 8) ^ lookup_value;\n" " }\n" " } else {\n" + // Standard Implementation for big endian byte order " /* Consume data not processed by slice-by-8 algorithm above, " "these data are in network byte order */\n" " unsigned char *currentChar = (unsigned char *) current;\n"