Skip to content

Commit

Permalink
Merge branch 'main' into symbolic_import_branch_60
Browse files Browse the repository at this point in the history
  • Loading branch information
VSuryaprasad-HCL authored Oct 23, 2024
2 parents 6d7a672 + e39edad commit cf5db03
Show file tree
Hide file tree
Showing 49 changed files with 2,875 additions and 1,716 deletions.
4 changes: 4 additions & 0 deletions p4_fuzzer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@ cc_library(
"//gutil:collections",
"//gutil:status",
"//lib/p4rt:p4rt_port",
"//p4_pdpi:built_ins",
"//p4_pdpi:entity_keys",
"//p4_pdpi:ir_cc_proto",
"//p4_pdpi:references",
"//p4_pdpi/internal:ordered_map",
"//p4_pdpi/netaddr:ipv6_address",
"//p4_pdpi/string_encodings:byte_string",
"//p4_pdpi/utils:ir",
"@com_github_google_glog//:glog",
"@com_github_p4lang_p4_constraints//p4_constraints/backend:constraint_info",
Expand Down Expand Up @@ -163,6 +165,8 @@ cc_test(
"//gutil:collections",
"//gutil:proto_matchers",
"//gutil:status_matchers",
"//gutil:testing",
"//p4_pdpi:built_ins",
"//p4_pdpi:ir_cc_proto",
"@com_github_google_glog//:glog",
"@com_github_p4lang_p4runtime//:p4info_cc_proto",
Expand Down
390 changes: 292 additions & 98 deletions p4_fuzzer/fuzz_util.cc

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions p4_fuzzer/fuzz_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ absl::StatusOr<p4::v1::TableEntry> FuzzValidTableEntry(
absl::BitGen* gen, const FuzzerConfig& config,
const SwitchState& switch_state, const uint32_t table_id);

// Randomly generates a multicast group entry. May fail if a reference to
// another table is required.
absl::StatusOr<p4::v1::MulticastGroupEntry> FuzzValidMulticastGroupEntry(
absl::BitGen* gen, const FuzzerConfig& config,
const SwitchState& switch_state);

// Randomly generates a set of valid table entries that, when installed in order
// to an empty switch state, all install correctly.
std::vector<AnnotatedTableEntry> ValidForwardingEntries(
Expand Down
207 changes: 207 additions & 0 deletions p4_fuzzer/fuzz_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
#include "gutil/collections.h"
#include "gutil/proto_matchers.h"
#include "gutil/status_matchers.h"
#include "gutil/testing.h"
#include "p4/config/v1/p4info.pb.h"
#include "p4/v1/p4runtime.pb.h"
#include "p4_fuzzer/fuzzer.pb.h"
#include "p4_fuzzer/fuzzer_config.h"
#include "p4_fuzzer/test_utils.h"
#include "p4_pdpi/built_ins.h"
#include "p4_pdpi/ir.pb.h"

namespace p4_fuzzer {
Expand Down Expand Up @@ -204,6 +206,175 @@ TEST(FuzzUtilTest, FuzzWriteRequestAreReproducibleWithState) {
}
}

TEST(FuzzUtilTest, FuzzWriteRequestCanFuzzMulticastGroupEntry) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();
absl::BitGen gen;
// Ensure a multicast entity is fuzzed.
fuzzer_state.config.fuzz_multicast_group_entry_probability = 1.0;

AnnotatedWriteRequest write_request;
// Because there is a non-zero chance to fuzz no updates.
while (write_request.updates().empty()) {
write_request =
FuzzWriteRequest(&gen, fuzzer_state.config, fuzzer_state.switch_state,
/*max_batch_size=*/1);
}

EXPECT_TRUE(write_request.updates(0)
.pi()
.entity()
.packet_replication_engine_entry()
.has_multicast_group_entry());
}

// This test uses behavior specific to the main.p4 program. In main.p4,
// `refers_to_multicast_by_action_table` is a table that uses an action whose
// parameter refers to multicast group id.
TEST(FuzzUtilTest, FuzzTableFailsWhenNoMulticastReferenceIsAvailable) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();

// Generate entry referring to multicast and fail due to no references.
pdpi::IrTableDefinition multicast_dependent_definition =
gutil::FindOrDie(fuzzer_state.config.GetIrP4Info().tables_by_name(),
"refers_to_multicast_by_action_table");
absl::BitGen gen;
EXPECT_THAT(
FuzzValidTableEntry(&gen, fuzzer_state.config, fuzzer_state.switch_state,
multicast_dependent_definition),
gutil::StatusIs(absl::StatusCode::kFailedPrecondition));
}

// This test uses behavior specific to the main.p4 program. In main.p4,
// `refers_to_multicast_by_action_table` is a table that uses an action whose
// parameter refers to multicast group id.
TEST(FuzzUtilTest, FuzzTableRespectsMulticastReferences) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();

// Store multicast group entry being referenced.
ASSERT_OK(fuzzer_state.switch_state.ApplyUpdate(
gutil::ParseProtoOrDie<p4::v1::Update>(R"pb(
type: INSERT
entity {
packet_replication_engine_entry {
multicast_group_entry { multicast_group_id: 0x86 }
}
}
)pb")));

// Generate entry referring to multicast and ensure the action references
// multicast group id.
pdpi::IrTableDefinition multicast_dependent_definition =
gutil::FindOrDie(fuzzer_state.config.GetIrP4Info().tables_by_name(),
"refers_to_multicast_by_action_table");
absl::BitGen gen;
EXPECT_THAT(
FuzzValidTableEntry(&gen, fuzzer_state.config, fuzzer_state.switch_state,
multicast_dependent_definition),
IsOkAndHolds(Partially(EqualsProto(R"pb(
action {
action {
# Action id for `refers_to_multicast_action`.
action_id: 18598416
params { param_id: 1 value: "\x86" }
}
}
)pb"))));
}

// This test uses behavior specific to the main.p4 program. In main.p4,
// built-in multicast group table replicas refer to fields in
// `referenced_by_multicast_replica_table`.
TEST(FuzzUtilTest, FuzzMulticastRespectsReplicaReferences) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();

// Store table entry being referenced.
ASSERT_OK(fuzzer_state.switch_state.ApplyUpdate(
gutil::ParseProtoOrDie<p4::v1::Update>(R"pb(
type: INSERT
entity {
table_entry {
table_id: 49197097
# Port
match {
field_id: 1
exact { value: "sample_port" }
}
# Instance
match {
field_id: 2
exact { value: "\x86" }
}
action { action { action_id: 16777221 } }
}
}
)pb")));

absl::BitGen gen;
p4::v1::MulticastGroupEntry multicast_entry;
// Fuzz until multicast group entry has the one replica.
while (multicast_entry.replicas().empty()) {
ASSERT_OK_AND_ASSIGN(multicast_entry, FuzzValidMulticastGroupEntry(
&gen, fuzzer_state.config,
fuzzer_state.switch_state));
}

// Multicast group cannot be 0.
EXPECT_NE(multicast_entry.multicast_group_id(), 0);

// Ensure the one replica references values in table entry.
ASSERT_EQ(multicast_entry.replicas_size(), 1);
EXPECT_THAT(multicast_entry, Partially(EqualsProto(R"pb(
replicas { instance: 0x86 port: "sample_port" }
)pb")));
}

// This test uses behavior specific to the main.p4 program. In main.p4,
// built-in multicast group table replicas refer to fields in
// `referenced_by_multicast_replica_table`.
TEST(FuzzUtilTest, FuzzMulticastAreReproducibleWithState) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();

pdpi::IrTableDefinition multicast_dependency_definition =
gutil::FindOrDie(fuzzer_state.config.GetIrP4Info().tables_by_name(),
"referenced_by_multicast_replica_table");

absl::BitGen init_gen;

// Generate up to 50 random table entries that can be referenced by multicast.
for (int i = 0; i < 50; ++i) {
p4::v1::Update update;
update.set_type(p4::v1::Update::INSERT);
ASSERT_OK_AND_ASSIGN(*update.mutable_entity()->mutable_table_entry(),
FuzzValidTableEntry(&init_gen, fuzzer_state.config,
fuzzer_state.switch_state,
multicast_dependency_definition));
ASSERT_OK(fuzzer_state.switch_state.ApplyUpdate(update));
}

LOG(INFO) << "State size = "
<< fuzzer_state.switch_state.GetNumTableEntries();

// Use the same sequence seed for both generators.
absl::SeedSeq seed;
absl::BitGen gen_0(seed);
absl::BitGen gen_1(seed);

// Create 50 instances and verify that they are identical.
for (int i = 0; i < 20; ++i) {
ASSERT_OK_AND_ASSIGN(
p4::v1::MulticastGroupEntry entry0,
FuzzValidMulticastGroupEntry(&gen_0, fuzzer_state.config,
fuzzer_state.switch_state));

ASSERT_OK_AND_ASSIGN(
p4::v1::MulticastGroupEntry entry1,
FuzzValidMulticastGroupEntry(&gen_1, fuzzer_state.config,
fuzzer_state.switch_state));

EXPECT_THAT(entry0, EqualsProto(entry1));
}
}

// Test that FuzzActionProfileActionSet correctly generates an ActionProfile
// Action Set of acceptable weights and size (derived from max_group_size and
// kActionProfileActionSetMaxCardinality).
Expand Down Expand Up @@ -399,6 +570,42 @@ TEST(FuzzUtilTest, FuzzWriteRequestRespectsDisallowList) {
}
}

TEST(FuzzUtilTest, FuzzValidTableEntryRespectsDisallowList) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();
fuzzer_state.config.disabled_fully_qualified_names = {
"ingress.ternary_table.ipv6_upper_64_bits",
"ingress.ternary_table.normal",
"ingress.ternary_table.mac",
"ingress.ternary_table.unsupported_field",
};

ASSERT_OK_AND_ASSIGN(
const pdpi::IrTableDefinition& ternary_table,
gutil::FindOrStatus(fuzzer_state.config.GetIrP4Info().tables_by_name(),
"ternary_table"));

absl::flat_hash_set<uint32_t> disallowed_ids;
for (const auto& path : fuzzer_state.config.disabled_fully_qualified_names) {
std::vector<std::string> parts = absl::StrSplit(path, '.');
ASSERT_OK_AND_ASSIGN(
const pdpi::IrMatchFieldDefinition& match,
gutil::FindOrStatus(ternary_table.match_fields_by_name(),
parts[parts.size() - 1]));
disallowed_ids.insert(match.match_field().id());
}

for (int i = 0; i < 1000; i++) {
ASSERT_OK_AND_ASSIGN(
p4::v1::TableEntry entry,
FuzzValidTableEntry(&fuzzer_state.gen, fuzzer_state.config,
fuzzer_state.switch_state,
ternary_table.preamble().id()));
for (const auto& match : entry.match()) {
EXPECT_THAT(match.field_id(), Not(AnyOfArray(disallowed_ids)));
}
}
}

TEST(FuzzUtilTest, FuzzActionRespectsDisallowList) {
FuzzerTestState fuzzer_state = ConstructStandardFuzzerTestState();
ASSERT_OK_AND_ASSIGN(
Expand Down
3 changes: 3 additions & 0 deletions p4_fuzzer/fuzzer_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class FuzzerConfig {
std::string role = "sdn_controller";
// The probability of performing a mutation on a given table entry.
float mutate_update_probability = 0.1;
// The probability of fuzzing a multicast group entry when fuzzing an update.
// TODO: b/319260502 - Change from zero once switch supports multicast.
float fuzz_multicast_group_entry_probability = 0;

// -- Optional ---------------------------------------------------------------
// The set of tables where the fuzzer should treat their resource guarantees
Expand Down
Loading

0 comments on commit cf5db03

Please sign in to comment.