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

Fix missing declaration of custom externs in the generated eBPF/uBPF header file. #4644

Merged
merged 7 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
27 changes: 27 additions & 0 deletions backends/ebpf/ebpfProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,20 @@ void EBPFProgram::emitTypes(CodeBuilder *builder) {
type->emit(builder);
builder->newline();
}
if (const auto *method = d->to<IR::Method>()) {
if (!method->srcInfo.isValid()) {
continue;
}
// Ignore methods originating from core.p4 and ubpf_model.p4 because they are already
// defined.
// TODO: Maybe we should still generate declarations for these methods?
if (isLibraryMethod(method->controlPlaneName())) {
continue;
}
EBPFMethodDeclaration methodInstance(method);
methodInstance.emit(builder);
builder->newline();
}
}
}

Expand Down Expand Up @@ -332,4 +346,17 @@ void EBPFProgram::emitPipeline(CodeBuilder *builder) {
}
}

bool EBPFProgram::isLibraryMethod(cstring methodName) {
static std::set<cstring> DEFAULT_METHODS = {"static_assert", "verify"};
if (DEFAULT_METHODS.find(methodName) != DEFAULT_METHODS.end() && options.target != "xdp") {
return true;
}

static std::set<cstring> XDP_METHODS = {
"ebpf_ipv4_checksum", "csum_replace2", "csum_replace4",
"BPF_PERF_EVENT_OUTPUT", "BPF_KTIME_GET_NS",
};
return XDP_METHODS.find(methodName) != XDP_METHODS.end();
}

} // namespace EBPF
5 changes: 5 additions & 0 deletions backends/ebpf/ebpfProgram.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ class EBPFProgram : public EBPFObject {
virtual void emitLocalVariables(CodeBuilder *builder);
virtual void emitPipeline(CodeBuilder *builder);

/// Checks whether a method name is considered to be part of the standard library, e.g., defined
/// in core.p4 or ebpf_model.p4.
/// TODO: Should we also distinguish overloaded methods?
virtual bool isLibraryMethod(cstring methodName);

public:
virtual void emitCommonPreamble(CodeBuilder *builder);
virtual void emitGeneratedComment(CodeBuilder *builder);
Expand Down
55 changes: 54 additions & 1 deletion backends/ebpf/ebpfType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ EBPFType *EBPFTypeFactory::create(const IR::Type *type) {
auto canon = typeMap->getTypeType(type, true);
result = create(canon);
result = new EBPFTypeName(tn, result);
} else if (auto te = type->to<IR::Type_Enum>()) {
} else if (const auto *te = type->to<IR::Type_Enum>()) {
result = new EBPFEnumType(te);
} else if (auto te = type->to<IR::Type_Error>()) {
result = new EBPFErrorType(te);
} else if (auto ts = type->to<IR::Type_Stack>()) {
auto et = create(ts->elementType);
if (et == nullptr) return nullptr;
Expand Down Expand Up @@ -325,4 +327,55 @@ void EBPFEnumType::emit(EBPF::CodeBuilder *builder) {
builder->blockEnd(true);
}

////////////////////////////////////////////////////////////////

void EBPFErrorType::declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) {
builder->append("enum ");
builder->append(getType()->name);
if (asPointer) builder->append("*");
builder->append(" ");
builder->append(id);
}

void EBPFErrorType::declareInit(CodeBuilder *builder, cstring id, bool asPointer) {
declare(builder, id, asPointer);
}

void EBPFErrorType::emit(EBPF::CodeBuilder *builder) {
builder->append("enum ");
auto et = getType();
builder->append(et->name);
builder->blockStart();
for (auto m : et->members) {
builder->append(m->name);
builder->appendLine(",");
}
builder->blockEnd(true);
}

////////////////////////////////////////////////////////////////

EBPFMethodDeclaration::EBPFMethodDeclaration(const IR::Method *method) : method_(method) {}

void EBPFMethodDeclaration::emit(CodeBuilder *builder) {
auto *returnType = EBPFTypeFactory::instance->create(method_->type->returnType);
returnType->emit(builder);
builder->append(" ");
builder->append(method_->name);
builder->append("(");
for (const auto *parameter : method_->getParameters()->parameters) {
if (parameter->direction == IR::Direction::None ||
parameter->direction == IR::Direction::In) {
builder->append("const ");
}
auto *type = EBPFTypeFactory::instance->create(parameter->type);
type->declare(builder, parameter->name, false);
if (parameter != method_->getParameters()->parameters.back()) {
builder->append(", ");
}
}
builder->append(");");
builder->newline();
}

} // namespace EBPF
29 changes: 29 additions & 0 deletions backends/ebpf/ebpfType.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,35 @@ class EBPFEnumType : public EBPFType, public EBPF::IHasWidth {
DECLARE_TYPEINFO(EBPFEnumType, EBPFType, IHasWidth);
};

