Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into gnmi_port_int_3.1
  • Loading branch information
divyagayathri-hcl committed Dec 2, 2024
2 parents 06b3291 + 24cb5aa commit 49da018
Show file tree
Hide file tree
Showing 11 changed files with 832 additions and 122 deletions.
44 changes: 44 additions & 0 deletions tests/integration/system/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,47 @@ cc_library(
],
alwayslink = True,
)

cc_library(
name = "packet_forwarding_tests",
testonly = True,
srcs = ["packet_forwarding_tests.cc"],
hdrs = ["packet_forwarding_tests.h"],
deps = [
"//gutil:collections",
"//gutil:status_matchers",
"//gutil:testing",
"//lib/basic_traffic",
"//lib/basic_traffic:basic_p4rt_util",
"//lib/gnmi:gnmi_helper",
"//lib/p4rt:p4rt_programming_context",
"//lib/utils:generic_testbed_utils",
"//p4_pdpi:ir",
"//p4_pdpi:ir_cc_proto",
"//p4_pdpi:p4_runtime_session",
"//p4_pdpi/packetlib",
"//p4_pdpi/packetlib:packetlib_cc_proto",
"//sai_p4/instantiations/google:sai_pd_cc_proto",
"//tests/lib:switch_test_setup_helpers",
"//thinkit:control_device",
"//thinkit:generic_testbed",
"//thinkit:generic_testbed_fixture",
"//thinkit:switch",
"//thinkit/proto:generic_testbed_cc_proto",
"@com_github_gnmi//proto/gnmi:gnmi_cc_grpc_proto",
"@com_github_google_glog//:glog",
"@com_github_p4lang_p4runtime//:p4info_cc_proto",
"@com_github_p4lang_p4runtime//:p4runtime_cc_proto",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/numeric:int128",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest",
],
alwayslink = True,
)
342 changes: 342 additions & 0 deletions tests/integration/system/packet_forwarding_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
// Copyright (c) 2024, Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "tests/integration/system/packet_forwarding_tests.h"

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "absl/flags/flag.h"
#include "absl/numeric/int128.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "gutil/collections.h"
#include "gutil/status.h"
#include "gutil/status_matchers.h"
#include "gutil/testing.h"
#include "lib/basic_traffic/basic_p4rt_util.h"
#include "lib/basic_traffic/basic_traffic.h"
#include "lib/gnmi/gnmi_helper.h"
#include "lib/p4rt/p4rt_programming_context.h"
#include "lib/utils/generic_testbed_utils.h"
#include "p4/config/v1/p4info.pb.h"
#include "p4/v1/p4runtime.pb.h"
#include "p4_pdpi/ir.h"
#include "p4_pdpi/ir.pb.h"
#include "p4_pdpi/p4_runtime_session.h"
#include "p4_pdpi/packetlib/packetlib.h"
#include "p4_pdpi/packetlib/packetlib.pb.h"
#include "proto/gnmi/gnmi.grpc.pb.h"
#include "sai_p4/instantiations/google/sai_pd.pb.h"
#include "tests/lib/switch_test_setup_helpers.h"
#include "thinkit/control_device.h"
#include "thinkit/generic_testbed.h"
#include "thinkit/proto/generic_testbed.pb.h"
#include "thinkit/switch.h"

ABSL_FLAG(bool, push_p4_info, true, "Push P4 info to SUT.");

