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

Handle Arithmetic operations for fields which are in network order #4566

Merged
merged 25 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
944edd0
Make Header fields in network order in Parser.
komaljai Jan 25, 2024
c14a296
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Jan 25, 2024
7716732
Update testcase output
komaljai Jan 25, 2024
e0da194
Address comments and update testcases
komaljai Feb 23, 2024
b5ffb3e
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Feb 23, 2024
b8aa951
Address comments and update testcases
komaljai Feb 26, 2024
e93cb8e
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Feb 26, 2024
9b44450
Add comments
komaljai Feb 26, 2024
7c7608e
ddressed comments
komaljai Feb 27, 2024
f35ba2f
Revert change and restore annotations in parser and deparser.
komaljai Mar 18, 2024
a9a5c5d
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Mar 18, 2024
9706c7c
ndle Arithmetic operations for annotated fields in header definition,
komaljai Mar 26, 2024
271a218
Fix cpplint
komaljai Mar 26, 2024
bc4e5b2
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Mar 26, 2024
49ef685
Update Testcase output
komaljai Mar 26, 2024
8c06a22
Merge branch 'main' of https://github.com/komaljai/p4c into change_en…
komaljai Mar 26, 2024
dda1ca1
Fix cpplint issue
komaljai Mar 26, 2024
6233e26
Merge branch 'main' of https://github.com/komaljai/p4c into networkOr…
komaljai Mar 26, 2024
e656005
Merge branch 'main' into networkOrder_arithmetic
komaljai Mar 27, 2024
09dc8cc
Merge branch 'networkOrder_arithmetic' of https://github.com/komaljai…
komaljai Mar 26, 2024
91c3fe1
Remove LPM tables byte order conversion before table lookups.
komaljai Mar 28, 2024
dd3a66a
Fix clang issue
komaljai Mar 28, 2024
0901677
Fix sanitizer issue
komaljai Mar 28, 2024
b6a0ce8
Addressed comments
komaljai Apr 1, 2024
0ca1f2b
Merge branch 'main' into networkOrder_arithmetic
komaljai Apr 2, 2024
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
184 changes: 169 additions & 15 deletions backends/ebpf/codeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,16 @@ bool CodeGenInspector::preorder(const IR::Operation_Binary *b) {
bool useParens = getParent<IR::IfStatement>() == nullptr || mask != "";
if (mask != "") builder->append("(");
if (useParens) builder->append("(");
visit(b->left);
builder->spc();
builder->append(b->getStringOp());
builder->spc();
expressionPrecedence = b->getPrecedence() + 1;
visit(b->right);
if (builder->target->name == "P4TC") {
emitTCBinaryOperation(b, true);
} else {
visit(b->left);
builder->spc();
builder->append(b->getStringOp());
builder->spc();
expressionPrecedence = b->getPrecedence() + 1;
visit(b->right);
}
if (useParens) builder->append(")");
builder->append(mask);
expressionPrecedence = prec;
Expand All @@ -104,20 +108,28 @@ bool CodeGenInspector::comparison(const IR::Operation_Relation *b) {
int prec = expressionPrecedence;
bool useParens = prec > b->getPrecedence();
if (useParens) builder->append("(");
visit(b->left);
builder->spc();
builder->append(b->getStringOp());
builder->spc();
visit(b->right);
if (builder->target->name == "P4TC") {
emitTCBinaryOperation(b, scalar);
} else {
visit(b->left);
builder->spc();
builder->append(b->getStringOp());
builder->spc();
visit(b->right);
}
if (useParens) builder->append(")");
} else {
if (!et->is<IHasWidth>())
BUG("%1%: Comparisons for type %2% not yet implemented", b->left, type);
unsigned width = et->to<IHasWidth>()->implementationWidthInBits();
builder->append("memcmp(&");
visit(b->left);
builder->append(", &");
visit(b->right);
if (builder->target->name == "P4TC") {
emitTCBinaryOperation(b, scalar);
} else {
visit(b->left);
builder->append(", &");
visit(b->right);
}
builder->appendFormat(", %d)", width / 8);
}
return false;
Expand Down Expand Up @@ -361,7 +373,11 @@ void CodeGenInspector::emitAssignStatement(const IR::Type *ltype, const IR::Expr
builder->append(lpath);
}
builder->append(" = ");
visit(rexpr);
if (builder->target->name == "P4TC") {
emitTCAssignmentEndianessConversion(lexpr, rexpr);
} else {
visit(rexpr);
}
}
builder->endOfStatement();
}
Expand Down Expand Up @@ -458,6 +474,144 @@ void CodeGenInspector::widthCheck(const IR::Node *node) const {
node, tb->size);
}

