Skip to content

Commit 3b3b08e

Browse files
kishanpsVSuryaprasad-HCL
authored andcommitted
adding an acl feature test, to test out ACL Deny Action and different packet actions
1 parent 7dd5eca commit 3b3b08e

File tree

2 files changed

+302
-0
lines changed

2 files changed

+302
-0
lines changed

tests/forwarding/acl_feature_test.cc

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "tests/forwarding/acl_feature_test.h"
16+
17+
#include <memory>
18+
#include <optional>
19+
#include <string>
20+
#include <tuple>
21+
#include <vector>
22+
23+
#include "absl/log/check.h"
24+
#include "absl/status/status.h"
25+
#include "absl/strings/string_view.h"
26+
#include "dvaas/dataplane_validation.h"
27+
#include "dvaas/test_vector.h"
28+
#include "dvaas/validation_result.h"
29+
#include "glog/logging.h"
30+
#include "gmock/gmock.h"
31+
#include "gtest/gtest.h"
32+
#include "gutil/status.h" // IWYU pragma: keep
33+
#include "gutil/status.h"
34+
#include "gutil/status_matchers.h" // IWYU pragma: keep
35+
#include "gutil/testing.h"
36+
#include "lib/gnmi/gnmi_helper.h"
37+
#include "net/google::protobuf/contrib/fixtures/proto-fixture-repository.h"
38+
#include "p4/v1/p4runtime.pb.h"
39+
#include "p4_pdpi/ir.h"
40+
#include "p4_pdpi/ir.pb.h"
41+
#include "p4_pdpi/p4_runtime_session.h"
42+
#include "p4_pdpi/p4_runtime_session_extras.h"
43+
#include "p4_pdpi/packetlib/packetlib.h"
44+
#include "p4_pdpi/packetlib/packetlib.pb.h"
45+
#include "p4_pdpi/pd.h"
46+
#include "sai_p4/instantiations/google/sai_pd.pb.h"
47+
#include "sai_p4/instantiations/google/test_tools/test_entries.h"
48+
#include "tests/lib/switch_test_setup_helpers.h"
49+
#include "thinkit/mirror_testbed.h"
50+
51+
namespace pins_test {
52+
namespace {
53+
54+
using ::google::protobuf::contrib::fixtures::ProtoFixtureRepository;
55+
56+
packetlib::Packet ParsePacketAndFillInComputedFields(
57+
const ProtoFixtureRepository& repo, absl::string_view packet_pb) {
58+
packetlib::Packet packet = repo.ParseTextOrDie<packetlib::Packet>(packet_pb);
59+
CHECK_OK(packetlib::PadPacketToMinimumSize(packet));
60+
CHECK_OK(packetlib::UpdateMissingComputedFields(packet));
61+
return packet;
62+
}
63+
64+
// Setup ingress ACL forward all packets.
65+
absl::Status SetUpIngressAclForwardingAllPackets(
66+
pdpi::P4RuntimeSession* p4_session, const pdpi::IrP4Info& ir_p4info) {
67+
sai::TableEntry pd_entry = gutil::ParseProtoOrDie<sai::TableEntry>(
68+
R"pb(
69+
acl_ingress_table_entry {
70+
match {} # Wildcard match.
71+
action { acl_forward {} }
72+
priority: 1
73+
}
74+
)pb");
75+
76+
ASSIGN_OR_RETURN(
77+
const p4::v1::TableEntry pi_entry,
78+
pdpi::PartialPdTableEntryToPiTableEntry(ir_p4info, pd_entry));
79+
return pdpi::InstallPiTableEntry(p4_session, pi_entry);
80+
}
81+
82+
// Helper function to build a UDP packet
83+
dvaas::PacketTestVector UdpPacket(std::string control_port,
84+
absl::string_view dst_mac,
85+
absl::string_view dst_ip,
86+
std::optional<sai::PuntAction> punt_action) {
87+
ProtoFixtureRepository repo;
88+
89+
repo.RegisterValue("@payload", dvaas::MakeTestPacketTagFromUniqueId(1))
90+
.RegisterValue("@ingress_port", control_port)
91+
.RegisterValue("@egress_port", control_port)
92+
.RegisterValue("@dst_ip", dst_ip)
93+
.RegisterValue("@dst_mac", dst_mac)
94+
.RegisterValue("@ttl", "0x10")
95+
.RegisterValue("@decremented_ttl", "0x0f");
96+
97+
dvaas::PacketTestVector test_vector =
98+
repo.RegisterSnippetOrDie<packetlib::Header>("@ethernet", R"pb(
99+
ethernet_header {
100+
ethernet_destination: @dst_mac,
101+
ethernet_source: "00:00:22:22:00:00"
102+
ethertype: "0x0800" # Udp
103+
}
104+
)pb")
105+
.RegisterSnippetOrDie<packetlib::Header>("@ipv4", R"pb(
106+
ipv4_header {
107+
version: "0x4"
108+
dscp: "0x1b"
109+
ecn: "0x1"
110+
ihl: "0x5"
111+
identification: "0x0000"
112+
flags: "0x0"
113+
ttl: @ttl
114+
fragment_offset: "0x0000"
115+
# payload_length: filled in automatically.
116+
protocol: "0x11"
117+
ipv4_source: "10.0.0.8"
118+
ipv4_destination: @dst_ip
119+
}
120+
)pb")
121+
.RegisterSnippetOrDie<packetlib::Header>("@udp", R"pb(
122+
udp_header { source_port: "0x0014" destination_port: "0x000a" }
123+
)pb")
124+
.RegisterMessage("@input_packet", ParsePacketAndFillInComputedFields(
125+
repo,
126+
R"pb(
127+
headers: @ethernet
128+
headers: @ipv4
129+
headers: @udp
130+
payload: @payload
131+
)pb"))
132+
.RegisterMessage(
133+
"@output_packet", ParsePacketAndFillInComputedFields(repo, R"pb(
134+
headers: @ethernet {
135+
ethernet_header {
136+
ethernet_destination: "02:03:04:05:06:07"
137+
ethernet_source: "00:01:02:03:04:05"
138+
}
139+
}
140+
headers: @ipv4 { ipv4_header { ttl: @decremented_ttl } }
141+
headers: @udp
142+
payload: @payload
143+
)pb"))
144+
.ParseTextOrDie<dvaas::PacketTestVector>(R"pb(
145+
input {
146+
type: DATAPLANE
147+
packet { port: @ingress_port parsed: @input_packet }
148+
}
149+
acceptable_outputs {
150+
packets { port: @egress_port parsed: @output_packet }
151+
packet_ins { parsed: @output_packet }
152+
}
153+
)pb");
154+
155+
for (dvaas::SwitchOutput& output :
156+
*test_vector.mutable_acceptable_outputs()) {
157+
if (!punt_action.has_value()) {
158+
output.clear_packet_ins();
159+
} else if (punt_action.value() == sai::PuntAction::kTrap) {
160+
output.clear_packets();
161+
}
162+
}
163+
return test_vector;
164+
}
165+
166+
// Helper routine to install L3 route
167+
absl::Status InstallL3Route(pdpi::P4RuntimeSession* switch_session,
168+
pdpi::IrP4Info ir_p4info, std::string given_port,
169+
std::optional<sai::PuntAction> punt_action) {
170+
std::vector<p4::v1::Entity> pi_entities;
171+
LOG(INFO) << "Installing L3 route";
172+
173+
sai::EntryBuilder entry_builder =
174+
sai::EntryBuilder()
175+
.AddVrfEntry("vrf-1")
176+
.AddPreIngressAclEntryAssigningVrfForGivenIpType(
177+
"vrf-1", sai::IpVersion::kIpv4)
178+
.AddDefaultRouteForwardingAllPacketsToGivenPort(
179+
given_port, sai::IpVersion::kIpv4, "vrf-1")
180+
.AddEntryAdmittingAllPacketsToL3();
181+
182+
if (punt_action.has_value()) {
183+
entry_builder.AddEntryPuntingAllPackets(punt_action.value());
184+
} else {
185+
RETURN_IF_ERROR(
186+
SetUpIngressAclForwardingAllPackets(switch_session, ir_p4info));
187+
}
188+
ASSIGN_OR_RETURN(
189+
pi_entities,
190+
entry_builder.LogPdEntries().GetDedupedPiEntities(ir_p4info));
191+
RETURN_IF_ERROR(pdpi::InstallPiEntities(*switch_session, pi_entities));
192+
return absl::OkStatus();
193+
}
194+
195+
TEST_P(AclFeatureTestFixture, AclDenyAction) {
196+
const AclFeatureTestParams& params = GetParam();
197+
198+
thinkit::MirrorTestbed& testbed =
199+
GetParam().mirror_testbed->GetMirrorTestbed();
200+
std::unique_ptr<pdpi::P4RuntimeSession> sut_p4rt_session,
201+
control_switch_p4rt_session;
202+
203+
ASSERT_OK_AND_ASSIGN(
204+
std::tie(sut_p4rt_session, control_switch_p4rt_session),
205+
pins_test::ConfigureSwitchPairAndReturnP4RuntimeSessionPair(
206+
testbed.Sut(), testbed.ControlSwitch(), std::nullopt,
207+
GetParam().p4info));
208+
209+
// Initialize the connection, clear table entries, and push GNMI
210+
// configuration (if given) for the SUT and Control switch.
211+
ASSERT_NE(sut_p4rt_session, nullptr);
212+
ASSERT_OK_AND_ASSIGN(
213+
p4::v1::GetForwardingPipelineConfigResponse sut_config,
214+
pdpi::GetForwardingPipelineConfig(sut_p4rt_session.get()));
215+
ASSERT_OK(testbed.Environment().StoreTestArtifact(
216+
"sut_p4Info.textproto", sut_config.config().p4info().DebugString()));
217+
ASSERT_OK_AND_ASSIGN(pdpi::IrP4Info sut_ir_p4info,
218+
pdpi::CreateIrP4Info(sut_config.config().p4info()));
219+
220+
ASSERT_OK(pdpi::ClearTableEntries(sut_p4rt_session.get()));
221+
222+
// Get control ports to test on.
223+
ASSERT_OK_AND_ASSIGN(
224+
auto gnmi_stub_control,
225+
GetParam().mirror_testbed->GetMirrorTestbed().Sut().CreateGnmiStub());
226+
ASSERT_OK_AND_ASSIGN(std::string control_port,
227+
pins_test::GetAnyUpInterfacePortId(*gnmi_stub_control));
228+
229+
ASSERT_OK(InstallL3Route(sut_p4rt_session.get(), sut_ir_p4info, control_port,
230+
params.punt_action));
231+
232+
// remove the skip
233+
if (params.punt_action.has_value()) {
234+
// Run test with custom packet test vector.
235+
dvaas::DataplaneValidationParams dvaas_params = params.dvaas_params;
236+
dvaas_params.packet_test_vector_override = {
237+
UdpPacket(control_port, /*dst_mac=*/"00:aa:bb:cc:cc:dd",
238+
/*dst_ip=*/"10.0.0.1", params.punt_action)};
239+
ASSERT_OK_AND_ASSIGN(
240+
dvaas::ValidationResult validation_result,
241+
GetParam().dvaas->ValidateDataplane(testbed, dvaas_params));
242+
243+
// Log statistics and check that things succeeded.
244+
validation_result.LogStatistics();
245+
EXPECT_OK(validation_result.HasSuccessRateOfAtLeast(1.0));
246+
}
247+
}
248+
249+
} // namespace
250+
} // namespace pins_test

tests/forwarding/acl_feature_test.h

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef PINS_TESTS_FORWARDING_ACL_FEATURE_TEST_H_
16+
#define PINS_TESTS_FORWARDING_ACL_FEATURE_TEST_H_
17+
18+
#include <optional>
19+
#include <tuple>
20+
21+
#include "dvaas/dataplane_validation.h"
22+
#include "dvaas/test_vector.h"
23+
#include "dvaas/test_vector.pb.h"
24+
#include "dvaas/validation_result.h"
25+
#include "sai_p4/instantiations/google/test_tools/test_entries.h"
26+
#include "thinkit/mirror_testbed_fixture.h"
27+
28+
namespace pins_test {
29+
30+
struct AclFeatureTestParams {
31+
// Using a shared_ptr because parameterized tests require objects to be
32+
// copyable.
33+
std::shared_ptr<thinkit::MirrorTestbedInterface> mirror_testbed;
34+
std::optional<p4::config::v1::P4Info> p4info;
35+
std::string test_name;
36+
// ACL action variant to test out different behavior
37+
std::optional<sai::PuntAction> punt_action;
38+
dvaas::DataplaneValidationParams dvaas_params;
39+
std::shared_ptr<dvaas::DataplaneValidator> dvaas;
40+
};
41+
42+
class AclFeatureTestFixture
43+
: public testing::TestWithParam<AclFeatureTestParams> {
44+
public:
45+
void SetUp() override { GetParam().mirror_testbed->SetUp(); }
46+
47+
void TearDown() override { GetParam().mirror_testbed->TearDown(); }
48+
};
49+
50+
} // namespace pins_test
51+
52+
#endif // PINS_TESTS_FORWARDING_ACL_FEATURE_TEST_H_

0 commit comments

Comments
 (0)