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

Implement the eBPF extension for P4Tools' P4Testgen #3510

Merged
merged 3 commits into from
Oct 20, 2022

Conversation

fruffy
Copy link
Collaborator

@fruffy fruffy commented Sep 3, 2022

This is a proof of concept implementation for P4Testgen to demonstrate its extensibility for other targets. The implementation is a little janky but works.

The eBPF test failures actually do expose flaws in the test back end.

This PR will be cleaned up and rebased once the P4Tools PR is merged in.

@hesingh
Copy link
Contributor

hesingh commented Sep 3, 2022

@fruffy If I have new source code under bmv2 from which a library is built, how can I use your tool to test the library's code? I do have several P4 programs to test the library and I use Cisco trex for traffic testing. I guess I first create stf files to test the P4 code?

@fruffy
Copy link
Collaborator Author

fruffy commented Sep 4, 2022

If you have a test script that can execute STF tests on your target than you can just use the tests generated by P4Testgen to test your target. For example, the p4c repository has run-bmv2-test.py and run-ebpf-test.py.

However, P4Testgen only support ebpf_model.p4 and v1model.p4 for now.

Copy link
Contributor

@mihaibudiu mihaibudiu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have about 80 C++ files to read.
I think you could have made the effort to break this into several independent PRs.

backends/p4tools/common/core/z3_solver.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/core/z3_solver.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/core/z3_solver.h Outdated Show resolved Hide resolved
backends/p4tools/common/lib/model.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/lib/model.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/lib/ir.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/lib/trace_events.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/lib/taint.cpp Outdated Show resolved Hide resolved
backends/p4tools/p4check/commands.cpp Outdated Show resolved Hide resolved
backends/p4tools/testgen/core/program_info.h Outdated Show resolved Hide resolved
@fruffy-bfn
Copy link
Contributor

fruffy-bfn commented Sep 9, 2022

Will try to address the comments in the other PR.

There is actually several follow-up PRs coming after to this one (which will be reviewed by others). Breaking up the current tool would have made the development of those PRs quite difficult. We would have needed to segment and stack several PRs. Each of these PRs would then continuously need to be synced with the current base PR under review. Under these circumstances it made more sense to release the core executor plus the BMv2 back end all at once and have the PRs develop against that monolith. Otherwise things would have gotten very messy.

Copy link
Contributor

@mihaibudiu mihaibudiu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed a few more file, I still have about 60.
The main question is about what part of stf is specific to a target.

backends/p4tools/testgen/core/externs.cpp Outdated Show resolved Hide resolved
/// standard: standard implementation - use normal control plane entries.
/// constant: The table is constant - no control entries are possible.
/// skip: Skip the implementation and just use the default entry (no entry at all).
enum class TableImplementation { standard, selector, profile, constant, skip };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think ebpf supports action selectors or action profiles. In fact, they are not even listed in the comment.