namespace pins_test {
namespace {

constexpr int kMtu[] = {1500, 5000, 9000};

// Test packet proto message sent from control switch to sut.
constexpr absl::string_view kTestPacket = R"pb(
headers {
ethernet_header {
ethernet_destination: "02:03:04:05:06:07"
ethernet_source: "00:01:02:03:04:05"
ethertype: "0x0800"
}
}
headers {
ipv4_header {
version: "0x4"
ihl: "0x5"
dscp: "0x03"
ecn: "0x0"
identification: "0x0000"
flags: "0x0"
fragment_offset: "0x0000"
ttl: "0x20"
protocol: "0x11"
ipv4_source: "1.2.3.4"
ipv4_destination: "$0"
}
}
headers { udp_header { source_port: "0x0000" destination_port: "0x0000" } }
payload: "Basic L3 test packet")pb";

// Pushes the P4 Info to SUT if the flag push_p4_info is set to true and returns
// the P4 Runtime Session
absl::StatusOr<std::unique_ptr<pdpi::P4RuntimeSession>> P4InfoPush(
const p4::config::v1::P4Info& p4_info, thinkit::GenericTestbed& testbed) {
std::optional<p4::config::v1::P4Info> p4info = std::nullopt;
if (absl::GetFlag(FLAGS_push_p4_info)) {
p4info = p4_info;
}
return ConfigureSwitchAndReturnP4RuntimeSession(
testbed.Sut(), /*gnmi_config=*/std::nullopt, p4info);
}

TEST_P(PacketForwardingTestFixture, PacketForwardingTest) {
thinkit::TestRequirements requirements =
gutil::ParseProtoOrDie<thinkit::TestRequirements>(
R"pb(interface_requirements {
count: 2
interface_mode: CONTROL_INTERFACE
})pb");

ASSERT_OK_AND_ASSIGN(auto testbed, GetTestbedWithRequirements(requirements));
std::vector<InterfaceLink> control_links =
FromTestbed(GetAllControlLinks, *testbed);

ASSERT_OK_AND_ASSIGN(auto stub, testbed->Sut().CreateGnmiStub());
ASSERT_OK_AND_ASSIGN(auto port_id_by_interface,
GetAllInterfaceNameToPortId(*stub));

// Set the `source_link` to the first SUT control link.
const InterfaceLink& source_link = control_links[0];
ASSERT_OK_AND_ASSIGN(
std::string source_port_id_value,
gutil::FindOrStatus(port_id_by_interface, source_link.sut_interface));

// Set the `destination_link` to the second SUT control link.
const InterfaceLink& destination_link = control_links[1];
ASSERT_OK_AND_ASSIGN(std::string destination_port_id_value,
gutil::FindOrStatus(port_id_by_interface,
destination_link.sut_interface));

LOG(INFO) << "Source port: " << source_link.sut_interface
<< " port id: " << source_port_id_value;
LOG(INFO) << "Destination port: " << destination_link.sut_interface
<< " port id: " << destination_port_id_value;

ASSERT_OK_AND_ASSIGN(std::unique_ptr<pdpi::P4RuntimeSession> p4_session,
P4InfoPush(GetParam().p4_info, *testbed));
// Set up a route between the source and destination interfaces.
ASSERT_OK_AND_ASSIGN(auto port_id_from_sut_interface,
GetAllInterfaceNameToPortId(*stub));
ASSERT_OK_AND_ASSIGN(const pdpi::IrP4Info ir_p4info,
pdpi::CreateIrP4Info(GetParam().p4_info));
P4rtProgrammingContext p4rt_context(p4_session.get(),
pdpi::SetMetadataAndSendPiWriteRequest);
ASSERT_OK(basic_traffic::ProgramRoutes(
p4rt_context.GetWriteRequestFunction(), ir_p4info,
port_id_from_sut_interface,
{{.ingress_interface = source_link.sut_interface,
.egress_interface = destination_link.sut_interface}}));

int destination_port_id;
ASSERT_TRUE(
absl::SimpleAtoi(destination_port_id_value, &destination_port_id));

// Make test packet based on destination port ID.
const auto test_packet =
gutil::ParseProtoOrDie<packetlib::Packet>(absl::Substitute(
kTestPacket, basic_traffic::PortIdToIP(destination_port_id)));
ASSERT_OK_AND_ASSIGN(std::string test_packet_data,
packetlib::SerializePacket(test_packet));

absl::Mutex mutex;
std::vector<std::string> received_packets;
static constexpr int kPacketsToSend = 10;
{
ASSERT_OK_AND_ASSIGN(auto finalizer,
testbed.get()->ControlDevice().CollectPackets());

LOG(INFO) << "Sending Packet to " << source_link.peer_interface;
LOG(INFO) << "Test packet data: " << test_packet.DebugString();

for (int i = 0; i < kPacketsToSend; i++) {
// Send packet to SUT.
ASSERT_OK(testbed->ControlDevice().SendPacket(source_link.peer_interface,
test_packet_data))
<< "failed to inject the packet.";
LOG(INFO) << "SendPacket completed";
}
ASSERT_OK(finalizer->HandlePacketsFor(
absl::Seconds(30),
[&](absl::string_view interface, absl::string_view packet) {
if (interface != destination_link.peer_interface) {
return;
}
packetlib::Packet parsed_packet = packetlib::ParsePacket(packet);
if (!absl::StrContains(parsed_packet.payload(),
"Basic L3 test packet")) {
return;
}
absl::MutexLock lock(&mutex);
received_packets.push_back(std::string(packet));
}));
}
EXPECT_EQ(received_packets.size(), kPacketsToSend);
}

