From 560e3cc0337b4a09b7027551878073a5ed0dba8e Mon Sep 17 00:00:00 2001 From: Srikishen Pondicherry Shanmugam Date: Mon, 9 Dec 2024 09:09:52 +0000 Subject: [PATCH] Adding p4rt_fixed_table_programming_helper_test.cc to test/lib --- tests/lib/BUILD.bazel | 15 ++ ...4rt_fixed_table_programming_helper_test.cc | 223 ++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 tests/lib/p4rt_fixed_table_programming_helper_test.cc diff --git a/tests/lib/BUILD.bazel b/tests/lib/BUILD.bazel index d6e7f410..130c8c4f 100644 --- a/tests/lib/BUILD.bazel +++ b/tests/lib/BUILD.bazel @@ -52,6 +52,21 @@ cc_library( ], ) +cc_test( + name = "p4rt_fixed_table_programming_helper_test", + srcs = ["p4rt_fixed_table_programming_helper_test.cc"], + deps = [ + ":p4rt_fixed_table_programming_helper", + "//gutil:status_matchers", + "//p4_pdpi:ir_cc_proto", + "//sai_p4/instantiations/google:instantiations", + "//sai_p4/instantiations/google:sai_p4info_cc", + "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", + "@com_google_absl//absl/status", + "@com_google_googletest//:gtest_main", + ], +) + cc_library( name = "switch_test_setup_helpers", testonly = True, diff --git a/tests/lib/p4rt_fixed_table_programming_helper_test.cc b/tests/lib/p4rt_fixed_table_programming_helper_test.cc new file mode 100644 index 00000000..f11c2cc0 --- /dev/null +++ b/tests/lib/p4rt_fixed_table_programming_helper_test.cc @@ -0,0 +1,223 @@ +// Copyright 2024 Google LLC +// +// 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 +// +// https://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 "tests/lib/p4rt_fixed_table_programming_helper.h" + +#include "absl/status/status.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gutil/status_matchers.h" +#include "p4/v1/p4runtime.pb.h" +#include "p4_pdpi/ir.pb.h" +#include "sai_p4/instantiations/google/instantiations.h" +#include "sai_p4/instantiations/google/sai_p4info.h" + +namespace gpins { +namespace { + +using ::gutil::StatusIs; +using ::testing::HasSubstr; + +MATCHER_P(HasExactMatch, value, "") { + for (const auto& match_field : arg.entity().table_entry().match()) { + if (match_field.exact().value() == value) { + return true; + } + } + return false; +} + +MATCHER_P2(HasLpmMatch, value, prefix, "") { + for (const auto& match_field : arg.entity().table_entry().match()) { + if (match_field.lpm().value() == value && + match_field.lpm().prefix_len() == prefix) { + return true; + } + } + return false; +} + +MATCHER_P2(HasTernaryMatch, value, mask, "") { + for (const auto& match_field : arg.entity().table_entry().match()) { + if (match_field.ternary().value() == value && + match_field.ternary().mask() == mask) { + return true; + } + } + return false; +} + +MATCHER_P(HasOptionalMatch, value, "") { + for (const auto& match_field : arg.entity().table_entry().match()) { + if (match_field.optional().value() == value) { + return true; + } + } + return false; +} + +MATCHER_P(HasActionParam, value, "") { + for (const auto& action_param : + arg.entity().table_entry().action().action().params()) { + if (action_param.value() == value) { + return true; + } + } + return false; +} + +// The L3 route programming tests verify that a given P4Info can translate all +// the flows needed to do L3 routing. +using L3RouteProgrammingTest = testing::TestWithParam; + +TEST_P(L3RouteProgrammingTest, RouterInterfaceId) { + ASSERT_OK_AND_ASSIGN(p4::v1::Update pi_update, + pins::RouterInterfaceTableUpdate( + sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + /*router_interface_id=*/"rid-0", + /*port=*/"1", + /*src_mac=*/"00:01:02:03:04:05")); + + EXPECT_THAT(pi_update, HasExactMatch("rid-0")); + EXPECT_THAT(pi_update, HasActionParam("1")); + EXPECT_THAT(pi_update, HasActionParam("\001\002\003\004\005")); +} + +TEST_P(L3RouteProgrammingTest, RouterInterfaceIdFailsWithInvalidMacAddress) { + EXPECT_THAT(pins::RouterInterfaceTableUpdate(sai::GetIrP4Info(GetParam()), + p4::v1::Update::INSERT, + /*router_interface_id=*/"rid-0", + /*port=*/"1", + /*src_mac=*/"invalid_format"), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Invalid MAC address"))); +} + +TEST_P(L3RouteProgrammingTest, NeighborId) { + ASSERT_OK_AND_ASSIGN( + p4::v1::Update pi_update, + pins::NeighborTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + /*router_interface_id=*/"rid-1", + /*neighbor_id=*/"::1", + /*dst_mac=*/"00:01:02:03:04:05")); + + EXPECT_THAT(pi_update, HasExactMatch("rid-1")); + EXPECT_THAT(pi_update, HasActionParam("\001\002\003\004\005")); +} + +TEST_P(L3RouteProgrammingTest, NeighborIdFailsWithInvalidMacAddress) { + EXPECT_THAT( + pins::NeighborTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + /*router_interface_id=*/"rid-1", + /*neighbor_id=*/"peer-1", + /*dst_mac=*/"invalid_format"), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Invalid MAC address"))); +} + + +TEST_P(L3RouteProgrammingTest, VrfTableAddFailsWithEmptyId) { + EXPECT_THAT( + pins::VrfTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + /*vrf_id=*/""), + StatusIs(absl::StatusCode::kInvalidArgument)); +} +TEST_P(L3RouteProgrammingTest, Ipv4TableDoesNotRequireAnAction) { + // The helper class will assume a default (e.g. drop). + ASSERT_OK_AND_ASSIGN( + p4::v1::Update pi_update, + pins::Ipv4TableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::IpTableOptions{.vrf_id = "vrf-0"})); + + EXPECT_THAT(pi_update, HasExactMatch("vrf-0")); +} + +TEST_P(L3RouteProgrammingTest, Ipv4TableWithSetNexthopAction) { + ASSERT_OK_AND_ASSIGN( + p4::v1::Update pi_update, + pins::Ipv4TableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::IpTableOptions{ + .vrf_id = "vrf-0", + .dst_addr_lpm = std::make_pair("10.1.1.1", 32), + .action = pins::IpTableOptions::Action::kSetNextHopId, + .nexthop_id = "nexthop-0", + })); + + EXPECT_THAT(pi_update, HasExactMatch("vrf-0")); + EXPECT_THAT(pi_update, HasLpmMatch("\n\001\001\001", 32)); + EXPECT_THAT(pi_update, HasActionParam("nexthop-0")); +} + +TEST_P(L3RouteProgrammingTest, Ipv4TableEntryFailsWihInvalidParameters) { + EXPECT_THAT( + pins::Ipv4TableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::IpTableOptions{ + .vrf_id = "vrf-0", + .action = pins::IpTableOptions::Action::kDrop, + .nexthop_id = "nexthop-0", + }), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Expected 0 parameters"))); +} + +TEST_P(L3RouteProgrammingTest, L3AdmitTableWithoutInPort) { + ASSERT_OK_AND_ASSIGN( + p4::v1::Update pi_update, + pins::L3AdmitTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::L3AdmitOptions{ + .priority = 10, + .dst_mac = std::make_pair("01:02:03:04:05:06", + "FF:FF:FF:FF:FF:FF"), + })); + + EXPECT_THAT(pi_update, HasTernaryMatch("\001\002\003\004\005\006", + "\377\377\377\377\377\377")); +} + +TEST_P(L3RouteProgrammingTest, L3AdmitTableWithInPort) { + ASSERT_OK_AND_ASSIGN( + p4::v1::Update pi_update, + pins::L3AdmitTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::L3AdmitOptions{ + .priority = 10, + .dst_mac = std::make_pair("01:02:03:04:05:06", + "FF:FF:FF:FF:FF:FF"), + .in_port = "in-port-1", + })); + + EXPECT_THAT(pi_update, HasOptionalMatch("in-port-1")); + EXPECT_THAT(pi_update, HasTernaryMatch("\001\002\003\004\005\006", + "\377\377\377\377\377\377")); +} + +TEST_P(L3RouteProgrammingTest, L3AdmitTableMustSetPriority) { + EXPECT_THAT( + pins::L3AdmitTableUpdate(sai::GetIrP4Info(GetParam()), p4::v1::Update::INSERT, + pins::L3AdmitOptions{ + .dst_mac = std::make_pair("01:02:03:04:05:06", + "FF:FF:FF:FF:FF:FF"), + }), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("require a positive non-zero priority"))); +} + +INSTANTIATE_TEST_SUITE_P( + L3RouteProgrammingTestInstance, L3RouteProgrammingTest, + testing::Values(sai::Instantiation::kMiddleblock, + sai::Instantiation::kFabricBorderRouter), + [](const testing::TestParamInfo& param) { + return sai::InstantiationToString(param.param); + }); + +} // namespace +} // namespace gpins