From 11c789bd4e49fbac666d543c3101be74cf88b45d Mon Sep 17 00:00:00 2001 From: rupesh-chiluka-marvell <166586543+rupesh-chiluka-marvell@users.noreply.github.com> Date: Thu, 8 Aug 2024 02:32:40 +0530 Subject: [PATCH] Add Basic PNA externs: Meter, Counter, Hash, etc (#1263) --- 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 +++++++ 11 files changed, 744 insertions(+), 1 deletion(-) 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 5c21ec3e..2ae34b70 100644 --- a/targets/pna_nic/Makefile.am +++ b/targets/pna_nic/Makefile.am @@ -10,7 +10,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..4253fd1d --- /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; +} diff --git a/targets/pna_nic/externs/pna_counter.h b/targets/pna_nic/externs/pna_counter.h new file mode 100644 index 00000000..9d8479be --- /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 diff --git a/targets/pna_nic/externs/pna_hash.cpp b/targets/pna_nic/externs/pna_hash.cpp new file mode 100644 index 00000000..ba688ac9 --- /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; +} diff --git a/targets/pna_nic/externs/pna_hash.h b/targets/pna_nic/externs/pna_hash.h new file mode 100644 index 00000000..762f3985 --- /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 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..96c40723 --- /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; +} 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..0cc2d817 --- /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 diff --git a/targets/pna_nic/externs/pna_meter.cpp b/targets/pna_nic/externs/pna_meter.cpp new file mode 100644 index 00000000..5419ba64 --- /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; +} diff --git a/targets/pna_nic/externs/pna_meter.h b/targets/pna_nic/externs/pna_meter.h new file mode 100644 index 00000000..718ae9db --- /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 diff --git a/targets/pna_nic/externs/pna_random.cpp b/targets/pna_nic/externs/pna_random.cpp new file mode 100644 index 00000000..b787345c --- /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; +} diff --git a/targets/pna_nic/externs/pna_random.h b/targets/pna_nic/externs/pna_random.h new file mode 100644 index 00000000..d645930f --- /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