using InterfaceCounters = absl::flat_hash_map<std::string, Counters>;

TEST_P(PacketForwardingTestFixture, AllPortsPacketForwardingTest) {
thinkit::TestRequirements requirements =
gutil::ParseProtoOrDie<thinkit::TestRequirements>(
R"pb(interface_requirements {
count: 2
interface_mode: CONTROL_INTERFACE
})pb");

ASSERT_OK_AND_ASSIGN(auto testbed, GetTestbedWithRequirements(requirements));
ASSERT_OK_AND_ASSIGN(auto gnmi_stub, testbed->Sut().CreateGnmiStub());

std::vector<std::string> sut_interfaces =
GetSutInterfaces(FromTestbed(GetAllControlLinks, *testbed));
ASSERT_OK_AND_ASSIGN(std::unique_ptr<pdpi::P4RuntimeSession> p4_session,
P4InfoPush(GetParam().p4_info, *testbed));
ASSERT_OK_AND_ASSIGN(const pdpi::IrP4Info ir_p4info,
pdpi::CreateIrP4Info(GetParam().p4_info));

// Collect counters before the test.
ASSERT_OK_AND_ASSIGN(InterfaceCounters pretraffic_counters,
GetAllInterfaceCounters(*gnmi_stub));

const auto test_packet =
gutil::ParseProtoOrDie<packetlib::Packet>(kTestPacket);
ASSERT_OK_AND_ASSIGN(
auto statistics,
basic_traffic::SendTraffic(*testbed, p4_session.get(), ir_p4info,
basic_traffic::AllToAll(sut_interfaces),
{test_packet}, absl::Minutes(5)));

// Collate traffic statistics to dump to artifacts.
std::string packet_statistics_csv =
"ingress_interface,egress_interface,packets_sent,packets_received\n";
for (const basic_traffic::TrafficStatistic& statistic : statistics) {
absl::StrAppend(&packet_statistics_csv,
absl::StrJoin({statistic.interfaces.ingress_interface,
statistic.interfaces.egress_interface,
absl::StrCat(statistic.packets_sent),
absl::StrCat(statistic.packets_received)},
","),
"\n");
EXPECT_EQ(statistic.packets_sent, statistic.packets_received);
EXPECT_EQ(statistic.packets_routed_incorrectly, 0);
}
EXPECT_OK(testbed->Environment().StoreTestArtifact("traffic_statistics.csv",
packet_statistics_csv));

// Calculate counter differences and dump to artifacts.
std::string sut_counters_csv = "interface,in_packets,out_packets\n";
ASSERT_OK_AND_ASSIGN(InterfaceCounters posttraffic_counters,
GetAllInterfaceCounters(*gnmi_stub));
for (const std::string& interface : sut_interfaces) {
const Counters& pre = pretraffic_counters[interface];
const Counters& post = posttraffic_counters[interface];
absl::StrAppend(
&sut_counters_csv,
absl::StrJoin({interface, absl::StrCat(post.in_pkts - pre.in_pkts),
absl::StrCat(post.out_pkts - pre.out_pkts)},
","),
"\n");
}
EXPECT_OK(testbed->Environment().StoreTestArtifact("sut_counters.csv",
sut_counters_csv));
}