void CodeGenInspector::emitAndConvertByteOrder(const IR::Expression *expr, cstring byte_order) {
auto ftype = typeMap->getType(expr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned widthToEmit = dynamic_cast<IHasWidth *>(et)->widthInBits();
cstring emit = "";
unsigned loadSize = 64;
if (widthToEmit <= 16) {
emit = byte_order == "HOST" ? "bpf_ntohs" : "bpf_htons";
loadSize = 16;
} else if (widthToEmit <= 32) {
emit = byte_order == "HOST" ? "bpf_ntohl" : "bpf_htonl";
loadSize = 32;
} else if (widthToEmit <= 64) {
emit = byte_order == "HOST" ? "ntohll" : "bpf_cpu_to_be64";
loadSize = 64;
}
unsigned shift = loadSize - widthToEmit;
builder->appendFormat("%s(", emit);
visit(expr);
if (shift != 0 && byte_order == "HOST") builder->appendFormat(" << %d", shift);
builder->append(")");
}

void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool isScalar) {
const IR::Expression *lexpr = b->left;
const IR::Expression *rexpr = b->right;
cstring stringop = b->getStringOp();

auto action = findContext<IR::P4Action>();
auto tcTarget = dynamic_cast<const P4TCTarget *>(builder->target);
cstring lByteOrder = "HOST", rByteOrder = "HOST";
if (lexpr) {
lByteOrder = tcTarget->getByteOrder(typeMap, action, lexpr);
}
if (rexpr) {
rByteOrder = tcTarget->getByteOrder(typeMap, action, rexpr);
}
if (lByteOrder == rByteOrder) {
visit(lexpr);
if (isScalar) {
builder->spc();
builder->append(stringop);
builder->spc();
} else {
builder->append(", &");
}
if (!b->is<IR::Operation_Relation>()) expressionPrecedence = b->getPrecedence() + 1;
visit(rexpr);
return;
}
if (lByteOrder == "NETWORK") {
// ConvertLeft
auto ftype = typeMap->getType(lexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned width = dynamic_cast<IHasWidth *>(et)->widthInBits();
if (width <= 8) {
visit(lexpr);
} else {
emitAndConvertByteOrder(lexpr, "NETWORK");
}
if (isScalar) {
builder->spc();
builder->append(stringop);
builder->spc();
} else {
builder->append(", &");
}
if (!b->is<IR::Operation_Relation>()) expressionPrecedence = b->getPrecedence() + 1;
visit(rexpr);
return;
} else if (rByteOrder == "NETWORK") {
// ConvertRight
auto ftype = typeMap->getType(rexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned width = dynamic_cast<IHasWidth *>(et)->widthInBits();
visit(lexpr);
if (isScalar) {
builder->spc();
builder->append(stringop);
builder->spc();
} else {
builder->append(", &");
}
if (!b->is<IR::Operation_Relation>()) expressionPrecedence = b->getPrecedence() + 1;
if (width <= 8) {
visit(rexpr);
} else {
emitAndConvertByteOrder(rexpr, "NETWORK");
}
}
return;
}

void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression *lexpr,
const IR::Expression *rexpr) {
auto action = findContext<IR::P4Action>();
auto b = dynamic_cast<const P4TCTarget *>(builder->target);
cstring lByteOrder = "HOST", rByteOrder = "HOST";
if (lexpr) {
lByteOrder = b->getByteOrder(typeMap, action, lexpr);
}
if (rexpr) {
rByteOrder = b->getByteOrder(typeMap, action, rexpr);
}
if (lByteOrder == rByteOrder) {
visit(rexpr);
return;
}
auto ftype = typeMap->getType(rexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned width = dynamic_cast<IHasWidth *>(et)->widthInBits();
if (width <= 8) {
visit(rexpr);
return;
}
if (rByteOrder == "NETWORK") {
/*
If left side of assignment is not annotated field i.e host endian and right expression
is annotated field i.e network endian, we need to convert rexp to host order.
Example -
select_0 = hdr.ipv4.diffserv
select_0 = bntoh(hdr.ipv4.diffserv)
*/
emitAndConvertByteOrder(rexpr, "HOST");
}
if (lByteOrder == "NETWORK") {
/*
If left side of assignment is annotated field i.e network endian, we need to convert
right expression to network order.
Example -
hdr.opv4.diffserv = 0x1;
hdr.opv4.diffserv = bhton(0x1)
*/
emitAndConvertByteOrder(rexpr, "NETWORK");
}
return;
}

unsigned EBPFInitializerUtils::ebpfTypeWidth(P4::TypeMap *typeMap, const IR::Expression *expr) {
auto type = typeMap->getType(expr);
if (type == nullptr) type = expr->type;
Expand Down
4 changes: 4 additions & 0 deletions backends/ebpf/codeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class CodeGenInspector : public Inspector {
bool preorder(const IR::IfStatement *s) override;

void widthCheck(const IR::Node *node) const;
void emitAndConvertByteOrder(const IR::Expression *expr, cstring byte_order);
void emitTCBinaryOperation(const IR::Operation_Binary *b, bool isScalar);
void emitTCAssignmentEndianessConversion(const IR::Expression *lexpr,
const IR::Expression *rexpr);
};

class EBPFInitializerUtils {
Expand Down
2 changes: 1 addition & 1 deletion backends/ebpf/ebpfParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ bool StateTranslationVisitor::preorder(const IR::SelectExpression *expression) {
etype->declare(builder, selectValue, false);
builder->endOfStatement(true);

emitAssignStatement(type, nullptr, selectValue, expression->select);
emitAssignStatement(type, nullptr, selectValue, expression->select->components.at(0));
builder->newline();

// Init value_sets
Expand Down
47 changes: 44 additions & 3 deletions backends/ebpf/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
#ifndef BACKENDS_EBPF_TARGET_H_
#define BACKENDS_EBPF_TARGET_H_

#include "frontends/p4/typeMap.h"
#include "ir/ir.h"
#include "lib/cstring.h"
#include "lib/error.h"
#include "lib/exceptions.h"
Expand Down Expand Up @@ -196,6 +198,45 @@ class KernelSamplesTarget : public Target {
cstring valueType) const;
};

class P4TCTarget : public KernelSamplesTarget {
public:
explicit P4TCTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "P4TC") {}
cstring getByteOrderFromAnnotation(const IR::Vector<IR::Annotation> annotations) const {
for (auto anno : annotations) {
if (anno->name != "tc_type") continue;
for (auto annoVal : anno->body) {
if (annoVal->text == "macaddr" || annoVal->text == "ipv4" ||
annoVal->text == "ipv6" || annoVal->text == "be16" || annoVal->text == "be32" ||
annoVal->text == "be64") {
return "NETWORK";
}
}
}
return "HOST";
}

cstring getByteOrder(P4::TypeMap *typeMap, const IR::P4Action *action,
const IR::Expression *exp) const {
if (auto mem = exp->to<IR::Member>()) {
auto type = typeMap->getType(mem->expr, true);
if (type->is<IR::Type_StructLike>()) {
auto field = type->to<IR::Type_StructLike>()->getField(mem->member);
return getByteOrderFromAnnotation(field->getAnnotations()->annotations);
}
} else if (action) {
auto paramList = action->getParameters();
if (paramList != nullptr && !paramList->empty()) {
for (auto param : paramList->parameters) {
if (param->name.originalName == exp->toString()) {
return getByteOrderFromAnnotation(param->getAnnotations()->annotations);
}
}
}
}
return "HOST";
}
};

// Target XDP
class XdpTarget : public KernelSamplesTarget {
public:
Expand Down Expand Up @@ -224,10 +265,10 @@ class XdpTarget : public KernelSamplesTarget {
class BccTarget : public Target {
public:
BccTarget() : Target("BCC") {}
void emitLicense(Util::SourceCodeBuilder *, cstring) const override {};
void emitLicense(Util::SourceCodeBuilder *, cstring) const override {}
void emitCodeSection(Util::SourceCodeBuilder *, cstring) const override {}
void emitIncludes(Util::SourceCodeBuilder *builder) const override;
void emitResizeBuffer(Util::SourceCodeBuilder *, cstring, cstring) const override {};
void emitResizeBuffer(Util::SourceCodeBuilder *, cstring, cstring) const override {}
void emitTableLookup(Util::SourceCodeBuilder *builder, cstring tblName, cstring key,
cstring value) const override;
void emitTableUpdate(Util::SourceCodeBuilder *builder, cstring tblName, cstring key,
Expand Down Expand Up @@ -256,7 +297,7 @@ class TestTarget : public EBPF::KernelSamplesTarget {
public:
TestTarget() : KernelSamplesTarget(false, "Userspace Test") {}

void emitResizeBuffer(Util::SourceCodeBuilder *, cstring, cstring) const override {};
void emitResizeBuffer(Util::SourceCodeBuilder *, cstring, cstring) const override {}
void emitIncludes(Util::SourceCodeBuilder *builder) const override;
void emitTableDecl(Util::SourceCodeBuilder *builder, cstring tblName, TableKind tableKind,
cstring keyType, cstring valueType, unsigned size) const override;
Expand Down
2 changes: 1 addition & 1 deletion backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ bool Backend::process() {
}

bool Backend::ebpfCodeGen(P4::ReferenceMap *refMapEBPF, P4::TypeMap *typeMapEBPF) {
target = new EBPF::KernelSamplesTarget(options.emitTraceMessages);
target = new EBPF::P4TCTarget(options.emitTraceMessages);
ebpfOption.xdp2tcMode = options.xdp2tcMode;
ebpfOption.exe_name = options.exe_name;
ebpfOption.file = options.file;
Expand Down
26 changes: 17 additions & 9 deletions backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1760,18 +1760,25 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) {
EBPF::EBPFScalarType *scalar = nullptr;
cstring swap;

bool isLPMKeyBigEndian = false;
if (table->isLPMTable()) {
if (c->matchType->path->name.name == P4::P4CoreLibrary::instance().lpmMatch.name)
isLPMKeyBigEndian = true;
auto tcTarget = dynamic_cast<const EBPF::P4TCTarget *>(builder->target);
cstring isKeyBigEndian =
tcTarget->getByteOrderFromAnnotation(c->getAnnotations()->annotations);
cstring isDefnBigEndian = "HOST";
if (auto mem = c->expression->to<IR::Member>()) {
auto type = typeMap->getType(mem->expr, true);
if (type->is<IR::Type_StructLike>()) {
auto field = type->to<IR::Type_StructLike>()->getField(mem->member);
isDefnBigEndian =
tcTarget->getByteOrderFromAnnotation(field->getAnnotations()->annotations);
}
}

if (ebpfType->is<EBPF::EBPFScalarType>()) {
scalar = ebpfType->to<EBPF::EBPFScalarType>();
unsigned width = scalar->implementationWidthInBits();
memcpy = !EBPF::EBPFScalarType::generatesScalar(width);

if (isLPMKeyBigEndian) {
if (isKeyBigEndian == "NETWORK" && isDefnBigEndian == "HOST") {
if (width <= 8) {
swap = ""; // single byte, nothing to swap
} else if (width <= 16) {
Expand All @@ -1794,9 +1801,10 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) {
builder->appendFormat("[0]), %d)", scalar->bytesRequired());
} else {
builder->appendFormat("%s.%s = ", keyname.c_str(), fieldName.c_str());
if (isLPMKeyBigEndian) builder->appendFormat("%s(", swap.c_str());
if (isKeyBigEndian == "NETWORK" && isDefnBigEndian == "HOST")
builder->appendFormat("%s(", swap.c_str());
table->codeGen->visit(c->expression);
if (isLPMKeyBigEndian) builder->append(")");
if (isKeyBigEndian == "NETWORK" && isDefnBigEndian == "HOST") builder->append(")");
}
builder->endOfStatement(true);

Expand Down Expand Up @@ -1906,13 +1914,13 @@ bool ControlBodyTranslatorPNA::preorder(const IR::AssignmentStatement *a) {
// =====================ActionTranslationVisitorPNA=============================
ActionTranslationVisitorPNA::ActionTranslationVisitorPNA(
const EBPF::EBPFProgram *program, cstring valueName, const EBPF::EBPFTablePSA *table,
const ConvertToBackendIR *tcIR, const IR::P4Action *action, bool isDefaultAction)
const ConvertToBackendIR *tcIR, const IR::P4Action *act, bool isDefaultAction)
: EBPF::CodeGenInspector(program->refMap, program->typeMap),
EBPF::ActionTranslationVisitor(valueName, program),
ControlBodyTranslatorPNA(program->as<EBPF::EBPFPipeline>().control, tcIR, table),
table(table),
isDefaultAction(isDefaultAction) {
action = action;
action = act;
}

bool ActionTranslationVisitorPNA::preorder(const IR::PathExpression *pe) {
Expand Down
2 changes: 1 addition & 1 deletion backends/tc/ebpfCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class ActionTranslationVisitorPNA : public EBPF::ActionTranslationVisitor,
const ConvertToBackendIR *tcIR;
ActionTranslationVisitorPNA(const EBPF::EBPFProgram *program, cstring valueName,
const EBPF::EBPFTablePSA *table, const ConvertToBackendIR *tcIR,
const IR::P4Action *action, bool isDefaultAction);
const IR::P4Action *act, bool isDefaultAction);
bool preorder(const IR::PathExpression *pe) override;
bool isActionParameter(const IR::Expression *expression) const;

Expand Down
Loading
Loading