class EBPFErrorType : public EBPFType, public EBPF::IHasWidth {
public:
explicit EBPFErrorType(const IR::Type_Error *type) : EBPFType(type) {}
void emit(CodeBuilder *builder) override;
void declare(CodeBuilder *builder, cstring id, bool asPointer) override;
void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override;
void emitInitializer(CodeBuilder *builder) override { builder->append("0"); }
unsigned widthInBits() const override { return 32; }
unsigned implementationWidthInBits() const override { return 32; }
const IR::Type_Error *getType() const { return type->to<IR::Type_Error>(); }

DECLARE_TYPEINFO(EBPFErrorType, EBPFType, IHasWidth);
};

/// Methods are function signatures.
class EBPFMethodDeclaration : public EBPFObject {
private:
/// The underlying P4 method of this declaration.
const IR::Method *method_;

public:
explicit EBPFMethodDeclaration(const IR::Method *method);

/// Emit the signature declaration of this method in C-style form.
void emit(CodeBuilder *builder);

DECLARE_TYPEINFO(EBPFMethodDeclaration, EBPFObject);
};

} // namespace EBPF

#endif /* BACKENDS_EBPF_EBPFTYPE_H_ */
4 changes: 3 additions & 1 deletion backends/ebpf/runtime/runtime.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ BPFOBJ=
BPFNAME=$(basename $(BPFOBJ))
BPFDIR=$(dir $(BPFOBJ))
override INCLUDES+= -I$(dir $(BPFOBJ))
# This can be any file with the extension ".c"
EXTERNOBJ=

# Arguments for the P4 Compiler
P4INCLUDE=-I./p4include
Expand All @@ -31,7 +33,7 @@ SOURCE_BASE= $(ROOT_DIR)ebpf_runtime.c $(ROOT_DIR)pcap_util.c
SOURCE_BASE+= $(ROOT_DIR)ebpf_runtime_$(TARGET).c
# Add the generated file and externs to the base sources
override SOURCES+= $(SOURCE_BASE)
SRC_PROCESSED= $(notdir $(SOURCES))
SRC_PROCESSED= $(notdir $(SOURCES)) $(EXTERNOBJ)
OBJECTS = $(SRC_PROCESSED:%.c=$(BUILDDIR)/%.o)
DEPS = $(OBJECTS:%.o=%.d)

