From 24065bf6683bf1d72051a771fc677e0fa8d9c163 Mon Sep 17 00:00:00 2001 From: VSuryaprasad-hcl <159443973+VSuryaprasad-HCL@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:21:01 +0000 Subject: [PATCH 1/9] [P4 Fuzzer] Move tests into pins_infra/tests/forwarding. (#678) Co-authored-by: jonathan-dilorenzo --- p4_fuzzer/fuzzer_tests.cc | 271 -------------- tests/forwarding/BUILD.bazel | 48 ++- tests/forwarding/fuzzer_tests.cc | 583 +++++++++++++++++++++++++++++++ tests/forwarding/fuzzer_tests.h | 130 +++++++ tests/gnoi/bert_tests.cc | 125 ------- 5 files changed, 759 insertions(+), 398 deletions(-) delete mode 100644 p4_fuzzer/fuzzer_tests.cc create mode 100644 tests/forwarding/fuzzer_tests.cc create mode 100644 tests/forwarding/fuzzer_tests.h diff --git a/p4_fuzzer/fuzzer_tests.cc b/p4_fuzzer/fuzzer_tests.cc deleted file mode 100644 index 9defc445..00000000 --- a/p4_fuzzer/fuzzer_tests.cc +++ /dev/null @@ -1,271 +0,0 @@ -// 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 -// -// 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 "p4_fuzzer/fuzzer_tests.h" - -#include -#include - -#include "absl/container/flat_hash_set.h" -#include "absl/flags/flag.h" -#include "absl/random/random.h" -#include "absl/random/seed_sequences.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" -#include "absl/strings/substitute.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "gutil/collections.h" -#include "gutil/status.h" -#include "gutil/status_matchers.h" -#include "lib/gnmi/gnmi_helper.h" -#include "p4/v1/p4runtime.pb.h" -#include "p4_fuzzer/annotation_util.h" -#include "p4_fuzzer/fuzz_util.h" -#include "p4_fuzzer/fuzzer.pb.h" -#include "p4_fuzzer/switch_state.h" -#include "p4_pdpi/connection_management.h" -#include "p4_pdpi/entity_management.h" -#include "p4_pdpi/ir.h" -#include "p4_pdpi/ir.pb.h" -#include "p4_pdpi/sequencing.h" -#include "sai_p4/instantiations/google/sai_p4info.h" -#include "thinkit/mirror_testbed_fixture.h" -#include "thinkit/test_environment.h" - -ABSL_FLAG(int, fuzzer_iterations, 1000, - "Number of updates the fuzzer should generate."); - -namespace p4_fuzzer { - -using ::p4::v1::WriteRequest; - -TEST_P(FuzzTest, P4rtWriteAndCheckNoInternalErrors) { - thinkit::Switch& sut = GetMirrorTestbed().Sut(); - thinkit::TestEnvironment& environment = GetMirrorTestbed().Environment(); - - pdpi::IrP4Info info = sai::GetIrP4Info(sai::SwitchRole::kMiddleblock); - FuzzerConfig config = { - .info = info, - .ports = {"1"}, - .qos_queues = {"0x1"}, - .role = "sdn_controller", - }; - - bool mask_known_failures = environment.MaskKnownFailures(); - - // Push the gnmi configuration. - ASSERT_OK( - pins_test::PushGnmiConfig(GetMirrorTestbed().Sut(), GetGnmiConfig())); - ASSERT_OK(pins_test::PushGnmiConfig(GetMirrorTestbed().ControlSwitch(), - GetGnmiConfig())); - - // Initialize connection. - ASSERT_OK_AND_ASSIGN(auto stub, sut.CreateP4RuntimeStub()); - ASSERT_OK_AND_ASSIGN( - std::unique_ptr session, - pdpi::P4RuntimeSession::Create(std::move(stub), sut.DeviceId())); - ASSERT_OK(pdpi::SetForwardingPipelineConfig( - session.get(), sai::GetP4Info(sai::SwitchRole::kMiddleblock))); - - // Clear switch state. - ASSERT_OK(pdpi::ClearTableEntries(session.get(), info)); - - absl::BitGen gen; - - // Run fuzzer. - int num_updates = 0; - int num_ok_statuses = 0; - int num_notok_without_mutations = 0; - int num_ok_with_mutations = 0; - int max_batch_size = 0; - std::set error_messages; - SwitchState state(info); - int num_iterations = absl::GetFlag(FLAGS_fuzzer_iterations); - for (int i = 0; i < num_iterations; i++) { - if (i % 100 == 0) LOG(INFO) << "Starting iteration " << (i + 1); - - // Generated fuzzed request. - AnnotatedWriteRequest annotated_request = - FuzzWriteRequest(&gen, config, state); - WriteRequest request = RemoveAnnotations(annotated_request); - num_updates += request.updates_size(); - max_batch_size = std::max(max_batch_size, request.updates_size()); - // Set IDs. - request.set_device_id(session->DeviceId()); - *request.mutable_election_id() = session->ElectionId(); - - ASSERT_OK(environment.AppendToTestArtifact( - "requests_and_responses.txt", - absl::StrCat("# Write request number ", i + 1, "\n", - MakeReadable(annotated_request).DebugString()))); - ASSERT_OK(environment.AppendToTestArtifact("pi_write_request_trace.txt", - request.DebugString())); - - // Send to switch. - grpc::ClientContext context; - p4::v1::WriteResponse pi_response; - ASSERT_OK_AND_ASSIGN( - pdpi::IrWriteRpcStatus response, - pdpi::GrpcStatusToIrWriteRpcStatus( - session->Stub().Write(&context, request, &pi_response), - request.updates_size())); - - ASSERT_OK(environment.AppendToTestArtifact( - "requests_and_responses.txt", - absl::StrCat("# Response to request number ", i + 1, "\n", - response.DebugString()))); - - // TODO: enable this once the switch actually returns a real reply - // for all inputs. - if (!mask_known_failures) { - ASSERT_TRUE(response.has_rpc_response()) - << "Expected proper response, but got: " << response.DebugString(); - } - if (response.has_rpc_response()) { - for (int i = 0; i < response.rpc_response().statuses().size(); i++) { - const pdpi::IrUpdateStatus& status = - response.rpc_response().statuses(i); - const p4::v1::Update& update = request.updates(i); - - // TODO: enable this once the switch stops returning INTERNAL - // errors. - if (!mask_known_failures) { - EXPECT_NE(status.code(), google::rpc::Code::INTERNAL) - << "Fuzzing should never cause an INTERNAL error, but got: " - << status.DebugString(); - } - // Check resource exhaustion. - if (status.code() == google::rpc::Code::RESOURCE_EXHAUSTED) { - int table_id = update.entity().table_entry().table_id(); - ASSERT_OK_AND_ASSIGN( - const pdpi::IrTableDefinition& table, - gutil::FindOrStatus(info.tables_by_id(), table_id)); - // TODO: acl_pre_ingress_table has a resource limit - // problem. - // TODO: router_interface_table, ipv4_table and - // ipv6_table all have resource limit problems. - // TODO: wcmp_group_table has a resource limit problem. - if (!(mask_known_failures && - (table.preamble().alias() == "acl_pre_ingress_table" || - table.preamble().alias() == "router_interface_table" || - table.preamble().alias() == "ipv4_table" || - table.preamble().alias() == "ipv6_table" || - table.preamble().alias() == "wcmp_group_table"))) { - // Check that table was full before this status. - ASSERT_TRUE(state.IsTableFull(table_id)) << absl::Substitute( - "Switch reported RESOURCE_EXHAUSTED for table named '$0'. The " - "table currently has $1 entries, but is supposed to support at " - "least $2 entries.\nUpdate = $3\nState = $4", - table.preamble().alias(), state.GetNumTableEntries(table_id), - table.size(), update.DebugString(), state.SwitchStateSummary()); - } - } - // Collect error messages and update state. - if (status.code() != google::rpc::Code::OK) { - error_messages.insert(absl::StrCat( - google::rpc::Code_Name(status.code()), ": ", status.message())); - } else { - ASSERT_OK(state.ApplyUpdate(update)); - num_ok_statuses += 1; - } - - bool is_mutated = annotated_request.updates(i).mutations_size() > 0; - - // If the Fuzzer uses a mutation, then the update is likely to be - // invalid. - if (status.code() == google::rpc::Code::OK && is_mutated) { - EXPECT_OK(environment.AppendToTestArtifact( - "fuzzer_mutated_but_ok.txt", - absl::StrCat("-------------------\n\nRequest = \n", - annotated_request.updates(i).DebugString()))); - num_ok_with_mutations++; - } - - if (status.code() != google::rpc::Code::OK && - status.code() != google::rpc::Code::RESOURCE_EXHAUSTED && - status.code() != google::rpc::Code::UNIMPLEMENTED) { - if (!is_mutated) { - // Switch did not consider update OK but fuzzer did not use a - // mutation (i.e. thought the update should be valid). - EXPECT_OK(environment.AppendToTestArtifact( - "fuzzer_inaccuracies.txt", - absl::StrCat("-------------------\n\nrequest = \n", - annotated_request.updates(i).DebugString(), - "\n\nstatus = \n", status.DebugString()))); - EXPECT_OK(environment.AppendToTestArtifact( - "fuzzer_inaccuracies_short.txt", - absl::StrCat(status.message(), "\n"))); - num_notok_without_mutations += 1; - } - } - } - } - } - - LOG(INFO) << "Finished " << num_iterations << " iterations."; - LOG(INFO) << " num_updates: " << num_updates; - // Expected value is 50, so if it's very far from that, we probably have a - // problem. - LOG(INFO) << " Avg updates per request: " - << num_updates / static_cast(num_iterations); - LOG(INFO) << " max updates in a request: " << max_batch_size; - LOG(INFO) << " num_ok_statuses: " << num_ok_statuses; - - // These should be 0 if the fuzzer works optimally. These numbers do not - // affect the soundness of the fuzzer, just the modularity, so it is a goal - // that we are not 100% strict on as it would be incredibly challenging to - // enforce. However, it is highly likely that bugs in the switch, which we - // can't currently detect, are hidden in these numbers. - LOG(INFO) << " num_notok_without_mutations: " << num_notok_without_mutations; - LOG(INFO) << " num_ok_with_mutations: " << num_ok_with_mutations; - - LOG(INFO) << "Final state:"; - LOG(INFO) << state.SwitchStateSummary(); - - EXPECT_OK(environment.StoreTestArtifact("final_switch_state.txt", - state.SwitchStateSummary())); - - EXPECT_OK(environment.StoreTestArtifact("error_messages.txt", - absl::StrJoin(error_messages, "\n"))); - - // Leave the switch in a clean state and log the final state to help with - // debugging. - // TODO: Clean-up has a known bug where deletion of existing - // table entries fails. - if (!mask_known_failures) { - ASSERT_OK_AND_ASSIGN(auto table_entries, - pdpi::ReadPiTableEntries(session.get())); - for (const auto& entry : table_entries) { - EXPECT_OK(environment.AppendToTestArtifact( - "clearing__pi_entries_read_from_switch.txt", entry)); - } - std::vector pi_updates = - pdpi::CreatePiUpdates(table_entries, p4::v1::Update::DELETE); - ASSERT_OK_AND_ASSIGN( - std::vector sequenced_clear_requests, - pdpi::SequencePiUpdatesIntoWriteRequests(info, pi_updates)); - - for (int i = 0; i < sequenced_clear_requests.size(); i++) { - EXPECT_OK(environment.AppendToTestArtifact( - "clearing__delete_write_requests.txt", - absl::StrCat("# Delete write batch ", i + 1, ".\n"))); - EXPECT_OK(environment.AppendToTestArtifact( - "clearing__delete_write_requests.txt", sequenced_clear_requests[i])); - } - ASSERT_OK(pdpi::SetMetadataAndSendPiWriteRequests( - session.get(), sequenced_clear_requests)); - } -} - -} // namespace p4_fuzzer diff --git a/tests/forwarding/BUILD.bazel b/tests/forwarding/BUILD.bazel index a8e343de..f662b4cf 100644 --- a/tests/forwarding/BUILD.bazel +++ b/tests/forwarding/BUILD.bazel @@ -97,7 +97,6 @@ cc_library( ], alwayslink = True, ) - cc_library( name = "packet_test_util", testonly = True, @@ -111,7 +110,6 @@ cc_library( "@com_google_absl//absl/container:flat_hash_map", ], ) - cc_library( name = "group_programming_util", testonly = True, @@ -140,6 +138,52 @@ cc_library( ], ) +cc_library( + name = "fuzzer_tests", + testonly = True, + srcs = ["fuzzer_tests.cc"], + hdrs = ["fuzzer_tests.h"], + deps = [ + "//gutil:collections", + "//gutil:status", + "//gutil:status_matchers", + "//gutil:version", + "//lib/gnmi:gnmi_helper", + "//lib/p4rt:p4rt_port", + "//p4_fuzzer:annotation_util", + "//p4_fuzzer:fuzzer_cc_proto", + "//p4_fuzzer:fuzzer_config", + "//p4_fuzzer:mutation_and_fuzz_util", + "//p4_fuzzer:switch_state", + "//p4_pdpi:ir_cc_proto", + "//p4_pdpi:names", + "//p4_pdpi:p4_runtime_session", + "//p4_pdpi:p4_runtime_session_extras", + "//p4_pdpi:sequencing", + "//sai_p4/instantiations/google:p4_versions", + "//tests:thinkit_sanity_tests", + "//tests/lib:switch_test_setup_helpers", + "//thinkit:mirror_testbed", + "//thinkit:mirror_testbed_fixture", + "//thinkit:switch", + "//thinkit:test_environment", + "@com_github_gnmi//proto/gnmi:gnmi_cc_proto", + "@com_github_google_glog//:glog", + "@com_github_p4lang_p4runtime//:p4info_cc_proto", + "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/container:btree", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:seed_sequences", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest", + ], +) + cc_library( name = "watch_port_test", testonly = True, diff --git a/tests/forwarding/fuzzer_tests.cc b/tests/forwarding/fuzzer_tests.cc new file mode 100644 index 00000000..97ffb242 --- /dev/null +++ b/tests/forwarding/fuzzer_tests.cc @@ -0,0 +1,583 @@ +// 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 +// +// 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 "tests/forwarding/fuzzer_tests.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/container/flat_hash_set.h" +#include "absl/flags/flag.h" +#include "absl/random/random.h" +#include "absl/random/seed_sequences.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "glog/logging.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gutil/collections.h" +#include "gutil/status.h" // IWYU pragma: keep +#include "gutil/status_matchers.h" // IWYU pragma: keep +#include "gutil/version.h" +#include "lib/gnmi/gnmi_helper.h" +#include "lib/p4rt/p4rt_port.h" +#include "p4/v1/p4runtime.pb.h" +#include "p4_fuzzer/annotation_util.h" +#include "p4_fuzzer/fuzz_util.h" +#include "p4_fuzzer/fuzzer.pb.h" +#include "p4_fuzzer/fuzzer_config.h" +#include "p4_fuzzer/switch_state.h" +#include "p4_pdpi/ir.pb.h" +#include "p4_pdpi/names.h" +#include "p4_pdpi/p4_runtime_session.h" +#include "p4_pdpi/p4_runtime_session_extras.h" +#include "p4_pdpi/sequencing.h" +#include "proto/gnmi/gnmi.pb.h" +// TODO: A temporary dependence on SAI to mask a bug. Ideally, safe +// to remove in April 2024. +#include "sai_p4/instantiations/google/versions.h" +#include "tests/lib/switch_test_setup_helpers.h" +#include "tests/thinkit_sanity_tests.h" +#include "thinkit/mirror_testbed.h" +#include "thinkit/mirror_testbed_fixture.h" +#include "thinkit/switch.h" +#include "thinkit/test_environment.h" + +ABSL_FLAG(std::optional, fuzzer_iterations, std::nullopt, + "Number of updates the fuzzer should generate. If not set, fuzzer " + "runs until `fuzzer_duration` seconds has elapsed (default 1 hour)."); + +// NOTE: If fuzzer_duration flag > 1 hour, then test_timeout blaze flag must be +// set to > 1 hour to avoid timeout failure when running blaze test. +ABSL_FLAG(absl::Duration, fuzzer_duration, absl::Hours(1), + "Max duration the fuzzer should run for. Includes time for setup and" + "tear down."); + +ABSL_FLAG( + std::vector, fuzzer_ports, {}, + "Set of valid port names for the fuzzer to use. The empty default value " + "signifies that the fuzzer should get the ports from the gNMI config."); + +ABSL_FLAG(std::vector, fuzzer_qos_queues, {"0x1"}, + "Set of valid QoS queues for the fuzzer to use."); + +ABSL_FLAG(bool, fuzzer_clear_switch_at_end, true, + "Clear the switch (possibly through forcible restart) at end of " + "test. Useful to disable for debugging."); + +namespace p4_fuzzer { +namespace { + +// Buffer time to wind down testing after the test iterations are complete. +constexpr absl::Duration kEndOfTestBuffer = absl::Minutes(10); + +bool IsMaskedResource(absl::string_view table_name, + gutil::Version current_version) { + absl::flat_hash_set masked_tables = {}; + + // TODO: Remove version check when the P4Info version in release + // is equal or higher than SAI_P4_PKGINFO_VERSION_FIXED_INGRESS_ACL_RESOURCE. + gutil::Version version_with_good_ingress_acls = gutil::ParseVersionOrDie( + SAI_P4_PKGINFO_VERSION_FIXED_INGRESS_ACL_RESOURCE); + if (current_version < version_with_good_ingress_acls) { + masked_tables.insert("acl_ingress_table"); + masked_tables.insert("acl_ingress_security_table"); + masked_tables.insert("acl_ingress_mirror_and_redirect_table"); + } + return masked_tables.contains(table_name); +} + +} // namespace + +// FuzzerTestFixture class functions + +void FuzzerTestFixture::SetUp() { + GetParam().mirror_testbed->SetUp(); + if (auto& id = GetParam().test_case_id; id.has_value()) { + GetParam().mirror_testbed->GetMirrorTestbed().Environment().SetTestCaseID( + *id); + } +} + +void FuzzerTestFixture::TearDown() { + auto& sut = GetParam().mirror_testbed->GetMirrorTestbed().Sut(); + + // Save the logs before reset clearing to help with debug in case of failure. + if (HasFatalFailure()) { + LOG(INFO) << "Saving failure state."; + EXPECT_OK(GetParam().mirror_testbed->SaveSwitchLogs( + /*save_prefix=*/"failure_state_")); + } + + // Clear the switch of all entries if flag is enabled. + if (absl::GetFlag(FLAGS_fuzzer_clear_switch_at_end)) { + // Attempt to connect to switch and clear tables. + auto session = pdpi::P4RuntimeSession::Create(sut); + absl::Status switch_cleared = + session.ok() ? pdpi::ClearEntities(**session) : session.status(); + + // Though the above statement should never fail, it sometimes + // inadvertently does due to some bug. Then we reboot the switch to + // clear the state. + if (!switch_cleared.ok()) { + ADD_FAILURE() + << "Failed to clear entries from switch (attempting reboot)"; + LOG(WARNING) << "Dumping reported error:\n " << switch_cleared; + // Save the logs before rebooting to help with debug. + EXPECT_OK(GetParam().mirror_testbed->SaveSwitchLogs( + /*save_prefix=*/"failed_to_clear_sut_state_")); + pins_test::TestGnoiSystemColdReboot(sut); + } + } + GetParam().mirror_testbed->TearDown(); +} + +using ::p4::v1::WriteRequest; + +TEST_P(FuzzerTestFixture, P4rtWriteAndCheckNoInternalErrors) { + const absl::Time deadline = + absl::Now() + absl::GetFlag(FLAGS_fuzzer_duration) - kEndOfTestBuffer; + + // Gets the mirror testbed from the test parameters given to + // FuzzerTestFixture. + thinkit::MirrorTestbed& mirror_testbed = + GetParam().mirror_testbed->GetMirrorTestbed(); + thinkit::Switch& sut = mirror_testbed.Sut(); + thinkit::TestEnvironment& environment = mirror_testbed.Environment(); + + // Probabilities must be between 0 and 1. + float mutate_update_probability = GetParam().mutate_update_probability; + ASSERT_GE(mutate_update_probability, 0.0); + ASSERT_LE(mutate_update_probability, 1.0); + + // Initialize connection, clear switch state, and push the GNMI configuration, + // if given. + ASSERT_OK_AND_ASSIGN(std::unique_ptr session, + pins_test::ConfigureSwitchAndReturnP4RuntimeSession( + sut, GetParam().gnmi_config, GetParam().p4info)); + + // Current switch version. + ASSERT_OK_AND_ASSIGN( + gutil::Version current_version, + gutil::ParseVersion(GetParam().p4info.pkg_info().version())); + + // TODO: Remove version check when the P4Info version in release + // is equal or higher than SAI_P4_PKGINFO_VERSION_USES_FAIL_ON_FIRST. + ASSERT_OK_AND_ASSIGN( + gutil::Version first_version_with_fail_on_first, + gutil::ParseVersion(SAI_P4_PKGINFO_VERSION_USES_FAIL_ON_FIRST)); + + // Record gNMI config and P4Info that we plan to push for debugging purposes. + if (GetParam().gnmi_config.has_value()) { + ASSERT_OK(environment.StoreTestArtifact("gnmi_config.txt", + *GetParam().gnmi_config)); + } + ASSERT_OK(environment.StoreTestArtifact("p4info.txt", GetParam().p4info)); + + bool mask_known_failures = environment.MaskKnownFailures(); + + // Construct gNMI stub. + ASSERT_OK_AND_ASSIGN(std::unique_ptr stub, + sut.CreateGnmiStub()); + + ASSERT_OK_AND_ASSIGN(std::vector ports, + pins_test::P4rtPortId::MakeVectorFromP4rtEncodings( + absl::GetFlag(FLAGS_fuzzer_ports))); + if (ports.empty()) { + // Get all valid ports from the gNMI config if none are specified as a flag. + // Currently, we only get Ethernet ports by default. + ASSERT_OK_AND_ASSIGN(ports, + pins_test::GetMatchingP4rtPortIds( + *stub, pins_test::IsEnabledEthernetInterface)); + } + + ASSERT_OK_AND_ASSIGN( + p4_fuzzer::FuzzerConfig config, + p4_fuzzer::FuzzerConfig::Create( + GetParam().p4info, + ConfigParams{ + .ports = ports, + .qos_queues = absl::GetFlag(FLAGS_fuzzer_qos_queues), + .role = GetParam().p4rt_role, + .mutate_update_probability = mutate_update_probability, + .tables_for_which_to_not_exceed_resource_guarantees = + GetParam().tables_for_which_to_not_exceed_resource_guarantees, + .disabled_fully_qualified_names = + GetParam().disabled_fully_qualified_names, + .non_modifiable_tables = GetParam().non_modifiable_tables, + .TreatAsEqualDuringReadDueToKnownBug = + GetParam().TreatAsEqualDuringReadDueToKnownBug, + .ignore_constraints_on_tables = + GetParam().ignore_constraints_on_tables, + })); + + // TODO: b/316926338 - Remove once switch state transitions to entities. This + // would allow multicast to be included in the weighted distribution the + // fuzzer uses. + int total_entries_supported = GetParam().multicast_group_table_size; + for (const auto& table : AllValidTablesForP4RtRole(config)) { + total_entries_supported += table.size(); + } + double fuzz_multicast_probability = + static_cast(GetParam().multicast_group_table_size) / + static_cast(total_entries_supported); + config.SetFuzzMulticastGroupEntryProbability(fuzz_multicast_probability); + LOG(INFO) << "Proability of fuzzing multicast is " + << fuzz_multicast_probability; + + // TODO: Remove absl::StreamFormatter when we update to a new LTS + // branch of Abseil. + ASSERT_OK(environment.StoreTestArtifact( + "ports_used_by_fuzzer.txt", + absl::StrJoin(config.GetPorts(), ",", absl::StreamFormatter()))); + ASSERT_OK(environment.StoreTestArtifact( + "queues_used_fuzzer.txt", + absl::StrJoin(config.GetQosQueues(), ",", absl::StreamFormatter()))); + + absl::BitGen gen; + + const absl::Time start_time = absl::Now(); + + // Run fuzzer. + int num_updates = 0; + int num_ok_statuses = 0; + int num_notok_without_mutations = 0; + int num_ok_with_mutations = 0; + int max_batch_size_seen = 0; + std::set error_messages; + SwitchState state(config.GetIrP4Info()); + const std::optional num_iterations = + absl::GetFlag(FLAGS_fuzzer_iterations); + int iteration = 0; + + int longest_iteration = 0; + absl::Duration longest_iteration_duration = absl::ZeroDuration(); + + // Run until the deadline or until we've fuzzed for the requested number of + // iterations. + while (absl::Now() < deadline && + (!num_iterations.has_value() || iteration < *num_iterations)) { + iteration++; + absl::Time iteration_start_time = absl::Now(); + if (iteration % 100 == 1) LOG(INFO) << "Starting iteration " << iteration; + + // Generated fuzzed request. + AnnotatedWriteRequest annotated_request = + FuzzWriteRequest(&gen, config, state, GetParam().max_batch_size); + WriteRequest request = RemoveAnnotations(annotated_request); + num_updates += request.updates_size(); + max_batch_size_seen = std::max(max_batch_size_seen, request.updates_size()); + + ASSERT_OK(environment.AppendToTestArtifact( + "requests_and_responses.txt", + absl::StrCat("# Write request number ", iteration, "\n", + MakeReadable(annotated_request).DebugString()))); + ASSERT_OK(environment.AppendToTestArtifact("pi_write_request_trace.txt", + request.DebugString())); + + // Send to switch. + ASSERT_OK_AND_ASSIGN(pdpi::IrWriteRpcStatus response, + pdpi::SendPiUpdatesAndReturnPerUpdateStatus( + *session, request.updates())); + + ASSERT_OK(environment.AppendToTestArtifact( + "requests_and_responses.txt", + absl::StrCat("# Response to request number ", iteration, "\n", + response.DebugString()))); + + // If there is an RPC-wide error, then the switch has gone into critical + // state and we can no longer continue testing. + ASSERT_TRUE(response.has_rpc_response()) + << "Expected proper response, but got: " << response.DebugString(); + + ASSERT_TRUE( + (response.rpc_response().statuses().size() == request.updates_size())) + << "Expected number of responses to equal number of updates, but they " + "differed. Updates: " + << request.updates_size() + << " Responses: " << response.rpc_response().statuses().size(); + + ASSERT_OK(OutputInterleavedRequestAndResponseToArtifact( + environment, /*artifact_name=*/"requests_and_responses_interleaved.txt", + /*identifying_prefix=*/absl::StrCat("Iteration ", iteration), + annotated_request, response)); + + // Ensure that the responses from the switch correctly use fail-on-first + // ordering. + if (!GetParam().do_not_enforce_fail_on_first_switch_ordering && + current_version >= first_version_with_fail_on_first) { + bool encountered_first_error = false; + for (const pdpi::IrUpdateStatus& status : + response.rpc_response().statuses()) { + if (status.code() == google::rpc::Code::OK && + !encountered_first_error) { + continue; + } + ASSERT_TRUE(!encountered_first_error || + status.code() == google::rpc::Code::ABORTED) + << "Expected all responses after first failure to be ABORTED, but " + "got: " + << status.DebugString() << "\n\nFull Response:\n" + << response.rpc_response().DebugString(); + encountered_first_error = true; + } + } + + // We update our internal view of the switch state incrementally and check + // for resource exhaustion. + for (int update_num = 0; + update_num < response.rpc_response().statuses().size(); update_num++) { + const pdpi::IrUpdateStatus& status = + response.rpc_response().statuses(update_num); + const p4::v1::Update& update = request.updates(update_num); + + EXPECT_NE(status.code(), google::rpc::Code::INTERNAL) + << "Fuzzing should never cause an INTERNAL error, but got: " + << status.DebugString(); + // Check resource exhaustion. + // TODO: b/286413264 - Check for invalid multicast resource exhaustion + // once multicast resource are modeled. + if (status.code() == google::rpc::Code::RESOURCE_EXHAUSTED && + update.entity().has_table_entry()) { + int table_id = update.entity().table_entry().table_id(); + ASSERT_OK_AND_ASSIGN( + const pdpi::IrTableDefinition& table, + gutil::FindOrStatus(config.GetIrP4Info().tables_by_id(), table_id)); + + // If this isn't a specifically masked resource, then check if resource + // exhaustion is allowed. + if (!IsMaskedResource(table.preamble().alias(), current_version)) { + // Check that table is allowed to have exhausted resources. + ASSERT_OK( + state.ResourceExhaustedIsAllowed(update.entity().table_entry())) + << "\nUpdate = " << update.DebugString() + << "\nState = " << state.SwitchStateSummary(); + } + } + // Collect error messages and update state. + if (status.code() != google::rpc::Code::OK) { + error_messages.insert(absl::StrCat( + google::rpc::Code_Name(status.code()), ": ", status.message())); + } else { + ASSERT_OK(state.ApplyUpdate(update)); + num_ok_statuses += 1; + } + + bool is_mutated = + annotated_request.updates(update_num).mutations_size() > 0; + + // If the Fuzzer uses a mutation, then the update is likely to be + // invalid. + if (status.code() == google::rpc::Code::OK && is_mutated) { + EXPECT_OK(environment.AppendToTestArtifact( + "fuzzer_mutated_but_ok.txt", + absl::StrCat("-------------------\n\nRequest = \n", + annotated_request.updates(update_num).DebugString()))); + num_ok_with_mutations++; + } + + if (status.code() != google::rpc::Code::OK && + status.code() != google::rpc::Code::RESOURCE_EXHAUSTED && + status.code() != google::rpc::Code::ABORTED && + status.code() != google::rpc::Code::UNIMPLEMENTED) { + if (!is_mutated) { + // Switch did not consider update OK but fuzzer did not use a + // mutation (i.e. thought the update should be valid). + EXPECT_OK(environment.AppendToTestArtifact( + "fuzzer_inaccuracies.txt", + absl::StrCat("-------------------\n\nrequest = \n", + annotated_request.updates(update_num).DebugString(), + "\n\nstatus = \n", status.DebugString()))); + EXPECT_OK(environment.AppendToTestArtifact( + "fuzzer_inaccuracies_short.txt", + absl::StrCat(status.message(), "\n"))); + num_notok_without_mutations += 1; + } + } + } + + if (!GetParam().milestone.has_value()) { + // Read switch state (to check that reading never fails). + ASSERT_OK_AND_ASSIGN(std::vector table_entries, + pdpi::ReadPiTableEntries(session.get())); + if (mask_known_failures) { + ASSERT_OK(state.AssertEntriesAreEqualToState( + table_entries, config.GetTreatAsEqualDuringReadDueToKnownBug())); + } else { + ASSERT_OK(state.AssertEntriesAreEqualToState(table_entries)); + } + } + + if (absl::Duration current_duration = absl::Now() - iteration_start_time; + current_duration > longest_iteration_duration) { + longest_iteration = iteration; + longest_iteration_duration = current_duration; + } + } + + if (num_iterations.has_value() && iteration < *num_iterations) { + ADD_FAILURE() + << "Iteration mode enabled. Fuzzer test ran out of time after " + << iteration << " out of " << *num_iterations << " iterations." + << " Fuzzer_Duration set to " << absl::GetFlag(FLAGS_fuzzer_duration) + << " seconds."; + } + + LOG(INFO) << "Finished " << iteration << " iterations."; + LOG(INFO) << " num_updates: " << num_updates; + // Expected value is 50, so if it's very far from that, we probably have a + // problem. + LOG(INFO) << " Avg updates per request: " + << num_updates / static_cast(iteration); + LOG(INFO) << " max updates in a request: " << max_batch_size_seen; + LOG(INFO) << " num_ok_statuses: " << num_ok_statuses; + + // These should be 0 if the fuzzer works optimally. These numbers do not + // affect the soundness of the fuzzer, just the modularity, so it is a goal + // that we are not 100% strict on as it would be incredibly challenging to + // enforce. However, it is highly likely that bugs in the switch, which we + // can't currently detect, are hidden in these numbers. + LOG(INFO) << " num_notok_without_mutations: " << num_notok_without_mutations; + LOG(INFO) << " num_ok_with_mutations: " << num_ok_with_mutations; + + LOG(INFO) << "Fuzzer Duration Limit: " + << absl::GetFlag(FLAGS_fuzzer_duration); + LOG(INFO) << "Test set up/tear down buffer: " << kEndOfTestBuffer; + LOG(INFO) << "Time Spent Fuzzing: " << (absl::Now() - start_time); + + LOG(INFO) << "Longest Iteration: " << longest_iteration; + LOG(INFO) << "Longest Iteration Duration: " << longest_iteration_duration; + + LOG(INFO) << "Final state:"; + LOG(INFO) << state.SwitchStateSummary(); + + EXPECT_OK(environment.StoreTestArtifact("final_switch_state.txt", + state.SwitchStateSummary())); + + EXPECT_OK(environment.StoreTestArtifact("error_messages.txt", + absl::StrJoin(error_messages, "\n"))); + + // Save switch logs at the `final_switch_state`. + + EXPECT_OK(GetParam().mirror_testbed->SaveSwitchLogs( + /*save_prefix=*/"final_switch_state_before_clearing_")); + + // Unless we are testing a specific milestone, ensure that clearing all + // tables succeeds. Can be safely skipped as we also clean up the switch + // during TearDown, but is helpful to detect switch bugs. + if (!GetParam().milestone.has_value() && + absl::GetFlag(FLAGS_fuzzer_clear_switch_at_end)) { + ASSERT_OK_AND_ASSIGN(auto entities, pdpi::ReadPiEntities(session.get())); + for (const auto& entity : entities) { + EXPECT_OK(environment.AppendToTestArtifact( + "clearing_pi_entities_read_from_switch.txt", entity)); + } + + // TODO: b/317373445 - Replace sequencing and batching code with function + // once it is available in sequencing library. + + // Sort by dependency order, then reverse since we will be deleting. + ASSERT_OK(pdpi::StableSortEntities(config.GetIrP4Info(), entities)); + absl::c_reverse(entities); + + std::vector pi_updates = + pdpi::CreatePiUpdates(entities, p4::v1::Update::DELETE); + + std::vector batched_clear_requests; + WriteRequest request; + + std::optional last_rank = std::nullopt; + int current_rank = 0; + // The P4 Runtime specification states that a good rule of thumb for the + // size of request is "8192 + MAX_UPDATES_PER_WRITE * 100 bytes of + // metadata". P4RuntimeSession uses a 1MB limit and 5000 updates falls + // safely within those limits and is simultaneously more than we ever tend + // to send. + int max_batch_size = 5000; + for (const p4::v1::Update& update : pi_updates) { + // If the switch doesn't support fail-on-first, batch requests based on + // rank AND number of updates. + // TODO: Remove version check when the P4Info version in + // release is equal or higher than + // SAI_P4_PKGINFO_VERSION_USES_FAIL_ON_FIRST. + if (current_version < first_version_with_fail_on_first) { + ASSERT_OK_AND_ASSIGN( + std::string table_name, + pdpi::EntityToTableName(config.GetIrP4Info(), update.entity())); + ASSERT_OK_AND_ASSIGN( + current_rank, + gutil::FindOrStatus( + config.GetIrP4Info().dependency_rank_by_table_name(), + table_name)); + // If we have reached a new entity rank or the limit of update size, + // start a new request. + if (last_rank.has_value() && *last_rank != current_rank) { + batched_clear_requests.push_back(std::move(request)); + request = WriteRequest(); + } + } + if (request.updates_size() > max_batch_size) { + batched_clear_requests.push_back(std::move(request)); + request = WriteRequest(); + } + + *request.add_updates() = update; + last_rank = current_rank; + } + if (request.updates_size() > 0) { + batched_clear_requests.push_back(std::move(request)); + } + + for (int i = 0; i < batched_clear_requests.size(); i++) { + EXPECT_OK(environment.AppendToTestArtifact( + "clearing_delete_write_requests.txt", + absl::StrCat("# Delete write batch ", i + 1, ".\n"))); + EXPECT_OK(environment.AppendToTestArtifact( + "clearing_delete_write_requests.txt", batched_clear_requests[i])); + } + ASSERT_OK(pdpi::SetMetadataAndSendPiWriteRequests(session.get(), + batched_clear_requests)); + } +} + +bool AbslParseFlag(absl::string_view milestone_text, Milestone* milestone, + std::string* error) { + for (auto& [milestone_, string] : MilestoneToStringMapping()) { + if (string == milestone_text) { + *milestone = milestone_; + return true; + } + } + absl::StrAppend(error, "unknown milestone: '", milestone_text, "'"); + return false; +} + +std::string AbslUnparseFlag(Milestone milestone) { + for (auto& [milestone_, string] : MilestoneToStringMapping()) { + if (milestone_ == milestone) return string; + } + LOG(DFATAL) << "invalid milestone: " << static_cast(milestone); + return ""; +} + +} // namespace p4_fuzzer diff --git a/tests/forwarding/fuzzer_tests.h b/tests/forwarding/fuzzer_tests.h new file mode 100644 index 00000000..5f3b04e3 --- /dev/null +++ b/tests/forwarding/fuzzer_tests.h @@ -0,0 +1,130 @@ +// 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 +// +// 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. +#ifndef PINS_TESTS_P4_FUZZER_FUZZER_TESTS_H_ +#define PINS_TESTS_P4_FUZZER_FUZZER_TESTS_H_ + +#include +#include +#include +#include +#include + +#include "absl/container/btree_set.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" +#include "p4/config/v1/p4info.pb.h" +#include "p4_fuzzer/fuzzer.pb.h" +#include "p4_pdpi/ir.pb.h" +#include "thinkit/mirror_testbed_fixture.h" + +namespace p4_fuzzer { + +// Used for testing a specific milestone, ignoring MaskKnownFailures(), rather +// than everything, respecting MaskKnownFailures(). +enum class Milestone { + // Tests that the switch adheres to the minimum guarantees on resources + // currently defined in + // google3/third_party/pins_infra/sai_p4/instantiations/google/minimum_guaranteed_sizes.p4. + kResourceLimits, + kInvalidInputs, +}; + +inline std::vector> +MilestoneToStringMapping() { + return { + {Milestone::kResourceLimits, "resource_limits"}, + {Milestone::kInvalidInputs, "invalid_inputs"}, + }; +} + +struct FuzzerTestFixtureParams { + thinkit::MirrorTestbedInterface* mirror_testbed; + // The test assumes that the switch is pre-configured if no `gnmi_config` is + // given (default), or otherwise pushes the given config before starting. + std::optional gnmi_config; + p4::config::v1::P4Info p4info; + // Maximum batch size of a single write request generated by the fuzzer. + std::optional max_batch_size; + // The probability of performing a mutation on a given table entry. + float mutate_update_probability = 0.1; + // TODO: b/286413264 - Remove once multicast resources are modeled in p4. + // The size of the built-in multicast group table. + int multicast_group_table_size = 512; + // Determines which type of issues the fuzzer detects. If left out, the fuzzer + // will test everything, respecting MaskKnownFailures(). See declaration of + // Milestone for more details. + std::optional milestone; + std::optional test_case_id; + // By default, the fuzzer attempts to exceed the listed resource guarantees on + // all tables, allowing the switch to reject entries beyond those guarantees + // with a RESOURCE_EXHAUSTED error. + // This variable lets users specify a set of tables for which the fuzzer + // should treat their resource guarantees as hard limits rather than trying to + // go above them. If there are limitations or bugs on the switch causing it to + // behave incorrectly when the resource guarantees of particular tables are + // exceeded, this list can be used to allow the fuzzer to produce interesting + // results in spite of this shortcoming. + absl::btree_set + tables_for_which_to_not_exceed_resource_guarantees; + // Fully qualified names of tables, actions, or match fields to skip during + // fuzzing. Match field names should be prepended with the relevant table name + // to uniquely identify them. + // Users should ensure that any set that makes it impossible to generate a + // valid table entry for a particular table contains the table itself. + // TODO: Check the property above instead. + absl::flat_hash_set disabled_fully_qualified_names; + // TODO: Fully qualified names of tables that do not support + // MODIFY updates. This behaviour is not compliant with p4 runtime spec. + absl::flat_hash_set non_modifiable_tables; + // The P4RT role the fuzzer should use. + std::string p4rt_role; + // A function for masking inequalities (due to known bugs) between entries + // with the same TableEntryKey on the switch and in the fuzzer. + std::optional< + std::function> + TreatAsEqualDuringReadDueToKnownBug; + // Ignores the constraints on tables listed when fuzzing entries. + absl::flat_hash_set ignore_constraints_on_tables; + // This parameter makes the Fuzzer test NOT check and enforce fail-on-first + // ordering in switch responses. By default, we expect such ordering. + // TODO: Get this information from the P4Info instead of using a + // parameter. + bool do_not_enforce_fail_on_first_switch_ordering; + // A function for masking any updates that should not be sent to the switch. + std::function IsBuggyUpdateThatShouldBeSkipped = + [](const AnnotatedUpdate& update) { return false; }; +}; + +class FuzzerTestFixture + : public testing::TestWithParam { + protected: + // Sets up the mirror test bed, then sets the test_case_id. + void SetUp() override; + + // Resets switch state after a fatal failure by attempting to clear the switch + // tables normally, falling back to rebooting the switch. Also runs the + // standard mirror test bed tear down procedure. + void TearDown() override; + + ~FuzzerTestFixture() override { delete GetParam().mirror_testbed; } +}; + +bool AbslParseFlag(absl::string_view milestone_text, Milestone* milestone, + std::string* error); +std::string AbslUnparseFlag(Milestone milestone); + +} // namespace p4_fuzzer + +#endif // PINS_TESTS_P4_FUZZER_FUZZER_TESTS_H_ diff --git a/tests/gnoi/bert_tests.cc b/tests/gnoi/bert_tests.cc index def55955..de9c58f3 100644 --- a/tests/gnoi/bert_tests.cc +++ b/tests/gnoi/bert_tests.cc @@ -784,129 +784,4 @@ TEST_P(BertTest, StartBertSucceeds) { // ASSERT_OK(pins_test::PortsUp(control_switch)); } -// Runs the BERT test on current maximum allowed number of interfaces. During -// the BERT run: -// 1) Disable admin state of few ports on SUT, -// 2) Disable admin state of few ports on control switch, -// This helps us verify a mix of operation during BERT - unexpected software or -// hardware errors. -TEST_P(BertTest, RunBertOnMaximumAllowedPorts) { - thinkit::Switch& sut = GetMirrorTestbed().Sut(); - ASSERT_OK_AND_ASSIGN(std::unique_ptr sut_gnmi_stub, - sut.CreateGnmiStub()); - ASSERT_OK(pins_test::PortsUp(sut)); - ASSERT_OK_AND_ASSIGN( - std::unique_ptr sut_gnoi_diag_stub, - sut.CreateGnoiDiagStub()); - - thinkit::Switch& control_switch = GetMirrorTestbed().ControlSwitch(); - ASSERT_OK_AND_ASSIGN( - std::unique_ptr control_switch_gnmi_stub, - control_switch.CreateGnmiStub()); - ASSERT_OK(pins_test::PortsUp(control_switch)); - ASSERT_OK_AND_ASSIGN( - std::unique_ptr control_switch_gnoi_diag_stub, - control_switch.CreateGnoiDiagStub()); - - // Get all the interfaces that are operational status "UP". - ASSERT_OK_AND_ASSIGN(std::vector interfaces, - pins_test::GetUpInterfacesOverGnmi(*sut_gnmi_stub)); - // For this test, we need at least 5 UP interfaces. - ASSERT_GE(interfaces.size(), 5); - // Resize the interface list if UP ports are more than max number of allowed - // ports. - if (interfaces.size() > kMaxAllowedInterfacesToRunBert) { - interfaces.resize(kMaxAllowedInterfacesToRunBert); - } - - // Select 'N' ports on control switch and 'N' ports on SUT for admin down. - int num_interfaces_to_disable = 1 + (interfaces.size() / 16); - // Seed the std::rand(). - LOG(INFO) << "Seeding pseudo-random number generator with seed: " - << absl::GetFlag(FLAGS_idx_seed); - // Select SUT interfaces in the range [0..interfaces/2). - std::vector sut_interfaces_for_admin_down; - std::sample(interfaces.begin(), interfaces.begin() + interfaces.size() / 2, - std::back_inserter(sut_interfaces_for_admin_down), - num_interfaces_to_disable, - std::mt19937(absl::GetFlag(FLAGS_idx_seed))); - // Select control switch interfaces in the range [interfaces/2..interfaces]. - std::vector control_switch_interfaces_for_admin_down; - std::sample(interfaces.begin() + interfaces.size() / 2, interfaces.end(), - std::back_inserter(control_switch_interfaces_for_admin_down), - num_interfaces_to_disable, - std::mt19937(absl::GetFlag(FLAGS_idx_seed))); - - LOG(INFO) << "Starting BERT on " << interfaces.size() << " interfaces."; - - gnoi::diag::StartBERTRequest bert_request; - // Create the BERT request. - bert_request.set_bert_operation_id( - absl::StrCat("OpId-", absl::ToUnixMillis(absl::Now()))); - for (const std::string& interface : interfaces) { - *(bert_request.add_per_port_requests()) = - gutil::ParseProtoOrDie( - BuildPerPortStartBertRequest(interface)); - } - - // Request StartBert on the SUT switch. - { - gnoi::diag::StartBERTResponse bert_response; - grpc::ClientContext context; - EXPECT_OK( - sut_gnoi_diag_stub->StartBERT(&context, bert_request, &bert_response)); - } - - // Request StartBert on the control switch. - { - gnoi::diag::StartBERTResponse bert_response; - grpc::ClientContext context; - EXPECT_OK(control_switch_gnoi_diag_stub->StartBERT(&context, bert_request, - &bert_response)); - } - - absl::Time start_time = absl::Now(); - // Give some time to BERT to move in SYNC state. - absl::SleepFor(absl::Seconds(90)); - - absl::Time end_time = absl::Now(); - - // Poll for remaining BERT duration. - int max_poll_count = - 1 + (absl::ToInt64Seconds(kDelayDuration + kWaitTime + kSyncDuration + - kTestDuration - (end_time - start_time) - - absl::Seconds(1)) / - ToInt64Seconds(kPollInterval)); - std::vector interfaces_not_up = interfaces; - for (int count = 0; count < max_poll_count; ++count) { - absl::SleepFor(kPollInterval); - // If port is "UP" and no longer in "TESTING" oper state on both sides of - // link, BERT has completed on the link and full BERT result is ready. - for (auto it = interfaces_not_up.begin(); it != interfaces_not_up.end();) { - ASSERT_OK_AND_ASSIGN( - pins_test::OperStatus oper_status, - pins_test::GetInterfaceOperStatusOverGnmi(*sut_gnmi_stub, *it)); - if (oper_status == pins_test::OperStatus::kUp) { - ASSERT_OK_AND_ASSIGN(oper_status, - pins_test::GetInterfaceOperStatusOverGnmi( - *control_switch_gnmi_stub, *it)); - if (oper_status == pins_test::OperStatus::kUp) { - it = interfaces_not_up.erase(it); - continue; - } - } - ++it; - } - if (interfaces_not_up.empty()) break; - } - - EXPECT_THAT(interfaces_not_up, testing::IsEmpty()); - - // Wait for some time before checking the port status. - absl::SleepFor(absl::Seconds(10)); - - ASSERT_OK(pins_test::PortsUp(sut)); - ASSERT_OK(pins_test::PortsUp(control_switch)); -} - } // namespace bert From a1e7bcf214f45b0dc120aa2ce498c0d14bb7fdab Mon Sep 17 00:00:00 2001 From: VSuryaprasad-hcl <159443973+VSuryaprasad-HCL@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:29:12 +0000 Subject: [PATCH 2/9] [p4_symbolic] Add control flow graph analysis. (#682) Co-authored-by: kheradmandG Co-authored-by: kishanps --- p4_symbolic/ir/BUILD.bazel | 44 +- p4_symbolic/ir/cfg.cc | 317 +++ p4_symbolic/ir/cfg.h | 194 ++ p4_symbolic/ir/cfg_test.cc | 501 ++++ p4_symbolic/ir/expected/basic.txt | 7 + .../ir/expected/complex_conditional.txt | 90 + p4_symbolic/ir/expected/conditional.txt | 14 + .../ir/expected/conditional_sequence.txt | 84 + p4_symbolic/ir/expected/hardcoded.txt | 10 + p4_symbolic/ir/expected/reflector.txt | 4 + p4_symbolic/ir/expected/set_invalid.txt | 14 + p4_symbolic/ir/expected/table.txt | 4 + p4_symbolic/ir/expected/table_hit_1.txt | 7 + p4_symbolic/ir/expected/table_hit_2.txt | 14 + p4_symbolic/ir/ir.cc | 37 +- p4_symbolic/ir/ir.h | 3 +- p4_symbolic/ir/ir.proto | 18 + p4_symbolic/symbolic/BUILD.bazel | 1 + p4_symbolic/symbolic/conditional.cc | 57 +- .../symbolic/expected/conditional.smt2 | 166 +- .../expected/conditional_sequence.smt2 | 2295 ++--------------- p4_symbolic/symbolic/table.cc | 39 +- p4_symbolic/symbolic/util.cc | 32 +- p4_symbolic/symbolic/util.h | 4 +- 24 files changed, 1696 insertions(+), 2260 deletions(-) create mode 100644 p4_symbolic/ir/cfg.cc create mode 100644 p4_symbolic/ir/cfg.h create mode 100644 p4_symbolic/ir/cfg_test.cc diff --git a/p4_symbolic/ir/BUILD.bazel b/p4_symbolic/ir/BUILD.bazel index c60fd320..21875e54 100644 --- a/p4_symbolic/ir/BUILD.bazel +++ b/p4_symbolic/ir/BUILD.bazel @@ -79,13 +79,53 @@ cc_library( "ir.h", ], deps = [ + ":cfg", ":ir_cc_proto", - ":table_entries", "//gutil:status", "//p4_symbolic/bmv2:bmv2_cc_proto", "@com_github_p4lang_p4runtime//:p4info_cc_proto", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/container:node_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "cfg", + srcs = [ + "cfg.cc", + "ir.h", # needed for the definition of EndOfPipeline + ], + hdrs = ["cfg.h"], + deps = [ + ":ir_cc_proto", + "//gutil:status", + "//p4_symbolic/bmv2:bmv2_cc_proto", + "@com_google_absl//absl/container:btree", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/container:node_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "cfg_test", + srcs = ["cfg_test.cc"], + deps = [ + ":cfg", + ":ir", + ":ir_cc_proto", + "//gutil:proto", + "//gutil:status_matchers", + "@com_google_absl//absl/container:btree", + "@com_google_absl//absl/status", "@com_google_absl//absl/strings", - "@com_google_protobuf//:protobuf", + "@com_google_googletest//:gtest_main", ], ) diff --git a/p4_symbolic/ir/cfg.cc b/p4_symbolic/ir/cfg.cc new file mode 100644 index 00000000..b610221a --- /dev/null +++ b/p4_symbolic/ir/cfg.cc @@ -0,0 +1,317 @@ +// 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 +// +// 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 "p4_symbolic/ir/cfg.h" + +#include +#include +#include +#include + +#include "absl/container/flat_hash_set.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/substitute.h" +#include "gutil/status.h" +#include "p4_symbolic/ir/ir.h" + +namespace p4_symbolic::ir { + +namespace { + +// Returns the set of the children of the given `control_name` in the given +// `program`. +absl::StatusOr> GetChildren( + const P4Program &program, const std::string &control_name) { + absl::btree_set children; + + if (control_name == EndOfPipeline()) return children; + + if (auto it = program.conditionals().find(control_name); + it != program.conditionals().end()) { + for (const auto &branch : + {it->second.if_branch(), it->second.else_branch()}) { + children.insert(branch); + } + + } else if (auto it = program.tables().find(control_name); + it != program.tables().end()) { + for (const auto &[_, next_control] : + it->second.table_implementation().action_to_next_control()) { + children.insert(next_control); + } + } else { + return absl::InvalidArgumentError( + absl::Substitute("Unrecognized control '$0'", control_name)); + } + + return children; +} + +// Returns the LCP of two control paths. +ControlPath LongestCommonPrefix(const ControlPath &l, const ControlPath &r) { + ControlPath result; + int index = 0; + while (index < l.size() && index < r.size() && l[index] == r[index]) { + result.push_back(l[index]); + index++; + } + return result; +} + +} // namespace + +std::string ToString(const CfgNode &node) { + return absl::Substitute( + "node: $0\n\tchildren: [$1]\n\tparents: [$2]\n\tpath_from_root: " + "$3\n\trev_path_from_leaf: $4\n\tmerge_point: $5\n\tcontinue: $6\n", + node.control_name, absl::StrJoin(node.children, ","), + absl::StrJoin(node.parents, ","), + absl::StrJoin(node.contracted_path_from_root, "->"), + absl::StrJoin(node.contracted_reverse_path_from_leaf, "<-"), + node.merge_point.has_value() ? node.merge_point.value() : "nullopt", + node.continue_to_merge_point ? "true" : "false"); +} + +std::string ControlFlowGraph::ToString() { + std::string out; + absl::StrAppend(&out, node_by_name_.size(), " nodes\n"); + for (const auto &[name, cfg_node] : node_by_name_) { + absl::StrAppend(&out, "[", name, "] ", + ::p4_symbolic::ir::ToString(cfg_node)); + } + return out; +} + +absl::StatusOr +ControlFlowGraph::GetOptimizedSymbolicExecutionInfo( + absl::string_view control_name) { + absl::StatusOr cfg_node_ptr_or_status = + GetNode(control_name); + RETURN_IF_ERROR(cfg_node_ptr_or_status.status()); + const CfgNode &cfg_node = **cfg_node_ptr_or_status; + + if (!cfg_node.merge_point.has_value()) + return absl::InvalidArgumentError( + absl::Substitute("Control node '$0' does not have a merge point", + cfg_node.control_name)); + + OptimizedSymbolicExecutionInfo info; + info.set_merge_point(*cfg_node.merge_point); + info.set_continue_to_merge_point(cfg_node.continue_to_merge_point); + return info; +} + +absl::StatusOr ControlFlowGraph::GetNode( + absl::string_view control_name) { + return GetMutableNode(control_name); +} + +absl::StatusOr ControlFlowGraph::GetMutableNode( + absl::string_view control_name) { + auto it = node_by_name_.find(control_name); + if (it == node_by_name_.end()) { + return absl::NotFoundError(absl::Substitute( + "Control name '$0' does not correspond to any node in the CFG", + control_name)); + } + + return &(it->second); +} + +CfgNode &ControlFlowGraph::GetOrAddNode(absl::string_view control_name) { + CfgNode &node = node_by_name_[control_name]; + node.control_name = control_name; + return node; +} + +absl::Status ControlFlowGraph::ConstructSubgraph( + const P4Program &program, const std::string &control_name) { + CfgNode &cfg_node = GetOrAddNode(control_name); + ASSIGN_OR_RETURN(absl::btree_set children, + GetChildren(program, control_name)); + for (const std::string &child_control_name : children) { + CfgNode &child_cfg_node = GetOrAddNode(child_control_name); + bool new_node = child_cfg_node.parents.empty(); + cfg_node.children.insert(child_control_name); + child_cfg_node.parents.insert(control_name); + if (new_node) { + // The child_cfg_node is a new node. + RETURN_IF_ERROR(ConstructSubgraph(program, child_control_name)); + } + } + + return absl::OkStatus(); +} + +absl::Status ControlFlowGraph::SetContractedReversePathFromLeaf( + CfgNode &cfg_node) { + ControlPath &reverse_path_from_leaf = + cfg_node.contracted_reverse_path_from_leaf; + + for (const auto &child : cfg_node.children) { + // Compute or get child's contracted reverse path from leaf. + ASSIGN_OR_RETURN(CfgNode * child_cfg_node, GetMutableNode(child)); + const ControlPath &child_reverse_path_from_leaf = + child_cfg_node->contracted_reverse_path_from_leaf; + if (child_reverse_path_from_leaf.empty()) { + RETURN_IF_ERROR(SetContractedReversePathFromLeaf(*child_cfg_node)); + RET_CHECK(!child_reverse_path_from_leaf.empty()) << absl::Substitute( + "Contracted reverse path from leaf of '$0' is empty", + child_cfg_node->control_name); + } + + // Set current node's reverse path from leaf to the longest common + // prefix of childrens'. + if (reverse_path_from_leaf.empty()) { + reverse_path_from_leaf = child_reverse_path_from_leaf; + } else { + // This could lead to O(n^3) complexity across graphs with O(n) branching + // factor. In practice we expect only constant branching, and thus O(n^2) + // complexity. + reverse_path_from_leaf = LongestCommonPrefix( + reverse_path_from_leaf, child_reverse_path_from_leaf); + } + } + + // Add self to the end of the reverse path from leaf. + reverse_path_from_leaf.push_back(cfg_node.control_name); + + return absl::OkStatus(); +} + +absl::Status ControlFlowGraph::SetContractedPathFromRoot(CfgNode &cfg_node) { + ControlPath &path_from_root = cfg_node.contracted_path_from_root; + + for (const auto &parent : cfg_node.parents) { + // Compute or get parent's contracted path from root. + ASSIGN_OR_RETURN(CfgNode * parent_cfg_node, GetMutableNode(parent)); + const ControlPath &parent_path_from_root = + parent_cfg_node->contracted_path_from_root; + if (parent_path_from_root.empty()) { + RETURN_IF_ERROR(SetContractedPathFromRoot(*parent_cfg_node)); + RET_CHECK(!parent_path_from_root.empty()) + << absl::Substitute("Contracted path from root of '$0' is empty", + parent_cfg_node->control_name); + } + + // Set current node's path from root to the longest common + // prefix of parents'. + if (path_from_root.empty()) { + path_from_root = parent_path_from_root; + } else { + path_from_root = + LongestCommonPrefix(path_from_root, parent_path_from_root); + } + } + + // Add self to the end of the path from root. + path_from_root.push_back(cfg_node.control_name); + + return absl::OkStatus(); +} + +absl::StatusOr> ControlFlowGraph::Create( + const P4Program &program) { + // Using `new` to access a non-public constructor. + auto cfg = absl::WrapUnique(new ControlFlowGraph()); + + // Build the basic CFG. + for (const auto &[name, pipeline] : program.pipeline()) { + RETURN_IF_ERROR( + cfg->ConstructSubgraph(program, pipeline.initial_control())); + } + + // Compute contracted paths from root and leaf for each node. + for (auto &[_, cfg_node] : cfg->node_by_name_) { + if (cfg_node.contracted_reverse_path_from_leaf.empty()) { + RETURN_IF_ERROR(cfg->SetContractedReversePathFromLeaf(cfg_node)); + RET_CHECK(!cfg_node.contracted_reverse_path_from_leaf.empty()) + << absl::Substitute( + "contracted_reverse_path_from_leaf of '$0' is empty", + cfg_node.control_name); + } + if (cfg_node.contracted_path_from_root.empty()) { + RETURN_IF_ERROR(cfg->SetContractedPathFromRoot(cfg_node)); + RET_CHECK(!cfg_node.contracted_path_from_root.empty()) + << absl::Substitute("contracted_path_from_root of '$0' is empty", + cfg_node.control_name); + } + } + + auto get_merge_point = + [](const ControlPath &contracted_path) -> std::optional { + // For any contracted path (or reverse path) [root/leaf, ..., n_{k-1}, + // n_k] ending in n_{k}, n_{k-1} is the merge point (or reverse merge + // point) of n_{k} since n_{k-1}. For example, in + // c1 - implicit source + // / \ + // c2 t3 + // / \ / + // t1 t2 / + // \ / / + // t4 - implicit sink + // Contracted reverse path from leaf of c2 is [t4, c2] and the merge point + // of c2 is t4. Also contracted path from root of t2 is [c1, c2, t2] and the + // reverse merge point of t2 c2. + // The merge point / rever merge point of nodes with out-degree / in-degree + // 0 is the implicit sink / source node. We denote that with nullopt (see + // the assumptions in cfg.h). E.g. the merge point of t4 above is nullopt. + return contracted_path.size() > 1 + ? std::optional(contracted_path.rbegin()[1]) + : std::nullopt; + }; + + // Compute continuation (for optimized symbolic execution) for each node. + for (auto &[_, cfg_node] : cfg->node_by_name_) { + // Compute the merge point. + cfg_node.merge_point = + get_merge_point(cfg_node.contracted_reverse_path_from_leaf); + + // Determine continue_to_merge_point. + cfg_node.continue_to_merge_point = false; + if (cfg_node.merge_point.has_value()) { + ASSIGN_OR_RETURN(const CfgNode *merge_point_cfg_node, + cfg->GetNode(*cfg_node.merge_point)); + std::optional merge_point_reverse_merge_point = + get_merge_point(merge_point_cfg_node->contracted_path_from_root); + + // May continue to the merge point iff the reverse merge point (i.e. merge + // point in reverse direction) of the merge point (if any) of the node is + // the node itself (i.e. the given node is the latest node + // prior to the merge point such that all execution paths going through + // the merge point also go through the current node). + // This is to prevent executing shared merge points more than once. + // For example, in the following graph + // c1 - implicit source + // / \ + // c2 t3 + // / \ / + // t1 t2 / + // \ / / + // t4 - implicit sink + // The merge points of c1, c2, t1, t2, t3 are t4. We must only continue to + // t4 from c1 because the revesrse merge point of t4 is c1. + if (merge_point_reverse_merge_point.has_value() && + *merge_point_reverse_merge_point == cfg_node.control_name) { + cfg_node.continue_to_merge_point = true; + } + } + } + + return std::move(cfg); +} + +} // namespace p4_symbolic::ir diff --git a/p4_symbolic/ir/cfg.h b/p4_symbolic/ir/cfg.h new file mode 100644 index 00000000..f5c1c519 --- /dev/null +++ b/p4_symbolic/ir/cfg.h @@ -0,0 +1,194 @@ +// 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 +// +// 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. + +// Defines APIs for constructing control flow graph of a P4 program and +// performing analysis useful for optimized symbolic execution. +// See go/optimized-symbolic-execution. + +#ifndef PINS_P4_SYMBOLIC_IR_CFG_H_ +#define PINS_P4_SYMBOLIC_IR_CFG_H_ + +#include +#include +#include + +#include "absl/container/btree_set.h" +#include "absl/container/flat_hash_set.h" +#include "absl/container/node_hash_map.h" +#include "absl/status/statusor.h" +#include "p4_symbolic/ir/ir.pb.h" + +namespace p4_symbolic::ir { + +// A subsequence of an execution path in a P4 program. Each element is a control +// name along the path. +using ControlPath = std::vector; + +// A single node in the control flow graph along with various computed metadata. +// We make the following assuptions in the descriptions and definitions below. +// 1. The collection of CfgNodes form a non-empty DAG. +// 2. The DAG has an implicit and unique root/source node implicitly connected +// to all nodes with (explicit) in-degree 0. +// 3. The DAG has an implicit and unique leaf/sink node that all nodes with +// (explicit) out-degree 0 are implicitly connected to. +// 4. We do not explicitly refer to these two implicit nodes in the code. E.g. +// do not include them in paths that start from or end in them. +struct CfgNode { + // Same as a the name of the control node in the IR. + std::string control_name; + + // The children of the current node. + // Using btree_set (here and below) for deterministic order, though not a + // necessary condition (e.g. a flat_hash_set would work too). + absl::btree_set children; + + // The parents of the current node. + absl::btree_set parents; + + // A path from the beginning of the execution (root) to the current node in + // which only nodes common to *all* possible execution paths between the two + // points are included. In other words, for any branching along the path, only + // its "merge point" (see the precise definition below) is included. + // For example, in the following graph + // -> n3 -> n4 + // / \ + // n1 -> n2 -> n6 -> n7 + // \ / + // ---> n5 --- + // The contracted path from root for n4 is n1->n2->n3->n4 and for n7 is + // n1->n2->n6->n7. + // We call such paths "contrated" because intuitively branches along the path + // are contracted. This is related to the notion of "edge contraction" from + // graph theory: given any path from ni to nj, the contracted path is obtained + // by contracting all edges along the path that are not shared among all ni -> + // nj paths. All pairs of nodes in any DAG are guaranteed to have a unique + // contracted path. + ControlPath contracted_path_from_root; + + // Same as `contracted_path_from_root` but the path is from the end of + // execution to the current node (in the reverse direction). + // In the example above, the contracted reverse path from leaf for n5 is + // n7<-n6<-n5 and for n1 is n7<-n6<-n2<-n1. + ControlPath contracted_reverse_path_from_leaf; + + // The name of the first (i.e. closest in topological order) control point + // where all paths starting from the children ("branches") of the + // current node to the sink meet. In the example above, the merge point of n1 + // is n2, for n2 it is n6, and for n3 it is n4. In any DAG with a sink node, + // any node except the sink node is guaranteed to have exactly one merge + // point. + // Note: The merge point of nodes with explicit out-degree 0 is the + // implicit sink node which is not displayed (assumptions 3 and 4 above), + // hence we use nullopt in that case. + // Concept of merge point defined here is equivalent to the concept of + // "immediate post-dominator" in graph theory literature + // (https://en.wikipedia.org/wiki/Dominator_(graph_theory)). + // TODO: Rename everything with familiar graph theory concepts. + std::optional merge_point; + + // Whether or not (optimized) symbolic execution should continue to the merge + // point after executing the subgraph of the current node (up to the merge + // point). This must be set in a way that each node in the graph is guaranteed + // to be executed exactly once: true iff the reverse merge point (i.e. merge + // point in reverse direction) of the merge point (if any) of the node is the + // node itself (see go/optimized-symbolic-execution for details). + bool continue_to_merge_point; +}; + +// Returns a string represting the information stored in the given `cfg_node`. +// Useful for debugging purposes. +std::string ToString(const CfgNode &cfg_node); + +// Control Flow Graph (CFG) of a P4 program created from its P4-Symbolic's IR +// representation along with various CFG analyses useful for optimized +// symbolic execution (go/optimized-symbolic-execution). +// Assumption: The CFG of the input P4 program forms a DAG (this is guaranteed +// in BMv2). Also there is at least one node in the DAG (this is guaranteed by +// `EndOfPipeline` node in IR). +class ControlFlowGraph { + public: + // Creates a ControlFlowGraph from an input P4 program and perform analysis + // for optimized symbolic execution. + // Runtime complexity: O(N*E) where N is the number of CFG + // nodes and E is the number of edges between the nodes. + // Note: Our most complex program at the moment has only 44 nodes, so the + // current complexity is good enough for our purposes (i.e. CFG + // analysis is not a bottleneck). We can revisit the algorithm if this becomes + // a bottleneck. + static absl::StatusOr> Create( + const P4Program &program); + + // Returns information used in optimized symbolic execution for the node + // correspnding to the given `control_name` in the graph, or error if no such + // node exists. Expects input to correspond to a node with an (explicit) + // merge point (i.e. a node with non-zero out-degree), otherwise returns + // error. + absl::StatusOr + GetOptimizedSymbolicExecutionInfo(absl::string_view control_name); + + // Returns a string represting the constructred CFG. Useful for debugging + // purposes. + std::string ToString(); + + // Disallow copy and move (for pointer stability during and after Create. + // Useful for debugging but not a necessary condition). + ControlFlowGraph(const ControlFlowGraph &) = delete; + ControlFlowGraph(ControlFlowGraph &&) = delete; + ControlFlowGraph &operator=(const ControlFlowGraph &) = delete; + ControlFlowGraph &operator=(ControlFlowGraph &&) = delete; + + private: + // Map of each control name to its correspodning CfgNode. + // Must use node_hash_map for pointer stability. + // Note: Pointer stability is a necessariy condition in this case, otherwise + // ConstructSubgraph as well as any code depending on pointers/references to + // CfgNodes in node_by_name_ would break. + absl::node_hash_map node_by_name_; + + // Can only be constructed through a call to Create. + ControlFlowGraph() = default; + + // Returns a non-null immutable pointer to the node correspnding to the given + // `control_name` in the graph, or error if no such node exists. + absl::StatusOr GetNode(absl::string_view control_name); + + // Returns a reference to the node correspnding to the given `control_name` in + // the graph. If such a node does not exist, creates and returns a new node + // with the given name. + CfgNode &GetOrAddNode(absl::string_view control_name); + + // Returns a non-null mutable pointer to the node correspnding to the given + // `control_name` in the graph, or error if no such node exists. + absl::StatusOr GetMutableNode(absl::string_view control_name); + + // Recursively constructs the subgraph corresponding to the given + // `control_name`. Updates the children and parents of the involved + // nodes. + absl::Status ConstructSubgraph(const P4Program &program, + const std::string &control_name); + + // Recursively computes the contracted reverse path from the (implicit) leaf + // to the given `cfg_node`. Sets the `contracted_reverse_path_from_leaf` field + // in the involved nodes (if not already set). + absl::Status SetContractedReversePathFromLeaf(CfgNode &cfg_node); + + // Recursively computes the contracted path from the (implicit) root to the + // given `cfg_node`. Sets the `contracted_path_from_root` field in the + // involved nodes (if not already set). + absl::Status SetContractedPathFromRoot(CfgNode &cfg_node); +}; + +} // namespace p4_symbolic::ir + +#endif // PINS_P4_SYMBOLIC_IR_CFG_H_ diff --git a/p4_symbolic/ir/cfg_test.cc b/p4_symbolic/ir/cfg_test.cc new file mode 100644 index 00000000..d57d089e --- /dev/null +++ b/p4_symbolic/ir/cfg_test.cc @@ -0,0 +1,501 @@ +#include "p4_symbolic/ir/cfg.h" + +#include + +#include "absl/container/btree_map.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gutil/proto.h" +#include "gutil/status_matchers.h" +#include "p4_symbolic/ir/ir.h" +#include "p4_symbolic/ir/ir.pb.h" + +namespace p4_symbolic::ir { +namespace { + +using gutil::StatusIs; +using testing::ValuesIn; + +struct CfgTestParam { + // Expected field values in OptimizedSymbolicExecutionInfo for a certain + // control point. + struct ExpectedInfo { + std::string merge_point; + bool continue_to_merge_point; + }; + + std::string test_name; + // The map of control_name to expected symbolic execution info only for + // control points that we care about. + absl::btree_map control_to_expected_info; + // Text proto representing the input IR P4Program. A full program is not + // necessary. It only needs to contain enough information to build the CFG. + std::string ir_program_text_proto; +}; + +absl::StatusOr ReplaceEopAndParseProgramTextProto( + absl::string_view ir_program_text_proto) { + return gutil::ParseTextProto(absl::StrReplaceAll( + ir_program_text_proto, + {{"$eop", absl::Substitute("\"$0\"", EndOfPipeline())}})); +} + +using CfgTest = ::testing::TestWithParam; +std::vector GetCfgTestInstances() { + return { + { + /* t1 - ingress + * | + * t2 - eop + */ + .test_name = "ProgramWithSequentialTables", + .control_to_expected_info = + { + {"t1", {"t2", true}}, + {"t2", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "t1" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "t2" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* c1 - ingress + * / \ + * t1 t2 + * \ / + * t3 - eop + */ + .test_name = "ProgramWithTableAfterConditional", + .control_to_expected_info = + { + {"c1", {"t3", true}}, + {"t1", {"t3", false}}, + {"t2", {"t3", false}}, + {"t3", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "t1" else_branch: "t2" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "t3" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: "t3" } } + } + } + tables { + key: "t3" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* c1 - ingress + * / | + * t1 | + * \ | + * t2 - eop + */ + .test_name = "ProgramWithConditionalWithoutElse", + .control_to_expected_info = + { + {"c1", {"t2", true}}, + {"t1", {"t2", false}}, + {"t2", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "t1" else_branch: "t2" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "t2" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* t1 - ingress + * | + * c1 + * / \ + * t2 t3 + * | / + * t4 / + * \ / + * t5 - eop + */ + .test_name = "ProgramWithCombinationOfSequentialTablesAndBranching", + .control_to_expected_info = + { + {"t1", {"c1", true}}, + {"c1", {"t5", true}}, + {"t2", {"t4", true}}, + {"t3", {"t5", false}}, + {"t4", {"t5", false}}, + {"t5", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "t1" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "c1" } } + } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "t2" else_branch: "t3" } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t3" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t4" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t5" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* c1 - ingress + * / \ + * c2 t3 + * / \ / + * t1 t2 / + * \ / / + * t4 / + * \/ + * t5 - eop + */ + .test_name = "ProgramWithNestedBranching", + .control_to_expected_info = + { + {"c1", {"t5", true}}, + {"c2", {"t4", true}}, + {"t1", {"t4", false}}, + {"t2", {"t4", false}}, + {"t3", {"t5", false}}, + {"t4", {"t5", false}}, + {"t5", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "c2" else_branch: "t3" } + } + conditionals { + key: "c2" + value { name: "c2" if_branch: "t1" else_branch: "t2" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t3" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t4" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t5" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* c1 - ingress + * / \ + * c2 t3 + * / \ / + * t1 t2 / + * \ / / + * t4 - eop + */ + .test_name = "ProgramWithSharedMergePoint", + .control_to_expected_info = + { + {"c1", {"t4", true}}, + {"c2", {"t4", false}}, + {"t1", {"t4", false}}, + {"t2", {"t4", false}}, + {"t3", {"t4", false}}, + {"t4", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "c2" else_branch: "t3" } + } + conditionals { + key: "c2" + value { name: "c2" if_branch: "t1" else_branch: "t2" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t3" + value { + table_implementation { action_to_next_control { value: "t4" } } + } + } + tables { + key: "t4" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + { + /* c1 - ingress + * / \ + * t1 t2 + * \ / + * c2 + * / \ + * t3 t4 + * \ / + * t5 - eop + */ + .test_name = "ProgramWithBranchOnMergePoint", + .control_to_expected_info = + { + {"c1", {"c2", true}}, + {"t1", {"c2", false}}, + {"t2", {"c2", false}}, + {"c2", {"t5", true}}, + {"t3", {"t5", false}}, + {"t3", {"t5", false}}, + {"t5", {EndOfPipeline(), true}}, + }, + .ir_program_text_proto = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "t1" else_branch: "t2" } + } + tables { + key: "t1" + value { + table_implementation { action_to_next_control { value: "c2" } } + } + } + tables { + key: "t2" + value { + table_implementation { action_to_next_control { value: "c2" } } + } + } + conditionals { + key: "c2" + value { name: "c2" if_branch: "t3" else_branch: "t4" } + } + tables { + key: "t3" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t4" + value { + table_implementation { action_to_next_control { value: "t5" } } + } + } + tables { + key: "t5" + value { + table_implementation { action_to_next_control { value: $eop } } + } + } + )pb", + }, + }; +} + +constexpr absl::string_view kMinimalProgram = R"pb( + pipeline { + key: "ingress" + value { name: "ingress" initial_control: "c1" } + } + conditionals { + key: "c1" + value { name: "c1" if_branch: "t1" else_branch: "t1" } + } + tables { + key: "t1" + value { table_implementation { action_to_next_control { value: $eop } } } + } +)pb"; + +TEST(GetOptimizedSymbolicExecutionInfoTest, ReturnsErrorForEndOfPipeline) { + ASSERT_OK_AND_ASSIGN(const P4Program program, + ReplaceEopAndParseProgramTextProto(kMinimalProgram)); + ASSERT_OK_AND_ASSIGN(std::unique_ptr cfg, + ControlFlowGraph::Create(program)); + + ASSERT_THAT(cfg->GetOptimizedSymbolicExecutionInfo(EndOfPipeline()), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST(GetOptimizedSymbolicExecutionInfoTest, ReturnsErrorForNonExistingNode) { + ASSERT_OK_AND_ASSIGN(const P4Program program, + ReplaceEopAndParseProgramTextProto(kMinimalProgram)); + ASSERT_OK_AND_ASSIGN(std::unique_ptr cfg, + ControlFlowGraph::Create(program)); + + ASSERT_THAT(cfg->GetOptimizedSymbolicExecutionInfo("non_existing_node"), + StatusIs(absl::StatusCode::kNotFound)); +} + +TEST(GetOptimizedSymbolicExecutionInfoTest, SucceedsForExistingControlNode) { + ASSERT_OK_AND_ASSIGN(const P4Program program, + ReplaceEopAndParseProgramTextProto(kMinimalProgram)); + ASSERT_OK_AND_ASSIGN(std::unique_ptr cfg, + ControlFlowGraph::Create(program)); + + ASSERT_THAT(cfg->GetOptimizedSymbolicExecutionInfo("c1"), + StatusIs(absl::StatusCode::kOk)); +} + +TEST(GetOptimizedSymbolicExecutionInfoTest, SucceedsForExistingTableNode) { + ASSERT_OK_AND_ASSIGN(const P4Program program, + ReplaceEopAndParseProgramTextProto(kMinimalProgram)); + ASSERT_OK_AND_ASSIGN(std::unique_ptr cfg, + ControlFlowGraph::Create(program)); + + ASSERT_THAT(cfg->GetOptimizedSymbolicExecutionInfo("t1"), + StatusIs(absl::StatusCode::kOk)); +} + +TEST_P(CfgTest, GetOptimizedSymbolicExecutionInfoReturnsExpectedInfo) { + const CfgTestParam& param = GetParam(); + + ASSERT_OK_AND_ASSIGN( + const P4Program program, + ReplaceEopAndParseProgramTextProto(param.ir_program_text_proto)); + ASSERT_OK_AND_ASSIGN(std::unique_ptr cfg, + ControlFlowGraph::Create(program)); + + for (const auto& [control_name, expected_output] : + param.control_to_expected_info) { + SCOPED_TRACE(absl::StrCat("control node: ", control_name)); + ASSERT_OK_AND_ASSIGN(auto info, + cfg->GetOptimizedSymbolicExecutionInfo(control_name)); + EXPECT_EQ(info.merge_point(), expected_output.merge_point); + EXPECT_EQ(info.continue_to_merge_point(), + expected_output.continue_to_merge_point); + } +} + +INSTANTIATE_TEST_SUITE_P( + CfgTests, CfgTest, ValuesIn(GetCfgTestInstances()), + [](const testing::TestParamInfo& info) { + return info.param.test_name; + }); + +} // namespace +} // namespace p4_symbolic::ir diff --git a/p4_symbolic/ir/expected/basic.txt b/p4_symbolic/ir/expected/basic.txt index fa3921ac..7a48ed5f 100644 --- a/p4_symbolic/ir/expected/basic.txt +++ b/p4_symbolic/ir/expected/basic.txt @@ -598,6 +598,9 @@ tables { field_name: "dstAddr" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -620,6 +623,10 @@ conditionals { } if_branch: "MyIngress.ipv4_lpm" else_branch: "__END_OF_PIPELINE__" + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/complex_conditional.txt b/p4_symbolic/ir/expected/complex_conditional.txt index 27d984e4..57adf136 100644 --- a/p4_symbolic/ir/expected/complex_conditional.txt +++ b/p4_symbolic/ir/expected/complex_conditional.txt @@ -306,6 +306,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "node_27" + continue_to_merge_point: true + } } } } @@ -388,6 +392,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyEgress.n25" + } } } } @@ -470,6 +477,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -552,6 +562,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n13" + } } } } @@ -634,6 +647,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n13" + } } } } @@ -716,6 +732,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "node_16" + } } } } @@ -798,6 +817,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "node_16" + } } } } @@ -880,6 +902,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n18" + continue_to_merge_point: true + } } } } @@ -962,6 +988,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n21" + } } } } @@ -1044,6 +1073,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n21" + } } } } @@ -1126,6 +1158,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n3" + continue_to_merge_point: true + } } } } @@ -1208,6 +1244,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n21" + } } } } @@ -1290,6 +1329,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n22" + continue_to_merge_point: true + } } } } @@ -1372,6 +1415,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -1454,6 +1500,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "node_6" + continue_to_merge_point: true + } } } } @@ -1536,6 +1586,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n9" + } } } } @@ -1618,6 +1671,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n8" + continue_to_merge_point: true + } } } } @@ -1700,6 +1757,9 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.n9" + } } } } @@ -1782,6 +1842,10 @@ tables { field_name: "f1" } } + optimized_symbolic_execution_info { + merge_point: "node_16" + continue_to_merge_point: true + } } } } @@ -1809,6 +1873,10 @@ conditionals { } if_branch: "MyIngress.n11" else_branch: "MyIngress.n12" + optimized_symbolic_execution_info { + merge_point: "MyIngress.n13" + continue_to_merge_point: true + } } } conditionals { @@ -1835,6 +1903,10 @@ conditionals { } if_branch: "node_17" else_branch: "MyIngress.n17" + optimized_symbolic_execution_info { + merge_point: "MyIngress.n21" + continue_to_merge_point: true + } } } conditionals { @@ -1861,6 +1933,9 @@ conditionals { } if_branch: "MyIngress.n19" else_branch: "MyIngress.n20" + optimized_symbolic_execution_info { + merge_point: "MyIngress.n21" + } } } conditionals { @@ -1887,6 +1962,10 @@ conditionals { } if_branch: "MyIngress.n2" else_branch: "MyIngress.n2" + optimized_symbolic_execution_info { + merge_point: "MyIngress.n2" + continue_to_merge_point: true + } } } conditionals { @@ -1913,6 +1992,10 @@ conditionals { } if_branch: "node_28" else_branch: "MyEgress.n25" + optimized_symbolic_execution_info { + merge_point: "MyEgress.n25" + continue_to_merge_point: true + } } } conditionals { @@ -1939,6 +2022,9 @@ conditionals { } if_branch: "MyEgress.n24" else_branch: "MyEgress.n25" + optimized_symbolic_execution_info { + merge_point: "MyEgress.n25" + } } } conditionals { @@ -1965,6 +2051,10 @@ conditionals { } if_branch: "MyIngress.n6" else_branch: "MyIngress.n7" + optimized_symbolic_execution_info { + merge_point: "MyIngress.n9" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/conditional.txt b/p4_symbolic/ir/expected/conditional.txt index 53c01e7b..c7c7db71 100644 --- a/p4_symbolic/ir/expected/conditional.txt +++ b/p4_symbolic/ir/expected/conditional.txt @@ -404,6 +404,9 @@ tables { field_name: "ether_type" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + } } } } @@ -525,6 +528,9 @@ tables { field_name: "src_addr" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + } } } } @@ -646,6 +652,10 @@ tables { field_name: "dst_addr" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } @@ -673,6 +683,10 @@ conditionals { } if_branch: "MyIngress.t_1" else_branch: "MyIngress.t_2" + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/conditional_sequence.txt b/p4_symbolic/ir/expected/conditional_sequence.txt index 32b5c9ab..4c033e97 100644 --- a/p4_symbolic/ir/expected/conditional_sequence.txt +++ b/p4_symbolic/ir/expected/conditional_sequence.txt @@ -399,6 +399,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_5" + } } } } @@ -501,6 +504,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_8" + } } } } @@ -603,6 +609,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_11" + } } } } @@ -705,6 +714,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_14" + } } } } @@ -807,6 +819,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_17" + } } } } @@ -909,6 +924,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_20" + } } } } @@ -1011,6 +1029,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_23" + } } } } @@ -1113,6 +1134,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t" + } } } } @@ -1215,6 +1239,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_5" + } } } } @@ -1317,6 +1344,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_8" + } } } } @@ -1419,6 +1449,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_11" + } } } } @@ -1521,6 +1554,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_14" + } } } } @@ -1623,6 +1659,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_17" + } } } } @@ -1725,6 +1764,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_20" + } } } } @@ -1827,6 +1869,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "node_23" + } } } } @@ -1929,6 +1974,9 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t" + } } } } @@ -2031,6 +2079,10 @@ tables { field_name: "fr" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } @@ -2058,6 +2110,10 @@ conditionals { } if_branch: "MyIngress.i4" else_branch: "MyIngress.e4" + optimized_symbolic_execution_info { + merge_point: "node_14" + continue_to_merge_point: true + } } } conditionals { @@ -2084,6 +2140,10 @@ conditionals { } if_branch: "MyIngress.i5" else_branch: "MyIngress.e5" + optimized_symbolic_execution_info { + merge_point: "node_17" + continue_to_merge_point: true + } } } conditionals { @@ -2110,6 +2170,10 @@ conditionals { } if_branch: "MyIngress.i6" else_branch: "MyIngress.e6" + optimized_symbolic_execution_info { + merge_point: "node_20" + continue_to_merge_point: true + } } } conditionals { @@ -2136,6 +2200,10 @@ conditionals { } if_branch: "MyIngress.i1" else_branch: "MyIngress.e1" + optimized_symbolic_execution_info { + merge_point: "node_5" + continue_to_merge_point: true + } } } conditionals { @@ -2162,6 +2230,10 @@ conditionals { } if_branch: "MyIngress.i7" else_branch: "MyIngress.e7" + optimized_symbolic_execution_info { + merge_point: "node_23" + continue_to_merge_point: true + } } } conditionals { @@ -2188,6 +2260,10 @@ conditionals { } if_branch: "MyIngress.i8" else_branch: "MyIngress.e8" + optimized_symbolic_execution_info { + merge_point: "MyIngress.t" + continue_to_merge_point: true + } } } conditionals { @@ -2214,6 +2290,10 @@ conditionals { } if_branch: "MyIngress.i2" else_branch: "MyIngress.e2" + optimized_symbolic_execution_info { + merge_point: "node_8" + continue_to_merge_point: true + } } } conditionals { @@ -2240,6 +2320,10 @@ conditionals { } if_branch: "MyIngress.i3" else_branch: "MyIngress.e3" + optimized_symbolic_execution_info { + merge_point: "node_11" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/hardcoded.txt b/p4_symbolic/ir/expected/hardcoded.txt index 929a608e..f0fc90fd 100644 --- a/p4_symbolic/ir/expected/hardcoded.txt +++ b/p4_symbolic/ir/expected/hardcoded.txt @@ -209,6 +209,9 @@ tables { key: "hardcoded55" value: "__END_OF_PIPELINE__" } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -226,6 +229,9 @@ tables { key: "hardcoded57" value: "__END_OF_PIPELINE__" } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -253,6 +259,10 @@ conditionals { } if_branch: "tbl_hardcoded55" else_branch: "tbl_hardcoded57" + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/reflector.txt b/p4_symbolic/ir/expected/reflector.txt index 0f443815..6c4289e8 100644 --- a/p4_symbolic/ir/expected/reflector.txt +++ b/p4_symbolic/ir/expected/reflector.txt @@ -177,6 +177,10 @@ tables { key: "reflector54" value: "__END_OF_PIPELINE__" } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } diff --git a/p4_symbolic/ir/expected/set_invalid.txt b/p4_symbolic/ir/expected/set_invalid.txt index 39ac613b..1090835e 100644 --- a/p4_symbolic/ir/expected/set_invalid.txt +++ b/p4_symbolic/ir/expected/set_invalid.txt @@ -255,6 +255,10 @@ tables { key: "set_invalid61" value: "node_3" } + optimized_symbolic_execution_info { + merge_point: "node_3" + continue_to_merge_point: true + } } } } @@ -272,6 +276,9 @@ tables { key: "set_invalid63" value: "__END_OF_PIPELINE__" } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -289,6 +296,9 @@ tables { key: "set_invalid65" value: "__END_OF_PIPELINE__" } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } @@ -316,6 +326,10 @@ conditionals { } if_branch: "tbl_set_invalid63" else_branch: "tbl_set_invalid65" + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } pipeline { diff --git a/p4_symbolic/ir/expected/table.txt b/p4_symbolic/ir/expected/table.txt index 053a91cb..70eccfa3 100644 --- a/p4_symbolic/ir/expected/table.txt +++ b/p4_symbolic/ir/expected/table.txt @@ -302,6 +302,10 @@ tables { field_name: "ingress_port" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } diff --git a/p4_symbolic/ir/expected/table_hit_1.txt b/p4_symbolic/ir/expected/table_hit_1.txt index 32b283d3..1b45a1f2 100644 --- a/p4_symbolic/ir/expected/table_hit_1.txt +++ b/p4_symbolic/ir/expected/table_hit_1.txt @@ -404,6 +404,10 @@ tables { field_name: "ether_type" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } @@ -525,6 +529,9 @@ tables { field_name: "src_addr" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + } } } } diff --git a/p4_symbolic/ir/expected/table_hit_2.txt b/p4_symbolic/ir/expected/table_hit_2.txt index 9cfb785b..2c26be5d 100644 --- a/p4_symbolic/ir/expected/table_hit_2.txt +++ b/p4_symbolic/ir/expected/table_hit_2.txt @@ -404,6 +404,10 @@ tables { field_name: "ether_type" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + continue_to_merge_point: true + } } } } @@ -525,6 +529,9 @@ tables { field_name: "ether_type" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + } } } } @@ -646,6 +653,9 @@ tables { field_name: "src_addr" } } + optimized_symbolic_execution_info { + merge_point: "MyIngress.t_3" + } } } } @@ -767,6 +777,10 @@ tables { field_name: "dst_addr" } } + optimized_symbolic_execution_info { + merge_point: "__END_OF_PIPELINE__" + continue_to_merge_point: true + } } } } diff --git a/p4_symbolic/ir/ir.cc b/p4_symbolic/ir/ir.cc index 61292f43..9e0f9f1d 100644 --- a/p4_symbolic/ir/ir.cc +++ b/p4_symbolic/ir/ir.cc @@ -14,16 +14,27 @@ #include "p4_symbolic/ir/ir.h" +#include +#include +#include #include #include #include #include +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/container/node_hash_map.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" #include "absl/strings/strip.h" -#include "google/protobuf/struct.pb.h" +#include "gutil/status.h" #include "p4/config/v1/p4info.pb.h" +#include "p4_symbolic/ir/cfg.h" +#include "p4_symbolic/ir/ir.pb.h" namespace p4_symbolic { namespace ir { @@ -452,10 +463,10 @@ absl::StatusOr ExtractRValue( // where an expression may have its value be a single other expression // which value may also be another single expression, etc, until // finally the actual value of the expression is reached. - // This is the bmv2 format analogous case to having an expression wrapped - // in many useless paranthesis. - // An example of this can be found at //p4-samples/ipv4-routing/basic.json - // after `make build` is run in that directory. + // This is the bmv2 format analogous case to having an expression + // wrapped in many useless paranthesis. An example of this can be found + // at //p4-samples/ipv4-routing/basic.json after `make build` is run in + // that directory. while (expression->fields().count("op") != 1) { if (expression->fields().count("type") != 1 || expression->fields().at("type").string_value() != "expression" || @@ -875,6 +886,22 @@ absl::StatusOr Bmv2AndP4infoToIr(const bmv2::P4Program &bmv2, } } + // Create the Control Flow Graph (CFG) of the program and perform analysis for + // optimized symbolic execution. + ASSIGN_OR_RETURN(std::unique_ptr cfg, + ControlFlowGraph::Create(output)); + // Set the optimized symbolic execution information in the IR program using + // the result of CFG analysis. + for (auto &[name, conditional] : *output.mutable_conditionals()) { + ASSIGN_OR_RETURN(*conditional.mutable_optimized_symbolic_execution_info(), + cfg->GetOptimizedSymbolicExecutionInfo(name)); + } + for (auto &[name, table] : *output.mutable_tables()) { + ASSIGN_OR_RETURN(*table.mutable_table_implementation() + ->mutable_optimized_symbolic_execution_info(), + cfg->GetOptimizedSymbolicExecutionInfo(name)); + } + return output; } diff --git a/p4_symbolic/ir/ir.h b/p4_symbolic/ir/ir.h index 5780c9e4..c02b55a5 100644 --- a/p4_symbolic/ir/ir.h +++ b/p4_symbolic/ir/ir.h @@ -19,11 +19,10 @@ #ifndef P4_SYMBOLIC_IR_IR_H_ #define P4_SYMBOLIC_IR_IR_H_ +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" -#include "gutil/status.h" #include "p4_symbolic/bmv2/bmv2.pb.h" #include "p4_symbolic/ir/ir.pb.h" -#include "p4_symbolic/ir/table_entries.h" namespace p4_symbolic { namespace ir { diff --git a/p4_symbolic/ir/ir.proto b/p4_symbolic/ir/ir.proto index 6f22bec7..9abc03fc 100644 --- a/p4_symbolic/ir/ir.proto +++ b/p4_symbolic/ir/ir.proto @@ -84,6 +84,19 @@ message ActionImplementation { repeated Statement action_body = 3; } +// Control flow information used during optimized symbolic execution +// (go/optimized-symbolic-execution) for each control point. +message OptimizedSymbolicExecutionInfo { + // The name of the first control point where all execution paths branched + // from the current control point will converge (refer to the respective field + // in `CfgNode` for precise definition). + string merge_point = 1; + // Whether symbolic execution must continue (to the merge point) after + // traversing the subgraph of the current control point (refer to the + // respective field in `CfgNode` for details). + bool continue_to_merge_point = 2; +} + // Overall table structure, combining definition with implementation. message Table { // This contains the name, id, action list, field matches, and max size. @@ -121,6 +134,9 @@ message TableImplementation { // Maps the name of a match (identical to the name used in p4 info), to // that match's target field. map match_name_to_field = 5; + + // Control flow information for optimized symbolic execution. + OptimizedSymbolicExecutionInfo optimized_symbolic_execution_info = 6; } // A conditional statement. @@ -139,6 +155,8 @@ message Conditional { // present). string if_branch = 3; string else_branch = 4; + // Control flow information for optimized symbolic execution. + OptimizedSymbolicExecutionInfo optimized_symbolic_execution_info = 5; } message Pipeline { diff --git a/p4_symbolic/symbolic/BUILD.bazel b/p4_symbolic/symbolic/BUILD.bazel index ad8b4908..084398c6 100644 --- a/p4_symbolic/symbolic/BUILD.bazel +++ b/p4_symbolic/symbolic/BUILD.bazel @@ -54,6 +54,7 @@ cc_library( "//p4_pdpi/utils:ir", "//p4_symbolic:z3_util", "//p4_symbolic/ir", + "//p4_symbolic/ir:cfg", "//p4_symbolic/ir:ir_cc_proto", "//p4_symbolic/ir:table_entries", "@com_github_google_glog//:glog", diff --git a/p4_symbolic/symbolic/conditional.cc b/p4_symbolic/symbolic/conditional.cc index aa2c8681..c9edc709 100644 --- a/p4_symbolic/symbolic/conditional.cc +++ b/p4_symbolic/symbolic/conditional.cc @@ -17,7 +17,11 @@ #include "p4_symbolic/symbolic/conditional.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" #include "gutil/status.h" +#include "p4_symbolic/ir/ir.h" #include "p4_symbolic/symbolic/action.h" #include "p4_symbolic/symbolic/operators.h" #include "p4_symbolic/symbolic/util.h" @@ -43,20 +47,61 @@ absl::StatusOr EvaluateConditional( ASSIGN_OR_RETURN(z3::expr else_guard, operators::And(guard, negated_condition)); + auto get_next_control_for_branch = [&](const std::string &branch) { + return branch == + conditional.optimized_symbolic_execution_info().merge_point() + ? ir::EndOfPipeline() // Do not jump to the merge point (yet). + : branch; + }; + // Evaluate both branches. - ASSIGN_OR_RETURN(SymbolicTableMatches if_matches, - control::EvaluateControl(data_plane, conditional.if_branch(), - state, translator, if_guard)); + ASSIGN_OR_RETURN( + SymbolicTableMatches if_matches, + control::EvaluateControl( + data_plane, get_next_control_for_branch(conditional.if_branch()), + state, translator, if_guard)); ASSIGN_OR_RETURN( SymbolicTableMatches else_matches, - control::EvaluateControl(data_plane, conditional.else_branch(), state, - translator, else_guard)); + control::EvaluateControl( + data_plane, get_next_control_for_branch(conditional.else_branch()), + state, translator, else_guard)); // Now we have two traces that need merging. // We should merge in a way such that the value of a field in the trace is // the one from the if branch if the condition is true, and the else branch // otherwise. - return util::MergeMatchesOnCondition(condition, if_matches, else_matches); + ASSIGN_OR_RETURN( + SymbolicTableMatches merged_matches, + util::MergeMatchesOnCondition(condition, if_matches, else_matches)); + + if (!conditional.optimized_symbolic_execution_info() + .continue_to_merge_point()) { + // The merge point is guaranteed to be evaluated through a different path + // (see go/optimized-symbolic-execution). + return merged_matches; + } else { + // Jump to the merge point and continue the execution from there. + ASSIGN_OR_RETURN( + SymbolicTableMatches result, + control::EvaluateControl( + data_plane, + conditional.optimized_symbolic_execution_info().merge_point(), + state, translator, guard)); + + // Merge the result of execution from the merge point with the result of + // merged if/else branches. + for (const auto &[table_name, match] : merged_matches) { + auto [_, inserted] = result.insert({table_name, std::move(match)}); + if (!inserted) { + return absl::InternalError( + absl::Substitute("Table '$0' is encountered in branches and after " + "the merge point of '$1'", + table_name, conditional.name())); + } + } + + return result; + } } } // namespace conditional diff --git a/p4_symbolic/symbolic/expected/conditional.smt2 b/p4_symbolic/symbolic/expected/conditional.smt2 index 563e1c38..b971879e 100644 --- a/p4_symbolic/symbolic/expected/conditional.smt2 +++ b/p4_symbolic/symbolic/expected/conditional.smt2 @@ -4,37 +4,31 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun ethernet.dst_addr () (_ BitVec 48)) (assert - (let (($x72 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x72)))) + (let (($x61 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x61)))) (assert (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) (let (($x34 (and true (not $x31)))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (or $x65 (or (or false (= ?x59 (_ bv0 9))) (= ?x59 (_ bv1 9))))))))))))))))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (or $x54 (or (or false (= ?x52 (_ bv0 9))) (= ?x52 (_ bv1 9)))))))))))))) (assert (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let (($x61 (ite $x31 $x33 false))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) + (let (($x39 (ite $x31 $x33 false))) (let (($x34 (and true (not $x31)))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (and (and (not $x65) $x61) (= (- 1) (- 1))))))))))))))))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (and (and (not $x54) $x39) (= (- 1) (- 1)))))))))))))) (check-sat) ; @@ -43,37 +37,31 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun ethernet.dst_addr () (_ BitVec 48)) (assert - (let (($x72 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x72)))) + (let (($x61 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x61)))) (assert (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) (let (($x34 (and true (not $x31)))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (or $x65 (or (or false (= ?x59 (_ bv0 9))) (= ?x59 (_ bv1 9))))))))))))))))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (or $x54 (or (or false (= ?x52 (_ bv0 9))) (= ?x52 (_ bv1 9)))))))))))))) (assert (let (($x34 (and true (not (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))))) (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) - (let (($x64 (ite $x31 false $x34))) - (let (($x33 (and true $x31))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (and (and (not $x65) $x64) (= (- 1) (- 1))))))))))))))))) + (let (($x40 (ite $x31 false $x34))) + (let ((?x38 (ite $x34 (_ bv511 9) (ite (and true $x31) (_ bv511 9) standard_metadata.egress_spec)))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) ?x38))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (and (and (not $x54) $x40) (= (- 1) (- 1)))))))))))))) (check-sat) ; @@ -82,38 +70,31 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun ethernet.dst_addr () (_ BitVec 48)) (assert - (let (($x72 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x72)))) + (let (($x61 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x61)))) (assert (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) (let (($x34 (and true (not $x31)))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (or $x65 (or (or false (= ?x59 (_ bv0 9))) (= ?x59 (_ bv1 9))))))))))))))))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (or $x54 (or (or false (= ?x52 (_ bv0 9))) (= ?x52 (_ bv1 9)))))))))))))) (assert - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x49 (ite $x44 0 (- 1)))) (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let (($x41 (and $x33 $x40))) - (let ((?x50 (ite $x41 (_ bv2 48) ethernet.dst_addr))) - (let (($x53 (and true (= ?x50 (_ bv1 48))))) (let (($x34 (and true (not $x31)))) - (let (($x54 (and $x34 $x53))) - (let ((?x63 (ite $x31 (ite $x41 0 (- 1)) (ite $x54 0 (- 1))))) - (let (($x62 (ite $x31 $x33 $x34))) - (let ((?x44 (ite (and $x33 (not $x40)) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite (and $x34 (not $x53)) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (and (and (not $x65) $x62) (= ?x63 (- 1)))))))))))))))))) + (let ((?x47 (ite (and true (not $x43)) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (and (and (not $x54) true) (= ?x49 (- 1)))))))))))))) (check-sat) ; @@ -122,38 +103,31 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun ethernet.dst_addr () (_ BitVec 48)) (assert - (let (($x72 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x72)))) + (let (($x61 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x61)))) (assert (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let ((?x44 (ite (and $x33 (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) - (let (($x41 (and $x33 $x40))) (let (($x34 (and true (not $x31)))) - (let (($x56 (and $x34 (not (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))))) - (let (($x53 (and true (= (ite $x41 (_ bv2 48) ethernet.dst_addr) (_ bv1 48))))) - (let (($x54 (and $x34 $x53))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite $x56 (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (or $x65 (or (or false (= ?x59 (_ bv0 9))) (= ?x59 (_ bv1 9))))))))))))))))) + (let ((?x47 (ite (and true (not (and true (= ethernet.dst_addr (_ bv1 48))))) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (or $x54 (or (or false (= ?x52 (_ bv0 9))) (= ?x52 (_ bv1 9)))))))))))))) (assert - (let (($x39 (= ethernet.dst_addr (_ bv1 48)))) - (let (($x40 (and true $x39))) + (let (($x42 (= ethernet.dst_addr (_ bv1 48)))) + (let (($x43 (and true $x42))) + (let (($x44 (and true $x43))) + (let ((?x49 (ite $x44 0 (- 1)))) (let (($x31 (= standard_metadata.ingress_port (concat (_ bv0 8) (_ bv0 1))))) (let (($x33 (and true $x31))) - (let (($x41 (and $x33 $x40))) - (let ((?x50 (ite $x41 (_ bv2 48) ethernet.dst_addr))) - (let (($x53 (and true (= ?x50 (_ bv1 48))))) (let (($x34 (and true (not $x31)))) - (let (($x54 (and $x34 $x53))) - (let ((?x63 (ite $x31 (ite $x41 0 (- 1)) (ite $x54 0 (- 1))))) - (let (($x62 (ite $x31 $x33 $x34))) - (let ((?x44 (ite (and $x33 (not $x40)) (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec)))) - (let ((?x59 (ite $x54 (_ bv1 9) (ite (and $x34 (not $x53)) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x41 (_ bv1 9) ?x44)))))) - (let (($x65 (= ?x59 (_ bv511 9)))) - (let (($x205 (and (not $x65) $x62))) - (and $x205 (= ?x63 0)))))))))))))))))) + (let ((?x47 (ite (and true (not $x43)) (_ bv511 9) (ite $x34 (_ bv511 9) (ite $x33 (_ bv511 9) standard_metadata.egress_spec))))) + (let ((?x52 (ite $x44 (_ bv1 9) ?x47))) + (let (($x54 (= ?x52 (_ bv511 9)))) + (let (($x159 (and (not $x54) true))) + (and $x159 (= ?x49 0)))))))))))))) (check-sat) diff --git a/p4_symbolic/symbolic/expected/conditional_sequence.smt2 b/p4_symbolic/symbolic/expected/conditional_sequence.smt2 index f845b91a..20d19229 100644 --- a/p4_symbolic/symbolic/expected/conditional_sequence.smt2 +++ b/p4_symbolic/symbolic/expected/conditional_sequence.smt2 @@ -4,20 +4,19 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert - (let (($x41 (and true (not (= h1.f1 (concat (_ bv0 7) (_ bv0 1))))))) (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) (let (($x38 (= h1.f1 ?x37))) - (let (($x3109 (ite $x38 false $x41))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3109) (= (- 1) (- 1)))))))))) + (let (($x44 (ite $x38 false (and true (not $x38))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x44) (= (- 1) (- 1))))))))) (check-sat) ; @@ -25,25 +24,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x3092 (ite $x38 (ite $x43 false (and (and true $x38) $x44)) (ite $x43 false $x1579)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3092) (= (- 1) (- 1))))))))))))) + (let (($x45 (= h1.f2 ?x37))) + (let (($x50 (ite $x45 false (and true (not $x45))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x50) (= (- 1) (- 1))))))))) (check-sat) ; @@ -51,34 +45,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x3076 (ite $x43 (ite $x47 false (and (and $x41 $x43) $x48)) (ite $x47 false $x2329)))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1562 (ite $x43 (ite $x47 false (and (and $x40 $x43) $x48)) (ite $x47 false $x815)))) - (let (($x3093 (ite $x38 $x1562 $x3076))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3093) (= (- 1) (- 1))))))))))))))))))))) + (let (($x51 (= h1.f3 ?x37))) + (let (($x56 (ite $x51 false (and true (not $x51))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x56) (= (- 1) (- 1))))))))) (check-sat) ; @@ -86,41 +66,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x3062 (ite $x47 (ite $x51 false (and (and $x1579 $x47) $x52)) (ite $x51 false $x2697)))) - (let (($x2314 (ite $x47 (ite $x51 false (and (and (and $x41 $x43) $x47) $x52)) (ite $x51 false (and (and (and $x41 $x43) $x48) $x52))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1548 (ite $x47 (ite $x51 false (and (and $x46 $x47) $x52)) (ite $x51 false $x1183)))) - (let (($x800 (ite $x47 (ite $x51 false (and (and (and $x40 $x43) $x47) $x52)) (ite $x51 false (and (and (and $x40 $x43) $x48) $x52))))) - (let (($x3094 (ite $x38 (ite $x43 $x800 $x1548) (ite $x43 $x2314 $x3062)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3094) (= (- 1) (- 1))))))))))))))))))))))))))) + (let (($x57 (= h1.f4 ?x37))) + (let (($x62 (ite $x57 false (and true (not $x57))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x62) (= (- 1) (- 1))))))))) (check-sat) ; @@ -128,50 +87,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x3050 (ite $x51 (ite $x55 false (and (and $x2329 $x51) $x56)) (ite $x55 false $x2875)))) - (let (($x2684 (ite $x51 (ite $x55 false (and (and (and $x1579 $x47) $x51) $x56)) (ite $x55 false (and (and (and $x1579 $x47) $x52) $x56))))) - (let (($x2302 (ite $x51 (ite $x55 false (and (and (and (and $x41 $x43) $x48) $x51) $x56)) (ite $x55 false (and (and (and (and $x41 $x43) $x48) $x52) $x56))))) - (let (($x1936 (ite $x51 (ite $x55 false (and (and (and (and $x41 $x43) $x47) $x51) $x56)) (ite $x55 false (and (and (and (and $x41 $x43) $x47) $x52) $x56))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1536 (ite $x51 (ite $x55 false (and (and $x815 $x51) $x56)) (ite $x55 false $x1361)))) - (let (($x1170 (ite $x51 (ite $x55 false (and (and (and $x46 $x47) $x51) $x56)) (ite $x55 false (and (and (and $x46 $x47) $x52) $x56))))) - (let (($x788 (ite $x51 (ite $x55 false (and (and (and (and $x40 $x43) $x48) $x51) $x56)) (ite $x55 false (and (and (and (and $x40 $x43) $x48) $x52) $x56))))) - (let (($x422 (ite $x51 (ite $x55 false (and (and (and (and $x40 $x43) $x47) $x51) $x56)) (ite $x55 false (and (and (and (and $x40 $x43) $x47) $x52) $x56))))) - (let (($x3095 (ite $x38 (ite $x43 (ite $x47 $x422 $x788) (ite $x47 $x1170 $x1536)) (ite $x43 (ite $x47 $x1936 $x2302) (ite $x47 $x2684 $x3050))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3095) (= (- 1) (- 1))))))))))))))))))))))))))))))))))) + (let (($x63 (= h1.f5 ?x37))) + (let (($x68 (ite $x63 false (and true (not $x63))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x68) (= (- 1) (- 1))))))))) (check-sat) ; @@ -179,75 +108,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x3040 (ite $x55 (ite $x59 false (and (and $x2697 $x55) $x60)) (ite $x59 false $x2959)))) - (let (($x2864 (ite $x55 (ite $x59 false (and (and (and $x2329 $x51) $x55) $x60)) (ite $x59 false (and (and (and $x2329 $x51) $x56) $x60))))) - (let (($x2674 (ite $x55 (ite $x59 false (and (and (and (and $x1579 $x47) $x52) $x55) $x60)) (ite $x59 false (and (and (and (and $x1579 $x47) $x52) $x56) $x60))))) - (let (($x2498 (ite $x55 (ite $x59 false (and (and (and (and $x1579 $x47) $x51) $x55) $x60)) (ite $x59 false (and (and (and (and $x1579 $x47) $x51) $x56) $x60))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2292 (ite $x55 (ite $x59 false (and (and $x1949 $x55) $x60)) (ite $x59 false $x2211)))) - (let (($x2116 (ite $x55 (ite $x59 false (and (and (and $x1581 $x51) $x55) $x60)) (ite $x59 false (and (and (and $x1581 $x51) $x56) $x60))))) - (let (($x1926 (ite $x55 (ite $x59 false (and (and (and (and $x1578 $x47) $x52) $x55) $x60)) (ite $x59 false (and (and (and (and $x1578 $x47) $x52) $x56) $x60))))) - (let (($x1750 (ite $x55 (ite $x59 false (and (and (and (and $x1578 $x47) $x51) $x55) $x60)) (ite $x59 false (and (and (and (and $x1578 $x47) $x51) $x56) $x60))))) - (let (($x3079 (ite $x43 (ite $x47 (ite $x51 $x1750 $x1926) (ite $x51 $x2116 $x2292)) (ite $x47 (ite $x51 $x2498 $x2674) (ite $x51 $x2864 $x3040))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1526 (ite $x55 (ite $x59 false (and (and $x1183 $x55) $x60)) (ite $x59 false $x1445)))) - (let (($x1350 (ite $x55 (ite $x59 false (and (and (and $x815 $x51) $x55) $x60)) (ite $x59 false (and (and (and $x815 $x51) $x56) $x60))))) - (let (($x1160 (ite $x55 (ite $x59 false (and (and (and (and $x46 $x47) $x52) $x55) $x60)) (ite $x59 false (and (and (and (and $x46 $x47) $x52) $x56) $x60))))) - (let (($x984 (ite $x55 (ite $x59 false (and (and (and (and $x46 $x47) $x51) $x55) $x60)) (ite $x59 false (and (and (and (and $x46 $x47) $x51) $x56) $x60))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x778 (ite $x55 (ite $x59 false (and (and $x435 $x55) $x60)) (ite $x59 false $x697)))) - (let (($x602 (ite $x55 (ite $x59 false (and (and (and $x50 $x51) $x55) $x60)) (ite $x59 false (and (and (and $x50 $x51) $x56) $x60))))) - (let (($x412 (ite $x55 (ite $x59 false (and (and (and (and $x45 $x47) $x52) $x55) $x60)) (ite $x59 false (and (and (and (and $x45 $x47) $x52) $x56) $x60))))) - (let (($x236 (ite $x55 (ite $x59 false (and (and (and (and $x45 $x47) $x51) $x55) $x60)) (ite $x59 false (and (and (and (and $x45 $x47) $x51) $x56) $x60))))) - (let (($x1565 (ite $x43 (ite $x47 (ite $x51 $x236 $x412) (ite $x51 $x602 $x778)) (ite $x47 (ite $x51 $x984 $x1160) (ite $x51 $x1350 $x1526))))) - (let (($x3096 (ite $x38 $x1565 $x3079))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3096) (= (- 1) (- 1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x69 (= h1.f6 ?x37))) + (let (($x74 (ite $x69 false (and true (not $x69))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x74) (= (- 1) (- 1))))))))) (check-sat) ; @@ -255,120 +129,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x64 (not $x63))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2997 (and $x2959 $x64))) - (let (($x3032 (ite $x59 (ite $x63 false (and (and $x2875 $x59) $x64)) (ite $x63 false $x2997)))) - (let (($x2950 (ite $x59 (ite $x63 false (and (and (and $x2697 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x2697 $x55) $x60) $x64))))) - (let (($x2856 (ite $x59 (ite $x63 false (and (and (and (and $x2329 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x2329 $x51) $x56) $x60) $x64))))) - (let (($x2774 (ite $x59 (ite $x63 false (and (and (and (and $x2329 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x2329 $x51) $x55) $x60) $x64))))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2631 (and $x2593 $x64))) - (let (($x2666 (ite $x59 (ite $x63 false (and (and $x2509 $x59) $x64)) (ite $x63 false $x2631)))) - (let (($x2584 (ite $x59 (ite $x63 false (and (and (and $x2331 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x2331 $x55) $x60) $x64))))) - (let (($x2490 (ite $x59 (ite $x63 false (and (and (and (and $x2328 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x2328 $x51) $x56) $x60) $x64))))) - (let (($x2408 (ite $x59 (ite $x63 false (and (and (and (and $x2328 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x2328 $x51) $x55) $x60) $x64))))) - (let (($x3065 (ite $x47 (ite $x51 (ite $x55 $x2408 $x2490) (ite $x55 $x2584 $x2666)) (ite $x51 (ite $x55 $x2774 $x2856) (ite $x55 $x2950 $x3032))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2249 (and $x2211 $x64))) - (let (($x2284 (ite $x59 (ite $x63 false (and (and $x2127 $x59) $x64)) (ite $x63 false $x2249)))) - (let (($x2202 (ite $x59 (ite $x63 false (and (and (and $x1949 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x1949 $x55) $x60) $x64))))) - (let (($x2108 (ite $x59 (ite $x63 false (and (and (and (and $x1581 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x1581 $x51) $x56) $x60) $x64))))) - (let (($x2026 (ite $x59 (ite $x63 false (and (and (and (and $x1581 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x1581 $x51) $x55) $x60) $x64))))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1883 (and $x1845 $x64))) - (let (($x1918 (ite $x59 (ite $x63 false (and (and $x1761 $x59) $x64)) (ite $x63 false $x1883)))) - (let (($x1836 (ite $x59 (ite $x63 false (and (and (and $x1583 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x1583 $x55) $x60) $x64))))) - (let (($x1742 (ite $x59 (ite $x63 false (and (and (and (and $x1580 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x1580 $x51) $x56) $x60) $x64))))) - (let (($x1660 (ite $x59 (ite $x63 false (and (and (and (and $x1580 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x1580 $x51) $x55) $x60) $x64))))) - (let (($x2317 (ite $x47 (ite $x51 (ite $x55 $x1660 $x1742) (ite $x55 $x1836 $x1918)) (ite $x51 (ite $x55 $x2026 $x2108) (ite $x55 $x2202 $x2284))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1483 (and $x1445 $x64))) - (let (($x1518 (ite $x59 (ite $x63 false (and (and $x1361 $x59) $x64)) (ite $x63 false $x1483)))) - (let (($x1436 (ite $x59 (ite $x63 false (and (and (and $x1183 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x1183 $x55) $x60) $x64))))) - (let (($x1342 (ite $x59 (ite $x63 false (and (and (and (and $x815 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x815 $x51) $x56) $x60) $x64))))) - (let (($x1260 (ite $x59 (ite $x63 false (and (and (and (and $x815 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x815 $x51) $x55) $x60) $x64))))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1117 (and $x1079 $x64))) - (let (($x1152 (ite $x59 (ite $x63 false (and (and $x995 $x59) $x64)) (ite $x63 false $x1117)))) - (let (($x1070 (ite $x59 (ite $x63 false (and (and (and $x817 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x817 $x55) $x60) $x64))))) - (let (($x976 (ite $x59 (ite $x63 false (and (and (and (and $x814 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x814 $x51) $x56) $x60) $x64))))) - (let (($x894 (ite $x59 (ite $x63 false (and (and (and (and $x814 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x814 $x51) $x55) $x60) $x64))))) - (let (($x1551 (ite $x47 (ite $x51 (ite $x55 $x894 $x976) (ite $x55 $x1070 $x1152)) (ite $x51 (ite $x55 $x1260 $x1342) (ite $x55 $x1436 $x1518))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x735 (and $x697 $x64))) - (let (($x770 (ite $x59 (ite $x63 false (and (and $x613 $x59) $x64)) (ite $x63 false $x735)))) - (let (($x688 (ite $x59 (ite $x63 false (and (and (and $x435 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x435 $x55) $x60) $x64))))) - (let (($x594 (ite $x59 (ite $x63 false (and (and (and (and $x50 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x50 $x51) $x56) $x60) $x64))))) - (let (($x512 (ite $x59 (ite $x63 false (and (and (and (and $x50 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x50 $x51) $x55) $x60) $x64))))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x369 (and $x331 $x64))) - (let (($x404 (ite $x59 (ite $x63 false (and (and $x247 $x59) $x64)) (ite $x63 false $x369)))) - (let (($x322 (ite $x59 (ite $x63 false (and (and (and $x54 $x55) $x59) $x64)) (ite $x63 false (and (and (and $x54 $x55) $x60) $x64))))) - (let (($x228 (ite $x59 (ite $x63 false (and (and (and (and $x49 $x51) $x56) $x59) $x64)) (ite $x63 false (and (and (and (and $x49 $x51) $x56) $x60) $x64))))) - (let (($x146 (ite $x59 (ite $x63 false (and (and (and (and $x49 $x51) $x55) $x59) $x64)) (ite $x63 false (and (and (and (and $x49 $x51) $x55) $x60) $x64))))) - (let (($x803 (ite $x47 (ite $x51 (ite $x55 $x146 $x228) (ite $x55 $x322 $x404)) (ite $x51 (ite $x55 $x512 $x594) (ite $x55 $x688 $x770))))) - (let (($x3097 (ite $x38 (ite $x43 $x803 $x1551) (ite $x43 $x2317 $x3065)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3097) (= (- 1) (- 1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x75 (= h1.f7 ?x37))) + (let (($x80 (ite $x75 false (and true (not $x75))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x80) (= (- 1) (- 1))))))))) (check-sat) ; @@ -376,207 +150,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f8 () (_ BitVec 8)) -(declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x67 (= h1.f8 ?x37))) - (let (($x68 (not $x67))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x64 (not $x63))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2997 (and $x2959 $x64))) - (let (($x3013 (and $x2997 $x68))) - (let (($x3026 (ite $x63 (ite $x67 false (and (and $x2959 $x63) $x68)) (ite $x67 false $x3013)))) - (let (($x2990 (ite $x63 (ite $x67 false (and (and (and $x2875 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x2875 $x59) $x64) $x68))))) - (let (($x2944 (ite $x63 (ite $x67 false (and (and (and (and $x2697 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x2697 $x55) $x60) $x64) $x68))))) - (let (($x2908 (ite $x63 (ite $x67 false (and (and (and (and $x2697 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x2697 $x55) $x59) $x64) $x68))))) - (let (($x2696 (and $x2329 $x51))) - (let (($x2699 (and $x2696 $x56))) - (let (($x2783 (and $x2699 $x60))) - (let (($x2821 (and $x2783 $x64))) - (let (($x2837 (and $x2821 $x68))) - (let (($x2850 (ite $x63 (ite $x67 false (and (and $x2783 $x63) $x68)) (ite $x67 false $x2837)))) - (let (($x2814 (ite $x63 (ite $x67 false (and (and (and $x2699 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x2699 $x59) $x64) $x68))))) - (let (($x2768 (ite $x63 (ite $x67 false (and (and (and (and $x2696 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x2696 $x55) $x60) $x64) $x68))))) - (let (($x2732 (ite $x63 (ite $x67 false (and (and (and (and $x2696 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x2696 $x55) $x59) $x64) $x68))))) - (let (($x3053 (ite $x51 (ite $x55 (ite $x59 $x2732 $x2768) (ite $x59 $x2814 $x2850)) (ite $x55 (ite $x59 $x2908 $x2944) (ite $x59 $x2990 $x3026))))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2631 (and $x2593 $x64))) - (let (($x2647 (and $x2631 $x68))) - (let (($x2660 (ite $x63 (ite $x67 false (and (and $x2593 $x63) $x68)) (ite $x67 false $x2647)))) - (let (($x2624 (ite $x63 (ite $x67 false (and (and (and $x2509 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x2509 $x59) $x64) $x68))))) - (let (($x2578 (ite $x63 (ite $x67 false (and (and (and (and $x2331 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x2331 $x55) $x60) $x64) $x68))))) - (let (($x2542 (ite $x63 (ite $x67 false (and (and (and (and $x2331 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x2331 $x55) $x59) $x64) $x68))))) - (let (($x2330 (and $x2328 $x51))) - (let (($x2333 (and $x2330 $x56))) - (let (($x2417 (and $x2333 $x60))) - (let (($x2455 (and $x2417 $x64))) - (let (($x2471 (and $x2455 $x68))) - (let (($x2484 (ite $x63 (ite $x67 false (and (and $x2417 $x63) $x68)) (ite $x67 false $x2471)))) - (let (($x2448 (ite $x63 (ite $x67 false (and (and (and $x2333 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x2333 $x59) $x64) $x68))))) - (let (($x2402 (ite $x63 (ite $x67 false (and (and (and (and $x2330 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x2330 $x55) $x60) $x64) $x68))))) - (let (($x2366 (ite $x63 (ite $x67 false (and (and (and (and $x2330 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x2330 $x55) $x59) $x64) $x68))))) - (let (($x2687 (ite $x51 (ite $x55 (ite $x59 $x2366 $x2402) (ite $x59 $x2448 $x2484)) (ite $x55 (ite $x59 $x2542 $x2578) (ite $x59 $x2624 $x2660))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2249 (and $x2211 $x64))) - (let (($x2265 (and $x2249 $x68))) - (let (($x2278 (ite $x63 (ite $x67 false (and (and $x2211 $x63) $x68)) (ite $x67 false $x2265)))) - (let (($x2242 (ite $x63 (ite $x67 false (and (and (and $x2127 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x2127 $x59) $x64) $x68))))) - (let (($x2196 (ite $x63 (ite $x67 false (and (and (and (and $x1949 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1949 $x55) $x60) $x64) $x68))))) - (let (($x2160 (ite $x63 (ite $x67 false (and (and (and (and $x1949 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1949 $x55) $x59) $x64) $x68))))) - (let (($x1948 (and $x1581 $x51))) - (let (($x1951 (and $x1948 $x56))) - (let (($x2035 (and $x1951 $x60))) - (let (($x2073 (and $x2035 $x64))) - (let (($x2089 (and $x2073 $x68))) - (let (($x2102 (ite $x63 (ite $x67 false (and (and $x2035 $x63) $x68)) (ite $x67 false $x2089)))) - (let (($x2066 (ite $x63 (ite $x67 false (and (and (and $x1951 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x1951 $x59) $x64) $x68))))) - (let (($x2020 (ite $x63 (ite $x67 false (and (and (and (and $x1948 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1948 $x55) $x60) $x64) $x68))))) - (let (($x1984 (ite $x63 (ite $x67 false (and (and (and (and $x1948 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1948 $x55) $x59) $x64) $x68))))) - (let (($x2305 (ite $x51 (ite $x55 (ite $x59 $x1984 $x2020) (ite $x59 $x2066 $x2102)) (ite $x55 (ite $x59 $x2160 $x2196) (ite $x59 $x2242 $x2278))))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1883 (and $x1845 $x64))) - (let (($x1899 (and $x1883 $x68))) - (let (($x1912 (ite $x63 (ite $x67 false (and (and $x1845 $x63) $x68)) (ite $x67 false $x1899)))) - (let (($x1876 (ite $x63 (ite $x67 false (and (and (and $x1761 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x1761 $x59) $x64) $x68))))) - (let (($x1830 (ite $x63 (ite $x67 false (and (and (and (and $x1583 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1583 $x55) $x60) $x64) $x68))))) - (let (($x1794 (ite $x63 (ite $x67 false (and (and (and (and $x1583 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1583 $x55) $x59) $x64) $x68))))) - (let (($x1582 (and $x1580 $x51))) - (let (($x1585 (and $x1582 $x56))) - (let (($x1669 (and $x1585 $x60))) - (let (($x1707 (and $x1669 $x64))) - (let (($x1723 (and $x1707 $x68))) - (let (($x1736 (ite $x63 (ite $x67 false (and (and $x1669 $x63) $x68)) (ite $x67 false $x1723)))) - (let (($x1700 (ite $x63 (ite $x67 false (and (and (and $x1585 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x1585 $x59) $x64) $x68))))) - (let (($x1654 (ite $x63 (ite $x67 false (and (and (and (and $x1582 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1582 $x55) $x60) $x64) $x68))))) - (let (($x1618 (ite $x63 (ite $x67 false (and (and (and (and $x1582 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1582 $x55) $x59) $x64) $x68))))) - (let (($x1939 (ite $x51 (ite $x55 (ite $x59 $x1618 $x1654) (ite $x59 $x1700 $x1736)) (ite $x55 (ite $x59 $x1794 $x1830) (ite $x59 $x1876 $x1912))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1483 (and $x1445 $x64))) - (let (($x1499 (and $x1483 $x68))) - (let (($x1512 (ite $x63 (ite $x67 false (and (and $x1445 $x63) $x68)) (ite $x67 false $x1499)))) - (let (($x1476 (ite $x63 (ite $x67 false (and (and (and $x1361 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x1361 $x59) $x64) $x68))))) - (let (($x1430 (ite $x63 (ite $x67 false (and (and (and (and $x1183 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1183 $x55) $x60) $x64) $x68))))) - (let (($x1394 (ite $x63 (ite $x67 false (and (and (and (and $x1183 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1183 $x55) $x59) $x64) $x68))))) - (let (($x1182 (and $x815 $x51))) - (let (($x1185 (and $x1182 $x56))) - (let (($x1269 (and $x1185 $x60))) - (let (($x1307 (and $x1269 $x64))) - (let (($x1323 (and $x1307 $x68))) - (let (($x1336 (ite $x63 (ite $x67 false (and (and $x1269 $x63) $x68)) (ite $x67 false $x1323)))) - (let (($x1300 (ite $x63 (ite $x67 false (and (and (and $x1185 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x1185 $x59) $x64) $x68))))) - (let (($x1254 (ite $x63 (ite $x67 false (and (and (and (and $x1182 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x1182 $x55) $x60) $x64) $x68))))) - (let (($x1218 (ite $x63 (ite $x67 false (and (and (and (and $x1182 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x1182 $x55) $x59) $x64) $x68))))) - (let (($x1539 (ite $x51 (ite $x55 (ite $x59 $x1218 $x1254) (ite $x59 $x1300 $x1336)) (ite $x55 (ite $x59 $x1394 $x1430) (ite $x59 $x1476 $x1512))))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1117 (and $x1079 $x64))) - (let (($x1133 (and $x1117 $x68))) - (let (($x1146 (ite $x63 (ite $x67 false (and (and $x1079 $x63) $x68)) (ite $x67 false $x1133)))) - (let (($x1110 (ite $x63 (ite $x67 false (and (and (and $x995 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x995 $x59) $x64) $x68))))) - (let (($x1064 (ite $x63 (ite $x67 false (and (and (and (and $x817 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x817 $x55) $x60) $x64) $x68))))) - (let (($x1028 (ite $x63 (ite $x67 false (and (and (and (and $x817 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x817 $x55) $x59) $x64) $x68))))) - (let (($x816 (and $x814 $x51))) - (let (($x819 (and $x816 $x56))) - (let (($x903 (and $x819 $x60))) - (let (($x941 (and $x903 $x64))) - (let (($x957 (and $x941 $x68))) - (let (($x970 (ite $x63 (ite $x67 false (and (and $x903 $x63) $x68)) (ite $x67 false $x957)))) - (let (($x934 (ite $x63 (ite $x67 false (and (and (and $x819 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x819 $x59) $x64) $x68))))) - (let (($x888 (ite $x63 (ite $x67 false (and (and (and (and $x816 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x816 $x55) $x60) $x64) $x68))))) - (let (($x852 (ite $x63 (ite $x67 false (and (and (and (and $x816 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x816 $x55) $x59) $x64) $x68))))) - (let (($x1173 (ite $x51 (ite $x55 (ite $x59 $x852 $x888) (ite $x59 $x934 $x970)) (ite $x55 (ite $x59 $x1028 $x1064) (ite $x59 $x1110 $x1146))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x735 (and $x697 $x64))) - (let (($x751 (and $x735 $x68))) - (let (($x764 (ite $x63 (ite $x67 false (and (and $x697 $x63) $x68)) (ite $x67 false $x751)))) - (let (($x728 (ite $x63 (ite $x67 false (and (and (and $x613 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x613 $x59) $x64) $x68))))) - (let (($x682 (ite $x63 (ite $x67 false (and (and (and (and $x435 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x435 $x55) $x60) $x64) $x68))))) - (let (($x646 (ite $x63 (ite $x67 false (and (and (and (and $x435 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x435 $x55) $x59) $x64) $x68))))) - (let (($x434 (and $x50 $x51))) - (let (($x437 (and $x434 $x56))) - (let (($x521 (and $x437 $x60))) - (let (($x559 (and $x521 $x64))) - (let (($x575 (and $x559 $x68))) - (let (($x588 (ite $x63 (ite $x67 false (and (and $x521 $x63) $x68)) (ite $x67 false $x575)))) - (let (($x552 (ite $x63 (ite $x67 false (and (and (and $x437 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x437 $x59) $x64) $x68))))) - (let (($x506 (ite $x63 (ite $x67 false (and (and (and (and $x434 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x434 $x55) $x60) $x64) $x68))))) - (let (($x470 (ite $x63 (ite $x67 false (and (and (and (and $x434 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x434 $x55) $x59) $x64) $x68))))) - (let (($x791 (ite $x51 (ite $x55 (ite $x59 $x470 $x506) (ite $x59 $x552 $x588)) (ite $x55 (ite $x59 $x646 $x682) (ite $x59 $x728 $x764))))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x369 (and $x331 $x64))) - (let (($x385 (and $x369 $x68))) - (let (($x398 (ite $x63 (ite $x67 false (and (and $x331 $x63) $x68)) (ite $x67 false $x385)))) - (let (($x362 (ite $x63 (ite $x67 false (and (and (and $x247 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x247 $x59) $x64) $x68))))) - (let (($x316 (ite $x63 (ite $x67 false (and (and (and (and $x54 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x54 $x55) $x60) $x64) $x68))))) - (let (($x280 (ite $x63 (ite $x67 false (and (and (and (and $x54 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x54 $x55) $x59) $x64) $x68))))) - (let (($x53 (and $x49 $x51))) - (let (($x58 (and $x53 $x56))) - (let (($x155 (and $x58 $x60))) - (let (($x193 (and $x155 $x64))) - (let (($x209 (and $x193 $x68))) - (let (($x222 (ite $x63 (ite $x67 false (and (and $x155 $x63) $x68)) (ite $x67 false $x209)))) - (let (($x186 (ite $x63 (ite $x67 false (and (and (and $x58 $x59) $x63) $x68)) (ite $x67 false (and (and (and $x58 $x59) $x64) $x68))))) - (let (($x140 (ite $x63 (ite $x67 false (and (and (and (and $x53 $x55) $x60) $x63) $x68)) (ite $x67 false (and (and (and (and $x53 $x55) $x60) $x64) $x68))))) - (let (($x104 (ite $x63 (ite $x67 false (and (and (and (and $x53 $x55) $x59) $x63) $x68)) (ite $x67 false (and (and (and (and $x53 $x55) $x59) $x64) $x68))))) - (let (($x425 (ite $x51 (ite $x55 (ite $x59 $x104 $x140) (ite $x59 $x186 $x222)) (ite $x55 (ite $x59 $x280 $x316) (ite $x59 $x362 $x398))))) - (let (($x3098 (ite $x38 (ite $x43 (ite $x47 $x425 $x791) (ite $x47 $x1173 $x1539)) (ite $x43 (ite $x47 $x1939 $x2305) (ite $x47 $x2687 $x3053))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3098) (= (- 1) (- 1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x81 (= h1.f8 ?x37))) + (let (($x86 (ite $x81 false (and true (not $x81))))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x86) (= (- 1) (- 1))))))))) (check-sat) ; @@ -585,20 +172,19 @@ (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x3099 (ite $x38 $x40 false))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3099) (= (- 1) (- 1)))))))))) + (let (($x43 (ite $x38 (and true $x38) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x43) (= (- 1) (- 1))))))))) (check-sat) ; @@ -606,24 +192,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1578 (and $x41 $x43))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x3100 (ite $x38 (ite $x43 (and (and true $x38) $x43) false) (ite $x43 $x1578 false)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3100) (= (- 1) (- 1)))))))))))) + (let (($x45 (= h1.f2 ?x37))) + (let (($x49 (ite $x45 (and true $x45) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x49) (= (- 1) (- 1))))))))) (check-sat) ; @@ -631,33 +213,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2328 (and $x1579 $x47))) - (let (($x3083 (ite $x43 (ite $x47 (and (and $x41 $x43) $x47) false) (ite $x47 $x2328 false)))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x814 (and $x46 $x47))) - (let (($x1569 (ite $x43 (ite $x47 (and (and $x40 $x43) $x47) false) (ite $x47 $x814 false)))) - (let (($x3101 (ite $x38 $x1569 $x3083))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3101) (= (- 1) (- 1)))))))))))))))))))) + (let (($x51 (= h1.f3 ?x37))) + (let (($x55 (ite $x51 (and true $x51) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x55) (= (- 1) (- 1))))))))) (check-sat) ; @@ -665,40 +234,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2696 (and $x2329 $x51))) - (let (($x3068 (ite $x47 (ite $x51 (and (and $x1579 $x47) $x51) false) (ite $x51 $x2696 false)))) - (let (($x2320 (ite $x47 (ite $x51 (and (and (and $x41 $x43) $x47) $x51) false) (ite $x51 (and (and (and $x41 $x43) $x48) $x51) false)))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1182 (and $x815 $x51))) - (let (($x1554 (ite $x47 (ite $x51 (and (and $x46 $x47) $x51) false) (ite $x51 $x1182 false)))) - (let (($x806 (ite $x47 (ite $x51 (and (and (and $x40 $x43) $x47) $x51) false) (ite $x51 (and (and (and $x40 $x43) $x48) $x51) false)))) - (let (($x3102 (ite $x38 (ite $x43 $x806 $x1554) (ite $x43 $x2320 $x3068)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3102) (= (- 1) (- 1)))))))))))))))))))))))))) + (let (($x57 (= h1.f4 ?x37))) + (let (($x61 (ite $x57 (and true $x57) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x61) (= (- 1) (- 1))))))))) (check-sat) ; @@ -706,49 +255,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2874 (and $x2697 $x55))) - (let (($x3055 (ite $x51 (ite $x55 (and (and $x2329 $x51) $x55) false) (ite $x55 $x2874 false)))) - (let (($x2689 (ite $x51 (ite $x55 (and (and (and $x1579 $x47) $x51) $x55) false) (ite $x55 (and (and (and $x1579 $x47) $x52) $x55) false)))) - (let (($x2307 (ite $x51 (ite $x55 (and (and (and (and $x41 $x43) $x48) $x51) $x55) false) (ite $x55 (and (and (and (and $x41 $x43) $x48) $x52) $x55) false)))) - (let (($x1941 (ite $x51 (ite $x55 (and (and (and (and $x41 $x43) $x47) $x51) $x55) false) (ite $x55 (and (and (and (and $x41 $x43) $x47) $x52) $x55) false)))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1360 (and $x1183 $x55))) - (let (($x1541 (ite $x51 (ite $x55 (and (and $x815 $x51) $x55) false) (ite $x55 $x1360 false)))) - (let (($x1175 (ite $x51 (ite $x55 (and (and (and $x46 $x47) $x51) $x55) false) (ite $x55 (and (and (and $x46 $x47) $x52) $x55) false)))) - (let (($x793 (ite $x51 (ite $x55 (and (and (and (and $x40 $x43) $x48) $x51) $x55) false) (ite $x55 (and (and (and (and $x40 $x43) $x48) $x52) $x55) false)))) - (let (($x427 (ite $x51 (ite $x55 (and (and (and (and $x40 $x43) $x47) $x51) $x55) false) (ite $x55 (and (and (and (and $x40 $x43) $x47) $x52) $x55) false)))) - (let (($x3103 (ite $x38 (ite $x43 (ite $x47 $x427 $x793) (ite $x47 $x1175 $x1541)) (ite $x43 (ite $x47 $x1941 $x2307) (ite $x47 $x2689 $x3055))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3103) (= (- 1) (- 1)))))))))))))))))))))))))))))))))) + (let (($x63 (= h1.f5 ?x37))) + (let (($x67 (ite $x63 (and true $x63) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x67) (= (- 1) (- 1))))))))) (check-sat) ; @@ -756,74 +276,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2958 (and $x2875 $x59))) - (let (($x3044 (ite $x55 (ite $x59 (and (and $x2697 $x55) $x59) false) (ite $x59 $x2958 false)))) - (let (($x2868 (ite $x55 (ite $x59 (and (and (and $x2329 $x51) $x55) $x59) false) (ite $x59 (and (and (and $x2329 $x51) $x56) $x59) false)))) - (let (($x2678 (ite $x55 (ite $x59 (and (and (and (and $x1579 $x47) $x52) $x55) $x59) false) (ite $x59 (and (and (and (and $x1579 $x47) $x52) $x56) $x59) false)))) - (let (($x2502 (ite $x55 (ite $x59 (and (and (and (and $x1579 $x47) $x51) $x55) $x59) false) (ite $x59 (and (and (and (and $x1579 $x47) $x51) $x56) $x59) false)))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2210 (and $x2127 $x59))) - (let (($x2296 (ite $x55 (ite $x59 (and (and $x1949 $x55) $x59) false) (ite $x59 $x2210 false)))) - (let (($x2120 (ite $x55 (ite $x59 (and (and (and $x1581 $x51) $x55) $x59) false) (ite $x59 (and (and (and $x1581 $x51) $x56) $x59) false)))) - (let (($x1930 (ite $x55 (ite $x59 (and (and (and (and $x1578 $x47) $x52) $x55) $x59) false) (ite $x59 (and (and (and (and $x1578 $x47) $x52) $x56) $x59) false)))) - (let (($x1754 (ite $x55 (ite $x59 (and (and (and (and $x1578 $x47) $x51) $x55) $x59) false) (ite $x59 (and (and (and (and $x1578 $x47) $x51) $x56) $x59) false)))) - (let (($x3086 (ite $x43 (ite $x47 (ite $x51 $x1754 $x1930) (ite $x51 $x2120 $x2296)) (ite $x47 (ite $x51 $x2502 $x2678) (ite $x51 $x2868 $x3044))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1444 (and $x1361 $x59))) - (let (($x1530 (ite $x55 (ite $x59 (and (and $x1183 $x55) $x59) false) (ite $x59 $x1444 false)))) - (let (($x1354 (ite $x55 (ite $x59 (and (and (and $x815 $x51) $x55) $x59) false) (ite $x59 (and (and (and $x815 $x51) $x56) $x59) false)))) - (let (($x1164 (ite $x55 (ite $x59 (and (and (and (and $x46 $x47) $x52) $x55) $x59) false) (ite $x59 (and (and (and (and $x46 $x47) $x52) $x56) $x59) false)))) - (let (($x988 (ite $x55 (ite $x59 (and (and (and (and $x46 $x47) $x51) $x55) $x59) false) (ite $x59 (and (and (and (and $x46 $x47) $x51) $x56) $x59) false)))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x696 (and $x613 $x59))) - (let (($x782 (ite $x55 (ite $x59 (and (and $x435 $x55) $x59) false) (ite $x59 $x696 false)))) - (let (($x606 (ite $x55 (ite $x59 (and (and (and $x50 $x51) $x55) $x59) false) (ite $x59 (and (and (and $x50 $x51) $x56) $x59) false)))) - (let (($x416 (ite $x55 (ite $x59 (and (and (and (and $x45 $x47) $x52) $x55) $x59) false) (ite $x59 (and (and (and (and $x45 $x47) $x52) $x56) $x59) false)))) - (let (($x240 (ite $x55 (ite $x59 (and (and (and (and $x45 $x47) $x51) $x55) $x59) false) (ite $x59 (and (and (and (and $x45 $x47) $x51) $x56) $x59) false)))) - (let (($x1572 (ite $x43 (ite $x47 (ite $x51 $x240 $x416) (ite $x51 $x606 $x782)) (ite $x47 (ite $x51 $x988 $x1164) (ite $x51 $x1354 $x1530))))) - (let (($x3104 (ite $x38 $x1572 $x3086))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3104) (= (- 1) (- 1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x69 (= h1.f6 ?x37))) + (let (($x73 (ite $x69 (and true $x69) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x73) (= (- 1) (- 1))))))))) (check-sat) ; @@ -831,119 +297,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2996 (and $x2959 $x63))) - (let (($x3035 (ite $x59 (ite $x63 (and (and $x2875 $x59) $x63) false) (ite $x63 $x2996 false)))) - (let (($x2953 (ite $x59 (ite $x63 (and (and (and $x2697 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x2697 $x55) $x60) $x63) false)))) - (let (($x2859 (ite $x59 (ite $x63 (and (and (and (and $x2329 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x2329 $x51) $x56) $x60) $x63) false)))) - (let (($x2777 (ite $x59 (ite $x63 (and (and (and (and $x2329 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x2329 $x51) $x55) $x60) $x63) false)))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2630 (and $x2593 $x63))) - (let (($x2669 (ite $x59 (ite $x63 (and (and $x2509 $x59) $x63) false) (ite $x63 $x2630 false)))) - (let (($x2587 (ite $x59 (ite $x63 (and (and (and $x2331 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x2331 $x55) $x60) $x63) false)))) - (let (($x2493 (ite $x59 (ite $x63 (and (and (and (and $x2328 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x2328 $x51) $x56) $x60) $x63) false)))) - (let (($x2411 (ite $x59 (ite $x63 (and (and (and (and $x2328 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x2328 $x51) $x55) $x60) $x63) false)))) - (let (($x3071 (ite $x47 (ite $x51 (ite $x55 $x2411 $x2493) (ite $x55 $x2587 $x2669)) (ite $x51 (ite $x55 $x2777 $x2859) (ite $x55 $x2953 $x3035))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2248 (and $x2211 $x63))) - (let (($x2287 (ite $x59 (ite $x63 (and (and $x2127 $x59) $x63) false) (ite $x63 $x2248 false)))) - (let (($x2205 (ite $x59 (ite $x63 (and (and (and $x1949 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x1949 $x55) $x60) $x63) false)))) - (let (($x2111 (ite $x59 (ite $x63 (and (and (and (and $x1581 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x1581 $x51) $x56) $x60) $x63) false)))) - (let (($x2029 (ite $x59 (ite $x63 (and (and (and (and $x1581 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x1581 $x51) $x55) $x60) $x63) false)))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1882 (and $x1845 $x63))) - (let (($x1921 (ite $x59 (ite $x63 (and (and $x1761 $x59) $x63) false) (ite $x63 $x1882 false)))) - (let (($x1839 (ite $x59 (ite $x63 (and (and (and $x1583 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x1583 $x55) $x60) $x63) false)))) - (let (($x1745 (ite $x59 (ite $x63 (and (and (and (and $x1580 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x1580 $x51) $x56) $x60) $x63) false)))) - (let (($x1663 (ite $x59 (ite $x63 (and (and (and (and $x1580 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x1580 $x51) $x55) $x60) $x63) false)))) - (let (($x2323 (ite $x47 (ite $x51 (ite $x55 $x1663 $x1745) (ite $x55 $x1839 $x1921)) (ite $x51 (ite $x55 $x2029 $x2111) (ite $x55 $x2205 $x2287))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1482 (and $x1445 $x63))) - (let (($x1521 (ite $x59 (ite $x63 (and (and $x1361 $x59) $x63) false) (ite $x63 $x1482 false)))) - (let (($x1439 (ite $x59 (ite $x63 (and (and (and $x1183 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x1183 $x55) $x60) $x63) false)))) - (let (($x1345 (ite $x59 (ite $x63 (and (and (and (and $x815 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x815 $x51) $x56) $x60) $x63) false)))) - (let (($x1263 (ite $x59 (ite $x63 (and (and (and (and $x815 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x815 $x51) $x55) $x60) $x63) false)))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1116 (and $x1079 $x63))) - (let (($x1155 (ite $x59 (ite $x63 (and (and $x995 $x59) $x63) false) (ite $x63 $x1116 false)))) - (let (($x1073 (ite $x59 (ite $x63 (and (and (and $x817 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x817 $x55) $x60) $x63) false)))) - (let (($x979 (ite $x59 (ite $x63 (and (and (and (and $x814 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x814 $x51) $x56) $x60) $x63) false)))) - (let (($x897 (ite $x59 (ite $x63 (and (and (and (and $x814 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x814 $x51) $x55) $x60) $x63) false)))) - (let (($x1557 (ite $x47 (ite $x51 (ite $x55 $x897 $x979) (ite $x55 $x1073 $x1155)) (ite $x51 (ite $x55 $x1263 $x1345) (ite $x55 $x1439 $x1521))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x734 (and $x697 $x63))) - (let (($x773 (ite $x59 (ite $x63 (and (and $x613 $x59) $x63) false) (ite $x63 $x734 false)))) - (let (($x691 (ite $x59 (ite $x63 (and (and (and $x435 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x435 $x55) $x60) $x63) false)))) - (let (($x597 (ite $x59 (ite $x63 (and (and (and (and $x50 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x50 $x51) $x56) $x60) $x63) false)))) - (let (($x515 (ite $x59 (ite $x63 (and (and (and (and $x50 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x50 $x51) $x55) $x60) $x63) false)))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x368 (and $x331 $x63))) - (let (($x407 (ite $x59 (ite $x63 (and (and $x247 $x59) $x63) false) (ite $x63 $x368 false)))) - (let (($x325 (ite $x59 (ite $x63 (and (and (and $x54 $x55) $x59) $x63) false) (ite $x63 (and (and (and $x54 $x55) $x60) $x63) false)))) - (let (($x231 (ite $x59 (ite $x63 (and (and (and (and $x49 $x51) $x56) $x59) $x63) false) (ite $x63 (and (and (and (and $x49 $x51) $x56) $x60) $x63) false)))) - (let (($x149 (ite $x59 (ite $x63 (and (and (and (and $x49 $x51) $x55) $x59) $x63) false) (ite $x63 (and (and (and (and $x49 $x51) $x55) $x60) $x63) false)))) - (let (($x809 (ite $x47 (ite $x51 (ite $x55 $x149 $x231) (ite $x55 $x325 $x407)) (ite $x51 (ite $x55 $x515 $x597) (ite $x55 $x691 $x773))))) - (let (($x3105 (ite $x38 (ite $x43 $x809 $x1557) (ite $x43 $x2323 $x3071)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3105) (= (- 1) (- 1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x75 (= h1.f7 ?x37))) + (let (($x79 (ite $x75 (and true $x75) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x79) (= (- 1) (- 1))))))))) (check-sat) ; @@ -951,206 +318,20 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.f8 () (_ BitVec 8)) -(declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x67 (= h1.f8 ?x37))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x64 (not $x63))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2997 (and $x2959 $x64))) - (let (($x3012 (and $x2997 $x67))) - (let (($x3028 (ite $x63 (ite $x67 (and (and $x2959 $x63) $x67) false) (ite $x67 $x3012 false)))) - (let (($x2992 (ite $x63 (ite $x67 (and (and (and $x2875 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x2875 $x59) $x64) $x67) false)))) - (let (($x2946 (ite $x63 (ite $x67 (and (and (and (and $x2697 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x2697 $x55) $x60) $x64) $x67) false)))) - (let (($x2910 (ite $x63 (ite $x67 (and (and (and (and $x2697 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x2697 $x55) $x59) $x64) $x67) false)))) - (let (($x2696 (and $x2329 $x51))) - (let (($x2699 (and $x2696 $x56))) - (let (($x2783 (and $x2699 $x60))) - (let (($x2821 (and $x2783 $x64))) - (let (($x2836 (and $x2821 $x67))) - (let (($x2852 (ite $x63 (ite $x67 (and (and $x2783 $x63) $x67) false) (ite $x67 $x2836 false)))) - (let (($x2816 (ite $x63 (ite $x67 (and (and (and $x2699 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x2699 $x59) $x64) $x67) false)))) - (let (($x2770 (ite $x63 (ite $x67 (and (and (and (and $x2696 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x2696 $x55) $x60) $x64) $x67) false)))) - (let (($x2734 (ite $x63 (ite $x67 (and (and (and (and $x2696 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x2696 $x55) $x59) $x64) $x67) false)))) - (let (($x3058 (ite $x51 (ite $x55 (ite $x59 $x2734 $x2770) (ite $x59 $x2816 $x2852)) (ite $x55 (ite $x59 $x2910 $x2946) (ite $x59 $x2992 $x3028))))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2631 (and $x2593 $x64))) - (let (($x2646 (and $x2631 $x67))) - (let (($x2662 (ite $x63 (ite $x67 (and (and $x2593 $x63) $x67) false) (ite $x67 $x2646 false)))) - (let (($x2626 (ite $x63 (ite $x67 (and (and (and $x2509 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x2509 $x59) $x64) $x67) false)))) - (let (($x2580 (ite $x63 (ite $x67 (and (and (and (and $x2331 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x2331 $x55) $x60) $x64) $x67) false)))) - (let (($x2544 (ite $x63 (ite $x67 (and (and (and (and $x2331 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x2331 $x55) $x59) $x64) $x67) false)))) - (let (($x2330 (and $x2328 $x51))) - (let (($x2333 (and $x2330 $x56))) - (let (($x2417 (and $x2333 $x60))) - (let (($x2455 (and $x2417 $x64))) - (let (($x2470 (and $x2455 $x67))) - (let (($x2486 (ite $x63 (ite $x67 (and (and $x2417 $x63) $x67) false) (ite $x67 $x2470 false)))) - (let (($x2450 (ite $x63 (ite $x67 (and (and (and $x2333 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x2333 $x59) $x64) $x67) false)))) - (let (($x2404 (ite $x63 (ite $x67 (and (and (and (and $x2330 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x2330 $x55) $x60) $x64) $x67) false)))) - (let (($x2368 (ite $x63 (ite $x67 (and (and (and (and $x2330 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x2330 $x55) $x59) $x64) $x67) false)))) - (let (($x2692 (ite $x51 (ite $x55 (ite $x59 $x2368 $x2404) (ite $x59 $x2450 $x2486)) (ite $x55 (ite $x59 $x2544 $x2580) (ite $x59 $x2626 $x2662))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2249 (and $x2211 $x64))) - (let (($x2264 (and $x2249 $x67))) - (let (($x2280 (ite $x63 (ite $x67 (and (and $x2211 $x63) $x67) false) (ite $x67 $x2264 false)))) - (let (($x2244 (ite $x63 (ite $x67 (and (and (and $x2127 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x2127 $x59) $x64) $x67) false)))) - (let (($x2198 (ite $x63 (ite $x67 (and (and (and (and $x1949 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1949 $x55) $x60) $x64) $x67) false)))) - (let (($x2162 (ite $x63 (ite $x67 (and (and (and (and $x1949 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1949 $x55) $x59) $x64) $x67) false)))) - (let (($x1948 (and $x1581 $x51))) - (let (($x1951 (and $x1948 $x56))) - (let (($x2035 (and $x1951 $x60))) - (let (($x2073 (and $x2035 $x64))) - (let (($x2088 (and $x2073 $x67))) - (let (($x2104 (ite $x63 (ite $x67 (and (and $x2035 $x63) $x67) false) (ite $x67 $x2088 false)))) - (let (($x2068 (ite $x63 (ite $x67 (and (and (and $x1951 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x1951 $x59) $x64) $x67) false)))) - (let (($x2022 (ite $x63 (ite $x67 (and (and (and (and $x1948 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1948 $x55) $x60) $x64) $x67) false)))) - (let (($x1986 (ite $x63 (ite $x67 (and (and (and (and $x1948 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1948 $x55) $x59) $x64) $x67) false)))) - (let (($x2310 (ite $x51 (ite $x55 (ite $x59 $x1986 $x2022) (ite $x59 $x2068 $x2104)) (ite $x55 (ite $x59 $x2162 $x2198) (ite $x59 $x2244 $x2280))))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1883 (and $x1845 $x64))) - (let (($x1898 (and $x1883 $x67))) - (let (($x1914 (ite $x63 (ite $x67 (and (and $x1845 $x63) $x67) false) (ite $x67 $x1898 false)))) - (let (($x1878 (ite $x63 (ite $x67 (and (and (and $x1761 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x1761 $x59) $x64) $x67) false)))) - (let (($x1832 (ite $x63 (ite $x67 (and (and (and (and $x1583 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1583 $x55) $x60) $x64) $x67) false)))) - (let (($x1796 (ite $x63 (ite $x67 (and (and (and (and $x1583 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1583 $x55) $x59) $x64) $x67) false)))) - (let (($x1582 (and $x1580 $x51))) - (let (($x1585 (and $x1582 $x56))) - (let (($x1669 (and $x1585 $x60))) - (let (($x1707 (and $x1669 $x64))) - (let (($x1722 (and $x1707 $x67))) - (let (($x1738 (ite $x63 (ite $x67 (and (and $x1669 $x63) $x67) false) (ite $x67 $x1722 false)))) - (let (($x1702 (ite $x63 (ite $x67 (and (and (and $x1585 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x1585 $x59) $x64) $x67) false)))) - (let (($x1656 (ite $x63 (ite $x67 (and (and (and (and $x1582 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1582 $x55) $x60) $x64) $x67) false)))) - (let (($x1620 (ite $x63 (ite $x67 (and (and (and (and $x1582 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1582 $x55) $x59) $x64) $x67) false)))) - (let (($x1944 (ite $x51 (ite $x55 (ite $x59 $x1620 $x1656) (ite $x59 $x1702 $x1738)) (ite $x55 (ite $x59 $x1796 $x1832) (ite $x59 $x1878 $x1914))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1483 (and $x1445 $x64))) - (let (($x1498 (and $x1483 $x67))) - (let (($x1514 (ite $x63 (ite $x67 (and (and $x1445 $x63) $x67) false) (ite $x67 $x1498 false)))) - (let (($x1478 (ite $x63 (ite $x67 (and (and (and $x1361 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x1361 $x59) $x64) $x67) false)))) - (let (($x1432 (ite $x63 (ite $x67 (and (and (and (and $x1183 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1183 $x55) $x60) $x64) $x67) false)))) - (let (($x1396 (ite $x63 (ite $x67 (and (and (and (and $x1183 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1183 $x55) $x59) $x64) $x67) false)))) - (let (($x1182 (and $x815 $x51))) - (let (($x1185 (and $x1182 $x56))) - (let (($x1269 (and $x1185 $x60))) - (let (($x1307 (and $x1269 $x64))) - (let (($x1322 (and $x1307 $x67))) - (let (($x1338 (ite $x63 (ite $x67 (and (and $x1269 $x63) $x67) false) (ite $x67 $x1322 false)))) - (let (($x1302 (ite $x63 (ite $x67 (and (and (and $x1185 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x1185 $x59) $x64) $x67) false)))) - (let (($x1256 (ite $x63 (ite $x67 (and (and (and (and $x1182 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x1182 $x55) $x60) $x64) $x67) false)))) - (let (($x1220 (ite $x63 (ite $x67 (and (and (and (and $x1182 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x1182 $x55) $x59) $x64) $x67) false)))) - (let (($x1544 (ite $x51 (ite $x55 (ite $x59 $x1220 $x1256) (ite $x59 $x1302 $x1338)) (ite $x55 (ite $x59 $x1396 $x1432) (ite $x59 $x1478 $x1514))))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1117 (and $x1079 $x64))) - (let (($x1132 (and $x1117 $x67))) - (let (($x1148 (ite $x63 (ite $x67 (and (and $x1079 $x63) $x67) false) (ite $x67 $x1132 false)))) - (let (($x1112 (ite $x63 (ite $x67 (and (and (and $x995 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x995 $x59) $x64) $x67) false)))) - (let (($x1066 (ite $x63 (ite $x67 (and (and (and (and $x817 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x817 $x55) $x60) $x64) $x67) false)))) - (let (($x1030 (ite $x63 (ite $x67 (and (and (and (and $x817 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x817 $x55) $x59) $x64) $x67) false)))) - (let (($x816 (and $x814 $x51))) - (let (($x819 (and $x816 $x56))) - (let (($x903 (and $x819 $x60))) - (let (($x941 (and $x903 $x64))) - (let (($x956 (and $x941 $x67))) - (let (($x972 (ite $x63 (ite $x67 (and (and $x903 $x63) $x67) false) (ite $x67 $x956 false)))) - (let (($x936 (ite $x63 (ite $x67 (and (and (and $x819 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x819 $x59) $x64) $x67) false)))) - (let (($x890 (ite $x63 (ite $x67 (and (and (and (and $x816 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x816 $x55) $x60) $x64) $x67) false)))) - (let (($x854 (ite $x63 (ite $x67 (and (and (and (and $x816 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x816 $x55) $x59) $x64) $x67) false)))) - (let (($x1178 (ite $x51 (ite $x55 (ite $x59 $x854 $x890) (ite $x59 $x936 $x972)) (ite $x55 (ite $x59 $x1030 $x1066) (ite $x59 $x1112 $x1148))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x735 (and $x697 $x64))) - (let (($x750 (and $x735 $x67))) - (let (($x766 (ite $x63 (ite $x67 (and (and $x697 $x63) $x67) false) (ite $x67 $x750 false)))) - (let (($x730 (ite $x63 (ite $x67 (and (and (and $x613 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x613 $x59) $x64) $x67) false)))) - (let (($x684 (ite $x63 (ite $x67 (and (and (and (and $x435 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x435 $x55) $x60) $x64) $x67) false)))) - (let (($x648 (ite $x63 (ite $x67 (and (and (and (and $x435 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x435 $x55) $x59) $x64) $x67) false)))) - (let (($x434 (and $x50 $x51))) - (let (($x437 (and $x434 $x56))) - (let (($x521 (and $x437 $x60))) - (let (($x559 (and $x521 $x64))) - (let (($x574 (and $x559 $x67))) - (let (($x590 (ite $x63 (ite $x67 (and (and $x521 $x63) $x67) false) (ite $x67 $x574 false)))) - (let (($x554 (ite $x63 (ite $x67 (and (and (and $x437 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x437 $x59) $x64) $x67) false)))) - (let (($x508 (ite $x63 (ite $x67 (and (and (and (and $x434 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x434 $x55) $x60) $x64) $x67) false)))) - (let (($x472 (ite $x63 (ite $x67 (and (and (and (and $x434 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x434 $x55) $x59) $x64) $x67) false)))) - (let (($x796 (ite $x51 (ite $x55 (ite $x59 $x472 $x508) (ite $x59 $x554 $x590)) (ite $x55 (ite $x59 $x648 $x684) (ite $x59 $x730 $x766))))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x369 (and $x331 $x64))) - (let (($x384 (and $x369 $x67))) - (let (($x400 (ite $x63 (ite $x67 (and (and $x331 $x63) $x67) false) (ite $x67 $x384 false)))) - (let (($x364 (ite $x63 (ite $x67 (and (and (and $x247 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x247 $x59) $x64) $x67) false)))) - (let (($x318 (ite $x63 (ite $x67 (and (and (and (and $x54 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x54 $x55) $x60) $x64) $x67) false)))) - (let (($x282 (ite $x63 (ite $x67 (and (and (and (and $x54 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x54 $x55) $x59) $x64) $x67) false)))) - (let (($x53 (and $x49 $x51))) - (let (($x58 (and $x53 $x56))) - (let (($x155 (and $x58 $x60))) - (let (($x193 (and $x155 $x64))) - (let (($x208 (and $x193 $x67))) - (let (($x224 (ite $x63 (ite $x67 (and (and $x155 $x63) $x67) false) (ite $x67 $x208 false)))) - (let (($x188 (ite $x63 (ite $x67 (and (and (and $x58 $x59) $x63) $x67) false) (ite $x67 (and (and (and $x58 $x59) $x64) $x67) false)))) - (let (($x142 (ite $x63 (ite $x67 (and (and (and (and $x53 $x55) $x60) $x63) $x67) false) (ite $x67 (and (and (and (and $x53 $x55) $x60) $x64) $x67) false)))) - (let (($x106 (ite $x63 (ite $x67 (and (and (and (and $x53 $x55) $x59) $x63) $x67) false) (ite $x67 (and (and (and (and $x53 $x55) $x59) $x64) $x67) false)))) - (let (($x430 (ite $x51 (ite $x55 (ite $x59 $x106 $x142) (ite $x59 $x188 $x224)) (ite $x55 (ite $x59 $x282 $x318) (ite $x59 $x364 $x400))))) - (let (($x3106 (ite $x38 (ite $x43 (ite $x47 $x430 $x796) (ite $x47 $x1178 $x1544)) (ite $x43 (ite $x47 $x1944 $x2310) (ite $x47 $x2692 $x3058))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3106) (= (- 1) (- 1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x81 (= h1.f8 ?x37))) + (let (($x85 (ite $x81 (and true $x81) false))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (let (($x159 (not $x92))) + (and (and $x159 $x85) (= (- 1) (- 1))))))))) (check-sat) ; @@ -1158,581 +339,17 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.fr () (_ BitVec 8)) -(declare-fun h1.f8 () (_ BitVec 8)) -(declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert - (let (($x72 (= h1.fr (_ bv255 8)))) - (let (($x73 (and true $x72))) - (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x67 (= h1.f8 ?x37))) - (let (($x68 (not $x67))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x64 (not $x63))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2997 (and $x2959 $x64))) - (let (($x3013 (and $x2997 $x68))) - (let (($x3015 (and $x3013 $x73))) - (let ((?x3024 (ite $x67 (ite (and (and $x2997 $x67) $x73) 0 (- 1)) (ite $x3015 0 (- 1))))) - (let ((?x3010 (ite $x67 (ite (and (and (and $x2959 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2959 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2988 (ite $x67 (ite (and (and (and (and $x2875 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2875 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2974 (ite $x67 (ite (and (and (and (and $x2875 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2875 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2874 (and $x2697 $x55))) - (let (($x2877 (and $x2874 $x60))) - (let (($x2915 (and $x2877 $x64))) - (let (($x2931 (and $x2915 $x68))) - (let (($x2933 (and $x2931 $x73))) - (let ((?x2942 (ite $x67 (ite (and (and $x2915 $x67) $x73) 0 (- 1)) (ite $x2933 0 (- 1))))) - (let ((?x2928 (ite $x67 (ite (and (and (and $x2877 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2877 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2906 (ite $x67 (ite (and (and (and (and $x2874 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2874 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2892 (ite $x67 (ite (and (and (and (and $x2874 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2874 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x3048 (ite $x55 (ite $x59 (ite $x63 ?x2892 ?x2906) (ite $x63 ?x2928 ?x2942)) (ite $x59 (ite $x63 ?x2974 ?x2988) (ite $x63 ?x3010 ?x3024))))) - (let (($x2696 (and $x2329 $x51))) - (let (($x2699 (and $x2696 $x56))) - (let (($x2783 (and $x2699 $x60))) - (let (($x2821 (and $x2783 $x64))) - (let (($x2837 (and $x2821 $x68))) - (let (($x2839 (and $x2837 $x73))) - (let ((?x2848 (ite $x67 (ite (and (and $x2821 $x67) $x73) 0 (- 1)) (ite $x2839 0 (- 1))))) - (let ((?x2834 (ite $x67 (ite (and (and (and $x2783 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2783 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2812 (ite $x67 (ite (and (and (and (and $x2699 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2699 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2798 (ite $x67 (ite (and (and (and (and $x2699 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2699 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2698 (and $x2696 $x55))) - (let (($x2701 (and $x2698 $x60))) - (let (($x2739 (and $x2701 $x64))) - (let (($x2755 (and $x2739 $x68))) - (let (($x2757 (and $x2755 $x73))) - (let ((?x2766 (ite $x67 (ite (and (and $x2739 $x67) $x73) 0 (- 1)) (ite $x2757 0 (- 1))))) - (let ((?x2752 (ite $x67 (ite (and (and (and $x2701 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2701 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2730 (ite $x67 (ite (and (and (and (and $x2698 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2698 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2716 (ite $x67 (ite (and (and (and (and $x2698 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2698 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2872 (ite $x55 (ite $x59 (ite $x63 ?x2716 ?x2730) (ite $x63 ?x2752 ?x2766)) (ite $x59 (ite $x63 ?x2798 ?x2812) (ite $x63 ?x2834 ?x2848))))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2631 (and $x2593 $x64))) - (let (($x2647 (and $x2631 $x68))) - (let (($x2649 (and $x2647 $x73))) - (let ((?x2658 (ite $x67 (ite (and (and $x2631 $x67) $x73) 0 (- 1)) (ite $x2649 0 (- 1))))) - (let ((?x2644 (ite $x67 (ite (and (and (and $x2593 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2593 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2622 (ite $x67 (ite (and (and (and (and $x2509 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2509 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2608 (ite $x67 (ite (and (and (and (and $x2509 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2509 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2508 (and $x2331 $x55))) - (let (($x2511 (and $x2508 $x60))) - (let (($x2549 (and $x2511 $x64))) - (let (($x2565 (and $x2549 $x68))) - (let (($x2567 (and $x2565 $x73))) - (let ((?x2576 (ite $x67 (ite (and (and $x2549 $x67) $x73) 0 (- 1)) (ite $x2567 0 (- 1))))) - (let ((?x2562 (ite $x67 (ite (and (and (and $x2511 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2511 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2540 (ite $x67 (ite (and (and (and (and $x2508 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2508 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2526 (ite $x67 (ite (and (and (and (and $x2508 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2508 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2682 (ite $x55 (ite $x59 (ite $x63 ?x2526 ?x2540) (ite $x63 ?x2562 ?x2576)) (ite $x59 (ite $x63 ?x2608 ?x2622) (ite $x63 ?x2644 ?x2658))))) - (let (($x2330 (and $x2328 $x51))) - (let (($x2333 (and $x2330 $x56))) - (let (($x2417 (and $x2333 $x60))) - (let (($x2455 (and $x2417 $x64))) - (let (($x2471 (and $x2455 $x68))) - (let (($x2473 (and $x2471 $x73))) - (let ((?x2482 (ite $x67 (ite (and (and $x2455 $x67) $x73) 0 (- 1)) (ite $x2473 0 (- 1))))) - (let ((?x2468 (ite $x67 (ite (and (and (and $x2417 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2417 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2446 (ite $x67 (ite (and (and (and (and $x2333 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2333 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2432 (ite $x67 (ite (and (and (and (and $x2333 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2333 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2332 (and $x2330 $x55))) - (let (($x2335 (and $x2332 $x60))) - (let (($x2373 (and $x2335 $x64))) - (let (($x2389 (and $x2373 $x68))) - (let (($x2391 (and $x2389 $x73))) - (let ((?x2400 (ite $x67 (ite (and (and $x2373 $x67) $x73) 0 (- 1)) (ite $x2391 0 (- 1))))) - (let ((?x2386 (ite $x67 (ite (and (and (and $x2335 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2335 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2364 (ite $x67 (ite (and (and (and (and $x2332 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2332 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2350 (ite $x67 (ite (and (and (and (and $x2332 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2332 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2506 (ite $x55 (ite $x59 (ite $x63 ?x2350 ?x2364) (ite $x63 ?x2386 ?x2400)) (ite $x59 (ite $x63 ?x2432 ?x2446) (ite $x63 ?x2468 ?x2482))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2249 (and $x2211 $x64))) - (let (($x2265 (and $x2249 $x68))) - (let (($x2267 (and $x2265 $x73))) - (let ((?x2276 (ite $x67 (ite (and (and $x2249 $x67) $x73) 0 (- 1)) (ite $x2267 0 (- 1))))) - (let ((?x2262 (ite $x67 (ite (and (and (and $x2211 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2211 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2240 (ite $x67 (ite (and (and (and (and $x2127 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2127 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2226 (ite $x67 (ite (and (and (and (and $x2127 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2127 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2126 (and $x1949 $x55))) - (let (($x2129 (and $x2126 $x60))) - (let (($x2167 (and $x2129 $x64))) - (let (($x2183 (and $x2167 $x68))) - (let (($x2185 (and $x2183 $x73))) - (let ((?x2194 (ite $x67 (ite (and (and $x2167 $x67) $x73) 0 (- 1)) (ite $x2185 0 (- 1))))) - (let ((?x2180 (ite $x67 (ite (and (and (and $x2129 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2129 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2158 (ite $x67 (ite (and (and (and (and $x2126 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2126 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2144 (ite $x67 (ite (and (and (and (and $x2126 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2126 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2300 (ite $x55 (ite $x59 (ite $x63 ?x2144 ?x2158) (ite $x63 ?x2180 ?x2194)) (ite $x59 (ite $x63 ?x2226 ?x2240) (ite $x63 ?x2262 ?x2276))))) - (let (($x1948 (and $x1581 $x51))) - (let (($x1951 (and $x1948 $x56))) - (let (($x2035 (and $x1951 $x60))) - (let (($x2073 (and $x2035 $x64))) - (let (($x2089 (and $x2073 $x68))) - (let (($x2091 (and $x2089 $x73))) - (let ((?x2100 (ite $x67 (ite (and (and $x2073 $x67) $x73) 0 (- 1)) (ite $x2091 0 (- 1))))) - (let ((?x2086 (ite $x67 (ite (and (and (and $x2035 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2035 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2064 (ite $x67 (ite (and (and (and (and $x1951 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1951 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2050 (ite $x67 (ite (and (and (and (and $x1951 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1951 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1950 (and $x1948 $x55))) - (let (($x1953 (and $x1950 $x60))) - (let (($x1991 (and $x1953 $x64))) - (let (($x2007 (and $x1991 $x68))) - (let (($x2009 (and $x2007 $x73))) - (let ((?x2018 (ite $x67 (ite (and (and $x1991 $x67) $x73) 0 (- 1)) (ite $x2009 0 (- 1))))) - (let ((?x2004 (ite $x67 (ite (and (and (and $x1953 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1953 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1982 (ite $x67 (ite (and (and (and (and $x1950 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1950 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1968 (ite $x67 (ite (and (and (and (and $x1950 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1950 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2124 (ite $x55 (ite $x59 (ite $x63 ?x1968 ?x1982) (ite $x63 ?x2004 ?x2018)) (ite $x59 (ite $x63 ?x2050 ?x2064) (ite $x63 ?x2086 ?x2100))))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1883 (and $x1845 $x64))) - (let (($x1899 (and $x1883 $x68))) - (let (($x1901 (and $x1899 $x73))) - (let ((?x1910 (ite $x67 (ite (and (and $x1883 $x67) $x73) 0 (- 1)) (ite $x1901 0 (- 1))))) - (let ((?x1896 (ite $x67 (ite (and (and (and $x1845 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1845 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1874 (ite $x67 (ite (and (and (and (and $x1761 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1761 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1860 (ite $x67 (ite (and (and (and (and $x1761 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1761 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1760 (and $x1583 $x55))) - (let (($x1763 (and $x1760 $x60))) - (let (($x1801 (and $x1763 $x64))) - (let (($x1817 (and $x1801 $x68))) - (let (($x1819 (and $x1817 $x73))) - (let ((?x1828 (ite $x67 (ite (and (and $x1801 $x67) $x73) 0 (- 1)) (ite $x1819 0 (- 1))))) - (let ((?x1814 (ite $x67 (ite (and (and (and $x1763 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1763 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1792 (ite $x67 (ite (and (and (and (and $x1760 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1760 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1778 (ite $x67 (ite (and (and (and (and $x1760 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1760 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1934 (ite $x55 (ite $x59 (ite $x63 ?x1778 ?x1792) (ite $x63 ?x1814 ?x1828)) (ite $x59 (ite $x63 ?x1860 ?x1874) (ite $x63 ?x1896 ?x1910))))) - (let (($x1582 (and $x1580 $x51))) - (let (($x1585 (and $x1582 $x56))) - (let (($x1669 (and $x1585 $x60))) - (let (($x1707 (and $x1669 $x64))) - (let (($x1723 (and $x1707 $x68))) - (let (($x1725 (and $x1723 $x73))) - (let ((?x1734 (ite $x67 (ite (and (and $x1707 $x67) $x73) 0 (- 1)) (ite $x1725 0 (- 1))))) - (let ((?x1720 (ite $x67 (ite (and (and (and $x1669 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1669 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1698 (ite $x67 (ite (and (and (and (and $x1585 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1585 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1684 (ite $x67 (ite (and (and (and (and $x1585 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1585 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1584 (and $x1582 $x55))) - (let (($x1587 (and $x1584 $x60))) - (let (($x1625 (and $x1587 $x64))) - (let (($x1641 (and $x1625 $x68))) - (let (($x1643 (and $x1641 $x73))) - (let ((?x1652 (ite $x67 (ite (and (and $x1625 $x67) $x73) 0 (- 1)) (ite $x1643 0 (- 1))))) - (let ((?x1638 (ite $x67 (ite (and (and (and $x1587 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1587 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1616 (ite $x67 (ite (and (and (and (and $x1584 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1584 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1602 (ite $x67 (ite (and (and (and (and $x1584 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1584 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1758 (ite $x55 (ite $x59 (ite $x63 ?x1602 ?x1616) (ite $x63 ?x1638 ?x1652)) (ite $x59 (ite $x63 ?x1684 ?x1698) (ite $x63 ?x1720 ?x1734))))) - (let ((?x3090 (ite $x43 (ite $x47 (ite $x51 ?x1758 ?x1934) (ite $x51 ?x2124 ?x2300)) (ite $x47 (ite $x51 ?x2506 ?x2682) (ite $x51 ?x2872 ?x3048))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1483 (and $x1445 $x64))) - (let (($x1499 (and $x1483 $x68))) - (let (($x1501 (and $x1499 $x73))) - (let ((?x1510 (ite $x67 (ite (and (and $x1483 $x67) $x73) 0 (- 1)) (ite $x1501 0 (- 1))))) - (let ((?x1496 (ite $x67 (ite (and (and (and $x1445 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1445 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1474 (ite $x67 (ite (and (and (and (and $x1361 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1361 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1460 (ite $x67 (ite (and (and (and (and $x1361 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1361 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1360 (and $x1183 $x55))) - (let (($x1363 (and $x1360 $x60))) - (let (($x1401 (and $x1363 $x64))) - (let (($x1417 (and $x1401 $x68))) - (let (($x1419 (and $x1417 $x73))) - (let ((?x1428 (ite $x67 (ite (and (and $x1401 $x67) $x73) 0 (- 1)) (ite $x1419 0 (- 1))))) - (let ((?x1414 (ite $x67 (ite (and (and (and $x1363 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1363 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1392 (ite $x67 (ite (and (and (and (and $x1360 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1360 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1378 (ite $x67 (ite (and (and (and (and $x1360 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1360 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1534 (ite $x55 (ite $x59 (ite $x63 ?x1378 ?x1392) (ite $x63 ?x1414 ?x1428)) (ite $x59 (ite $x63 ?x1460 ?x1474) (ite $x63 ?x1496 ?x1510))))) - (let (($x1182 (and $x815 $x51))) - (let (($x1185 (and $x1182 $x56))) - (let (($x1269 (and $x1185 $x60))) - (let (($x1307 (and $x1269 $x64))) - (let (($x1323 (and $x1307 $x68))) - (let (($x1325 (and $x1323 $x73))) - (let ((?x1334 (ite $x67 (ite (and (and $x1307 $x67) $x73) 0 (- 1)) (ite $x1325 0 (- 1))))) - (let ((?x1320 (ite $x67 (ite (and (and (and $x1269 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1269 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1298 (ite $x67 (ite (and (and (and (and $x1185 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1185 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1284 (ite $x67 (ite (and (and (and (and $x1185 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1185 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1184 (and $x1182 $x55))) - (let (($x1187 (and $x1184 $x60))) - (let (($x1225 (and $x1187 $x64))) - (let (($x1241 (and $x1225 $x68))) - (let (($x1243 (and $x1241 $x73))) - (let ((?x1252 (ite $x67 (ite (and (and $x1225 $x67) $x73) 0 (- 1)) (ite $x1243 0 (- 1))))) - (let ((?x1238 (ite $x67 (ite (and (and (and $x1187 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1187 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1216 (ite $x67 (ite (and (and (and (and $x1184 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1184 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1202 (ite $x67 (ite (and (and (and (and $x1184 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1184 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1358 (ite $x55 (ite $x59 (ite $x63 ?x1202 ?x1216) (ite $x63 ?x1238 ?x1252)) (ite $x59 (ite $x63 ?x1284 ?x1298) (ite $x63 ?x1320 ?x1334))))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1117 (and $x1079 $x64))) - (let (($x1133 (and $x1117 $x68))) - (let (($x1135 (and $x1133 $x73))) - (let ((?x1144 (ite $x67 (ite (and (and $x1117 $x67) $x73) 0 (- 1)) (ite $x1135 0 (- 1))))) - (let ((?x1130 (ite $x67 (ite (and (and (and $x1079 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1079 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1108 (ite $x67 (ite (and (and (and (and $x995 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x995 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1094 (ite $x67 (ite (and (and (and (and $x995 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x995 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x994 (and $x817 $x55))) - (let (($x997 (and $x994 $x60))) - (let (($x1035 (and $x997 $x64))) - (let (($x1051 (and $x1035 $x68))) - (let (($x1053 (and $x1051 $x73))) - (let ((?x1062 (ite $x67 (ite (and (and $x1035 $x67) $x73) 0 (- 1)) (ite $x1053 0 (- 1))))) - (let ((?x1048 (ite $x67 (ite (and (and (and $x997 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x997 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1026 (ite $x67 (ite (and (and (and (and $x994 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x994 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1012 (ite $x67 (ite (and (and (and (and $x994 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x994 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1168 (ite $x55 (ite $x59 (ite $x63 ?x1012 ?x1026) (ite $x63 ?x1048 ?x1062)) (ite $x59 (ite $x63 ?x1094 ?x1108) (ite $x63 ?x1130 ?x1144))))) - (let (($x816 (and $x814 $x51))) - (let (($x819 (and $x816 $x56))) - (let (($x903 (and $x819 $x60))) - (let (($x941 (and $x903 $x64))) - (let (($x957 (and $x941 $x68))) - (let (($x959 (and $x957 $x73))) - (let ((?x968 (ite $x67 (ite (and (and $x941 $x67) $x73) 0 (- 1)) (ite $x959 0 (- 1))))) - (let ((?x954 (ite $x67 (ite (and (and (and $x903 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x903 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x932 (ite $x67 (ite (and (and (and (and $x819 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x819 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x918 (ite $x67 (ite (and (and (and (and $x819 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x819 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x818 (and $x816 $x55))) - (let (($x821 (and $x818 $x60))) - (let (($x859 (and $x821 $x64))) - (let (($x875 (and $x859 $x68))) - (let (($x877 (and $x875 $x73))) - (let ((?x886 (ite $x67 (ite (and (and $x859 $x67) $x73) 0 (- 1)) (ite $x877 0 (- 1))))) - (let ((?x872 (ite $x67 (ite (and (and (and $x821 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x821 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x850 (ite $x67 (ite (and (and (and (and $x818 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x818 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x836 (ite $x67 (ite (and (and (and (and $x818 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x818 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x992 (ite $x55 (ite $x59 (ite $x63 ?x836 ?x850) (ite $x63 ?x872 ?x886)) (ite $x59 (ite $x63 ?x918 ?x932) (ite $x63 ?x954 ?x968))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x735 (and $x697 $x64))) - (let (($x751 (and $x735 $x68))) - (let (($x753 (and $x751 $x73))) - (let ((?x762 (ite $x67 (ite (and (and $x735 $x67) $x73) 0 (- 1)) (ite $x753 0 (- 1))))) - (let ((?x748 (ite $x67 (ite (and (and (and $x697 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x697 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x726 (ite $x67 (ite (and (and (and (and $x613 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x613 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x712 (ite $x67 (ite (and (and (and (and $x613 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x613 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x612 (and $x435 $x55))) - (let (($x615 (and $x612 $x60))) - (let (($x653 (and $x615 $x64))) - (let (($x669 (and $x653 $x68))) - (let (($x671 (and $x669 $x73))) - (let ((?x680 (ite $x67 (ite (and (and $x653 $x67) $x73) 0 (- 1)) (ite $x671 0 (- 1))))) - (let ((?x666 (ite $x67 (ite (and (and (and $x615 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x615 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x644 (ite $x67 (ite (and (and (and (and $x612 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x612 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x630 (ite $x67 (ite (and (and (and (and $x612 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x612 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x786 (ite $x55 (ite $x59 (ite $x63 ?x630 ?x644) (ite $x63 ?x666 ?x680)) (ite $x59 (ite $x63 ?x712 ?x726) (ite $x63 ?x748 ?x762))))) - (let (($x434 (and $x50 $x51))) - (let (($x437 (and $x434 $x56))) - (let (($x521 (and $x437 $x60))) - (let (($x559 (and $x521 $x64))) - (let (($x575 (and $x559 $x68))) - (let (($x577 (and $x575 $x73))) - (let ((?x586 (ite $x67 (ite (and (and $x559 $x67) $x73) 0 (- 1)) (ite $x577 0 (- 1))))) - (let ((?x572 (ite $x67 (ite (and (and (and $x521 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x521 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x550 (ite $x67 (ite (and (and (and (and $x437 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x437 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x536 (ite $x67 (ite (and (and (and (and $x437 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x437 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x436 (and $x434 $x55))) - (let (($x439 (and $x436 $x60))) - (let (($x477 (and $x439 $x64))) - (let (($x493 (and $x477 $x68))) - (let (($x495 (and $x493 $x73))) - (let ((?x504 (ite $x67 (ite (and (and $x477 $x67) $x73) 0 (- 1)) (ite $x495 0 (- 1))))) - (let ((?x490 (ite $x67 (ite (and (and (and $x439 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x439 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x468 (ite $x67 (ite (and (and (and (and $x436 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x436 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x454 (ite $x67 (ite (and (and (and (and $x436 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x436 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x610 (ite $x55 (ite $x59 (ite $x63 ?x454 ?x468) (ite $x63 ?x490 ?x504)) (ite $x59 (ite $x63 ?x536 ?x550) (ite $x63 ?x572 ?x586))))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x369 (and $x331 $x64))) - (let (($x385 (and $x369 $x68))) - (let (($x387 (and $x385 $x73))) - (let ((?x396 (ite $x67 (ite (and (and $x369 $x67) $x73) 0 (- 1)) (ite $x387 0 (- 1))))) - (let ((?x382 (ite $x67 (ite (and (and (and $x331 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x331 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x360 (ite $x67 (ite (and (and (and (and $x247 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x247 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x346 (ite $x67 (ite (and (and (and (and $x247 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x247 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x246 (and $x54 $x55))) - (let (($x249 (and $x246 $x60))) - (let (($x287 (and $x249 $x64))) - (let (($x303 (and $x287 $x68))) - (let (($x305 (and $x303 $x73))) - (let ((?x314 (ite $x67 (ite (and (and $x287 $x67) $x73) 0 (- 1)) (ite $x305 0 (- 1))))) - (let ((?x300 (ite $x67 (ite (and (and (and $x249 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x249 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x278 (ite $x67 (ite (and (and (and (and $x246 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x246 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x264 (ite $x67 (ite (and (and (and (and $x246 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x246 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x420 (ite $x55 (ite $x59 (ite $x63 ?x264 ?x278) (ite $x63 ?x300 ?x314)) (ite $x59 (ite $x63 ?x346 ?x360) (ite $x63 ?x382 ?x396))))) - (let (($x53 (and $x49 $x51))) - (let (($x58 (and $x53 $x56))) - (let (($x155 (and $x58 $x60))) - (let (($x193 (and $x155 $x64))) - (let (($x209 (and $x193 $x68))) - (let (($x211 (and $x209 $x73))) - (let ((?x220 (ite $x67 (ite (and (and $x193 $x67) $x73) 0 (- 1)) (ite $x211 0 (- 1))))) - (let ((?x206 (ite $x67 (ite (and (and (and $x155 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x155 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x184 (ite $x67 (ite (and (and (and (and $x58 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x58 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x170 (ite $x67 (ite (and (and (and (and $x58 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x58 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x57 (and $x53 $x55))) - (let (($x62 (and $x57 $x60))) - (let (($x111 (and $x62 $x64))) - (let (($x127 (and $x111 $x68))) - (let (($x129 (and $x127 $x73))) - (let ((?x138 (ite $x67 (ite (and (and $x111 $x67) $x73) 0 (- 1)) (ite $x129 0 (- 1))))) - (let ((?x124 (ite $x67 (ite (and (and (and $x62 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x62 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x102 (ite $x67 (ite (and (and (and (and $x57 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x57 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x88 (ite $x67 (ite (and (and (and (and $x57 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x57 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x244 (ite $x55 (ite $x59 (ite $x63 ?x88 ?x102) (ite $x63 ?x124 ?x138)) (ite $x59 (ite $x63 ?x170 ?x184) (ite $x63 ?x206 ?x220))))) - (let ((?x1576 (ite $x43 (ite $x47 (ite $x51 ?x244 ?x420) (ite $x51 ?x610 ?x786)) (ite $x47 (ite $x51 ?x992 ?x1168) (ite $x51 ?x1358 ?x1534))))) - (let ((?x3108 (ite $x38 ?x1576 ?x3090))) - (let (($x3029 (ite $x63 (ite $x67 (and (and $x2959 $x63) $x67) (and (and $x2959 $x63) $x68)) (ite $x67 (and $x2997 $x67) $x3013)))) - (let (($x2958 (and $x2875 $x59))) - (let (($x2961 (and $x2958 $x64))) - (let (($x2977 (and $x2961 $x68))) - (let (($x2976 (and $x2961 $x67))) - (let (($x2993 (ite $x63 (ite $x67 (and (and $x2958 $x63) $x67) (and (and $x2958 $x63) $x68)) (ite $x67 $x2976 $x2977)))) - (let (($x2947 (ite $x63 (ite $x67 (and (and $x2877 $x63) $x67) (and (and $x2877 $x63) $x68)) (ite $x67 (and $x2915 $x67) $x2931)))) - (let (($x2876 (and $x2874 $x59))) - (let (($x2879 (and $x2876 $x64))) - (let (($x2895 (and $x2879 $x68))) - (let (($x2894 (and $x2879 $x67))) - (let (($x2911 (ite $x63 (ite $x67 (and (and $x2876 $x63) $x67) (and (and $x2876 $x63) $x68)) (ite $x67 $x2894 $x2895)))) - (let (($x2853 (ite $x63 (ite $x67 (and (and $x2783 $x63) $x67) (and (and $x2783 $x63) $x68)) (ite $x67 (and $x2821 $x67) $x2837)))) - (let (($x2782 (and $x2699 $x59))) - (let (($x2785 (and $x2782 $x64))) - (let (($x2801 (and $x2785 $x68))) - (let (($x2800 (and $x2785 $x67))) - (let (($x2817 (ite $x63 (ite $x67 (and (and $x2782 $x63) $x67) (and (and $x2782 $x63) $x68)) (ite $x67 $x2800 $x2801)))) - (let (($x2771 (ite $x63 (ite $x67 (and (and $x2701 $x63) $x67) (and (and $x2701 $x63) $x68)) (ite $x67 (and $x2739 $x67) $x2755)))) - (let (($x2700 (and $x2698 $x59))) - (let (($x2703 (and $x2700 $x64))) - (let (($x2719 (and $x2703 $x68))) - (let (($x2718 (and $x2703 $x67))) - (let (($x2735 (ite $x63 (ite $x67 (and (and $x2700 $x63) $x67) (and (and $x2700 $x63) $x68)) (ite $x67 $x2718 $x2719)))) - (let (($x3059 (ite $x51 (ite $x55 (ite $x59 $x2735 $x2771) (ite $x59 $x2817 $x2853)) (ite $x55 (ite $x59 $x2911 $x2947) (ite $x59 $x2993 $x3029))))) - (let (($x2663 (ite $x63 (ite $x67 (and (and $x2593 $x63) $x67) (and (and $x2593 $x63) $x68)) (ite $x67 (and $x2631 $x67) $x2647)))) - (let (($x2592 (and $x2509 $x59))) - (let (($x2595 (and $x2592 $x64))) - (let (($x2611 (and $x2595 $x68))) - (let (($x2610 (and $x2595 $x67))) - (let (($x2627 (ite $x63 (ite $x67 (and (and $x2592 $x63) $x67) (and (and $x2592 $x63) $x68)) (ite $x67 $x2610 $x2611)))) - (let (($x2581 (ite $x63 (ite $x67 (and (and $x2511 $x63) $x67) (and (and $x2511 $x63) $x68)) (ite $x67 (and $x2549 $x67) $x2565)))) - (let (($x2510 (and $x2508 $x59))) - (let (($x2513 (and $x2510 $x64))) - (let (($x2529 (and $x2513 $x68))) - (let (($x2528 (and $x2513 $x67))) - (let (($x2545 (ite $x63 (ite $x67 (and (and $x2510 $x63) $x67) (and (and $x2510 $x63) $x68)) (ite $x67 $x2528 $x2529)))) - (let (($x2487 (ite $x63 (ite $x67 (and (and $x2417 $x63) $x67) (and (and $x2417 $x63) $x68)) (ite $x67 (and $x2455 $x67) $x2471)))) - (let (($x2416 (and $x2333 $x59))) - (let (($x2419 (and $x2416 $x64))) - (let (($x2435 (and $x2419 $x68))) - (let (($x2434 (and $x2419 $x67))) - (let (($x2451 (ite $x63 (ite $x67 (and (and $x2416 $x63) $x67) (and (and $x2416 $x63) $x68)) (ite $x67 $x2434 $x2435)))) - (let (($x2405 (ite $x63 (ite $x67 (and (and $x2335 $x63) $x67) (and (and $x2335 $x63) $x68)) (ite $x67 (and $x2373 $x67) $x2389)))) - (let (($x2334 (and $x2332 $x59))) - (let (($x2337 (and $x2334 $x64))) - (let (($x2353 (and $x2337 $x68))) - (let (($x2352 (and $x2337 $x67))) - (let (($x2369 (ite $x63 (ite $x67 (and (and $x2334 $x63) $x67) (and (and $x2334 $x63) $x68)) (ite $x67 $x2352 $x2353)))) - (let (($x2693 (ite $x51 (ite $x55 (ite $x59 $x2369 $x2405) (ite $x59 $x2451 $x2487)) (ite $x55 (ite $x59 $x2545 $x2581) (ite $x59 $x2627 $x2663))))) - (let (($x2281 (ite $x63 (ite $x67 (and (and $x2211 $x63) $x67) (and (and $x2211 $x63) $x68)) (ite $x67 (and $x2249 $x67) $x2265)))) - (let (($x2210 (and $x2127 $x59))) - (let (($x2213 (and $x2210 $x64))) - (let (($x2229 (and $x2213 $x68))) - (let (($x2228 (and $x2213 $x67))) - (let (($x2245 (ite $x63 (ite $x67 (and (and $x2210 $x63) $x67) (and (and $x2210 $x63) $x68)) (ite $x67 $x2228 $x2229)))) - (let (($x2199 (ite $x63 (ite $x67 (and (and $x2129 $x63) $x67) (and (and $x2129 $x63) $x68)) (ite $x67 (and $x2167 $x67) $x2183)))) - (let (($x2128 (and $x2126 $x59))) - (let (($x2131 (and $x2128 $x64))) - (let (($x2147 (and $x2131 $x68))) - (let (($x2146 (and $x2131 $x67))) - (let (($x2163 (ite $x63 (ite $x67 (and (and $x2128 $x63) $x67) (and (and $x2128 $x63) $x68)) (ite $x67 $x2146 $x2147)))) - (let (($x2105 (ite $x63 (ite $x67 (and (and $x2035 $x63) $x67) (and (and $x2035 $x63) $x68)) (ite $x67 (and $x2073 $x67) $x2089)))) - (let (($x2034 (and $x1951 $x59))) - (let (($x2037 (and $x2034 $x64))) - (let (($x2053 (and $x2037 $x68))) - (let (($x2052 (and $x2037 $x67))) - (let (($x2069 (ite $x63 (ite $x67 (and (and $x2034 $x63) $x67) (and (and $x2034 $x63) $x68)) (ite $x67 $x2052 $x2053)))) - (let (($x2023 (ite $x63 (ite $x67 (and (and $x1953 $x63) $x67) (and (and $x1953 $x63) $x68)) (ite $x67 (and $x1991 $x67) $x2007)))) - (let (($x1952 (and $x1950 $x59))) - (let (($x1955 (and $x1952 $x64))) - (let (($x1971 (and $x1955 $x68))) - (let (($x1970 (and $x1955 $x67))) - (let (($x1987 (ite $x63 (ite $x67 (and (and $x1952 $x63) $x67) (and (and $x1952 $x63) $x68)) (ite $x67 $x1970 $x1971)))) - (let (($x2311 (ite $x51 (ite $x55 (ite $x59 $x1987 $x2023) (ite $x59 $x2069 $x2105)) (ite $x55 (ite $x59 $x2163 $x2199) (ite $x59 $x2245 $x2281))))) - (let (($x1915 (ite $x63 (ite $x67 (and (and $x1845 $x63) $x67) (and (and $x1845 $x63) $x68)) (ite $x67 (and $x1883 $x67) $x1899)))) - (let (($x1844 (and $x1761 $x59))) - (let (($x1847 (and $x1844 $x64))) - (let (($x1863 (and $x1847 $x68))) - (let (($x1862 (and $x1847 $x67))) - (let (($x1879 (ite $x63 (ite $x67 (and (and $x1844 $x63) $x67) (and (and $x1844 $x63) $x68)) (ite $x67 $x1862 $x1863)))) - (let (($x1833 (ite $x63 (ite $x67 (and (and $x1763 $x63) $x67) (and (and $x1763 $x63) $x68)) (ite $x67 (and $x1801 $x67) $x1817)))) - (let (($x1762 (and $x1760 $x59))) - (let (($x1765 (and $x1762 $x64))) - (let (($x1781 (and $x1765 $x68))) - (let (($x1780 (and $x1765 $x67))) - (let (($x1797 (ite $x63 (ite $x67 (and (and $x1762 $x63) $x67) (and (and $x1762 $x63) $x68)) (ite $x67 $x1780 $x1781)))) - (let (($x1739 (ite $x63 (ite $x67 (and (and $x1669 $x63) $x67) (and (and $x1669 $x63) $x68)) (ite $x67 (and $x1707 $x67) $x1723)))) - (let (($x1668 (and $x1585 $x59))) - (let (($x1671 (and $x1668 $x64))) - (let (($x1687 (and $x1671 $x68))) - (let (($x1686 (and $x1671 $x67))) - (let (($x1703 (ite $x63 (ite $x67 (and (and $x1668 $x63) $x67) (and (and $x1668 $x63) $x68)) (ite $x67 $x1686 $x1687)))) - (let (($x1657 (ite $x63 (ite $x67 (and (and $x1587 $x63) $x67) (and (and $x1587 $x63) $x68)) (ite $x67 (and $x1625 $x67) $x1641)))) - (let (($x1586 (and $x1584 $x59))) - (let (($x1589 (and $x1586 $x64))) - (let (($x1605 (and $x1589 $x68))) - (let (($x1604 (and $x1589 $x67))) - (let (($x1621 (ite $x63 (ite $x67 (and (and $x1586 $x63) $x67) (and (and $x1586 $x63) $x68)) (ite $x67 $x1604 $x1605)))) - (let (($x1945 (ite $x51 (ite $x55 (ite $x59 $x1621 $x1657) (ite $x59 $x1703 $x1739)) (ite $x55 (ite $x59 $x1797 $x1833) (ite $x59 $x1879 $x1915))))) - (let (($x1515 (ite $x63 (ite $x67 (and (and $x1445 $x63) $x67) (and (and $x1445 $x63) $x68)) (ite $x67 (and $x1483 $x67) $x1499)))) - (let (($x1444 (and $x1361 $x59))) - (let (($x1447 (and $x1444 $x64))) - (let (($x1463 (and $x1447 $x68))) - (let (($x1462 (and $x1447 $x67))) - (let (($x1479 (ite $x63 (ite $x67 (and (and $x1444 $x63) $x67) (and (and $x1444 $x63) $x68)) (ite $x67 $x1462 $x1463)))) - (let (($x1433 (ite $x63 (ite $x67 (and (and $x1363 $x63) $x67) (and (and $x1363 $x63) $x68)) (ite $x67 (and $x1401 $x67) $x1417)))) - (let (($x1362 (and $x1360 $x59))) - (let (($x1365 (and $x1362 $x64))) - (let (($x1381 (and $x1365 $x68))) - (let (($x1380 (and $x1365 $x67))) - (let (($x1397 (ite $x63 (ite $x67 (and (and $x1362 $x63) $x67) (and (and $x1362 $x63) $x68)) (ite $x67 $x1380 $x1381)))) - (let (($x1339 (ite $x63 (ite $x67 (and (and $x1269 $x63) $x67) (and (and $x1269 $x63) $x68)) (ite $x67 (and $x1307 $x67) $x1323)))) - (let (($x1268 (and $x1185 $x59))) - (let (($x1271 (and $x1268 $x64))) - (let (($x1287 (and $x1271 $x68))) - (let (($x1286 (and $x1271 $x67))) - (let (($x1303 (ite $x63 (ite $x67 (and (and $x1268 $x63) $x67) (and (and $x1268 $x63) $x68)) (ite $x67 $x1286 $x1287)))) - (let (($x1257 (ite $x63 (ite $x67 (and (and $x1187 $x63) $x67) (and (and $x1187 $x63) $x68)) (ite $x67 (and $x1225 $x67) $x1241)))) - (let (($x1186 (and $x1184 $x59))) - (let (($x1189 (and $x1186 $x64))) - (let (($x1205 (and $x1189 $x68))) - (let (($x1204 (and $x1189 $x67))) - (let (($x1221 (ite $x63 (ite $x67 (and (and $x1186 $x63) $x67) (and (and $x1186 $x63) $x68)) (ite $x67 $x1204 $x1205)))) - (let (($x1545 (ite $x51 (ite $x55 (ite $x59 $x1221 $x1257) (ite $x59 $x1303 $x1339)) (ite $x55 (ite $x59 $x1397 $x1433) (ite $x59 $x1479 $x1515))))) - (let (($x1149 (ite $x63 (ite $x67 (and (and $x1079 $x63) $x67) (and (and $x1079 $x63) $x68)) (ite $x67 (and $x1117 $x67) $x1133)))) - (let (($x1078 (and $x995 $x59))) - (let (($x1081 (and $x1078 $x64))) - (let (($x1097 (and $x1081 $x68))) - (let (($x1096 (and $x1081 $x67))) - (let (($x1113 (ite $x63 (ite $x67 (and (and $x1078 $x63) $x67) (and (and $x1078 $x63) $x68)) (ite $x67 $x1096 $x1097)))) - (let (($x1067 (ite $x63 (ite $x67 (and (and $x997 $x63) $x67) (and (and $x997 $x63) $x68)) (ite $x67 (and $x1035 $x67) $x1051)))) - (let (($x996 (and $x994 $x59))) - (let (($x999 (and $x996 $x64))) - (let (($x1015 (and $x999 $x68))) - (let (($x1014 (and $x999 $x67))) - (let (($x1031 (ite $x63 (ite $x67 (and (and $x996 $x63) $x67) (and (and $x996 $x63) $x68)) (ite $x67 $x1014 $x1015)))) - (let (($x973 (ite $x63 (ite $x67 (and (and $x903 $x63) $x67) (and (and $x903 $x63) $x68)) (ite $x67 (and $x941 $x67) $x957)))) - (let (($x902 (and $x819 $x59))) - (let (($x905 (and $x902 $x64))) - (let (($x921 (and $x905 $x68))) - (let (($x920 (and $x905 $x67))) - (let (($x937 (ite $x63 (ite $x67 (and (and $x902 $x63) $x67) (and (and $x902 $x63) $x68)) (ite $x67 $x920 $x921)))) - (let (($x891 (ite $x63 (ite $x67 (and (and $x821 $x63) $x67) (and (and $x821 $x63) $x68)) (ite $x67 (and $x859 $x67) $x875)))) - (let (($x820 (and $x818 $x59))) - (let (($x823 (and $x820 $x64))) - (let (($x839 (and $x823 $x68))) - (let (($x838 (and $x823 $x67))) - (let (($x855 (ite $x63 (ite $x67 (and (and $x820 $x63) $x67) (and (and $x820 $x63) $x68)) (ite $x67 $x838 $x839)))) - (let (($x1179 (ite $x51 (ite $x55 (ite $x59 $x855 $x891) (ite $x59 $x937 $x973)) (ite $x55 (ite $x59 $x1031 $x1067) (ite $x59 $x1113 $x1149))))) - (let (($x767 (ite $x63 (ite $x67 (and (and $x697 $x63) $x67) (and (and $x697 $x63) $x68)) (ite $x67 (and $x735 $x67) $x751)))) - (let (($x696 (and $x613 $x59))) - (let (($x699 (and $x696 $x64))) - (let (($x715 (and $x699 $x68))) - (let (($x714 (and $x699 $x67))) - (let (($x731 (ite $x63 (ite $x67 (and (and $x696 $x63) $x67) (and (and $x696 $x63) $x68)) (ite $x67 $x714 $x715)))) - (let (($x685 (ite $x63 (ite $x67 (and (and $x615 $x63) $x67) (and (and $x615 $x63) $x68)) (ite $x67 (and $x653 $x67) $x669)))) - (let (($x614 (and $x612 $x59))) - (let (($x617 (and $x614 $x64))) - (let (($x633 (and $x617 $x68))) - (let (($x632 (and $x617 $x67))) - (let (($x649 (ite $x63 (ite $x67 (and (and $x614 $x63) $x67) (and (and $x614 $x63) $x68)) (ite $x67 $x632 $x633)))) - (let (($x591 (ite $x63 (ite $x67 (and (and $x521 $x63) $x67) (and (and $x521 $x63) $x68)) (ite $x67 (and $x559 $x67) $x575)))) - (let (($x520 (and $x437 $x59))) - (let (($x523 (and $x520 $x64))) - (let (($x539 (and $x523 $x68))) - (let (($x538 (and $x523 $x67))) - (let (($x555 (ite $x63 (ite $x67 (and (and $x520 $x63) $x67) (and (and $x520 $x63) $x68)) (ite $x67 $x538 $x539)))) - (let (($x509 (ite $x63 (ite $x67 (and (and $x439 $x63) $x67) (and (and $x439 $x63) $x68)) (ite $x67 (and $x477 $x67) $x493)))) - (let (($x438 (and $x436 $x59))) - (let (($x441 (and $x438 $x64))) - (let (($x457 (and $x441 $x68))) - (let (($x456 (and $x441 $x67))) - (let (($x473 (ite $x63 (ite $x67 (and (and $x438 $x63) $x67) (and (and $x438 $x63) $x68)) (ite $x67 $x456 $x457)))) - (let (($x797 (ite $x51 (ite $x55 (ite $x59 $x473 $x509) (ite $x59 $x555 $x591)) (ite $x55 (ite $x59 $x649 $x685) (ite $x59 $x731 $x767))))) - (let (($x401 (ite $x63 (ite $x67 (and (and $x331 $x63) $x67) (and (and $x331 $x63) $x68)) (ite $x67 (and $x369 $x67) $x385)))) - (let (($x330 (and $x247 $x59))) - (let (($x333 (and $x330 $x64))) - (let (($x349 (and $x333 $x68))) - (let (($x348 (and $x333 $x67))) - (let (($x365 (ite $x63 (ite $x67 (and (and $x330 $x63) $x67) (and (and $x330 $x63) $x68)) (ite $x67 $x348 $x349)))) - (let (($x319 (ite $x63 (ite $x67 (and (and $x249 $x63) $x67) (and (and $x249 $x63) $x68)) (ite $x67 (and $x287 $x67) $x303)))) - (let (($x248 (and $x246 $x59))) - (let (($x251 (and $x248 $x64))) - (let (($x267 (and $x251 $x68))) - (let (($x266 (and $x251 $x67))) - (let (($x283 (ite $x63 (ite $x67 (and (and $x248 $x63) $x67) (and (and $x248 $x63) $x68)) (ite $x67 $x266 $x267)))) - (let (($x225 (ite $x63 (ite $x67 (and (and $x155 $x63) $x67) (and (and $x155 $x63) $x68)) (ite $x67 (and $x193 $x67) $x209)))) - (let (($x154 (and $x58 $x59))) - (let (($x157 (and $x154 $x64))) - (let (($x173 (and $x157 $x68))) - (let (($x172 (and $x157 $x67))) - (let (($x189 (ite $x63 (ite $x67 (and (and $x154 $x63) $x67) (and (and $x154 $x63) $x68)) (ite $x67 $x172 $x173)))) - (let (($x143 (ite $x63 (ite $x67 (and (and $x62 $x63) $x67) (and (and $x62 $x63) $x68)) (ite $x67 (and $x111 $x67) $x127)))) - (let (($x61 (and $x57 $x59))) - (let (($x66 (and $x61 $x64))) - (let (($x91 (and $x66 $x68))) - (let (($x90 (and $x66 $x67))) - (let (($x107 (ite $x63 (ite $x67 (and (and $x61 $x63) $x67) (and (and $x61 $x63) $x68)) (ite $x67 $x90 $x91)))) - (let (($x431 (ite $x51 (ite $x55 (ite $x59 $x107 $x143) (ite $x59 $x189 $x225)) (ite $x55 (ite $x59 $x283 $x319) (ite $x59 $x365 $x401))))) - (let (($x3107 (ite $x38 (ite $x43 (ite $x47 $x431 $x797) (ite $x47 $x1179 $x1545)) (ite $x43 (ite $x47 $x1945 $x2311) (ite $x47 $x2693 $x3059))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3107) (= ?x3108 (- 1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x90 (and true (and true (= h1.fr (_ bv255 8)))))) + (let ((?x94 (ite $x90 0 (- 1)))) + (and (and (not (= standard_metadata.egress_spec (_ bv511 9))) true) (= ?x94 (- 1)))))) (check-sat) ; @@ -1740,580 +357,16 @@ (declare-fun standard_metadata.ingress_port () (_ BitVec 9)) (declare-fun standard_metadata.egress_spec () (_ BitVec 9)) (declare-fun h1.fr () (_ BitVec 8)) -(declare-fun h1.f8 () (_ BitVec 8)) -(declare-fun h1.f7 () (_ BitVec 8)) -(declare-fun h1.f6 () (_ BitVec 8)) -(declare-fun h1.f5 () (_ BitVec 8)) -(declare-fun h1.f4 () (_ BitVec 8)) -(declare-fun h1.f3 () (_ BitVec 8)) -(declare-fun h1.f2 () (_ BitVec 8)) -(declare-fun h1.f1 () (_ BitVec 8)) (assert - (let (($x3118 (= standard_metadata.ingress_port (_ bv1 9)))) - (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x3118)))) + (let (($x106 (= standard_metadata.ingress_port (_ bv1 9)))) + (and (and (distinct standard_metadata.ingress_port (_ bv511 9)) true) (or (or false (= standard_metadata.ingress_port (_ bv0 9))) $x106)))) (assert - (let (($x3120 (= standard_metadata.egress_spec (_ bv1 9)))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (or $x3111 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x3120))))) + (let (($x108 (= standard_metadata.egress_spec (_ bv1 9)))) + (let (($x92 (= standard_metadata.egress_spec (_ bv511 9)))) + (or $x92 (or (or false (= standard_metadata.egress_spec (_ bv0 9))) $x108))))) (assert - (let (($x72 (= h1.fr (_ bv255 8)))) - (let (($x73 (and true $x72))) - (let ((?x37 (concat (_ bv0 7) (_ bv0 1)))) - (let (($x67 (= h1.f8 ?x37))) - (let (($x68 (not $x67))) - (let (($x63 (= h1.f7 ?x37))) - (let (($x64 (not $x63))) - (let (($x59 (= h1.f6 ?x37))) - (let (($x60 (not $x59))) - (let (($x55 (= h1.f5 ?x37))) - (let (($x56 (not $x55))) - (let (($x51 (= h1.f4 ?x37))) - (let (($x52 (not $x51))) - (let (($x47 (= h1.f3 ?x37))) - (let (($x48 (not $x47))) - (let (($x43 (= h1.f2 ?x37))) - (let (($x44 (not $x43))) - (let (($x41 (and true (not (= h1.f1 ?x37))))) - (let (($x1579 (and $x41 $x44))) - (let (($x2329 (and $x1579 $x48))) - (let (($x2697 (and $x2329 $x52))) - (let (($x2875 (and $x2697 $x56))) - (let (($x2959 (and $x2875 $x60))) - (let (($x2997 (and $x2959 $x64))) - (let (($x3013 (and $x2997 $x68))) - (let (($x3015 (and $x3013 $x73))) - (let ((?x3024 (ite $x67 (ite (and (and $x2997 $x67) $x73) 0 (- 1)) (ite $x3015 0 (- 1))))) - (let ((?x3010 (ite $x67 (ite (and (and (and $x2959 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2959 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2988 (ite $x67 (ite (and (and (and (and $x2875 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2875 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2974 (ite $x67 (ite (and (and (and (and $x2875 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2875 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2874 (and $x2697 $x55))) - (let (($x2877 (and $x2874 $x60))) - (let (($x2915 (and $x2877 $x64))) - (let (($x2931 (and $x2915 $x68))) - (let (($x2933 (and $x2931 $x73))) - (let ((?x2942 (ite $x67 (ite (and (and $x2915 $x67) $x73) 0 (- 1)) (ite $x2933 0 (- 1))))) - (let ((?x2928 (ite $x67 (ite (and (and (and $x2877 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2877 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2906 (ite $x67 (ite (and (and (and (and $x2874 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2874 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2892 (ite $x67 (ite (and (and (and (and $x2874 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2874 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x3048 (ite $x55 (ite $x59 (ite $x63 ?x2892 ?x2906) (ite $x63 ?x2928 ?x2942)) (ite $x59 (ite $x63 ?x2974 ?x2988) (ite $x63 ?x3010 ?x3024))))) - (let (($x2696 (and $x2329 $x51))) - (let (($x2699 (and $x2696 $x56))) - (let (($x2783 (and $x2699 $x60))) - (let (($x2821 (and $x2783 $x64))) - (let (($x2837 (and $x2821 $x68))) - (let (($x2839 (and $x2837 $x73))) - (let ((?x2848 (ite $x67 (ite (and (and $x2821 $x67) $x73) 0 (- 1)) (ite $x2839 0 (- 1))))) - (let ((?x2834 (ite $x67 (ite (and (and (and $x2783 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2783 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2812 (ite $x67 (ite (and (and (and (and $x2699 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2699 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2798 (ite $x67 (ite (and (and (and (and $x2699 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2699 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2698 (and $x2696 $x55))) - (let (($x2701 (and $x2698 $x60))) - (let (($x2739 (and $x2701 $x64))) - (let (($x2755 (and $x2739 $x68))) - (let (($x2757 (and $x2755 $x73))) - (let ((?x2766 (ite $x67 (ite (and (and $x2739 $x67) $x73) 0 (- 1)) (ite $x2757 0 (- 1))))) - (let ((?x2752 (ite $x67 (ite (and (and (and $x2701 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2701 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2730 (ite $x67 (ite (and (and (and (and $x2698 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2698 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2716 (ite $x67 (ite (and (and (and (and $x2698 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2698 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2872 (ite $x55 (ite $x59 (ite $x63 ?x2716 ?x2730) (ite $x63 ?x2752 ?x2766)) (ite $x59 (ite $x63 ?x2798 ?x2812) (ite $x63 ?x2834 ?x2848))))) - (let (($x2328 (and $x1579 $x47))) - (let (($x2331 (and $x2328 $x52))) - (let (($x2509 (and $x2331 $x56))) - (let (($x2593 (and $x2509 $x60))) - (let (($x2631 (and $x2593 $x64))) - (let (($x2647 (and $x2631 $x68))) - (let (($x2649 (and $x2647 $x73))) - (let ((?x2658 (ite $x67 (ite (and (and $x2631 $x67) $x73) 0 (- 1)) (ite $x2649 0 (- 1))))) - (let ((?x2644 (ite $x67 (ite (and (and (and $x2593 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2593 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2622 (ite $x67 (ite (and (and (and (and $x2509 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2509 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2608 (ite $x67 (ite (and (and (and (and $x2509 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2509 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2508 (and $x2331 $x55))) - (let (($x2511 (and $x2508 $x60))) - (let (($x2549 (and $x2511 $x64))) - (let (($x2565 (and $x2549 $x68))) - (let (($x2567 (and $x2565 $x73))) - (let ((?x2576 (ite $x67 (ite (and (and $x2549 $x67) $x73) 0 (- 1)) (ite $x2567 0 (- 1))))) - (let ((?x2562 (ite $x67 (ite (and (and (and $x2511 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2511 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2540 (ite $x67 (ite (and (and (and (and $x2508 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2508 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2526 (ite $x67 (ite (and (and (and (and $x2508 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2508 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2682 (ite $x55 (ite $x59 (ite $x63 ?x2526 ?x2540) (ite $x63 ?x2562 ?x2576)) (ite $x59 (ite $x63 ?x2608 ?x2622) (ite $x63 ?x2644 ?x2658))))) - (let (($x2330 (and $x2328 $x51))) - (let (($x2333 (and $x2330 $x56))) - (let (($x2417 (and $x2333 $x60))) - (let (($x2455 (and $x2417 $x64))) - (let (($x2471 (and $x2455 $x68))) - (let (($x2473 (and $x2471 $x73))) - (let ((?x2482 (ite $x67 (ite (and (and $x2455 $x67) $x73) 0 (- 1)) (ite $x2473 0 (- 1))))) - (let ((?x2468 (ite $x67 (ite (and (and (and $x2417 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2417 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2446 (ite $x67 (ite (and (and (and (and $x2333 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2333 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2432 (ite $x67 (ite (and (and (and (and $x2333 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2333 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2332 (and $x2330 $x55))) - (let (($x2335 (and $x2332 $x60))) - (let (($x2373 (and $x2335 $x64))) - (let (($x2389 (and $x2373 $x68))) - (let (($x2391 (and $x2389 $x73))) - (let ((?x2400 (ite $x67 (ite (and (and $x2373 $x67) $x73) 0 (- 1)) (ite $x2391 0 (- 1))))) - (let ((?x2386 (ite $x67 (ite (and (and (and $x2335 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2335 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2364 (ite $x67 (ite (and (and (and (and $x2332 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2332 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2350 (ite $x67 (ite (and (and (and (and $x2332 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2332 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2506 (ite $x55 (ite $x59 (ite $x63 ?x2350 ?x2364) (ite $x63 ?x2386 ?x2400)) (ite $x59 (ite $x63 ?x2432 ?x2446) (ite $x63 ?x2468 ?x2482))))) - (let (($x1578 (and $x41 $x43))) - (let (($x1581 (and $x1578 $x48))) - (let (($x1949 (and $x1581 $x52))) - (let (($x2127 (and $x1949 $x56))) - (let (($x2211 (and $x2127 $x60))) - (let (($x2249 (and $x2211 $x64))) - (let (($x2265 (and $x2249 $x68))) - (let (($x2267 (and $x2265 $x73))) - (let ((?x2276 (ite $x67 (ite (and (and $x2249 $x67) $x73) 0 (- 1)) (ite $x2267 0 (- 1))))) - (let ((?x2262 (ite $x67 (ite (and (and (and $x2211 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2211 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2240 (ite $x67 (ite (and (and (and (and $x2127 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2127 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2226 (ite $x67 (ite (and (and (and (and $x2127 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2127 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x2126 (and $x1949 $x55))) - (let (($x2129 (and $x2126 $x60))) - (let (($x2167 (and $x2129 $x64))) - (let (($x2183 (and $x2167 $x68))) - (let (($x2185 (and $x2183 $x73))) - (let ((?x2194 (ite $x67 (ite (and (and $x2167 $x67) $x73) 0 (- 1)) (ite $x2185 0 (- 1))))) - (let ((?x2180 (ite $x67 (ite (and (and (and $x2129 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2129 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2158 (ite $x67 (ite (and (and (and (and $x2126 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2126 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2144 (ite $x67 (ite (and (and (and (and $x2126 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x2126 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2300 (ite $x55 (ite $x59 (ite $x63 ?x2144 ?x2158) (ite $x63 ?x2180 ?x2194)) (ite $x59 (ite $x63 ?x2226 ?x2240) (ite $x63 ?x2262 ?x2276))))) - (let (($x1948 (and $x1581 $x51))) - (let (($x1951 (and $x1948 $x56))) - (let (($x2035 (and $x1951 $x60))) - (let (($x2073 (and $x2035 $x64))) - (let (($x2089 (and $x2073 $x68))) - (let (($x2091 (and $x2089 $x73))) - (let ((?x2100 (ite $x67 (ite (and (and $x2073 $x67) $x73) 0 (- 1)) (ite $x2091 0 (- 1))))) - (let ((?x2086 (ite $x67 (ite (and (and (and $x2035 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x2035 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2064 (ite $x67 (ite (and (and (and (and $x1951 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1951 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x2050 (ite $x67 (ite (and (and (and (and $x1951 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1951 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1950 (and $x1948 $x55))) - (let (($x1953 (and $x1950 $x60))) - (let (($x1991 (and $x1953 $x64))) - (let (($x2007 (and $x1991 $x68))) - (let (($x2009 (and $x2007 $x73))) - (let ((?x2018 (ite $x67 (ite (and (and $x1991 $x67) $x73) 0 (- 1)) (ite $x2009 0 (- 1))))) - (let ((?x2004 (ite $x67 (ite (and (and (and $x1953 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1953 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1982 (ite $x67 (ite (and (and (and (and $x1950 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1950 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1968 (ite $x67 (ite (and (and (and (and $x1950 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1950 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x2124 (ite $x55 (ite $x59 (ite $x63 ?x1968 ?x1982) (ite $x63 ?x2004 ?x2018)) (ite $x59 (ite $x63 ?x2050 ?x2064) (ite $x63 ?x2086 ?x2100))))) - (let (($x1580 (and $x1578 $x47))) - (let (($x1583 (and $x1580 $x52))) - (let (($x1761 (and $x1583 $x56))) - (let (($x1845 (and $x1761 $x60))) - (let (($x1883 (and $x1845 $x64))) - (let (($x1899 (and $x1883 $x68))) - (let (($x1901 (and $x1899 $x73))) - (let ((?x1910 (ite $x67 (ite (and (and $x1883 $x67) $x73) 0 (- 1)) (ite $x1901 0 (- 1))))) - (let ((?x1896 (ite $x67 (ite (and (and (and $x1845 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1845 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1874 (ite $x67 (ite (and (and (and (and $x1761 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1761 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1860 (ite $x67 (ite (and (and (and (and $x1761 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1761 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1760 (and $x1583 $x55))) - (let (($x1763 (and $x1760 $x60))) - (let (($x1801 (and $x1763 $x64))) - (let (($x1817 (and $x1801 $x68))) - (let (($x1819 (and $x1817 $x73))) - (let ((?x1828 (ite $x67 (ite (and (and $x1801 $x67) $x73) 0 (- 1)) (ite $x1819 0 (- 1))))) - (let ((?x1814 (ite $x67 (ite (and (and (and $x1763 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1763 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1792 (ite $x67 (ite (and (and (and (and $x1760 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1760 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1778 (ite $x67 (ite (and (and (and (and $x1760 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1760 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1934 (ite $x55 (ite $x59 (ite $x63 ?x1778 ?x1792) (ite $x63 ?x1814 ?x1828)) (ite $x59 (ite $x63 ?x1860 ?x1874) (ite $x63 ?x1896 ?x1910))))) - (let (($x1582 (and $x1580 $x51))) - (let (($x1585 (and $x1582 $x56))) - (let (($x1669 (and $x1585 $x60))) - (let (($x1707 (and $x1669 $x64))) - (let (($x1723 (and $x1707 $x68))) - (let (($x1725 (and $x1723 $x73))) - (let ((?x1734 (ite $x67 (ite (and (and $x1707 $x67) $x73) 0 (- 1)) (ite $x1725 0 (- 1))))) - (let ((?x1720 (ite $x67 (ite (and (and (and $x1669 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1669 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1698 (ite $x67 (ite (and (and (and (and $x1585 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1585 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1684 (ite $x67 (ite (and (and (and (and $x1585 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1585 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1584 (and $x1582 $x55))) - (let (($x1587 (and $x1584 $x60))) - (let (($x1625 (and $x1587 $x64))) - (let (($x1641 (and $x1625 $x68))) - (let (($x1643 (and $x1641 $x73))) - (let ((?x1652 (ite $x67 (ite (and (and $x1625 $x67) $x73) 0 (- 1)) (ite $x1643 0 (- 1))))) - (let ((?x1638 (ite $x67 (ite (and (and (and $x1587 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1587 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1616 (ite $x67 (ite (and (and (and (and $x1584 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1584 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1602 (ite $x67 (ite (and (and (and (and $x1584 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1584 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1758 (ite $x55 (ite $x59 (ite $x63 ?x1602 ?x1616) (ite $x63 ?x1638 ?x1652)) (ite $x59 (ite $x63 ?x1684 ?x1698) (ite $x63 ?x1720 ?x1734))))) - (let ((?x3090 (ite $x43 (ite $x47 (ite $x51 ?x1758 ?x1934) (ite $x51 ?x2124 ?x2300)) (ite $x47 (ite $x51 ?x2506 ?x2682) (ite $x51 ?x2872 ?x3048))))) - (let (($x38 (= h1.f1 ?x37))) - (let (($x40 (and true $x38))) - (let (($x46 (and $x40 $x44))) - (let (($x815 (and $x46 $x48))) - (let (($x1183 (and $x815 $x52))) - (let (($x1361 (and $x1183 $x56))) - (let (($x1445 (and $x1361 $x60))) - (let (($x1483 (and $x1445 $x64))) - (let (($x1499 (and $x1483 $x68))) - (let (($x1501 (and $x1499 $x73))) - (let ((?x1510 (ite $x67 (ite (and (and $x1483 $x67) $x73) 0 (- 1)) (ite $x1501 0 (- 1))))) - (let ((?x1496 (ite $x67 (ite (and (and (and $x1445 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1445 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1474 (ite $x67 (ite (and (and (and (and $x1361 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1361 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1460 (ite $x67 (ite (and (and (and (and $x1361 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1361 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1360 (and $x1183 $x55))) - (let (($x1363 (and $x1360 $x60))) - (let (($x1401 (and $x1363 $x64))) - (let (($x1417 (and $x1401 $x68))) - (let (($x1419 (and $x1417 $x73))) - (let ((?x1428 (ite $x67 (ite (and (and $x1401 $x67) $x73) 0 (- 1)) (ite $x1419 0 (- 1))))) - (let ((?x1414 (ite $x67 (ite (and (and (and $x1363 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1363 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1392 (ite $x67 (ite (and (and (and (and $x1360 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1360 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1378 (ite $x67 (ite (and (and (and (and $x1360 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1360 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1534 (ite $x55 (ite $x59 (ite $x63 ?x1378 ?x1392) (ite $x63 ?x1414 ?x1428)) (ite $x59 (ite $x63 ?x1460 ?x1474) (ite $x63 ?x1496 ?x1510))))) - (let (($x1182 (and $x815 $x51))) - (let (($x1185 (and $x1182 $x56))) - (let (($x1269 (and $x1185 $x60))) - (let (($x1307 (and $x1269 $x64))) - (let (($x1323 (and $x1307 $x68))) - (let (($x1325 (and $x1323 $x73))) - (let ((?x1334 (ite $x67 (ite (and (and $x1307 $x67) $x73) 0 (- 1)) (ite $x1325 0 (- 1))))) - (let ((?x1320 (ite $x67 (ite (and (and (and $x1269 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1269 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1298 (ite $x67 (ite (and (and (and (and $x1185 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1185 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1284 (ite $x67 (ite (and (and (and (and $x1185 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1185 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x1184 (and $x1182 $x55))) - (let (($x1187 (and $x1184 $x60))) - (let (($x1225 (and $x1187 $x64))) - (let (($x1241 (and $x1225 $x68))) - (let (($x1243 (and $x1241 $x73))) - (let ((?x1252 (ite $x67 (ite (and (and $x1225 $x67) $x73) 0 (- 1)) (ite $x1243 0 (- 1))))) - (let ((?x1238 (ite $x67 (ite (and (and (and $x1187 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1187 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1216 (ite $x67 (ite (and (and (and (and $x1184 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1184 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1202 (ite $x67 (ite (and (and (and (and $x1184 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x1184 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1358 (ite $x55 (ite $x59 (ite $x63 ?x1202 ?x1216) (ite $x63 ?x1238 ?x1252)) (ite $x59 (ite $x63 ?x1284 ?x1298) (ite $x63 ?x1320 ?x1334))))) - (let (($x814 (and $x46 $x47))) - (let (($x817 (and $x814 $x52))) - (let (($x995 (and $x817 $x56))) - (let (($x1079 (and $x995 $x60))) - (let (($x1117 (and $x1079 $x64))) - (let (($x1133 (and $x1117 $x68))) - (let (($x1135 (and $x1133 $x73))) - (let ((?x1144 (ite $x67 (ite (and (and $x1117 $x67) $x73) 0 (- 1)) (ite $x1135 0 (- 1))))) - (let ((?x1130 (ite $x67 (ite (and (and (and $x1079 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x1079 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1108 (ite $x67 (ite (and (and (and (and $x995 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x995 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1094 (ite $x67 (ite (and (and (and (and $x995 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x995 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x994 (and $x817 $x55))) - (let (($x997 (and $x994 $x60))) - (let (($x1035 (and $x997 $x64))) - (let (($x1051 (and $x1035 $x68))) - (let (($x1053 (and $x1051 $x73))) - (let ((?x1062 (ite $x67 (ite (and (and $x1035 $x67) $x73) 0 (- 1)) (ite $x1053 0 (- 1))))) - (let ((?x1048 (ite $x67 (ite (and (and (and $x997 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x997 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1026 (ite $x67 (ite (and (and (and (and $x994 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x994 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x1012 (ite $x67 (ite (and (and (and (and $x994 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x994 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x1168 (ite $x55 (ite $x59 (ite $x63 ?x1012 ?x1026) (ite $x63 ?x1048 ?x1062)) (ite $x59 (ite $x63 ?x1094 ?x1108) (ite $x63 ?x1130 ?x1144))))) - (let (($x816 (and $x814 $x51))) - (let (($x819 (and $x816 $x56))) - (let (($x903 (and $x819 $x60))) - (let (($x941 (and $x903 $x64))) - (let (($x957 (and $x941 $x68))) - (let (($x959 (and $x957 $x73))) - (let ((?x968 (ite $x67 (ite (and (and $x941 $x67) $x73) 0 (- 1)) (ite $x959 0 (- 1))))) - (let ((?x954 (ite $x67 (ite (and (and (and $x903 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x903 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x932 (ite $x67 (ite (and (and (and (and $x819 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x819 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x918 (ite $x67 (ite (and (and (and (and $x819 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x819 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x818 (and $x816 $x55))) - (let (($x821 (and $x818 $x60))) - (let (($x859 (and $x821 $x64))) - (let (($x875 (and $x859 $x68))) - (let (($x877 (and $x875 $x73))) - (let ((?x886 (ite $x67 (ite (and (and $x859 $x67) $x73) 0 (- 1)) (ite $x877 0 (- 1))))) - (let ((?x872 (ite $x67 (ite (and (and (and $x821 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x821 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x850 (ite $x67 (ite (and (and (and (and $x818 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x818 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x836 (ite $x67 (ite (and (and (and (and $x818 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x818 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x992 (ite $x55 (ite $x59 (ite $x63 ?x836 ?x850) (ite $x63 ?x872 ?x886)) (ite $x59 (ite $x63 ?x918 ?x932) (ite $x63 ?x954 ?x968))))) - (let (($x45 (and $x40 $x43))) - (let (($x50 (and $x45 $x48))) - (let (($x435 (and $x50 $x52))) - (let (($x613 (and $x435 $x56))) - (let (($x697 (and $x613 $x60))) - (let (($x735 (and $x697 $x64))) - (let (($x751 (and $x735 $x68))) - (let (($x753 (and $x751 $x73))) - (let ((?x762 (ite $x67 (ite (and (and $x735 $x67) $x73) 0 (- 1)) (ite $x753 0 (- 1))))) - (let ((?x748 (ite $x67 (ite (and (and (and $x697 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x697 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x726 (ite $x67 (ite (and (and (and (and $x613 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x613 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x712 (ite $x67 (ite (and (and (and (and $x613 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x613 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x612 (and $x435 $x55))) - (let (($x615 (and $x612 $x60))) - (let (($x653 (and $x615 $x64))) - (let (($x669 (and $x653 $x68))) - (let (($x671 (and $x669 $x73))) - (let ((?x680 (ite $x67 (ite (and (and $x653 $x67) $x73) 0 (- 1)) (ite $x671 0 (- 1))))) - (let ((?x666 (ite $x67 (ite (and (and (and $x615 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x615 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x644 (ite $x67 (ite (and (and (and (and $x612 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x612 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x630 (ite $x67 (ite (and (and (and (and $x612 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x612 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x786 (ite $x55 (ite $x59 (ite $x63 ?x630 ?x644) (ite $x63 ?x666 ?x680)) (ite $x59 (ite $x63 ?x712 ?x726) (ite $x63 ?x748 ?x762))))) - (let (($x434 (and $x50 $x51))) - (let (($x437 (and $x434 $x56))) - (let (($x521 (and $x437 $x60))) - (let (($x559 (and $x521 $x64))) - (let (($x575 (and $x559 $x68))) - (let (($x577 (and $x575 $x73))) - (let ((?x586 (ite $x67 (ite (and (and $x559 $x67) $x73) 0 (- 1)) (ite $x577 0 (- 1))))) - (let ((?x572 (ite $x67 (ite (and (and (and $x521 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x521 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x550 (ite $x67 (ite (and (and (and (and $x437 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x437 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x536 (ite $x67 (ite (and (and (and (and $x437 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x437 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x436 (and $x434 $x55))) - (let (($x439 (and $x436 $x60))) - (let (($x477 (and $x439 $x64))) - (let (($x493 (and $x477 $x68))) - (let (($x495 (and $x493 $x73))) - (let ((?x504 (ite $x67 (ite (and (and $x477 $x67) $x73) 0 (- 1)) (ite $x495 0 (- 1))))) - (let ((?x490 (ite $x67 (ite (and (and (and $x439 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x439 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x468 (ite $x67 (ite (and (and (and (and $x436 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x436 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x454 (ite $x67 (ite (and (and (and (and $x436 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x436 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x610 (ite $x55 (ite $x59 (ite $x63 ?x454 ?x468) (ite $x63 ?x490 ?x504)) (ite $x59 (ite $x63 ?x536 ?x550) (ite $x63 ?x572 ?x586))))) - (let (($x49 (and $x45 $x47))) - (let (($x54 (and $x49 $x52))) - (let (($x247 (and $x54 $x56))) - (let (($x331 (and $x247 $x60))) - (let (($x369 (and $x331 $x64))) - (let (($x385 (and $x369 $x68))) - (let (($x387 (and $x385 $x73))) - (let ((?x396 (ite $x67 (ite (and (and $x369 $x67) $x73) 0 (- 1)) (ite $x387 0 (- 1))))) - (let ((?x382 (ite $x67 (ite (and (and (and $x331 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x331 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x360 (ite $x67 (ite (and (and (and (and $x247 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x247 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x346 (ite $x67 (ite (and (and (and (and $x247 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x247 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x246 (and $x54 $x55))) - (let (($x249 (and $x246 $x60))) - (let (($x287 (and $x249 $x64))) - (let (($x303 (and $x287 $x68))) - (let (($x305 (and $x303 $x73))) - (let ((?x314 (ite $x67 (ite (and (and $x287 $x67) $x73) 0 (- 1)) (ite $x305 0 (- 1))))) - (let ((?x300 (ite $x67 (ite (and (and (and $x249 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x249 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x278 (ite $x67 (ite (and (and (and (and $x246 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x246 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x264 (ite $x67 (ite (and (and (and (and $x246 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x246 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x420 (ite $x55 (ite $x59 (ite $x63 ?x264 ?x278) (ite $x63 ?x300 ?x314)) (ite $x59 (ite $x63 ?x346 ?x360) (ite $x63 ?x382 ?x396))))) - (let (($x53 (and $x49 $x51))) - (let (($x58 (and $x53 $x56))) - (let (($x155 (and $x58 $x60))) - (let (($x193 (and $x155 $x64))) - (let (($x209 (and $x193 $x68))) - (let (($x211 (and $x209 $x73))) - (let ((?x220 (ite $x67 (ite (and (and $x193 $x67) $x73) 0 (- 1)) (ite $x211 0 (- 1))))) - (let ((?x206 (ite $x67 (ite (and (and (and $x155 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x155 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x184 (ite $x67 (ite (and (and (and (and $x58 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x58 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x170 (ite $x67 (ite (and (and (and (and $x58 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x58 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let (($x57 (and $x53 $x55))) - (let (($x62 (and $x57 $x60))) - (let (($x111 (and $x62 $x64))) - (let (($x127 (and $x111 $x68))) - (let (($x129 (and $x127 $x73))) - (let ((?x138 (ite $x67 (ite (and (and $x111 $x67) $x73) 0 (- 1)) (ite $x129 0 (- 1))))) - (let ((?x124 (ite $x67 (ite (and (and (and $x62 $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and $x62 $x63) $x68) $x73) 0 (- 1))))) - (let ((?x102 (ite $x67 (ite (and (and (and (and $x57 $x59) $x64) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x57 $x59) $x64) $x68) $x73) 0 (- 1))))) - (let ((?x88 (ite $x67 (ite (and (and (and (and $x57 $x59) $x63) $x67) $x73) 0 (- 1)) (ite (and (and (and (and $x57 $x59) $x63) $x68) $x73) 0 (- 1))))) - (let ((?x244 (ite $x55 (ite $x59 (ite $x63 ?x88 ?x102) (ite $x63 ?x124 ?x138)) (ite $x59 (ite $x63 ?x170 ?x184) (ite $x63 ?x206 ?x220))))) - (let ((?x1576 (ite $x43 (ite $x47 (ite $x51 ?x244 ?x420) (ite $x51 ?x610 ?x786)) (ite $x47 (ite $x51 ?x992 ?x1168) (ite $x51 ?x1358 ?x1534))))) - (let ((?x3108 (ite $x38 ?x1576 ?x3090))) - (let (($x3029 (ite $x63 (ite $x67 (and (and $x2959 $x63) $x67) (and (and $x2959 $x63) $x68)) (ite $x67 (and $x2997 $x67) $x3013)))) - (let (($x2958 (and $x2875 $x59))) - (let (($x2961 (and $x2958 $x64))) - (let (($x2977 (and $x2961 $x68))) - (let (($x2976 (and $x2961 $x67))) - (let (($x2993 (ite $x63 (ite $x67 (and (and $x2958 $x63) $x67) (and (and $x2958 $x63) $x68)) (ite $x67 $x2976 $x2977)))) - (let (($x2947 (ite $x63 (ite $x67 (and (and $x2877 $x63) $x67) (and (and $x2877 $x63) $x68)) (ite $x67 (and $x2915 $x67) $x2931)))) - (let (($x2876 (and $x2874 $x59))) - (let (($x2879 (and $x2876 $x64))) - (let (($x2895 (and $x2879 $x68))) - (let (($x2894 (and $x2879 $x67))) - (let (($x2911 (ite $x63 (ite $x67 (and (and $x2876 $x63) $x67) (and (and $x2876 $x63) $x68)) (ite $x67 $x2894 $x2895)))) - (let (($x2853 (ite $x63 (ite $x67 (and (and $x2783 $x63) $x67) (and (and $x2783 $x63) $x68)) (ite $x67 (and $x2821 $x67) $x2837)))) - (let (($x2782 (and $x2699 $x59))) - (let (($x2785 (and $x2782 $x64))) - (let (($x2801 (and $x2785 $x68))) - (let (($x2800 (and $x2785 $x67))) - (let (($x2817 (ite $x63 (ite $x67 (and (and $x2782 $x63) $x67) (and (and $x2782 $x63) $x68)) (ite $x67 $x2800 $x2801)))) - (let (($x2771 (ite $x63 (ite $x67 (and (and $x2701 $x63) $x67) (and (and $x2701 $x63) $x68)) (ite $x67 (and $x2739 $x67) $x2755)))) - (let (($x2700 (and $x2698 $x59))) - (let (($x2703 (and $x2700 $x64))) - (let (($x2719 (and $x2703 $x68))) - (let (($x2718 (and $x2703 $x67))) - (let (($x2735 (ite $x63 (ite $x67 (and (and $x2700 $x63) $x67) (and (and $x2700 $x63) $x68)) (ite $x67 $x2718 $x2719)))) - (let (($x3059 (ite $x51 (ite $x55 (ite $x59 $x2735 $x2771) (ite $x59 $x2817 $x2853)) (ite $x55 (ite $x59 $x2911 $x2947) (ite $x59 $x2993 $x3029))))) - (let (($x2663 (ite $x63 (ite $x67 (and (and $x2593 $x63) $x67) (and (and $x2593 $x63) $x68)) (ite $x67 (and $x2631 $x67) $x2647)))) - (let (($x2592 (and $x2509 $x59))) - (let (($x2595 (and $x2592 $x64))) - (let (($x2611 (and $x2595 $x68))) - (let (($x2610 (and $x2595 $x67))) - (let (($x2627 (ite $x63 (ite $x67 (and (and $x2592 $x63) $x67) (and (and $x2592 $x63) $x68)) (ite $x67 $x2610 $x2611)))) - (let (($x2581 (ite $x63 (ite $x67 (and (and $x2511 $x63) $x67) (and (and $x2511 $x63) $x68)) (ite $x67 (and $x2549 $x67) $x2565)))) - (let (($x2510 (and $x2508 $x59))) - (let (($x2513 (and $x2510 $x64))) - (let (($x2529 (and $x2513 $x68))) - (let (($x2528 (and $x2513 $x67))) - (let (($x2545 (ite $x63 (ite $x67 (and (and $x2510 $x63) $x67) (and (and $x2510 $x63) $x68)) (ite $x67 $x2528 $x2529)))) - (let (($x2487 (ite $x63 (ite $x67 (and (and $x2417 $x63) $x67) (and (and $x2417 $x63) $x68)) (ite $x67 (and $x2455 $x67) $x2471)))) - (let (($x2416 (and $x2333 $x59))) - (let (($x2419 (and $x2416 $x64))) - (let (($x2435 (and $x2419 $x68))) - (let (($x2434 (and $x2419 $x67))) - (let (($x2451 (ite $x63 (ite $x67 (and (and $x2416 $x63) $x67) (and (and $x2416 $x63) $x68)) (ite $x67 $x2434 $x2435)))) - (let (($x2405 (ite $x63 (ite $x67 (and (and $x2335 $x63) $x67) (and (and $x2335 $x63) $x68)) (ite $x67 (and $x2373 $x67) $x2389)))) - (let (($x2334 (and $x2332 $x59))) - (let (($x2337 (and $x2334 $x64))) - (let (($x2353 (and $x2337 $x68))) - (let (($x2352 (and $x2337 $x67))) - (let (($x2369 (ite $x63 (ite $x67 (and (and $x2334 $x63) $x67) (and (and $x2334 $x63) $x68)) (ite $x67 $x2352 $x2353)))) - (let (($x2693 (ite $x51 (ite $x55 (ite $x59 $x2369 $x2405) (ite $x59 $x2451 $x2487)) (ite $x55 (ite $x59 $x2545 $x2581) (ite $x59 $x2627 $x2663))))) - (let (($x2281 (ite $x63 (ite $x67 (and (and $x2211 $x63) $x67) (and (and $x2211 $x63) $x68)) (ite $x67 (and $x2249 $x67) $x2265)))) - (let (($x2210 (and $x2127 $x59))) - (let (($x2213 (and $x2210 $x64))) - (let (($x2229 (and $x2213 $x68))) - (let (($x2228 (and $x2213 $x67))) - (let (($x2245 (ite $x63 (ite $x67 (and (and $x2210 $x63) $x67) (and (and $x2210 $x63) $x68)) (ite $x67 $x2228 $x2229)))) - (let (($x2199 (ite $x63 (ite $x67 (and (and $x2129 $x63) $x67) (and (and $x2129 $x63) $x68)) (ite $x67 (and $x2167 $x67) $x2183)))) - (let (($x2128 (and $x2126 $x59))) - (let (($x2131 (and $x2128 $x64))) - (let (($x2147 (and $x2131 $x68))) - (let (($x2146 (and $x2131 $x67))) - (let (($x2163 (ite $x63 (ite $x67 (and (and $x2128 $x63) $x67) (and (and $x2128 $x63) $x68)) (ite $x67 $x2146 $x2147)))) - (let (($x2105 (ite $x63 (ite $x67 (and (and $x2035 $x63) $x67) (and (and $x2035 $x63) $x68)) (ite $x67 (and $x2073 $x67) $x2089)))) - (let (($x2034 (and $x1951 $x59))) - (let (($x2037 (and $x2034 $x64))) - (let (($x2053 (and $x2037 $x68))) - (let (($x2052 (and $x2037 $x67))) - (let (($x2069 (ite $x63 (ite $x67 (and (and $x2034 $x63) $x67) (and (and $x2034 $x63) $x68)) (ite $x67 $x2052 $x2053)))) - (let (($x2023 (ite $x63 (ite $x67 (and (and $x1953 $x63) $x67) (and (and $x1953 $x63) $x68)) (ite $x67 (and $x1991 $x67) $x2007)))) - (let (($x1952 (and $x1950 $x59))) - (let (($x1955 (and $x1952 $x64))) - (let (($x1971 (and $x1955 $x68))) - (let (($x1970 (and $x1955 $x67))) - (let (($x1987 (ite $x63 (ite $x67 (and (and $x1952 $x63) $x67) (and (and $x1952 $x63) $x68)) (ite $x67 $x1970 $x1971)))) - (let (($x2311 (ite $x51 (ite $x55 (ite $x59 $x1987 $x2023) (ite $x59 $x2069 $x2105)) (ite $x55 (ite $x59 $x2163 $x2199) (ite $x59 $x2245 $x2281))))) - (let (($x1915 (ite $x63 (ite $x67 (and (and $x1845 $x63) $x67) (and (and $x1845 $x63) $x68)) (ite $x67 (and $x1883 $x67) $x1899)))) - (let (($x1844 (and $x1761 $x59))) - (let (($x1847 (and $x1844 $x64))) - (let (($x1863 (and $x1847 $x68))) - (let (($x1862 (and $x1847 $x67))) - (let (($x1879 (ite $x63 (ite $x67 (and (and $x1844 $x63) $x67) (and (and $x1844 $x63) $x68)) (ite $x67 $x1862 $x1863)))) - (let (($x1833 (ite $x63 (ite $x67 (and (and $x1763 $x63) $x67) (and (and $x1763 $x63) $x68)) (ite $x67 (and $x1801 $x67) $x1817)))) - (let (($x1762 (and $x1760 $x59))) - (let (($x1765 (and $x1762 $x64))) - (let (($x1781 (and $x1765 $x68))) - (let (($x1780 (and $x1765 $x67))) - (let (($x1797 (ite $x63 (ite $x67 (and (and $x1762 $x63) $x67) (and (and $x1762 $x63) $x68)) (ite $x67 $x1780 $x1781)))) - (let (($x1739 (ite $x63 (ite $x67 (and (and $x1669 $x63) $x67) (and (and $x1669 $x63) $x68)) (ite $x67 (and $x1707 $x67) $x1723)))) - (let (($x1668 (and $x1585 $x59))) - (let (($x1671 (and $x1668 $x64))) - (let (($x1687 (and $x1671 $x68))) - (let (($x1686 (and $x1671 $x67))) - (let (($x1703 (ite $x63 (ite $x67 (and (and $x1668 $x63) $x67) (and (and $x1668 $x63) $x68)) (ite $x67 $x1686 $x1687)))) - (let (($x1657 (ite $x63 (ite $x67 (and (and $x1587 $x63) $x67) (and (and $x1587 $x63) $x68)) (ite $x67 (and $x1625 $x67) $x1641)))) - (let (($x1586 (and $x1584 $x59))) - (let (($x1589 (and $x1586 $x64))) - (let (($x1605 (and $x1589 $x68))) - (let (($x1604 (and $x1589 $x67))) - (let (($x1621 (ite $x63 (ite $x67 (and (and $x1586 $x63) $x67) (and (and $x1586 $x63) $x68)) (ite $x67 $x1604 $x1605)))) - (let (($x1945 (ite $x51 (ite $x55 (ite $x59 $x1621 $x1657) (ite $x59 $x1703 $x1739)) (ite $x55 (ite $x59 $x1797 $x1833) (ite $x59 $x1879 $x1915))))) - (let (($x1515 (ite $x63 (ite $x67 (and (and $x1445 $x63) $x67) (and (and $x1445 $x63) $x68)) (ite $x67 (and $x1483 $x67) $x1499)))) - (let (($x1444 (and $x1361 $x59))) - (let (($x1447 (and $x1444 $x64))) - (let (($x1463 (and $x1447 $x68))) - (let (($x1462 (and $x1447 $x67))) - (let (($x1479 (ite $x63 (ite $x67 (and (and $x1444 $x63) $x67) (and (and $x1444 $x63) $x68)) (ite $x67 $x1462 $x1463)))) - (let (($x1433 (ite $x63 (ite $x67 (and (and $x1363 $x63) $x67) (and (and $x1363 $x63) $x68)) (ite $x67 (and $x1401 $x67) $x1417)))) - (let (($x1362 (and $x1360 $x59))) - (let (($x1365 (and $x1362 $x64))) - (let (($x1381 (and $x1365 $x68))) - (let (($x1380 (and $x1365 $x67))) - (let (($x1397 (ite $x63 (ite $x67 (and (and $x1362 $x63) $x67) (and (and $x1362 $x63) $x68)) (ite $x67 $x1380 $x1381)))) - (let (($x1339 (ite $x63 (ite $x67 (and (and $x1269 $x63) $x67) (and (and $x1269 $x63) $x68)) (ite $x67 (and $x1307 $x67) $x1323)))) - (let (($x1268 (and $x1185 $x59))) - (let (($x1271 (and $x1268 $x64))) - (let (($x1287 (and $x1271 $x68))) - (let (($x1286 (and $x1271 $x67))) - (let (($x1303 (ite $x63 (ite $x67 (and (and $x1268 $x63) $x67) (and (and $x1268 $x63) $x68)) (ite $x67 $x1286 $x1287)))) - (let (($x1257 (ite $x63 (ite $x67 (and (and $x1187 $x63) $x67) (and (and $x1187 $x63) $x68)) (ite $x67 (and $x1225 $x67) $x1241)))) - (let (($x1186 (and $x1184 $x59))) - (let (($x1189 (and $x1186 $x64))) - (let (($x1205 (and $x1189 $x68))) - (let (($x1204 (and $x1189 $x67))) - (let (($x1221 (ite $x63 (ite $x67 (and (and $x1186 $x63) $x67) (and (and $x1186 $x63) $x68)) (ite $x67 $x1204 $x1205)))) - (let (($x1545 (ite $x51 (ite $x55 (ite $x59 $x1221 $x1257) (ite $x59 $x1303 $x1339)) (ite $x55 (ite $x59 $x1397 $x1433) (ite $x59 $x1479 $x1515))))) - (let (($x1149 (ite $x63 (ite $x67 (and (and $x1079 $x63) $x67) (and (and $x1079 $x63) $x68)) (ite $x67 (and $x1117 $x67) $x1133)))) - (let (($x1078 (and $x995 $x59))) - (let (($x1081 (and $x1078 $x64))) - (let (($x1097 (and $x1081 $x68))) - (let (($x1096 (and $x1081 $x67))) - (let (($x1113 (ite $x63 (ite $x67 (and (and $x1078 $x63) $x67) (and (and $x1078 $x63) $x68)) (ite $x67 $x1096 $x1097)))) - (let (($x1067 (ite $x63 (ite $x67 (and (and $x997 $x63) $x67) (and (and $x997 $x63) $x68)) (ite $x67 (and $x1035 $x67) $x1051)))) - (let (($x996 (and $x994 $x59))) - (let (($x999 (and $x996 $x64))) - (let (($x1015 (and $x999 $x68))) - (let (($x1014 (and $x999 $x67))) - (let (($x1031 (ite $x63 (ite $x67 (and (and $x996 $x63) $x67) (and (and $x996 $x63) $x68)) (ite $x67 $x1014 $x1015)))) - (let (($x973 (ite $x63 (ite $x67 (and (and $x903 $x63) $x67) (and (and $x903 $x63) $x68)) (ite $x67 (and $x941 $x67) $x957)))) - (let (($x902 (and $x819 $x59))) - (let (($x905 (and $x902 $x64))) - (let (($x921 (and $x905 $x68))) - (let (($x920 (and $x905 $x67))) - (let (($x937 (ite $x63 (ite $x67 (and (and $x902 $x63) $x67) (and (and $x902 $x63) $x68)) (ite $x67 $x920 $x921)))) - (let (($x891 (ite $x63 (ite $x67 (and (and $x821 $x63) $x67) (and (and $x821 $x63) $x68)) (ite $x67 (and $x859 $x67) $x875)))) - (let (($x820 (and $x818 $x59))) - (let (($x823 (and $x820 $x64))) - (let (($x839 (and $x823 $x68))) - (let (($x838 (and $x823 $x67))) - (let (($x855 (ite $x63 (ite $x67 (and (and $x820 $x63) $x67) (and (and $x820 $x63) $x68)) (ite $x67 $x838 $x839)))) - (let (($x1179 (ite $x51 (ite $x55 (ite $x59 $x855 $x891) (ite $x59 $x937 $x973)) (ite $x55 (ite $x59 $x1031 $x1067) (ite $x59 $x1113 $x1149))))) - (let (($x767 (ite $x63 (ite $x67 (and (and $x697 $x63) $x67) (and (and $x697 $x63) $x68)) (ite $x67 (and $x735 $x67) $x751)))) - (let (($x696 (and $x613 $x59))) - (let (($x699 (and $x696 $x64))) - (let (($x715 (and $x699 $x68))) - (let (($x714 (and $x699 $x67))) - (let (($x731 (ite $x63 (ite $x67 (and (and $x696 $x63) $x67) (and (and $x696 $x63) $x68)) (ite $x67 $x714 $x715)))) - (let (($x685 (ite $x63 (ite $x67 (and (and $x615 $x63) $x67) (and (and $x615 $x63) $x68)) (ite $x67 (and $x653 $x67) $x669)))) - (let (($x614 (and $x612 $x59))) - (let (($x617 (and $x614 $x64))) - (let (($x633 (and $x617 $x68))) - (let (($x632 (and $x617 $x67))) - (let (($x649 (ite $x63 (ite $x67 (and (and $x614 $x63) $x67) (and (and $x614 $x63) $x68)) (ite $x67 $x632 $x633)))) - (let (($x591 (ite $x63 (ite $x67 (and (and $x521 $x63) $x67) (and (and $x521 $x63) $x68)) (ite $x67 (and $x559 $x67) $x575)))) - (let (($x520 (and $x437 $x59))) - (let (($x523 (and $x520 $x64))) - (let (($x539 (and $x523 $x68))) - (let (($x538 (and $x523 $x67))) - (let (($x555 (ite $x63 (ite $x67 (and (and $x520 $x63) $x67) (and (and $x520 $x63) $x68)) (ite $x67 $x538 $x539)))) - (let (($x509 (ite $x63 (ite $x67 (and (and $x439 $x63) $x67) (and (and $x439 $x63) $x68)) (ite $x67 (and $x477 $x67) $x493)))) - (let (($x438 (and $x436 $x59))) - (let (($x441 (and $x438 $x64))) - (let (($x457 (and $x441 $x68))) - (let (($x456 (and $x441 $x67))) - (let (($x473 (ite $x63 (ite $x67 (and (and $x438 $x63) $x67) (and (and $x438 $x63) $x68)) (ite $x67 $x456 $x457)))) - (let (($x797 (ite $x51 (ite $x55 (ite $x59 $x473 $x509) (ite $x59 $x555 $x591)) (ite $x55 (ite $x59 $x649 $x685) (ite $x59 $x731 $x767))))) - (let (($x401 (ite $x63 (ite $x67 (and (and $x331 $x63) $x67) (and (and $x331 $x63) $x68)) (ite $x67 (and $x369 $x67) $x385)))) - (let (($x330 (and $x247 $x59))) - (let (($x333 (and $x330 $x64))) - (let (($x349 (and $x333 $x68))) - (let (($x348 (and $x333 $x67))) - (let (($x365 (ite $x63 (ite $x67 (and (and $x330 $x63) $x67) (and (and $x330 $x63) $x68)) (ite $x67 $x348 $x349)))) - (let (($x319 (ite $x63 (ite $x67 (and (and $x249 $x63) $x67) (and (and $x249 $x63) $x68)) (ite $x67 (and $x287 $x67) $x303)))) - (let (($x248 (and $x246 $x59))) - (let (($x251 (and $x248 $x64))) - (let (($x267 (and $x251 $x68))) - (let (($x266 (and $x251 $x67))) - (let (($x283 (ite $x63 (ite $x67 (and (and $x248 $x63) $x67) (and (and $x248 $x63) $x68)) (ite $x67 $x266 $x267)))) - (let (($x225 (ite $x63 (ite $x67 (and (and $x155 $x63) $x67) (and (and $x155 $x63) $x68)) (ite $x67 (and $x193 $x67) $x209)))) - (let (($x154 (and $x58 $x59))) - (let (($x157 (and $x154 $x64))) - (let (($x173 (and $x157 $x68))) - (let (($x172 (and $x157 $x67))) - (let (($x189 (ite $x63 (ite $x67 (and (and $x154 $x63) $x67) (and (and $x154 $x63) $x68)) (ite $x67 $x172 $x173)))) - (let (($x143 (ite $x63 (ite $x67 (and (and $x62 $x63) $x67) (and (and $x62 $x63) $x68)) (ite $x67 (and $x111 $x67) $x127)))) - (let (($x61 (and $x57 $x59))) - (let (($x66 (and $x61 $x64))) - (let (($x91 (and $x66 $x68))) - (let (($x90 (and $x66 $x67))) - (let (($x107 (ite $x63 (ite $x67 (and (and $x61 $x63) $x67) (and (and $x61 $x63) $x68)) (ite $x67 $x90 $x91)))) - (let (($x431 (ite $x51 (ite $x55 (ite $x59 $x107 $x143) (ite $x59 $x189 $x225)) (ite $x55 (ite $x59 $x283 $x319) (ite $x59 $x365 $x401))))) - (let (($x3107 (ite $x38 (ite $x43 (ite $x47 $x431 $x797) (ite $x47 $x1179 $x1545)) (ite $x43 (ite $x47 $x1945 $x2311) (ite $x47 $x2693 $x3059))))) - (let (($x3111 (= standard_metadata.egress_spec (_ bv511 9)))) - (let (($x3171 (not $x3111))) - (and (and $x3171 $x3107) (= ?x3108 0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let (($x90 (and true (and true (= h1.fr (_ bv255 8)))))) + (let ((?x94 (ite $x90 0 (- 1)))) + (and (and (not (= standard_metadata.egress_spec (_ bv511 9))) true) (= ?x94 0))))) (check-sat) diff --git a/p4_symbolic/symbolic/table.cc b/p4_symbolic/symbolic/table.cc index 847e3e12..c4faeeb1 100644 --- a/p4_symbolic/symbolic/table.cc +++ b/p4_symbolic/symbolic/table.cc @@ -26,12 +26,14 @@ #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "absl/strings/substitute.h" #include "absl/types/optional.h" #include "absl/types/span.h" #include "gutil/status.h" #include "p4/config/v1/p4info.pb.h" #include "p4_pdpi/internal/ordered_map.h" #include "p4_pdpi/ir.pb.h" +#include "p4_symbolic/ir/ir.h" #include "p4_symbolic/symbolic/action.h" #include "p4_symbolic/symbolic/operators.h" #include "p4_symbolic/symbolic/symbolic.h" @@ -464,13 +466,12 @@ absl::StatusOr EvaluateTable( translator, entry_assignment_guard)); } - // This table has been completely evaluated, the result of the evaluation - // is now in "state" and "match_index". - // Time to evaluate the next control construct. - std::string next_control; + const std::string &merge_point = table.table_implementation() + .optimized_symbolic_execution_info() + .merge_point(); - // We only support tables that always have the same next control construct - // regardless of the table's matches. + // We currenlt only support tables that always have the same next control + // construct regardless of the table's matches. // // This can be supported by calling EvaluateControl(...) // inside the above for loop for control found at @@ -480,29 +481,31 @@ absl::StatusOr EvaluateTable( // As an optimization, the loop should not call EvaluateControl // when all actions have the same next_control, and should instead // execute the call once outside the loop as below. - bool first = true; - for (const auto &[_, control] : + for (const auto &[_, next_control] : table.table_implementation().action_to_next_control()) { - if (first) { - next_control = control; - first = false; - } else if (next_control != control) { - return absl::UnimplementedError(absl::StrCat( - "Table \"", table_name, - "\" invokes different control constructs based on matched actions.")); + if (next_control != merge_point) { + return absl::UnimplementedError(absl::Substitute( + "Table '$0' invokes different control constructs based on matched", + table_name)); } } + const std::string continuation = table.table_implementation() + .optimized_symbolic_execution_info() + .continue_to_merge_point() + ? merge_point + : ir::EndOfPipeline(); + // Evaluate the next control. ASSIGN_OR_RETURN(SymbolicTableMatches result, - control::EvaluateControl(data_plane, next_control, state, + control::EvaluateControl(data_plane, continuation, state, translator, guard)); // The trace should not contain information for this table, otherwise, it // means we visited the table twice in the same execution path! if (result.contains(table_name)) { - return absl::InvalidArgumentError(absl::StrCat( - "Table \"", table_name, "\" was executed twice in the same path.")); + return absl::InternalError(absl::Substitute( + "Table '$0' was executed twice in the same path.", table_name)); } // Add this table's match to the trace, and return it. diff --git a/p4_symbolic/symbolic/util.cc b/p4_symbolic/symbolic/util.cc index cc5c1861..740e0816 100644 --- a/p4_symbolic/symbolic/util.cc +++ b/p4_symbolic/symbolic/util.cc @@ -18,7 +18,9 @@ #include +#include "absl/status/status.h" #include "absl/strings/str_format.h" +#include "absl/strings/substitute.h" #include "p4_pdpi/utils/ir.h" #include "p4_symbolic/symbolic/operators.h" #include "p4_symbolic/z3_util.h" @@ -137,12 +139,18 @@ absl::StatusOr MergeMatchesOnCondition( const SymbolicTableMatches &false_matches) { SymbolicTableMatches merged; - // Merge all tables matches in true_trace (including ones in both traces). + // Add all tables matches in true_trace. for (const auto &[name, true_match] : true_matches) { - // Find match in other trace (or use default). - SymbolicTableMatch false_match = false_matches.contains(name) - ? false_matches.at(name) - : DefaultTableMatch(); + // The table should not be applied in the other branch. + if (false_matches.contains(name)) { + return absl::InternalError( + absl::Substitute("Table '$0' was symbolically executed both in true " + "and false branches, this is not expected", + name)); + } + + // Get the default match for the false branch. + const SymbolicTableMatch false_match = DefaultTableMatch(); // Merge this match. ASSIGN_OR_RETURN( @@ -157,10 +165,18 @@ absl::StatusOr MergeMatchesOnCondition( }}); } - // Merge all tables matches in false_matches only. + // Add all tables matches in false_matches. for (const auto &[name, false_match] : false_matches) { - if (true_matches.contains(name)) continue; // Already covered. - SymbolicTableMatch true_match = DefaultTableMatch(); + // The table should not be applied in the other branch. + if (true_matches.contains(name)) { + return absl::InternalError( + absl::Substitute("Table '$0' was symbolically executed both in true " + "and false branches, this is not expected", + name)); + } + + // Get the default match for the true branch. + const SymbolicTableMatch true_match = DefaultTableMatch(); // Merge this match. ASSIGN_OR_RETURN( diff --git a/p4_symbolic/symbolic/util.h b/p4_symbolic/symbolic/util.h index 87a932cb..01eff0ba 100644 --- a/p4_symbolic/symbolic/util.h +++ b/p4_symbolic/symbolic/util.h @@ -50,8 +50,8 @@ absl::StatusOr ExtractFromModel( // Merges two maps of table matches into a single map. A field in the returned // map has the value of `true_matches` if the condition is true, and the -// value of `false_matches` otherwise. Assertion: both maps must contain -// matches for the same set of table names. +// value of `false_matches` otherwise. +// The two maps must contain disjoint keys, otherwise an error is returned. absl::StatusOr MergeMatchesOnCondition( const z3::expr &condition, const SymbolicTableMatches &true_matches, const SymbolicTableMatches &false_matches); From 5f35b54434bb7d5d16c7189b4139585ee0febb4b Mon Sep 17 00:00:00 2001 From: divyagayathri-hcl <159437886+divyagayathri-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:32:48 +0530 Subject: [PATCH 3/9] [Thinkit] Counters tests. (#683) Co-authored-by: kishanps --- tests/gnmi/BUILD.bazel | 33 + tests/gnmi/ethcounter_ixia_test.cc | 1762 ++++++++++++++++++++++++++++ tests/gnmi/ethcounter_ixia_test.h | 26 + 3 files changed, 1821 insertions(+) create mode 100644 tests/gnmi/ethcounter_ixia_test.cc create mode 100644 tests/gnmi/ethcounter_ixia_test.h diff --git a/tests/gnmi/BUILD.bazel b/tests/gnmi/BUILD.bazel index 69af16ef..cfa1d48e 100644 --- a/tests/gnmi/BUILD.bazel +++ b/tests/gnmi/BUILD.bazel @@ -44,3 +44,36 @@ cc_library( ], alwayslink = True, ) + +cc_library( + name = "ethcounter_ixia_test", + testonly = True, + srcs = ["ethcounter_ixia_test.cc"], + hdrs = ["ethcounter_ixia_test.h"], + deps = [ + "//gutil:status", + "//gutil:status_matchers", + "//gutil:testing", + "//lib:ixia_helper", + "//lib/gnmi:gnmi_helper", + "//lib/p4rt:packet_listener", + "//lib/validator:validator_lib", + "//p4_pdpi:ir", + "//p4_pdpi:p4_runtime_session", + "//p4_pdpi:pd", + "//p4_pdpi/packetlib", + "//p4_pdpi/packetlib:packetlib_cc_proto", + "//sai_p4/instantiations/google:sai_p4info_cc", + "//thinkit:generic_testbed", + "//thinkit:generic_testbed_fixture", + "//thinkit:switch", + "//thinkit/proto:generic_testbed_cc_proto", + "@com_github_google_glog//:glog", + "@com_github_nlohmann_json//:nlohmann_json", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + ], + alwayslink = True, +) diff --git a/tests/gnmi/ethcounter_ixia_test.cc b/tests/gnmi/ethcounter_ixia_test.cc new file mode 100644 index 00000000..9efc0e79 --- /dev/null +++ b/tests/gnmi/ethcounter_ixia_test.cc @@ -0,0 +1,1762 @@ +// 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 +// +// 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. +// +// To run this test: +// /google/data/ro/teams/biglab/biglab sandman -p pins -t ${TESTBED}.gcl +// --skip_confirmation --lock_priority 2 then from google3 directory run: +// platforms/networking/pins/testing/integration/system:ethcounter_ixia_test +// (this file) +// +// TODO: Resolve whole save/restore thing wrt speed? +// +#include "tests/gnmi/ethcounter_ixia_test.h" + +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/strings/escaping.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "glog/logging.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gutil/status.h" +#include "gutil/status_matchers.h" +#include "gutil/testing.h" +#include "include/nlohmann/json.hpp" +#include "lib/gnmi/gnmi_helper.h" +#include "lib/ixia_helper.h" +#include "lib/p4rt/packet_listener.h" +#include "lib/validator/validator_lib.h" +#include "p4_pdpi/ir.h" +#include "p4_pdpi/p4_runtime_session.h" +#include "p4_pdpi/packetlib/packetlib.h" +#include "p4_pdpi/packetlib/packetlib.pb.h" +#include "p4_pdpi/pd.h" +#include "sai_p4/instantiations/google/sai_p4info.h" +#include "thinkit/generic_testbed.h" +#include "thinkit/proto/generic_testbed.pb.h" +#include "thinkit/switch.h" + +namespace pins_test { + +using ::nlohmann::json; + +namespace { +constexpr char kOpsDown[] = "\"DOWN\""; // NOLINT +constexpr char kOpsUp[] = "\"UP\""; + +constexpr char kSpeed100GB[] = "\"openconfig-if-ethernet:SPEED_100GB\""; + +constexpr char kLoopbackFalse[] = "false"; // NOLINT +constexpr char kLoopbackTrue[] = "true"; + +constexpr uint32_t kMtu = 1514; +} // namespace + +// TrapToCPU - Set up the switch to punt ingress packets to the CPU +// +// The rules will punt all matching packets to the CPU. +// +absl::Status TrapToCPU(thinkit::Switch &sut) { + auto acl_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + acl_ingress_table_entry { + match { + dst_mac { value: "02:02:02:02:02:02" mask: "ff:ff:ff:ff:ff:ff" } + } + action { trap { qos_queue: "0x2" } } + priority: 1 + } + )pb")); + + LOG(INFO) << "p4_stub"; + ASSIGN_OR_RETURN(std::unique_ptr p4_stub, + sut.CreateP4RuntimeStub()); + + LOG(INFO) << "p4_session"; + ASSIGN_OR_RETURN( + std::unique_ptr p4_session, + pdpi::P4RuntimeSession::Create(std::move(p4_stub), sut.DeviceId())); + + LOG(INFO) << "GetP4Info"; + p4::config::v1::P4Info p4info = + sai::GetP4Info(sai::Instantiation::kMiddleblock); + + LOG(INFO) << "CreateIrP4Info"; + ASSIGN_OR_RETURN(auto ir_p4info, pdpi::CreateIrP4Info(p4info)); + + LOG(INFO) << "SetForwardingPipelineConfig"; + RETURN_IF_ERROR(pdpi::SetMetadataAndSetForwardingPipelineConfig( + p4_session.get(), + p4::v1::SetForwardingPipelineConfigRequest::RECONCILE_AND_COMMIT, + sai::GetP4Info(sai::Instantiation::kMiddleblock))) + << "SetForwardingPipelineConfig: Failed to push P4Info: "; + + LOG(INFO) << "ClearTableEntries"; + RETURN_IF_ERROR(pdpi::ClearTableEntries(p4_session.get())); + // Check that switch is in a clean state. + ASSIGN_OR_RETURN(auto read_back_entries, + pdpi::ReadPiTableEntries(p4_session.get())); + EXPECT_EQ(read_back_entries.size(), 0); + + LOG(INFO) << "for loop"; + std::vector pi_entries; + for (const auto &pd_entry : {acl_entry}) { + LOG(INFO) << "loop"; + ASSIGN_OR_RETURN( + p4::v1::TableEntry pi_entry, + pdpi::PartialPdTableEntryToPiTableEntry(ir_p4info, pd_entry), + _.SetPrepend() << "Failed in PD table conversion to PI, entry: " + << pd_entry.DebugString() << " error: "); + pi_entries.push_back(pi_entry); + } + + LOG(INFO) << "InstallPiTableEntries"; + return (pdpi::InstallPiTableEntries(p4_session.get(), ir_p4info, pi_entries)); +} + +// Set up the switch to forward inbound packets to the egress port +// +// The rules will forward all matching packets matching src to the egress port +// specified. Set is_ipv6 to true to get the IPv6 version. Otherwise it will +// use IPv4. +// +// Note: after seeing occasional problems with forwarding not working +// and following b/190736007 and chats with @kishanps I have added +// a RIF to the ingress port as well as one for the egress port jic. +// +absl::Status ForwardToEgress(uint32_t in_port, uint32_t out_port, bool is_ipv6, + thinkit::Switch &sut) { + constexpr absl::string_view kVrfId = "vrf-80"; + constexpr absl::string_view kRifOutId = "router-interface-1"; + constexpr absl::string_view kRifInId = "router-interface-2"; + constexpr absl::string_view kNhopId = "nexthop-1"; + constexpr absl::string_view kNborIdv4 = "1.1.1.2"; + constexpr absl::string_view kNborIdv6 = "fe80::002:02ff:fe02:0202"; + absl::string_view nborid = kNborIdv4; + + if (is_ipv6) nborid = kNborIdv6; + + auto rif_out_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + router_interface_table_entry { + match { router_interface_id: "$0" } + action { + set_port_and_src_mac { port: "$1" src_mac: "66:55:44:33:22:11" } + } + } + )pb", + kRifOutId, out_port)); + + auto rif_in_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + router_interface_table_entry { + match { router_interface_id: "$0" } + action { + set_port_and_src_mac { port: "$1" src_mac: "88:55:44:33:22:11" } + } + } + )pb", + kRifInId, in_port)); + + auto nbor_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + neighbor_table_entry { + match { router_interface_id: "$0" neighbor_id: "$1" } + action { set_dst_mac { dst_mac: "02:02:02:02:02:02" } } + } + )pb", + kRifOutId, nborid)); + + auto nhop_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + nexthop_table_entry { + match { nexthop_id: "$2" } + action { set_nexthop { router_interface_id: "$0" neighbor_id: "$1" } } + } + )pb", + kRifOutId, nborid, kNhopId)); + + auto ipv4_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + ipv4_table_entry { + match { vrf_id: "$0" } + action { set_nexthop_id { nexthop_id: "$1" } } + } + )pb", + kVrfId, kNhopId)); + + auto ipv6_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + ipv6_table_entry { + match { vrf_id: "$0" } + action { set_nexthop_id { nexthop_id: "$1" } } + } + )pb", + kVrfId, kNhopId)); + + auto acl_entry = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + acl_pre_ingress_table_entry { + match { + src_mac { value: "00:01:02:03:04:05" mask: "ff:ff:ff:ff:ff:ff" } + } + action { set_vrf { vrf_id: "$0" } } + priority: 1 + } + )pb", + kVrfId)); + + LOG(INFO) << "p4_stub"; + ASSIGN_OR_RETURN(std::unique_ptr p4_stub, + sut.CreateP4RuntimeStub()); + + LOG(INFO) << "p4_session"; + ASSIGN_OR_RETURN( + std::unique_ptr p4_session, + pdpi::P4RuntimeSession::Create(std::move(p4_stub), sut.DeviceId())); + + LOG(INFO) << "GetP4Info"; + p4::config::v1::P4Info p4info = + sai::GetP4Info(sai::Instantiation::kMiddleblock); + + LOG(INFO) << "CreateIrP4Info"; + ASSIGN_OR_RETURN(auto ir_p4info, pdpi::CreateIrP4Info(p4info)); + + LOG(INFO) << "SetForwardingPipelineConfig"; + RETURN_IF_ERROR(pdpi::SetMetadataAndSetForwardingPipelineConfig( + p4_session.get(), + p4::v1::SetForwardingPipelineConfigRequest::RECONCILE_AND_COMMIT, + sai::GetP4Info(sai::Instantiation::kMiddleblock))) + << "SetForwardingPipelineConfig: Failed to push P4Info: "; + + LOG(INFO) << "ClearTableEntries"; + RETURN_IF_ERROR(pdpi::ClearTableEntries(p4_session.get())); + // Check that switch is in a clean state. + ASSIGN_OR_RETURN(auto read_back_entries, + pdpi::ReadPiTableEntries(p4_session.get())); + EXPECT_EQ(read_back_entries.size(), 0); + + LOG(INFO) << "for loop"; + std::vector pi_entries; + for (const auto &pd_entry : + {rif_out_entry, rif_in_entry, nbor_entry, nhop_entry, + is_ipv6 ? ipv6_entry : ipv4_entry, acl_entry}) { + LOG(INFO) << "loop"; + ASSIGN_OR_RETURN( + p4::v1::TableEntry pi_entry, + pdpi::PartialPdTableEntryToPiTableEntry(ir_p4info, pd_entry), + _.SetPrepend() << "Failed in PD table conversion to PI, entry: " + << pd_entry.DebugString() << " error: "); + pi_entries.push_back(pi_entry); + } + + LOG(INFO) << "InstallPiTableEntries"; + return (pdpi::InstallPiTableEntries(p4_session.get(), ir_p4info, pi_entries)); +} + +// Tear down any forwarding rules set up +absl::Status ForwardTeardown(thinkit::Switch &sut) { + ASSIGN_OR_RETURN(std::unique_ptr p4_stub, + sut.CreateP4RuntimeStub()); + + ASSIGN_OR_RETURN( + std::unique_ptr p4_session, + pdpi::P4RuntimeSession::Create(std::move(p4_stub), sut.DeviceId())); + + RETURN_IF_ERROR(pdpi::ClearTableEntries(p4_session.get())); + // Check that switch is in a clean state. + ASSIGN_OR_RETURN(auto read_back_entries, + pdpi::ReadPiTableEntries(p4_session.get())); + EXPECT_EQ(read_back_entries.size(), 0); + + return absl::OkStatus(); +} + +absl::StatusOr CheckLinkUp(absl::string_view iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_state_path = + absl::StrCat("interfaces/interface[name=", iface, "]/state/oper-status"); + + ASSIGN_OR_RETURN(std::string ops_response, + GetGnmiStatePathInfo(gnmi_stub, ops_state_path, + "openconfig-interfaces:oper-status")); + + return (ops_response == kOpsUp); +} + +absl::StatusOr CheckLoopback(absl::string_view iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_state_path = absl::StrCat("interfaces/interface[name=", iface, + "]/state/loopback-mode"); + + ASSIGN_OR_RETURN(std::string ops_response, + GetGnmiStatePathInfo(gnmi_stub, ops_state_path, + "openconfig-interfaces:loopback-mode")); + + return (ops_response == kLoopbackTrue); +} + +absl::Status SetLoopback(bool port_loopback, absl::string_view iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_config_path = absl::StrCat( + "interfaces/interface[name=", iface, "]/config/loopback-mode"); + + // Originally I wrote: + // ops_val = + // ConstructGnmiConfigSetString("openconfig-interfaces:loopback-mode", + // port_loopback); but that gets converted to 0 or 1 and that gets rejected as + // a "float". so the API needs an upgrade for bool. + + std::string ops_val; + if (port_loopback) { + ops_val = "{\"openconfig-interfaces:loopback-mode\":true}"; + } else { + ops_val = "{\"openconfig-interfaces:loopback-mode\":false}"; + } + + RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(gnmi_stub, ops_config_path, + GnmiSetType::kUpdate, ops_val)); + + return absl::OkStatus(); +} + +absl::StatusOr CheckPortSpeed( + absl::string_view iface, gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_state_path = absl::StrCat("interfaces/interface[name=", iface, + "]/ethernet/state/port-speed"); + + std::string ops_parse_str = "openconfig-if-ethernet:port-speed"; + return GetGnmiStatePathInfo(gnmi_stub, ops_state_path, ops_parse_str); +} + +absl::Status SetPortSpeed(absl::string_view port_speed, absl::string_view iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_config_path = absl::StrCat( + "interfaces/interface[name=", iface, "]/ethernet/config/port-speed"); + std::string ops_val = + absl::StrCat("{\"openconfig-if-ethernet:port-speed\":", port_speed, "}"); + + RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(gnmi_stub, ops_config_path, + GnmiSetType::kUpdate, ops_val)); + + return absl::OkStatus(); +} + +absl::StatusOr GetGnmiStat(std::string stat_name, + absl::string_view iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + std::string ops_state_path; + std::string ops_parse_str; + + if (absl::StartsWith(stat_name, "ipv4-")) { + std::string name = stat_name.substr(5); + ops_state_path = absl::StrCat( + "interfaces/interface[name=", iface, + "]subinterfaces/subinterface[index=0]/ipv4/state/counters/", name); + ops_parse_str = "openconfig-if-ip:" + name; + } else if (absl::StartsWith(stat_name, "ipv6-")) { + std::string name = stat_name.substr(5); + ops_state_path = absl::StrCat( + "interfaces/interface[name=", iface, + "]subinterfaces/subinterface[index=0]/ipv6/state/counters/", name); + ops_parse_str = "openconfig-if-ip:" + name; + } else { + ops_state_path = absl::StrCat("interfaces/interface[name=", iface, + "]/state/counters/", stat_name); + ops_parse_str = "openconfig-interfaces:" + stat_name; + } + + ASSIGN_OR_RETURN( + std::string ops_response, + GetGnmiStatePathInfo(gnmi_stub, ops_state_path, ops_parse_str)); + + uint64_t stat; + // skip over the initial quote '"' + (void)absl::SimpleAtoi(ops_response.substr(1), &stat); + return stat; +} + +absl::StatusOr ReadCounters(std::string iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + Counters cnt = {}; + + ASSIGN_OR_RETURN(cnt.in_pkts, GetGnmiStat("in-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_pkts, GetGnmiStat("out-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_octets, GetGnmiStat("in-octets", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_octets, GetGnmiStat("out-octets", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_unicast_pkts, + GetGnmiStat("in-unicast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_unicast_pkts, + GetGnmiStat("out-unicast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_multicast_pkts, + GetGnmiStat("in-multicast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_multicast_pkts, + GetGnmiStat("out-multicast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_broadcast_pkts, + GetGnmiStat("in-broadcast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_broadcast_pkts, + GetGnmiStat("out-broadcast-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_errors, GetGnmiStat("in-errors", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_errors, GetGnmiStat("out-errors", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_discards, + GetGnmiStat("in-discards", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_discards, + GetGnmiStat("out-discards", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_fcs_errors, + GetGnmiStat("in-fcs-errors", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_ipv4_pkts, + GetGnmiStat("ipv4-in-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_ipv4_pkts, + GetGnmiStat("ipv4-out-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_ipv6_pkts, + GetGnmiStat("ipv6-in-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_ipv6_pkts, + GetGnmiStat("ipv6-out-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.in_ipv6_discarded_pkts, + GetGnmiStat("ipv6-in-discarded-pkts", iface, gnmi_stub)); + ASSIGN_OR_RETURN(cnt.out_ipv6_discarded_pkts, + GetGnmiStat("ipv6-out-discarded-pkts", iface, gnmi_stub)); + + return cnt; +} + +void ShowCounters(const Counters &cnt) { + LOG(INFO) << "in-pkts " << cnt.in_pkts; + LOG(INFO) << "out-pkts " << cnt.out_pkts; + LOG(INFO) << "in-octets " << cnt.in_octets; + LOG(INFO) << "out-octets " << cnt.out_octets; + LOG(INFO) << "in-unicast-pkts " << cnt.in_unicast_pkts; + LOG(INFO) << "out-unicast-pkts " << cnt.out_unicast_pkts; + LOG(INFO) << "in-multicast-pkts " << cnt.in_multicast_pkts; + LOG(INFO) << "out-multicast-pkts " << cnt.out_multicast_pkts; + LOG(INFO) << "in-broadcast-pkts " << cnt.in_broadcast_pkts; + LOG(INFO) << "out-broadcast-pkts " << cnt.out_broadcast_pkts; + LOG(INFO) << "in-errors " << cnt.in_errors; + LOG(INFO) << "out-errors " << cnt.out_errors; + LOG(INFO) << "in-discards " << cnt.in_discards; + LOG(INFO) << "out-discards " << cnt.out_discards; + LOG(INFO) << "in-fcs-errors " << cnt.in_fcs_errors; + LOG(INFO) << "in-ipv4-pkts " << cnt.in_ipv4_pkts; + LOG(INFO) << "out-ipv4-pkts " << cnt.out_ipv4_pkts; + LOG(INFO) << "in-ipv6-pkts " << cnt.in_ipv6_pkts; + LOG(INFO) << "out-ipv6-pkts " << cnt.out_ipv6_pkts; + LOG(INFO) << "in-ipv6-discarded-pkts " << cnt.in_ipv6_discarded_pkts; + LOG(INFO) << "out-ipv6-discarded-pkts " << cnt.out_ipv6_discarded_pkts; +} + +// DeltaCounters - computer delta as change from initial to final counters +Counters DeltaCounters(const Counters &initial, const Counters &final) { + Counters delta = {}; + + delta.in_pkts = final.in_pkts - initial.in_pkts; + delta.out_pkts = final.out_pkts - initial.out_pkts; + delta.in_octets = final.in_octets - initial.in_octets; + delta.out_octets = final.out_octets - initial.out_octets; + delta.in_unicast_pkts = final.in_unicast_pkts - initial.in_unicast_pkts; + delta.out_unicast_pkts = final.out_unicast_pkts - initial.out_unicast_pkts; + delta.in_multicast_pkts = final.in_multicast_pkts - initial.in_multicast_pkts; + delta.out_multicast_pkts = + final.out_multicast_pkts - initial.out_multicast_pkts; + delta.in_broadcast_pkts = final.in_broadcast_pkts - initial.in_broadcast_pkts; + delta.out_broadcast_pkts = + final.out_broadcast_pkts - initial.out_broadcast_pkts; + delta.in_errors = final.in_errors - initial.in_errors; + delta.out_errors = final.out_errors - initial.out_errors; + delta.in_discards = final.in_discards - initial.in_discards; + delta.out_discards = final.out_discards - initial.out_discards; + delta.in_fcs_errors = final.in_fcs_errors - initial.in_fcs_errors; + delta.in_ipv4_pkts = final.in_ipv4_pkts - initial.in_ipv4_pkts; + delta.out_ipv4_pkts = final.out_ipv4_pkts - initial.out_ipv4_pkts; + delta.in_ipv6_pkts = final.in_ipv6_pkts - initial.in_ipv6_pkts; + delta.out_ipv6_pkts = final.out_ipv6_pkts - initial.out_ipv6_pkts; + delta.in_ipv6_discarded_pkts = + final.in_ipv6_discarded_pkts - initial.in_ipv6_discarded_pkts; + delta.out_ipv6_discarded_pkts = + final.out_ipv6_discarded_pkts - initial.out_ipv6_discarded_pkts; + + return delta; +} + +// NameToP4Id - Map an interface name to the P4 ID for it +// +// Fetch the state for the interface then parse out the P4 ID. The format is: +// \"openconfig-p4rt:id\":8, +// which in this case would be for ID 8. +// +// FYI, the formula for computing the port ID used by P4 is: +// orion_port_id = channel_index * 512 + port_index + 1 +// +absl::StatusOr NameToP4Id(std::string iface, + gnmi::gNMI::StubInterface *gnmi_stub) { + // fetch all the information for the interface from gNMI + std::string state_path = + absl::StrCat("interfaces/interface[name=", iface, "]/state"); + ASSIGN_OR_RETURN(gnmi::GetRequest request, + BuildGnmiGetRequest(state_path, gnmi::GetRequest::STATE)); + gnmi::GetResponse response; + grpc::ClientContext context; + auto status = gnmi_stub->Get(&context, request, &response); + if (!status.ok()) return absl::InternalError("bad status"); + std::string resp_str = response.DebugString(); + std::size_t idix = resp_str.find("openconfig-p4rt:id"); + if (idix == std::string::npos) return absl::InvalidArgumentError("no id"); + std::string id_str = resp_str.substr(idix + 21, 3); + return std::stoul(id_str); +} + +#if 0 +TEST_P(ExampleIxiaTestFixture, TestInFcsErrors) { + LOG(INFO) << "\n\n\n\n\n\n\n\n\n\n---------- Starting TestInFcsErrors " + "----------\n\n\n\n\n"; + + // Pick a testbed with an Ixia Traffic Generator. A SUT is assumed. + thinkit::TestRequirements requirements = + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 1 + interface_mode: TRAFFIC_GENERATOR + })pb"); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr generic_testbed, + GetTestbedWithRequirements(requirements)); + + absl::flat_hash_map interface_info = + generic_testbed->GetSutInterfaceInfo(); + + // Connect to TestTracker for test status + generic_testbed->Environment().SetTestCaseID( + "3da5c6f0-c85e-465f-9221-1e07523092d6"); + + // Hook up to GNMI + ASSERT_OK_AND_ASSIGN( + std::unique_ptr gnmi_stub, + generic_testbed->Sut().CreateGnmiStub()); + + // go through all the ports that interface to the Ixia and set them + // to 100GB since the Ixia ports are all 100GB. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "gwc: Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + } + } + + // Wait to let the links come up + absl::SleepFor(absl::Seconds(20)); + + // Loop through the interface_info looking for Ixia/SUT interface pairs, + // checking if the link is up. we need one pair with link up for the + // ingress interface/IXIA bad fcs traffic generation + std::string ixia_interface = ""; + std::string sut_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + auto sut_link_up = CheckLinkUp(interface, gnmi_stub.get()); + EXPECT_TRUE(sut_link_up.ok()); + if (sut_link_up.ok() && sut_link_up.value()) { + ixia_interface = info.peer_interface_name; + sut_interface = interface; + break; + } + } + } + + ASSERT_FALSE(ixia_interface.empty()); + ASSERT_FALSE(sut_interface.empty()); + LOG(INFO) << "\n\nChose Ixia interface " << ixia_interface + << " and SUT interface " << sut_interface << "\n\n"; + + std::vector v = absl::StrSplit(ixia_interface, '/'); + absl::string_view ixia_ip = v[0]; + absl::string_view ixia_card = v[1]; + absl::string_view ixia_port = v[2]; + ASSERT_FALSE(ixia_ip.empty()); + ASSERT_FALSE(ixia_card.empty()); + ASSERT_FALSE(ixia_port.empty()); + LOG(INFO) << "Ixia IP is " << ixia_ip; + LOG(INFO) << "Ixia card is " << ixia_card; + LOG(INFO) << "Ixia port is " << ixia_port; + LOG(INFO) << "SUT is " << generic_testbed->Sut().ChassisName(); + + // Read some initial counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto initial_counters, + ReadCounters(sut_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nInitial Counters (" << sut_interface << "):\n"; + ShowCounters(initial_counters); + LOG(INFO) << "\n\n"; + + // Connect to the Ixia + ASSERT_OK_AND_ASSIGN(std::string href, + ixia::IxiaConnect(ixia_ip, *generic_testbed)); + LOG(INFO) << "href " << href; + + std::size_t ixpos = href.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string ixref = href.substr(0, ixpos + 10); + LOG(INFO) << "ixref " << ixref; + + // Connect to the Ixia card/port + ASSERT_OK_AND_ASSIGN( + std::string vref, + ixia::IxiaVport(href, ixia_card, ixia_port, *generic_testbed)); + + // Start a session + ASSERT_OK_AND_ASSIGN(std::string tref, + ixia::IxiaSession(vref, *generic_testbed)); + LOG(INFO) << "gwc tref = " << tref; + + // Set the frame rate to 100 fps + ASSERT_OK(ixia::SetFrameRate(tref, 100, *generic_testbed)); + + // Set the frame count to 950 + ASSERT_OK(ixia::SetFrameCount(tref, 950, *generic_testbed)); + + // Set the destination MAC address to LLDP multicast + ASSERT_OK(ixia::SetDestMac(tref, "01:80:c2:00:00:0e", *generic_testbed)); + + // Set the source MAC address + ASSERT_OK(ixia::SetSrcMac(tref, "00:01:02:03:04:05", *generic_testbed)); + + // PATCH to /ixnetwork/traffic/trafficItem/1/configElement/1 + // with {"crc":"badCrc"} + std::string badcrc_path = tref + "/configElement/1"; + std::string badcrc_json = "{\"crc\":\"badCrc\"}"; + LOG(INFO) << "path " << badcrc_path; + LOG(INFO) << "json " << badcrc_json; + ASSERT_OK_AND_ASSIGN( + thinkit::HttpResponse badcrc_response, + generic_testbed->SendRestRequestToIxia(thinkit::RequestType::kPatch, + badcrc_path, badcrc_json)); + EXPECT_EQ(badcrc_response.response_code, 200) << badcrc_response.response; + LOG(INFO) << "gwc: Returns " << badcrc_response.response_code; + + ASSERT_OK(ixia::StartTraffic(tref, ixref, *generic_testbed)); + + // Wait until 10 seconds after the traffic started + absl::Time t1; + t1 = absl::Now(); + + absl::Time t2; + while (1) { + t2 = absl::Now(); + if (t2 >= t1 + absl::Seconds(10)) break; + absl::SleepFor(absl::Milliseconds(100)); + } + + ASSERT_OK(ixia::StopTraffic(tref, *generic_testbed)); + + // Re-read the same counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto final_counters, + ReadCounters(sut_interface, gnmi_stub.get())); + + // Display the final counters + ShowCounters(final_counters); + + // Compute the change for each counter + auto delta = DeltaCounters(initial_counters, final_counters); + + // Display the difference in the counters for now (during test dev) + LOG(INFO) << "\n\nDeltas:"; + ShowCounters(delta); + + // Check the changes are as expected. + // Note that i'm seeing an occasional multicast packet (probably LLDP) + // going out so I'm allowing some minimal change in the output counters + // during the test to account for this. + EXPECT_EQ(delta.in_pkts, 0); + EXPECT_LE(delta.out_pkts, 10); + EXPECT_LE(delta.out_octets, 1000); + EXPECT_EQ(delta.in_unicast_pkts, 0); + EXPECT_EQ(delta.out_unicast_pkts, 0); + EXPECT_EQ(delta.in_multicast_pkts, 0); + EXPECT_LE(delta.out_multicast_pkts, 10); + EXPECT_EQ(delta.in_broadcast_pkts, 0); + EXPECT_EQ(delta.out_broadcast_pkts, 0); + EXPECT_EQ(delta.out_errors, 0); + EXPECT_EQ(delta.in_discards, 0); + EXPECT_EQ(delta.out_discards, 0); + EXPECT_EQ(delta.in_fcs_errors, 950); + EXPECT_EQ(delta.in_errors, delta.in_fcs_errors); + EXPECT_EQ(delta.in_octets, delta.in_fcs_errors * 64); + EXPECT_EQ(delta.in_ipv4_pkts, 0); + EXPECT_EQ(delta.out_ipv4_pkts, 0); + EXPECT_EQ(delta.in_ipv6_pkts, 0); + EXPECT_EQ(delta.out_ipv6_pkts, 0); + EXPECT_EQ(delta.in_ipv6_discarded_pkts, 0); + EXPECT_EQ(delta.out_ipv6_discarded_pkts, 0); + + LOG(INFO) << "\n\n\n\n\n---------- Finished TestInFcsErrors " + "----------\n\n\n\n\n\n\n\n\n\n"; +} +#endif + +#if 1 +TEST_P(ExampleIxiaTestFixture, TestIPv4Pkts) { + LOG(INFO) << "\n\n\n\n\n\n\n\n\n\n---------- Starting TestIPv4Pkts " + "----------\n\n\n\n\n"; + + // Pick a testbed with an Ixia Traffic Generator. A SUT is assumed. + thinkit::TestRequirements requirements = + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 1 + interface_mode: TRAFFIC_GENERATOR + })pb"); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr generic_testbed, + GetTestbedWithRequirements(requirements)); + + absl::flat_hash_map interface_info = + generic_testbed->GetSutInterfaceInfo(); + + // Connect to TestTracker for test status + generic_testbed->Environment().SetTestCaseID( + "2fac23ff-6794-4a31-8fce-a1aa76afe72e"); + + // Hook up to GNMI + ASSERT_OK_AND_ASSIGN(std::unique_ptr gnmi_stub, + generic_testbed->Sut().CreateGnmiStub()); + + // go through all the ports that interface to the Ixia and set them + // to 100GB since the Ixia ports are all 100GB. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + } + } + + // Wait to let the links come up + absl::SleepFor(absl::Seconds(20)); + + // Loop through the interface_info looking for Ixia/SUT interface pairs, + // checking if the link is up. we need one pair with link up for the + // ingress interface/IXIA traffic generation + std::string ixia_interface = ""; + std::string sut_in_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + auto sut_link_up = CheckLinkUp(interface, gnmi_stub.get()); + EXPECT_TRUE(sut_link_up.ok()); + if (sut_link_up.ok() && sut_link_up.value()) { + ixia_interface = info.peer_interface_name; + sut_in_interface = interface; + break; + } + } + } + + // Now loop through again and pick an egress interface. This one doesn't + // have to be up, just a different interface. + std::string sut_out_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + if (interface != sut_in_interface) { + sut_out_interface = interface; + break; + } + } + } + + ASSERT_FALSE(ixia_interface.empty()); + ASSERT_FALSE(sut_in_interface.empty()); + ASSERT_FALSE(sut_out_interface.empty()); + + // Look up the port numbers for the ingress and egress interfaces + ASSERT_OK_AND_ASSIGN(uint32_t in_id, + NameToP4Id(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(uint32_t out_id, + NameToP4Id(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestIPv4Pkts:\n" + << "Chose Ixia interface " << ixia_interface << "\n" + << "and SUT ingress interface " << sut_in_interface << " (id " + << in_id << ")\n" + << "and SUT egress interface " << sut_out_interface << " (id " + << out_id << ")\n\n"; + + std::vector v = absl::StrSplit(ixia_interface, '/'); + absl::string_view ixia_ip = v[0]; + absl::string_view ixia_in_card = v[1]; + absl::string_view ixia_in_port = v[2]; + ASSERT_FALSE(ixia_ip.empty()); + ASSERT_FALSE(ixia_in_card.empty()); + ASSERT_FALSE(ixia_in_port.empty()); + LOG(INFO) << "Ixia IP is " << ixia_ip; + LOG(INFO) << "Ixia ingress card is " << ixia_in_card; + LOG(INFO) << "Ixia ingress port is " << ixia_in_port; + LOG(INFO) << "SUT is " << generic_testbed->Sut().ChassisName(); + + // Fetch the initial conditions for the egress interface. + // Note: Not currently fetching the FEC mode since the gNMI get on that + // fails even if I populate redis first. See b/197778604. As a result + // the link will not come up at the end of the test after I switch it + // back to 100GB. TBD. + ASSERT_OK_AND_ASSIGN(auto out_initial_loopback, + CheckLoopback(sut_out_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto out_initial_speed, + CheckPortSpeed(sut_out_interface, gnmi_stub.get())); + + // Output the initial conditions + LOG(INFO) << "sut out_initial_speed is " << out_initial_speed; + LOG(INFO) << "sut out_initial_loopback is " << out_initial_loopback; + LOG(INFO) << "\n\n"; + + // Set the egress port to loopback mode + EXPECT_OK(SetLoopback(true, sut_out_interface, gnmi_stub.get())); + + // Set up the switch to forward inbound IPv4 packets to the egress port + LOG(INFO) << "\n\n----- TestIPv4Pkts: ForwardToEgress -----\n"; + EXPECT_OK(ForwardToEgress(in_id, out_id, false, generic_testbed->Sut())); + LOG(INFO) << "\n\n----- ForwardToEgress Done -----\n"; + + // Read some initial counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto initial_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto initial_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestIPv4Pkts:\n\n" + << "\n\nInitial Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(initial_in_counters); + LOG(INFO) << "\n\nInitial Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(initial_out_counters); + LOG(INFO) << "\n\n"; + + // Connect to the Ixia + LOG(INFO) << "\n\nTestIPv4Pkts: IxiaConnect\n\n"; + ASSERT_OK_AND_ASSIGN(std::string href, + ixia::IxiaConnect(ixia_ip, *generic_testbed)); + + std::size_t ixpos = href.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string ixref = href.substr(0, ixpos + 10); + LOG(INFO) << "ixref " << ixref; + + // Connect to the Ixia card/port + ASSERT_OK_AND_ASSIGN( + std::string vref, + ixia::IxiaVport(href, ixia_in_card, ixia_in_port, *generic_testbed)); + + // Start a session + ASSERT_OK_AND_ASSIGN(std::string full_tref, + ixia::IxiaSession(vref, *generic_testbed)); + + LOG(INFO) << "full_tref = " << full_tref; + ixpos = full_tref.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string tref = full_tref.substr(ixpos); + LOG(INFO) << "tref " << tref; + + // Set the line rate to 100 percent + ASSERT_OK(ixia::SetLineRate(tref, 100, *generic_testbed)); + + // Set the frame count to 90M + ASSERT_OK(ixia::SetFrameCount(tref, 90000000, *generic_testbed)); + + // Set the destination MAC address + ASSERT_OK(ixia::SetDestMac(tref, "02:02:02:02:02:02", *generic_testbed)); + + // Set the source MAC address + ASSERT_OK(ixia::SetSrcMac(tref, "00:01:02:03:04:05", *generic_testbed)); + + // Append an IPv4 header + ASSERT_OK(ixia::AppendIPv4(full_tref, *generic_testbed)); + + // Set up the source and destination IP addresses + ASSERT_OK(ixia::SetSrcIPv4(tref, "192.168.0.1", *generic_testbed)); + ASSERT_OK(ixia::SetDestIPv4(tref, "192.168.0.2", *generic_testbed)); + + // Set the frame size to 1514 bytes + ASSERT_OK(ixia::SetFrameSize(tref, kMtu, *generic_testbed)); + + // LOG(INFO) << "\n\n*** 2 minutes till START ***\n\n"; + // absl::SleepFor(absl::Seconds(120)); + ASSERT_OK(ixia::StartTraffic(full_tref, ixref, *generic_testbed)); + + // Wait until 10 seconds after the traffic started + absl::Time t1; + t1 = absl::Now(); + + absl::Time t2; + while (1) { + t2 = absl::Now(); + if (t2 >= t1 + absl::Seconds(10)) break; + absl::SleepFor(absl::Milliseconds(100)); + } + + LOG(INFO) << "Time at stop is " << t2; + LOG(INFO) << "Delta is " << t2 - t1; + + ASSERT_OK(ixia::StopTraffic(full_tref, *generic_testbed)); + + // Re-read the same counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto final_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto final_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + // Check the time again + absl::Time t3 = absl::Now(); + LOG(INFO) << "Time after statistics read is " << t3; + LOG(INFO) << "Delta is " << t3 - t1; + uint64_t seconds = ((t3 - t1) / absl::Seconds(1)) + 1; + + // Display the final counters + LOG(INFO) << "\n\nTestIPv4Pkts:\n\n" + << "\n\nFinal Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(final_in_counters); + LOG(INFO) << "\n\nFinal Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(final_out_counters); + LOG(INFO) << "\n\n"; + + // Compute the change for each counter + auto delta_in = DeltaCounters(initial_in_counters, final_in_counters); + auto delta_out = DeltaCounters(initial_out_counters, final_out_counters); + + // Display the difference in the counters for now (during test dev) + LOG(INFO) << "\n\nTestIPv4Pkts:\n\n" + << "\n\nIngress Deltas (" << sut_in_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_in); + LOG(INFO) << "\n\nEgress Deltas (" << sut_out_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_out); + + // Check the changes are as expected. Test should run about 10sec, maybe + // a little more (time to stop). Ixia is sending 100GB line rate unicast + // IPv4 traffic. ACL/Route is forwarding all of it to the egress but it + // is running at 40GB so only about 40% can fit. + // note that i'm seeing an occasional multicast packet (probably LLDP) + // going out so I'm allowing some minimal change in some counters + // during the test to account for this. + EXPECT_GE(delta_out.out_pkts, 90000000); + EXPECT_LE(delta_out.out_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_out.out_octets, delta_out.out_pkts * kMtu - 10000); + EXPECT_LE(delta_out.out_octets, delta_out.out_pkts * kMtu + 10000); + EXPECT_LE(delta_out.out_unicast_pkts, delta_out.out_pkts + 10); + EXPECT_LE(delta_out.out_multicast_pkts, 5); + EXPECT_EQ(delta_out.out_broadcast_pkts, 0); + EXPECT_EQ(delta_out.out_errors, 0); + EXPECT_EQ(delta_out.out_discards, 0); + EXPECT_GE(delta_out.out_ipv4_pkts, delta_out.out_pkts - 10); + EXPECT_LE(delta_out.out_ipv4_pkts, delta_out.out_pkts + 10); + EXPECT_EQ(delta_out.out_ipv6_pkts, 0); + EXPECT_EQ(delta_out.out_ipv6_discarded_pkts, 0); + EXPECT_LE(delta_in.in_ipv4_pkts, delta_out.out_pkts + 10); + EXPECT_LE(delta_in.in_ipv4_pkts, delta_out.out_pkts - 10); + + LOG(INFO) << "\n\n\n\n\n---------- Restore ----------\n\n\n\n\n"; + + // go through all the ports that interface to the Ixia and set them + // back to 100GB whether their link is up or not. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + EXPECT_OK(SetLoopback(false, interface, gnmi_stub.get())); + } + } + + // Tear down any forwarding rules set up + EXPECT_OK(ForwardTeardown(generic_testbed->Sut())); + + LOG(INFO) << "\n\n\n\n\n---------- Finished TestIPv4Pkts " + "----------\n\n\n\n\n\n\n\n\n\n"; +} +#endif + +#if 0 +TEST_P(ExampleIxiaTestFixture, TestOutDiscards) { + LOG(INFO) << "\n\n\n\n\n\n\n\n\n\n---------- Starting TestOutDiscards " + "----------\n\n\n\n\n"; + + // Pick a testbed with an Ixia Traffic Generator. A SUT is assumed. + thinkit::TestRequirements requirements = + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 1 + interface_mode: TRAFFIC_GENERATOR + })pb"); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr generic_testbed, + GetTestbedWithRequirements(requirements)); + + absl::flat_hash_map interface_info = + generic_testbed->GetSutInterfaceInfo(); + + // Connect to TestTracker for test status + generic_testbed->Environment().SetTestCaseID( + "0539b74c-656f-4a0c-aa8f-39d7721520ad"); + + // Hook up to GNMI + ASSERT_OK_AND_ASSIGN(auto gnmi_stub, generic_testbed->Sut().CreateGnmiStub()); + + // go through all the ports that interface to the Ixia and set them + // to 100GB since the Ixia ports are all 100GB. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + } + } + + // Wait to let the links come up + absl::SleepFor(absl::Seconds(20)); + + // Loop through the interface_info looking for Ixia/SUT interface pairs, + // checking if the link is up. we need one pair with link up for the + // ingress interface/IXIA traffic generation + std::string ixia_interface = ""; + std::string sut_in_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + auto sut_link_up = CheckLinkUp(interface, gnmi_stub.get()); + EXPECT_TRUE(sut_link_up.ok()); + if (sut_link_up.ok() && sut_link_up.value()) { + ixia_interface = info.peer_interface_name; + sut_in_interface = interface; + break; + } + } + } + + // Now loop through again and pick an egress interface. This one doesn't + // have to be up, just a different interface. + std::string sut_out_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + if (interface != sut_in_interface) { + sut_out_interface = interface; + break; + } + } + } + + ASSERT_FALSE(ixia_interface.empty()); + ASSERT_FALSE(sut_in_interface.empty()); + ASSERT_FALSE(sut_out_interface.empty()); + + // Look up the port number for the egress interface + ASSERT_OK_AND_ASSIGN(uint32_t in_id, + NameToP4Id(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(uint32_t out_id, + NameToP4Id(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestOutDiscards:\n" + << "\n\nChose Ixia interface " << ixia_interface << "\n" + << "and SUT ingress interface " << sut_in_interface << " (id " + << in_id << ")\n" + << "and SUT egress interface " << sut_out_interface << " (id " + << out_id << ")\n\n"; + + std::vector v = absl::StrSplit(ixia_interface, '/'); + absl::string_view ixia_ip = v[0]; + absl::string_view ixia_in_card = v[1]; + absl::string_view ixia_in_port = v[2]; + ASSERT_FALSE(ixia_ip.empty()); + ASSERT_FALSE(ixia_in_card.empty()); + ASSERT_FALSE(ixia_in_port.empty()); + LOG(INFO) << "Ixia IP is " << ixia_ip; + LOG(INFO) << "Ixia ingress card is " << ixia_in_card; + LOG(INFO) << "Ixia ingress port is " << ixia_in_port; + LOG(INFO) << "SUT is " << generic_testbed->Sut().ChassisName(); + + // Fetch the initial conditions for the egress interface. + // Note: Not currently fetching the FEC mode since the gNMI get on that + // fails even if I populate redis first. See b/197778604. As a result + // the link will not come up at the end of the test after I switch it + // back to 100GB. TBD. + ASSERT_OK_AND_ASSIGN(auto out_initial_loopback, + CheckLoopback(sut_out_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto out_initial_speed, + CheckPortSpeed(sut_out_interface, gnmi_stub.get())); + + // Output the initial conditions + LOG(INFO) << "sut out_initial_speed is " << out_initial_speed; + LOG(INFO) << "sut out_initial_loopback is " << out_initial_loopback; + LOG(INFO) << "\n\n"; + + // Set the egress port to loopback mode + EXPECT_OK(SetLoopback(true, sut_out_interface, gnmi_stub.get())); + + // Set the egress port speed to 40GB + EXPECT_OK(SetPortSpeed(kSpeed40GB, sut_out_interface, gnmi_stub.get())); + absl::SleepFor(absl::Seconds(15)); + + auto out_status_speed = CheckPortSpeed(sut_out_interface, gnmi_stub.get()); + EXPECT_THAT(out_status_speed, IsOkAndHolds(kSpeed40GB)); + + // Set up the switch to forward inbound packets to the egress port + LOG(INFO) << "\n\n----- ForwardToEgress: TestOutDiscards -----\n"; + EXPECT_OK(ForwardToEgress(in_id, out_id, false, generic_testbed->Sut())); + LOG(INFO) << "\n\n----- ForwardToEgress Done -----\n"; + + // Read some initial counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto initial_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto initial_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestOutDiscards:\n\n" + << "\n\nInitial Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(initial_in_counters); + LOG(INFO) << "\n\nInitial Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(initial_out_counters); + LOG(INFO) << "\n\n"; + + // Connect to the Ixia + ASSERT_OK_AND_ASSIGN(std::string href, + ixia::IxiaConnect(ixia_ip, *generic_testbed)); + + std::size_t ixpos = href.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string ixref = href.substr(0, ixpos + 10); + LOG(INFO) << "ixref " << ixref; + + // Connect to the Ixia card/port + LOG(INFO) << "\n\nTestOutDiscards: IxiaConnect\n\n"; + ASSERT_OK_AND_ASSIGN( + std::string vref, + ixia::IxiaVport(href, ixia_in_card, ixia_in_port, *generic_testbed)); + + // Start a session + ASSERT_OK_AND_ASSIGN(std::string full_tref, + ixia::IxiaSession(vref, *generic_testbed)); + + LOG(INFO) << "full_tref = " << full_tref; + ixpos = full_tref.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string tref = full_tref.substr(ixpos); + LOG(INFO) << "tref " << tref; + + // Set the line rate to 100 percent + ASSERT_OK(ixia::SetLineRate(tref, 100, *generic_testbed)); + + // Set the frame count to 90M + ASSERT_OK(ixia::SetFrameCount(tref, 90000000, *generic_testbed)); + + // Set the source and destination MAC addresses + ASSERT_OK(ixia::SetSrcMac(tref, "00:01:02:03:04:05", *generic_testbed)); + ASSERT_OK(ixia::SetDestMac(tref, "02:02:02:02:02:02", *generic_testbed)); + + // Append an IPv4 header + ASSERT_OK(ixia::AppendIPv4(full_tref, *generic_testbed)); + + // Set up the source and destination IP addresses + ASSERT_OK(ixia::SetSrcIPv4(tref, "192.168.0.1", *generic_testbed)); + ASSERT_OK(ixia::SetDestIPv4(tref, "192.168.0.2", *generic_testbed)); + + // Set the frame size to 1514 bytes + ASSERT_OK(ixia::SetFrameSize(tref, kMtu, *generic_testbed)); + + // Start Traffic + ASSERT_OK(ixia::StartTraffic(full_tref, ixref, *generic_testbed)); + + // Wait until 10 seconds after the traffic started + absl::Time t1; + t1 = absl::Now(); + + absl::Time t2; + while (1) { + t2 = absl::Now(); + if (t2 >= t1 + absl::Seconds(10)) break; + absl::SleepFor(absl::Milliseconds(100)); + } + + LOG(INFO) << "Time at stop is " << t2; + LOG(INFO) << "Delta is " << t2 - t1; + + ASSERT_OK(ixia::StopTraffic(full_tref, *generic_testbed)); + + // Re-read the same counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto final_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto final_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + // Check the time again + absl::Time t3 = absl::Now(); + LOG(INFO) << "Time after statistics read is " << t3; + LOG(INFO) << "Delta is " << t3 - t1; + uint64_t seconds = ((t3 - t1) / absl::Seconds(1)) + 1; + + // Display the final counters + LOG(INFO) << "\n\nTestOutDiscards:\n\n" + << "\n\nFinal Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(final_in_counters); + LOG(INFO) << "\n\nFinal Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(final_out_counters); + LOG(INFO) << "\n\n"; + + // Compute the change for each counter + auto delta_in = DeltaCounters(initial_in_counters, final_in_counters); + auto delta_out = DeltaCounters(initial_out_counters, final_out_counters); + + // Display the difference in the counters for now (during test dev) + LOG(INFO) << "\n\nTestOutDiscards:\n\n" + << "\n\nIngress Deltas (" << sut_in_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_in); + LOG(INFO) << "\n\nEgress Deltas (" << sut_out_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_out); + + // Check the changes are as expected. Test should run about 10sec, maybe + // a little more (time to stop). Ixia is sending 100GB line rate unicast + // IPv4 traffic. ACL/Route is forwarding all of it to the egress but it + // is running at 40GB so only about 40% can fit. + // note that i'm seeing an occasional multicast packet (probably LLDP) + // going out so I'm allowing some minimal change in some counters + // during the test to account for this. + uint64_t expect = 90000000; + EXPECT_GT(delta_out.out_pkts, ((expect * 35) / 100)); + EXPECT_LT(delta_out.out_pkts, ((expect * 45) / 100)); + EXPECT_LE(delta_out.out_octets, delta_out.out_pkts * kMtu + 10000); + EXPECT_GE(delta_out.out_octets, delta_out.out_pkts * kMtu - 10000); + EXPECT_LE(delta_out.out_unicast_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_out.out_unicast_pkts, delta_out.out_pkts - 10); + EXPECT_LE(delta_out.out_multicast_pkts, 5); + EXPECT_EQ(delta_out.out_broadcast_pkts, 0); + EXPECT_EQ(delta_out.out_errors, 0); + EXPECT_GE(delta_out.out_discards, ((55 * expect) / 100)); + EXPECT_LE(delta_out.out_discards, ((65 * expect) / 100)); + EXPECT_LE(delta_out.out_ipv4_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_out.out_ipv4_pkts, delta_out.out_pkts - 10); + EXPECT_EQ(delta_out.out_ipv6_pkts, 0); + EXPECT_EQ(delta_out.out_ipv6_discarded_pkts, 0); + + LOG(INFO) << "\n\n\n\n\n---------- Restore ----------\n\n\n\n\n"; + + // go through all the ports that interface to the Ixia and set them + // back to 100GB whether their link is up or not. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + EXPECT_OK(SetLoopback(false, interface, gnmi_stub.get())); + } + } + + // Tear down any forwarding rules set up + EXPECT_OK(ForwardTeardown(generic_testbed->Sut())); + + LOG(INFO) << "\n\n\n\n\n---------- Finished TestOutDiscards " + "----------\n\n\n\n\n\n\n\n\n\n"; +} +#endif + +#if 0 +TEST_P(ExampleIxiaTestFixture, TestIPv6Pkts) { + LOG(INFO) << "\n\n\n\n\n\n\n\n\n\n---------- Starting TestIPv6Pkts " + "----------\n\n\n\n\n"; + + // Pick a testbed with an Ixia Traffic Generator. A SUT is assumed. + thinkit::TestRequirements requirements = + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 1 + interface_mode: TRAFFIC_GENERATOR + })pb"); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr generic_testbed, + GetTestbedWithRequirements(requirements)); + + absl::flat_hash_map interface_info = + generic_testbed->GetSutInterfaceInfo(); + + // Connect to TestTracker for test status + generic_testbed->Environment().SetTestCaseID( + "3f3859b8-7602-479c-a2ad-ab964ded694b"); + + // Hook up to GNMI + ASSERT_OK_AND_ASSIGN(auto gnmi_stub, generic_testbed->Sut().CreateGnmiStub()); + + // go through all the ports that interface to the Ixia and set them + // to 100GB since the Ixia ports are all 100GB. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + } + } + + // Wait to let the links come up + absl::SleepFor(absl::Seconds(20)); + + // Loop through the interface_info looking for Ixia/SUT interface pairs, + // checking if the link is up. we need one pair with link up for the + // ingress interface/IXIA traffic generation + std::string ixia_interface = ""; + std::string sut_in_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + auto sut_link_up = CheckLinkUp(interface, gnmi_stub.get()); + EXPECT_TRUE(sut_link_up.ok()); + if (sut_link_up.ok() && sut_link_up.value()) { + ixia_interface = info.peer_interface_name; + sut_in_interface = interface; + break; + } + } + } + + // Now loop through again and pick an egress interface. This one doesn't + // have to be up, just a different interface. + std::string sut_out_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + if (interface != sut_in_interface) { + sut_out_interface = interface; + break; + } + } + } + + ASSERT_FALSE(ixia_interface.empty()); + ASSERT_FALSE(sut_in_interface.empty()); + ASSERT_FALSE(sut_out_interface.empty()); + + // Look up the port number for the egress interface + ASSERT_OK_AND_ASSIGN(uint32_t in_id, + NameToP4Id(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(uint32_t out_id, + NameToP4Id(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestIPv6Pkts:\n\n" + << "\n\nChose Ixia interface " << ixia_interface << "\n" + << "and SUT ingress interface " << sut_in_interface << " (id " + << in_id << ")\n" + << "and SUT egress interface " << sut_out_interface << " (id " + << out_id << ")\n\n"; + + std::vector v = absl::StrSplit(ixia_interface, '/'); + absl::string_view ixia_ip = v[0]; + absl::string_view ixia_in_card = v[1]; + absl::string_view ixia_in_port = v[2]; + ASSERT_FALSE(ixia_ip.empty()); + ASSERT_FALSE(ixia_in_card.empty()); + ASSERT_FALSE(ixia_in_port.empty()); + LOG(INFO) << "Ixia IP is " << ixia_ip; + LOG(INFO) << "Ixia ingress card is " << ixia_in_card; + LOG(INFO) << "Ixia ingress port is " << ixia_in_port; + LOG(INFO) << "SUT is " << generic_testbed->Sut().ChassisName(); + + // Fetch the initial conditions for the egress interface. + // Note: Not currently fetching the FEC mode since the gNMI get on that + // fails even if I populate redis first. See b/197778604. As a result + // the link will not come up at the end of the test after I switch it + // back to 100GB. TBD. + ASSERT_OK_AND_ASSIGN(auto out_initial_loopback, + CheckLoopback(sut_out_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto out_initial_speed, + CheckPortSpeed(sut_out_interface, gnmi_stub.get())); + + // Output the initial conditions + LOG(INFO) << "sut out_initial_speed is " << out_initial_speed; + LOG(INFO) << "sut out_initial_loopback is " << out_initial_loopback; + LOG(INFO) << "\n\n"; + + // Set the egress port to loopback mode + EXPECT_OK(SetLoopback(true, sut_out_interface, gnmi_stub.get())); + + // Set up the switch to forward inbound packets to the egress port + EXPECT_OK(ForwardToEgress(in_id, out_id, true, generic_testbed->Sut())); + + // Read some initial counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto initial_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto initial_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nInitial Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(initial_in_counters); + LOG(INFO) << "\n\nInitial Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(initial_out_counters); + LOG(INFO) << "\n\n"; + + // Connect to the Ixia + ASSERT_OK_AND_ASSIGN(std::string href, + ixia::IxiaConnect(ixia_ip, *generic_testbed)); + + std::size_t ixpos = href.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string ixref = href.substr(0, ixpos + 10); + LOG(INFO) << "ixref " << ixref; + + // Connect to the Ixia card/port + ASSERT_OK_AND_ASSIGN( + std::string vref, + ixia::IxiaVport(href, ixia_in_card, ixia_in_port, *generic_testbed)); + + // Start a session + ASSERT_OK_AND_ASSIGN(std::string full_tref, + ixia::IxiaSession(vref, *generic_testbed)); + + LOG(INFO) << "full_tref = " << full_tref; + ixpos = full_tref.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string tref = full_tref.substr(ixpos); + LOG(INFO) << "tref " << tref; + + // Set the line rate to 100 percent + ASSERT_OK(ixia::SetLineRate(tref, 100, *generic_testbed)); + + // Set the frame count to 90M + ASSERT_OK(ixia::SetFrameCount(tref, 90000000, *generic_testbed)); + + // Set the source and destination MAC addresses + ASSERT_OK(ixia::SetSrcMac(tref, "00:01:02:03:04:05", *generic_testbed)); + ASSERT_OK(ixia::SetDestMac(tref, "02:02:02:02:02:02", *generic_testbed)); + + // Add an IPv6 header + ASSERT_OK(ixia::AppendIPv6(tref, *generic_testbed)); + + // Set the source and destination IPv6 addresses + ASSERT_OK( + ixia::SetSrcIPv6(tref, "fe80::201:02ff:fe03:0405", *generic_testbed)); + ASSERT_OK( + ixia::SetDestIPv6(tref, "fe80::002:02ff:fe02:0202", *generic_testbed)); + + // Set the frame size to 1514 bytes + ASSERT_OK(ixia::SetFrameSize(tref, kMtu, *generic_testbed)); + + // LOG(INFO) << "\n\n\n\n\nAbout to sleep"; + // absl::SleepFor(absl::Seconds(15)); + ASSERT_OK(ixia::StartTraffic(full_tref, ixref, *generic_testbed)); + + // Wait until 10 seconds after the traffic started + absl::Time t1; + t1 = absl::Now(); + + absl::Time t2; + while (1) { + t2 = absl::Now(); + if (t2 >= t1 + absl::Seconds(10)) break; + absl::SleepFor(absl::Milliseconds(100)); + } + + LOG(INFO) << "Time at stop is " << t2; + LOG(INFO) << "Delta is " << t2 - t1; + + ASSERT_OK(ixia::StopTraffic(full_tref, *generic_testbed)); + + // Re-read the same counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto final_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto final_out_counters, + ReadCounters(sut_out_interface, gnmi_stub.get())); + + // Check the time again + absl::Time t3 = absl::Now(); + LOG(INFO) << "Time after statistics read is " << t3; + LOG(INFO) << "Delta is " << t3 - t1; + uint64_t seconds = ((t3 - t1) / absl::Seconds(1)) + 1; + + // Display the final counters + LOG(INFO) << "\n\nTestIPv6Pkts:\n\n" + << "\n\nFinal Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(final_in_counters); + LOG(INFO) << "\n\nFinal Egress Counters (" << sut_out_interface << "):\n"; + ShowCounters(final_out_counters); + LOG(INFO) << "\n\n"; + + // Compute the change for each counter + auto delta_in = DeltaCounters(initial_in_counters, final_in_counters); + auto delta_out = DeltaCounters(initial_out_counters, final_out_counters); + + // Display the difference in the counters for now (during test dev) + LOG(INFO) << "\n\nTestIPv6Pkts:\n\n" + << "\n\nIngress Deltas (" << sut_in_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_in); + LOG(INFO) << "\n\nEgress Deltas (" << sut_out_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_out); + + // Check the changes are as expected. Test should run about 10sec, maybe + // a little more (time to stop). Ixia is sending 100GB line rate unicast + // IPv6 traffic, stopping at 90,000,000 packets at 1514 bytes. ACL/Route + // is forwarding all of it to the egress. + // note that i'm seeing an occasional multicast packet (probably LLDP) + // going out so I'm allowing some minimal change in some counters + // during the test to account for this. + EXPECT_GE(delta_out.out_pkts, 90000000); + EXPECT_LE(delta_out.out_pkts, 90000000 + 10); + EXPECT_LE(delta_out.out_octets, delta_out.out_pkts * kMtu + 10000); + EXPECT_GE(delta_out.out_octets, delta_out.out_pkts * kMtu - 10000); + EXPECT_LE(delta_out.out_unicast_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_out.out_unicast_pkts, delta_out.out_pkts - 10); + EXPECT_LE(delta_out.out_multicast_pkts, 5); + EXPECT_EQ(delta_out.out_broadcast_pkts, 0); + EXPECT_EQ(delta_out.out_errors, 0); + EXPECT_EQ(delta_out.out_discards, 0); + EXPECT_EQ(delta_out.out_ipv4_pkts, 0); + EXPECT_GE(delta_out.in_ipv6_pkts, delta_out.out_pkts - 10); + EXPECT_LE(delta_out.in_ipv6_pkts, delta_out.out_pkts + 10); + EXPECT_LE(delta_out.out_ipv6_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_out.out_ipv6_pkts, delta_out.out_pkts - 10); + EXPECT_EQ(delta_out.out_ipv6_discarded_pkts, 0); + EXPECT_LE(delta_in.in_ipv6_pkts, delta_out.out_pkts + 10); + EXPECT_GE(delta_in.in_ipv6_pkts, delta_out.out_pkts - 10); + + LOG(INFO) << "\n\n\n\n\n---------- Restore ----------\n\n\n\n\n"; + + // go through all the ports that interface to the Ixia and set them + // back to 100GB whether their link is up or not. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + EXPECT_OK(SetLoopback(false, interface, gnmi_stub.get())); + } + } + + // Tear down any forwarding rules set up + EXPECT_OK(ForwardTeardown(generic_testbed->Sut())); + + LOG(INFO) << "\n\n\n\n\n---------- Finished TestIPv6Pkts " + "----------\n\n\n\n\n\n\n\n\n\n"; +} +#endif + +#if 0 +TEST_P(ExampleIxiaTestFixture, TestCPUOutDiscards) { + LOG(INFO) << "\n\n\n\n\n\n\n\n\n\n---------- Starting TestCPUOutDiscards " + "----------\n\n\n\n\n"; + + // Pick a testbed with an Ixia Traffic Generator. A SUT is assumed. + thinkit::TestRequirements requirements = + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 1 + interface_mode: TRAFFIC_GENERATOR + })pb"); + + ASSERT_OK_AND_ASSIGN(std::unique_ptr generic_testbed, + GetTestbedWithRequirements(requirements)); + + absl::flat_hash_map interface_info = + generic_testbed->GetSutInterfaceInfo(); + + // Connect to TestTracker for test status + generic_testbed->Environment().SetTestCaseID( + "3c8823ab-1aba-48a5-8af6-90d2f268c699"); + + // Hook up to GNMI + ASSERT_OK_AND_ASSIGN(auto gnmi_stub, generic_testbed->Sut().CreateGnmiStub()); + + // go through all the ports that interface to the Ixia and set them + // to 100GB since the Ixia ports are all 100GB. + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + LOG(INFO) << "Host Interface " << interface; + EXPECT_OK(SetPortSpeed(kSpeed100GB, interface, gnmi_stub.get())); + } + } + + // Wait to let the links come up + absl::SleepFor(absl::Seconds(20)); + + // Loop through the interface_info looking for Ixia/SUT interface pairs, + // checking if the link is up. we need one pair with link up for the + // ingress interface/IXIA traffic generation + std::string ixia_interface = ""; + std::string sut_in_interface = ""; + + for (const auto &[interface, info] : interface_info) { + if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) { + auto sut_link_up = CheckLinkUp(interface, gnmi_stub.get()); + EXPECT_TRUE(sut_link_up.ok()); + if (sut_link_up.ok() && sut_link_up.value()) { + ixia_interface = info.peer_interface_name; + sut_in_interface = interface; + break; + } + } + } + + ASSERT_FALSE(ixia_interface.empty()); + ASSERT_FALSE(sut_in_interface.empty()); + + // Look up the port numbers for the ingress and interface + ASSERT_OK_AND_ASSIGN(uint32_t in_id, + NameToP4Id(sut_in_interface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestCPUOutDiscards:\n" + << "Chose Ixia interface " << ixia_interface << "\n" + << "and SUT ingress interface " << sut_in_interface << " (id " + << in_id << ")\n\n"; + + std::vector v = absl::StrSplit(ixia_interface, '/'); + absl::string_view ixia_ip = v[0]; + absl::string_view ixia_in_card = v[1]; + absl::string_view ixia_in_port = v[2]; + ASSERT_FALSE(ixia_ip.empty()); + ASSERT_FALSE(ixia_in_card.empty()); + ASSERT_FALSE(ixia_in_port.empty()); + LOG(INFO) << "Ixia IP is " << ixia_ip; + LOG(INFO) << "Ixia ingress card is " << ixia_in_card; + LOG(INFO) << "Ixia ingress port is " << ixia_in_port; + LOG(INFO) << "SUT is " << generic_testbed->Sut().ChassisName(); + + // Set up the switch to forward inbound IPv4 packets to the egress port + // We're doing this to overwhelm the egress port so at least some of the + // packets we'll send from the CPU get discarded + LOG(INFO) << "\n\n----- TestCPUOutDiscards: TrapToCPU -----\n"; + EXPECT_OK(TrapToCPU(generic_testbed->Sut())); + LOG(INFO) << "\n\n----- TrapToCPU Done -----\n"; + + // Read some initial counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto initial_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + std::string cpu_iface = "CPU"; + ASSERT_OK_AND_ASSIGN(auto initial_cpu_out_discards, + GetGnmiStat("out-discards", cpu_iface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto initial_cpu_in_discards, + GetGnmiStat("in-discards", cpu_iface, gnmi_stub.get())); + + LOG(INFO) << "\n\nTestCPUOutDiscards:\n\n" + << "\n\nInitial Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(initial_in_counters); + LOG(INFO) << "\n\nInitial CPU in-discards " << initial_cpu_in_discards + << "\n\n"; + LOG(INFO) << "\n\nInitial CPU out-discards " << initial_cpu_out_discards + << "\n\n"; + + // Connect to the Ixia + LOG(INFO) << "\n\nTestCPUOutDiscards: IxiaConnect\n\n"; + ASSERT_OK_AND_ASSIGN(std::string href, + ixia::IxiaConnect(ixia_ip, *generic_testbed)); + + std::size_t ixpos = href.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string ixref = href.substr(0, ixpos + 10); + LOG(INFO) << "ixref " << ixref; + + // Connect to the Ixia card/port + ASSERT_OK_AND_ASSIGN( + std::string vref, + ixia::IxiaVport(href, ixia_in_card, ixia_in_port, *generic_testbed)); + + // Start a session + ASSERT_OK_AND_ASSIGN(std::string full_tref, + ixia::IxiaSession(vref, *generic_testbed)); + + LOG(INFO) << "full_tref = " << full_tref; + ixpos = full_tref.find("/ixnetwork"); + ASSERT_NE(ixpos, std::string::npos); + std::string tref = full_tref.substr(ixpos); + LOG(INFO) << "tref " << tref; + + // Set the line rate to 100 percent + ASSERT_OK(ixia::SetLineRate(tref, 100, *generic_testbed)); + + // Set the frame count to 90M + ASSERT_OK(ixia::SetFrameCount(tref, 90000000, *generic_testbed)); + + // Set the source & destination MAC addresses + ASSERT_OK(ixia::SetSrcMac(tref, "00:01:02:03:04:05", *generic_testbed)); + ASSERT_OK(ixia::SetDestMac(tref, "02:02:02:02:02:02", *generic_testbed)); + + // Append an IPv4 header + ASSERT_OK(ixia::AppendIPv4(full_tref, *generic_testbed)); + + // Set up the source and destination IP addresses + ASSERT_OK(ixia::SetSrcIPv4(tref, "192.168.0.1", *generic_testbed)); + ASSERT_OK(ixia::SetDestIPv4(tref, "192.168.0.2", *generic_testbed)); + + // Set the frame size to 1514 bytes + ASSERT_OK(ixia::SetFrameSize(tref, kMtu, *generic_testbed)); + + // Start the traffic + ASSERT_OK(ixia::StartTraffic(full_tref, ixref, *generic_testbed)); + + // Wait for 10 seconds after the test starts + absl::Time t1; + t1 = absl::Now(); + + absl::Time t2; + while (1) { + t2 = absl::Now(); + if (t2 >= t1 + absl::Seconds(10)) break; + absl::SleepFor(absl::Milliseconds(100)); + } + + LOG(INFO) << "Time at stop is " << t2; + LOG(INFO) << "Delta is " << t2 - t1; + + ASSERT_OK(ixia::StopTraffic(full_tref, *generic_testbed)); + + // Re-read the same counters via GNMI from the SUT + ASSERT_OK_AND_ASSIGN(auto final_in_counters, + ReadCounters(sut_in_interface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto final_cpu_in_discards, + GetGnmiStat("in-discards", cpu_iface, gnmi_stub.get())); + ASSERT_OK_AND_ASSIGN(auto final_cpu_out_discards, + GetGnmiStat("out-discards", cpu_iface, gnmi_stub.get())); + + // Check the time again + absl::Time t3 = absl::Now(); + LOG(INFO) << "Time after statistics read is " << t3; + LOG(INFO) << "Delta is " << t3 - t1; + uint64_t seconds = ((t3 - t1) / absl::Seconds(1)) + 1; + + // Display the final counters + LOG(INFO) << "\n\nTestCPUOutDiscards:\n\n" + << "\n\nFinal Ingress Counters (" << sut_in_interface << "):\n"; + ShowCounters(final_in_counters); + LOG(INFO) << "\n\nFinal CPU in-discards " << final_cpu_in_discards << "\n\n"; + LOG(INFO) << "\n\nFinal CPU out-discards " << final_cpu_out_discards + << "\n\n"; + + // Compute the change for each counter + auto delta_in = DeltaCounters(initial_in_counters, final_in_counters); + auto delta_cpu_in_discards = final_cpu_in_discards - initial_cpu_in_discards; + auto delta_cpu_out_discards = + final_cpu_out_discards - initial_cpu_out_discards; + + // Display the difference in the counters for now (during test dev) + LOG(INFO) << "\n\nTestCPUOutDiscards:\n\n" + << "\n\nIngress Deltas (" << sut_in_interface << ") in " << seconds + << " seconds:"; + ShowCounters(delta_in); + LOG(INFO) << "\n\nDelta CPU in-discards " << delta_cpu_in_discards << "\n\n"; + LOG(INFO) << "\n\nDelta CPU out-discards " << delta_cpu_out_discards + << "\n\n"; + + LOG(INFO) << "\n\n\n\n\n---------- Restore ----------\n\n\n\n\n"; + + // Tear down any forwarding rules set up + EXPECT_OK(ForwardTeardown(generic_testbed->Sut())); + + LOG(INFO) << "\n\n\n\n\n---------- Finished TestCPUOutDiscards " + "----------\n\n\n\n\n\n\n\n\n\n"; +} +#endif + +} // namespace pins_test diff --git a/tests/gnmi/ethcounter_ixia_test.h b/tests/gnmi/ethcounter_ixia_test.h new file mode 100644 index 00000000..a3f58769 --- /dev/null +++ b/tests/gnmi/ethcounter_ixia_test.h @@ -0,0 +1,26 @@ +// 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 +// +// 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. + +#ifndef PINS_TEST_GNMI_ETHCOUNTER_IXIA_TEST_H_ +#define PINS_TEST_GNMI_ETHCOUNTER_IXIA_TEST_H_ + +#include "thinkit/generic_testbed_fixture.h" + +namespace pins_test { + +class ExampleIxiaTestFixture : public thinkit::GenericTestbedFixture<> {}; + +} // namespace pins_test + +#endif // PINS_TEST_GNMI_ETHCOUNTER_IXIA_TEST_H_ From a9bf92cd2d0a25390cc22f5059afae9230454f30 Mon Sep 17 00:00:00 2001 From: divyagayathri-hcl <159437886+divyagayathri-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:38:21 +0530 Subject: [PATCH 4/9] [Thinkit] Add random blackbox events test and fix bug in traffic library & Add gNMI subscribe to random_blackbox_events_tests. (#686) Co-authored-by: kishanps --- tests/integration/system/BUILD.bazel | 59 +++++ .../system/random_blackbox_events_tests.cc | 245 ++++++++++++++++++ .../system/random_blackbox_events_tests.h | 26 ++ 3 files changed, 330 insertions(+) create mode 100644 tests/integration/system/BUILD.bazel create mode 100644 tests/integration/system/random_blackbox_events_tests.cc create mode 100644 tests/integration/system/random_blackbox_events_tests.h diff --git a/tests/integration/system/BUILD.bazel b/tests/integration/system/BUILD.bazel new file mode 100644 index 00000000..bbf38306 --- /dev/null +++ b/tests/integration/system/BUILD.bazel @@ -0,0 +1,59 @@ +# 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. + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +cc_library( + name = "random_blackbox_events_tests", + testonly = True, + srcs = ["random_blackbox_events_tests.cc"], + hdrs = ["random_blackbox_events_tests.h"], + deps = [ + "//gutil:status_matchers", + "//gutil:testing", + "//lib/basic_traffic", + "//lib/gnmi:gnmi_helper", + "//lib/p4rt:p4rt_port", + "//lib/utils:generic_testbed_utils", + "//p4_fuzzer:annotation_util", + "//p4_fuzzer:fuzzer_cc_proto", + "//p4_fuzzer:fuzzer_config", + "//p4_fuzzer:mutation_and_fuzz_util", + "//p4_fuzzer:switch_state", + "//p4_pdpi:ir", + "//p4_pdpi:ir_cc_proto", + "//p4_pdpi:p4_runtime_session", + "//p4_pdpi/packetlib:packetlib_cc_proto", + "//sai_p4/fixed:p4_roles", + "//sai_p4/instantiations/google:instantiations", + "//sai_p4/instantiations/google:sai_p4info_cc", + "//thinkit:generic_testbed", + "//thinkit:generic_testbed_fixture", + "//thinkit/proto:generic_testbed_cc_proto", + "@com_github_p4lang_p4runtime//:p4runtime_cc_grpc", + "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/random", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_googleapis//google/rpc:code_cc_proto", + "@com_google_googletest//:gtest", + ], + alwayslink = True, +) diff --git a/tests/integration/system/random_blackbox_events_tests.cc b/tests/integration/system/random_blackbox_events_tests.cc new file mode 100644 index 00000000..bb797963 --- /dev/null +++ b/tests/integration/system/random_blackbox_events_tests.cc @@ -0,0 +1,245 @@ +// 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/integration/system/random_blackbox_events_tests.h" + +#include +#include +#include +#include +#include +#include //NOLINT +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/cleanup/cleanup.h" +#include "absl/container/flat_hash_map.h" +#include "absl/random/random.h" +#include "absl/status/statusor.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "glog/logging.h" +#include "gmock/gmock.h" +#include "google/rpc/code.pb.h" +#include "grpcpp/client_context.h" +#include "grpcpp/impl/codegen/call_op_set.h" +#include "grpcpp/impl/codegen/client_context.h" +#include "grpcpp/support/sync_stream.h" +#include "gtest/gtest.h" +#include "gutil/proto.h" +#include "gutil/status.h" +#include "gutil/status_matchers.h" +#include "gutil/testing.h" +#include "lib/basic_traffic/basic_traffic.h" +#include "lib/gnmi/gnmi_helper.h" +#include "lib/p4rt/p4rt_port.h" +#include "lib/utils/generic_testbed_utils.h" +#include "lib/validator/validator_lib.h" +#include "p4/v1/p4runtime.grpc.pb.h" +#include "p4/v1/p4runtime.pb.h" +#include "p4_fuzzer/annotation_util.h" +#include "p4_fuzzer/fuzz_util.h" +#include "p4_fuzzer/fuzzer.pb.h" +#include "p4_fuzzer/fuzzer_config.h" +#include "p4_fuzzer/switch_state.h" +#include "p4_pdpi/ir.h" +#include "p4_pdpi/ir.pb.h" +#include "p4_pdpi/p4_runtime_session.h" +#include "p4_pdpi/packetlib/packetlib.pb.h" +#include "proto/gnmi/gnmi.grpc.pb.h" +#include "proto/gnmi/gnmi.pb.h" +#include "sai_p4/fixed/roles.h" +#include "sai_p4/instantiations/google/instantiations.h" +#include "sai_p4/instantiations/google/sai_p4info.h" +#include "thinkit/generic_testbed.h" +#include "thinkit/proto/generic_testbed.pb.h" +#include "thinkit/switch.h" +#include "thinkit/test_environment.h" + +namespace pins_test { +namespace { + +class ScopedThread { + public: + ScopedThread(std::function body) + : time_to_exit_(false), + thread_(std::move(body), std::cref(time_to_exit_)) {} + + ~ScopedThread() { + time_to_exit_ = true; + thread_.join(); + } + + private: + bool time_to_exit_; + std::thread thread_; +}; + +} // namespace + +TEST_P(RandomBlackboxEventsTest, ControlPlaneWithTrafficWithoutValidation) { + ASSERT_OK_AND_ASSIGN(std::unique_ptr testbed, + GetTestbedWithRequirements( + gutil::ParseProtoOrDie( + R"pb(interface_requirements { + count: 2 + interface_mode: CONTROL_INTERFACE + })pb"))); + testbed->Environment().SetTestCaseID("491b3f60-1369-4099-9385-da5dd44a087d"); + + // Initial sanity check. + ASSERT_OK(SwitchReady(testbed->Sut())); + + // Setup gNMI subscription request. + ASSERT_OK_AND_ASSIGN(auto gnmi_stub, testbed->Sut().CreateGnmiStub()); + auto subscription_request = + gutil::ParseProtoFileOrDie( + "tests/integration/system/" + "gnmi_subscription_request.textproto"); + grpc::ClientContext subscribe_context; + auto subscription = gnmi_stub->Subscribe(&subscribe_context); + subscription->WriteLast(subscription_request, grpc::WriteOptions()); + std::thread subscribe_thread([&subscription] { + gnmi::SubscribeResponse response; + while (subscription->Read(&response)) { + LOG_EVERY_N(INFO, 1000) + << "Received subscribe notification (Count: " << google::COUNTER + << "): " << response.ShortDebugString(); + } + }); + absl::Cleanup cancel_subscribe = [&subscribe_context, &subscribe_thread] { + subscribe_context.TryCancel(); + subscribe_thread.join(); + }; + + // Setup fuzzer thread. + ASSERT_OK_AND_ASSIGN(std::vector port_ids, + pins_test::GetMatchingP4rtPortIds( + *gnmi_stub, pins_test::IsEnabledEthernetInterface)); + p4::config::v1::P4Info p4_info = GetParam().p4_info; + if (p4_info.tables().empty()) { + LOG(INFO) << "No P4Info passed, using the one on the switch."; + ASSERT_OK_AND_ASSIGN(auto p4rt_session, + pdpi::P4RuntimeSession::Create(testbed->Sut())); + ASSERT_OK_AND_ASSIGN(p4::v1::GetForwardingPipelineConfigResponse response, + pdpi::GetForwardingPipelineConfig(p4rt_session.get())); + p4_info = std::move(*response.mutable_config()->mutable_p4info()); + } + + ASSERT_OK_AND_ASSIGN( + p4_fuzzer::FuzzerConfig config, + p4_fuzzer::FuzzerConfig::Create( + p4_info, p4_fuzzer::ConfigParams{ + .ports = std::move(port_ids), + .qos_queues = {"0x0", "0x1", "0x2", "0x3", "0x4", "0x5", + "0x6", "0x7"}, + .role = "sdn_controller", + .mutate_update_probability = 0.1, + .tables_for_which_to_not_exceed_resource_guarantees = + {"vrf_table", "mirror_session_table"}, + })); + ASSERT_OK_AND_ASSIGN(auto p4rt_session, + pdpi::P4RuntimeSession::CreateWithP4InfoAndClearTables( + testbed->Sut(), GetParam().p4_info)); + { + ScopedThread p4rt_fuzzer([&config, + &p4rt_session](const bool& time_to_exit) { + absl::BitGen generator; + p4_fuzzer::SwitchState state(config.GetIrP4Info()); + while (!time_to_exit) { + p4_fuzzer::AnnotatedWriteRequest annotated_request = + p4_fuzzer::FuzzWriteRequest(&generator, config, state, + std::numeric_limits::max()); + p4::v1::WriteRequest request = + p4_fuzzer::RemoveAnnotations(annotated_request); + request.set_device_id(p4rt_session->DeviceId()); + request.set_role(P4RUNTIME_ROLE_SDN_CONTROLLER); + *request.mutable_election_id() = p4rt_session->ElectionId(); + + ASSERT_OK_AND_ASSIGN( + pdpi::IrWriteRpcStatus response, + pdpi::GrpcStatusToIrWriteRpcStatus( + p4rt_session->WriteAndReturnGrpcStatus(request), + request.updates_size())); + + for (int i = 0; i < response.rpc_response().statuses().size(); i++) { + const pdpi::IrUpdateStatus& status = + response.rpc_response().statuses(i); + const p4::v1::Update& update = request.updates(i); + EXPECT_NE(status.code(), google::rpc::Code::INTERNAL) + << "Fuzzing should never cause an INTERNAL error, but got: " + << status.DebugString(); + + if (status.code() == google::rpc::Code::OK) { + ASSERT_OK(state.ApplyUpdate(update)); + } + } + + EXPECT_OK(pdpi::ReadPiTableEntries(p4rt_session.get()).status()); + } + }); + + // Send traffic and report discrepencies. + const auto test_packet = gutil::ParseProtoOrDie(R"pb( + headers { + ethernet_header { + ethernet_destination: "02:03:04:05:06:07" + ethernet_source: "00:01:02:03:04:05" + ethertype: "0x0800" + } + } + headers { + ipv4_header { + version: "0x4" + ihl: "0x5" + dscp: "0x03" + ecn: "0x0" + identification: "0x0000" + flags: "0x0" + fragment_offset: "0x0000" + ttl: "0x20" + protocol: "0x11" + ipv4_source: "1.2.3.4" + } + } + headers { + udp_header { source_port: "0x0000" destination_port: "0x0000" } + })pb"); + std::vector sut_control_interfaces = + GetSutInterfaces(FromTestbed(GetAllControlLinks, *testbed)); + ASSERT_OK_AND_ASSIGN( + auto statistics, + basic_traffic::SendTraffic( + *testbed, p4rt_session.get(), config.GetIrP4Info(), + {basic_traffic::InterfacePair{ + .ingress_interface = sut_control_interfaces[0], + .egress_interface = sut_control_interfaces[1]}}, + {test_packet}, absl::Minutes(5))); + for (const basic_traffic::TrafficStatistic& statistic : statistics) { + if (statistic.packets_sent != statistic.packets_received) { + LOG(WARNING) << statistic.interfaces.ingress_interface << " -> " + << statistic.interfaces.egress_interface + << ": Count mismatch; sent " << statistic.packets_sent + << " received " << statistic.packets_received << ", " + << statistic.packets_routed_incorrectly + << " routed incorrectly."; + } + } + } + // Final sanity check. + ASSERT_OK(SwitchReady(testbed->Sut())); +} + +} // namespace pins_test diff --git a/tests/integration/system/random_blackbox_events_tests.h b/tests/integration/system/random_blackbox_events_tests.h new file mode 100644 index 00000000..7943bd20 --- /dev/null +++ b/tests/integration/system/random_blackbox_events_tests.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef PINS_TESTS_INTEGRATION_SYSTEM_RANDOM_BLACKBOX_EVENTS_TESTS_H_ +#define PINS_TESTS_INTEGRATION_SYSTEM_RANDOM_BLACKBOX_EVENTS_TESTS_H_ + +#include "thinkit/generic_testbed_fixture.h" + +namespace pins_test { + +class RandomBlackboxEventsTest : public thinkit::GenericTestbedFixture<> {}; + +} // namespace pins_test + +#endif // PINS_TESTS_INTEGRATION_SYSTEM_RANDOM_BLACKBOX_EVENTS_TESTS_H_ From d1bc23397012a30168dbee9a57dbbca9f733b7b4 Mon Sep 17 00:00:00 2001 From: bibhuprasad-hcl <161687009+bibhuprasad-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:39:25 +0530 Subject: [PATCH 5/9] [Thinkit] Adding additional BERT tests. Fix issues in arbitration test. (#687) Co-authored-by: smolkaj Co-authored-by: Srikishen Pondicherry Shanmugam --- tests/gnoi/BUILD.bazel | 1 + tests/gnoi/bert_tests.cc | 138 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/tests/gnoi/BUILD.bazel b/tests/gnoi/BUILD.bazel index 4413fec0..78897c9f 100644 --- a/tests/gnoi/BUILD.bazel +++ b/tests/gnoi/BUILD.bazel @@ -32,6 +32,7 @@ cc_library( "//lib/gnmi:gnmi_helper", "//lib/validator:validator_lib", "//thinkit:mirror_testbed_fixture", + "//thinkit:test_environment", "@com_github_gnoi//diag:diag_cc_proto", "@com_github_google_glog//:glog", "@com_google_absl//absl/container:flat_hash_set", diff --git a/tests/gnoi/bert_tests.cc b/tests/gnoi/bert_tests.cc index de9c58f3..9925dea9 100644 --- a/tests/gnoi/bert_tests.cc +++ b/tests/gnoi/bert_tests.cc @@ -32,6 +32,7 @@ #include "gutil/testing.h" #include "lib/gnmi/gnmi_helper.h" #include "lib/validator/validator_lib.h" +#include "thinkit/test_environment.h" ABSL_FLAG(uint32_t, idx_seed, static_cast(std::time(nullptr)), "Seed to randomly generate interface index."); @@ -314,6 +315,8 @@ void GetAndVerifyBertResultsWithAdminDownInterfaces( // Test StartBERT with invalid request parameters. TEST_P(BertTest, StartBertFailsIfRequestParametersInvalid) { + GetMirrorTestbed().Environment().SetTestCaseID( + "c1dcb1cc-4806-45cc-8f8a-676beafde103"); thinkit::Switch& sut = GetMirrorTestbed().Sut(); // TODO (b/176913347): Enable the all ports UP check. // ASSERT_OK(pins_test::PortsUp(sut)); @@ -401,6 +404,8 @@ TEST_P(BertTest, StartBertFailsIfRequestParametersInvalid) { // 2) If StopBERT RPC is requested on a port that is not running BERT, RPC // should fail. TEST_P(BertTest, StopBertfailsIfRequestParametersInvalid) { + GetMirrorTestbed().Environment().SetTestCaseID( + "224db9cf-c709-486d-a0d3-6ab64c1a1e1f"); thinkit::Switch& sut = GetMirrorTestbed().Sut(); // TODO (b/176913347): Enable the all ports UP check. // ASSERT_OK(pins_test::PortsUp(sut)); @@ -458,6 +463,8 @@ TEST_P(BertTest, StopBertfailsIfRequestParametersInvalid) { // 2) If GetBERTResult RPC is requested on a port that never ran BERT before, // RPC should fail. TEST_P(BertTest, GetBertResultFailsIfRequestParametersInvalid) { + GetMirrorTestbed().Environment().SetTestCaseID( + "4f837d7a-ab44-4694-9ca9-399d576757f4"); thinkit::Switch& sut = GetMirrorTestbed().Sut(); // TODO (b/176913347): Enable the all ports UP check. // ASSERT_OK(pins_test::PortsUp(sut)); @@ -514,6 +521,8 @@ TEST_P(BertTest, GetBertResultFailsIfRequestParametersInvalid) { // Test StartBERT fails if peer port is not running BERT. TEST_P(BertTest, StartBertfailsIfPeerPortNotRunningBert) { + GetMirrorTestbed().Environment().SetTestCaseID( + "37e48922-0616-4d16-8fd3-975897491956"); thinkit::Switch& sut = GetMirrorTestbed().Sut(); ASSERT_OK_AND_ASSIGN(std::unique_ptr sut_gnmi_stub, sut.CreateGnmiStub()); @@ -586,6 +595,8 @@ TEST_P(BertTest, StartBertfailsIfPeerPortNotRunningBert) { // 3) Operation id that was used earlier to start the BERT test will fail to // start BERT if used again. TEST_P(BertTest, StartBertSucceeds) { + GetMirrorTestbed().Environment().SetTestCaseID( + "b31a796a-d078-4d45-b785-f09ec598e05a"); thinkit::Switch& sut = GetMirrorTestbed().Sut(); ASSERT_OK_AND_ASSIGN(std::unique_ptr sut_gnmi_stub, sut.CreateGnmiStub()); @@ -784,4 +795,131 @@ TEST_P(BertTest, StartBertSucceeds) { // ASSERT_OK(pins_test::PortsUp(control_switch)); } +// Runs the BERT test on current maximum allowed number of interfaces. During +// the BERT run: +// 1) Disable admin state of few ports on SUT, +// 2) Disable admin state of few ports on control switch, +// This helps us verify a mix of operation during BERT - unexpected software or +// hardware errors. +TEST_P(BertTest, RunBertOnMaximumAllowedPorts) { + GetMirrorTestbed().Environment().SetTestCaseID( + "ce526e97-2a62-4044-9dce-8fc74b232e4b"); + thinkit::Switch& sut = GetMirrorTestbed().Sut(); + ASSERT_OK_AND_ASSIGN(std::unique_ptr sut_gnmi_stub, + sut.CreateGnmiStub()); + ASSERT_OK(pins_test::PortsUp(sut)); + ASSERT_OK_AND_ASSIGN( + std::unique_ptr sut_gnoi_diag_stub, + sut.CreateGnoiDiagStub()); + + thinkit::Switch& control_switch = GetMirrorTestbed().ControlSwitch(); + ASSERT_OK_AND_ASSIGN( + std::unique_ptr control_switch_gnmi_stub, + control_switch.CreateGnmiStub()); + ASSERT_OK(pins_test::PortsUp(control_switch)); + ASSERT_OK_AND_ASSIGN( + std::unique_ptr control_switch_gnoi_diag_stub, + control_switch.CreateGnoiDiagStub()); + + // Get all the interfaces that are operational status "UP". + ASSERT_OK_AND_ASSIGN(std::vector interfaces, + pins_test::GetUpInterfacesOverGnmi(*sut_gnmi_stub)); + // For this test, we need at least 5 UP interfaces. + ASSERT_GE(interfaces.size(), 5); + // Resize the interface list if UP ports are more than max number of allowed + // ports. + if (interfaces.size() > kMaxAllowedInterfacesToRunBert) { + interfaces.resize(kMaxAllowedInterfacesToRunBert); + } + + // Select 'N' ports on control switch and 'N' ports on SUT for admin down. + int num_interfaces_to_disable = 1 + (interfaces.size() / 16); + // Seed the std::rand(). + LOG(INFO) << "Seeding pseudo-random number generator with seed: " + << absl::GetFlag(FLAGS_idx_seed); + // Select SUT interfaces in the range [0..interfaces/2). + std::vector sut_interfaces_for_admin_down; + std::sample(interfaces.begin(), interfaces.begin() + interfaces.size() / 2, + std::back_inserter(sut_interfaces_for_admin_down), + num_interfaces_to_disable, + std::mt19937(absl::GetFlag(FLAGS_idx_seed))); + // Select control switch interfaces in the range [interfaces/2..interfaces]. + std::vector control_switch_interfaces_for_admin_down; + std::sample(interfaces.begin() + interfaces.size() / 2, interfaces.end(), + std::back_inserter(control_switch_interfaces_for_admin_down), + num_interfaces_to_disable, + std::mt19937(absl::GetFlag(FLAGS_idx_seed))); + + LOG(INFO) << "Starting BERT on " << interfaces.size() << " interfaces."; + + gnoi::diag::StartBERTRequest bert_request; + // Create the BERT request. + bert_request.set_bert_operation_id( + absl::StrCat("OpId-", absl::ToUnixMillis(absl::Now()))); + for (const std::string& interface : interfaces) { + *(bert_request.add_per_port_requests()) = + gutil::ParseProtoOrDie( + BuildPerPortStartBertRequest(interface)); + } + + // Request StartBert on the SUT switch. + { + gnoi::diag::StartBERTResponse bert_response; + grpc::ClientContext context; + EXPECT_OK( + sut_gnoi_diag_stub->StartBERT(&context, bert_request, &bert_response)); + } + + // Request StartBert on the control switch. + { + gnoi::diag::StartBERTResponse bert_response; + grpc::ClientContext context; + EXPECT_OK(control_switch_gnoi_diag_stub->StartBERT(&context, bert_request, + &bert_response)); + } + + absl::Time start_time = absl::Now(); + // Give some time to BERT to move in SYNC state. + absl::SleepFor(absl::Seconds(90)); + + absl::Time end_time = absl::Now(); + + // Poll for remaining BERT duration. + int max_poll_count = + 1 + (absl::ToInt64Seconds(kDelayDuration + kWaitTime + kSyncDuration + + kTestDuration - (end_time - start_time) - + absl::Seconds(1)) / + ToInt64Seconds(kPollInterval)); + std::vector interfaces_not_up = interfaces; + for (int count = 0; count < max_poll_count; ++count) { + absl::SleepFor(kPollInterval); + // If port is "UP" and no longer in "TESTING" oper state on both sides of + // link, BERT has completed on the link and full BERT result is ready. + for (auto it = interfaces_not_up.begin(); it != interfaces_not_up.end();) { + ASSERT_OK_AND_ASSIGN( + pins_test::OperStatus oper_status, + pins_test::GetInterfaceOperStatusOverGnmi(*sut_gnmi_stub, *it)); + if (oper_status == pins_test::OperStatus::kUp) { + ASSERT_OK_AND_ASSIGN(oper_status, + pins_test::GetInterfaceOperStatusOverGnmi( + *control_switch_gnmi_stub, *it)); + if (oper_status == pins_test::OperStatus::kUp) { + it = interfaces_not_up.erase(it); + continue; + } + } + ++it; + } + if (interfaces_not_up.empty()) break; + } + + EXPECT_THAT(interfaces_not_up, testing::IsEmpty()); + + // Wait for some time before checking the port status. + absl::SleepFor(absl::Seconds(10)); + + ASSERT_OK(pins_test::PortsUp(sut)); + ASSERT_OK(pins_test::PortsUp(control_switch)); +} + } // namespace bert From 77ea8a16dacf0c97ed4938a04db85ff23b68be8c Mon Sep 17 00:00:00 2001 From: bibhuprasad-hcl <161687009+bibhuprasad-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:40:17 +0530 Subject: [PATCH 6/9] [Thinkit] Update smoke_test to ignore counter data on ACL reads.gNMI interface tests. Add wait after port disable.Verify openconfig-p4rt:id instead of openconfig-pins-interfaces:id. PRBS BERT test. (#688) Co-authored-by: smolkaj Co-authored-by: Srikishen Pondicherry Shanmugam Co-authored-by: Robert Halstead --- tests/forwarding/BUILD.bazel | 3 ++ tests/forwarding/smoke_test.cc | 15 +++++++-- tests/gnoi/bert_tests.cc | 44 +++++++++++++++++---------- tests/thinkit_gnmi_interface_tests.cc | 9 +++--- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/tests/forwarding/BUILD.bazel b/tests/forwarding/BUILD.bazel index f662b4cf..b325a934 100644 --- a/tests/forwarding/BUILD.bazel +++ b/tests/forwarding/BUILD.bazel @@ -93,7 +93,10 @@ cc_library( "//sai_p4/instantiations/google:sai_p4info_cc", "//sai_p4/instantiations/google:sai_pd_cc_proto", "//thinkit:mirror_testbed_fixture", + "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", + "@com_google_absl//absl/strings", "@com_google_googletest//:gtest", + "@com_google_protobuf//:protobuf", ], alwayslink = True, ) diff --git a/tests/forwarding/smoke_test.cc b/tests/forwarding/smoke_test.cc index d82fc671..3c72795f 100644 --- a/tests/forwarding/smoke_test.cc +++ b/tests/forwarding/smoke_test.cc @@ -14,11 +14,14 @@ #include "tests/forwarding/smoke_test.h" +#include "absl/strings/str_cat.h" #include "gmock/gmock.h" +#include "google/protobuf/util/message_differencer.h" #include "gtest/gtest.h" #include "gutil/proto_matchers.h" #include "gutil/status_matchers.h" #include "gutil/testing.h" +#include "p4/v1/p4runtime.pb.h" #include "p4_pdpi/p4_runtime_session.h" #include "p4_pdpi/pd.h" #include "sai_p4/instantiations/google/sai_p4info.h" @@ -140,8 +143,16 @@ TEST_P(SmokeTestFixture, InsertAndReadTableEntries) { } // Compare the result in proto format since the fields being compared are - // nested and out of order. - EXPECT_THAT(read_response, gutil::EqualsProto(expected_read_response)); + // nested and out of order. Also ignore any dynamic fields (e.g. counters). + google::protobuf::util::MessageDifferencer diff; + diff.set_repeated_field_comparison( + google::protobuf::util::MessageDifferencer::RepeatedFieldComparison:: + AS_SET); + diff.IgnoreField( + p4::v1::TableEntry::descriptor()->FindFieldByName("counter_data")); + EXPECT_TRUE(diff.Compare(read_response, expected_read_response)) + << "Expected: " << expected_read_response.DebugString() + << "\nActual: " << read_response.DebugString(); } } // namespace diff --git a/tests/gnoi/bert_tests.cc b/tests/gnoi/bert_tests.cc index 9925dea9..403988d0 100644 --- a/tests/gnoi/bert_tests.cc +++ b/tests/gnoi/bert_tests.cc @@ -50,6 +50,8 @@ constexpr absl::Duration kSyncDuration = absl::Minutes(5); // Maximum allowed BERT delay duration due to setup, sync and recovery // operations. constexpr absl::Duration kDelayDuration = absl::Minutes(10); +// Wait duration after requesting BERT to read the oper status of the port. +constexpr absl::Duration kWaitToReadOperStatus = absl::Seconds(30); // Polling interval. constexpr absl::Duration kPollInterval = absl::Seconds(30); // Minimum wait time after the BERT request to read the BERT result. @@ -290,6 +292,7 @@ void GetAndVerifyBertResultsWithAdminDownInterfaces( const std::string interface_name, GetInterfaceNameFromOcInterfacePath( result_response.per_port_responses(idx).interface())); + LOG(INFO) << "Verifying result for interface: " << interface_name; // Check if interface is part of list where admin state was disabled. if (IsInterfaceInList(interface_name, sut_admin_down_interfaces) || IsInterfaceInList(interface_name, @@ -648,8 +651,11 @@ TEST_P(BertTest, StartBertSucceeds) { &bert_response)); } - // Wait for sync duration. - absl::SleepFor(kSyncDuration); + // Get start timestamp. + absl::Time start_time = absl::Now(); + // Wait before reading the oper status. + absl::SleepFor(kWaitToReadOperStatus); + // Verify that ports should be in TESTING mode now. for (const std::string& interface : interfaces) { SCOPED_TRACE( @@ -657,11 +663,11 @@ TEST_P(BertTest, StartBertSucceeds) { ASSERT_OK_AND_ASSIGN( pins_test::OperStatus oper_status, pins_test::GetInterfaceOperStatusOverGnmi(*sut_gnmi_stub, interface)); - ASSERT_TRUE(oper_status == pins_test::OperStatus::kTesting); + ASSERT_EQ(oper_status, pins_test::OperStatus::kTesting); ASSERT_OK_AND_ASSIGN(oper_status, pins_test::GetInterfaceOperStatusOverGnmi( *control_switch_gnmi_stub, interface)); - ASSERT_TRUE(oper_status == pins_test::OperStatus::kTesting); + ASSERT_EQ(oper_status, pins_test::OperStatus::kTesting); } // Request another StartBert on the same ports on SUT and it should fail. @@ -703,33 +709,34 @@ TEST_P(BertTest, StartBertSucceeds) { // Poll for remaining BERT duration. int max_poll_count = - 1 + (absl::ToInt64Seconds(kDelayDuration + kTestDuration - kSyncDuration - - kWaitTime - absl::Seconds(1)) / + 1 + (absl::ToInt64Seconds(kDelayDuration + kTestDuration - + (absl::Now() - start_time) - absl::Seconds(1)) / ToInt64Seconds(kPollInterval)); - std::vector interfaces_not_up = interfaces; + std::vector interfaces_in_testing = interfaces; for (int count = 0; count < max_poll_count; ++count) { absl::SleepFor(kPollInterval); - // If port is "UP" and no longer in "TESTING" oper state on both sides of - // link, BERT has completed on the link and full BERT result is ready. - for (auto it = interfaces_not_up.begin(); it != interfaces_not_up.end();) { + // If port is no longer in "TESTING" oper state on both sides of the link, + // linkqual has completed on the link and full result is ready. + for (auto it = interfaces_in_testing.begin(); + it != interfaces_in_testing.end();) { ASSERT_OK_AND_ASSIGN( pins_test::OperStatus oper_status, pins_test::GetInterfaceOperStatusOverGnmi(*sut_gnmi_stub, *it)); - if (oper_status == pins_test::OperStatus::kUp) { + if (oper_status != pins_test::OperStatus::kTesting) { ASSERT_OK_AND_ASSIGN(oper_status, pins_test::GetInterfaceOperStatusOverGnmi( *control_switch_gnmi_stub, *it)); - if (oper_status == pins_test::OperStatus::kUp) { - it = interfaces_not_up.erase(it); + if (oper_status != pins_test::OperStatus::kTesting) { + it = interfaces_in_testing.erase(it); continue; } } ++it; } - if (interfaces_not_up.empty()) break; + if (interfaces_in_testing.empty()) break; } - EXPECT_THAT(interfaces_not_up, testing::IsEmpty()); + EXPECT_THAT(interfaces_in_testing, testing::IsEmpty()); gnoi::diag::GetBERTResultRequest result_request; result_request.set_bert_operation_id(bert_request.bert_operation_id()); @@ -850,7 +857,12 @@ TEST_P(BertTest, RunBertOnMaximumAllowedPorts) { num_interfaces_to_disable, std::mt19937(absl::GetFlag(FLAGS_idx_seed))); - LOG(INFO) << "Starting BERT on " << interfaces.size() << " interfaces."; + LOG(INFO) << "Starting BERT on " << interfaces.size() + << " interfaces: " << absl::StrJoin(interfaces, ","); + LOG(INFO) << "Interfaces selected on SUT for admin down: " + << absl::StrJoin(sut_interfaces_for_admin_down, ","); + LOG(INFO) << "Interfaces selected on control switch for admin down: " + << absl::StrJoin(control_switch_interfaces_for_admin_down, ","); gnoi::diag::StartBERTRequest bert_request; // Create the BERT request. diff --git a/tests/thinkit_gnmi_interface_tests.cc b/tests/thinkit_gnmi_interface_tests.cc index a3d54d31..c76033b4 100644 --- a/tests/thinkit_gnmi_interface_tests.cc +++ b/tests/thinkit_gnmi_interface_tests.cc @@ -58,6 +58,7 @@ void TestGnmiInterfaceConfigSetAdminStatus(thinkit::Switch& sut, absl::StrCat("interfaces/interface[name=", if_name, "]/config/enabled"); ASSERT_OK(SetGnmiConfigPath(sut_gnmi_stub.get(), if_enabled_config_path, GnmiSetType::kUpdate, kEnabledFalse)); + absl::SleepFor(absl::Seconds(5)); // Perform state path verifications. // Verify /interfaces/interface[name=]/state/enabled = false. @@ -91,6 +92,7 @@ void TestGnmiInterfaceConfigSetAdminStatus(thinkit::Switch& sut, LOG(INFO) << "Enabling front panel port: " << if_name; ASSERT_OK(SetGnmiConfigPath(sut_gnmi_stub.get(), if_enabled_config_path, GnmiSetType::kUpdate, kEnabledTrue)); + absl::SleepFor(absl::Seconds(5)); // Perform state path verifications. // Verify /interfaces/interface[name=]/state/enabled = true. @@ -112,7 +114,6 @@ void TestGnmiInterfaceConfigSetAdminStatus(thinkit::Switch& sut, EXPECT_THAT(state_path_response, HasSubstr(kStateUp)); // Verify /interfaces/interface[name=]/state/oper-status = UP. - absl::SleepFor(absl::Seconds(5)); if_state_path = absl::StrCat("interfaces/interface[name=", if_name, "]/state/oper-status"); resp_parse_str = "openconfig-interfaces:oper-status"; @@ -235,7 +236,7 @@ void TestGnmiInterfaceConfigSetPortSpeed( ASSERT_OK(SetGnmiConfigPath( sut_gnmi_stub.get(), if_port_speed_config_path, GnmiSetType::kUpdate, ConstructGnmiConfigSetString(kPortSpeed, kNewPortSpeedStr))); - absl::SleepFor(absl::Seconds(5)); + absl::SleepFor(absl::Seconds(30)); // Perform state path verifications. // Verify /interfaces/interface[name=]/ethernet/state/port-speed = @@ -264,7 +265,7 @@ void TestGnmiInterfaceConfigSetPortSpeed( ASSERT_OK(SetGnmiConfigPath( sut_gnmi_stub.get(), if_port_speed_config_path, GnmiSetType::kUpdate, ConstructGnmiConfigSetString(kPortSpeed, kOriginalPortSpeedStr))); - absl::SleepFor(absl::Seconds(5)); + absl::SleepFor(absl::Seconds(30)); // Verify /interfaces/interface[name=]/ethernet/state/port-speed = // original speed. @@ -302,7 +303,7 @@ void TestGnmiInterfaceConfigSetId(thinkit::Switch& sut, // Verify /interfaces/interface[name=]/state/id = . std::string if_state_path = absl::StrCat("interfaces/interface[name=", if_name, "]/state/id"); - std::string resp_parse_str = "openconfig-pins-interfaces:id"; + std::string resp_parse_str = "openconfig-p4rt:id"; ASSERT_OK_AND_ASSIGN( std::string state_path_response, GetGnmiStatePathInfo(sut_gnmi_stub.get(), if_state_path, resp_parse_str)); From d7088ab9f05c74c62952810a71bb5a3966f3b06b Mon Sep 17 00:00:00 2001 From: divyagayathri-hcl <159437886+divyagayathri-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:40:55 +0530 Subject: [PATCH 7/9] [Thinkit] Added tests/thinkit_gnmi_interface_util.h (#689) Co-authored-by: kishanps --- tests/BUILD.bazel | 7 ++ tests/thinkit_gnmi_interface_util.cc | 2 +- tests/thinkit_gnmi_interface_util.h | 127 +++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/thinkit_gnmi_interface_util.h diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index edc6b7ba..5bca0289 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -59,19 +59,26 @@ cc_library( testonly = 1, srcs = [ "thinkit_gnmi_interface_tests.cc", + "thinkit_gnmi_interface_util.cc", ], hdrs = [ "thinkit_gnmi_interface_tests.h", + "thinkit_gnmi_interface_util.h", "thinkit_util.h", ], deps = [ + "//gutil:status", "//gutil:status_matchers", + "//gutil:testing", "//lib/gnmi:gnmi_helper", + "//p4_pdpi:pd", + "//sai_p4/instantiations/google:sai_pd_cc_proto", "//thinkit:ssh_client", "//thinkit:switch", "@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto", "@com_github_google_glog//:glog", "@com_github_nlohmann_json//:nlohmann_json", + "@com_google_absl//absl/status", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/tests/thinkit_gnmi_interface_util.cc b/tests/thinkit_gnmi_interface_util.cc index 8be43b79..0778feb9 100644 --- a/tests/thinkit_gnmi_interface_util.cc +++ b/tests/thinkit_gnmi_interface_util.cc @@ -23,7 +23,7 @@ #include "gutil/status.h" #include "lib/gnmi/gnmi_helper.h" #include "proto/gnmi/gnmi.grpc.pb.h" -#include "single_include/nlohmann/json.hpp" +#include "include/nlohmann/json.hpp" #include "tests/thinkit_util.h" #include "thinkit/ssh_client.h" #include "thinkit/switch.h" diff --git a/tests/thinkit_gnmi_interface_util.h b/tests/thinkit_gnmi_interface_util.h new file mode 100644 index 00000000..668af0d7 --- /dev/null +++ b/tests/thinkit_gnmi_interface_util.h @@ -0,0 +1,127 @@ +// Copyright 2021 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. + +#ifndef PINS_TESTS_THINKIT_GNMI_INTERFACE_UTIL_H_ +#define PINS_TESTS_THINKIT_GNMI_INTERFACE_UTIL_H_ + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "gutil/testing.h" +#include "lib/gnmi/gnmi_helper.h" +#include "p4_pdpi/pd.h" +#include "proto/gnmi/gnmi.grpc.pb.h" +#include "sai_p4/instantiations/google/sai_pd.pb.h" +#include "include/nlohmann/json.hpp" +#include "thinkit/ssh_client.h" +#include "thinkit/switch.h" + +namespace pins_test { + +const int kMaxPortLanes = 8; +const int kEthernetLen = 8; +constexpr char kEthernet[] = "Ethernet"; + +// // PortBreakoutInfo contains physical channels and operational status for an +// // interface. +typedef struct { + std::string physical_channels; // Eg. format: [0,1,2,3] + std::string oper_status; // Eg. format: "UP" +} PortBreakoutInfo; + +typedef struct { + std::string port_name; // Randomly selected port on switch. + std::string + curr_breakout_mode; // Currently configured breakout mode on the port. + std::string supported_breakout_mode; // Supported breakout mode on port + // different from current breakout mode. +} RandomPortBreakoutInfo; + +enum BreakoutType { kAny, kChannelized }; + +// GetSupportedBreakoutModesForPort returns list of supported breakout modes for +// given interface. +absl::StatusOr> GetSupportedBreakoutModesForPort( + const std::string& interface_info, const std::string& port, + const BreakoutType breakout_type = BreakoutType::kAny); + +// GetRandomPortWithSupportedBreakoutModes attempts to get a random port from +// list of front panel ports that supports at least one more breakout mode other +// than the currently configured breakout mode. +absl::StatusOr GetRandomPortWithSupportedBreakoutModes( + gnmi::gNMI::StubInterface& sut_gnmi_stub, + const std::string& platform_json_contents, + const BreakoutType breakout_type = BreakoutType::kAny); + +// GetBreakoutStateInfoForPort returns the state values of physical channels and +// operational status information for ports in a given breakout mode. +absl::StatusOr> +GetBreakoutStateInfoForPort(gnmi::gNMI::StubInterface* sut_gnmi_stub, + const std::string& port, + absl::string_view breakout_mode); + +// GetExpectedPortInfoForBreakoutMode returns the expected port list and +// physical channels for a given breakout mode. +// Eg. Ethernet0 configured to a breakout mode of "2x100G + 1x200G" will return +// the following: Ethernet0:{0,1}, Ethernet2:{2,3}, Ethernet4:{4,5,6,7}. The +// number of physical channels per breakout mode is used to compute the offset +// from the parent port number. +absl::StatusOr> +GetExpectedPortInfoForBreakoutMode(const std::string& port, + absl::string_view breakout_mode); + +// GetBreakoutModeConfigFromString returns breakout config path values from +// given breakout mode. Breakout mode is in the format "numBreakouts1 x +// breakoutSpeed1 + numBreakouts2 x breakoutSpeed2 + ... Eg: "1x400G", 2x100G + +// 1x200G" +absl::Status GetBreakoutModeConfigFromString( + gnmi::SetRequest& req, const absl::string_view index, + const absl::string_view breakout_mode); + +// GetNonExistingPortsAfterBreakout returns list of ports that were part of a +// previous breakout config but no longer exist after a new breakout config is +// applied. +// For a negative test case where we do not expect the breakout mode on +// the port to change, ports in new breakout config that were not originally +// present should not exist as the config is not successfully applied. +// For a successful test case where we expect the breakout mode to be applied on +// the port, ports in original breakout config that were not in new breakout +// config should no longer exist as new breakout is now applied. +std::vector GetNonExistingPortsAfterBreakout( + absl::flat_hash_map& orig_port_info, + absl::flat_hash_map& new_port_info, + bool expected_success); + +// ValidateBreakoutState checks the breakout related state paths with the +// expected values. +// For a negative test case where we do not expect the breakout mode on the port +// to change, the expected_port_info contains state path values of the original +// breakout mode before pushing new breakout mode. +// For a successful test case where we expect the breakout mode to be applied on +// the port, the expected_port_info contains expected breakout values for the +// new mode. +absl::Status ValidateBreakoutState( + gnmi::gNMI::StubInterface* sut_gnmi_stub, + absl::flat_hash_map& expected_port_info, + std::vector& non_existing_ports_list); + +absl::StatusOr GetPortIndex( + const std::string& platform_json_contents, absl::string_view port); + +std::string ConstructSupportedBreakoutMode(std::string& num_breakouts, + std::string& breakout_speed); +} // namespace pins_test +#endif // PINS_TESTS_THINKIT_GNMI_INTERFACE_UTIL_H_ From 5662cdd6f7594f3e42eea4d555bcc385e2440548 Mon Sep 17 00:00:00 2001 From: divyagayathri-hcl <159437886+divyagayathri-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:43:06 +0530 Subject: [PATCH 8/9] [Thinkit] Add gNMI subscribe to random_blackbox_events_tests. (#690) Co-authored-by: kishanps --- tests/integration/system/BUILD.bazel | 10 + .../gnmi_subscription_request.textproto | 705 ++++++++++++++++++ 2 files changed, 715 insertions(+) create mode 100644 tests/integration/system/gnmi_subscription_request.textproto diff --git a/tests/integration/system/BUILD.bazel b/tests/integration/system/BUILD.bazel index bbf38306..c880409f 100644 --- a/tests/integration/system/BUILD.bazel +++ b/tests/integration/system/BUILD.bazel @@ -22,13 +22,16 @@ cc_library( testonly = True, srcs = ["random_blackbox_events_tests.cc"], hdrs = ["random_blackbox_events_tests.h"], + data = ["gnmi_subscription_request.textproto"], deps = [ + "//gutil:proto", "//gutil:status_matchers", "//gutil:testing", "//lib/basic_traffic", "//lib/gnmi:gnmi_helper", "//lib/p4rt:p4rt_port", "//lib/utils:generic_testbed_utils", + "//lib/validator:validator_lib", "//p4_fuzzer:annotation_util", "//p4_fuzzer:fuzzer_cc_proto", "//p4_fuzzer:fuzzer_config", @@ -43,10 +46,17 @@ cc_library( "//sai_p4/instantiations/google:sai_p4info_cc", "//thinkit:generic_testbed", "//thinkit:generic_testbed_fixture", + "//thinkit:switch", + "//thinkit:test_environment", "//thinkit/proto:generic_testbed_cc_proto", + "@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto", + "@com_github_gnmi//proto/gnmi:gnmi_cc_proto", + "@com_github_google_glog//:glog", "@com_github_p4lang_p4runtime//:p4runtime_cc_grpc", "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/cleanup", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/random", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", diff --git a/tests/integration/system/gnmi_subscription_request.textproto b/tests/integration/system/gnmi_subscription_request.textproto new file mode 100644 index 00000000..ec140ea1 --- /dev/null +++ b/tests/integration/system/gnmi_subscription_request.textproto @@ -0,0 +1,705 @@ +# proto-file: third_party/openconfig/gnmi/proto/gnmi/gnmi.proto +# proto-message: SubscribeRequest + +subscribe { + prefix { + origin: "openconfig" + target: "chassis" + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "admin-status" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "ethernet" + } + elem { + name: "state" + } + elem { + name: "mac-address" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "hardware-port" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "health-indicator" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "id" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "oper-status" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "ethernet" + } + elem { + name: "state" + } + elem { + name: "port-speed" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "components" + } + elem { + name: "component" + key { + key: "name" + value: "*" + } + } + elem { + name: "integrated-circuit" + } + elem { + name: "state" + } + elem { + name: "node-id" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "components" + } + elem { + name: "component" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "parent" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "components" + } + elem { + name: "component" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "oper-status" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "components" + } + elem { + name: "component" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "software-version" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "components" + } + elem { + name: "component" + key { + key: "name" + value: "*" + } + } + elem { + name: "software-module" + } + elem { + name: "state" + } + elem { + name: "module-type" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "system" + } + elem { + name: "alarms" + } + elem { + name: "alarm" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "severity" + } + } + mode: ON_CHANGE + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-octets" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-unicast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-broadcast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-multicast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-discards" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-errors" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "in-fcs-errors" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-unicast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-broadcast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-multicast-pkts" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-octets" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-discards" + } + } + } + subscription { + path { + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "counters" + } + elem { + name: "out-errors" + } + } + } + subscription { + path { + elem { + name: "qos" + } + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "interface-id" + value: "*" + } + } + elem { + name: "output" + } + elem { + name: "queues" + } + elem { + name: "queue" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "transmit-pkts" + } + } + } + subscription { + path { + elem { + name: "qos" + } + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "interface-id" + value: "*" + } + } + elem { + name: "output" + } + elem { + name: "queues" + } + elem { + name: "queue" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "transmit-octets" + } + } + } + subscription { + path { + elem { + name: "qos" + } + elem { + name: "interfaces" + } + elem { + name: "interface" + key { + key: "interface-id" + value: "*" + } + } + elem { + name: "output" + } + elem { + name: "queues" + } + elem { + name: "queue" + key { + key: "name" + value: "*" + } + } + elem { + name: "state" + } + elem { + name: "dropped-pkts" + } + } + } + encoding: PROTO +} From 36eb8919a9d8816ed599e6898a41cfaeea738655 Mon Sep 17 00:00:00 2001 From: divyagayathri-hcl <159437886+divyagayathri-hcl@users.noreply.github.com> Date: Wed, 6 Nov 2024 05:49:39 +0530 Subject: [PATCH 9/9] [Thinkit] Implement watch port test, Add member down test case, Add single member and watchport modify test cases, Add down ports to the group and verify watch port action & Use control switch for admin up/down operations in watch port tests. (#696) Co-authored-by: kishanps --- dvaas/packet_injection.cc | 2 +- lib/pins_control_device.cc | 2 +- tests/forwarding/BUILD.bazel | 35 + tests/forwarding/group_programming_util.cc | 57 +- tests/forwarding/group_programming_util.h | 28 +- tests/forwarding/packet_test_util.cc | 11 + tests/forwarding/packet_test_util.h | 3 + tests/forwarding/util.cc | 4 +- tests/forwarding/util.h | 4 +- tests/forwarding/watch_port_test.cc | 1022 ++++++++++++++++++++ tests/forwarding/watch_port_test.h | 44 +- 11 files changed, 1178 insertions(+), 34 deletions(-) create mode 100644 tests/forwarding/watch_port_test.cc diff --git a/dvaas/packet_injection.cc b/dvaas/packet_injection.cc index 80221736..5c88c40f 100644 --- a/dvaas/packet_injection.cc +++ b/dvaas/packet_injection.cc @@ -134,7 +134,7 @@ absl::StatusOr SendTestPacketsAndCollectOutputs( const Packet& packet = packet_test_vector.input().packet(); // Inject to egress of control switch. - RETURN_IF_ERROR(gpins::InjectEgressPacket( + RETURN_IF_ERROR(pins::InjectEgressPacket( packet.port(), absl::HexStringToBytes(packet.hex()), control_ir_p4info, &control_switch, injection_delay)); } else { diff --git a/lib/pins_control_device.cc b/lib/pins_control_device.cc index c7b136e7..0a3c7c9a 100644 --- a/lib/pins_control_device.cc +++ b/lib/pins_control_device.cc @@ -162,7 +162,7 @@ absl::Status PinsControlDevice::SendPacket( "No P4RuntimeSession exists; Likely failed to establish another " "P4RuntimeSession."); } - return gpins::InjectEgressPacket(interface_name_to_port_id_[interface], + return pins::InjectEgressPacket(interface_name_to_port_id_[interface], std::string(packet), ir_p4_info_, control_session_.get(), packet_delay); } diff --git a/tests/forwarding/BUILD.bazel b/tests/forwarding/BUILD.bazel index b325a934..3047b3b2 100644 --- a/tests/forwarding/BUILD.bazel +++ b/tests/forwarding/BUILD.bazel @@ -190,15 +190,50 @@ cc_library( cc_library( name = "watch_port_test", testonly = True, + srcs = ["watch_port_test.cc"], hdrs = ["watch_port_test.h"], linkstatic = 1, deps = [ ":group_programming_util", ":packet_test_util", + ":util", + "//dvaas:test_vector_cc_proto", + "//gutil:collections", + "//gutil:proto_matchers", + "//gutil:status_matchers", + "//gutil:testing", + "//lib/gnmi:gnmi_helper", + "//p4_pdpi:ir_cc_proto", "//p4_pdpi:p4_runtime_session", + "//p4_pdpi:pd", + "//p4_pdpi/packetlib", + "//p4_pdpi/packetlib:packetlib_cc_proto", + "//p4_pdpi/string_encodings:decimal_string", + "//p4rt_app/tests/lib:p4runtime_grpc_service", + "//sai_p4/instantiations/google:instantiations", "//sai_p4/instantiations/google:sai_p4info_cc", + "//sai_p4/instantiations/google:sai_pd_cc_proto", + "//tests:thinkit_sanity_tests", + "//thinkit:mirror_testbed", "//thinkit:mirror_testbed_fixture", + "//thinkit:switch", + "//thinkit:test_environment", + "@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto", + "@com_github_google_glog//:glog", "@com_github_grpc_grpc//:grpc++", + "@com_github_p4lang_p4runtime//:p4info_cc_proto", + "@com_github_p4lang_p4runtime//:p4runtime_cc_grpc", + "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/random", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest", ], alwayslink = True, ) diff --git a/tests/forwarding/group_programming_util.cc b/tests/forwarding/group_programming_util.cc index 1d68b599..b39d091b 100644 --- a/tests/forwarding/group_programming_util.cc +++ b/tests/forwarding/group_programming_util.cc @@ -33,9 +33,9 @@ namespace pins { absl::Status ProgramNextHops(thinkit::TestEnvironment& test_environment, - pdpi::P4RuntimeSession* const p4_session, + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, - std::vector& members) { + std::vector& members) { int index = 0; std::vector nexthops; std::vector pi_entries; @@ -103,7 +103,7 @@ absl::Status ProgramNextHops(thinkit::TestEnvironment& test_environment, // Program the switch. RETURN_IF_ERROR( - (pdpi::InstallPiTableEntries(p4_session, ir_p4info, pi_entries))); + (pdpi::InstallPiTableEntries(&p4_session, ir_p4info, pi_entries))); // Write the PI & PD entries to artifacts. for (const auto& pi : pi_entries) { @@ -124,10 +124,10 @@ absl::Status ProgramNextHops(thinkit::TestEnvironment& test_environment, } absl::Status ProgramGroupWithMembers(thinkit::TestEnvironment& test_environment, - pdpi::P4RuntimeSession* const p4_session, + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, absl::string_view group_id, - absl::Span members, + absl::Span members, const p4::v1::Update_Type& type) { auto group_update = gutil::ParseProtoOrDie(absl::Substitute( R"pb( @@ -168,7 +168,7 @@ absl::Status ProgramGroupWithMembers(thinkit::TestEnvironment& test_environment, update->set_type(type); *update->mutable_entity()->mutable_table_entry() = pi_entry; RETURN_IF_ERROR( - pdpi::SetMetadataAndSendPiWriteRequest(p4_session, write_request)); + pdpi::SetMetadataAndSendPiWriteRequest(&p4_session, write_request)); // Append the PI & PD entries. RETURN_IF_ERROR(test_environment.AppendToTestArtifact( @@ -178,7 +178,7 @@ absl::Status ProgramGroupWithMembers(thinkit::TestEnvironment& test_environment, return absl::OkStatus(); } -absl::Status DeleteGroup(pdpi::P4RuntimeSession* const p4_session, +absl::Status DeleteGroup(pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, absl::string_view group_id) { ASSIGN_OR_RETURN( @@ -196,19 +196,20 @@ absl::Status DeleteGroup(pdpi::P4RuntimeSession* const p4_session, )pb", group_id)))); - return pdpi::SetMetadataAndSendPiWriteRequest(p4_session, write_request); + return pdpi::SetMetadataAndSendPiWriteRequest(&p4_session, write_request); } // Verifies the actual members received from P4 read response matches the // expected members. absl::Status VerifyGroupMembersFromP4Read( - pdpi::P4RuntimeSession* const p4_session, const pdpi::IrP4Info& ir_p4info, - absl::string_view group_id, absl::Span expected_members) { + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, + absl::string_view group_id, + absl::Span expected_members) { p4::v1::ReadRequest read_request; read_request.add_entities()->mutable_table_entry(); ASSIGN_OR_RETURN( p4::v1::ReadResponse read_response, - pdpi::SetMetadataAndSendPiReadRequest(p4_session, read_request)); + pdpi::SetMetadataAndSendPiReadRequest(&p4_session, read_request)); // Filter out WCMP group entries separately from the whole read response. absl::flat_hash_map @@ -238,7 +239,7 @@ absl::Status VerifyGroupMembersFromP4Read( gutil::ParseProtoOrDie( absl::Substitute(R"pb( action { set_nexthop_id { nexthop_id: "$0" } } - weight: 0 + weight: 1 watch_port: "" )pb", member.nexthop)); @@ -306,8 +307,8 @@ int RescaleWeightForTomahawk3(int weight) { return (weight - 1) / 2; } -void RescaleMemberWeights(std::vector& members) { - for (Member& member : members) { +void RescaleMemberWeights(std::vector& members) { + for (GroupMember& member : members) { int old_weight = member.weight; member.weight = RescaleWeightForTomahawk3(old_weight); LOG(INFO) << "Rescaling member id: " << member.port @@ -316,4 +317,32 @@ void RescaleMemberWeights(std::vector& members) { } } +std::string DescribeDistribution( + int expected_total_test_packets, + absl::Span members, + const absl::flat_hash_map& num_packets_per_port, + bool expect_single_port) { + double total_weight = 0; + for (const auto& member : members) { + total_weight += member.weight; + } + std::string explanation = ""; + for (const auto& member : members) { + double actual_packets = num_packets_per_port.contains(member.port) + ? num_packets_per_port.at(member.port) + : 0; + if (expect_single_port) { + absl::StrAppend(&explanation, "\nport ", member.port, + ": actual_count = ", actual_packets); + } else { + double expected_packets = + expected_total_test_packets * member.weight / total_weight; + absl::StrAppend(&explanation, "\nport ", member.port, " with weight ", + member.weight, ": expected_count = ", expected_packets, + ", actual_count = ", actual_packets); + } + } + return explanation; +} + } // namespace pins diff --git a/tests/forwarding/group_programming_util.h b/tests/forwarding/group_programming_util.h index 850f35a5..b54ae866 100644 --- a/tests/forwarding/group_programming_util.h +++ b/tests/forwarding/group_programming_util.h @@ -28,7 +28,7 @@ namespace pins { // Structure that holds the member details like port, weight and the // nexthop object key (output) that was created. -struct Member { +struct GroupMember { int weight = 1; int port = 0; std::string nexthop; @@ -39,31 +39,31 @@ struct Member { // members.nexthop is an output here with the updated nexthop object that was // created. absl::Status ProgramNextHops(thinkit::TestEnvironment& test_environment, - pdpi::P4RuntimeSession* const p4_session, + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, - std::vector& members); + std::vector& members); // Programs (insert/modify) a nexthop group on the switch with the given // set of nexthops and weights. It is expected that the dependant nexthops are // already created for an insert/modify operation. absl::Status ProgramGroupWithMembers(thinkit::TestEnvironment& test_environment, - pdpi::P4RuntimeSession* const p4_session, + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, absl::string_view group_id, - absl::Span members, + absl::Span members, const p4::v1::Update_Type& type); // Deletes the group with the given group_id. It is expected that the caller // takes care of cleaning up the dependant nexthops. -absl::Status DeleteGroup(pdpi::P4RuntimeSession* const p4_session, +absl::Status DeleteGroup(pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, absl::string_view group_id); // Verifies the actual members received from P4 read response matches the // expected members. absl::Status VerifyGroupMembersFromP4Read( - pdpi::P4RuntimeSession* const p4_session, const pdpi::IrP4Info& ir_p4info, - absl::string_view group_id, absl::Span expected_members); + pdpi::P4RuntimeSession& p4_session, const pdpi::IrP4Info& ir_p4info, + absl::string_view group_id, absl::Span expected_members); // Verifies the actual members inferred from receive traffic matches the // expected members. @@ -85,7 +85,17 @@ int RescaleWeightForTomahawk3(int weight); // hardware behaviour, remove when hardware supports > 128 weights. // Halves member weights >= 2 and works only for sum of initial member weights // <= 256. -void RescaleMemberWeights(std::vector& members); +void RescaleMemberWeights(std::vector& members); + +// Returns a human-readable description of the actual vs expected +// distribution of packets on the group member ports. +// expect_single_port specifies whether all packets are expected on a single +// output port(since no hashing applies) or multiple ports(with hashing). +std::string DescribeDistribution( + int expected_total_test_packets, + absl::Span members, + const absl::flat_hash_map& num_packets_per_port, + bool expect_single_port); } // namespace pins diff --git a/tests/forwarding/packet_test_util.cc b/tests/forwarding/packet_test_util.cc index 417f0d54..3affde68 100644 --- a/tests/forwarding/packet_test_util.cc +++ b/tests/forwarding/packet_test_util.cc @@ -110,6 +110,17 @@ uint32_t GetIthL4Port(int i, uint32_t base) { } // namespace +// Clears the received packet output vector and the packet statistics counters. +void TestData::ClearReceivedPackets() { + absl::MutexLock lock(&mutex); + for (auto& [packet, input_output] : input_output_per_packet) { + input_output.output.clear(); + } + total_packets_sent = 0; + total_packets_received = 0; + total_invalid_packets_received = 0; +} + // Is this a valid test configuration? Not all configurations are valid, e.g. // you can't modify the flow label in an IPv4 packet (because there is no flow // label there). diff --git a/tests/forwarding/packet_test_util.h b/tests/forwarding/packet_test_util.h index 3fe5c85f..b0207cca 100644 --- a/tests/forwarding/packet_test_util.h +++ b/tests/forwarding/packet_test_util.h @@ -79,6 +79,9 @@ struct TestData { int total_invalid_packets_received = 0; absl::flat_hash_map input_output_per_packet ABSL_GUARDED_BY(mutex); + // Clears the received packets in the output vector and the send/receive + // counters. + void ClearReceivedPackets() ABSL_LOCKS_EXCLUDED(mutex); }; // Checks wehether this a valid test configuration. Not all configurations are diff --git a/tests/forwarding/util.cc b/tests/forwarding/util.cc index 4fa14fd7..d831c1f6 100644 --- a/tests/forwarding/util.cc +++ b/tests/forwarding/util.cc @@ -23,7 +23,7 @@ #include "p4_pdpi/ir.pb.h" #include "sai_p4/tools/packetio_tools.h" -namespace gpins { +namespace pins { absl::Status TryUpToNTimes(int n, absl::Duration delay, std::function callback) { @@ -91,4 +91,4 @@ absl::Status InjectIngressPacket(const std::string& packet, << request.ShortDebugString(); } -} // namespace gpins +} // namespace pins diff --git a/tests/forwarding/util.h b/tests/forwarding/util.h index ef46884c..e3be1412 100644 --- a/tests/forwarding/util.h +++ b/tests/forwarding/util.h @@ -24,7 +24,7 @@ #include "p4_pdpi/ir.pb.h" #include "p4_pdpi/p4_runtime_session.h" -namespace gpins { +namespace pins { // Calls given callback up to the given number of times with the given delay in // between successive attempts, returning ok status as soon as the callback @@ -68,6 +68,6 @@ absl::StatusOr TryStatusOrUpToNTimes( return result; } -} // namespace gpins +} // namespace pins #endif // PINS_TESTS_FORWARDING_UTIL_H_ diff --git a/tests/forwarding/watch_port_test.cc b/tests/forwarding/watch_port_test.cc new file mode 100644 index 00000000..9236b64d --- /dev/null +++ b/tests/forwarding/watch_port_test.cc @@ -0,0 +1,1022 @@ +// Copyright 2021 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/forwarding/watch_port_test.h" + +#include +#include +#include // NOLINT +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/random/random.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/escaping.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "dvaas/test_vector.pb.h" +#include "glog/logging.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "gutil/collections.h" +#include "gutil/proto_matchers.h" +#include "gutil/status_matchers.h" +#include "gutil/testing.h" +#include "lib/gnmi/gnmi_helper.h" +#include "p4/config/v1/p4info.pb.h" +#include "p4/v1/p4runtime.grpc.pb.h" +#include "p4/v1/p4runtime.pb.h" +#include "p4_pdpi/ir.pb.h" +#include "p4_pdpi/packetlib/packetlib.h" +#include "p4_pdpi/packetlib/packetlib.pb.h" +#include "p4_pdpi/pd.h" +#include "p4_pdpi/p4_runtime_session.h" +#include "p4_pdpi/string_encodings/decimal_string.h" +#include "p4rt_app/tests/lib/p4runtime_grpc_service.h" +#include "proto/gnmi/gnmi.grpc.pb.h" +#include "sai_p4/instantiations/google/instantiations.h" +#include "sai_p4/instantiations/google/sai_p4info.h" +#include "sai_p4/instantiations/google/sai_pd.pb.h" +#include "tests/forwarding/group_programming_util.h" +#include "tests/forwarding/packet_test_util.h" +#include "tests/forwarding/util.h" +#include "tests/thinkit_sanity_tests.h" +#include "thinkit/mirror_testbed.h" +#include "thinkit/mirror_testbed_fixture.h" +#include "thinkit/switch.h" +#include "thinkit/test_environment.h" +// Tests for the watchport functionality in Action Profile Group operation. + +namespace pins { + +namespace { +// Admin down/up state used for interfaces. +enum class AdminState { + kDown, + kUp, +}; + +// Group id used in this test. +constexpr absl::string_view kGroupId = "group-1"; + +// Vrf used in the test. +constexpr absl::string_view kVrfId = "vrf-1"; + +// Time to wait after which received packets are processed. +constexpr absl::Duration kDurationToWaitForPackets = absl::Seconds(5); + +// Number of members used in the test. +constexpr int kNumWcmpMembersForTest = 5; + +// Number of packets used in the test. +constexpr int kNumTestPackets = 5000; + +// Default input port index of the group members vector, on which packets +// arrive. +constexpr int kDefaultInputPortIndex = 0; + +// Helper function that sets up the input port for packet recieve. +// Creates the router interface for the input port. Without this input packets +// get dropped (b/190736007). +absl::Status SetUpInputPortForPacketReceive(pdpi::P4RuntimeSession& p4_session, + const pdpi::IrP4Info& ir_p4info, + int input_port) { + ASSIGN_OR_RETURN( + p4::v1::WriteRequest write_request, + pdpi::PdWriteRequestToPi( + ir_p4info, gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + updates { + type: INSERT + table_entry { + router_interface_table_entry { + match { router_interface_id: "$0" } + action { + set_port_and_src_mac { + port: "$1" + src_mac: "00:02:03:04:05:06" + } + } + } + } + } + )pb", + input_port, input_port)))); + + return pdpi::SetMetadataAndSendPiWriteRequest(&p4_session, write_request); +} + +// Helper function that creates/deletes V4, V6 default route entries. +absl::Status ProgramDefaultRoutes(pdpi::P4RuntimeSession& p4_session, + const pdpi::IrP4Info& ir_p4info, + absl::string_view default_vrf, + const p4::v1::Update_Type& type) { + if (!p4::v1::Update_Type_IsValid(type) || + type == p4::v1::Update_Type_UNSPECIFIED) { + return absl::InvalidArgumentError( + absl::StrCat("Type: ", type, " not supported.")); + } + std::string type_str = p4::v1::Update_Type_Name(type); + // Add minimal set of flows to allow forwarding. + auto ipv4_fallback = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + type: $0 + table_entry { + ipv4_table_entry { + match { vrf_id: "$1" } + action { set_wcmp_group_id { wcmp_group_id: "$2" } } + } + })pb", + type_str, default_vrf, kGroupId)); + auto ipv6_fallback = gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + type: $0 + table_entry { + ipv6_table_entry { + match { vrf_id: "$1" } + action { set_wcmp_group_id { wcmp_group_id: "$2" } } + } + })pb", + type_str, default_vrf, kGroupId)); + + p4::v1::WriteRequest write_request; + for (const auto& pd_entry : {ipv4_fallback, ipv6_fallback}) { + ASSIGN_OR_RETURN( + p4::v1::Update pi_entry, pdpi::PdUpdateToPi(ir_p4info, pd_entry), + _.SetPrepend() << "Failed in PD table conversion to PI, entry: " + << pd_entry.DebugString() << " error: "); + *write_request.add_updates() = pi_entry; + } + return pdpi::SetMetadataAndSendPiWriteRequest(&p4_session, write_request); +} + +// Installs a default vrf for all packets on the SUT. +absl::Status SetUpSut(pdpi::P4RuntimeSession& p4_session, + const pdpi::IrP4Info& ir_p4info, + absl::string_view default_vrf) { + // Set default VRF for all packets. + ASSIGN_OR_RETURN( + p4::v1::TableEntry pi_entry, + pdpi::PartialPdTableEntryToPiTableEntry( + ir_p4info, gutil::ParseProtoOrDie(absl::Substitute( + R"pb( + acl_pre_ingress_table_entry { + match {} # Wildcard match + action { set_vrf { vrf_id: "$0" } } # Default vrf + priority: 1129 + })pb", + default_vrf)))); + + return pdpi::InstallPiTableEntry(&p4_session, pi_entry); +} + +// Punts all packets on the control switch. +absl::Status SetUpControlSwitch(pdpi::P4RuntimeSession& p4_session, + const pdpi::IrP4Info& ir_p4info) { + // Trap all packets on control switch. + ASSIGN_OR_RETURN( + p4::v1::TableEntry punt_all_pi_entry, + pdpi::PartialPdTableEntryToPiTableEntry( + ir_p4info, + gutil::ParseProtoOrDie( + R"pb( + acl_ingress_table_entry { + match {} # Wildcard match. + action { acl_trap { qos_queue: "0x7" } } # Action: punt. + priority: 1 # Highest priority. + } + )pb"))); + return pdpi::InstallPiTableEntry(&p4_session, punt_all_pi_entry); +} + +// Creates members by filling in the controller port ids and random weights for +// each member that add upto 30(random). Skips the default input port on which +// traffic is received, since that is excluded from the traffic forwarding +// members in the group. +absl::StatusOr> CreateGroupMembers( + int group_size, absl::Span controller_port_ids) { + if (group_size + /*input_port=*/1 > controller_port_ids.size()) { + return absl::InvalidArgumentError(absl::StrCat( + "Not enough members: ", controller_port_ids.size(), + " to reserve an input port and create the group with size: ", + group_size)); + } + std::vector members; + for (int i = 0; i < controller_port_ids.size() && members.size() < group_size; + i++) { + // Add port ids except for the default input port id. + if (i != kDefaultInputPortIndex) { + members.push_back( + pins::GroupMember{.weight = 0, .port = controller_port_ids[i]}); + } + } + + ASSIGN_OR_RETURN(std::vector weights, + GenerateNRandomWeights(group_size, + /*total_weight=*/30)); + for (int i = 0; i < members.size(); i++) { + members[i].weight = weights[i]; + } + return members; +} + +// Creates a set of expected port ids from the member ports. +absl::flat_hash_set CreateExpectedMemberPorts( + absl::Span members) { + absl::flat_hash_set expected_member_ports; + for (const auto& member : members) { + expected_member_ports.insert(member.port); + } + return expected_member_ports; +} + +// Returns a map of number of packets received per port. +absl::StatusOr> CountNumPacketsPerPort( + absl::Span output_packets) { + absl::flat_hash_map num_packets_per_port; + for (const auto& output : output_packets) { + ASSIGN_OR_RETURN(int out_port, pdpi::DecimalStringToInt(output.port())); + num_packets_per_port[out_port]++; + } + return num_packets_per_port; +} + +// Sends N packets from the control switch to sut at a rate of 500 packets/sec. +absl::Status SendNPacketsToSut(int num_packets, + const TestConfiguration& test_config, + absl::Span members, + absl::Span port_ids, + const pdpi::IrP4Info& ir_p4info, + pdpi::P4RuntimeSession& p4_session, + thinkit::TestEnvironment& test_environment) { + const absl::Time start_time = absl::Now(); + for (int i = 0; i < num_packets; i++) { + // Rate limit to 500 packets per second. + auto earliest_send_time = start_time + (i * absl::Seconds(1) / 500.0); + absl::SleepFor(earliest_send_time - absl::Now()); + + // Vary the port on which to send the packet if the hash field selected is + // input port. + int port = port_ids[kDefaultInputPortIndex]; + if (test_config.field == PacketField::kInputPort) { + port = port_ids[i % members.size()]; + } + + ASSIGN_OR_RETURN(packetlib::Packet packet, + pins::GenerateIthPacket(test_config, i)); + ASSIGN_OR_RETURN(std::string raw_packet, SerializePacket(packet)); + ASSIGN_OR_RETURN(std::string port_string, pdpi::IntToDecimalString(port)); + RETURN_IF_ERROR( + pins::InjectEgressPacket(port_string, raw_packet, ir_p4info, &p4_session)); + + dvaas::Packet p; + p.set_port(port_string); + *p.mutable_parsed() = packet; + p.set_hex(absl::BytesToHexString(raw_packet)); + // Save log of packets. + RETURN_IF_ERROR(test_environment.AppendToTestArtifact( + absl::StrCat( + "packets-for-config-", + absl::StrJoin(absl::StrSplit(DescribeTestConfig(test_config), " "), + "-"), + ".txt"), + p.DebugString())); + } + + LOG(INFO) << "Sent " << num_packets << " packets in " + << (absl::Now() - start_time) << "."; + return absl::OkStatus(); +} + +void PrettyPrintDistribution( + const TestConfiguration& config, const TestInputOutput& test, + const TestData& test_data, absl::Span members, + const absl::flat_hash_map& num_packets_per_port) { + LOG(INFO) << "Results for " << DescribeTestConfig(config) << ":"; + LOG(INFO) << "- received " << test.output.size() << " packets"; + LOG(INFO) << "- observed distribution was:" + << DescribeDistribution(test_data.total_packets_sent, members, + num_packets_per_port, + /*expect_single_port=*/false); + LOG(INFO) << "Number of sent packets: " + << test_data.total_packets_sent; + LOG(INFO) << "Number of received packets (valid): " + << test_data.total_packets_received; + LOG(INFO) << "Number of received packets (invalid): " + << test_data.total_invalid_packets_received; +} + +// Creates the port_names_per_port_id map from GNMI config. +absl::StatusOr> +GetPortNamePerPortId(gnmi::gNMI::StubInterface& gnmi_stub) { + absl::flat_hash_map port_name_per_port_id; + ASSIGN_OR_RETURN(auto port_id_per_port_name, + pins_test::GetAllInterfaceNameToPortId(gnmi_stub)); + for (const auto& [name, port_id] : port_id_per_port_name) { + port_name_per_port_id[port_id] = name; + } + return port_name_per_port_id; +} + +// Sets the admin state of the interface to UP/DOWN using GNMI config path. +// Queries the state path to verify if the desired state is achieved or not. +absl::Status SetInterfaceAdminState(gnmi::gNMI::StubInterface& gnmi_stub, + absl::string_view if_name, + AdminState admin_state) { + const std::string if_status = + admin_state == AdminState::kDown ? "DOWN" : "UP"; + const std::string config_value = + admin_state == AdminState::kDown ? "false" : "true"; + const std::string if_admin_config_path = + absl::StrCat("interfaces/interface[name=", if_name, "]/config/enabled"); + LOG(INFO) << "Setting interface " << if_name << " to admin " << if_status; + RETURN_IF_ERROR(SetGnmiConfigPath( + &gnmi_stub, if_admin_config_path, pins_test::GnmiSetType::kUpdate, + absl::Substitute("{\"enabled\":$0}", config_value))); + // Wait for the admin state to take effect. + absl::SleepFor(absl::Seconds(1)); + // Verifies /interfaces/interface[name=]/state/admin-status = UP/DOWN. + const std::string if_state_path = + absl::StrCat("interfaces/interface[name=", if_name, "]/state"); + ASSIGN_OR_RETURN(const std::string state_path_response, + pins_test::GetGnmiStatePathInfo( + &gnmi_stub, if_state_path, + /*resp_parse_str=*/"openconfig-interfaces:state")); + if (!absl::StrContains(state_path_response, if_status)) { + return absl::UnknownError(absl::StrCat("Unable to set interface ", if_name, + " to admin ", if_status)); + } + return absl::OkStatus(); +} + +} // namespace + +void WatchPortTestFixture::SetUp() { + GetParam().testbed->SetUp(); + thinkit::MirrorTestbed& testbed = GetParam().testbed->GetMirrorTestbed(); + + // Push gnmi config to the sut and control switch. + const std::string& gnmi_config = GetParam().gnmi_config; + ASSERT_OK( + testbed.Environment().StoreTestArtifact("gnmi_config.txt", gnmi_config)); + ASSERT_OK(pins_test::PushGnmiConfig(testbed.Sut(), gnmi_config)); + ASSERT_OK(pins_test::PushGnmiConfig(testbed.ControlSwitch(), gnmi_config)); + + ASSERT_OK(testbed.Environment().StoreTestArtifact("p4info.pb.txt", + GetP4Info().DebugString())); + + // Setup SUT & control switch. + + ASSERT_OK_AND_ASSIGN(sut_p4_session_, + pdpi::P4RuntimeSession::CreateWithP4InfoAndClearTables( + testbed.Sut(), GetP4Info())); + ASSERT_OK_AND_ASSIGN(control_p4_session_, + pdpi::P4RuntimeSession::CreateWithP4InfoAndClearTables( + testbed.ControlSwitch(), GetP4Info())); + ASSERT_OK(SetUpSut(*sut_p4_session_, GetIrP4Info(), kVrfId)); + ASSERT_OK(SetUpControlSwitch(*control_p4_session_, GetIrP4Info())); + + // Create GNMI stub for admin operations. + ASSERT_OK_AND_ASSIGN(control_gnmi_stub_, + testbed.ControlSwitch().CreateGnmiStub()); + + // Start the receiver thread for control switch to listen for packets from + // SUT, this thread is terminated in the TearDown. + receive_packet_thread_ = std::thread([&]() { + p4::v1::StreamMessageResponse pi_response; + while (control_p4_session_->StreamChannelRead(pi_response)) { + absl::MutexLock lock(&test_data_.mutex); + sai::StreamMessageResponse pd_response; + ASSERT_OK(pdpi::PiStreamMessageResponseToPd(GetIrP4Info(), pi_response, + &pd_response)) + << " PacketIn PI to PD failed: "; + ASSERT_TRUE(pd_response.has_packet()) + << " Received unexpected stream message for packet in: " + << pd_response.DebugString(); + absl::string_view raw_packet = pd_response.packet().payload(); + dvaas::Packet packet; + packet.set_port(pd_response.packet().metadata().ingress_port()); + packet.set_hex(absl::BytesToHexString(raw_packet)); + *packet.mutable_parsed() = packetlib::ParsePacket(raw_packet); + std::string key = packet.parsed().payload(); + if (test_data_.input_output_per_packet.contains(key)) { + test_data_.input_output_per_packet[key].output.push_back(packet); + test_data_.total_packets_received += 1; + } else { + ASSERT_OK(testbed.Environment().AppendToTestArtifact( + "control_unexpected_packet_ins.pb.txt", + absl::StrCat(packet.DebugString(), "\n"))); + test_data_.total_invalid_packets_received += 1; + } + } + }); +} + +void WatchPortTestFixture::TearDown() { + thinkit::MirrorTestbedInterface& testbed = *GetParam().testbed; + + // Clear table entries. + if (sut_p4_session_ != nullptr) { + EXPECT_OK(pdpi::ClearTableEntries(sut_p4_session_.get())); + EXPECT_OK(sut_p4_session_->Finish()); + } + // Stop RPC sessions. + if (control_p4_session_ != nullptr) { + EXPECT_OK( + pdpi::ClearTableEntries(control_p4_session_.get())); + EXPECT_OK(control_p4_session_->Finish()); + } + if (receive_packet_thread_.joinable()) { + receive_packet_thread_.join(); + } + if (control_gnmi_stub_) { + ASSERT_OK_AND_ASSIGN(const auto port_name_per_port_id, + GetPortNamePerPortId(*control_gnmi_stub_)); + // Restore the admin state to UP. + for (const auto& [port_id, name] : port_name_per_port_id) { + EXPECT_OK( + SetInterfaceAdminState(*control_gnmi_stub_, name, AdminState::kUp)); + } + } + testbed.TearDown(); +} + +// TODO: Parameterize over the different instantiations like +// MiddleBlock, FBR400. +const p4::config::v1::P4Info& WatchPortTestFixture::GetP4Info() { + return sai::GetP4Info(sai::Instantiation::kMiddleblock); +} +const pdpi::IrP4Info& WatchPortTestFixture::GetIrP4Info() { + return sai::GetIrP4Info(sai::Instantiation::kMiddleblock); +} + +namespace { + +// Verifies basic WCMP behavior by programming a group with multiple members +// with random weights and ensuring that all members receive some part of +// the sent traffic. +TEST_P(WatchPortTestFixture, VerifyBasicWcmpPacketDistribution) { + thinkit::TestEnvironment& environment = + GetParam().testbed->GetMirrorTestbed().Environment(); + + absl::Span controller_port_ids = GetParam().port_ids; + const int group_size = kNumWcmpMembersForTest; + ASSERT_OK_AND_ASSIGN(std::vector members, + CreateGroupMembers(group_size, controller_port_ids)); + + const int input_port = controller_port_ids[kDefaultInputPortIndex]; + ASSERT_OK(SetUpInputPortForPacketReceive(*sut_p4_session_, GetIrP4Info(), + input_port)); + + // Programs the required router interfaces, nexthops for wcmp group. + ASSERT_OK(pins::ProgramNextHops(environment, *sut_p4_session_, GetIrP4Info(), + members)); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::INSERT)) + << "Failed to program WCMP group: "; + + // Program default routing for all packets on SUT. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::INSERT)); + + // TODO: Revisit for newer chipsets. + // Rescale the member weights (temp workaround) to what would have been + // programmed by the hardware. + RescaleMemberWeights(members); + + // Generate test configuration, pick any field (IP_SRC) used by hashing to + // vary for every packet so that it gets sent to all the members. + TestConfiguration test_config = { + .field = PacketField::kIpSrc, + .ipv4 = true, + .encapped = false, + .inner_ipv4 = false, + .decap = false, + }; + ASSERT_TRUE(IsValidTestConfiguration(test_config)); + + // Create test data entry. + std::string test_config_key = TestConfigurationToPayload(test_config); + { + absl::MutexLock lock(&test_data_.mutex); + test_data_.input_output_per_packet[test_config_key] = TestInputOutput{ + .config = test_config, + }; + } + + // Send 5000 packets and check for packet distribution. + ASSERT_OK(SendNPacketsToSut(kNumTestPackets, test_config, members, + controller_port_ids, GetIrP4Info(), + *control_p4_session_, environment)); + test_data_.total_packets_sent = kNumTestPackets; + + // Wait for packets from the SUT to arrive. + absl::SleepFor(kDurationToWaitForPackets); + + // For the test configuration, check the output distribution. + { + absl::MutexLock lock(&test_data_.mutex); + const TestInputOutput& test = + test_data_.input_output_per_packet[test_config_key]; + EXPECT_EQ(test.output.size(), test_data_.total_packets_sent) + << "Mismatch in expected: " << test_data_.total_packets_sent + << " and actual: " << test.output.size() << "packets received for " + << DescribeTestConfig(test_config); + + ASSERT_OK_AND_ASSIGN(auto num_packets_per_port, + CountNumPacketsPerPort(test.output)); + absl::flat_hash_set expected_member_ports = + CreateExpectedMemberPorts(members); + + ASSERT_OK(VerifyGroupMembersFromP4Read(*sut_p4_session_, GetIrP4Info(), + kGroupId, members)); + ASSERT_OK(VerifyGroupMembersFromReceiveTraffic(num_packets_per_port, + expected_member_ports)); + PrettyPrintDistribution(test_config, test, test_data_, members, + num_packets_per_port); + } +} + +// Bring down/up ActionProfileGroup member and verify traffic is distributed +// only to the up ports. +TEST_P(WatchPortTestFixture, VerifyBasicWatchPortAction) { + thinkit::TestEnvironment& environment = + GetParam().testbed->GetMirrorTestbed().Environment(); + absl::Span controller_port_ids = GetParam().port_ids; + const int group_size = kNumWcmpMembersForTest; + ASSERT_OK_AND_ASSIGN(std::vector members, + CreateGroupMembers(group_size, controller_port_ids)); + + const int input_port = controller_port_ids[kDefaultInputPortIndex]; + ASSERT_OK(SetUpInputPortForPacketReceive(*sut_p4_session_, GetIrP4Info(), + input_port)); + + // Programs the required router interfaces, nexthops for wcmp group. + ASSERT_OK(pins::ProgramNextHops(environment, *sut_p4_session_, GetIrP4Info(), + members)); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::INSERT)); + // Program default routing for all packets on SUT. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::INSERT)); + + // TODO: Revisit for newer chipsets. + // Rescale the member weights to what would have been programmed by the + // hardware. + RescaleMemberWeights(members); + + // Generate test configuration, pick any field used by hashing to vary for + // every packet so that it gets sent to all the members. + TestConfiguration test_config = { + .field = PacketField::kIpDst, + .ipv4 = true, + .encapped = false, + .inner_ipv4 = false, + .decap = false, + }; + ASSERT_TRUE(IsValidTestConfiguration(test_config)); + + // Create test data entry. + std::string test_config_key = TestConfigurationToPayload(test_config); + { + absl::MutexLock lock(&test_data_.mutex); + test_data_.input_output_per_packet[test_config_key] = TestInputOutput{ + .config = test_config, + }; + } + + absl::flat_hash_set expected_member_ports = + CreateExpectedMemberPorts(members); + + // Select one random member of the group to toggle. + absl::BitGen gen; + const int random_member_index = + absl::Uniform(absl::IntervalClosedOpen, gen, 0, members.size()); + const int selected_port_id = members[random_member_index].port; + ASSERT_OK_AND_ASSIGN(const auto port_name_per_port_id, + GetPortNamePerPortId(*control_gnmi_stub_)); + for (auto operation : {AdminState::kDown, AdminState::kUp}) { + ASSERT_OK_AND_ASSIGN(const auto& port_name, + gutil::FindOrStatus(port_name_per_port_id, + absl::StrCat(selected_port_id))); + ASSERT_OK( + SetInterfaceAdminState(*control_gnmi_stub_, port_name, operation)); + + // TODO: Adding watch port up action causes unexpected traffic + // loss. Remove after the bug in OrchAgent is fixed. + absl::SleepFor(absl::Seconds(5)); + + // Clear the counters before the test. + test_data_.ClearReceivedPackets(); + + // Send 5000 packets and check for packet distribution. + ASSERT_OK(SendNPacketsToSut(kNumTestPackets, test_config, members, + controller_port_ids, GetIrP4Info(), + *control_p4_session_, environment)); + test_data_.total_packets_sent = kNumTestPackets; + + // Wait for packets from the SUT to arrive. + absl::SleepFor(kDurationToWaitForPackets); + + // For the test configuration, check the output distribution. + { + absl::MutexLock lock(&test_data_.mutex); + TestInputOutput& test = + test_data_.input_output_per_packet[test_config_key]; + EXPECT_EQ(test.output.size(), test_data_.total_packets_sent) + << "Mismatch in expected: " << test_data_.total_packets_sent + << " and actual: " << test.output.size() << "packets received for " + << DescribeTestConfig(test_config); + + ASSERT_OK_AND_ASSIGN(auto num_packets_per_port, + CountNumPacketsPerPort(test.output)); + + // Add/remove the selected member from expected_member_ports for admin + // up/down case. + if (operation == AdminState::kDown) { + expected_member_ports.erase(selected_port_id); + } else { + expected_member_ports.insert(selected_port_id); + } + + ASSERT_OK(VerifyGroupMembersFromP4Read(*sut_p4_session_, GetIrP4Info(), + kGroupId, members)); + ASSERT_OK(VerifyGroupMembersFromReceiveTraffic(num_packets_per_port, + expected_member_ports)); + PrettyPrintDistribution(test_config, test, test_data_, members, + num_packets_per_port); + } + } +} + +// TODO: Bring down APG member (when in critical state) and verify traffic is +// distributed only to the up ports. +TEST_P(WatchPortTestFixture, VerifyWatchPortActionInCriticalState){}; + +// Bring up/down the only ActionProfileGroup member and verify traffic is +// forwarded/dropped. +TEST_P(WatchPortTestFixture, VerifyWatchPortActionForSingleMember) { + thinkit::TestEnvironment& environment = + GetParam().testbed->GetMirrorTestbed().Environment(); + + absl::Span controller_port_ids = GetParam().port_ids; + const int group_size = 1; + ASSERT_OK_AND_ASSIGN(std::vector members, + CreateGroupMembers(group_size, controller_port_ids)); + + const int input_port = controller_port_ids[kDefaultInputPortIndex]; + ASSERT_OK(SetUpInputPortForPacketReceive(*sut_p4_session_, GetIrP4Info(), + input_port)); + + // Programs the required router interfaces, nexthops for wcmp group. + ASSERT_OK(pins::ProgramNextHops(environment, *sut_p4_session_, GetIrP4Info(), + members)); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::INSERT)); + // Program default routing for all packets on SUT. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::INSERT)); + + // TODO: Revisit for newer chipsets. + // Rescale the member weights to what would have been programmed by the + // hardware. + RescaleMemberWeights(members); + + // Generate test configuration, pick any field used by hashing to vary for + // every packet so that it gets sent to all the members. + TestConfiguration test_config = { + .field = PacketField::kL4SrcPort, + .ipv4 = true, + .encapped = false, + .inner_ipv4 = false, + .decap = false, + }; + ASSERT_TRUE(IsValidTestConfiguration(test_config)); + + // Create test data entry. + std::string test_config_key = TestConfigurationToPayload(test_config); + { + absl::MutexLock lock(&test_data_.mutex); + test_data_.input_output_per_packet[test_config_key] = TestInputOutput{ + .config = test_config, + }; + } + + absl::flat_hash_set expected_member_ports = + CreateExpectedMemberPorts(members); + + // Pickup the only member (index 0) in the group and toggle down/up and verify + // traffic distribution. + ASSERT_THAT(members, testing::SizeIs(1)) + << "Unexpected member size for single member group"; + const int single_member_port_id = members[0].port; + ASSERT_OK_AND_ASSIGN(const auto port_name_per_port_id, + GetPortNamePerPortId(*control_gnmi_stub_)); + for (auto operation : {AdminState::kDown, AdminState::kUp}) { + ASSERT_OK_AND_ASSIGN( + const auto& port_name, + gutil::FindOrStatus(port_name_per_port_id, + absl::StrCat(single_member_port_id))); + ASSERT_OK( + SetInterfaceAdminState(*control_gnmi_stub_, port_name, operation)); + + // Clear the counters before the test. + test_data_.ClearReceivedPackets(); + + // TODO: Adding watch port up action causes unexpected traffic + // loss. Remove after the bug in OrchAgent is fixed. + absl::SleepFor(absl::Seconds(5)); + + // Send 5000 packets and check for packet distribution. + ASSERT_OK(SendNPacketsToSut(kNumTestPackets, test_config, members, + controller_port_ids, GetIrP4Info(), + *control_p4_session_, environment)); + test_data_.total_packets_sent = kNumTestPackets; + + // Wait for packets from the SUT to arrive. + absl::SleepFor(kDurationToWaitForPackets); + + // For the test configuration, check the output distribution. + { + absl::MutexLock lock(&test_data_.mutex); + TestInputOutput& test = + test_data_.input_output_per_packet[test_config_key]; + if (operation == AdminState::kDown) { + // Expect all packets to be lost for single member group watch port down + // action. + EXPECT_EQ(test.output.size(), 0) + << "Expected all packets to be lost for single member group watch " + "port down action, but received " + << test.output.size() << " actual packets"; + } else { + expected_member_ports.insert(single_member_port_id); + EXPECT_EQ(test.output.size(), test_data_.total_packets_sent) + << "Mismatch in expected: " << test_data_.total_packets_sent + << " and actual: " << test.output.size() << " packets received for " + << DescribeTestConfig(test_config); + } + ASSERT_OK_AND_ASSIGN(auto num_packets_per_port, + CountNumPacketsPerPort(test.output)); + + ASSERT_OK(VerifyGroupMembersFromP4Read(*sut_p4_session_, GetIrP4Info(), + kGroupId, members)); + ASSERT_OK(VerifyGroupMembersFromReceiveTraffic(num_packets_per_port, + expected_member_ports)); + PrettyPrintDistribution(test_config, test, test_data_, members, + num_packets_per_port); + } + } +}; + +// Modify ActionProfileGroup member and verify traffic is distributed +// accordingly. +TEST_P(WatchPortTestFixture, VerifyWatchPortActionForMemberModify) { + thinkit::TestEnvironment& environment = + GetParam().testbed->GetMirrorTestbed().Environment(); + + absl::Span controller_port_ids = GetParam().port_ids; + const int group_size = kNumWcmpMembersForTest; + ASSERT_OK_AND_ASSIGN(std::vector members, + CreateGroupMembers(group_size, controller_port_ids)); + + const int input_port = controller_port_ids[kDefaultInputPortIndex]; + ASSERT_OK(SetUpInputPortForPacketReceive(*sut_p4_session_, GetIrP4Info(), + input_port)); + + // Programs the required router interfaces, nexthops for wcmp group. + ASSERT_OK(pins::ProgramNextHops(environment, *sut_p4_session_, GetIrP4Info(), + members)); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::INSERT)); + // Program default routing for all packets on SUT. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::INSERT)); + + // TODO: Revisit for newer chipsets. + // Rescale the member weights to what would have been programmed by the + // hardware. + RescaleMemberWeights(members); + + // Generate test configuration, pick any field used by hashing to vary for + // every packet so that it gets sent to all the members. + TestConfiguration test_config = { + .field = PacketField::kIpDst, + .ipv4 = true, + .encapped = false, + .inner_ipv4 = false, + .decap = false, + }; + ASSERT_TRUE(IsValidTestConfiguration(test_config)); + + // Create test data entry. + std::string test_config_key = TestConfigurationToPayload(test_config); + { + absl::MutexLock lock(&test_data_.mutex); + test_data_.input_output_per_packet[test_config_key] = TestInputOutput{ + .config = test_config, + }; + } + + // Select one random member of the group to be brought down. + absl::BitGen gen; + const int random_member_index = + absl::Uniform(absl::IntervalClosedOpen, gen, 0, members.size()); + const int selected_port_id = members[random_member_index].port; + ASSERT_OK_AND_ASSIGN(const auto port_name_per_port_id, + GetPortNamePerPortId(*control_gnmi_stub_)); + ASSERT_OK_AND_ASSIGN(const auto& selected_port_name, + gutil::FindOrStatus(port_name_per_port_id, + absl::StrCat(selected_port_id))); + ASSERT_OK(SetInterfaceAdminState(*control_gnmi_stub_, selected_port_name, + AdminState::kDown)); + + // Send Modify request to remove the down member from the group. + members.erase(members.begin() + random_member_index); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::MODIFY)); + // Bring the down member watch port up. + ASSERT_OK(SetInterfaceAdminState(*control_gnmi_stub_, selected_port_name, + AdminState::kUp)); + + // TODO: Adding watch port up action causes unexpected traffic + // loss. Remove after the bug in OrchAgent is fixed. + absl::SleepFor(absl::Seconds(5)); + + // Send 5000 packets and check for packet distribution. + ASSERT_OK(SendNPacketsToSut(kNumTestPackets, test_config, members, + controller_port_ids, GetIrP4Info(), + *control_p4_session_, environment)); + test_data_.total_packets_sent = kNumTestPackets; + + // Wait for packets from the SUT to arrive. + absl::SleepFor(kDurationToWaitForPackets); + + // For the test configuration, check the output distribution. + { + absl::MutexLock lock(&test_data_.mutex); + TestInputOutput& test = test_data_.input_output_per_packet[test_config_key]; + EXPECT_EQ(test.output.size(), test_data_.total_packets_sent) + << "Mismatch in expected: " << test_data_.total_packets_sent + << " and actual: " << test.output.size() << "packets received for " + << DescribeTestConfig(test_config); + + ASSERT_OK_AND_ASSIGN(auto num_packets_per_port, + CountNumPacketsPerPort(test.output)); + + absl::flat_hash_set expected_member_ports = + CreateExpectedMemberPorts(members); + + ASSERT_OK(VerifyGroupMembersFromP4Read(*sut_p4_session_, GetIrP4Info(), + kGroupId, members)); + ASSERT_OK(VerifyGroupMembersFromReceiveTraffic(num_packets_per_port, + expected_member_ports)); + PrettyPrintDistribution(test_config, test, test_data_, members, + num_packets_per_port); + } + + // Delete default routes to prepare for delete group. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::DELETE)); + + // Delete group and verify no errors. + ASSERT_OK(DeleteGroup(*sut_p4_session_, GetIrP4Info(), kGroupId)); +}; + +// Add ActionProfileGroup member whose watch port is down (during create) and +// verify traffic distribution when port is down/up. +TEST_P(WatchPortTestFixture, VerifyWatchPortActionForDownPortMemberInsert) { + thinkit::TestEnvironment& environment = + GetParam().testbed->GetMirrorTestbed().Environment(); + environment.SetTestCaseID("e54da480-d2cc-42c6-bced-0354b5ab3329"); + absl::Span controller_port_ids = GetParam().port_ids; + const int input_port = controller_port_ids[kDefaultInputPortIndex]; + ASSERT_OK(SetUpInputPortForPacketReceive(*sut_p4_session_, GetIrP4Info(), + input_port)); + + const int group_size = kNumWcmpMembersForTest; + ASSERT_OK_AND_ASSIGN(std::vector members, + CreateGroupMembers(group_size, controller_port_ids)); + // Select one random port from the member port ids to be brought down/up. + absl::BitGen gen; + const int random_member_index = + absl::Uniform(absl::IntervalClosedOpen, gen, 0, members.size()); + const int selected_port_id = members[random_member_index].port; + ASSERT_OK_AND_ASSIGN(const auto port_name_per_port_id, + GetPortNamePerPortId(*control_gnmi_stub_)); + ASSERT_OK_AND_ASSIGN(const auto& selected_port_name, + gutil::FindOrStatus(port_name_per_port_id, + absl::StrCat(selected_port_id))); + // Bring the port down before the group and members are created. + ASSERT_OK(SetInterfaceAdminState(*control_gnmi_stub_, selected_port_name, + AdminState::kDown)); + + // Programs the required router interfaces, nexthops for wcmp group. + ASSERT_OK(pins::ProgramNextHops(environment, *sut_p4_session_, GetIrP4Info(), + members)); + ASSERT_OK(pins::ProgramGroupWithMembers(environment, *sut_p4_session_, + GetIrP4Info(), kGroupId, members, + p4::v1::Update::INSERT)); + // Program default routing for all packets on SUT. + ASSERT_OK(ProgramDefaultRoutes(*sut_p4_session_, GetIrP4Info(), kVrfId, + p4::v1::Update::INSERT)); + + // Generate test configuration, pick any field used by hashing to vary for + // every packet so that it gets sent to all the members. + TestConfiguration test_config = { + .field = PacketField::kL4DstPort, + .ipv4 = true, + .encapped = false, + .inner_ipv4 = false, + .decap = false, + }; + ASSERT_TRUE(IsValidTestConfiguration(test_config)); + + // Create test data entry. + std::string test_config_key = TestConfigurationToPayload(test_config); + { + absl::MutexLock lock(&test_data_.mutex); + test_data_.input_output_per_packet[test_config_key] = TestInputOutput{ + .config = test_config, + }; + } + + for (auto operation : {AdminState::kDown, AdminState::kUp}) { + // Down operation is a no-op here since the port is already down. + ASSERT_OK(SetInterfaceAdminState(*control_gnmi_stub_, selected_port_name, + operation)); + + // Clear the counters before the test. + test_data_.ClearReceivedPackets(); + + // TODO: Adding watch port up action causes unexpected traffic + // loss. Remove after the bug in OrchAgent is fixed. + absl::SleepFor(absl::Seconds(5)); + + // Send 5000 packets and check for packet distribution. + ASSERT_OK(SendNPacketsToSut(kNumTestPackets, test_config, members, + controller_port_ids, GetIrP4Info(), + *control_p4_session_, environment)); + test_data_.total_packets_sent = kNumTestPackets; + + // Wait for packets from the SUT to arrive. + absl::SleepFor(kDurationToWaitForPackets); + + // For the test configuration, check the output distribution. + { + absl::MutexLock lock(&test_data_.mutex); + TestInputOutput& test = + test_data_.input_output_per_packet[test_config_key]; + EXPECT_EQ(test.output.size(), test_data_.total_packets_sent) + << "Mismatch in expected: " << test_data_.total_packets_sent + << " and actual: " << test.output.size() << "packets received for " + << DescribeTestConfig(test_config); + + absl::flat_hash_set expected_member_ports = + CreateExpectedMemberPorts(members); + // Remove the selected member from expected_member_ports for admin + // down case. + if (operation == AdminState::kDown) { + expected_member_ports.erase(selected_port_id); + } + ASSERT_OK_AND_ASSIGN(auto num_packets_per_port, + CountNumPacketsPerPort(test.output)); + + ASSERT_OK(VerifyGroupMembersFromP4Read(*sut_p4_session_, GetIrP4Info(), + kGroupId, members)); + ASSERT_OK(VerifyGroupMembersFromReceiveTraffic(num_packets_per_port, + expected_member_ports)); + PrettyPrintDistribution(test_config, test, test_data_, members, + num_packets_per_port); + } + } +} + +} // namespace +} // namespace pins diff --git a/tests/forwarding/watch_port_test.h b/tests/forwarding/watch_port_test.h index 496b9fe5..94ed6e8d 100644 --- a/tests/forwarding/watch_port_test.h +++ b/tests/forwarding/watch_port_test.h @@ -15,21 +15,55 @@ #ifndef PINS_TESTS_FORWARDING_WATCH_PORT_TEST_H_ #define PINS_TESTS_FORWARDING_WATCH_PORT_TEST_H_ +#include +#include +#include +#include #include // NOLINT: Need threads (instead of fiber) for upstream code. #include +#include "absl/status/status.h" +#include "gtest/gtest.h" +#include "p4/config/v1/p4info.pb.h" +#include "p4_pdpi/ir.pb.h" #include "p4_pdpi/p4_runtime_session.h" -#include "sai_p4/instantiations/google/sai_p4info.h" +#include "proto/gnmi/gnmi.grpc.pb.h" #include "tests/forwarding/group_programming_util.h" #include "tests/forwarding/packet_test_util.h" #include "thinkit/mirror_testbed_fixture.h" +#include "thinkit/switch.h" namespace pins { -// WatchPortTestFixture that holds member functions needed for testing watch -// port action. -// TODO: To be implemented. -class WatchPortTestFixture : public thinkit::MirrorTestbedFixture {}; +// Holds the common params needed for watch port test. +struct WatchPortTestParams { + thinkit::MirrorTestbedInterface* testbed; + std::string gnmi_config; + // TODO: Remove port ids from here and derive from gNMI config. + std::vector port_ids; +}; + +// WatchPortTestFixture for testing watch port action. +class WatchPortTestFixture + : public testing::TestWithParam { + protected: + void SetUp() override; + + void TearDown() override; + + // Returns the P4Info used by the test, for now just Middleblock. + const p4::config::v1::P4Info& GetP4Info(); + const pdpi::IrP4Info& GetIrP4Info(); + + TestData test_data_; + std::unique_ptr sut_p4_session_; + std::unique_ptr control_p4_session_; + std::unique_ptr control_gnmi_stub_; + // Stores the receive thread that is created in SetUp() and joined in + // TearDown(). Accesses control_p4_session_->StreamChannelRead to read + // packets, which must not be used by other threads. + std::thread receive_packet_thread_; +}; } // namespace pins