Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[P4Testgen] Set other headers also invalid when calling setInvalid on a union header. #4853

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backends/bmv2/pna_nic/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ PnaNicMidEnd::PnaNicMidEnd(CompilerOptions &options, std::ostream *outStream)
new P4::StrengthReduction(&typeMap),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig()),
new P4::NestedStructs(&typeMap),
new P4::SimplifySelectList(&typeMap),
new P4::RemoveSelectBooleans(&typeMap),
Expand Down
2 changes: 1 addition & 1 deletion backends/bmv2/psa_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre
new P4::StrengthReduction(&typeMap),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig()),
new P4::NestedStructs(&typeMap),
new P4::SimplifySelectList(&typeMap),
new P4::RemoveSelectBooleans(&typeMap),
Expand Down
2 changes: 1 addition & 1 deletion backends/bmv2/simple_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o
new P4::StrengthReduction(&typeMap),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig()),
new P4::NestedStructs(&typeMap),
new P4::SimplifySelectList(&typeMap),
new P4::RemoveSelectBooleans(&typeMap),
Expand Down
6 changes: 5 additions & 1 deletion backends/dpdk/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,11 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) {
new P4::StrengthReduction(&typeMap),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap, false /* errorOnMethodCall */),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig{
/*errorOnMethodCall*/ false,
/*copyHeaders*/ false,
/*expandUnions*/ true,
}),
new P4::NestedStructs(&typeMap),
new P4::SimplifySelectList(&typeMap),
new P4::RemoveSelectBooleans(&typeMap),
Expand Down
6 changes: 5 additions & 1 deletion backends/p4test/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ MidEnd::MidEnd(CompilerOptions &options, std::ostream *outStream) {
new P4::StrengthReduction(&typeMap),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap, false),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig{
/*errorOnMethodCall*/ false,
/*copyHeaders*/ false,
/*expandUnions*/ true,
}),
new P4::NestedStructs(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::SimplifySelectList(&typeMap),
Expand Down
8 changes: 7 additions & 1 deletion backends/p4tools/common/compiler/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ void MidEnd::addDefaultPasses() {
new P4::SimplifyComparisons(&typeMap),
// Expand header and struct assignments into sequences of field assignments.
new PassRepeated({
new P4::CopyStructures(&typeMap, false, true, nullptr),
new P4::CopyStructures(&typeMap,
{
/*errorOnMethodCall*/ false,
/*copyHeaders*/ true,
/*expandUnions*/ false,
},
nullptr),
}),
new P4::RemoveParserControlFlow(&typeMap),
// Flatten nested list expressions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,38 +210,48 @@ bool AbstractStepper::stepGetHeaderValidity(const IR::StateVariable &headerRef)
return false;
}

void AbstractStepper::setHeaderValidity(const IR::StateVariable &headerRef, bool validity,
ExecutionState &nextState) {
namespace {

void setHeaderValidityHelper(const IR::StateVariable &headerRef, bool validity,
const ProgramInfo &programInfo, ExecutionState &nextState) {
const auto &headerRefValidity = ToolsVariables::getHeaderValidity(headerRef);
nextState.set(headerRefValidity, IR::BoolLiteral::get(validity));

// In some cases, the header may be `part of a union.
if (validity) {
const auto *headerBaseMember = headerRef.ref->to<IR::Member>();
if (headerBaseMember == nullptr) {
return;
// The header is going to be invalid. Set all fields to taint constants.
// TODO: Should we make this target specific? Some targets set the header fields to 0...
if (!validity) {
std::vector<IR::StateVariable> validityVector;
auto fieldsVector = nextState.getFlatFields(headerRef, &validityVector);
for (const auto &field : validityVector) {
nextState.set(field, IR::BoolLiteral::get(false));
}
for (const auto &field : fieldsVector) {
nextState.set(field, programInfo.createTargetUninitialized(field->type, true));
}
const auto *headerBase = headerBaseMember->expr;
}
}

} // namespace

void AbstractStepper::setHeaderValidity(const IR::StateVariable &headerRef, bool validity,
ExecutionState &nextState) {
setHeaderValidityHelper(headerRef, validity, programInfo, nextState);

// In some cases, the header may be nested.
if (const auto *headerBase = headerRef.ref->to<IR::Member>()) {
// In the case of header unions, we need to set all other union members invalid.
if (const auto *hdrUnion = headerBase->type->to<IR::Type_HeaderUnion>()) {
CHECK_NULL(headerBase->expr->type);
if (const auto *hdrUnion = headerBase->expr->type->to<IR::Type_HeaderUnion>()) {
for (const auto *field : hdrUnion->fields) {
auto *member = new IR::Member(field->type, headerBase, field->name);
// Ignore the member we are setting to valid.
if (headerRef->equiv(*member)) {
// Ignore the member we are setting.
if (headerBase->member == field->name) {
continue;
}
// Set all other members to invalid.
setHeaderValidity(member, false, nextState);
setHeaderValidityHelper(new IR::Member(field->type, headerBase->expr, field->name),
false, programInfo, nextState);
}
}
return;
}
std::vector<IR::StateVariable> validityVector;
auto fieldsVector = nextState.getFlatFields(headerRef, &validityVector);
// The header is going to be invalid. Set all fields to taint constants.
// TODO: Should we make this target specific? Some targets set the header fields to 0.
for (const auto &field : fieldsVector) {
nextState.set(field, programInfo.createTargetUninitialized(field->type, true));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ p4tools_add_xfail_reason(
v1model-digest-custom-type.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-ptf"
"Expected packet was not received on device"
# BMv2 has the incorrect HU invalidation implementation.
bmv2_invalid_hu_1.p4
bmv2_invalid_hu_2.p4
union4-bmv2.p4
)

####################################################################################################
# 2. P4Testgen Issues
# These are failures in P4Testgen that need to be fixed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ p4tools_add_xfail_reason(
extract_for_header_union.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-stf"
"differs|Expected ([0-9]+) packets on port ([0-9]+) got ([0-9]+)"
# BMv2 has the incorrect HU invalidation implementation.
bmv2_invalid_hu_1.p4
bmv2_invalid_hu_2.p4
union4-bmv2.p4
)

####################################################################################################
# 2. P4Testgen Issues
# These are failures in P4Testgen that need to be fixed.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <v1model.p4>

header opt_t {
bit<8> opt;
}

header ethernet_t {
bit<48> dst_addr;
bit<48> src_addr;
bit<16> eth_type;
}

header H {
bit<8> a;
bit<8> a1;
bit<8> b;
}

header_union U {
ethernet_t e;
H h;
}

struct Headers {
opt_t opt;
U u;
}

struct Meta {}

parser p(packet_in pkt, out Headers h, inout Meta meta, inout standard_metadata_t stdmeta) {
state start {
pkt.extract(h.opt);
transition select(h.opt.opt) {
0x0: parse_e;
0x1: parse_h;
default: accept;
}
}

state parse_e {
pkt.extract(h.u.e);
transition accept;
}

state parse_h {
pkt.extract(h.u.h);
transition accept;
}
}

control vrfy(inout Headers h, inout Meta meta) {
apply { }
}

control ingress(inout Headers h, inout Meta m, inout standard_metadata_t s) {
apply {
h.u.e.setInvalid();
}
}

control egress(inout Headers h, inout Meta m, inout standard_metadata_t s) {
apply { }
}

control update(inout Headers h, inout Meta m) {
apply { }
}

control deparser(packet_out pkt, in Headers h) {
apply {
pkt.emit(h);
}
}

V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <v1model.p4>

header opt_t {
bit<8> opt;
}

header ethernet_t {
bit<48> dst_addr;
bit<48> src_addr;
bit<16> eth_type;
}

header H {
bit<8> a;
bit<8> a1;
bit<8> b;
}

header_union U {
ethernet_t e;
H h;
}

struct Headers {
opt_t opt;
U u;
}

struct Meta {}

parser p(packet_in pkt, out Headers h, inout Meta meta, inout standard_metadata_t stdmeta) {
state start {
pkt.extract(h.opt);
transition select(h.opt.opt) {
0x0: parse_e;
0x1: parse_h;
default: accept;
}
}

state parse_e {
pkt.extract(h.u.e);
transition invalidate;
}

state parse_h {
pkt.extract(h.u.h);
transition invalidate;
}

state invalidate {
h.u.e.setInvalid();
transition accept;
}
}

control vrfy(inout Headers h, inout Meta meta) {
apply { }
}

control ingress(inout Headers h, inout Meta m, inout standard_metadata_t s) {
apply {
}
}

control egress(inout Headers h, inout Meta m, inout standard_metadata_t s) {
apply { }
}

control update(inout Headers h, inout Meta m) {
apply { }
}

control deparser(packet_out pkt, in Headers h) {
apply {
pkt.emit(h);
}
}

V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
2 changes: 1 addition & 1 deletion backends/ubpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const IR::ToplevelBlock *MidEnd::run(EbpfOptions &options, const IR::P4Program *
new P4::StrengthReduction(&typeMap),
}),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
new P4::CopyStructures(&typeMap, P4::CopyStructuresConfig()),
new P4::LocalCopyPropagation(&typeMap),
new P4::SimplifySelectList(&typeMap),
new P4::MoveDeclarations(), // more may have been introduced
Expand Down
9 changes: 5 additions & 4 deletions midend/copyStructures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ const IR::Node *DoCopyStructures::postorder(IR::AssignmentStatement *statement)
FIXME: this is not correct for header unions and should be fixed.
The fix bellow, commented-out, causes problems elsewhere.
https://github.com/p4lang/p4c/issues/3842
if (ltype->is<IR::Type_HeaderUnion>())
return statement;
*/
if (!_config.expandUnions && ltype->is<IR::Type_HeaderUnion>()) {
return statement;
}

// Do not copy structures for method calls.
if (statement->right->is<IR::MethodCallExpression>()) {
if (errorOnMethodCall) {
if (_config.errorOnMethodCall) {
::P4::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET,
"%1%: functions or methods returning structures "
"are not supported on this target",
Expand All @@ -98,7 +99,7 @@ const IR::Node *DoCopyStructures::postorder(IR::AssignmentStatement *statement)
retval->push_back(
new IR::AssignmentStatement(statement->srcInfo, left, right->expression));
}
} else if (copyHeaders && ltype->is<IR::Type_Header>()) {
} else if (_config.copyHeaders && ltype->is<IR::Type_Header>()) {
const auto *header = ltype->checkedTo<IR::Type_Header>();
// Build a "src.isValid()" call.
const auto *isSrcValidCall = new IR::MethodCallExpression(
Expand Down
Loading
Loading