diff --git a/dvaas/BUILD.bazel b/dvaas/BUILD.bazel index 1852460b..a7179a9a 100644 --- a/dvaas/BUILD.bazel +++ b/dvaas/BUILD.bazel @@ -165,31 +165,6 @@ cc_library( ], ) -# go/golden-test-with-coverage -cc_test( - name = "test_vector_stats_test", - srcs = ["test_vector_stats_test.cc"], - linkstatic = True, - deps = [ - ":test_vector_cc_proto", - ":test_vector_stats", - "//gutil:testing", - "@com_google_googletest//:gtest_main", - ], -) - -cmd_diff_test( - name = "test_vector_stats_diff_test", - actual_cmd = " | ".join([ - "$(execpath :test_vector_stats_test)", - # Strip unnecessary lines for golden testing. - "sed '1,/^\\[ RUN/d'", # Strip everything up to a line beginning with '[ RUN'. - "sed '/^\\[/d'", # Strip every line beginning with '['. - ]), - expected = "test_vector_stats_test.expected", - tools = [":test_vector_stats_test"], -) - cc_library( name = "mirror_testbed_config", testonly = True, @@ -293,6 +268,7 @@ cc_test( "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", ], ) @@ -307,3 +283,42 @@ cmd_diff_test( expected = "user_provided_packet_test_vector_test.expected", tools = [":user_provided_packet_test_vector_test"], ) + +# go/golden-test-with-coverage +cc_test( + name = "test_vector_stats_test", + srcs = ["test_vector_stats_test.cc"], + linkstatic = True, + deps = [ + ":test_vector_cc_proto", + ":test_vector_stats", + "//gutil:testing", + "@com_google_googletest//:gtest_main", + ], +) + +cmd_diff_test( + name = "test_vector_stats_diff_test", + actual_cmd = " | ".join([ + "$(execpath :test_vector_stats_test)", + # Strip unnecessary lines for golden testing. + "sed '1,/^\\[ RUN/d'", # Strip everything up to a line beginning with '[ RUN'. + "sed '/^\\[/d'", # Strip every line beginning with '['. + ]), + expected = "test_vector_stats_test.expected", + tools = [":test_vector_stats_test"], +) + +cc_test( + name = "test_run_validation_test", + srcs = ["test_run_validation_test.cc"], + deps = [ + ":test_run_validation", + ":test_vector_cc_proto", + "//gutil:proto_matchers", + "//gutil:testing", + "//p4_pdpi/packetlib:packetlib_cc_proto", + "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", + ], +) \ No newline at end of file diff --git a/dvaas/test_run_validation.cc b/dvaas/test_run_validation.cc index 32d147b3..55791394 100644 --- a/dvaas/test_run_validation.cc +++ b/dvaas/test_run_validation.cc @@ -121,7 +121,8 @@ bool CompareSwitchOutputs(SwitchOutput actual_output, const Packet& actual_packet = actual_output.packets(i); const Packet& expected_packet = expected_output.packets(i); MessageDifferencer differ; - for (auto* field : params.ignored_fields) differ.IgnoreField(field); + for (auto* field : params.ignored_packetlib_fields) + differ.IgnoreField(field); std::string diff; differ.ReportDifferencesToString(&diff); if (!differ.Compare(expected_packet.parsed(), actual_packet.parsed())) { @@ -129,6 +130,13 @@ bool CompareSwitchOutputs(SwitchOutput actual_output, << Indent(2, diff); return false; } + if (expected_packet.port() != actual_packet.port()) { + *listener << "has packet " << i << " with mismatched ports:\n" + << absl::Substitute(" \"$0\" -> \"$1\"", + expected_packet.port(), + actual_packet.port()); + return false; + } } for (int i = 0; i < expected_output.packet_ins_size(); ++i) { @@ -136,7 +144,8 @@ bool CompareSwitchOutputs(SwitchOutput actual_output, const PacketIn& expected_packet_in = expected_output.packet_ins(i); MessageDifferencer differ; - for (auto* field : params.ignored_fields) differ.IgnoreField(field); + for (auto* field : params.ignored_packetlib_fields) + differ.IgnoreField(field); std::string diff; differ.ReportDifferencesToString(&diff); if (!differ.Compare(expected_packet_in.parsed(), @@ -164,7 +173,7 @@ bool CompareSwitchOutputs(SwitchOutput actual_output, actual_metadata->value())) { *listener << "has packet in " << i << " with mismatched value for metadata field '" - << expected_metadata.name() << "':\n " << Indent(2, diff); + << expected_metadata.name() << "':\n " << Indent(2, diff); return false; } } @@ -351,10 +360,10 @@ PacketTestValidationResult ValidateTestRun( std::string expectation = DescribeExpectation( test_run.test_vector().input(), acceptable_output_characterizations); - if (!diff_params.ignored_fields.empty()) { + if (!diff_params.ignored_packetlib_fields.empty()) { absl::StrAppend( &expectation, "\n (ignoring the field(s) ", - absl::StrJoin(diff_params.ignored_fields, ",", + absl::StrJoin(diff_params.ignored_packetlib_fields, ",", [](std::string* out, const google::protobuf::FieldDescriptor* field) { absl::StrAppend(out, "'", field->name(), "'"); diff --git a/dvaas/test_run_validation.h b/dvaas/test_run_validation.h index 49cb1163..1d78f43d 100644 --- a/dvaas/test_run_validation.h +++ b/dvaas/test_run_validation.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef PINS_DVAAS_test_run_validation_H_ -#define PINS_DVAAS_test_run_validation_H_ +#ifndef PINS_test_run_validation_H_ +#define PINS_test_run_validation_H_ #include #include @@ -32,8 +32,10 @@ namespace dvaas { struct SwitchOutputDiffParams { // Used to skip packet fields where model and switch are known to have // different behavior, which we don't want to test. All FieldDescriptors - // should belong to packetlib::Packet. - std::vector ignored_fields; + // should belong to packetlib::Packet. The ignored fields are ignored both in + // normal (i.e. front-panel) packets and in packet-ins. + std::vector + ignored_packetlib_fields; // Used to skip packet-in metadata where model and switch are known to have // different behavior, which we don't want to test. If a packet-in metadata @@ -57,4 +59,4 @@ absl::Status ValidateTestRuns(const PacketTestRuns& test_runs, } // namespace dvaas -#endif // PINS_DVAAS_test_run_validation_H_ +#endif // PINS_test_run_validation_H_ diff --git a/dvaas/test_run_validation_test.cc b/dvaas/test_run_validation_test.cc new file mode 100644 index 00000000..0a166bf0 --- /dev/null +++ b/dvaas/test_run_validation_test.cc @@ -0,0 +1,136 @@ +#include "dvaas/test_run_validation.h" + +#include "dvaas/test_vector.pb.h" +#include "gmock/gmock.h" +#include "google/protobuf/descriptor.h" +#include "gtest/gtest.h" +#include "gutil/proto_matchers.h" +#include "gutil/testing.h" +#include "p4_pdpi/packetlib/packetlib.pb.h" + +namespace dvaas { +namespace { + +using gutil::EqualsProto; +using testing::HasSubstr; + +TEST(TestRunValidationTest, + PacketFieldIsIgnoredIfAndOnlyIfIncludedInIgnoredPacketlibFields) { + const PacketTestRun test_run = gutil::ParseProtoOrDie(R"pb( + test_vector { + acceptable_outputs { + packets { + port: "1" + parsed { headers { ethernet_header { ethertype: "0x0888" } } } + } + } + } + actual_output { + packets { + port: "1" + parsed { headers { ethernet_header { ethertype: "0x0111" } } } + } + } + )pb"); + + // Without ignoring ethertype, validation must fail. + ASSERT_THAT(ValidateTestRun(test_run).failure().description(), + HasSubstr("modified:")); + + const google::protobuf::FieldDescriptor* ethertype_field_descriptor = + packetlib::EthernetHeader::descriptor()->FindFieldByName("ethertype"); + ASSERT_THAT(ethertype_field_descriptor, testing::NotNull()); + + // Ignoring ethertype, validation must succeed. + ASSERT_THAT(ValidateTestRun( + test_run, + { + .ignored_packetlib_fields = {ethertype_field_descriptor}, + }), + EqualsProto(R"pb()pb")); +} + +TEST(TestRunValidationTest, + PacketInFieldIsIgnoredIfAndOnlyIfIncludedInIgnoredPacketlibFields) { + const PacketTestRun test_run = gutil::ParseProtoOrDie(R"pb( + test_vector { + acceptable_outputs { + packet_ins { + parsed { headers { ethernet_header { ethertype: "0x0888" } } } + } + } + } + actual_output { + packet_ins { + parsed { headers { ethernet_header { ethertype: "0x0111" } } } + } + } + )pb"); + + // Without ignoring ethertype, validation must fail. + ASSERT_THAT(ValidateTestRun(test_run).failure().description(), + HasSubstr("modified:")); + + const google::protobuf::FieldDescriptor* ethertype_field_descriptor = + packetlib::EthernetHeader::descriptor()->FindFieldByName("ethertype"); + ASSERT_THAT(ethertype_field_descriptor, testing::NotNull()); + + // Ignoring ethertype, validation must succeed. + ASSERT_THAT(ValidateTestRun( + test_run, + { + .ignored_packetlib_fields = {ethertype_field_descriptor}, + }), + EqualsProto(R"pb()pb")); +} + +TEST(TestRunValidationTest, + PacketInMetadataIsIgnoredIfAndOnlyIfIncludedInIgnoredPacketinMetadata) { + const PacketTestRun test_run = gutil::ParseProtoOrDie(R"pb( + test_vector { + acceptable_outputs { + packet_ins { + metadata { + name: "target_egress_port" + value { str: "1" } + } + } + } + } + actual_output { + packet_ins { + metadata { + name: "target_egress_port" + value { str: "2" } + } + } + } + )pb"); + + // Without ignoring target_egress_port, validation must fail. + ASSERT_THAT(ValidateTestRun(test_run).failure().description(), + HasSubstr("modified:")); + + // Ignoring target_egress_port, validation must succeed. + ASSERT_THAT( + ValidateTestRun(test_run, + { + .ignored_packet_in_metadata = {"target_egress_port"}, + }), + EqualsProto(R"pb()pb")); +} + +TEST(TestRunValidationTest, + DifferenceBetweenPortsInActualAndAcceptableOutputLeadToFailure) { + // Without ignoring target_egress_port, validation must fail. + ASSERT_THAT(ValidateTestRun(gutil::ParseProtoOrDie(R"pb( + test_vector { acceptable_outputs { packets { port: "1" } } } + actual_output { packets { port: "2" } } + )pb")) + .failure() + .description(), + HasSubstr("mismatched ports:")); +} + +} // namespace +} // namespace dvaas diff --git a/p4_symbolic/bmv2/bmv2.proto b/p4_symbolic/bmv2/bmv2.proto index 1062fc94..1dbe270f 100644 --- a/p4_symbolic/bmv2/bmv2.proto +++ b/p4_symbolic/bmv2/bmv2.proto @@ -78,7 +78,7 @@ message P4Program { repeated Deparser deparsers = 4; // All actions defined in the program, including their names // paramters, and bodies. - // Eventhough actions are typically attached to tables, + // Even though actions are typically attached to tables, // they are defined seperatly in the JSON format, // and the table definitions refer to them by their action id. repeated Action actions = 5; @@ -86,6 +86,8 @@ message P4Program { // including all their tables, and the mapping of tables // to actions via match keys. repeated Pipeline pipelines = 6; + // All errors defined in the program. + repeated google.protobuf.ListValue errors = 7; } // A P4 header type definition. diff --git a/p4_symbolic/bmv2/expected/basic.pb.txt b/p4_symbolic/bmv2/expected/basic.pb.txt index 78bfd67d..f21b6e56 100644 --- a/p4_symbolic/bmv2/expected/basic.pb.txt +++ b/p4_symbolic/bmv2/expected/basic.pb.txt @@ -1109,3 +1109,59 @@ pipelines { source_fragment: "MyEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/hardcoded.pb.txt b/p4_symbolic/bmv2/expected/hardcoded.pb.txt index 2f005d75..ae3760a3 100644 --- a/p4_symbolic/bmv2/expected/hardcoded.pb.txt +++ b/p4_symbolic/bmv2/expected/hardcoded.pb.txt @@ -522,3 +522,59 @@ pipelines { source_fragment: "UselessEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/reflector.pb.txt b/p4_symbolic/bmv2/expected/reflector.pb.txt index f85073d5..22817043 100644 --- a/p4_symbolic/bmv2/expected/reflector.pb.txt +++ b/p4_symbolic/bmv2/expected/reflector.pb.txt @@ -350,3 +350,59 @@ pipelines { source_fragment: "UselessEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/set_invalid.pb.txt b/p4_symbolic/bmv2/expected/set_invalid.pb.txt index 36110f33..9eb33bf5 100644 --- a/p4_symbolic/bmv2/expected/set_invalid.pb.txt +++ b/p4_symbolic/bmv2/expected/set_invalid.pb.txt @@ -644,3 +644,59 @@ pipelines { source_fragment: "UselessEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/table.pb.txt b/p4_symbolic/bmv2/expected/table.pb.txt index 65ddab30..971d0f54 100644 --- a/p4_symbolic/bmv2/expected/table.pb.txt +++ b/p4_symbolic/bmv2/expected/table.pb.txt @@ -362,3 +362,59 @@ pipelines { source_fragment: "UselessEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/table_hit_1.pb.txt b/p4_symbolic/bmv2/expected/table_hit_1.pb.txt index 13e64a2b..b5454af2 100644 --- a/p4_symbolic/bmv2/expected/table_hit_1.pb.txt +++ b/p4_symbolic/bmv2/expected/table_hit_1.pb.txt @@ -860,3 +860,59 @@ pipelines { source_fragment: "MyEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/bmv2/expected/table_hit_2.pb.txt b/p4_symbolic/bmv2/expected/table_hit_2.pb.txt index e0b7a17b..75e37a1a 100644 --- a/p4_symbolic/bmv2/expected/table_hit_2.pb.txt +++ b/p4_symbolic/bmv2/expected/table_hit_2.pb.txt @@ -922,3 +922,59 @@ pipelines { source_fragment: "MyEgress" } } +errors { + values { + string_value: "NoError" + } + values { + number_value: 0 + } +} +errors { + values { + string_value: "PacketTooShort" + } + values { + number_value: 1 + } +} +errors { + values { + string_value: "NoMatch" + } + values { + number_value: 2 + } +} +errors { + values { + string_value: "StackOutOfBounds" + } + values { + number_value: 3 + } +} +errors { + values { + string_value: "HeaderTooShort" + } + values { + number_value: 4 + } +} +errors { + values { + string_value: "ParserTimeout" + } + values { + number_value: 5 + } +} +errors { + values { + string_value: "ParserInvalidArgument" + } + values { + number_value: 6 + } +} diff --git a/p4_symbolic/ir/BUILD.bazel b/p4_symbolic/ir/BUILD.bazel index 0bafd3ff..0b1b73e9 100644 --- a/p4_symbolic/ir/BUILD.bazel +++ b/p4_symbolic/ir/BUILD.bazel @@ -90,6 +90,7 @@ cc_library( "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", ], ) @@ -202,3 +203,18 @@ ir_parsing_test( golden_file = "expected/table_hit_2.txt", p4_program = "//p4_symbolic/testdata:conditional/table_hit_2.p4", ) + +ir_parsing_test( + name = "sai_parser_test", + golden_file = "expected/sai_parser.txt", + p4_deps = ["//p4_symbolic/testdata:common/headers.p4"], + p4_program = "//p4_symbolic/testdata:parser/sai_parser.p4", +) + +ir_parsing_test( + name = "hex_string_transition_test", + golden_file = "expected/hex_string_transition.txt", + p4_deps = ["//p4_symbolic/testdata:common/headers.p4"], + p4_program = "//p4_symbolic/testdata:parser/hex_string_transition.p4", +) + diff --git a/p4_symbolic/ir/expected/hex_string_transition.txt b/p4_symbolic/ir/expected/hex_string_transition.txt new file mode 100644 index 00000000..fb63ca77 --- /dev/null +++ b/p4_symbolic/ir/expected/hex_string_transition.txt @@ -0,0 +1,287 @@ +headers { + key: "ethernet" + value { + name: "ethernet_t" + id: 2 + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 48 + } + } + fields { + key: "ether_type" + value { + name: "ether_type" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 48 + } + } + } +} +headers { + key: "ipv4" + value { + name: "ipv4_t" + id: 3 + fields { + key: "do_not_fragment" + value { + name: "do_not_fragment" + bitwidth: 1 + } + } + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 32 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "frag_offset" + value { + name: "frag_offset" + bitwidth: 13 + } + } + fields { + key: "header_checksum" + value { + name: "header_checksum" + bitwidth: 16 + } + } + fields { + key: "identification" + value { + name: "identification" + bitwidth: 16 + } + } + fields { + key: "ihl" + value { + name: "ihl" + bitwidth: 4 + } + } + fields { + key: "more_fragments" + value { + name: "more_fragments" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 8 + } + } + fields { + key: "reserved" + value { + name: "reserved" + bitwidth: 1 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 32 + } + } + fields { + key: "total_len" + value { + name: "total_len" + bitwidth: 16 + } + } + fields { + key: "ttl" + value { + name: "ttl" + bitwidth: 8 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "scalars" + value { + name: "scalars_0" + } +} +headers { + key: "standard_metadata" + value { + name: "standard_metadata" + id: 1 + fields { + key: "_padding" + value { + name: "_padding" + bitwidth: 3 + } + } + fields { + key: "checksum_error" + value { + name: "checksum_error" + bitwidth: 1 + } + } + fields { + key: "deq_qdepth" + value { + name: "deq_qdepth" + bitwidth: 19 + } + } + fields { + key: "deq_timedelta" + value { + name: "deq_timedelta" + bitwidth: 32 + } + } + fields { + key: "egress_global_timestamp" + value { + name: "egress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "egress_port" + value { + name: "egress_port" + bitwidth: 9 + } + } + fields { + key: "egress_rid" + value { + name: "egress_rid" + bitwidth: 16 + } + } + fields { + key: "egress_spec" + value { + name: "egress_spec" + bitwidth: 9 + } + } + fields { + key: "enq_qdepth" + value { + name: "enq_qdepth" + bitwidth: 19 + } + } + fields { + key: "enq_timestamp" + value { + name: "enq_timestamp" + bitwidth: 32 + } + } + fields { + key: "ingress_global_timestamp" + value { + name: "ingress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "ingress_port" + value { + name: "ingress_port" + bitwidth: 9 + } + } + fields { + key: "instance_type" + value { + name: "instance_type" + bitwidth: 32 + } + } + fields { + key: "mcast_grp" + value { + name: "mcast_grp" + bitwidth: 16 + } + } + fields { + key: "packet_length" + value { + name: "packet_length" + bitwidth: 32 + } + } + fields { + key: "parser_error" + value { + name: "parser_error" + bitwidth: 32 + } + } + fields { + key: "priority" + value { + name: "priority" + bitwidth: 3 + } + } + } +} +pipeline { + key: "egress" + value { + name: "egress" + initial_control: "__END_OF_PIPELINE__" + } +} +pipeline { + key: "ingress" + value { + name: "ingress" + initial_control: "__END_OF_PIPELINE__" + } +} + diff --git a/p4_symbolic/ir/expected/sai_parser.txt b/p4_symbolic/ir/expected/sai_parser.txt new file mode 100644 index 00000000..e118214b --- /dev/null +++ b/p4_symbolic/ir/expected/sai_parser.txt @@ -0,0 +1,1120 @@ +headers { + key: "arp" + value { + name: "arp_t" + id: 12 + fields { + key: "hw_addr_len" + value { + name: "hw_addr_len" + bitwidth: 8 + } + } + fields { + key: "hw_type" + value { + name: "hw_type" + bitwidth: 16 + } + } + fields { + key: "opcode" + value { + name: "opcode" + bitwidth: 16 + } + } + fields { + key: "proto_addr_len" + value { + name: "proto_addr_len" + bitwidth: 8 + } + } + fields { + key: "proto_type" + value { + name: "proto_type" + bitwidth: 16 + } + } + fields { + key: "sender_hw_addr" + value { + name: "sender_hw_addr" + bitwidth: 48 + } + } + fields { + key: "sender_proto_addr" + value { + name: "sender_proto_addr" + bitwidth: 32 + } + } + fields { + key: "target_hw_addr" + value { + name: "target_hw_addr" + bitwidth: 48 + } + } + fields { + key: "target_proto_addr" + value { + name: "target_proto_addr" + bitwidth: 32 + } + } + } +} +headers { + key: "erspan_ethernet" + value { + name: "ethernet_t" + id: 4 + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 48 + } + } + fields { + key: "ether_type" + value { + name: "ether_type" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 48 + } + } + } +} +headers { + key: "erspan_gre" + value { + name: "gre_t" + id: 6 + fields { + key: "acknowledgement_present" + value { + name: "acknowledgement_present" + bitwidth: 1 + } + } + fields { + key: "checksum_present" + value { + name: "checksum_present" + bitwidth: 1 + } + } + fields { + key: "flags" + value { + name: "flags" + bitwidth: 4 + } + } + fields { + key: "key_present" + value { + name: "key_present" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 16 + } + } + fields { + key: "recursion_control" + value { + name: "recursion_control" + bitwidth: 3 + } + } + fields { + key: "routing_present" + value { + name: "routing_present" + bitwidth: 1 + } + } + fields { + key: "sequence_present" + value { + name: "sequence_present" + bitwidth: 1 + } + } + fields { + key: "strict_source_route" + value { + name: "strict_source_route" + bitwidth: 1 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 3 + } + } + } +} +headers { + key: "erspan_ipv4" + value { + name: "ipv4_t" + id: 5 + fields { + key: "do_not_fragment" + value { + name: "do_not_fragment" + bitwidth: 1 + } + } + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 32 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "frag_offset" + value { + name: "frag_offset" + bitwidth: 13 + } + } + fields { + key: "header_checksum" + value { + name: "header_checksum" + bitwidth: 16 + } + } + fields { + key: "identification" + value { + name: "identification" + bitwidth: 16 + } + } + fields { + key: "ihl" + value { + name: "ihl" + bitwidth: 4 + } + } + fields { + key: "more_fragments" + value { + name: "more_fragments" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 8 + } + } + fields { + key: "reserved" + value { + name: "reserved" + bitwidth: 1 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 32 + } + } + fields { + key: "total_len" + value { + name: "total_len" + bitwidth: 16 + } + } + fields { + key: "ttl" + value { + name: "ttl" + bitwidth: 8 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "ethernet" + value { + name: "ethernet_t" + id: 4 + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 48 + } + } + fields { + key: "ether_type" + value { + name: "ether_type" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 48 + } + } + } +} +headers { + key: "icmp" + value { + name: "icmp_t" + id: 9 + fields { + key: "checksum" + value { + name: "checksum" + bitwidth: 16 + } + } + fields { + key: "code" + value { + name: "code" + bitwidth: 8 + } + } + fields { + key: "type" + value { + name: "type" + bitwidth: 8 + } + } + } +} +headers { + key: "ipv4" + value { + name: "ipv4_t" + id: 5 + fields { + key: "do_not_fragment" + value { + name: "do_not_fragment" + bitwidth: 1 + } + } + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 32 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "frag_offset" + value { + name: "frag_offset" + bitwidth: 13 + } + } + fields { + key: "header_checksum" + value { + name: "header_checksum" + bitwidth: 16 + } + } + fields { + key: "identification" + value { + name: "identification" + bitwidth: 16 + } + } + fields { + key: "ihl" + value { + name: "ihl" + bitwidth: 4 + } + } + fields { + key: "more_fragments" + value { + name: "more_fragments" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 8 + } + } + fields { + key: "reserved" + value { + name: "reserved" + bitwidth: 1 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 32 + } + } + fields { + key: "total_len" + value { + name: "total_len" + bitwidth: 16 + } + } + fields { + key: "ttl" + value { + name: "ttl" + bitwidth: 8 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "ipv6" + value { + name: "ipv6_t" + id: 8 + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 128 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "flow_label" + value { + name: "flow_label" + bitwidth: 20 + } + } + fields { + key: "hop_limit" + value { + name: "hop_limit" + bitwidth: 8 + } + } + fields { + key: "next_header" + value { + name: "next_header" + bitwidth: 8 + } + } + fields { + key: "payload_length" + value { + name: "payload_length" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 128 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "packet_in_header" + value { + name: "packet_in_header_t" + id: 2 + fields { + key: "ingress_port" + value { + name: "ingress_port" + bitwidth: 16 + } + } + fields { + key: "target_egress_port" + value { + name: "target_egress_port" + bitwidth: 16 + } + } + } +} +headers { + key: "packet_out_header" + value { + name: "packet_out_header_t" + id: 3 + fields { + key: "egress_port" + value { + name: "egress_port" + bitwidth: 16 + } + } + fields { + key: "submit_to_ingress" + value { + name: "submit_to_ingress" + bitwidth: 1 + } + } + fields { + key: "unused_pad" + value { + name: "unused_pad" + bitwidth: 7 + } + } + } +} +headers { + key: "scalars" + value { + name: "scalars_0" + fields { + key: "_padding_0" + value { + name: "_padding_0" + bitwidth: 1 + } + } + fields { + key: "local_metadata_t._admit_to_l32" + value { + name: "local_metadata_t._admit_to_l32" + bitwidth: 1 + } + } + fields { + key: "local_metadata_t._apply_tunnel_encap_at_egress9" + value { + name: "local_metadata_t._apply_tunnel_encap_at_egress9" + bitwidth: 1 + } + } + fields { + key: "local_metadata_t._l4_dst_port7" + value { + name: "local_metadata_t._l4_dst_port7" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t._l4_src_port6" + value { + name: "local_metadata_t._l4_src_port6" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t._packet_in_ingress_port12" + value { + name: "local_metadata_t._packet_in_ingress_port12" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t._packet_in_target_egress_port13" + value { + name: "local_metadata_t._packet_in_target_egress_port13" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t._packet_rewrites_dst_mac5" + value { + name: "local_metadata_t._packet_rewrites_dst_mac5" + bitwidth: 48 + } + } + fields { + key: "local_metadata_t._packet_rewrites_src_mac4" + value { + name: "local_metadata_t._packet_rewrites_src_mac4" + bitwidth: 48 + } + } + fields { + key: "local_metadata_t._tunnel_encap_dst_ipv611" + value { + name: "local_metadata_t._tunnel_encap_dst_ipv611" + bitwidth: 128 + } + } + fields { + key: "local_metadata_t._tunnel_encap_src_ipv610" + value { + name: "local_metadata_t._tunnel_encap_src_ipv610" + bitwidth: 128 + } + } + fields { + key: "local_metadata_t._vlan_id0" + value { + name: "local_metadata_t._vlan_id0" + bitwidth: 12 + } + } + fields { + key: "local_metadata_t._vlan_id_valid1" + value { + name: "local_metadata_t._vlan_id_valid1" + bitwidth: 1 + } + } + fields { + key: "local_metadata_t._vrf_id3" + value { + name: "local_metadata_t._vrf_id3" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t._wcmp_selector_input8" + value { + name: "local_metadata_t._wcmp_selector_input8" + bitwidth: 16 + } + } + } +} +headers { + key: "standard_metadata" + value { + name: "standard_metadata" + id: 1 + fields { + key: "_padding" + value { + name: "_padding" + bitwidth: 3 + } + } + fields { + key: "checksum_error" + value { + name: "checksum_error" + bitwidth: 1 + } + } + fields { + key: "deq_qdepth" + value { + name: "deq_qdepth" + bitwidth: 19 + } + } + fields { + key: "deq_timedelta" + value { + name: "deq_timedelta" + bitwidth: 32 + } + } + fields { + key: "egress_global_timestamp" + value { + name: "egress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "egress_port" + value { + name: "egress_port" + bitwidth: 9 + } + } + fields { + key: "egress_rid" + value { + name: "egress_rid" + bitwidth: 16 + } + } + fields { + key: "egress_spec" + value { + name: "egress_spec" + bitwidth: 9 + } + } + fields { + key: "enq_qdepth" + value { + name: "enq_qdepth" + bitwidth: 19 + } + } + fields { + key: "enq_timestamp" + value { + name: "enq_timestamp" + bitwidth: 32 + } + } + fields { + key: "ingress_global_timestamp" + value { + name: "ingress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "ingress_port" + value { + name: "ingress_port" + bitwidth: 9 + } + } + fields { + key: "instance_type" + value { + name: "instance_type" + bitwidth: 32 + } + } + fields { + key: "mcast_grp" + value { + name: "mcast_grp" + bitwidth: 16 + } + } + fields { + key: "packet_length" + value { + name: "packet_length" + bitwidth: 32 + } + } + fields { + key: "parser_error" + value { + name: "parser_error" + bitwidth: 32 + } + } + fields { + key: "priority" + value { + name: "priority" + bitwidth: 3 + } + } + } +} +headers { + key: "tcp" + value { + name: "tcp_t" + id: 10 + fields { + key: "ack_no" + value { + name: "ack_no" + bitwidth: 32 + } + } + fields { + key: "checksum" + value { + name: "checksum" + bitwidth: 16 + } + } + fields { + key: "data_offset" + value { + name: "data_offset" + bitwidth: 4 + } + } + fields { + key: "dst_port" + value { + name: "dst_port" + bitwidth: 16 + } + } + fields { + key: "flags" + value { + name: "flags" + bitwidth: 8 + } + } + fields { + key: "res" + value { + name: "res" + bitwidth: 4 + } + } + fields { + key: "seq_no" + value { + name: "seq_no" + bitwidth: 32 + } + } + fields { + key: "src_port" + value { + name: "src_port" + bitwidth: 16 + } + } + fields { + key: "urgent_ptr" + value { + name: "urgent_ptr" + bitwidth: 16 + } + } + fields { + key: "window" + value { + name: "window" + bitwidth: 16 + } + } + } +} +headers { + key: "tunnel_encap_gre" + value { + name: "gre_t" + id: 6 + fields { + key: "acknowledgement_present" + value { + name: "acknowledgement_present" + bitwidth: 1 + } + } + fields { + key: "checksum_present" + value { + name: "checksum_present" + bitwidth: 1 + } + } + fields { + key: "flags" + value { + name: "flags" + bitwidth: 4 + } + } + fields { + key: "key_present" + value { + name: "key_present" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 16 + } + } + fields { + key: "recursion_control" + value { + name: "recursion_control" + bitwidth: 3 + } + } + fields { + key: "routing_present" + value { + name: "routing_present" + bitwidth: 1 + } + } + fields { + key: "sequence_present" + value { + name: "sequence_present" + bitwidth: 1 + } + } + fields { + key: "strict_source_route" + value { + name: "strict_source_route" + bitwidth: 1 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 3 + } + } + } +} +headers { + key: "tunnel_encap_ipv6" + value { + name: "ipv6_t" + id: 8 + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 128 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "flow_label" + value { + name: "flow_label" + bitwidth: 20 + } + } + fields { + key: "hop_limit" + value { + name: "hop_limit" + bitwidth: 8 + } + } + fields { + key: "next_header" + value { + name: "next_header" + bitwidth: 8 + } + } + fields { + key: "payload_length" + value { + name: "payload_length" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 128 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "udp" + value { + name: "udp_t" + id: 11 + fields { + key: "checksum" + value { + name: "checksum" + bitwidth: 16 + } + } + fields { + key: "dst_port" + value { + name: "dst_port" + bitwidth: 16 + } + } + fields { + key: "hdr_length" + value { + name: "hdr_length" + bitwidth: 16 + } + } + fields { + key: "src_port" + value { + name: "src_port" + bitwidth: 16 + } + } + } +} +headers { + key: "vlan" + value { + name: "vlan_t" + id: 7 + fields { + key: "drop_eligible_indicator" + value { + name: "drop_eligible_indicator" + bitwidth: 1 + } + } + fields { + key: "ether_type" + value { + name: "ether_type" + bitwidth: 16 + } + } + fields { + key: "priority_code_point" + value { + name: "priority_code_point" + bitwidth: 3 + } + } + fields { + key: "vlan_id" + value { + name: "vlan_id" + bitwidth: 12 + } + } + } +} +pipeline { + key: "egress" + value { + name: "egress" + initial_control: "__END_OF_PIPELINE__" + } +} +pipeline { + key: "ingress" + value { + name: "ingress" + initial_control: "__END_OF_PIPELINE__" + } +} + diff --git a/p4_symbolic/ir/expected/set_parser_operation.txt b/p4_symbolic/ir/expected/set_parser_operation.txt new file mode 100644 index 00000000..834b535e --- /dev/null +++ b/p4_symbolic/ir/expected/set_parser_operation.txt @@ -0,0 +1,449 @@ +headers { + key: "ethernet" + value { + name: "ethernet_t" + id: 2 + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 48 + } + } + fields { + key: "ether_type" + value { + name: "ether_type" + bitwidth: 16 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 48 + } + } + } +} +headers { + key: "ipv4" + value { + name: "ipv4_t" + id: 3 + fields { + key: "do_not_fragment" + value { + name: "do_not_fragment" + bitwidth: 1 + } + } + fields { + key: "dscp" + value { + name: "dscp" + bitwidth: 6 + } + } + fields { + key: "dst_addr" + value { + name: "dst_addr" + bitwidth: 32 + } + } + fields { + key: "ecn" + value { + name: "ecn" + bitwidth: 2 + } + } + fields { + key: "frag_offset" + value { + name: "frag_offset" + bitwidth: 13 + } + } + fields { + key: "header_checksum" + value { + name: "header_checksum" + bitwidth: 16 + } + } + fields { + key: "identification" + value { + name: "identification" + bitwidth: 16 + } + } + fields { + key: "ihl" + value { + name: "ihl" + bitwidth: 4 + } + } + fields { + key: "more_fragments" + value { + name: "more_fragments" + bitwidth: 1 + } + } + fields { + key: "protocol" + value { + name: "protocol" + bitwidth: 8 + } + } + fields { + key: "reserved" + value { + name: "reserved" + bitwidth: 1 + } + } + fields { + key: "src_addr" + value { + name: "src_addr" + bitwidth: 32 + } + } + fields { + key: "total_len" + value { + name: "total_len" + bitwidth: 16 + } + } + fields { + key: "ttl" + value { + name: "ttl" + bitwidth: 8 + } + } + fields { + key: "version" + value { + name: "version" + bitwidth: 4 + } + } + } +} +headers { + key: "scalars" + value { + name: "scalars_0" + fields { + key: "local_metadata_t.dst_mac" + value { + name: "local_metadata_t.dst_mac" + bitwidth: 48 + } + } + fields { + key: "local_metadata_t.ether_type" + value { + name: "local_metadata_t.ether_type" + bitwidth: 16 + } + } + fields { + key: "local_metadata_t.signed_integer1" + value { + name: "local_metadata_t.signed_integer1" + bitwidth: 16 + signed: true + } + } + fields { + key: "local_metadata_t.signed_integer2" + value { + name: "local_metadata_t.signed_integer2" + bitwidth: 16 + signed: true + } + } + fields { + key: "local_metadata_t.src_mac" + value { + name: "local_metadata_t.src_mac" + bitwidth: 48 + } + } + } +} +headers { + key: "standard_metadata" + value { + name: "standard_metadata" + id: 1 + fields { + key: "_padding" + value { + name: "_padding" + bitwidth: 3 + } + } + fields { + key: "checksum_error" + value { + name: "checksum_error" + bitwidth: 1 + } + } + fields { + key: "deq_qdepth" + value { + name: "deq_qdepth" + bitwidth: 19 + } + } + fields { + key: "deq_timedelta" + value { + name: "deq_timedelta" + bitwidth: 32 + } + } + fields { + key: "egress_global_timestamp" + value { + name: "egress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "egress_port" + value { + name: "egress_port" + bitwidth: 9 + } + } + fields { + key: "egress_rid" + value { + name: "egress_rid" + bitwidth: 16 + } + } + fields { + key: "egress_spec" + value { + name: "egress_spec" + bitwidth: 9 + } + } + fields { + key: "enq_qdepth" + value { + name: "enq_qdepth" + bitwidth: 19 + } + } + fields { + key: "enq_timestamp" + value { + name: "enq_timestamp" + bitwidth: 32 + } + } + fields { + key: "ingress_global_timestamp" + value { + name: "ingress_global_timestamp" + bitwidth: 48 + } + } + fields { + key: "ingress_port" + value { + name: "ingress_port" + bitwidth: 9 + } + } + fields { + key: "instance_type" + value { + name: "instance_type" + bitwidth: 32 + } + } + fields { + key: "mcast_grp" + value { + name: "mcast_grp" + bitwidth: 16 + } + } + fields { + key: "packet_length" + value { + name: "packet_length" + bitwidth: 32 + } + } + fields { + key: "parser_error" + value { + name: "parser_error" + bitwidth: 32 + } + } + fields { + key: "priority" + value { + name: "priority" + bitwidth: 3 + } + } + } +} +pipeline { + key: "egress" + value { + name: "egress" + initial_control: "__END_OF_PIPELINE__" + } +} +pipeline { + key: "ingress" + value { + name: "ingress" + initial_control: "__END_OF_PIPELINE__" + } +} +parsers { + key: "parser" + value { + name: "parser" + initial_state: "start" + parse_states { + key: "parse_ipv4" + value { + name: "parse_ipv4" + parser_ops { + extract { + header { + header_name: "ipv4" + } + } + } + transitions { + default_transition { + next_state: "__END_OF_PARSER__" + } + } + } + } + parse_states { + key: "start" + value { + name: "start" + parser_ops { + set { + lvalue { + header_name: "scalars" + field_name: "local_metadata_t.ether_type" + } + lookahead_rvalue { + bitwidth: 16 + } + } + } + parser_ops { + set { + lvalue { + header_name: "scalars" + field_name: "local_metadata_t.signed_integer1" + } + hexstr_rvalue { + value: "0x0001" + negative: true + } + } + } + parser_ops { + set { + lvalue { + header_name: "scalars" + field_name: "local_metadata_t.signed_integer2" + } + hexstr_rvalue { + value: "0x0002" + } + } + } + parser_ops { + extract { + header { + header_name: "ethernet" + } + } + } + parser_ops { + set { + lvalue { + header_name: "scalars" + field_name: "local_metadata_t.dst_mac" + } + field_rvalue { + header_name: "ethernet" + field_name: "dst_addr" + } + } + } + parser_ops { + set { + lvalue { + header_name: "scalars" + field_name: "local_metadata_t.src_mac" + } + expression_rvalue { + binary_expression { + operation: BIT_AND + left { + field_value { + header_name: "ethernet" + field_name: "src_addr" + } + } + right { + hexstr_value { + value: "0xffffffffff00" + } + } + } + } + } + } + transition_key_fields { + field { + header_name: "scalars" + field_name: "local_metadata_t.ether_type" + } + } + transitions { + hex_string_transition { + value: "0x0800" + next_state: "parse_ipv4" + } + } + transitions { + default_transition { + next_state: "__END_OF_PARSER__" + } + } + } + } + } +} + diff --git a/p4_symbolic/ir/ir.h b/p4_symbolic/ir/ir.h index bfab9c4b..b57ea6fe 100644 --- a/p4_symbolic/ir/ir.h +++ b/p4_symbolic/ir/ir.h @@ -20,7 +20,6 @@ #define P4_SYMBOLIC_IR_IR_H_ #include "absl/status/statusor.h" -#include "absl/strings/string_view.h" #include "p4_symbolic/bmv2/bmv2.pb.h" #include "p4_symbolic/ir/ir.pb.h" @@ -31,6 +30,11 @@ namespace ir { // in P4-Symbolic's IR. inline std::string EndOfPipeline() { return "__END_OF_PIPELINE__"; } +// A special parse state name indicating the end of execution in a parser in +// P4-Symbolic's IR. We decided to keep the parser CFG separated from the +// pipeline CFG for the symbolic evaluation. +inline std::string EndOfParser() { return "__END_OF_PARSER__"; } + // For any table application, BMv2 JSON (and P4-Symbolic IR) use a map from // actions that may be executed as a result of table application to the next // table/control that must be evaluated if the corresponding action is executed. diff --git a/p4_symbolic/testdata/common/headers.p4 b/p4_symbolic/testdata/common/headers.p4 new file mode 100644 index 00000000..8804687f --- /dev/null +++ b/p4_symbolic/testdata/common/headers.p4 @@ -0,0 +1,215 @@ +#ifndef P4_SYMBOLIC_TESTDATA_COMMON_HEADERS_P4_ +#define P4_SYMBOLIC_TESTDATA_COMMON_HEADERS_P4_ + +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_IPV6 0x86dd +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_LLDP 0x88cc +#define ETHERTYPE_8021Q 0x8100 + +#define IP_PROTOCOL_TCP 0x06 +#define IP_PROTOCOL_UDP 0x11 +#define IP_PROTOCOL_ICMP 0x01 +#define IP_PROTOCOL_ICMPV6 0x3a +#define IP_PROTOCOLS_GRE 0x2f + +#define GRE_PROTOCOL_ERSPAN 0x88be + +#define ERSPAN_VERSION_TYPE_II 1 + +typedef bit<48> ethernet_addr_t; +typedef bit<32> ipv4_addr_t; +typedef bit<128> ipv6_addr_t; +typedef bit<12> vlan_id_t; +typedef bit<16> ether_type_t; + +// "The VID value 0xFFF is reserved for implementation use; it must not be +// configured or transmitted." (https://en.wikipedia.org/wiki/IEEE_802.1Q). +const vlan_id_t INTERNAL_VLAN_ID = 0xfff; +// "The reserved value 0x000 indicates that the frame does not carry a VLAN ID; +// in this case, the 802.1Q tag specifies only a priority" +// (https://en.wikipedia.org/wiki/IEEE_802.1Q). +const vlan_id_t NO_VLAN_ID = 0x000; + +// --- Intrinsic ports --------------------------------------------------------- + +// Port used for PacketIO. Packets sent to this port go to the CPU. +// Packets received on this port come from the CPU. +#define SAI_P4_CPU_PORT 510 + +// The port used by `mark_to_drop` from v1model.p4. For details, see the +// documentation of `mark_to_drop`. +#define SAI_P4_DROP_PORT 511 + +// -- Translated Types --------------------------------------------------------- + +// BMv2 does not support @p4runtime_translation. + +#ifndef PLATFORM_BMV2 +@p4runtime_translation("", string) +@p4runtime_translation_mappings({ + // The "default VRF", 0, corresponds to the empty string, "", in P4Runtime. + {"", 0}, +}) +#endif +type bit<16> vrf_id_t; + +const vrf_id_t kDefaultVrf = 0; + +#ifndef PLATFORM_BMV2 +@p4runtime_translation("", string) +#endif +type bit<16> port_id_t; + +// -- Protocol headers --------------------------------------------------------- + +#define ETHERNET_HEADER_BYTES 14 + +header ethernet_t { + ethernet_addr_t dst_addr; + ethernet_addr_t src_addr; + ether_type_t ether_type; +} + +header vlan_t { + // Note: Tag Protocol Identifier (TPID) will be parsed as the ether_type of + // the ethernet header. It is technically a part of the vlan header but is + // modeled like this to facilitate parsing and deparsing. + bit<3> priority_code_point; // PCP + bit<1> drop_eligible_indicator; // DEI + vlan_id_t vlan_id; // VID + // Note: The next ether_type will be parsed as part of the vlan + // header. It is technically a part of the ethernet header but is modeled like + // this to facilitate parsing and deparsing. + ether_type_t ether_type; +} + +#define IPV4_HEADER_BYTES 20 + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<6> dscp; // The 6 most significant bits of the diff_serv field. + bit<2> ecn; // The 2 least significant bits of the diff_serv field. + bit<16> total_len; + bit<16> identification; + bit<1> reserved; + bit<1> do_not_fragment; + bit<1> more_fragments; + bit<13> frag_offset; + bit<8> ttl; + bit<8> protocol; + bit<16> header_checksum; + ipv4_addr_t src_addr; + ipv4_addr_t dst_addr; +} + +#define IPV6_HEADER_BYTES 40 + +header ipv6_t { + bit<4> version; + bit<6> dscp; // The 6 most significant bits of the traffic_class field. + bit<2> ecn; // The 2 least significant bits of the traffic_class field. + bit<20> flow_label; + bit<16> payload_length; + bit<8> next_header; + bit<8> hop_limit; + ipv6_addr_t src_addr; + ipv6_addr_t dst_addr; +} + +header udp_t { + bit<16> src_port; + bit<16> dst_port; + bit<16> hdr_length; + bit<16> checksum; +} + +header tcp_t { + bit<16> src_port; + bit<16> dst_port; + bit<32> seq_no; + bit<32> ack_no; + bit<4> data_offset; + bit<4> res; + bit<8> flags; + bit<16> window; + bit<16> checksum; + bit<16> urgent_ptr; +} + +header icmp_t { + bit<8> type; + bit<8> code; + bit<16> checksum; +} + +header arp_t { + bit<16> hw_type; + bit<16> proto_type; + bit<8> hw_addr_len; + bit<8> proto_addr_len; + bit<16> opcode; + bit<48> sender_hw_addr; + bit<32> sender_proto_addr; + bit<48> target_hw_addr; + bit<32> target_proto_addr; +} + +#define GRE_HEADER_BYTES 4 + +header gre_t { + bit<1> checksum_present; + bit<1> routing_present; + bit<1> key_present; + bit<1> sequence_present; + bit<1> strict_source_route; + bit<3> recursion_control; + bit<1> acknowledgement_present; + bit<4> flags; + bit<3> version; + bit<16> protocol; +} + +// -- Packet IO headers -------------------------------------------------------- + +@controller_header("packet_in") +header packet_in_header_t { + // The port the packet ingressed on. + port_id_t ingress_port; + // The initial intended egress port decided for the packet by the pipeline. + port_id_t target_egress_port; +} + +@controller_header("packet_out") +header packet_out_header_t { + // The port this packet should egress out of when `submit_to_ingress == 0`. + // Meaningless when `submit_to_ingress == 1`. + port_id_t egress_port; + // Indicates if the packet should go through the ingress pipeline like a + // dataplane packet, or be sent straight out of the given `egress_port`. + bit<1> submit_to_ingress; + // Padding field to align the header to 8-bit multiple, as required by BMv2. + // Carries no information. + @padding + bit<7> unused_pad; +} + +// -- Preserved Field Lists ---------------------------------------------------- + +// The field list numbers used in @field_list annotations to identify the fields +// that need to be preserved during clone/recirculation/etc. operations. +enum bit<8> PreservedFieldList { + CLONE_I2E_MIRRORING = 8w1, + // We implement packet-in in SAI P4 by using the replication engine to make a + // clone of the punted packet and then send the clone to the controller. But + // the standard metadata of the packet clone will be empty, that's a problem + // because the controller needs to know the ingress port and expected egress + // port of the punted packet. To solve this problem, we save the targeted + // egress port and ingress port of the punted packet in local metadata and use + // clone_preserving_field_list to preserve these local metadata fields when + // cloning the punted packet. + CLONE_I2E_PACKET_IN = 8w2 +}; + +#endif // P4_SYMBOLIC_TESTDATA_COMMON_HEADERS_P4_ diff --git a/p4_symbolic/testdata/parser/default_transition.p4 b/p4_symbolic/testdata/parser/default_transition.p4 new file mode 100644 index 00000000..cd7e1374 --- /dev/null +++ b/p4_symbolic/testdata/parser/default_transition.p4 @@ -0,0 +1,60 @@ +#include +#include "../common/headers.p4" + +struct local_metadata_t { + /* empty */ +} + +struct headers_t { + ethernet_t ethernet; +} + +parser packet_parser(packet_in packet, out headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + state start { + transition parse_ethernet; + } + + state parse_ethernet { + packet.extract(headers.ethernet); + transition accept; + } +} + +control empty_verify_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply {} +} // control empty_verify_checksum + +control ingress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control ingress + +control egress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control egress + +control empty_compute_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply {} +} // control empty_compute_checksum + +control packet_deparser(packet_out packet, in headers_t headers) { + apply { + packet.emit(headers.ethernet); + } +} // control packet_deparser + +V1Switch( + packet_parser(), + empty_verify_checksum(), + ingress(), + egress(), + empty_compute_checksum(), + packet_deparser() +) main; diff --git a/p4_symbolic/testdata/parser/hex_string_transition.p4 b/p4_symbolic/testdata/parser/hex_string_transition.p4 new file mode 100644 index 00000000..5c28ea09 --- /dev/null +++ b/p4_symbolic/testdata/parser/hex_string_transition.p4 @@ -0,0 +1,71 @@ +#include +#include "../common/headers.p4" + +struct local_metadata_t { + /* empty */ +} + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser packet_parser(packet_in packet, out headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + state start { + transition parse_ethernet; + } + + state parse_ethernet { + packet.extract(headers.ethernet); + transition select(headers.ethernet.ether_type) { + 0 &&& 0xfe00: accept; + ETHERTYPE_IPV4: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(headers.ipv4); + transition accept; + } +} + +control empty_verify_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply {} +} // control empty_verify_checksum + +control ingress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control ingress + +control egress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control egress + +control empty_compute_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply {} +} // control empty_compute_checksum + +control packet_deparser(packet_out packet, in headers_t headers) { + apply { + packet.emit(headers.ethernet); + } +} // control packet_deparser + +V1Switch( + packet_parser(), + empty_verify_checksum(), + ingress(), + egress(), + empty_compute_checksum(), + packet_deparser() +) main; + diff --git a/p4_symbolic/testdata/parser/sai_parser.p4 b/p4_symbolic/testdata/parser/sai_parser.p4 new file mode 100644 index 00000000..70de9cc2 --- /dev/null +++ b/p4_symbolic/testdata/parser/sai_parser.p4 @@ -0,0 +1,267 @@ +#include +#include "../common/headers.p4" + +struct headers_t { + // Never extracted during parsing, but serialized during deparsing for packets + // punted to the controller. + packet_in_header_t packet_in_header; + + // PacketOut header; extracted only for packets received from the controller. + packet_out_header_t packet_out_header; + + // ERSPAN headers, not extracted during parsing. + ethernet_t erspan_ethernet; + ipv4_t erspan_ipv4; + gre_t erspan_gre; + + ethernet_t ethernet; + vlan_t vlan; + + // Not extracted during parsing. + ipv6_t tunnel_encap_ipv6; + gre_t tunnel_encap_gre; + + ipv4_t ipv4; + ipv6_t ipv6; + icmp_t icmp; + tcp_t tcp; + udp_t udp; + arp_t arp; +} + +// Header fields rewritten by the ingress pipeline. Rewrites are computed and +// stored in this struct, but actual rewriting is dealyed until the egress +// pipeline so that the original values aren't overridden and get be matched on. +struct packet_rewrites_t { + ethernet_addr_t src_mac; + ethernet_addr_t dst_mac; +} + +// Local metadata for each packet being processed. +struct local_metadata_t { + vlan_id_t vlan_id; + // True iff `vlan_id` is valid. + bool vlan_id_valid; + bool admit_to_l3; + vrf_id_t vrf_id; + packet_rewrites_t packet_rewrites; + bit<16> l4_src_port; + bit<16> l4_dst_port; + bit<16> wcmp_selector_input; + // GRE tunnel encap related fields. + bool apply_tunnel_encap_at_egress; + ipv6_addr_t tunnel_encap_src_ipv6; + ipv6_addr_t tunnel_encap_dst_ipv6; + + // Packet-in related fields, which we can't group into a struct, because BMv2 + // doesn't support passing structs in clone3. + + // The value to be copied into the `ingress_port` field of packet_in_header on + // punted packets. + @field_list(PreservedFieldList.CLONE_I2E_PACKET_IN) + port_id_t packet_in_ingress_port; + // The value to be copied into the `target_egress_port` field of + // packet_in_header on punted packets. + @field_list(PreservedFieldList.CLONE_I2E_PACKET_IN) + port_id_t packet_in_target_egress_port; +} + +parser packet_parser(packet_in packet, out headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + state start { + // Initialize local metadata fields. + local_metadata.vlan_id_valid = false; + local_metadata.vlan_id = 0; + local_metadata.admit_to_l3 = false; + local_metadata.vrf_id = kDefaultVrf; + local_metadata.packet_rewrites.src_mac = 0; + local_metadata.packet_rewrites.dst_mac = 0; + local_metadata.l4_src_port = 0; + local_metadata.l4_dst_port = 0; + local_metadata.wcmp_selector_input = 0; + + transition select(standard_metadata.ingress_port) { + SAI_P4_CPU_PORT: parse_packet_out_header; + _ : parse_ethernet; + } + } + + state parse_packet_out_header { + packet.extract(headers.packet_out_header); + transition parse_ethernet; + } + + state parse_ethernet { + packet.extract(headers.ethernet); + transition select(headers.ethernet.ether_type) { + ETHERTYPE_IPV4: parse_ipv4; + ETHERTYPE_IPV6: parse_ipv6; + ETHERTYPE_ARP: parse_arp; + ETHERTYPE_8021Q: parse_8021q_vlan; + // VLAN double-tagging (ether_type 0x88a8) is not modeled as we do not + // have a use case for it. + _: accept; + } + } + + state parse_8021q_vlan { + packet.extract(headers.vlan); + transition select(headers.vlan.ether_type) { + ETHERTYPE_IPV4: parse_ipv4; + ETHERTYPE_IPV6: parse_ipv6; + ETHERTYPE_ARP: parse_arp; + _: accept; + } + } + + state parse_ipv4 { + packet.extract(headers.ipv4); + transition select(headers.ipv4.protocol) { + IP_PROTOCOL_ICMP: parse_icmp; + IP_PROTOCOL_TCP: parse_tcp; + IP_PROTOCOL_UDP: parse_udp; + _: accept; + } + } + + state parse_ipv6 { + packet.extract(headers.ipv6); + transition select(headers.ipv6.next_header) { + IP_PROTOCOL_ICMPV6: parse_icmp; + IP_PROTOCOL_TCP: parse_tcp; + IP_PROTOCOL_UDP: parse_udp; + _: accept; + } + } + + state parse_tcp { + packet.extract(headers.tcp); + // Normalize TCP port metadata to common port metadata. + local_metadata.l4_src_port = headers.tcp.src_port; + local_metadata.l4_dst_port = headers.tcp.dst_port; + transition accept; + } + + state parse_udp { + packet.extract(headers.udp); + // Normalize UDP port metadata to common port metadata. + local_metadata.l4_src_port = headers.udp.src_port; + local_metadata.l4_dst_port = headers.udp.dst_port; + transition accept; + } + + state parse_icmp { + packet.extract(headers.icmp); + transition accept; + } + + state parse_arp { + packet.extract(headers.arp); + transition accept; + } +} // parser packet_parser + +control verify_ipv4_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply { + verify_checksum(headers.ipv4.isValid(), { + headers.ipv4.version, + headers.ipv4.ihl, + headers.ipv4.dscp, + headers.ipv4.ecn, + headers.ipv4.total_len, + headers.ipv4.identification, + headers.ipv4.reserved, + headers.ipv4.do_not_fragment, + headers.ipv4.more_fragments, + headers.ipv4.frag_offset, + headers.ipv4.ttl, + headers.ipv4.protocol, + headers.ipv4.src_addr, + headers.ipv4.dst_addr + }, headers.ipv4.header_checksum, HashAlgorithm.csum16); + } +} // control verify_ipv4_checksum + +control ingress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control ingress + +control egress(inout headers_t headers, + inout local_metadata_t local_metadata, + inout standard_metadata_t standard_metadata) { + apply {} +} // control egress + +control compute_ipv4_checksum(inout headers_t headers, + inout local_metadata_t local_metadata) { + apply { + update_checksum(headers.erspan_ipv4.isValid(), { + headers.erspan_ipv4.version, + headers.erspan_ipv4.ihl, + headers.erspan_ipv4.dscp, + headers.erspan_ipv4.ecn, + headers.erspan_ipv4.total_len, + headers.erspan_ipv4.identification, + headers.erspan_ipv4.reserved, + headers.erspan_ipv4.do_not_fragment, + headers.erspan_ipv4.more_fragments, + headers.erspan_ipv4.frag_offset, + headers.erspan_ipv4.ttl, + headers.erspan_ipv4.protocol, + headers.erspan_ipv4.src_addr, + headers.erspan_ipv4.dst_addr + }, headers.erspan_ipv4.header_checksum, HashAlgorithm.csum16); + + update_checksum(headers.ipv4.isValid(), { + headers.ipv4.version, + headers.ipv4.ihl, + headers.ipv4.dscp, + headers.ipv4.ecn, + headers.ipv4.total_len, + headers.ipv4.identification, + headers.ipv4.reserved, + headers.ipv4.do_not_fragment, + headers.ipv4.more_fragments, + headers.ipv4.frag_offset, + headers.ipv4.ttl, + headers.ipv4.protocol, + headers.ipv4.src_addr, + headers.ipv4.dst_addr + }, headers.ipv4.header_checksum, HashAlgorithm.csum16); + } +} // control compute_ipv4_checksum + +control packet_deparser(packet_out packet, in headers_t headers) { + apply { + // We always expect the packet_out_header to be invalid at the end of the + // pipeline, so this line has no effect on the output packet. + packet.emit(headers.packet_out_header); + packet.emit(headers.packet_in_header); + packet.emit(headers.erspan_ethernet); + packet.emit(headers.erspan_ipv4); + packet.emit(headers.erspan_gre); + packet.emit(headers.ethernet); + packet.emit(headers.vlan); + packet.emit(headers.tunnel_encap_ipv6); + packet.emit(headers.tunnel_encap_gre); + packet.emit(headers.ipv4); + packet.emit(headers.ipv6); + packet.emit(headers.arp); + packet.emit(headers.icmp); + packet.emit(headers.tcp); + packet.emit(headers.udp); + } +} // control packet_deparser + +V1Switch( + packet_parser(), + verify_ipv4_checksum(), + ingress(), + egress(), + compute_ipv4_checksum(), + packet_deparser() +) main; diff --git a/tests/gnoi/factory_reset_test.cc b/tests/gnoi/factory_reset_test.cc index d823080a..1f42349a 100644 --- a/tests/gnoi/factory_reset_test.cc +++ b/tests/gnoi/factory_reset_test.cc @@ -93,7 +93,7 @@ void TestFactoryResetSuccess(thinkit::Switch& sut, gnoi::factory_reset::StartRequest request; gnoi::factory_reset::StartResponse response; IssueGnoiFactoryResetAndValidateStatus(sut, request, &response); - // TODO: Check the response protobuf. + EXPECT_TRUE(response.has_reset_success()); ValidateStackState(sut, interfaces); } @@ -105,7 +105,9 @@ void TestDuplicateFactoryResetFailure( IssueGnoiFactoryResetAndValidateStatus(sut, request, &response); // Before the switch stack is down, send an immediate duplicate request. IssueGnoiFactoryResetAndValidateStatus(sut, request, &dup_response); - // TODO: Check the response and dup_response protobuf. + EXPECT_TRUE(response.has_reset_success()); + EXPECT_TRUE(dup_response.reset_error().other()); + EXPECT_EQ(dup_response.reset_error().detail(), "Previous reset is ongoing."); ValidateStackState(sut, interfaces); } @@ -115,6 +117,7 @@ void TestGnoiFactoryResetGnoiServerUnreachableFail( gnoi::factory_reset::StartRequest request; gnoi::factory_reset::StartResponse response; IssueGnoiFactoryResetAndValidateStatus(sut, request, &response); + EXPECT_TRUE(response.has_reset_success()); absl::SleepFor(kFactoryResetWaitForDownTime); ASSERT_TRUE(!pins_test::Pingable(sut).ok()) diff --git a/tests/lib/BUILD.bazel b/tests/lib/BUILD.bazel index 7f7b8a37..1e78dc02 100644 --- a/tests/lib/BUILD.bazel +++ b/tests/lib/BUILD.bazel @@ -11,6 +11,9 @@ # 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. + +load("//p4_pdpi/testing:diff_test.bzl", "cmd_diff_test") + package( default_visibility = ["//visibility:public"], licenses = ["notice"], diff --git a/tests/lib/switch_test_setup_helpers.expected b/tests/lib/switch_test_setup_helpers.expected new file mode 100644 index 00000000..47b1aeca --- /dev/null +++ b/tests/lib/switch_test_setup_helpers.expected @@ -0,0 +1,729 @@ +================================================================================ +1,2,some_port -> a_port +Available ports: a_port +================================================================================ +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "router_interface_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +action { + name: "set_port_and_src_mac" + params { + name: "port" + value { + str: "1" + } + } + params { + name: "src_mac" + value { + mac: "00:02:03:04:05:06" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action.params[0].value.str: "1" -> "a_port" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "wcmp_group_table" +matches { + name: "wcmp_group_id" + exact { + str: "group-4294934545" + } +} +action_set { + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-1" + } + } + } + weight: 1 + watch_port: "2" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "some_port" + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action_set.actions[0].watch_port: "2" -> "a_port" +modified: action_set.actions[1].watch_port: "some_port" -> "a_port" + +================================================================================ +1 -> Exactly one of {2,3} +Available ports: 2,3 +================================================================================ +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "router_interface_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +action { + name: "set_port_and_src_mac" + params { + name: "port" + value { + str: "1" + } + } + params { + name: "src_mac" + value { + mac: "00:02:03:04:05:06" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action.params[0].value.str: "1" -> "3" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "wcmp_group_table" +matches { + name: "wcmp_group_id" + exact { + str: "group-4294934545" + } +} +action_set { + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-1" + } + } + } + weight: 1 + watch_port: "1" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "1" + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action_set.actions[0].watch_port: "1" -> "3" +modified: action_set.actions[1].watch_port: "1" -> "3" + +================================================================================ +Unchanged due to only existing ports +Available ports: 2,3 +================================================================================ +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "router_interface_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +action { + name: "set_port_and_src_mac" + params { + name: "port" + value { + str: "2" + } + } + params { + name: "src_mac" + value { + mac: "00:02:03:04:05:06" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "wcmp_group_table" +matches { + name: "wcmp_group_id" + exact { + str: "group-4294934545" + } +} +action_set { + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-1" + } + } + } + weight: 1 + watch_port: "2" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "3" + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +================================================================================ +All unchanged due to no ports +Available ports: 1 +================================================================================ +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "neighbor_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +matches { + name: "neighbor_id" + exact { + str: "fe80::3e28:6dff:fe34:c002" + } +} +action { + name: "set_dst_mac" + params { + name: "dst_mac" + value { + mac: "3c:28:6d:34:c0:02" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "nexthop_table" +matches { + name: "nexthop_id" + exact { + str: "nexthop-1" + } +} +action { + name: "set_nexthop" + params { + name: "router_interface_id" + value { + str: "router-interface-1" + } + } + params { + name: "neighbor_id" + value { + str: "fe80::3e28:6dff:fe34:c002" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "ipv4_table" +matches { + name: "vrf_id" + exact { + str: "vrf-80" + } +} +action { + name: "set_wcmp_group_id" + params { + name: "wcmp_group_id" + value { + str: "group-4294934531" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "ipv6_table" +matches { + name: "vrf_id" + exact { + str: "vrf-80" + } +} +action { + name: "set_wcmp_group_id" + params { + name: "wcmp_group_id" + value { + str: "group-4294934531" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "vrf_table" +matches { + name: "vrf_id" + exact { + str: "vrf-80" + } +} +action { + name: "no_action" +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +================================================================================ +Roughly even number of 1, 2, and 'a_port', with existing 'a_port' and port-less entries unchanged +Available ports: 1,2,a_port +================================================================================ +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "neighbor_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +matches { + name: "neighbor_id" + exact { + str: "fe80::3e28:6dff:fe34:c002" + } +} +action { + name: "set_dst_mac" + params { + name: "dst_mac" + value { + mac: "3c:28:6d:34:c0:02" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "router_interface_table" +matches { + name: "router_interface_id" + exact { + str: "router-interface-1" + } +} +action { + name: "set_port_and_src_mac" + params { + name: "port" + value { + str: "a_port" + } + } + params { + name: "src_mac" + value { + mac: "00:02:03:04:05:06" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +NONE + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "wcmp_group_table" +matches { + name: "wcmp_group_id" + exact { + str: "group-4294934545" + } +} +action_set { + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-1" + } + } + } + weight: 1 + watch_port: "4" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "5" + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action_set.actions[0].watch_port: "4" -> "a_port" +modified: action_set.actions[1].watch_port: "5" -> "2" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "mirror_session_table" +matches { + name: "mirror_session_id" + exact { + str: "mirror-session-201326593" + } +} +action { + name: "mirror_as_ipv4_erspan" + params { + name: "port" + value { + str: "6" + } + } + params { + name: "src_ip" + value { + ipv4: "10.206.196.0" + } + } + params { + name: "dst_ip" + value { + ipv4: "172.20.0.202" + } + } + params { + name: "src_mac" + value { + mac: "00:02:03:04:05:06" + } + } + params { + name: "dst_mac" + value { + mac: "00:1a:11:17:5f:80" + } + } + params { + name: "ttl" + value { + hex_str: "0x40" + } + } + params { + name: "tos" + value { + hex_str: "0x00" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action.params[0].value.str: "6" -> "1" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "l3_admit_table" +matches { + name: "dst_mac" + ternary { + value { + mac: "02:32:0a:ce:c4:04" + } + mask { + mac: "ff:ff:ff:ff:ff:ff" + } + } +} +matches { + name: "in_port" + optional { + value { + str: "7" + } + } +} +priority: 2030 +action { + name: "admit_to_l3" +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: matches[1].optional.value.str: "7" -> "a_port" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "acl_ingress_table" +matches { + name: "is_ipv4" + optional { + value { + hex_str: "0x1" + } + } +} +matches { + name: "ip_protocol" + ternary { + value { + hex_str: "0x11" + } + mask { + hex_str: "0xff" + } + } +} +matches { + name: "l4_dst_port" + ternary { + value { + hex_str: "0x0223" + } + mask { + hex_str: "0xffff" + } + } +} +matches { + name: "in_port" + optional { + value { + str: "8" + } + } +} +priority: 3100 +action { + name: "acl_drop" +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: matches[3].optional.value.str: "8" -> "2" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "acl_pre_ingress_table" +matches { + name: "in_port" + optional { + value { + str: "9" + } + } +} +priority: 1151 +action { + name: "set_vrf" + params { + name: "vrf_id" + value { + str: "vrf-210" + } + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: matches[0].optional.value.str: "9" -> "1" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "acl_egress_table" +matches { + name: "ether_type" + ternary { + value { + hex_str: "0x0800" + } + mask { + hex_str: "" + } + } +} +matches { + name: "ip_protocol" + ternary { + value { + hex_str: "0x11" + } + mask { + hex_str: "0xff" + } + } +} +matches { + name: "l4_dst_port" + ternary { + value { + hex_str: "0x0223" + } + mask { + hex_str: "0xffff" + } + } +} +matches { + name: "out_port" + optional { + value { + str: "10" + } + } +} +priority: 3101 +action { + name: "acl_drop" +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: matches[3].optional.value.str: "10" -> "2" + +-- ORIGINAL ENTRY -------------------------------------------------------------- +table_name: "wcmp_group_table" +matches { + name: "wcmp_group_id" + exact { + str: "group-4294934545" + } +} +action_set { + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-1" + } + } + } + weight: 1 + watch_port: "11" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "12" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "13" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "14" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "15" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "16" + } + actions { + action { + name: "set_nexthop_id" + params { + name: "nexthop_id" + value { + str: "nexthop-2" + } + } + } + weight: 1 + watch_port: "17" + } +} +-- MODIFICATIONS --------------------------------------------------------------- +modified: action_set.actions[0].watch_port: "11" -> "1" +modified: action_set.actions[1].watch_port: "12" -> "a_port" +modified: action_set.actions[2].watch_port: "13" -> "2" +modified: action_set.actions[3].watch_port: "14" -> "1" +modified: action_set.actions[4].watch_port: "15" -> "a_port" +modified: action_set.actions[5].watch_port: "16" -> "2" +modified: action_set.actions[6].watch_port: "17" -> "1" +