namespace EBPF {

/// Encapsulates the STF commands and assembles the arguments to be printed to the STF File.
class STFTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What in this file is specific to EBPF?

@@ -0,0 +1,207 @@
#ifndef TESTGEN_TARGETS_BMV2_BACKEND_STF_STF_H_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this file different from the one in the ebpf backend?
what in stf is specific to a target?

@mihaibudiu
Copy link
Contributor

I am not reviewing two PRs of 50K lines each. I am reviewing just this one.

@fruffy
Copy link
Collaborator Author

fruffy commented Sep 16, 2022

Once the other PR is merged, I will rebase it. There should be considerably less lines of code then. This PR is still a draft, it was not meant to be reviewed yet. Unfortunately, I can not change the base to fruffy-bfn/p4c.

Copy link
Contributor

@mihaibudiu mihaibudiu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Down to 35 files to "review".

const ExecutionState& prevState,
gsl::not_null<ExecutionState*> nextState)
: constraint(IRUtils::getBoolLiteral(true)), nextState(nextState) {
if (c) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general it is uncommon to do deep processing in constructors, since if that fails the object is left in an indeterminate state.

@fruffy fruffy force-pushed the ebpf_tools branch 2 times, most recently from d5f10ab to 23a8f75 Compare September 23, 2022 18:57
Copy link
Contributor

@mihaibudiu mihaibudiu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am down to a dozen files left to review

template <typename... T>
explicit TestgenUnimplemented(const char* format, T... args)
: P4CExceptionBase(format, args...) {
// Check if output is redirected and if so, then don't color text so that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a TODO?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually from the original /lib/exceptions.h.

backends/p4tools/testgen/lib/continuation.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/continuation.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/test_spec.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/test_spec.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/test_spec.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/test_spec.cpp Outdated Show resolved Hide resolved
backends/p4tools/testgen/lib/execution_state.h Outdated Show resolved Hide resolved
/// Typically, this is equivalent to the size of the input packet. However, there may be
/// functions such as lookahead that peek into the program packet without actually advancing the
/// cursor. The cursor ensures that parsing remains consistent in these cases.
int inputPacketCursor = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not size_t?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this variable is also incremented by width_bits(), which has the return type int. It might make sense to return size_t for width_bits in general. This is a very common type mismatch in the compiler.

@fruffy fruffy force-pushed the ebpf_tools branch 4 times, most recently from cf38a46 to d098d84 Compare September 29, 2022 16:32
@fruffy-bfn
Copy link
Contributor

fruffy-bfn commented Oct 5, 2022

I left unresolved comments open. Do any of them still need to be addressed? I will work on the eBPF comments after #3495 is merged.

@mihaibudiu
Copy link
Contributor

I left unresolved comments open. Do any of them still need to be addressed? I will work on the eBPF comments after #3495 is merged.

With so many commits it is impossible for me to keep track of which comments have been addressed.

@fruffy fruffy force-pushed the ebpf_tools branch 3 times, most recently from f7d27cf to c774e9d Compare October 6, 2022 13:16
@fruffy-bfn
Copy link
Contributor

I left unresolved comments open. Do any of them still need to be addressed? I will work on the eBPF comments after #3495 is merged.

With so many commits it is impossible for me to keep track of which comments have been addressed.

I left all the comments that I have not addressed unresolved. It should be only about a dozen. Any other things that still need to be done?

@mihaibudiu
Copy link
Contributor

  1. If a comment will require future work I think you should file a corresponding issue
  2. I will try to finish reviewing the PR this week
  3. I would suggest writing a short top-level readme explaining the core structure of the test generator: how it symbolically executes a program representing the results of evaluation as expressions using the IR itself, and how it uses Z3 to explore various paths, etc. This could also be a short guide to the code structure. Having that would have helped me a lot. I am still piecing my understanding as a puzzle.

@jnfoster
Copy link
Contributor

jnfoster commented Oct 6, 2022

We can share a draft paper with you privately (would love your feedback!)

We are working on some public documentation -- more focused on the UI than the internals, but can include a bit of that too.

@mihaibudiu
Copy link
Contributor

Papers are great, but a short README is still necessary, especially if the paper does not talk about the code structure.

@jnfoster
Copy link
Contributor

jnfoster commented Oct 6, 2022

Agree!

Copy link
Contributor

@mihaibudiu mihaibudiu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am done. This looks very nice.

backends/p4tools/common/lib/format_int.cpp Outdated Show resolved Hide resolved
backends/p4tools/common/lib/format_int.cpp Outdated Show resolved Hide resolved
lib/castable.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/targets/bmv2/concolic.h Outdated Show resolved Hide resolved
backends/p4tools/testgen/targets/bmv2/cmd_stepper.cpp Outdated Show resolved Hide resolved
backends/p4tools/testgen/targets/bmv2/expr_stepper.cpp Outdated Show resolved Hide resolved
const ExecutionState& state, SmallStepEvaluator::Result& result) {
uint64_t recirculateCount = 0;
// Grab the recirculate count. Stop after more than 1 circulation loop to avoid
// infinite recirculation loops.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part of the bmv2 spec?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, in fact BMv2 seems to circulate more rounds. I do not have the exact count. Will add this as a TODO.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure that bmv2 does not enforce any limit on the number of recirculations or clones of a packet.

auto recirculateIndex = args->at(2)->expression->checkedTo<IR::Constant>()->asUint64();
boost::optional<const Constraint*> cond = boost::none;

if (cloneType == BMv2Constants::CLONE_TYPE_I2E) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this make sure that the effects of the clone happen at the end of the pipeline?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Practically speaking clone can only be called in ingress or egress. This is enforced by the compiler. So we have some leeway here since the egress block will immediately follow in the I2E case.


if (cloneType == BMv2Constants::CLONE_TYPE_I2E) {
// Pick a clone port var. For now, pick a random value from 0-511.
const auto* rndConst =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some sense this is an executable specification of BMv2.
I wonder whether one could take advantage of that in some way besides test generation. For example, why do you need bmv2 at all, can you replace it with this implementation?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we can only give you the expected output for a given input (packet and control plane config) but BMv2 also models all the other parts of the stack such as the control plane API etc. So are a little bit more limited here.

backends/p4tools/testgen/targets/bmv2/expr_stepper.cpp Outdated Show resolved Hide resolved
@fruffy fruffy force-pushed the ebpf_tools branch 9 times, most recently from 1464c3f to 0430b5c Compare October 19, 2022 17:50
Fix up some eBPF programs.


Typo.


Implement parser errors. 


Smaller fixes.


Smaller fixes.


Implementing the first version of a custom checksum extern for eBPF. 


eBPF can not write to a packet.


Fix.


More cleanup.


Fix a couple more issues. more work on the checksum. 


Minor.


Revert. 


Implement correct checksum function for eBPF.


Implement simple version of conntrack extern and fix up header indices.


Remove file.
asdasda


More edits.
Copy link
Collaborator Author

@fruffy fruffy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbudiu-vmw I cleaned and fixed up the eBPF back end for P4Testgen. Maybe if you have time could you give this a second check? Otherwise I will merge it. It seems to expose some problems with the test framework. I am thinking of fixing these in a separate PR.

@@ -189,7 +189,11 @@ find_python_module (re REQUIRED)
# other packages
find_package (Doxygen)
find_package (BMV2)

# If we have found simple switch or psa switch, we also need scapy and ipaddr.
Copy link
Collaborator Author

@fruffy fruffy Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were spurious warnings emitted by CMake on newer versions. I fixed this in this PR but can move this into a separate PR, if requested.

@@ -51,7 +51,10 @@
"default is test")
PARSER.add_argument("-e", "--extern-file", dest="extern", default="",
help="Specify path additional file with C extern function definition")

PARSER.add_argument("-tf", "--testfile", dest="testfile",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The eBPF test script had no means to specify an input test file. I added this.

auto const& fieldMatch = match.second;

// Replace header stack indices hdr[<index>] with hdr$<index>.
// TODO: This is a limitation of the stf parser. We should fix this.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The STF parser can not handle header stacks as key names. We have to rewrite them. This is a strange limitation we should fix at some point.

p4tools_add_xfail_reason(
"testgen-p4c-ebpf"
"Error 2: Failed to build the filter:"
lpm_ebpf.p4
Copy link
Collaborator Author

@fruffy fruffy Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are compilation failures triggered by P4Testgen. It seems like there are issues with the synthesized control plane interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many

@mihaibudiu
Copy link
Contributor

How about removing the "Draft" label?

@fruffy fruffy marked this pull request as ready for review October 20, 2022 01:20
@@ -106,8 +108,9 @@ void CmdStepper::initializeBlockParams(const IR::Type_Declaration* typeDecl,
if (const auto* ts = paramType->to<IR::Type_StructLike>()) {
declareStructLike(nextState, paramPath, ts);
} else if (paramType->is<IR::Type_Base>()) {
auto paramRef = nextState->convertPathExpr(paramPath);
nextState->set(paramRef, programInfo.createTargetUninitialized(paramRef->type, false));
// If the type is a flat Type_BAse, convert it to a member with a "*" prefix.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in comment

@@ -347,6 +347,11 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression* c
generateCopyIn(nextState, fieldargRef, fieldGlobalRef, dir, forceTaint->value);
}
} else if (assignType->is<IR::Type_Base>()) {
// If the type is a flat Type_Base, convert it to a member with a "*" prefix.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks very much like a utility function.

p4tools_add_xfail_reason(
"testgen-p4c-ebpf"
"Error 2: Failed to build the filter:"
lpm_ebpf.p4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many


class EBPFTableStepper : public TableStepper {
private:
/// Specifies the type of the table implementation:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what is the relationship between these enums and ebpf.
Ebpf has only 2 implementation properties, array or hash.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, eBPF does not have a lot of additional table properties or implementations. We could add hash and array to this enum, but they are not changing the semantics of entry generation for tests if I recall correctly.

namespace EBPF {

/// Extracts information from the @testSpec to emit a STF test case.
class STF : public TF {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I repeat the question about what in this class is specific to EBPF. It looks to me like STF should be the same for all backends.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are subtle difference between how the STF tests are processed for each back end. For example, BMv2 does not need this and does support $ as a postfix to indicate exact packet length matching. Furthermore, BMv2 supports various externs such as clone, action profiles, registers, which are handled in this stf class.

@fruffy fruffy changed the title Implement the P4Testgen back end for the eBPF back end Implement the eBPF extension for P4Tools's P4Testgen Oct 20, 2022
@fruffy fruffy changed the title Implement the eBPF extension for P4Tools's P4Testgen Implement the eBPF extension for P4Tools' P4Testgen Oct 20, 2022
@fruffy fruffy merged commit a696d9f into p4lang:main Oct 20, 2022
@fruffy fruffy deleted the ebpf_tools branch October 20, 2022 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants