diff --git a/tests/forwarding/BUILD.bazel b/tests/forwarding/BUILD.bazel index 8f5f27480..acea86901 100644 --- a/tests/forwarding/BUILD.bazel +++ b/tests/forwarding/BUILD.bazel @@ -434,6 +434,7 @@ cc_library( "//p4_pdpi:ir_cc_proto", "//p4_pdpi:p4_runtime_session", "//p4_pdpi:p4_runtime_session_extras", + "//p4_pdpi/netaddr:ipv4_address", "//p4_pdpi/packetlib", "//p4_pdpi/packetlib:packetlib_cc_proto", "//tests/lib:p4info_helper", diff --git a/tests/forwarding/l3_admit_test.h b/tests/forwarding/l3_admit_test.h index 82d08d3e3..7335f84a8 100644 --- a/tests/forwarding/l3_admit_test.h +++ b/tests/forwarding/l3_admit_test.h @@ -18,6 +18,7 @@ #include #include +#include "gmock/gmock.h" #include "gutil/status_matchers.h" #include "lib/gnmi/gnmi_helper.h" #include "lib/gnmi/openconfig.pb.h" @@ -25,10 +26,11 @@ #include "p4_pdpi/ir.pb.h" #include "p4_pdpi/p4_runtime_session.h" #include "p4_pdpi/p4_runtime_session_extras.h" +#include "proto/gnmi/gnmi.grpc.pb.h" +#include "proto/gnmi/gnmi.pb.h" #include "tests/lib/switch_test_setup_helpers.h" #include "thinkit/mirror_testbed.h" #include "thinkit/mirror_testbed_fixture.h" -#include "gmock/gmock.h" namespace pins { diff --git a/tests/integration/system/nsf/traffic_helpers/otg_helper.cc b/tests/integration/system/nsf/traffic_helpers/otg_helper.cc index b22885d1c..33abb767d 100644 --- a/tests/integration/system/nsf/traffic_helpers/otg_helper.cc +++ b/tests/integration/system/nsf/traffic_helpers/otg_helper.cc @@ -285,6 +285,7 @@ absl::Status OtgHelper::ValidateTraffic(const Testbed &testbed, metrics_req.mutable_metrics_request()->set_choice( otg::MetricsRequest::Choice::flow); + metrics_req.mutable_metrics_request()->mutable_flow(); RETURN_IF_ERROR(gutil::GrpcStatusToAbslStatus( stub->GetMetrics(&metrics_ctx, metrics_req, &metrics_res))); diff --git a/tests/packet_capture/packet_capture_test.cc b/tests/packet_capture/packet_capture_test.cc index 99a2bf78e..bc1c8841d 100644 --- a/tests/packet_capture/packet_capture_test.cc +++ b/tests/packet_capture/packet_capture_test.cc @@ -14,6 +14,7 @@ #include "tests/packet_capture/packet_capture_test.h" +#include #include #include #include @@ -22,6 +23,8 @@ #include "absl/container/flat_hash_map.h" #include "absl/flags/declare.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/status/statusor.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -29,11 +32,18 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "absl/types/optional.h" -#include "glog/logging.h" +#include "dvaas/dataplane_validation.h" +#include "dvaas/test_vector.h" +#include "dvaas/test_vector.pb.h" +#include "dvaas/validation_result.h" +#include "gmock/gmock.h" +#include "google/protobuf/descriptor.h" +#include "gtest/gtest.h" #include "gutil/collections.h" #include "gutil/status.h" #include "lib/gnmi/gnmi_helper.h" #include "lib/gnmi/openconfig.pb.h" +#include "net/google::protobuf/contrib/fixtures/proto-fixture-repository.h" #include "p4/config/v1/p4info.pb.h" #include "p4/v1/p4runtime.pb.h" #include "p4_pdpi/ir.h" @@ -42,7 +52,9 @@ #include "p4_pdpi/p4_runtime_session_extras.h" #include "p4_pdpi/packetlib/packetlib.h" #include "p4_pdpi/packetlib/packetlib.pb.h" +#include "p4_pdpi/string_encodings/decimal_string.h" #include "p4_pdpi/string_encodings/hex_string.h" +#include "p4_pdpi/ternary.h" #include "proto/gnmi/gnmi.pb.h" #include "sai_p4/instantiations/google/instantiations.h" #include "sai_p4/instantiations/google/sai_pd.pb.h" @@ -53,8 +65,6 @@ #include "thinkit/mirror_testbed.h" #include "thinkit/proto/generic_testbed.pb.h" #include "thinkit/switch.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" ABSL_DECLARE_FLAG(std::optional, switch_instantiation); @@ -68,9 +78,9 @@ using pctutil::SutToControlLinks; // on an incoming port to a mirror-to-port using PSAMP encapsulation and // adding a specified Vlan tag. absl::StatusOr> -ConstructEntriesToMirrorTrafficWithVlanTag( - const pdpi::IrP4Info &ir_p4info, const std::string &p4rt_src_port_id, - const sai::MirrorSessionParams &mirror_session) { +CreateEntriesToMirrorTrafficWithVlanTag( + const pdpi::IrP4Info& ir_p4info, const std::string& p4rt_src_port_id, + const sai::MirrorSessionParams& mirror_session) { ASSIGN_OR_RETURN( std::vector pi_entities, sai::EntryBuilder() @@ -91,8 +101,8 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { // Setup: the testbed consists of a SUT connected to a control device // that allows us to send and receive packets to/from the SUT. - thinkit::Switch &sut = Testbed().Sut(); - thinkit::Switch &control_device = Testbed().ControlSwitch(); + thinkit::Switch& sut = Testbed().Sut(); + thinkit::Switch& control_device = Testbed().ControlSwitch(); // Configure mirror testbed. std::unique_ptr sut_p4rt_session, @@ -105,9 +115,9 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { pins_test::ConfigureSwitchAndReturnP4RuntimeSession( control_device, std::nullopt, std::nullopt)); - ASSERT_OK_AND_ASSIGN(const P4Info &p4info, + ASSERT_OK_AND_ASSIGN(const P4Info& p4info, pdpi::GetP4Info(*sut_p4rt_session)); - ASSERT_OK_AND_ASSIGN(const P4Info &control_p4info, + ASSERT_OK_AND_ASSIGN(const P4Info& control_p4info, pdpi::GetP4Info(*control_p4rt_session)); ASSERT_OK_AND_ASSIGN(const pdpi::IrP4Info ir_p4info, pdpi::CreateIrP4Info(p4info)); @@ -170,7 +180,7 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { .mirror_encap_udp_dst_port = "0x1283"}; // Install ACL table entry to match on inject port on Control switch // and mirror-to-port on SUT. - ASSERT_OK_AND_ASSIGN(auto entries, ConstructEntriesToMirrorTrafficWithVlanTag( + ASSERT_OK_AND_ASSIGN(auto entries, CreateEntriesToMirrorTrafficWithVlanTag( ir_p4info, kSutIngressPortP4rtId, mirror_session_params)); ASSERT_OK( @@ -209,9 +219,8 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { // Read packets mirrored back to Control switch. std::vector received_packets; EXPECT_OK(control_p4rt_session->HandleNextNStreamMessages( - [&](const p4::v1::StreamMessageResponse &message) { - if (!message.has_packet()) - return false; + [&](const p4::v1::StreamMessageResponse& message) { + if (!message.has_packet()) return false; packetlib::Packet received_packet = packetlib::ParsePacket(message.packet().payload()); received_packets.push_back(received_packet); @@ -225,7 +234,7 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { int mirrored_packets_received = 0; std::optional prev_obs_time, curr_obs_time; std::optional prev_sequence, curr_sequence; - for (const packetlib::Packet &received_packet : received_packets) { + for (const packetlib::Packet& received_packet : received_packets) { // Header count sanity check. LOG(INFO) << absl::StrCat("Packet: ", received_packet.DebugString()); if (received_packet.headers().size() != 6) { @@ -233,7 +242,7 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { } // Parse Ethernet header. ASSERT_EQ(received_packet.headers(0).has_ethernet_header(), true); - const auto ð_header = received_packet.headers(0).ethernet_header(); + const auto& eth_header = received_packet.headers(0).ethernet_header(); EXPECT_EQ(eth_header.ethernet_source(), mirror_session_params.mirror_encap_src_mac); EXPECT_EQ(eth_header.ethernet_destination(), @@ -244,14 +253,14 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { mirror_session_params.mirror_encap_vlan_id); // Parse IPv6 header. ASSERT_EQ(received_packet.headers(2).has_ipv6_header(), true); - const auto &ip_header = received_packet.headers(2).ipv6_header(); + const auto& ip_header = received_packet.headers(2).ipv6_header(); EXPECT_EQ(ip_header.ipv6_source(), mirror_session_params.mirror_encap_src_ip); EXPECT_EQ(ip_header.ipv6_destination(), mirror_session_params.mirror_encap_dst_ip); // Parse UDP header. ASSERT_EQ(received_packet.headers(3).has_udp_header(), true); - const auto &udp_header = received_packet.headers(3).udp_header(); + const auto& udp_header = received_packet.headers(3).udp_header(); EXPECT_EQ(udp_header.source_port(), mirror_session_params.mirror_encap_udp_src_port); @@ -271,7 +280,7 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { prev_sequence = curr_sequence; // Parse PSAMP header. ASSERT_EQ(received_packet.headers(5).has_psamp_header(), true); - const auto &psamp_header = received_packet.headers(5).psamp_header(); + const auto& psamp_header = received_packet.headers(5).psamp_header(); // Validate observation times increment within expected range. ASSERT_OK_AND_ASSIGN(curr_obs_time, pdpi::HexStringToUint64( psamp_header.observation_time())); @@ -339,5 +348,426 @@ TEST_P(PacketCaptureTestWithoutIxia, PsampEncapsulatedMirroringTest) { ", out_packets_pre: ", out_packets_pre); } -} // anonymous namespace -} // namespace pins_test +using ::google::protobuf::contrib::fixtures::ProtoFixtureRepository; + +struct ControllerPacketCaptureParams { + std::string ingress_port; + std::string egress_port; + // Ingress VLAN IDs to match on. + std::vector ingress_vlan_ids; + // Egress VLAN ID to be set on packets. + int forwarded_packet_vlan_id; + std::string mirror_session_id; +}; + +std::string GetVlanIdHexStr(int val) { + return absl::StrCat("0x", absl::Hex(val, absl::kZeroPad3)); +} + +std::string GetAclMetadataHexStr(int val) { + return absl::StrCat("0x", absl::Hex(val, absl::kZeroPad2)); +} + +// Returns a set of table entries that will cause a switch to match on Ingress +// VLAN ID and Ingress Port and set ACL Metadata and Egress VLAN ID. +absl::StatusOr> CreatePreIngressAclEntries( + const pdpi::IrP4Info& ir_p4info, const std::string& ingress_port, + const std::vector& ingress_vlan_ids, + const int forwarded_packet_vlan_id) { + std::vector entities; + sai::EntryBuilder entry_builder; + for (const int ingress_vlan_id : ingress_vlan_ids) { + ASSIGN_OR_RETURN(std::bitset ingress_vlan_id_bitset, + pdpi::HexStringToBitset( + GetVlanIdHexStr(ingress_vlan_id))); + entry_builder.AddPreIngressAclEntrySettingVlanAndAclMetadata( + GetVlanIdHexStr(forwarded_packet_vlan_id), + /*set ingress vlan id as acl metadata*/ + GetAclMetadataHexStr(ingress_vlan_id), + sai::AclPreIngressVlanTableMatchFields{ + .vlan_id = pdpi::Ternary>( + ingress_vlan_id_bitset), + .in_port = ingress_port, + }, + /*priority=*/1); + } + ASSIGN_OR_RETURN( + std::vector builder_entities, + entry_builder.LogPdEntries().GetDedupedPiEntities(ir_p4info)); + entities.insert(entities.end(), builder_entities.begin(), + builder_entities.end()); + return entities; +} + +// Returns a set of table entries that will cause a switch to match on ACL +// metadata and mirror all packets on an incoming port to a mirror-to-port +// using PSAMP encapsulation and adding a specified Vlan tag. +absl::StatusOr> +CreateEntriesToMatchOnAclMetadataAndMirrorTrafficAndRedirectToPort( + const pdpi::IrP4Info& ir_p4info, + const sai::MirrorSessionParams& mirror_session_params, + const std::vector& ingress_vlan_ids, const std::string& egress_port, + const std::string& mirror_session_id) { + std::vector pi_entities; + ASSIGN_OR_RETURN(std::vector builder_entities, + sai::EntryBuilder() + .AddDisableIngressVlanChecksEntry() + .AddMirrorSessionTableEntry(mirror_session_params) + .LogPdEntries() + .GetDedupedPiEntities(ir_p4info)); + pi_entities.insert(pi_entities.end(), builder_entities.begin(), + builder_entities.end()); + for (const int ingress_vlan_id : ingress_vlan_ids) { + /* Set ACL metadata to be the ingress VLAN ID. */ + ASSIGN_OR_RETURN(std::bitset acl_metadata, + pdpi::HexStringToBitset( + GetAclMetadataHexStr(ingress_vlan_id))); + ASSIGN_OR_RETURN( + std::vector pre_ingress_acl_entries, + sai::EntryBuilder() + .AddIngressAclEntryMirroringAndRedirectingToPort( + egress_port, mirror_session_id, + sai::MirrorAndRedirectMatchFields{ + .acl_metadata = + pdpi::Ternary>( + acl_metadata), + }, + /*priority=*/1) + .LogPdEntries() + .GetDedupedPiEntities(ir_p4info)); + pi_entities.insert(pi_entities.end(), pre_ingress_acl_entries.begin(), + pre_ingress_acl_entries.end()); + } + + return pi_entities; +} + +packetlib::Packet ParsePacketAndPadToMinimumSize( + const ProtoFixtureRepository& repo, absl::string_view packet_pb) { + packetlib::Packet packet = repo.ParseTextOrDie(packet_pb); + CHECK_OK(packetlib::PadPacketToMinimumSize(packet)); + return packet; +} + +absl::StatusOr> +CreateControllerPacketCaptureTestVectors( + const ControllerPacketCaptureParams& params, + const sai::MirrorSessionParams& mirror_session_params) { + // Test packets injected and expected results. + std::vector test_vectors; + + for (int i = 0; i < params.ingress_vlan_ids.size(); ++i) { + dvaas::PacketTestVector test_vector; + ProtoFixtureRepository repo; + + ASSIGN_OR_RETURN(int mirror_port, pdpi::DecimalStringToInt( + mirror_session_params.monitor_port)); + + std::string mirror_port_hex = + absl::StrCat("0x", absl::Hex(mirror_port, absl::kZeroPad4)); + repo.RegisterValue("@ingress_port", ""); + + repo.RegisterValue("@egress_port", params.egress_port); + repo.RegisterValue("@mirror_port_hex", mirror_port_hex); + repo.RegisterValue("@mirror_port", mirror_session_params.monitor_port); + repo.RegisterValue("@ingress_vlan_id", + GetVlanIdHexStr(params.ingress_vlan_ids[i])); + repo.RegisterValue("@mirror_ethernet_source", + mirror_session_params.mirror_encap_src_mac); + repo.RegisterValue("@mirror_ethernet_destination", + mirror_session_params.mirror_encap_dst_mac); + repo.RegisterValue("@mirror_vlan_id", + mirror_session_params.mirror_encap_vlan_id); + repo.RegisterValue("@mirror_encap_udp_src_port", + mirror_session_params.mirror_encap_udp_src_port); + repo.RegisterValue("@mirror_encap_udp_dst_port", + mirror_session_params.mirror_encap_udp_dst_port); + repo.RegisterValue("@mirror_encap_ip_src", + mirror_session_params.mirror_encap_src_ip); + repo.RegisterValue("@mirror_encap_ip_dst", + mirror_session_params.mirror_encap_dst_ip); + repo.RegisterValue("@ttl", "0x10"); + repo.RegisterValue("@payload", + dvaas::MakeTestPacketTagFromUniqueId( + i, + "SwitchCapturesControlPacketsWithVlanTagAn" + "dRedirectsToPortAndMirrorsPackets")); + // Build headers. + repo.RegisterSnippetOrDie("@ethernet", R"pb( + ethernet_header { + ethernet_destination: "08:00:20:86:35:4b" + ethernet_source: "00:1a:11:17:5f:80" + ethertype: "0x8100" + } + )pb") + .RegisterSnippetOrDie("@vlan", R"pb( + vlan_header { + priority_code_point: "0x0", + drop_eligible_indicator: "0x0", + vlan_identifier: @ingress_vlan_id, + ethertype: "0x0800" + } + )pb") + .RegisterSnippetOrDie("@ipv4", R"pb( + ipv4_header { + version: "0x4" + dscp: "0x00" + ecn: "0x0" + # total_length: filled in automatically. + identification: "0xaafb" + flags: "0x2" + fragment_offset: "0x0000" + ttl: @ttl + protocol: "0x01" + # checksum: filled in automatically + ipv4_source: "10.0.0.1" + ipv4_destination: "10.0.0.2" + } + )pb") + .RegisterSnippetOrDie("@ipv6", R"pb( + ipv6_header { + version: "0x6" + dscp: "0x00" + ecn: "0x0" + flow_label: "0x00000" + # payload_length: filled in automatically. + next_header: "0x11" + hop_limit: "0x00" + ipv6_source: @mirror_encap_ip_src + ipv6_destination: @mirror_encap_ip_dst + } + )pb") + .RegisterSnippetOrDie("@icmp", R"pb( + icmp_header { type: "0x00" code: "0x00" rest_of_header: "0x1e600000" } + )pb") + .RegisterSnippetOrDie("@udp", R"pb( + udp_header { + source_port: @mirror_encap_udp_src_port + destination_port: @mirror_encap_udp_dst_port + # length: filled in automatically + # checksum: filled in automatically + } + )pb") + .RegisterSnippetOrDie("@ipfix", R"pb( + ipfix_header { + version: "0x000a" + # length: filled in automatically + export_time: "0x00002edf" + sequence_number: "0x00000000" + observation_domain_id: "0x00000000" + } + )pb") + .RegisterSnippetOrDie("@psamp_header", R"pb( + psamp_header { + template_id: "0x0000" + # length: filled in automatically + observation_time: "0x00002edf27a5cb40" + flowset: "0xe72d" + next_hop_index: "0x0000" + epoch: "0x0000" + ingress_port: "0x0000" + egress_port: @mirror_port_hex + user_meta_field: "0x0000" + dlb_id: "0x00" + } + )pb") + .RegisterMessage("@input_packet", + ParsePacketAndPadToMinimumSize(repo, + R"pb( + headers: @ethernet + headers: @vlan + headers: @ipv4 + headers: @icmp + payload: @payload + )pb")); + + // Build up acceptable_outputs string, to account for each replica. + dvaas::SwitchOutput expected_output; + *expected_output.add_packets() = + repo.RegisterValue("@egress_port", params.egress_port) + .RegisterMessage( + "@output_packet", ParsePacketAndPadToMinimumSize(repo, R"pb( + headers: @ethernet { ethernet_header { ethertype: "0x0800" } } + headers: @ipv4 + headers: @icmp + payload: @payload + )pb")) + .ParseTextOrDie(R"pb( + port: @egress_port + parsed: @output_packet + )pb"); + *expected_output.add_packets() = + repo.RegisterValue("@egress_port", mirror_session_params.monitor_port) + .RegisterMessage( + "@output_packet", ParsePacketAndPadToMinimumSize(repo, R"pb( + headers: @ethernet { + ethernet_header { + ethernet_destination: @mirror_ethernet_destination + ethernet_source: @mirror_ethernet_source + ethertype: "0x8100" + } + } + headers: @vlan { + vlan_header { + vlan_identifier: @mirror_vlan_id + ethertype: "0x86dd" + } + } + headers: @ipv6 + headers: @udp + headers: @ipfix + headers: @psamp_header + payload: @payload + )pb")) + .ParseTextOrDie(R"pb( + port: @egress_port + parsed: @output_packet + )pb"); + + test_vector = repo.RegisterMessage("@expected_output", expected_output) + .ParseTextOrDie(R"pb( + input { + type: DATAPLANE + packet { port: @ingress_port parsed: @input_packet } + } + acceptable_outputs: @expected_output + )pb"); + test_vector.mutable_input()->set_type( + dvaas::SwitchInput::SUBMIT_TO_INGRESS); + test_vectors.push_back(test_vector); + } + return test_vectors; +} + +TEST_P(PacketCaptureTestWithoutIxia, + SwitchCapturesControlPacketWithVlanTagAndRedirectsToPort) { + const int kPortsToUseInTest = 3; + + dvaas::DataplaneValidationParams dvaas_params = GetParam().validation_params; + thinkit::MirrorTestbed& testbed = + GetParam().testbed_interface->GetMirrorTestbed(); + + // Initialize the connection, clear all entities, and (for the SUT) push + // P4Info. + ASSERT_OK_AND_ASSIGN( + auto sut_p4rt_session, + pins_test::ConfigureSwitchAndReturnP4RuntimeSession( + testbed.Sut(), + /*gnmi_config=*/std::nullopt, GetParam().sut_p4info)); + + ASSERT_OK_AND_ASSIGN(auto sut_ir_p4info, + pdpi::GetIrP4Info(*sut_p4rt_session)); + ASSERT_OK(pdpi::ClearEntities(*sut_p4rt_session)); + + // Collect port IDs. + // Get SUT and control ports to test on. + ASSERT_OK_AND_ASSIGN(auto gnmi_stub, testbed.Sut().CreateGnmiStub()); + ASSERT_OK_AND_ASSIGN(std::vector sut_port_ids, + GetNUpInterfacePortIds(*gnmi_stub, kPortsToUseInTest)); + + const std::string kMirrorSessionId = "psamp_mirror"; + const ControllerPacketCaptureParams controller_packet_capture_params = { + .ingress_port = absl::StrCat(GetParam().cpu_port_id), + .egress_port = sut_port_ids[0], + .ingress_vlan_ids = GetParam().vlans_to_be_tested, + .forwarded_packet_vlan_id = 4095, + .mirror_session_id = kMirrorSessionId, + }; + + ASSERT_OK_AND_ASSIGN( + std::vector acl_entities, + CreatePreIngressAclEntries( + sut_ir_p4info, controller_packet_capture_params.ingress_port, + controller_packet_capture_params.ingress_vlan_ids, + controller_packet_capture_params.forwarded_packet_vlan_id)); + ASSERT_OK(pdpi::InstallPiEntities(sut_p4rt_session.get(), sut_ir_p4info, + acl_entities)); + + // Configure mirror session attributes. + const sai::MirrorSessionParams mirror_session_params = + sai::MirrorSessionParams{ + .mirror_session_id = kMirrorSessionId, + .monitor_port = sut_port_ids[1], + .monitor_backup_port = sut_port_ids[1], + .mirror_encap_src_mac = "00:00:00:22:22:22", + .mirror_encap_dst_mac = "00:00:00:44:44:44", + .mirror_encap_vlan_id = "0x0fe", + .mirror_encap_src_ip = "2222:2222:2222:2222:2222:2222:2222:2222", + .mirror_encap_dst_ip = "4444:4444:4444:4444:4444:4444:4444:4444", + .mirror_encap_udp_src_port = "0x08ae", + .mirror_encap_udp_dst_port = "0x1283"}; + // Install ACL table entry to match on inject port on Control switch + // and mirror-to-port on SUT. + ASSERT_OK_AND_ASSIGN( + const std::vector entries, + CreateEntriesToMatchOnAclMetadataAndMirrorTrafficAndRedirectToPort( + sut_ir_p4info, mirror_session_params, + controller_packet_capture_params.ingress_vlan_ids, + controller_packet_capture_params.egress_port, kMirrorSessionId)); + ASSERT_OK( + pdpi::InstallPiEntities(sut_p4rt_session.get(), sut_ir_p4info, entries)); + // Build test vectors. + ASSERT_OK_AND_ASSIGN( + std::vector test_vector, + CreateControllerPacketCaptureTestVectors(controller_packet_capture_params, + mirror_session_params)); + + dvaas_params.packet_test_vector_override = test_vector; + + const google::protobuf::FieldDescriptor* ipfix_header_descriptor = + packetlib::Header::descriptor()->FindFieldByName("ipfix_header"); + if (ipfix_header_descriptor == nullptr) { + FAIL() << "IPFIX header not found in packetlib"; + } + const google::protobuf::FieldDescriptor* psamp_header_descriptor = + packetlib::Header::descriptor()->FindFieldByName("psamp_header"); + if (psamp_header_descriptor == nullptr) { + FAIL() << "PSAMP header not found in packetlib"; + } + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + ipfix_header_descriptor); + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + psamp_header_descriptor); + const google::protobuf::FieldDescriptor* + ipv6_header_payload_length_descriptor = + packetlib::Ipv6Header::descriptor()->FindFieldByName( + "payload_length"); + if (ipv6_header_payload_length_descriptor == nullptr) { + FAIL() << "IPv6 header field payload_length not found in packetlib"; + } + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + ipv6_header_payload_length_descriptor); + const google::protobuf::FieldDescriptor* udp_header_length_descriptor = + packetlib::UdpHeader::descriptor()->FindFieldByName("length"); + if (udp_header_length_descriptor == nullptr) { + FAIL() << "UDP header field length not found in packetlib"; + } + const google::protobuf::FieldDescriptor* udp_header_checksum_descriptor = + packetlib::UdpHeader::descriptor()->FindFieldByName("checksum"); + if (udp_header_checksum_descriptor == nullptr) { + FAIL() << "UDP header field checksum not found in packetlib"; + } + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + udp_header_length_descriptor); + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + udp_header_checksum_descriptor); + const google::protobuf::FieldDescriptor* payload_descriptor = + packetlib::Packet::descriptor()->FindFieldByName("payload"); + if (payload_descriptor == nullptr) { + FAIL() << "Payload field not found in packetlib"; + } + dvaas_params.switch_output_diff_params.ignored_packetlib_fields.push_back( + payload_descriptor); + + // Send test packets. + LOG(INFO) << "Sending test packets."; + ASSERT_OK_AND_ASSIGN( + dvaas::ValidationResult validation_result, + GetParam().validator->ValidateDataplane(testbed, dvaas_params)); + // Validate traffic. + validation_result.LogStatistics(); + EXPECT_OK(validation_result.HasSuccessRateOfAtLeast(1.0)); +} + +} // anonymous namespace +} // namespace pins_test diff --git a/tests/packet_capture/packet_capture_test.h b/tests/packet_capture/packet_capture_test.h index 4342f4ae6..c07b22ec9 100644 --- a/tests/packet_capture/packet_capture_test.h +++ b/tests/packet_capture/packet_capture_test.h @@ -14,26 +14,41 @@ #ifndef PINS_TESTS_PACKET_CAPTURE_PACKET_CAPTURE_TEST_H_ #define PINS_TESTS_PACKET_CAPTURE_PACKET_CAPTURE_TEST_H_ -#include "gutil/status_matchers.h" + +#include +#include +#include +#include + +#include "dvaas/dataplane_validation.h" +#include "gtest/gtest.h" #include "p4_pdpi/packetlib/packetlib.pb.h" +#include "sai_p4/instantiations/google/instantiations.h" #include "thinkit/mirror_testbed.h" #include "thinkit/mirror_testbed_fixture.h" -#include "gtest/gtest.h" namespace pins_test { // Parameters used by tests that don't require an Ixia. -struct ParamsForPacketCaptureTestsWithoutIxia { +struct PacketCaptureTestWithoutIxiaParams { // Using a shared_ptr because parameterized tests require objects to be // copyable. std::shared_ptr testbed_interface; packetlib::Packet test_packet; + std::vector vlans_to_be_tested; // Ingress Packet VLAN IDs to be tested. + uint32_t cpu_port_id; + // If provided, installs the P4Info on the SUT. Otherwise, uses the P4Info + // already on the SUT. + std::optional sut_p4info; + sai::Instantiation sut_instantiation; + std::shared_ptr validator; + dvaas::DataplaneValidationParams validation_params; }; // These tests must be run on a testbed where the SUT is connected // to a "control device" that can send and received packets. class PacketCaptureTestWithoutIxia - : public testing::TestWithParam { -protected: + : public testing::TestWithParam { + protected: void SetUp() override { GetParam().testbed_interface->SetUp(); } thinkit::MirrorTestbed &Testbed() {