From 048470b9197dbf425fc8bfef7f79fab176e0cca3 Mon Sep 17 00:00:00 2001 From: Rupesh Chiluka Date: Fri, 19 Jul 2024 23:28:31 +0530 Subject: [PATCH 1/3] Added Basic externs: Meter, Counter, Hash, etc --- targets/pna_nic/Makefile.am | 7 +- targets/pna_nic/externs/pna_counter.cpp | 58 ++++++++ targets/pna_nic/externs/pna_counter.h | 68 +++++++++ targets/pna_nic/externs/pna_hash.cpp | 84 +++++++++++ targets/pna_nic/externs/pna_hash.h | 56 ++++++++ .../pna_nic/externs/pna_internet_checksum.cpp | 136 ++++++++++++++++++ .../pna_nic/externs/pna_internet_checksum.h | 61 ++++++++ targets/pna_nic/externs/pna_meter.cpp | 96 +++++++++++++ targets/pna_nic/externs/pna_meter.h | 66 +++++++++ targets/pna_nic/externs/pna_random.cpp | 62 ++++++++ targets/pna_nic/externs/pna_random.h | 51 +++++++ targets/pna_nic/pnic_CLI.py | 23 ++- 12 files changed, 766 insertions(+), 2 deletions(-) create mode 100644 targets/pna_nic/externs/pna_counter.cpp create mode 100644 targets/pna_nic/externs/pna_counter.h create mode 100644 targets/pna_nic/externs/pna_hash.cpp create mode 100644 targets/pna_nic/externs/pna_hash.h create mode 100644 targets/pna_nic/externs/pna_internet_checksum.cpp create mode 100644 targets/pna_nic/externs/pna_internet_checksum.h create mode 100644 targets/pna_nic/externs/pna_meter.cpp create mode 100644 targets/pna_nic/externs/pna_meter.h create mode 100644 targets/pna_nic/externs/pna_random.cpp create mode 100644 targets/pna_nic/externs/pna_random.h diff --git a/targets/pna_nic/Makefile.am b/targets/pna_nic/Makefile.am index 3d795603..bc653971 100644 --- a/targets/pna_nic/Makefile.am +++ b/targets/pna_nic/Makefile.am @@ -4,7 +4,12 @@ noinst_LTLIBRARIES = libpnanic.la libpnanic_la_SOURCES = \ pna_nic.cpp pna_nic.h \ -primitives.cpp +primitives.cpp \ +externs/pna_counter.h externs/pna_counter.cpp \ +externs/pna_meter.h externs/pna_meter.cpp \ +externs/pna_random.h externs/pna_random.cpp \ +externs/pna_internet_checksum.h externs/pna_internet_checksum.cpp \ +externs/pna_hash.h externs/pna_hash.cpp libpnanic_la_LIBADD = \ $(top_builddir)/src/bm_sim/libbmsim.la \ diff --git a/targets/pna_nic/externs/pna_counter.cpp b/targets/pna_nic/externs/pna_counter.cpp new file mode 100644 index 00000000..d9fc4e6f --- /dev/null +++ b/targets/pna_nic/externs/pna_counter.cpp @@ -0,0 +1,58 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + + +#include "pna_counter.h" + +namespace bm { + +namespace pna { + +void +PNA_Counter::count(const Data &index) { + _counter->get_counter( + index.get()).increment_counter(get_packet()); +} + +Counter & +PNA_Counter::get_counter(size_t idx) { + return _counter->get_counter(idx); +} + +const Counter & +PNA_Counter::get_counter(size_t idx) const { + return _counter->get_counter(idx); +} + +Counter::CounterErrorCode +PNA_Counter::reset_counters(){ + return _counter->reset_counters(); +} + +BM_REGISTER_EXTERN_W_NAME(Counter, PNA_Counter); +BM_REGISTER_EXTERN_W_NAME_METHOD(Counter, PNA_Counter, count, const Data &); + +} // namespace bm::pna + +} // namespace bm + +int import_counters(){ + return 0; +} \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_counter.h b/targets/pna_nic/externs/pna_counter.h new file mode 100644 index 00000000..0570fc5c --- /dev/null +++ b/targets/pna_nic/externs/pna_counter.h @@ -0,0 +1,68 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + + +#ifndef PNA_NIC_PNA_COUNTER_H_ +#define PNA_NIC_PNA_COUNTER_H_ + +#include +#include + +namespace bm { + +namespace pna { + +class PNA_Counter : public bm::ExternType { + public: + static constexpr p4object_id_t spec_id = 0xffffffff; + + BM_EXTERN_ATTRIBUTES { + BM_EXTERN_ATTRIBUTE_ADD(n_counters); + BM_EXTERN_ATTRIBUTE_ADD(type); + } + + void init() override { + _counter = std::unique_ptr( + new CounterArray(get_name() + ".$impl", + spec_id, + n_counters.get())); + } + + void count(const Data &index); + + Counter &get_counter(size_t idx); + + const Counter &get_counter(size_t idx) const; + + Counter::CounterErrorCode reset_counters(); + + size_t size() const { return _counter->size(); }; + + private: + Data n_counters; + Data type; + std::unique_ptr _counter; +}; + +} // namespace bm::pna + +} // namespace bm + +#endif \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_hash.cpp b/targets/pna_nic/externs/pna_hash.cpp new file mode 100644 index 00000000..13ec534f --- /dev/null +++ b/targets/pna_nic/externs/pna_hash.cpp @@ -0,0 +1,84 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include "pna_hash.h" + +namespace { + +bm::ByteContainer +build_buffer(const std::vector &fields) { + int nbits = 0; + int nbytes; + for (const auto &field : fields) { + nbits += field.get_nbits(); + } + nbytes = (nbits + 7) / 8; + bm::ByteContainer buf(nbytes, '\x00'); + nbits = (nbytes * 8 - nbits); // pad to the left with 0s + for (const auto &field : fields) { + char *ptr = buf.data() + (nbits / 8); + field.deparse(ptr, nbits % 8); + nbits += field.get_nbits(); + } + return buf; +} + +} // namespace + +namespace bm { + +namespace pna { + +void +PNA_Hash::init() { + calc = CalculationsMap::get_instance()->get_copy(algo); +} + +void +PNA_Hash::get_hash(Field &dst, const std::vector &fields) { + auto buf = build_buffer(fields); + auto hash = compute(buf.data(), buf.size()); + dst.set(hash); +} + +void +PNA_Hash::get_hash_mod(Field &dst, const Data &base, const std::vector &fields, const Data &max) { + auto buf = build_buffer(fields); + auto hash = compute(buf.data(), buf.size()); + auto result = base.get() + (hash % max.get()); + dst.set(result); +} + +uint64_t +PNA_Hash::compute(const char *buf, size_t s) { + return calc.get()->output(buf, s); +} + +BM_REGISTER_EXTERN_W_NAME(Hash, PNA_Hash); +BM_REGISTER_EXTERN_W_NAME_METHOD(Hash, PNA_Hash, get_hash, Field &, const std::vector); +BM_REGISTER_EXTERN_W_NAME_METHOD(Hash, PNA_Hash, get_hash_mod, Field &, const Data &, const std::vector, const Data &); + +} // namespace bm::pna + +} // namespace bm + +int import_hash() { + return 0; +} \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_hash.h b/targets/pna_nic/externs/pna_hash.h new file mode 100644 index 00000000..cef6cb5e --- /dev/null +++ b/targets/pna_nic/externs/pna_hash.h @@ -0,0 +1,56 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + + +#ifndef PNA_NIC_PNA_HASH_H_ +#define PNA_NIC_PNA_HASH_H_ + +#include +#include + +namespace bm { + +namespace pna { + +class PNA_Hash : public bm::ExternType { + public: + + BM_EXTERN_ATTRIBUTES { + BM_EXTERN_ATTRIBUTE_ADD(algo); + } + + void init() override; + + void get_hash(Field &dst, const std::vector &fields); + + void get_hash_mod(Field &dst, const Data &base, const std::vector &fields, const Data &max); + + uint64_t compute(const char *buffer, size_t s); + + private: + std::string algo; + std::unique_ptr calc; + +}; + +} // namespace bm::pna + +} // namespace bm +#endif \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_internet_checksum.cpp b/targets/pna_nic/externs/pna_internet_checksum.cpp new file mode 100644 index 00000000..537724b8 --- /dev/null +++ b/targets/pna_nic/externs/pna_internet_checksum.cpp @@ -0,0 +1,136 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + + +#include "pna_internet_checksum.h" +#include + + +namespace { + +void +concatenate_fields(const std::vector &fields, bm::Data &input) { + uint16_t n_bits = 0; + bm::Data field_shl; + + // Concatenate fields in one single data + for (int i = fields.size() - 1; i >= 0; i--) { + field_shl.shift_left(fields.at(i), n_bits); + input.add(input, field_shl); + n_bits += fields.at(i).get_nbits(); + } + + _BM_ASSERT(n_bits % 16 == 0); +} + +uint16_t +ones_complement_sum(uint16_t x, uint16_t y) { + uint32_t ret = (uint32_t) x + (uint32_t) y; + if (ret >= 0x10000) + ret++; + + return ret; +} + +} // namespace + +namespace bm { + +namespace pna { + +void +PNA_InternetChecksum::init() { + clear(); +} + +void +PNA_InternetChecksum::get(Field &dst) const { + dst.set(static_cast(~sum)); +} + +void +PNA_InternetChecksum::get_state(Field &dst) const { + dst.set(sum); +} + +void +PNA_InternetChecksum::get_verify(Field &dst, Field &equOp) const { + dst.set(equOp.get() == static_cast(~sum)); +} + +void +PNA_InternetChecksum::set_state(const Data &src) { + sum = src.get(); +} + +void +PNA_InternetChecksum::clear() { + sum = 0; +} + +void +PNA_InternetChecksum::add(const std::vector &fields) { + Data input(0); + Data chunk; + static const Data mask(0xffff); + + concatenate_fields(fields, input); + + while (!input.test_eq(0)) { + chunk.bit_and(input, mask); + uint16_t d = chunk.get(); + sum = ones_complement_sum(sum, d); + input.shift_right(input, 16); + } +} + +void +PNA_InternetChecksum::subtract(const std::vector &fields) { + Data input(0); + Data chunk; + static const Data mask(0xffff); + + concatenate_fields(fields, input); + + while (!input.test_eq(0)) { + chunk.bit_and(input, mask); + uint16_t d = chunk.get(); + sum = ones_complement_sum(sum, ~d); + input.shift_right(input, 16); + } +} + + +BM_REGISTER_EXTERN_W_NAME(InternetChecksum, PNA_InternetChecksum); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, add, const std::vector); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, subtract, const std::vector); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, get_state, Field &); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, set_state,const Data &); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, get, Field &); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, get_verify, Field &, Field &); +BM_REGISTER_EXTERN_W_NAME_METHOD(InternetChecksum, PNA_InternetChecksum, clear); + +} // namespace bm::pna + +} // namespace bm + +int import_internet_checksum() { + return 0; +} \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_internet_checksum.h b/targets/pna_nic/externs/pna_internet_checksum.h new file mode 100644 index 00000000..f4e108c8 --- /dev/null +++ b/targets/pna_nic/externs/pna_internet_checksum.h @@ -0,0 +1,61 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + + +#ifndef PNA_NIC_PNA_INTERNETCHECKSUM_H_ +#define PNA_NIC_PNA_INTERNETCHECKSUM_H_ + +#include + +namespace bm { + +namespace pna { + +class PNA_InternetChecksum : public bm::ExternType { + public: + + BM_EXTERN_ATTRIBUTES { +} + + void init() override; + + void get(Field &dst) const; + + void get_verify(Field &dst, Field &equOp) const; + + void clear(); + + void add(const std::vector &fields); + + void subtract(const std::vector &fields); + + void get_state(Field &dst) const; + + void set_state(const Data &src); + + private: + uint16_t sum; + +}; + +} // namespace bm::pna + +} // namespace bm +#endif \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_meter.cpp b/targets/pna_nic/externs/pna_meter.cpp new file mode 100644 index 00000000..e1b4f5cb --- /dev/null +++ b/targets/pna_nic/externs/pna_meter.cpp @@ -0,0 +1,96 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include "pna_meter.h" +#include + +namespace bm { + +namespace pna { + +void +PNA_Meter::init() { + bm::MeterArray::MeterType meter_type; + if (type == "bytes") { + meter_type = bm::MeterArray::MeterType::BYTES; + } else { + meter_type = bm::MeterArray::MeterType::PACKETS; + } + _meter = std::unique_ptr( + new MeterArray(get_name() + ".$impl", + spec_id, + meter_type, + rate_count.get(), + n_meters.get())); +} + +void +PNA_Meter::execute(const Data &index, Data &value) { + auto color_out = _meter->execute_meter(get_packet(), index.get(), static_cast(0)); + + // color adjustment for PNA: + // bmv2 meter implementation assign higher value for busier flow: + // (bmv2-meter) GREEN = 0, YELLOW = 1, RED = 2. + // PNA specification order enums differently: + // (see p4c/p4include/pna.p4) + // (PNA-specification) RED = 0, GREEN = 1, YELLOW = 2. + // The following code maps color_out (bmv2-meter) to + // pna_color_out (PNA-specification). + bm::Meter::color_t pna_color_out = 1; + switch(color_out) { + case 0 : + pna_color_out = 1; + break; + case 1 : + pna_color_out = 2; + break; + case 2 : + pna_color_out = 0; + break; + } + + value.set(pna_color_out); +} + +Meter & +PNA_Meter::get_meter(size_t idx) { + return _meter->get_meter(idx); +} + +const Meter & +PNA_Meter::get_meter(size_t idx) const { + return _meter->get_meter(idx); +} + +Meter::MeterErrorCode +PNA_Meter::set_rates(const std::vector &configs) { + return _meter->set_rates(configs); +} + +BM_REGISTER_EXTERN_W_NAME(Meter, PNA_Meter); +BM_REGISTER_EXTERN_W_NAME_METHOD(Meter, PNA_Meter, execute, const Data &, Data &); + +} // namespace bm::pna + +} // namespace bm + +int import_meters(){ + return 0; +} \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_meter.h b/targets/pna_nic/externs/pna_meter.h new file mode 100644 index 00000000..817bc925 --- /dev/null +++ b/targets/pna_nic/externs/pna_meter.h @@ -0,0 +1,66 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#ifndef PNA_NIC_PNA_METER_H_ +#define PNA_NIC_PNA_METER_H_ + +#include +#include + +namespace bm { + +namespace pna { + +class PNA_Meter : public bm::ExternType { + public: + static constexpr p4object_id_t spec_id = 0xfffffffe; + + BM_EXTERN_ATTRIBUTES { + BM_EXTERN_ATTRIBUTE_ADD(n_meters); + BM_EXTERN_ATTRIBUTE_ADD(type); + BM_EXTERN_ATTRIBUTE_ADD(is_direct); + BM_EXTERN_ATTRIBUTE_ADD(rate_count); + } + + void init() override; + + void execute(const Data &index, Data &value); + + Meter &get_meter(size_t idx); + + const Meter &get_meter(size_t idx) const; + + Meter::MeterErrorCode set_rates(const std::vector &configs); + + size_t size() const { return _meter->size(); }; + + private: + Data n_meters; + std::string type; + Data is_direct; + Data rate_count; + Data color; + std::unique_ptr _meter; +}; + +} // namespace bm::pna + +} // namespace bm +#endif \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_random.cpp b/targets/pna_nic/externs/pna_random.cpp new file mode 100644 index 00000000..b5887682 --- /dev/null +++ b/targets/pna_nic/externs/pna_random.cpp @@ -0,0 +1,62 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include "pna_random.h" +#include + +#include +#include +#include + +namespace bm { + +namespace pna { + +void +PNA_Random::init() { + min_val = min.get_uint64(); + max_val = max.get_uint64(); + _BM_ASSERT((max_val > min_val) && "[Error] Random number range must be positive."); + + /* Note: Even though PNA spec mentioned range should be a power of 2 for + * max portability, bmv2 does not impose this restriction. + */ +} + +void +PNA_Random::read(Data &value) { + using engine = std::default_random_engine; + using hash = std::hash; + static thread_local engine generator(hash()(std::this_thread::get_id())); + using distrib64 = std::uniform_int_distribution; + distrib64 distribution(min_val, max_val); + value.set(distribution(generator)); +} + +BM_REGISTER_EXTERN_W_NAME(Random, PNA_Random); +BM_REGISTER_EXTERN_W_NAME_METHOD(Random, PNA_Random, read, Data &); + +} // namespace bm::pna + +} // namespace bm + +int import_random(){ + return 0; +} \ No newline at end of file diff --git a/targets/pna_nic/externs/pna_random.h b/targets/pna_nic/externs/pna_random.h new file mode 100644 index 00000000..49ab541f --- /dev/null +++ b/targets/pna_nic/externs/pna_random.h @@ -0,0 +1,51 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#ifndef PNA_NIC_PNA_RANDOM_H_ +#define PNA_NIC_PNA_RANDOM_H_ + +#include + +namespace bm { + +namespace pna { + +class PNA_Random : public bm::ExternType { + public: + BM_EXTERN_ATTRIBUTES { + BM_EXTERN_ATTRIBUTE_ADD(min); + BM_EXTERN_ATTRIBUTE_ADD(max); + } + + void init() override; + + void read(Data &value); + + private: + Data min; + Data max; + uint64_t min_val; + uint64_t max_val; +}; + +} // namespace bm::pna + +} // namespace bm +#endif \ No newline at end of file diff --git a/targets/pna_nic/pnic_CLI.py b/targets/pna_nic/pnic_CLI.py index 4b17c732..f8b2dd60 100644 --- a/targets/pna_nic/pnic_CLI.py +++ b/targets/pna_nic/pnic_CLI.py @@ -48,7 +48,28 @@ def do_get_time_since_epoch(self, line): print(self.pnic_client.get_time_since_epoch_us()) def load_json_pna(json): - pass + def get_json_key(key): + return json.get(key, []) + + for j_meter in get_json_key("extern_instances"): + if j_meter["type"] != "Meter": + continue + meter_array = runtime_CLI.MeterArray(j_meter["name"], j_meter["id"]) + attribute_values = j_meter.get("attribute_values", []) + for attr in attribute_values: + name = attr.get("name", []) + val_type = attr.get("type", []) + value = attr.get("value", []) + if name == "is_direct": + meter_array.is_direct = value == True + # TODO set meter_array.binding for direct_meter + # direct_meter not supported on pna_nic yet + elif name == "n_meters": + meter_array.size = value + elif name == "type": + meter_array.type_ = value + elif name == "rate_count": + meter_array.rate_count = value def main(): args = runtime_CLI.get_parser().parse_args() From 04e4a33afdc2afd655f738e0fd69595b78fcbb85 Mon Sep 17 00:00:00 2001 From: Rupesh Chiluka Date: Thu, 25 Jul 2024 00:43:09 +0530 Subject: [PATCH 2/3] Added basic tests in pna_nic directory --- configure.ac | 1 + targets/pna_nic/Makefile.am | 6 + targets/pna_nic/tests/.gitignore | 2 + targets/pna_nic/tests/Makefile.am | 26 ++ targets/pna_nic/tests/main.cpp | 32 +++ targets/pna_nic/tests/test_hash.cpp | 217 +++++++++++++++++ .../pna_nic/tests/test_internet_checksum.cpp | 225 ++++++++++++++++++ 7 files changed, 509 insertions(+) create mode 100644 targets/pna_nic/tests/.gitignore create mode 100644 targets/pna_nic/tests/Makefile.am create mode 100644 targets/pna_nic/tests/main.cpp create mode 100644 targets/pna_nic/tests/test_hash.cpp create mode 100644 targets/pna_nic/tests/test_internet_checksum.cpp diff --git a/configure.ac b/configure.ac index c94a0e72..6dc27951 100755 --- a/configure.ac +++ b/configure.ac @@ -327,6 +327,7 @@ AC_CONFIG_FILES([Makefile targets/psa_switch/Makefile targets/psa_switch/tests/Makefile targets/pna_nic/Makefile + targets/pna_nic/tests/Makefile tests/Makefile tests/stress_tests/Makefile tools/Makefile diff --git a/targets/pna_nic/Makefile.am b/targets/pna_nic/Makefile.am index bc653971..2ae34b70 100644 --- a/targets/pna_nic/Makefile.am +++ b/targets/pna_nic/Makefile.am @@ -1,3 +1,9 @@ +if COND_NANOMSG +MAYBE_TESTS = tests +endif + +SUBDIRS = . $(MAYBE_TESTS) + THRIFT_IDL = $(srcdir)/thrift/pna_nic.thrift noinst_LTLIBRARIES = libpnanic.la diff --git a/targets/pna_nic/tests/.gitignore b/targets/pna_nic/tests/.gitignore new file mode 100644 index 00000000..e732bc7d --- /dev/null +++ b/targets/pna_nic/tests/.gitignore @@ -0,0 +1,2 @@ +test* +!test*.cpp \ No newline at end of file diff --git a/targets/pna_nic/tests/Makefile.am b/targets/pna_nic/tests/Makefile.am new file mode 100644 index 00000000..6784ee4b --- /dev/null +++ b/targets/pna_nic/tests/Makefile.am @@ -0,0 +1,26 @@ +SUBDIRS = . + +AM_CPPFLAGS += \ +-isystem $(top_srcdir)/third_party/gtest/include \ +-I$(srcdir)/.. \ +-I$(srcdir)/ \ +-DTESTDATADIR=\"$(srcdir)/testdata\" +LDADD = $(builddir)/../libpnanic.la \ +$(top_builddir)/third_party/gtest/libgtest.la \ +$(top_builddir)/src/bm_apps/libbmapps.la \ +-lboost_filesystem + +# Define unit tests +common_source = main.cpp +TESTS = test_internet_checksum \ +test_hash + +check_PROGRAMS = $(TESTS) test_all + +# Sources for tests +test_internet_checksum_SOURCES = $(common_source) test_internet_checksum.cpp +test_hash_SOURCES = $(common_source) test_hash.cpp + +test_all_SOURCES = $(common_source) \ +test_internet_checksum.cpp \ +test_hash.cpp diff --git a/targets/pna_nic/tests/main.cpp b/targets/pna_nic/tests/main.cpp new file mode 100644 index 00000000..83c4a98b --- /dev/null +++ b/targets/pna_nic/tests/main.cpp @@ -0,0 +1,32 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include +#include +#include + +#include + +bool WITH_VALGRIND = false; + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/targets/pna_nic/tests/test_hash.cpp b/targets/pna_nic/tests/test_hash.cpp new file mode 100644 index 00000000..e9c2a4e2 --- /dev/null +++ b/targets/pna_nic/tests/test_hash.cpp @@ -0,0 +1,217 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace bm; + +extern int import_hash(); + +/* Frame (34 bytes) */ +static const unsigned char raw_pkt[34] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x02, 0x08, 0x00, + 0x27, 0x01, 0x8b, 0xbc, 0x08, 0x00, 0x45, 0x00, + 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, + 0xff, 0xff, 0x0a, 0x00, 0x02, 0x0f, 0x0a, 0x01, + 0x00, 0x01 +}; + +class PNA_HashTest : public ::testing::Test { + protected: + HeaderType ethernetHeaderType, ipv4HeaderType; + HeaderType metaHeaderType; + ParseState ethernetParseState, ipv4ParseState; + header_id_t ethernetHeader{0}, ipv4Header{1}; + header_id_t metaHeader{2}; + + ErrorCodeMap error_codes; + Parser parser; + + std::unique_ptr phv_source{nullptr}; + + std::unique_ptr instance{nullptr}; + + PHVFactory phv_factory; + + std::unique_ptr packet{nullptr}; + + PNA_HashTest() + : ethernetHeaderType("ethernet_t", 0), ipv4HeaderType("ipv4_t", 1), + metaHeaderType("meta_t", 2), + ethernetParseState("parse_ethernet", 0), + ipv4ParseState("parse_ipv4", 1), + error_codes(ErrorCodeMap::make_with_core()), + parser("test_parser", 0, &error_codes), + phv_source(PHVSourceIface::make_phv_source()), + instance(ExternFactoryMap::get_instance()-> + get_extern_instance("Hash")) { + ethernetHeaderType.push_back_field("dstAddr", 48); + ethernetHeaderType.push_back_field("srcAddr", 48); + ethernetHeaderType.push_back_field("ethertype", 16); + + ipv4HeaderType.push_back_field("version", 4); + ipv4HeaderType.push_back_field("ihl", 4); + ipv4HeaderType.push_back_field("diffserv", 8); + ipv4HeaderType.push_back_field("len", 16); + ipv4HeaderType.push_back_field("id", 16); + ipv4HeaderType.push_back_field("flags", 3); + ipv4HeaderType.push_back_field("flagOffset", 13); + ipv4HeaderType.push_back_field("ttl", 8); + ipv4HeaderType.push_back_field("protocol", 8); + ipv4HeaderType.push_back_field("checksum", 16); + ipv4HeaderType.push_back_field("srcAddr", 32); + ipv4HeaderType.push_back_field("dstAddr", 32); + + metaHeaderType.push_back_field("input", 12); + metaHeaderType.push_back_field("dst", 16); + metaHeaderType.push_back_field("padding", 4); + + phv_factory.push_back_header("ethernet", ethernetHeader, + ethernetHeaderType); + phv_factory.push_back_header("ipv4", ipv4Header, ipv4HeaderType); + phv_factory.push_back_header("meta", metaHeader, metaHeaderType, true); + } + + virtual void SetUp() { + phv_source->set_phv_factory(0, &phv_factory); + + ParseSwitchKeyBuilder ethernetKeyBuilder; + ethernetKeyBuilder.push_back_field(ethernetHeader, 2, 16); // ethertype + ethernetParseState.set_key_builder(ethernetKeyBuilder); + + ParseSwitchKeyBuilder ipv4KeyBuilder; + ipv4KeyBuilder.push_back_field(ipv4Header, 8, 8); // protocol + ipv4ParseState.set_key_builder(ipv4KeyBuilder); + + ethernetParseState.add_extract(ethernetHeader); + ipv4ParseState.add_extract(ipv4Header); + + char ethernet_ipv4_key[2]; + ethernet_ipv4_key[0] = 0x08; + ethernet_ipv4_key[1] = 0x00; + ethernetParseState.add_switch_case(sizeof(ethernet_ipv4_key), + ethernet_ipv4_key, &ipv4ParseState); + + parser.set_init_state(ðernetParseState); + + packet = std::unique_ptr(new Packet(Packet::make_new( + sizeof(raw_pkt), + PacketBuffer(34, (const char *) raw_pkt, + sizeof(raw_pkt)), phv_source.get()))); + parser.parse(packet.get()); + + instance.get()->_register_attributes(); + instance->_set_attribute("algo", "crc16"); + instance->init(); + + import_hash(); + } + + virtual void TearDown() { } +}; + +static std::unique_ptr get_extern_primitive( + const std::string &extern_name, const std::string &method_name) { + return ActionOpcodesMap::get_instance()->get_primitive( + "_" + extern_name + "_" + method_name); +} + +TEST_F(PNA_HashTest, PNA_HashMethods) { + uint16_t hash; + auto phv = packet.get()->get_phv(); + + // ACTION get_hash + ActionFn actionFn_gh("_Hash_get_hash", 0, 0); + ActionFnEntry actionFnEntry_gh(&actionFn_gh); + auto primitive_gh = get_extern_primitive("Hash", "get_hash"); + ASSERT_NE(nullptr, primitive_gh); + actionFn_gh.push_back_primitive(primitive_gh.get()); + actionFn_gh.parameter_push_back_extern_instance(instance.get()); + actionFn_gh.parameter_push_back_field(ipv4Header, 9); + actionFn_gh.parameter_start_field_list(); + actionFn_gh.parameter_push_back_field(ipv4Header, 0); + actionFn_gh.parameter_push_back_field(ipv4Header, 1); + actionFn_gh.parameter_push_back_field(ipv4Header, 2); + actionFn_gh.parameter_push_back_field(ipv4Header, 3); + actionFn_gh.parameter_push_back_field(ipv4Header, 4); + actionFn_gh.parameter_push_back_field(ipv4Header, 5); + actionFn_gh.parameter_push_back_field(ipv4Header, 6); + actionFn_gh.parameter_push_back_field(ipv4Header, 7); + actionFn_gh.parameter_push_back_field(ipv4Header, 8); + actionFn_gh.parameter_push_back_field(ipv4Header, 10); + actionFn_gh.parameter_push_back_field(ipv4Header, 11); + actionFn_gh.parameter_end_field_list(); + + // ACTION get_hash_mod + ActionFn actionFn_ghm("_Hash_get_hash_mod", 0, 0); + ActionFnEntry actionFnEntry_ghm(&actionFn_ghm); + auto primitive_ghm = get_extern_primitive("Hash", "get_hash_mod"); + ASSERT_NE(nullptr, primitive_ghm); + actionFn_ghm.push_back_primitive(primitive_ghm.get()); + actionFn_ghm.parameter_push_back_extern_instance(instance.get()); + actionFn_ghm.parameter_push_back_field(ipv4Header, 9); + actionFn_ghm.parameter_push_back_const(Data("0x06")); + actionFn_ghm.parameter_start_field_list(); + actionFn_ghm.parameter_push_back_field(ipv4Header, 0); + actionFn_ghm.parameter_push_back_field(ipv4Header, 1); + actionFn_ghm.parameter_push_back_field(ipv4Header, 2); + actionFn_ghm.parameter_push_back_field(ipv4Header, 3); + actionFn_ghm.parameter_push_back_field(ipv4Header, 4); + actionFn_ghm.parameter_push_back_field(ipv4Header, 5); + actionFn_ghm.parameter_push_back_field(ipv4Header, 6); + actionFn_ghm.parameter_push_back_field(ipv4Header, 7); + actionFn_ghm.parameter_push_back_field(ipv4Header, 8); + actionFn_ghm.parameter_push_back_field(ipv4Header, 10); + actionFn_ghm.parameter_push_back_field(ipv4Header, 11); + actionFn_ghm.parameter_end_field_list(); + actionFn_ghm.parameter_push_back_const(Data("0x0A")); + + hash = 0xba50; + actionFnEntry_gh(packet.get()); + ASSERT_EQ(hash, phv->get_field("ipv4.checksum").get()); + + hash = 0x0c; + actionFnEntry_ghm(packet.get()); + ASSERT_EQ(hash, phv->get_field("ipv4.checksum").get()); + + // ACTION get_hash 2 + ActionFn actionFn_gh2("_Hash_get_hash", 0, 0); + ActionFnEntry actionFnEntry_gh2(&actionFn_gh2); + auto primitive_gh2 = get_extern_primitive("Hash", "get_hash"); + ASSERT_NE(nullptr, primitive_gh2); + actionFn_gh2.push_back_primitive(primitive_gh2.get()); + actionFn_gh2.parameter_push_back_extern_instance(instance.get()); + actionFn_gh2.parameter_push_back_field(metaHeader, 1); + actionFn_gh2.parameter_start_field_list(); + actionFn_gh2.parameter_push_back_field(metaHeader, 0); + actionFn_gh2.parameter_end_field_list(); + + phv->get_field("meta.input").set(0x456); + hash = 0xfe82; + actionFnEntry_gh2(packet.get()); + ASSERT_EQ(hash, phv->get_field("meta.dst").get()); +} \ No newline at end of file diff --git a/targets/pna_nic/tests/test_internet_checksum.cpp b/targets/pna_nic/tests/test_internet_checksum.cpp new file mode 100644 index 00000000..259a0d42 --- /dev/null +++ b/targets/pna_nic/tests/test_internet_checksum.cpp @@ -0,0 +1,225 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace bm; + +extern int import_internet_checksum(); + +/* Frame (34 bytes) */ +static const unsigned char raw_pkt[34] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x02, 0x08, 0x00, + 0x27, 0x01, 0x8b, 0xbc, 0x08, 0x00, 0x00, 0xFE, + 0xC5, 0x23, 0xFD, 0xA1, 0xD6, 0x8A, 0xAF, 0x02, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02 +}; + +class PNA_InternetChecksumTest : public ::testing::Test { + protected: + HeaderType ethernetHeaderType, ipv4HeaderType; + HeaderType metaHeaderType; + ParseState ethernetParseState, ipv4ParseState; + header_id_t ethernetHeader{0}, ipv4Header{1}; + header_id_t metaHeader{2}; + + ErrorCodeMap error_codes; + Parser parser; + + std::unique_ptr phv_source{nullptr}; + + std::unique_ptr instance{nullptr}; + + PHVFactory phv_factory; + + std::unique_ptr packet{nullptr}; + + PNA_InternetChecksumTest() + : ethernetHeaderType("ethernet_t", 0), ipv4HeaderType("ipv4_t", 1), + metaHeaderType("meta_t", 2), + ethernetParseState("parse_ethernet", 0), + ipv4ParseState("parse_ipv4", 1), + error_codes(ErrorCodeMap::make_with_core()), + parser("test_parser", 0, &error_codes), + phv_source(PHVSourceIface::make_phv_source()), + instance(ExternFactoryMap::get_instance()-> + get_extern_instance("InternetChecksum")) { + ethernetHeaderType.push_back_field("dstAddr", 48); + ethernetHeaderType.push_back_field("srcAddr", 48); + ethernetHeaderType.push_back_field("ethertype", 16); + + ipv4HeaderType.push_back_field("version", 4); + ipv4HeaderType.push_back_field("ihl", 4); + ipv4HeaderType.push_back_field("diffserv", 8); + ipv4HeaderType.push_back_field("len", 16); + ipv4HeaderType.push_back_field("id", 16); + ipv4HeaderType.push_back_field("flags", 3); + ipv4HeaderType.push_back_field("flagOffset", 13); + ipv4HeaderType.push_back_field("ttl", 8); + ipv4HeaderType.push_back_field("protocol", 8); + ipv4HeaderType.push_back_field("checksum", 16); + ipv4HeaderType.push_back_field("srcAddr", 32); + ipv4HeaderType.push_back_field("dstAddr", 32); + + metaHeaderType.push_back_field("tmp", 16); + + phv_factory.push_back_header("ethernet", ethernetHeader, + ethernetHeaderType); + phv_factory.push_back_header("ipv4", ipv4Header, ipv4HeaderType); + phv_factory.push_back_header("meta", metaHeader, metaHeaderType, true); + } + + virtual void SetUp() { + phv_source->set_phv_factory(0, &phv_factory); + + ParseSwitchKeyBuilder ethernetKeyBuilder; + ethernetKeyBuilder.push_back_field(ethernetHeader, 2, 16); // ethertype + ethernetParseState.set_key_builder(ethernetKeyBuilder); + + ParseSwitchKeyBuilder ipv4KeyBuilder; + ipv4KeyBuilder.push_back_field(ipv4Header, 8, 8); // protocol + ipv4ParseState.set_key_builder(ipv4KeyBuilder); + + ethernetParseState.add_extract(ethernetHeader); + ipv4ParseState.add_extract(ipv4Header); + + char ethernet_ipv4_key[2]; + ethernet_ipv4_key[0] = 0x08; + ethernet_ipv4_key[1] = 0x00; + ethernetParseState.add_switch_case(sizeof(ethernet_ipv4_key), + ethernet_ipv4_key, &ipv4ParseState); + + parser.set_init_state(ðernetParseState); + + packet = std::unique_ptr(new Packet(Packet::make_new( + sizeof(raw_pkt), + PacketBuffer(34, (const char *) raw_pkt, + sizeof(raw_pkt)), phv_source.get()))); + parser.parse(packet.get()); + + import_internet_checksum(); + } + + virtual void TearDown() { } +}; + +static std::unique_ptr get_extern_primitive( + const std::string &extern_name, const std::string &method_name) { + return ActionOpcodesMap::get_instance()->get_primitive( + "_" + extern_name + "_" + method_name); +} + +TEST_F(PNA_InternetChecksumTest, PNA_InternetChecksumMethods) { + uint16_t cksum; + uint16_t sum; + auto phv = packet.get()->get_phv(); + + // ACTION ADD + ActionFn actionFn_add("_InternetChecksum_add", 0, 0); + ActionFnEntry actionFnEntry_add(&actionFn_add); + auto primitive_add = get_extern_primitive("InternetChecksum", "add"); + ASSERT_NE(nullptr, primitive_add); + actionFn_add.push_back_primitive(primitive_add.get()); + actionFn_add.parameter_push_back_extern_instance(instance.get()); + actionFn_add.parameter_start_field_list(); + actionFn_add.parameter_push_back_field(ipv4Header, 0); + actionFn_add.parameter_push_back_field(ipv4Header, 1); + actionFn_add.parameter_push_back_field(ipv4Header, 2); + actionFn_add.parameter_push_back_field(ipv4Header, 3); + actionFn_add.parameter_push_back_field(ipv4Header, 4); + actionFn_add.parameter_push_back_field(ipv4Header, 5); + actionFn_add.parameter_push_back_field(ipv4Header, 6); + actionFn_add.parameter_push_back_field(ipv4Header, 7); + actionFn_add.parameter_push_back_field(ipv4Header, 8); + actionFn_add.parameter_push_back_field(ipv4Header, 10); + actionFn_add.parameter_push_back_field(ipv4Header, 11); + actionFn_add.parameter_end_field_list(); + + // ACTION GET + ActionFn actionFn_get("_InternetChecksum_get", 0, 0); + ActionFnEntry actionFnEntry_get(&actionFn_get); + auto primitive_get = get_extern_primitive("InternetChecksum", "get"); + ASSERT_NE(nullptr, primitive_get); + actionFn_get.push_back_primitive(primitive_get.get()); + actionFn_get.parameter_push_back_extern_instance(instance.get()); + actionFn_get.parameter_push_back_field(ipv4Header, 9); + + // ACTION SUBTRACT + ActionFn actionFn_sub("_InternetChecksum_subtract", 0, 0); + ActionFnEntry actionFnEntry_sub(&actionFn_sub); + auto primitive_sub = get_extern_primitive("InternetChecksum", "subtract"); + ASSERT_NE(nullptr, primitive_sub); + actionFn_sub.push_back_primitive(primitive_sub.get()); + actionFn_sub.parameter_push_back_extern_instance(instance.get()); + actionFn_sub.parameter_start_field_list(); + actionFn_sub.parameter_push_back_field(ipv4Header, 10); + actionFn_sub.parameter_push_back_field(ipv4Header, 11); + actionFn_sub.parameter_end_field_list(); + + // ACTION GET_STATE + ActionFn actionFn_get_state("_InternetChecksum_get_state", 0, 0); + ActionFnEntry actionFnEntry_get_state(&actionFn_get_state); + auto primitive_get_state = get_extern_primitive("InternetChecksum", "get_state"); + ASSERT_NE(nullptr, primitive_get_state); + actionFn_get_state.push_back_primitive(primitive_get_state.get()); + actionFn_get_state.parameter_push_back_extern_instance(instance.get()); + actionFn_get_state.parameter_push_back_field(metaHeader, 0); + + // ACTION SET_STATE + ActionFn actionFn_set_state("_InternetChecksum_set_state", 0, 0); + ActionFnEntry actionFnEntry_set_state(&actionFn_set_state); + auto primitive_set_state = get_extern_primitive("InternetChecksum", "set_state"); + ASSERT_NE(nullptr, primitive_set_state); + actionFn_set_state.push_back_primitive(primitive_set_state.get()); + actionFn_set_state.parameter_push_back_extern_instance(instance.get()); + actionFn_set_state.parameter_push_back_const(Data("0x01")); + + cksum = 0xb6ab; + sum = 0x4954; + + actionFnEntry_add(packet.get()); + actionFnEntry_get(packet.get()); + actionFnEntry_get_state(packet.get()); + ASSERT_EQ(sum, phv->get_field("meta.tmp").get()); + ASSERT_EQ(cksum, phv->get_field("ipv4.checksum").get()); + + cksum = 0xb6ae; + sum = 0x4951; + + actionFnEntry_sub(packet.get()); + actionFnEntry_get(packet.get()); + actionFnEntry_get_state(packet.get()); + ASSERT_EQ(sum, phv->get_field("meta.tmp").get()); + ASSERT_EQ(cksum, phv->get_field("ipv4.checksum").get()); + + sum = 0x01; + + actionFnEntry_set_state(packet.get()); + actionFnEntry_get_state(packet.get()); + ASSERT_EQ(sum, phv->get_field("meta.tmp").get()); +} \ No newline at end of file From 0cefe8345856c38856943ed6f206a34e8c2e116f Mon Sep 17 00:00:00 2001 From: Rupesh Chiluka Date: Mon, 29 Jul 2024 21:07:02 +0530 Subject: [PATCH 3/3] Added test to check whether pna_nic parses a sample_pna.json --- targets/pna_nic/tests/.gitignore | 3 +- targets/pna_nic/tests/Makefile.am | 13 +- targets/pna_nic/tests/test_parse_pna.cpp | 111 +++++++++++ .../tests/testdata/pna-demo-L2-one-table.json | 178 ++++++++++++++++++ targets/pna_nic/tests/utils.cpp | 63 +++++++ targets/pna_nic/tests/utils.h | 56 ++++++ 6 files changed, 420 insertions(+), 4 deletions(-) create mode 100644 targets/pna_nic/tests/test_parse_pna.cpp create mode 100644 targets/pna_nic/tests/testdata/pna-demo-L2-one-table.json create mode 100644 targets/pna_nic/tests/utils.cpp create mode 100644 targets/pna_nic/tests/utils.h diff --git a/targets/pna_nic/tests/.gitignore b/targets/pna_nic/tests/.gitignore index e732bc7d..d52918fe 100644 --- a/targets/pna_nic/tests/.gitignore +++ b/targets/pna_nic/tests/.gitignore @@ -1,2 +1,3 @@ test* -!test*.cpp \ No newline at end of file +!test*.cpp +!testdata \ No newline at end of file diff --git a/targets/pna_nic/tests/Makefile.am b/targets/pna_nic/tests/Makefile.am index 6784ee4b..306d2e23 100644 --- a/targets/pna_nic/tests/Makefile.am +++ b/targets/pna_nic/tests/Makefile.am @@ -11,16 +11,23 @@ $(top_builddir)/src/bm_apps/libbmapps.la \ -lboost_filesystem # Define unit tests -common_source = main.cpp +common_source = main.cpp utils.cpp utils.h TESTS = test_internet_checksum \ -test_hash +test_hash \ +test_parse_pna check_PROGRAMS = $(TESTS) test_all # Sources for tests test_internet_checksum_SOURCES = $(common_source) test_internet_checksum.cpp test_hash_SOURCES = $(common_source) test_hash.cpp +test_parse_pna_SOURCES = $(common_source) test_parse_pna.cpp test_all_SOURCES = $(common_source) \ test_internet_checksum.cpp \ -test_hash.cpp +test_hash.cpp \ +test_parse_pna.cpp + +EXTRA_DIST = \ +testdata/pna-demo-L2-one-table.json \ +testdata/pna-demo-L2-one-table.p4 \ No newline at end of file diff --git a/targets/pna_nic/tests/test_parse_pna.cpp b/targets/pna_nic/tests/test_parse_pna.cpp new file mode 100644 index 00000000..84a8a884 --- /dev/null +++ b/targets/pna_nic/tests/test_parse_pna.cpp @@ -0,0 +1,111 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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 +#include +#include +#include + +#include + +#include "pna_nic.h" + +#include "utils.h" + +namespace fs = boost::filesystem; + +using bm::MatchErrorCode; +using bm::ActionData; +using bm::MatchKeyParam; +using bm::entry_handle_t; + +namespace { + +void packet_handler(int port_num, const char *buffer, int len, void *cookie) { + static_cast(cookie)->receive(port_num, buffer, len); +} + +} // namespace + +class PNA_ParseTest: public ::testing::Test { + protected: + static constexpr size_t kMaxBufSize = 512; + + static constexpr bm::device_id_t device_id{0}; + + PNA_ParseTest() + : packet_inject(packet_in_addr) { } + + // Per-test-case set-up. + static void SetUpTestCase() { + test_pna_nic = new bm::pna::PnaNic(); + + // load JSON + fs::path json_path = fs::path(testdata_dir) / fs::path(test_json); + test_pna_nic->init_objects(json_path.string()); + + // packet in -packet out + test_pna_nic->set_dev_mgr_packet_in(device_id, packet_in_addr, nullptr); + test_pna_nic->Switch::start(); // there is a start member in PnaNic + test_pna_nic->set_packet_handler(packet_handler, static_cast(test_pna_nic)); + test_pna_nic->start_and_return(); + } + + // Per-test-case tear-down. + static void TearDownTestCase() { + delete test_pna_nic; + } + + virtual void SetUp() { + packet_inject.start(); + auto cb = std::bind(&PacketInReceiver::receive, &receiver, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4); + packet_inject.set_packet_receiver(cb, nullptr); + } + + protected: + static const char packet_in_addr[]; + static bm::pna::PnaNic *test_pna_nic; + bm_apps::PacketInject packet_inject; + PacketInReceiver receiver{}; + + private: + static const char testdata_dir[]; + static const char test_json[]; +}; + +const char PNA_ParseTest::packet_in_addr[] = "inproc://packets"; + +bm::pna::PnaNic *PNA_ParseTest::test_pna_nic = nullptr; + +const char PNA_ParseTest::testdata_dir[] = TESTDATADIR; +const char PNA_ParseTest::test_json[] = "pna-demo-L2-one-table.json"; + +TEST_F(PNA_ParseTest, Parse) { + static constexpr int port = 1; + + const char pkt[] = {'\x00'}; + packet_inject.send(port, pkt, sizeof(pkt)); + char recv_buffer[] = {'\x00', '\x00'}; + int recv_port = -1; + receiver.read( + recv_buffer, sizeof(recv_buffer), &recv_port); + ASSERT_TRUE(true); +} \ No newline at end of file diff --git a/targets/pna_nic/tests/testdata/pna-demo-L2-one-table.json b/targets/pna_nic/tests/testdata/pna-demo-L2-one-table.json new file mode 100644 index 00000000..026e4be9 --- /dev/null +++ b/targets/pna_nic/tests/testdata/pna-demo-L2-one-table.json @@ -0,0 +1,178 @@ +{ + "header_types" : [ + { + "name" : "ethernet_t", + "id" : 0, + "fields" : [ + ["dstAddr", 48, false], + ["srcAddr", 48, false], + ["etherType", 16, false] + ] + }, + { + "name" : "pna_main_parser_input_metadata_t", + "id" : 1, + "fields" : [ + ["recirculated", 1, false], + ["input_port", 32, false], + ["_padding", 7, false] + ] + }, + { + "name" : "pna_main_input_metadata_t", + "id" : 2, + "fields" : [ + ["recirculated", 1, false], + ["timestamp", 64, false], + ["parser_error", 32, false], + ["class_of_service", 8, false], + ["input_port", 32, false], + ["_padding_0", 7, false] + ] + }, + { + "name" : "pna_main_output_metadata_t", + "id" : 3, + "fields" : [ + ["class_of_service", 8, false] + ] + }, + { + "name" : "scalars_t", + "id" : 4, + "fields" : [] + } + ], + "headers" : [ + { + "name" : "eth", + "id" : 0, + "header_type" : "ethernet_t", + "metadata" : false, + "pi_omit" : true + }, + { + "name" : "pna_main_parser_input_metadata", + "id" : 1, + "header_type" : "pna_main_parser_input_metadata_t", + "metadata" : true, + "pi_omit" : true + }, + { + "name" : "pna_main_input_metadata", + "id" : 2, + "header_type" : "pna_main_input_metadata_t", + "metadata" : true, + "pi_omit" : true + }, + { + "name" : "pna_main_output_metadata", + "id" : 3, + "header_type" : "pna_main_output_metadata_t", + "metadata" : true, + "pi_omit" : true + }, + { + "name" : "", + "id" : 4, + "header_type" : "scalars_t", + "metadata" : false, + "pi_omit" : true + } + ], + "header_stacks" : [], + "header_union_types" : [], + "header_unions" : [], + "header_union_stacks" : [], + "field_lists" : [], + "errors" : [], + "enums" : [ + { + "name" : "PNA_MeterColor_t", + "entries" : [ + ["GREEN", 1], + ["RED", 0], + ["YELLOW", 2] + ] + } + ], + "parsers" : [ + { + "name" : "main_parser", + "id" : 0, + "init_state" : "start", + "parse_states" : [ + { + "name" : "start", + "id" : 0, + "parser_ops" : [ + { + "parameters" : [ + { + "type" : "regular", + "value" : "eth" + } + ], + "op" : "extract" + } + ], + "transitions" : [ + { + "type" : "default", + "value" : null, + "mask" : null, + "next_state" : null + } + ], + "transition_key" : [] + } + ] + } + ], + "parse_vsets" : [], + "deparsers" : [ + { + "name" : "main_deparser", + "id" : 0, + "source_info" : { + "filename" : "pna-demo-L2-one-table.p4", + "line" : 98, + "column" : 8, + "source_fragment" : "MainDeparserImpl" + }, + "order" : ["eth"], + "primitives" : [] + } + ], + "meter_arrays" : [], + "counter_arrays" : [], + "register_arrays" : [], + "calculations" : [], + "learn_lists" : [], + "actions" : [], + "pipelines" : [ + { + "name" : "main_control", + "id" : 0, + "source_info" : { + "filename" : "pna-demo-L2-one-table.p4", + "line" : 58, + "column" : 8, + "source_fragment" : "MainControlImpl" + }, + "init_table" : null, + "tables" : [], + "action_profiles" : [], + "conditionals" : [] + } + ], + "checksums" : [], + "force_arith" : [], + "extern_instances" : [], + "field_aliases" : [], + "program" : "pna-demo-L2-one-table.p4", + "__meta__" : { + "version" : [2, 23], + "compiler" : "https://github.com/p4lang/p4c" + } +} \ No newline at end of file diff --git a/targets/pna_nic/tests/utils.cpp b/targets/pna_nic/tests/utils.cpp new file mode 100644 index 00000000..ee748611 --- /dev/null +++ b/targets/pna_nic/tests/utils.cpp @@ -0,0 +1,63 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#include +#include +#include +#include // for std::copy, std::min + +#include "utils.h" + +PacketInReceiver::PacketInReceiver() { } + +void +PacketInReceiver::receive(int port_num, const char *buffer, int len, + void *cookie) { + (void) cookie; + std::unique_lock lock(mutex); + while (status != Status::CAN_RECEIVE) { + can_receive.wait(lock); + } + buffer_.insert(buffer_.end(), buffer, buffer + len); + port = port_num; + status = Status::CAN_READ; + can_read.notify_one(); +} + +size_t +PacketInReceiver::read(char *dst, size_t max_size, int *recv_port) { + std::unique_lock lock(mutex); + while (status != Status::CAN_READ) { + can_read.wait(lock); + } + size_t size = std::min(max_size, buffer_.size()); + std::copy(buffer_.begin(), buffer_.begin() + size, dst); + buffer_.clear(); + *recv_port = port; + status = Status::CAN_RECEIVE; + can_receive.notify_one(); + return size; +} + +PacketInReceiver::Status +PacketInReceiver::check_status() { + std::unique_lock lock(mutex); + return status; +} \ No newline at end of file diff --git a/targets/pna_nic/tests/utils.h b/targets/pna_nic/tests/utils.h new file mode 100644 index 00000000..990413bc --- /dev/null +++ b/targets/pna_nic/tests/utils.h @@ -0,0 +1,56 @@ +/* Copyright 2024 Marvell Technology, Inc. + * + * 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. + */ + +/* + * Rupesh Chiluka (rchiluka@marvell.com) + * + */ + +#ifndef PNA_NIC_TESTS_UTILS_H_ +#define PNA_NIC_TESTS_UTILS_H_ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +class PacketInReceiver { + public: + enum class Status { CAN_READ, CAN_RECEIVE }; + + PacketInReceiver(); + + void receive(int port_num, const char *buffer, int len, void *cookie); + + size_t read(char *dst, size_t max_size, int *recv_port); + + Status check_status(); + + private: + std::vector buffer_{}; + int port; + Status status{Status::CAN_RECEIVE}; + mutable std::mutex mutex{}; + mutable std::condition_variable can_receive{}; + mutable std::condition_variable can_read{}; +}; + +#endif // PNA_NIC_TESTS_UTILS_H_ \ No newline at end of file