Expand Down
5 changes: 1 addition & 4 deletions backends/ebpf/targets/test_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ def compile_dataplane(self):
# include the src of libbpf directly, does not require installation
args += f"INCLUDES+=-I{self.runtimedir}/contrib/libbpf/src "
if self.options.extern:
# we inline the extern so we need a direct include
args += f"INCLUDES+=-include{self.options.extern} "
# need to include the temporary dir because of the tmp import
args += f"INCLUDES+=-I{self.tmpdir} "
args += f"EXTERNOBJ+={self.options.extern} "
result = testutils.exec_process(args)
if result.returncode != testutils.SUCCESS:
testutils.log.error("Failed to build the filter")
Expand Down
14 changes: 14 additions & 0 deletions backends/ubpf/ubpfProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ void UBPFProgram::emitTypes(EBPF::CodeBuilder *builder) {
type->emit(builder);
builder->newline();
}
if (const auto *method = d->to<IR::Method>()) {
if (!method->srcInfo.isValid()) {
continue;
}
// Ignore methods originating from core.p4 and ubpf_model.p4 because they are already
// defined.
// TODO: Maybe we should still generate declarations for these methods?
if (isLibraryMethod(method->controlPlaneName())) {
continue;
}
EBPF::EBPFMethodDeclaration methodInstance(method);
methodInstance.emit(builder);
builder->newline();
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions backends/ubpf/ubpfProgram.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ class UBPFProgram : public EBPF::EBPFProgram {
void emitMetadataInstance(EBPF::CodeBuilder *builder) const;
void emitLocalVariables(EBPF::CodeBuilder *builder) override;
void emitPipeline(EBPF::CodeBuilder *builder) override;

bool isLibraryMethod(cstring methodName) override {
static std::set<cstring> DEFAULT_METHODS = {
"mark_to_drop", "mark_to_pass", "ubpf_time_get_ns", "truncate",
"hash", "csum_replace2", "csum_replace4",
};
return DEFAULT_METHODS.find(methodName) != DEFAULT_METHODS.end() ||
EBPFProgram::isLibraryMethod(methodName);
}
};

} // namespace UBPF
Expand Down
18 changes: 18 additions & 0 deletions backends/ubpf/ubpfType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ EBPF::EBPFType *UBPFTypeFactory::create(const IR::Type *type) {
result = new EBPF::EBPFTypeName(tn, result);
} else if (auto te = type->to<IR::Type_Enum>()) {
result = new UBPFEnumType(te);
} else if (auto te = type->to<IR::Type_Error>()) {
result = new UBPFErrorType(te);
} else if (auto ts = type->to<IR::Type_Stack>()) {
auto et = create(ts->elementType);
if (et == nullptr) return nullptr;
Expand Down Expand Up @@ -155,6 +157,7 @@ void UBPFStructType::declare(EBPF::CodeBuilder *builder, cstring id, bool asPoin
void UBPFStructType::declareInit(EBPF::CodeBuilder *builder, cstring id, bool asPointer) {
declare(builder, id, asPointer);
}

//////////////////////////////////////////////////////////

void UBPFEnumType::emit(EBPF::CodeBuilder *builder) {
Expand All @@ -172,6 +175,21 @@ void UBPFEnumType::emit(EBPF::CodeBuilder *builder) {

//////////////////////////////////////////////////////////

void UBPFErrorType::emit(EBPF::CodeBuilder *builder) {
builder->append("enum ");
auto et = getType();
builder->append(et->name);
builder->blockStart();
for (auto m : et->members) {
builder->append(m->name);
builder->appendLine(",");
}
builder->blockEnd(false);
builder->endOfStatement(true);
}

//////////////////////////////////////////////////////////

UBPFListType::UBPFListType(const IR::Type_List *lst) : EBPFType(lst) {
kind = "struct";
width = 0;
Expand Down
23 changes: 23 additions & 0 deletions backends/ubpf/ubpfType.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ class UBPFScalarType : public EBPF::EBPFScalarType {
DECLARE_TYPEINFO(UBPFScalarType, EBPF::EBPFScalarType);
};

class UBPFExternType : public EBPF::EBPFScalarType {
public:
explicit UBPFExternType(const IR::Type_Bits *bits) : EBPF::EBPFScalarType(bits) {}

void emit(EBPF::CodeBuilder *builder) override;

cstring getAsString();

void declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override;
void declareInit(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override;

DECLARE_TYPEINFO(UBPFExternType, EBPF::EBPFScalarType);
};

class UBPFStructType : public EBPF::EBPFStructType {
public:
explicit UBPFStructType(const IR::Type_StructLike *strct) : EBPF::EBPFStructType(strct) {}
Expand All @@ -77,6 +91,15 @@ class UBPFEnumType : public EBPF::EBPFEnumType {
DECLARE_TYPEINFO(UBPFEnumType, EBPF::EBPFEnumType);
};

class UBPFErrorType : public EBPF::EBPFErrorType {
public:
explicit UBPFErrorType(const IR::Type_Error *strct) : EBPF::EBPFErrorType(strct) {}

void emit(EBPF::CodeBuilder *builder) override;

DECLARE_TYPEINFO(UBPFErrorType, EBPF::EBPFErrorType);
};

class UBPFListType : public EBPF::EBPFType, public EBPF::IHasWidth {
class UBPFListElement : public ICastable {
public:
Expand Down
2 changes: 1 addition & 1 deletion testdata/extern_modules/extern-checksum-ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @param iphdr Structure representing IP header. The IP header is generated by the P4 compiler and defined in test.h.
* @return True if checksum is correct.
*/
static inline u8 verify_ipv4_checksum(const struct IPv4_h iphdr)
u8 verify_ipv4_checksum(const struct IPv4_h iphdr)
{
u8 correct = 0;
u32 checksum = bpf_htons(((u16) iphdr.version << 12) | ((u16) iphdr.ihl << 8) | (u16) iphdr.diffserv);
Expand Down
2 changes: 1 addition & 1 deletion testdata/extern_modules/extern-conntrack-ebpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ REGISTER_START()
REGISTER_TABLE(tcp_reg, BPF_MAP_TYPE_HASH, sizeof(u32), sizeof(struct connInfo), MAX_ENTRIES)
REGISTER_END()

static inline u8 tcp_conntrack(struct Headers_t hdrs)
u8 tcp_conntrack(struct Headers_t hdrs)
{
u32 saddr = hdrs.ipv4.srcAddr;
u32 daddr = hdrs.ipv4.dstAddr;
Expand Down
Loading