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 1 commit
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
130 changes: 31 additions & 99 deletions backends/ebpf/codeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,18 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
const IR::Expression *lexpr = b->left;
const IR::Expression *rexpr = b->right;
cstring stringop = b->getStringOp();
bool left = EBPFInitializerUtils::IsHeaderField(typeMap, lexpr);
bool right = EBPFInitializerUtils::IsHeaderField(typeMap, rexpr);
if (left == right) {

auto action = findContext<IR::P4Action>();
auto table = findContext<IR::P4Table>();
auto tcTarget = dynamic_cast<const P4TCTarget *>(builder->target);
bool isLAnnotated = false, isRAnnotated = false;
if (lexpr) {
isLAnnotated = tcTarget->isNetworkOrder(typeMap, action, table, lexpr);
}
if (rexpr) {
isRAnnotated = tcTarget->isNetworkOrder(typeMap, action, table, rexpr);
}
if (isLAnnotated == isRAnnotated) {
visit(lexpr);
if (isScalar) {
builder->spc();
Expand All @@ -513,7 +522,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
visit(rexpr);
return;
}
if (!left) {
if (isLAnnotated) {
// ConvertLeft
auto ftype = typeMap->getType(lexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
Expand All @@ -533,7 +542,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
expressionPrecedence = b->getPrecedence() + 1;
visit(rexpr);
return;
} else if (!right) {
} else if (isRAnnotated) {
// ConvertRight
auto ftype = typeMap->getType(rexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
Expand All @@ -543,7 +552,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
builder->spc();
builder->append(stringop);
builder->spc();
} else {
} else {
builder->append(", &");
}
expressionPrecedence = b->getPrecedence() + 1;
komaljai marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -558,9 +567,17 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool

void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression *lexpr,
const IR::Expression *rexpr) {
auto left = EBPFInitializerUtils::IsHeaderField(typeMap, lexpr);
auto right = EBPFInitializerUtils::IsHeaderField(typeMap, rexpr);
if (left == right) {
auto action = findContext<IR::P4Action>();
auto table = findContext<IR::P4Table>();
auto b = dynamic_cast<const P4TCTarget *>(builder->target);
bool isLAnnotated = false, isRAnnotated = false;
if(lexpr) {
isLAnnotated = b->isNetworkOrder(typeMap, action, table, lexpr);
}
if (rexpr) {
isRAnnotated = b->isNetworkOrder(typeMap, action, table, rexpr);
}
if (isLAnnotated == isRAnnotated) {
visit(rexpr);
return;
}
Expand All @@ -571,19 +588,19 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression
visit(rexpr);
return;
}
if (right) {
if (isRAnnotated) {
/*
If left side of assignment is non-header field and right expression
is header field, we need to convert rexp to host order.
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 (left) {
if (isLAnnotated) {
/*
If left side of assignment is header field, we need to convert
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;
Expand Down Expand Up @@ -623,89 +640,4 @@ cstring EBPFInitializerUtils::genHexStr(const big_int &value, unsigned width,
return str;
}

const IR::Expression *EBPFInitializerUtils::ExtractExpFromCast(const IR::Expression *exp) {
const IR::Expression *castexp = exp;
while (castexp->is<IR::Cast>()) {
castexp = castexp->to<IR::Cast>()->expr;
}
return castexp;
}

const IR::Expression *EBPFInitializerUtils::ExtractSliceFromExp(const IR::Expression *exp) {
auto baseexp = exp;
if (baseexp->is<IR::Slice>()) {
baseexp = baseexp->to<IR::Slice>()->e0;
}
return baseexp;
}

// return true if an expression is header or header union
bool EBPFInitializerUtils::IsTypeHeaderOrUnion(const P4::TypeMap *typemap,
const IR::Expression *exp) {
if (!exp) return false;
auto tempexp = ExtractExpFromCast(exp);
if (tempexp->is<IR::Slice>()) {
tempexp = tempexp->to<IR::Slice>()->e0;
}
auto memexp = tempexp;
if (tempexp->is<IR::Member>() && tempexp->type->is<IR::Type_Bits>()) {
memexp = tempexp->to<IR::Member>()->expr;
}
if (memexp->is<IR::ArrayIndex>()) {
memexp = memexp->to<IR::ArrayIndex>()->left;
}
if (!memexp) return false;
if (!memexp->is<IR::Member>()) return false;
auto type = typemap->getType(memexp);
if (type == nullptr && memexp->type != nullptr) {
type = memexp->type;
}
if (type && type->is<IR::Type_Stack>()) {
type = type->to<IR::Type_Stack>()->elementType;
}
if (type && (type->is<IR::Type_Header>() || type->is<IR::Type_HeaderUnion>())) return true;
return false;
}

// return true if an expression is array of header or array of hader union
// example: hdrs.mpls[] type
bool EBPFInitializerUtils::IsTypeArrayHeader(const P4::TypeMap *typemap,
const IR::Expression *exp) {
if (!exp) return false;
if (!exp->is<IR::Member>()) return false;
auto memexp = exp->to<IR::Member>()->expr;
if (!memexp) return false;
if (!memexp->is<IR::ArrayIndex>()) return false;
auto leftexp = memexp->to<IR::ArrayIndex>()->left;
auto rightexp = memexp->to<IR::ArrayIndex>()->right;
if (!leftexp) return false;
if (!leftexp->is<IR::Member>()) return false;
if (!rightexp) return false;
auto type = typemap->getType(memexp);
if (type == nullptr && memexp->type) {
type = memexp->type;
}
if (!type) return false;
if (type->is<IR::Type_Header>() || type->is<IR::Type_HeaderUnion>()) {
return true;
}
return false;
}

bool EBPFInitializerUtils::IsHeaderField(const P4::TypeMap *typemap, const IR::Expression *exp) {
if (exp == nullptr) {
return false;
}
if (exp->is<IR::Constant>()) return false;
auto exp1 = exp;
// remove cast from the expression IR
exp1 = ExtractExpFromCast(exp1);
// get slice expression if it is slice
exp1 = ExtractSliceFromExp(exp1);
if (IsTypeHeaderOrUnion(typemap, exp1) || IsTypeArrayHeader(typemap, exp1)) {
return true;
}
return false;
}

} // namespace EBPF
5 changes: 0 additions & 5 deletions backends/ebpf/codeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,6 @@ class EBPFInitializerUtils {

// Generate hex string and prepend it with zeroes when shorter than required width
static cstring genHexStr(const big_int &value, unsigned width, const IR::Expression *expr);
static const IR::Expression *ExtractExpFromCast(const IR::Expression *exp);
static const IR::Expression *ExtractSliceFromExp(const IR::Expression *exp);
static bool IsTypeHeaderOrUnion(const P4::TypeMap *typemap, const IR::Expression *exp);
static bool IsTypeArrayHeader(const P4::TypeMap *typemap, const IR::Expression *exp);
static bool IsHeaderField(const P4::TypeMap *typemap, const IR::Expression *exp);
};

} // namespace EBPF
Expand Down
45 changes: 45 additions & 0 deletions backends/ebpf/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ limitations under the License.
#include "lib/error.h"
#include "lib/exceptions.h"
#include "lib/sourceCodeBuilder.h"
#include "frontends/p4/typeMap.h"
#include "ir/ir.h"

// We are prepared to support code generation using multiple styles
// (e.g., using BCC or using CLANG).
Expand Down Expand Up @@ -199,6 +201,49 @@ class KernelSamplesTarget : public Target {
class P4TCTarget : public KernelSamplesTarget {
public:
explicit P4TCTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "P4TC") {}
bool isAnnotated(const IR::Vector<IR::Annotation> annotations) const {
komaljai marked this conversation as resolved.
Show resolved Hide resolved
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 true;
}
}
}
return false;
}

bool isNetworkOrder(P4::TypeMap *typeMap, const IR::P4Action *action, const IR::P4Table *table,
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 isAnnotated(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 isAnnotated(param->getAnnotations()->annotations);
}
}
}
} else if (table) {
auto key = table->getKey();
if (key != nullptr && key->keyElements.size()) {
for (auto k : key->keyElements) {
if(k->expression->toString() == exp->toString()) {
return isAnnotated(k->getAnnotations()->annotations);
}
}
}
}
return false;
}
};

// Target XDP
Expand Down
4 changes: 2 additions & 2 deletions testdata/p4tc_samples/ipip.p4
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ struct metadata_t {
}

header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
@tc_type ("macaddr") bit<48> dstAddr;
@tc_type ("macaddr") bit<48> srcAddr;
bit<16> etherType;
}

Expand Down
2 changes: 1 addition & 1 deletion testdata/p4tc_samples_outputs/checksum_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static __always_inline int run_parser(struct __sk_buff *skb, struct my_ingress_h
;
tmp_0 = /* ck_0.get() */
((u16) (~ck_0_state));/* verify(hdr->ipv4.hdrChecksum == tmp_0, BadIPv4HeaderChecksum) */
if (!(hdr->ipv4.hdrChecksum == tmp_0)) {
if (!((hdr->ipv4.hdrChecksum == tmp_0))) {
komaljai marked this conversation as resolved.
Show resolved Hide resolved
ebpf_errorCode = BadIPv4HeaderChecksum;
goto reject;
}
Expand Down
6 changes: 2 additions & 4 deletions testdata/p4tc_samples_outputs/ipip_control_blocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ if (/* hdr->outer.isValid() */
switch (value->action) {
case MAIN_FWD_TABLE_ACT_MAIN_SET_IPIP:
{
meta->src = value->u.Main_set_ipip.src;
meta->dst = value->u.Main_set_ipip.dst;
meta->src = bpf_ntohl(value->u.Main_set_ipip.src);
meta->dst = bpf_ntohl(value->u.Main_set_ipip.dst);
meta->push = true;
/* send_to_port(value->u.Main_set_ipip.port) */
compiler_meta__->drop = false;
Expand Down Expand Up @@ -182,7 +182,6 @@ if (/* hdr->outer.isValid() */
return TC_ACT_SHOT;
}

hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16);
komaljai marked this conversation as resolved.
Show resolved Hide resolved
ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[0];
write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte));
ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[1];
Expand All @@ -197,7 +196,6 @@ if (/* hdr->outer.isValid() */
write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 5, (ebpf_byte));
ebpf_packetOffsetInBits += 48;

hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16);
ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[0];
write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte));
ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[1];
Expand Down
4 changes: 2 additions & 2 deletions testdata/p4tc_samples_outputs/ipip_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ static __always_inline int run_parser(struct __sk_buff *skb, struct headers_t *h
goto reject;
}

hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48));
__builtin_memcpy(&hdr->ethernet.dstAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6);
ebpf_packetOffsetInBits += 48;

hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48));
__builtin_memcpy(&hdr->ethernet.srcAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6);
ebpf_packetOffsetInBits += 48;

hdr->ethernet.etherType = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits))));
Expand Down