TEST_P(PacketForwardingTestFixture, MtuPacketForwardingTest) {
thinkit::TestRequirements requirements =
gutil::ParseProtoOrDie<thinkit::TestRequirements>(
R"pb(interface_requirements {
count: 2
interface_mode: CONTROL_INTERFACE
})pb");

ASSERT_OK_AND_ASSIGN(auto testbed, GetTestbedWithRequirements(requirements));
ASSERT_OK_AND_ASSIGN(auto gnmi_stub, testbed->Sut().CreateGnmiStub());
std::vector<std::string> sut_interfaces =
GetSutInterfaces(FromTestbed(GetAllControlLinks, *testbed));

ASSERT_OK_AND_ASSIGN(std::unique_ptr<pdpi::P4RuntimeSession> p4_session,
P4InfoPush(GetParam().p4_info, *testbed));
ASSERT_OK_AND_ASSIGN(const pdpi::IrP4Info ir_p4info,
pdpi::CreateIrP4Info(GetParam().p4_info));

for (int mtu : kMtu) {
// Collect counters before the test.
ASSERT_OK_AND_ASSIGN(InterfaceCounters pretraffic_counters,
GetAllInterfaceCounters(*gnmi_stub));

LOG(INFO) << "MTU: " << mtu;
auto test_packet = gutil::ParseProtoOrDie<packetlib::Packet>(kTestPacket);
ASSERT_OK(PadPacket(mtu, test_packet));
LOG(INFO) << "Packet: " << test_packet.DebugString();
ASSERT_OK_AND_ASSIGN(
auto statistics,
basic_traffic::SendTraffic(*testbed, p4_session.get(), ir_p4info,
basic_traffic::AllToAll(sut_interfaces),
{test_packet}, absl::Minutes(5)));

// Collate traffic statistics to dump to artifacts.
std::string packet_statistics_csv =
"ingress_interface,egress_interface,packets_sent,packets_received\n";
for (const basic_traffic::TrafficStatistic& statistic : statistics) {
absl::StrAppend(&packet_statistics_csv,
absl::StrJoin({statistic.interfaces.ingress_interface,
statistic.interfaces.egress_interface,
absl::StrCat(statistic.packets_sent),
absl::StrCat(statistic.packets_received)},
","),
"\n");
EXPECT_EQ(statistic.packets_sent, statistic.packets_received);
EXPECT_EQ(statistic.packets_routed_incorrectly, 0);
}
EXPECT_OK(testbed->Environment().StoreTestArtifact(
absl::StrCat("traffic_statistics_mtu", mtu, ".csv"),
packet_statistics_csv));

// Calculate counter differences and dump to artifacts.
std::string sut_counters_csv = "interface,in_packets,out_packets\n";
ASSERT_OK_AND_ASSIGN(InterfaceCounters posttraffic_counters,
GetAllInterfaceCounters(*gnmi_stub));
for (const std::string& interface : sut_interfaces) {
const Counters& pre = pretraffic_counters[interface];
const Counters& post = posttraffic_counters[interface];
absl::StrAppend(
&sut_counters_csv,
absl::StrJoin({interface, absl::StrCat(post.in_pkts - pre.in_pkts),
absl::StrCat(post.out_pkts - pre.out_pkts)},
","),
"\n");
}
EXPECT_OK(testbed->Environment().StoreTestArtifact(
absl::StrCat("sut_counters_mtu", mtu, ".csv"), sut_counters_csv));
}
}

} // namespace
} // namespace pins_test
Loading

0 comments on commit 49da018

Please sign in to comment.