From 26f7d133346f0a36bc59764334f1531d9606fa6c Mon Sep 17 00:00:00 2001 From: kishanps Date: Thu, 16 Jan 2025 14:23:56 +0000 Subject: [PATCH] [Comb] Move utilities to common libraries, Pull logic for buffer configuration into helper function, Migrate some users to ReadStreamChannelResponsesAndFinish, Toggle port speed before test, Adding packet, Add tolerance for Queue stats check, Renamed Packet to PacketAtPort, L3 admit tests should choose only ports that are UP & Update L3 Admit Test to not rely on a custom GNMI Config. --- tests/forwarding/BUILD.bazel | 14 +- tests/forwarding/l3_admit_test.cc | 295 +++++++++++++++++------------- tests/forwarding/l3_admit_test.h | 52 ++++-- tests/forwarding/packet_at_port.h | 47 +++++ tests/qos/BUILD.bazel | 2 + tests/qos/cpu_qos_test.cc | 79 ++++---- tests/qos/frontpanel_qos_test.cc | 286 +++++++++++------------------ tests/qos/qos_test_util.cc | 97 ---------- tests/qos/qos_test_util.h | 43 ----- 9 files changed, 413 insertions(+), 502 deletions(-) create mode 100644 tests/forwarding/packet_at_port.h diff --git a/tests/forwarding/BUILD.bazel b/tests/forwarding/BUILD.bazel index 5255b4ec..25f695bc 100644 --- a/tests/forwarding/BUILD.bazel +++ b/tests/forwarding/BUILD.bazel @@ -205,7 +205,6 @@ cc_library( srcs = ["l3_admit_test.cc"], hdrs = ["l3_admit_test.h"], deps = [ - ":mirror_blackbox_test_fixture", ":util", "//gutil:proto", "//gutil:status_matchers", @@ -215,16 +214,17 @@ cc_library( "//p4_pdpi:p4_runtime_session", "//p4_pdpi/packetlib", "//p4_pdpi/packetlib:packetlib_cc_proto", - "//sai_p4/instantiations/google:instantiations", - "//sai_p4/instantiations/google:sai_p4info_cc", "//tests/lib:p4info_helper", "//tests/lib:p4rt_fixed_table_programming_helper", "//tests/lib:packet_in_helper", + "//tests/lib:switch_test_setup_helpers", "//thinkit:mirror_testbed_fixture", + "//thinkit:switch", "@com_github_google_glog//:glog", "@com_github_p4lang_p4runtime//:p4info_cc_proto", "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/time", @@ -348,3 +348,11 @@ cc_library( "@com_google_googletest//:gtest", ], ) + +cc_library( + name = "packet_at_port", + hdrs = [ + "packet_at_port.h", + ], + deps = ["@com_google_absl//absl/strings"], +) diff --git a/tests/forwarding/l3_admit_test.cc b/tests/forwarding/l3_admit_test.cc index 9b50e4cd..2c0449bc 100644 --- a/tests/forwarding/l3_admit_test.cc +++ b/tests/forwarding/l3_admit_test.cc @@ -19,6 +19,7 @@ #include #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" @@ -26,9 +27,7 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "glog/logging.h" -#include "gmock/gmock.h" #include "gutil/proto.h" -#include "gtest/gtest.h" #include "gutil/status_matchers.h" #include "lib/gnmi/gnmi_helper.h" #include "p4/v1/p4runtime.pb.h" @@ -42,6 +41,9 @@ #include "tests/lib/p4rt_fixed_table_programming_helper.h" #include "tests/lib/packet_in_helper.h" #include "thinkit/mirror_testbed_fixture.h" +#include "thinkit/switch.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" namespace pins { namespace { @@ -265,41 +267,63 @@ absl::Status SendUdpPacket(pdpi::P4RuntimeSession& session, return absl::OkStatus(); } +absl::StatusOr> +GetNUpInterfaceIDs(thinkit::Switch &device, int num_interfaces) { + // The test fixture pushes a new config during setup so we give the switch a + // few minutes to converge before failing to report no valid ports. + auto stop_time = absl::Now() + absl::Minutes(3); + absl::StatusOr> result; + do { + ASSIGN_OR_RETURN(auto gnmi_stub, device.CreateGnmiStub()); + result = pins_test::GetNUpInterfacePortIds(*gnmi_stub, num_interfaces); + } while (!result.ok() && absl::Now() < stop_time); + return result; +} + } // namespace -TEST_P(L3AdmitTestFixture, - DISABLED_L3PacketsAreRoutedOnlyWhenMacAddressIsInMyStation) { +TEST_P(L3AdmitTestFixture, L3PacketsAreRoutedOnlyWhenMacAddressIsInMyStation) { + // Get SUT and control ports to test on. + ASSERT_OK_AND_ASSIGN( + auto sut_ports, + GetNUpInterfaceIDs(GetParam().testbed_interface->GetMirrorTestbed().Sut(), + 1)); + ASSERT_OK_AND_ASSIGN( + auto control_ports, + GetNUpInterfaceIDs( + GetParam().testbed_interface->GetMirrorTestbed().ControlSwitch(), 1)); + // Punt all traffic arriving at the control switch, and collect them to verify // forwarding. std::unique_ptr packetio_control = - std::make_unique(&GetControlP4RuntimeSession(), + std::make_unique(control_switch_p4rt_session_.get(), PacketInHelper::NoFilter); ASSERT_OK( - PuntAllPacketsToController(GetControlP4RuntimeSession(), sai::GetIrP4Info(sai::Instantiation::kMiddleblock))); - + PuntAllPacketsToController(*control_switch_p4rt_session_, ir_p4info_)); + // Add an L3 route to enable forwarding. L3Route l3_route{ .vrf_id = "vrf-1", .switch_mac = "00:00:00:00:00:01", .switch_ip = std::make_pair("10.0.0.1", 32), - .peer_port = "1", + .peer_port = sut_ports[0], .peer_mac = "00:00:00:00:00:02", .peer_ip = "fe80::2", .router_interface_id = "rif-1", .nexthop_id = "nexthop-1", }; - ASSERT_OK(AddAndSetDefaultVrf(GetSutP4RuntimeSession(), sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route.vrf_id)); - ASSERT_OK(AddL3Route(GetSutP4RuntimeSession(), sai::GetIrP4Info(sai::Instantiation::kMiddleblock), l3_route)); - + ASSERT_OK( + AddAndSetDefaultVrf(*sut_p4rt_session_, ir_p4info_, l3_route.vrf_id)); + ASSERT_OK(AddL3Route(*sut_p4rt_session_, ir_p4info_, l3_route)); + // Admit only 1 MAC address to the forwaring pipeline. ASSERT_OK(AdmitL3Route( - GetSutP4RuntimeSession(), sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + *sut_p4rt_session_, ir_p4info_, L3AdmitOptions{ .priority = 2070, .dst_mac = std ::make_pair("00:01:02:03:04:05", "FF:FF:FF:FF:FF:FF"), })); - + // Send 2 sets of packets to the switch. The first set of packets should not // match the L3 admit MAC and therefore will be dropped. The second set of // packet should match the L3 admit MAC and therefore get forwarded. @@ -308,21 +332,19 @@ TEST_P(L3AdmitTestFixture, // Send the "bad" packets first to give them the most time. const std::string kBadPayload = "Testing L3 forwarding. This packet should be dropped."; - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, /*dst_mac=*/"00:aa:bb:cc:cc:dd", /*dst_ip=*/"10.0.0.1", kBadPayload)); - + // Then send the "good" packets. const std::string kGoodPayload = "Testing L3 forwarding. This packet should arrive to packet in."; - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, /*dst_mac=*/"00:01:02:03:04:05", /*dst_ip=*/"10.0.0.1", kGoodPayload)); - + absl::Time timeout = absl::Now() + absl::Minutes(1); int good_packet_count = 0; int bad_packet_count = 0; @@ -357,37 +379,42 @@ TEST_P(L3AdmitTestFixture, } TEST_P(L3AdmitTestFixture, L3AdmitCanUseMaskToAllowMultipleMacAddresses) { + // Get SUT and control ports to test on. + ASSERT_OK_AND_ASSIGN( + auto sut_ports, + GetNUpInterfaceIDs(GetParam().testbed_interface->GetMirrorTestbed().Sut(), + 1)); + ASSERT_OK_AND_ASSIGN( + auto control_ports, + GetNUpInterfaceIDs( + GetParam().testbed_interface->GetMirrorTestbed().ControlSwitch(), 1)); + // Punt all traffic arriving at the control switch, and collect them to verify // forwarding. std::unique_ptr packetio_control = - std::make_unique(&GetControlP4RuntimeSession(), + std::make_unique(control_switch_p4rt_session_.get(), PacketInHelper::NoFilter); ASSERT_OK( - PuntAllPacketsToController(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock))); + PuntAllPacketsToController(*control_switch_p4rt_session_, ir_p4info_)); // Add an L3 route to enable forwarding. L3Route l3_route{ .vrf_id = "vrf-1", .switch_mac = "00:00:00:00:00:01", .switch_ip = std::make_pair("10.0.0.1", 32), - .peer_port = "1", + .peer_port = sut_ports[0], .peer_mac = "00:00:00:00:00:02", .peer_ip = "fe80::2", .router_interface_id = "rif-1", .nexthop_id = "nexthop-1", }; - - ASSERT_OK(AddAndSetDefaultVrf(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route.vrf_id)); - ASSERT_OK(AddL3Route(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route)); + ASSERT_OK( + AddAndSetDefaultVrf(*sut_p4rt_session_, ir_p4info_, l3_route.vrf_id)); + ASSERT_OK(AddL3Route(*sut_p4rt_session_, ir_p4info_, l3_route)); // Admit multiple MAC addresses into L3 routing with a single L3 admit rule. ASSERT_OK(AdmitL3Route( - GetSutP4RuntimeSession(), sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + *sut_p4rt_session_, ir_p4info_, L3AdmitOptions{ .priority = 2070, .dst_mac = std ::make_pair("00:01:02:03:00:05", "FF:FF:FF:FF:F0:FF"), @@ -400,9 +427,8 @@ TEST_P(L3AdmitTestFixture, L3AdmitCanUseMaskToAllowMultipleMacAddresses) { "Testing L3 forwarding. This packet should arrive to packet in."; for (int i = 0; i < 5; ++i) { std::string dst_mac = absl::StrFormat("00:01:02:03:%02d:05", i); - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, dst_mac, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, dst_mac, /*dst_ip=*/"10.0.0.1", kGoodPayload)); } @@ -435,42 +461,47 @@ TEST_P(L3AdmitTestFixture, L3AdmitCanUseMaskToAllowMultipleMacAddresses) { EXPECT_EQ(good_packet_count, 5 * kNumberOfTestPacket); } -TEST_P(L3AdmitTestFixture, DISABLED_L3AdmitCanUseInPortToRestrictMacAddresses) { +TEST_P(L3AdmitTestFixture, L3AdmitCanUseInPortToRestrictMacAddresses) { + // Get SUT and control ports to test on. + ASSERT_OK_AND_ASSIGN( + auto sut_ports, + GetNUpInterfaceIDs(GetParam().testbed_interface->GetMirrorTestbed().Sut(), + 1)); + ASSERT_OK_AND_ASSIGN( + auto control_ports, + GetNUpInterfaceIDs( + GetParam().testbed_interface->GetMirrorTestbed().ControlSwitch(), 2)); + // Punt all traffic arriving at the control switch, and collect them to verify // forwarding. std::unique_ptr packetio_control = - std::make_unique(&GetControlP4RuntimeSession(), + std::make_unique(control_switch_p4rt_session_.get(), PacketInHelper::NoFilter); ASSERT_OK( - PuntAllPacketsToController(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock))); + PuntAllPacketsToController(*control_switch_p4rt_session_, ir_p4info_)); // Add an L3 route to enable forwarding. L3Route l3_route{ .vrf_id = "vrf-1", .switch_mac = "00:00:00:00:00:01", .switch_ip = std::make_pair("10.0.0.1", 32), - .peer_port = "1", + .peer_port = sut_ports[0], .peer_mac = "00:00:00:00:00:02", .peer_ip = "fe80::2", .router_interface_id = "rif-1", .nexthop_id = "nexthop-1", }; - ASSERT_OK(AddAndSetDefaultVrf(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route.vrf_id)); - ASSERT_OK(AddL3Route(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route)); + ASSERT_OK( + AddAndSetDefaultVrf(*sut_p4rt_session_, ir_p4info_, l3_route.vrf_id)); + ASSERT_OK(AddL3Route(*sut_p4rt_session_, ir_p4info_, l3_route)); // Admit the MAC addresses only on port XYZ ASSERT_OK(AdmitL3Route( - GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + *sut_p4rt_session_, ir_p4info_, L3AdmitOptions{ .priority = 2070, .dst_mac = std ::make_pair("00:01:02:03:00:05", "FF:FF:FF:FF:F0:FF"), - .in_port = "2", + .in_port = control_ports[0], })); // Send 2 sets of packets to the switch. The first set of packets should not @@ -481,18 +512,16 @@ TEST_P(L3AdmitTestFixture, DISABLED_L3AdmitCanUseInPortToRestrictMacAddresses) { // Send the "bad" packets first to give them the most time. const std::string kBadPayload = "Testing L3 forwarding. This packet should be dropped."; - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[1], kNumberOfTestPacket, /*dst_mac=*/"00:01:02:03:04:05", /*dst_ip=*/"10.0.0.1", kBadPayload)); - + // Then send the "good" packets. const std::string kGoodPayload = "Testing L3 forwarding. This packet should arrive to packet in."; - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"2", kNumberOfTestPacket, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, /*dst_mac=*/"00:01:02:03:04:05", /*dst_ip=*/"10.0.0.1", kGoodPayload)); @@ -531,67 +560,69 @@ TEST_P(L3AdmitTestFixture, DISABLED_L3AdmitCanUseInPortToRestrictMacAddresses) { } TEST_P(L3AdmitTestFixture, L3PacketsCanBeRoutedWithOnlyARouterInterface) { + // Only use 1 port because for the router interface L3 admit behavior to work + // the incomming packet needs to match the outgoing port. + ASSERT_OK_AND_ASSIGN( + auto sut_ports, + GetNUpInterfaceIDs(GetParam().testbed_interface->GetMirrorTestbed().Sut(), + 1)); + // Punt all traffic arriving at the control switch, and collect them to verify // forwarding. std::unique_ptr packetio_control = - std::make_unique(&GetControlP4RuntimeSession(), + std::make_unique(control_switch_p4rt_session_.get(), PacketInHelper::NoFilter); -ASSERT_OK( - PuntAllPacketsToController(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock))); + ASSERT_OK( + PuntAllPacketsToController(*control_switch_p4rt_session_, ir_p4info_)); -// Add an L3 route to enable forwarding, but do not add an explicit L3Admit + // Add an L3 route to enable forwarding, but do not add an explicit L3Admit // rule. -L3Route l3_route{ - .vrf_id = "vrf-1", - .switch_mac = "00:00:00:00:00:01", - .switch_ip = std::make_pair("10.0.0.1", 32), - .peer_port = "1", - .peer_mac = "00:00:00:00:00:02", - .peer_ip = "fe80::2", - .router_interface_id = "rif-1", - .nexthop_id = "nexthop-1", -}; -ASSERT_OK(AddAndSetDefaultVrf( - GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), l3_route.vrf_id)); -ASSERT_OK(AddL3Route(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - l3_route)); - -// Send 1 set of packets to the switch using the switch's MAC address from the -// L3 route. -const int kNumberOfTestPacket = 100; -const std::string kGoodPayload = - "Testing L3 forwarding. This packet should arrive to packet in."; -ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, - /*dst_mac=*/"00:00:00:00:00:01", - /*dst_ip=*/"10.0.0.1", kGoodPayload)); - -absl::Time timeout = absl::Now() + absl::Minutes(1); -int good_packet_count = 0; -while (good_packet_count < kNumberOfTestPacket) { - if (packetio_control->HasPacketInMessage()) { - ASSERT_OK_AND_ASSIGN(p4::v1::StreamMessageResponse response, - packetio_control->GetNextPacketInMessage()); - - // Verify this is the packet we expect. - packetlib::Packet packet_in = - packetlib::ParsePacket(response.packet().payload()); - if (response.update_case() == p4::v1::StreamMessageResponse::kPacket && - absl::StrContains(packet_in.payload(), kGoodPayload)) { - ++good_packet_count; - } else { - LOG(WARNING) << "Unexpected response: " << response.DebugString(); + L3Route l3_route{ + .vrf_id = "vrf-1", + .switch_mac = "00:00:00:00:00:01", + .switch_ip = std::make_pair("10.0.0.1", 32), + .peer_port = sut_ports[0], + .peer_mac = "00:00:00:00:00:02", + .peer_ip = "fe80::2", + .router_interface_id = "rif-1", + .nexthop_id = "nexthop-1", + }; + ASSERT_OK( + AddAndSetDefaultVrf(*sut_p4rt_session_, ir_p4info_, l3_route.vrf_id)); + ASSERT_OK(AddL3Route(*sut_p4rt_session_, ir_p4info_, l3_route)); + + // Send 1 set of packets to the switch using the switch's MAC address from the + // L3 route. + const int kNumberOfTestPacket = 100; + const std::string kGoodPayload = + "Testing L3 forwarding. This packet should arrive to packet in."; + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + sut_ports[0], kNumberOfTestPacket, + /*dst_mac=*/"00:00:00:00:00:01", + /*dst_ip=*/"10.0.0.1", kGoodPayload)); + + absl::Time timeout = absl::Now() + absl::Minutes(1); + int good_packet_count = 0; + while (good_packet_count < kNumberOfTestPacket) { + if (packetio_control->HasPacketInMessage()) { + ASSERT_OK_AND_ASSIGN(p4::v1::StreamMessageResponse response, + packetio_control->GetNextPacketInMessage()); + + // Verify this is the packet we expect. + packetlib::Packet packet_in = + packetlib::ParsePacket(response.packet().payload()); + if (response.update_case() == p4::v1::StreamMessageResponse::kPacket && + absl::StrContains(packet_in.payload(), kGoodPayload)) { + ++good_packet_count; + } else { + LOG(WARNING) << "Unexpected response: " << response.DebugString(); + } } - } - if (absl::Now() > timeout) { - LOG(ERROR) << "Reached timeout waiting on packets to arrive."; - break; - } + if (absl::Now() > timeout) { + LOG(ERROR) << "Reached timeout waiting on packets to arrive."; + break; + } } LOG(INFO) << "Done collecting packets."; @@ -601,20 +632,28 @@ while (good_packet_count < kNumberOfTestPacket) { TEST_P(L3AdmitTestFixture, L3PacketsCanBeClassifiedByDestinationMac) { // Only run this test if the ACL_PRE_INGRESS table supports matching on // DST_MAC. - if (!TableHasMatchField(sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - "acl_pre_ingress_table", "dst_mac")) { + if (!TableHasMatchField(ir_p4info_, "acl_pre_ingress_table", "dst_mac")) { GTEST_SKIP() << "Skipping because ACL_PRE_INGRESS table can not match on DST_MAC."; } + // Get SUT and control ports to test on. + ASSERT_OK_AND_ASSIGN( + auto sut_ports, + GetNUpInterfaceIDs(GetParam().testbed_interface->GetMirrorTestbed().Sut(), + 1)); + ASSERT_OK_AND_ASSIGN( + auto control_ports, + GetNUpInterfaceIDs( + GetParam().testbed_interface->GetMirrorTestbed().ControlSwitch(), 1)); + // Punt all traffic arriving at the control switch, and collect them to verify // forwarding. std::unique_ptr packetio_control = - std::make_unique(&GetControlP4RuntimeSession(), + std::make_unique(control_switch_p4rt_session_.get(), PacketInHelper::NoFilter); ASSERT_OK( - PuntAllPacketsToController(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock))); + PuntAllPacketsToController(*control_switch_p4rt_session_, ir_p4info_)); // This test uses 2 MAC addresses. Both will be admitted to L3 routing, but // only one will get assigned a VRF ID. We expect packets receiving the @@ -623,19 +662,16 @@ TEST_P(L3AdmitTestFixture, L3PacketsCanBeClassifiedByDestinationMac) { std::string vrf_id = "vrf-1"; std::string good_dst_mac = "00:00:00:00:00:03"; std::string drop_dst_mac = "00:00:00:00:00:04"; - ASSERT_OK(AllowVrfTrafficToDstMac(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + ASSERT_OK(AllowVrfTrafficToDstMac(*sut_p4rt_session_, ir_p4info_, good_dst_mac, vrf_id)); ASSERT_OK(AdmitL3Route( - GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + *sut_p4rt_session_, ir_p4info_, L3AdmitOptions{ .priority = 2070, .dst_mac = std ::make_pair(good_dst_mac, "FF:FF:FF:FF:FF:FF"), })); ASSERT_OK(AdmitL3Route( - GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), + *sut_p4rt_session_, ir_p4info_, L3AdmitOptions{ .priority = 2070, .dst_mac = std ::make_pair(drop_dst_mac, "FF:FF:FF:FF:FF:FF"), @@ -646,14 +682,13 @@ TEST_P(L3AdmitTestFixture, L3PacketsCanBeClassifiedByDestinationMac) { .vrf_id = vrf_id, .switch_mac = "00:00:00:00:00:01", .switch_ip = std::make_pair("10.0.0.1", 32), - .peer_port = "1", + .peer_port = sut_ports[0], .peer_mac = "00:00:00:00:00:02", .peer_ip = "fe80::2", .router_interface_id = "rif-1", .nexthop_id = "nexthop-1", }; - ASSERT_OK(AddL3Route(GetSutP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), l3_route)); + ASSERT_OK(AddL3Route(*sut_p4rt_session_, ir_p4info_, l3_route)); // Send 2 set of packets to the switch. One using the expected destination // MAC (gets forwarded), and another using an unexpected destination MAC @@ -665,13 +700,11 @@ TEST_P(L3AdmitTestFixture, L3PacketsCanBeClassifiedByDestinationMac) { "Testing L3 forwarding. This packet should be dropped."; // Send the "bad" packets first to give them the most time. - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, drop_dst_mac, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, drop_dst_mac, /*dst_ip=*/"10.0.0.1", kBadPayload)); - ASSERT_OK(SendUdpPacket(GetControlP4RuntimeSession(), - sai::GetIrP4Info(sai::Instantiation::kMiddleblock), - /*port_id=*/"1", kNumberOfTestPacket, good_dst_mac, + ASSERT_OK(SendUdpPacket(*control_switch_p4rt_session_, ir_p4info_, + control_ports[0], kNumberOfTestPacket, good_dst_mac, /*dst_ip=*/"10.0.0.1", kGoodPayload)); // Wait for all the good packets to get punted back on the control switch. diff --git a/tests/forwarding/l3_admit_test.h b/tests/forwarding/l3_admit_test.h index 631c7bb7..b5a8142e 100644 --- a/tests/forwarding/l3_admit_test.h +++ b/tests/forwarding/l3_admit_test.h @@ -15,28 +15,52 @@ #define PINS_TESTS_FORWARDING_L3_ADMIT_TEST_H_ #include +#include +#include +#include "gutil/status_matchers.h" #include "p4/config/v1/p4info.pb.h" +#include "p4_pdpi/ir.h" #include "p4_pdpi/ir.pb.h" -#include "p4_pdpi/p4_runtime_session.h" -#include "sai_p4/instantiations/google/instantiations.h" -#include "sai_p4/instantiations/google/sai_p4info.h" -#include "tests/forwarding/mirror_blackbox_test_fixture.h" -#include "tests/lib/packet_in_helper.h" +#include "tests/lib/switch_test_setup_helpers.h" #include "thinkit/mirror_testbed_fixture.h" +#include "gmock/gmock.h" namespace pins { -class L3AdmitTestFixture : public pins_test::MirrorBlackboxTestFixture { - protected: - void TearDown() override { - // MirrorBlackboxTestFixture unnecessarily clears tables at TearDown. This - // is not harmful for other tests but is problematic for l3_admit_tests - // since the P4RT session to the controller is closed during the tests (see - // lib/packet_in_helper.h). Therefore, We bypass table clearance in - // TearDown. - MirrorTestbedFixture::TearDown(); +struct L3AdmitTestParams { + thinkit::MirrorTestbedInterface *testbed_interface; + p4::config::v1::P4Info p4info; +}; + +// This test assumes that the switch is set up with a gNMI config. +class L3AdmitTestFixture : public testing::TestWithParam { +protected: + void SetUp() override { + GetParam().testbed_interface->SetUp(); + + // Initialize the connection and clear table entries for the SUT and Control + // switch. + ASSERT_OK_AND_ASSIGN( + std::tie(sut_p4rt_session_, control_switch_p4rt_session_), + pins_test::ConfigureSwitchPairAndReturnP4RuntimeSessionPair( + GetParam().testbed_interface->GetMirrorTestbed().Sut(), + GetParam().testbed_interface->GetMirrorTestbed().ControlSwitch(), + /*gnmi_config=*/std::nullopt, GetParam().p4info)); + + ASSERT_OK_AND_ASSIGN(ir_p4info_, pdpi::CreateIrP4Info(GetParam().p4info)); } + + void TearDown() override { GetParam().testbed_interface->TearDown(); } + + ~L3AdmitTestFixture() override { delete GetParam().testbed_interface; } + + // This test runs on a mirror testbed setup so we open a P4RT connection to + // both switches. + std::unique_ptr sut_p4rt_session_; + std::unique_ptr control_switch_p4rt_session_; + + pdpi::IrP4Info ir_p4info_; }; } // namespace pins diff --git a/tests/forwarding/packet_at_port.h b/tests/forwarding/packet_at_port.h new file mode 100644 index 00000000..42b56bf6 --- /dev/null +++ b/tests/forwarding/packet_at_port.h @@ -0,0 +1,47 @@ +#ifndef PINS_TESTS_FORWARDING_PACKET_H_ +#define PINS_TESTS_FORWARDING_PACKET_H_ + +#include +#include +#include +#include +#include + +#include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" + +namespace pins { + +// A packet, represented by the packet's data and the port that it was +// sent/received on. +struct PacketAtPort { + // TODO Change it to string type port. + int port; + std::string data; + + bool operator==(const PacketAtPort& other) const { + return port == other.port && data == other.data; + } + + bool operator<(const PacketAtPort& other) const { + return std::tie(port, data) < std::tie(other.port, other.data); + } + + template + friend H AbslHashValue(H h, const PacketAtPort& m); +}; + +inline std::ostream& operator<<(std::ostream& os, + const ::pins::PacketAtPort& packet) { + return os << "{port: " << packet.port << " length: " << packet.data.size() + << " data: \"" << absl::BytesToHexString(packet.data) << "\"}"; +} + +template +H AbslHashValue(H h, const PacketAtPort& m) { + return H::combine(std::move(h), m.port, m.data); +} + +} // namespace pins + +#endif // PINS_TESTS_FORWARDING_PACKET_H_ diff --git a/tests/qos/BUILD.bazel b/tests/qos/BUILD.bazel index ca585b1b..27affe5f 100644 --- a/tests/qos/BUILD.bazel +++ b/tests/qos/BUILD.bazel @@ -104,6 +104,7 @@ cc_library( "//lib:ixia_helper_cc_proto", "//lib/gnmi:gnmi_helper", "//lib/utils:json_utils", + "//lib/validator:validator_lib", "//p4_pdpi:ir", "//p4_pdpi:ir_cc_proto", "//p4_pdpi:p4_runtime_session", @@ -119,6 +120,7 @@ cc_library( "//tests/lib:switch_test_setup_helpers", "//thinkit:generic_testbed", "//thinkit:generic_testbed_fixture", + "//thinkit:mirror_testbed", "@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto", "@com_github_p4lang_p4runtime//:p4info_cc_proto", "@com_github_p4lang_p4runtime//:p4runtime_cc_proto", diff --git a/tests/qos/cpu_qos_test.cc b/tests/qos/cpu_qos_test.cc index f9f8256d..d1602726 100644 --- a/tests/qos/cpu_qos_test.cc +++ b/tests/qos/cpu_qos_test.cc @@ -715,6 +715,21 @@ TEST_P(CpuQosTestWithoutIxia, << "for injected test packet: " << packet.DebugString(); initial_cpu_queue_state = cpu_queue_state; } + + // Ensure tha the switch did not punt packets to the controller via P4RT. + ASSERT_OK_AND_ASSIGN(std::vector pi_responses, + sut_p4rt_session->ReadStreamChannelResponsesAndFinish()); + for (const auto &pi_response : pi_responses) { + sai::PacketIn pd_packet; + EXPECT_OK(pdpi::PiPacketInToPd(ir_p4info, pi_response.packet(), &pd_packet)) + << "where packet = " << pi_response.packet().DebugString(); + ADD_FAILURE() << "SUT punted the following packet to the controller " + "via P4Runtime: " + << (pd_packet.ByteSizeLong() == 0 // Translation failed. + ? pi_response.packet().DebugString() + : pd_packet.DebugString()); + } + LOG(INFO) << "-- END OF TEST -----------------------------------------------"; } @@ -840,38 +855,15 @@ TEST_P(CpuQosTestWithoutIxia, PuntToCpuWithVlanTag) { pdpi::PartialPdTableEntryToPiTableEntry(ir_p4info, pd_acl_entry)); ASSERT_OK(pdpi::InstallPiTableEntry(sut_p4rt_session.get(), pi_acl_entry)); - struct VlanTestPacketCounters { - absl::Mutex mutex; - int num_vlan_packets_received ABSL_GUARDED_BY(mutex) = 0; - }; - - VlanTestPacketCounters packet_receive_info; - PacketInReceiver sut_packet_receiver( - *sut_p4rt_session, [&](const p4::v1::StreamMessageResponse pi_response) { - sai::StreamMessageResponse pd_response; - ASSERT_OK(pdpi::PiStreamMessageResponseToPd(ir_p4info, pi_response, - &pd_response)) - << " packet in PI to PD failed: " << pi_response.DebugString(); - ASSERT_TRUE(pd_response.has_packet()) - << " received unexpected stream message for packet in: " - << pd_response.DebugString(); - packetlib::Packet packet = - packetlib::ParsePacket(pd_response.packet().payload()); - EXPECT_EQ(packet.headers(1).vlan_header().vlan_identifier(), - ipv4_packet.headers(1).vlan_header().vlan_identifier()); - absl::MutexLock lock(&packet_receive_info.mutex); - packet_receive_info.num_vlan_packets_received++; - }); - - for (auto test_packet : test_packets) { - { - absl::MutexLock lock(&packet_receive_info.mutex); - packet_receive_info.num_vlan_packets_received = 0; - } + for (packetlib::Packet &test_packet : test_packets) { + // Start from fresh P4RT session. + ASSERT_OK_AND_ASSIGN(sut_p4rt_session, pdpi::P4RuntimeSession::Create(sut)); + // Send packets. + ASSERT_OK(packetlib::PadPacketToMinimumSize(test_packet)); + ASSERT_OK(packetlib::UpdateAllComputedFields(test_packet)); ASSERT_OK_AND_ASSIGN(const std::string raw_packet, packetlib::SerializePacket(test_packet)); - const int kPacketCount = 10; for (int iter = 0; iter < kPacketCount; iter++) { ASSERT_OK(pins::InjectEgressPacket( @@ -880,15 +872,26 @@ TEST_P(CpuQosTestWithoutIxia, PuntToCpuWithVlanTag) { /*packet_delay=*/std::nullopt)); } - ASSERT_OK(pins::TryUpToNTimes(10, /*delay=*/absl::Seconds(1), [&] { - absl::MutexLock lock(&packet_receive_info.mutex); - if (packet_receive_info.num_vlan_packets_received == kPacketCount) { - return absl::OkStatus(); - } - return absl::InternalError(absl::StrCat( - "Received packets: ", packet_receive_info.num_vlan_packets_received, - "Expected packets", kPacketCount)); - })); + // Verify we receive expected packets back. + absl::SleepFor(absl::Seconds(1)); + int num_vlan_packets_received = 0; + ASSERT_OK_AND_ASSIGN( + std::vector pi_responses, + sut_p4rt_session->ReadStreamChannelResponsesAndFinish()); + for (const auto &pi_response : pi_responses) { + sai::StreamMessageResponse pd_response; + ASSERT_OK(pdpi::PiStreamMessageResponseToPd(ir_p4info, pi_response, + &pd_response)) + << " packet in PI to PD failed: " << pi_response.DebugString(); + ASSERT_TRUE(pd_response.has_packet()) + << " received unexpected stream message for packet in: " + << pd_response.DebugString(); + packetlib::Packet punted_packet = + packetlib::ParsePacket(pd_response.packet().payload()); + EXPECT_THAT(punted_packet, EqualsProto(test_packet)); + num_vlan_packets_received += 1; + } + EXPECT_EQ(num_vlan_packets_received, kPacketCount); } LOG(INFO) << "-- END OF TEST -----------------------------------------------"; } diff --git a/tests/qos/frontpanel_qos_test.cc b/tests/qos/frontpanel_qos_test.cc index b690c4d0..df322306 100644 --- a/tests/qos/frontpanel_qos_test.cc +++ b/tests/qos/frontpanel_qos_test.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include // NOLINT #include +#include #include #include "absl/algorithm/container.h" @@ -53,6 +55,7 @@ #include "lib/ixia_helper.h" #include "lib/ixia_helper.pb.h" #include "lib/utils/json_utils.h" +#include "lib/validator/validator_lib.h" #include "p4/v1/p4runtime.pb.h" #include "p4_pdpi/internal/ordered_map.h" #include "p4_pdpi/ir.h" @@ -71,6 +74,7 @@ #include "tests/qos/packet_in_receiver.h" #include "tests/qos/qos_test_util.h" #include "thinkit/generic_testbed.h" +#include "thinkit/mirror_testbed.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -93,22 +97,48 @@ template std::string ToString(const T &t) { return ss.str(); } -// Connects to Ixia on the given testbed and returns a string handle identifying -// the connection (aka "topology ref"). -absl::StatusOr ConnectToIxia(thinkit::GenericTestbed &testbed) { - ASSIGN_OR_RETURN(auto gnmi_stub, testbed.Sut().CreateGnmiStub()); - ASSIGN_OR_RETURN(std::vector ready_links, - GetReadyIxiaLinks(testbed, *gnmi_stub)); - if (ready_links.empty()) { - return gutil::UnavailableErrorBuilder() << "no Ixia-to-SUT link up"; +// Type of an object that performs some cleanup logic in its destructor. +using Cleanup = decltype(absl::Cleanup{std::function()}); + +// Modifies the buffer config of the given `egress_port` such that all ports +// fairly share all space dynamically, and return a `Cleanup` object that +// restores the previous config when the object is destructed. +absl::StatusOr ConfigureFairBufferConfigForPortUntilEndOfScope( + absl::string_view egress_port, gnmi::gNMI::StubInterface &gnmi) { + ASSIGN_OR_RETURN(const std::string kBufferProfileName, + GetBufferAllocationProfileByEgressPort(egress_port, gnmi)); + + // Before we update the buffer config, save the current config and + // prepare to restore it. + ASSIGN_OR_RETURN(const std::string kInitialBufferConfig, + GetBufferAllocationProfileConfig(kBufferProfileName, gnmi)); + Cleanup cleanup = absl::Cleanup(std::function([=, &gnmi] { + EXPECT_OK(UpdateBufferAllocationProfileConfig(kBufferProfileName, + kInitialBufferConfig, gnmi)) + << "failed to restore initial buffer config -- switch config may be " + "corrupted, causing subsequent tests to fail"; + })); + + // Set fair buffer config. + absl::flat_hash_map + buffer_config_by_queue_name; + // TODO: Read queue names from switch instead of + // hard-coding them here. + for (absl::string_view queue_name : + {"LLQ1", "LLQ2", "BE1", "AF1", "AF2", "AF3", "AF4", "NC1"}) { + buffer_config_by_queue_name[queue_name] = BufferParameters{ + .dedicated_buffer = 0, + .use_shared_buffer = true, + .shared_buffer_limit_type = + "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", + .dynamic_limit_scaling_factor = -3, + .shared_static_limit = 0, + }; } - absl::string_view ixia_interface = ready_links[0].ixia_interface; - ASSIGN_OR_RETURN(ixia::IxiaPortInfo ixia_port_info, - ixia::ExtractPortInfo(ixia_interface)); - ASSIGN_OR_RETURN( - std::string ixia_connection_handle, - pins_test::ixia::IxiaConnect(ixia_port_info.hostname, testbed)); - return ixia_connection_handle; + RETURN_IF_ERROR(SetBufferConfigParameters(kBufferProfileName, + buffer_config_by_queue_name, gnmi)); + + return std::move(cleanup); } // Installs the given table `entries` using the given P4Runtime session, @@ -395,6 +425,20 @@ GetIxiaLinks(thinkit::GenericTestbed &testbed, return links; } +// Returns a function that logs port debug information for both switches in a +// mirror testbed if the ports are down. +std::function +MakeLogPortDebugInfoFunction(thinkit::GenericTestbed &testbed, + absl::Span enabled_interfaces) { + return [&testbed, enabled_interfaces] { + if (absl::Status sut_port_status = + pins_test::PortsUp(testbed.Sut(), enabled_interfaces); + !sut_port_status.ok()) { + LOG(WARNING) << sut_port_status; + } + }; +} + // The purpose of this test is to verify that: // - Incoming IP packets are mapped to queues according to their DSCP. // - Queue peak information rates (PIRs) are enforced. @@ -544,12 +588,40 @@ TEST_P(FrontpanelQosTest, FormatJsonBestEffort(updated_scheduler_config))); // Connect to Ixia and fix global parameters. - ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, ConnectToIxia(*testbed)); + ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, + ixia::ConnectToIxia(*testbed)); ASSERT_OK_AND_ASSIGN(const std::string kIxiaSrcPortHandle, ixia::IxiaVport(kIxiaHandle, kIxiaSrcPort, *testbed)); ASSERT_OK_AND_ASSIGN(const std::string kIxiaDstPortHandle, ixia::IxiaVport(kIxiaHandle, kIxiaDstPort, *testbed)); + constexpr int64_t kSpeed400g = 400000000000; + constexpr int64_t kSpeed200g = 200000000000; + // Toggle speed to add coverage for b/246290651. + if (kSutEgressPortSpeedInBitsPerSecond != kSpeed200g) { + ASSERT_OK(SetPortSpeedInBitsPerSecond(PortSpeed(kSpeed200g), kSutEgressPort, + *gnmi_stub)); + ASSERT_OK(SetPortSpeedInBitsPerSecond( + PortSpeed(kSutEgressPortSpeedInBitsPerSecond), kSutEgressPort, + *gnmi_stub)); + } else { + ASSERT_OK(SetPortSpeedInBitsPerSecond(PortSpeed(kSpeed400g), kSutEgressPort, + *gnmi_stub)); + ASSERT_OK(SetPortSpeedInBitsPerSecond( + PortSpeed(kSutEgressPortSpeedInBitsPerSecond), kSutEgressPort, + *gnmi_stub)); + } + + std::vector required_interfaces = {kSutEgressPort}; + // Wait for all enabled interfaces to be up before sending packets. + ASSERT_OK(pins_test::OnFailure( + pins_test::WaitForCondition(pins_test::PortsUp, absl::Minutes(10), + testbed->Sut(), required_interfaces, + /*with_healthz=*/false), + MakeLogPortDebugInfoFunction(*testbed, required_interfaces))) + << "all required ports must be initialized on the SUT before sending " + "test packets"; + // Actual testing -- inject test IPv4 and IPv6 packets for each DSCP, and // check the behavior is as eexpted. constexpr int kMaxDscp = 63; @@ -674,15 +746,18 @@ TEST_P(FrontpanelQosTest, EXPECT_THAT(delta_counters, ResultOf(TotalPacketsForQueue, Ge(kIxiaTrafficStats.num_tx_frames()))); - // Protocol packets such as LLDP can be transmitted via queue during test. - // Add some tolerance to account for these packets. + // Protocol packets such as LLDP/NDv6 can be transmitted via queue during + // test. Add some tolerance to account for these packets. constexpr int kMaxToleratedExtraPackets = 5; EXPECT_THAT( delta_counters, ResultOf(TotalPacketsForQueue, Le(kIxiaTrafficStats.num_tx_frames() + kMaxToleratedExtraPackets))); EXPECT_THAT(delta_counters, Field(&QueueCounters::num_packets_transmitted, - Eq(kIxiaTrafficStats.num_rx_frames()))); + Ge(kIxiaTrafficStats.num_rx_frames()))); + EXPECT_THAT(delta_counters, Field(&QueueCounters::num_packets_transmitted, + Le(kIxiaTrafficStats.num_rx_frames() + + kMaxToleratedExtraPackets))); } } LOG(INFO) << "-- Test done -------------------------------------------------"; @@ -830,83 +905,11 @@ TEST_P(FrontpanelQosTest, WeightedRoundRobinWeightsAreRespected) { "corrupted, causing subsequent test to fail"; }); - // Save Buffer config and restore at end of the test. - ASSERT_OK_AND_ASSIGN( - const std::string kSutEgressPortBufferProfile, - GetBufferAllocationProfileByEgressPort(kSutEgressPort, *gnmi_stub)); - // Before we update the buffer config, save the current config and - // prepare to restore it at the end of the test. - ASSERT_OK_AND_ASSIGN(const std::string kInitialBufferConfig, - GetBufferAllocationProfileConfig( - kSutEgressPortBufferProfile, *gnmi_stub)); - const auto kRestoreBufferConfig = absl::Cleanup([&] { - EXPECT_OK(UpdateBufferAllocationProfileConfig( - kSutEgressPortBufferProfile, kInitialBufferConfig, *gnmi_stub)) - << "failed to restore initial buffer config -- switch config may be " - "corrupted, causing subsequent tests to fail"; - }); - - // Set equal bufer for all queues. - absl::flat_hash_map bufferConfigByQueueName = { - {"LLQ1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"LLQ2", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"BE1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF2", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF3", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF4", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"NC1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - }; - ASSERT_OK(SetBufferConfigParameters(kSutEgressPortBufferProfile, - bufferConfigByQueueName, *gnmi_stub)); + // Configure fair buffer profile (until the end of the test) so we can ignore + // buffer carving effects. + ASSERT_OK_AND_ASSIGN(Cleanup restore_buffer_config, + ConfigureFairBufferConfigForPortUntilEndOfScope( + kSutEgressPort, *gnmi_stub)); // Set lower & upper bounds (CIRs/PIRs) such that: // - Round-robin-scheduled queues are not rate limited. @@ -942,7 +945,8 @@ TEST_P(FrontpanelQosTest, WeightedRoundRobinWeightsAreRespected) { // Connect to Ixia and fix some parameters. LOG(INFO) << "configuring Ixia traffic"; - ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, ConnectToIxia(*testbed)); + ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, + ixia::ConnectToIxia(*testbed)); ASSERT_OK_AND_ASSIGN( const std::string kIxiaMainSrcPortHandle, ixia::IxiaVport(kIxiaHandle, kIxiaMainSrcPort, *testbed)); @@ -1204,87 +1208,16 @@ TEST_P(FrontpanelQosTest, StrictQueuesAreStrictlyPrioritized) { "corrupted, causing subsequent test to fail"; }); - // Save Buffer config and restore at end of the test. - ASSERT_OK_AND_ASSIGN( - const std::string kSutEgressPortBufferProfile, - GetBufferAllocationProfileByEgressPort(kSutEgressPort, *gnmi_stub)); - // Before we update the buffer config, save the current config and - // prepare to restore it at the end of the test. - ASSERT_OK_AND_ASSIGN(const std::string kInitialBufferConfig, - GetBufferAllocationProfileConfig( - kSutEgressPortBufferProfile, *gnmi_stub)); - const auto kRestoreBufferConfig = absl::Cleanup([&] { - EXPECT_OK(UpdateBufferAllocationProfileConfig( - kSutEgressPortBufferProfile, kInitialBufferConfig, *gnmi_stub)) - << "failed to restore initial buffer config -- switch config may be " - "corrupted, causing subsequent tests to fail"; - }); - - // Set equal buffer for all queues. - absl::flat_hash_map bufferConfigByQueueName = { - {"LLQ1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"LLQ2", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"BE1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF2", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF3", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"AF4", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - {"NC1", - {/*.dedicated_buffer =*/0, - /*.use_shared_buffer =*/true, - /*.shared_buffer_type =*/ - "openconfig-qos:DYNAMIC_BASED_ON_SCALING_FACTOR", - /*.dynamic_limit_scaling_factor =*/-3, - /*.shared_static_limit =*/0}}, - }; - ASSERT_OK(SetBufferConfigParameters(kSutEgressPortBufferProfile, - bufferConfigByQueueName, *gnmi_stub)); + // Configure fair buffer profile (until the end of the test) so we can ignore + // buffer carving effects. + ASSERT_OK_AND_ASSIGN(Cleanup restore_buffer_config, + ConfigureFairBufferConfigForPortUntilEndOfScope( + kSutEgressPort, *gnmi_stub)); // Connect to Ixia and fix constant traffic parameters. LOG(INFO) << "connecting to Ixia"; - ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, ConnectToIxia(*testbed)); + ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, + ixia::ConnectToIxia(*testbed)); ASSERT_OK_AND_ASSIGN( const std::string kIxiaMainTrafficSrcPortHandle, ixia::IxiaVport(kIxiaHandle, kIxiaMainTrafficSrcPort, *testbed)); @@ -2066,7 +1999,8 @@ TEST_P(FrontpanelBufferTest, BufferCarving) { // Connect to Ixia and fix endpoints & parameters. LOG(INFO) << "configuring Ixia traffic"; - ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, ConnectToIxia(*testbed)); + ASSERT_OK_AND_ASSIGN(const std::string kIxiaHandle, + ixia::ConnectToIxia(*testbed)); ASSERT_OK_AND_ASSIGN( const std::string kIxiaIpv4SrcPortHandle, ixia::IxiaVport(kIxiaHandle, kIxiaIpv4SrcPort, *testbed)); diff --git a/tests/qos/qos_test_util.cc b/tests/qos/qos_test_util.cc index 67369046..28a3796b 100644 --- a/tests/qos/qos_test_util.cc +++ b/tests/qos/qos_test_util.cc @@ -91,103 +91,6 @@ int64_t TotalPacketsForQueue(const QueueCounters &counters) { return counters.num_packets_dropped + counters.num_packets_transmitted; } -absl::Status SetPortSpeedInBitsPerSecond(const std::string &port_speed, - const std::string &iface, - gnmi::gNMI::StubInterface &gnmi_stub) { - std::string ops_config_path = absl::StrCat( - "interfaces/interface[name=", iface, "]/ethernet/config/port-speed"); - std::string ops_val = - absl::StrCat("{\"openconfig-if-ethernet:port-speed\":", port_speed, "}"); - - RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, ops_config_path, - GnmiSetType::kUpdate, ops_val)); - - return absl::OkStatus(); -} - -absl::StatusOr -GetPortSpeedInBitsPerSecond(const std::string &interface_name, - gnmi::gNMI::StubInterface &gnmi_stub) { - // Map keyed on openconfig speed string to value in bits per second. - // http://ops.openconfig.net/branches/models/master/docs/openconfig-interfaces.html#mod-openconfig-if-ethernet - const auto kPortSpeedTable = - absl::flat_hash_map({ - {"openconfig-if-ethernet:SPEED_100GB", 100000000000}, - {"openconfig-if-ethernet:SPEED_200GB", 200000000000}, - {"openconfig-if-ethernet:SPEED_400GB", 400000000000}, - }); - std::string speed_state_path = - absl::StrCat("interfaces/interface[name=", interface_name, - "]/ethernet/state/port-speed"); - - std::string parse_str = "openconfig-if-ethernet:port-speed"; - ASSIGN_OR_RETURN( - std::string response, - GetGnmiStatePathInfo(&gnmi_stub, speed_state_path, parse_str)); - - auto speed = kPortSpeedTable.find(StripQuotes(response)); - if (speed == kPortSpeedTable.end()) { - return absl::NotFoundError(response); - } - return speed->second; -} - -absl::Status SetPortMtu(int port_mtu, const std::string &interface_name, - gnmi::gNMI::StubInterface &gnmi_stub) { - std::string config_path = absl::StrCat( - "interfaces/interface[name=", interface_name, "]/config/mtu"); - std::string value = absl::StrCat("{\"config:mtu\":", port_mtu, "}"); - - RETURN_IF_ERROR(pins_test::SetGnmiConfigPath(&gnmi_stub, config_path, - GnmiSetType::kUpdate, value)); - - return absl::OkStatus(); -} - -absl::StatusOr CheckLinkUp(const std::string &iface, - gnmi::gNMI::StubInterface &gnmi_stub) { - std::string oper_status_state_path = - absl::StrCat("interfaces/interface[name=", iface, "]/state/oper-status"); - - std::string parse_str = "openconfig-interfaces:oper-status"; - ASSIGN_OR_RETURN( - std::string ops_response, - GetGnmiStatePathInfo(&gnmi_stub, oper_status_state_path, parse_str)); - - return ops_response == "\"UP\""; -} - -// Go over the connections and return vector of connections -// whose links are up. -absl::StatusOr> GetReadyIxiaLinks( - thinkit::GenericTestbed &generic_testbed, - gnmi::gNMI::StubInterface &gnmi_stub) { - std::vector links; - - absl::flat_hash_map interface_info = - generic_testbed.GetSutInterfaceInfo(); - // Loop through the interface_info looking for Ixia/SUT interface pairs, - // checking if the link is up. Add the pair to connections. - for (const auto &[interface, info] : interface_info) { - bool sut_link_up = false; - if (info.interface_modes.contains(thinkit::TRAFFIC_GENERATOR)) - { - ASSIGN_OR_RETURN(sut_link_up, CheckLinkUp(interface, gnmi_stub)); - if (sut_link_up) { - ASSIGN_OR_RETURN(int64_t bit_per_second, - GetPortSpeedInBitsPerSecond(interface, gnmi_stub)); - links.push_back(IxiaLink{ - .ixia_interface = info.peer_interface_name, - .sut_interface = interface, - .sut_interface_bits_per_second = bit_per_second, - }); - } - } - } - - return links; -} - absl::StatusOr> ParseIpv4DscpToQueueMapping(absl::string_view gnmi_config) { // TODO: Actually parse config -- hard-coded for now. diff --git a/tests/qos/qos_test_util.h b/tests/qos/qos_test_util.h index 2227d680..3f46dff9 100644 --- a/tests/qos/qos_test_util.h +++ b/tests/qos/qos_test_util.h @@ -56,49 +56,6 @@ absl::StatusOr GetGnmiQueueCounterWithTimestamp( // Get total packets (transmitted + dropped) for port queue. int64_t TotalPacketsForQueue(const QueueCounters &counters); -// Set port speed using gNMI. -absl::Status SetPortSpeedInBitsPerSecond(const std::string &port_speed, - const std::string &iface, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Get configured port speed. -absl::StatusOr -GetPortSpeedInBitsPerSecond(const std::string &interface_name, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Get configured port speed. -absl::StatusOr GetPortSpeed(const std::string &interface_name, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Set port MTU using gNMI. -absl::Status SetPortMtu(int port_mtu, const std::string &interface_name, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Set a port in loopback mode. -absl::Status SetPortLoopbackMode(bool port_loopback, - absl::string_view interface_name, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Check if switch port link is up. -absl::StatusOr CheckLinkUp(const std::string &iface, - gnmi::gNMI::StubInterface &gnmi_stub); - -// Structure represents a link between SUT and Ixia. -// This is represented by Ixia interface name and the SUT's gNMI interface -// name. -struct IxiaLink { - std::string ixia_interface; - std::string sut_interface; - // Speed of the SUT interface in bits/second. - int64_t sut_interface_bits_per_second = 0; -}; - -// Go over the connections and return vector of connections -// whose links are up. -absl::StatusOr> GetReadyIxiaLinks( - thinkit::GenericTestbed &generic_testbed, - gnmi::gNMI::StubInterface &gnmi_stub); - // Parse IPv4 DSCP to queue mapping from gnmi configuration. absl::StatusOr> ParseIpv4DscpToQueueMapping(absl::string_view gnmi_config);