From 54d0981bc27e161bc86f188af3da7ec297123c9f Mon Sep 17 00:00:00 2001 From: fruffy Date: Mon, 29 Apr 2024 08:22:33 -0400 Subject: [PATCH 1/7] Fix missing declaration of custom externs in the generated eBPF/uBPF header file. --- backends/ebpf/ebpfProgram.cpp | 16 +++++++++++ backends/ebpf/ebpfType.cpp | 54 ++++++++++++++++++++++++++++++++++- backends/ebpf/ebpfType.h | 29 +++++++++++++++++++ backends/ubpf/ubpfProgram.cpp | 16 +++++++++++ backends/ubpf/ubpfType.cpp | 18 ++++++++++++ backends/ubpf/ubpfType.h | 23 +++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-) diff --git a/backends/ebpf/ebpfProgram.cpp b/backends/ebpf/ebpfProgram.cpp index 681b937e121..8f9eb6b6b81 100644 --- a/backends/ebpf/ebpfProgram.cpp +++ b/backends/ebpf/ebpfProgram.cpp @@ -196,6 +196,22 @@ void EBPFProgram::emitTypes(CodeBuilder *builder) { type->emit(builder); builder->newline(); } + if (const auto *method = d->to()) { + if (method->srcInfo.isValid()) { + continue; + } + // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already + // defined. + // TODO: Is there a more portable way to do this? Currently we check for a specific + // filename as the source of a method. + auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); + if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + continue; + } + EBPFMethodDeclaration methodInstance(method); + methodInstance.emit(builder); + builder->newline(); + } } } diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 10c12961eec..0dd0432a877 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -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()) { + } else if (const auto *te = type->to()) { result = new EBPFEnumType(te); + } else if (auto te = type->to()) { + result = new EBPFErrorType(te); } else if (auto ts = type->to()) { auto et = create(ts->elementType); if (et == nullptr) return nullptr; @@ -325,4 +327,54 @@ 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(");"); +} + } // namespace EBPF diff --git a/backends/ebpf/ebpfType.h b/backends/ebpf/ebpfType.h index 6af9a9cdbc5..703738b59ad 100644 --- a/backends/ebpf/ebpfType.h +++ b/backends/ebpf/ebpfType.h @@ -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(); } + + 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_ */ diff --git a/backends/ubpf/ubpfProgram.cpp b/backends/ubpf/ubpfProgram.cpp index 2c365485947..a40d97c987e 100644 --- a/backends/ubpf/ubpfProgram.cpp +++ b/backends/ubpf/ubpfProgram.cpp @@ -169,6 +169,22 @@ void UBPFProgram::emitTypes(EBPF::CodeBuilder *builder) { type->emit(builder); builder->newline(); } + if (const auto *method = d->to()) { + if (!method->srcInfo.isValid()) { + continue; + } + // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already + // defined. + // TODO: Is there a more portable way to do this? Currently we check for a specific + // filename as the source of a method. + auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); + if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + continue; + } + EBPF::EBPFMethodDeclaration methodInstance(method); + methodInstance.emit(builder); + builder->newline(); + } } } diff --git a/backends/ubpf/ubpfType.cpp b/backends/ubpf/ubpfType.cpp index 3049fac6e1d..b5641d8ba3f 100644 --- a/backends/ubpf/ubpfType.cpp +++ b/backends/ubpf/ubpfType.cpp @@ -41,6 +41,8 @@ EBPF::EBPFType *UBPFTypeFactory::create(const IR::Type *type) { result = new EBPF::EBPFTypeName(tn, result); } else if (auto te = type->to()) { result = new UBPFEnumType(te); + } else if (auto te = type->to()) { + result = new UBPFErrorType(te); } else if (auto ts = type->to()) { auto et = create(ts->elementType); if (et == nullptr) return nullptr; @@ -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) { @@ -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; diff --git a/backends/ubpf/ubpfType.h b/backends/ubpf/ubpfType.h index 9e0ae406d83..aada218a8eb 100644 --- a/backends/ubpf/ubpfType.h +++ b/backends/ubpf/ubpfType.h @@ -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) {} @@ -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: From 4986811fa21545fafd141b4b84c8e8a80d990a4e Mon Sep 17 00:00:00 2001 From: fruffy Date: Tue, 30 Apr 2024 10:59:40 -0400 Subject: [PATCH 2/7] Add library functions instead of checking for file names. --- backends/ebpf/ebpfProgram.cpp | 21 ++++++++++++++++----- backends/ebpf/ebpfProgram.h | 5 +++++ backends/ubpf/ubpfProgram.cpp | 6 ++---- backends/ubpf/ubpfProgram.h | 9 +++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/backends/ebpf/ebpfProgram.cpp b/backends/ebpf/ebpfProgram.cpp index 8f9eb6b6b81..24e145ea5c5 100644 --- a/backends/ebpf/ebpfProgram.cpp +++ b/backends/ebpf/ebpfProgram.cpp @@ -197,15 +197,13 @@ void EBPFProgram::emitTypes(CodeBuilder *builder) { builder->newline(); } if (const auto *method = d->to()) { - if (method->srcInfo.isValid()) { + if (!method->srcInfo.isValid()) { continue; } // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already // defined. - // TODO: Is there a more portable way to do this? Currently we check for a specific - // filename as the source of a method. - auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); - if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + // TODO: Maybe we should still generate declarations for these methods? + if (isLibraryMethod(method->controlPlaneName())) { continue; } EBPFMethodDeclaration methodInstance(method); @@ -348,4 +346,17 @@ void EBPFProgram::emitPipeline(CodeBuilder *builder) { } } +bool EBPFProgram::isLibraryMethod(cstring methodName) { + static std::set DEFAULT_METHODS = {"static_assert", "verify"}; + if (DEFAULT_METHODS.find(methodName) != DEFAULT_METHODS.end() && options.target != "xdp") { + return true; + } + + static std::set 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 diff --git a/backends/ebpf/ebpfProgram.h b/backends/ebpf/ebpfProgram.h index ff029976ac8..b354ab02825 100644 --- a/backends/ebpf/ebpfProgram.h +++ b/backends/ebpf/ebpfProgram.h @@ -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); diff --git a/backends/ubpf/ubpfProgram.cpp b/backends/ubpf/ubpfProgram.cpp index a40d97c987e..efc732ae12c 100644 --- a/backends/ubpf/ubpfProgram.cpp +++ b/backends/ubpf/ubpfProgram.cpp @@ -175,10 +175,8 @@ void UBPFProgram::emitTypes(EBPF::CodeBuilder *builder) { } // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already // defined. - // TODO: Is there a more portable way to do this? Currently we check for a specific - // filename as the source of a method. - auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); - if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + // TODO: Maybe we should still generate declarations for these methods? + if (isLibraryMethod(method->controlPlaneName())) { continue; } EBPF::EBPFMethodDeclaration methodInstance(method); diff --git a/backends/ubpf/ubpfProgram.h b/backends/ubpf/ubpfProgram.h index 3f0bad65a7f..71e2b1eb782 100644 --- a/backends/ubpf/ubpfProgram.h +++ b/backends/ubpf/ubpfProgram.h @@ -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 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 From cec9561ff5343e285366084826b08059ce8b1385 Mon Sep 17 00:00:00 2001 From: fruffy Date: Tue, 30 Apr 2024 13:12:14 -0400 Subject: [PATCH 3/7] Do not use static for extern definition if we generate a declaration. --- backends/ebpf/ebpfType.cpp | 2 ++ testdata/extern_modules/extern-checksum-ebpf.c | 2 +- testdata/extern_modules/extern-conntrack-ebpf.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 0dd0432a877..cafa78800d4 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -359,6 +359,7 @@ EBPFMethodDeclaration::EBPFMethodDeclaration(const IR::Method *method) : method_ void EBPFMethodDeclaration::emit(CodeBuilder *builder) { auto *returnType = EBPFTypeFactory::instance->create(method_->type->returnType); + builder->append("static "); returnType->emit(builder); builder->append(" "); builder->append(method_->name); @@ -375,6 +376,7 @@ void EBPFMethodDeclaration::emit(CodeBuilder *builder) { } } builder->append(");"); + builder->newline(); } } // namespace EBPF diff --git a/testdata/extern_modules/extern-checksum-ebpf.c b/testdata/extern_modules/extern-checksum-ebpf.c index 374ece9b262..a9e4cae419c 100644 --- a/testdata/extern_modules/extern-checksum-ebpf.c +++ b/testdata/extern_modules/extern-checksum-ebpf.c @@ -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); diff --git a/testdata/extern_modules/extern-conntrack-ebpf.c b/testdata/extern_modules/extern-conntrack-ebpf.c index 2b90d0a3b7e..fd6f3681cf5 100644 --- a/testdata/extern_modules/extern-conntrack-ebpf.c +++ b/testdata/extern_modules/extern-conntrack-ebpf.c @@ -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; From 333a083be3721ecbaee2e18ee1d7a5b57cb0c8ac Mon Sep 17 00:00:00 2001 From: fruffy Date: Tue, 30 Apr 2024 14:59:05 -0400 Subject: [PATCH 4/7] Use extern objects for the eBPF test framework. --- backends/ebpf/ebpfType.cpp | 1 - backends/ebpf/runtime/runtime.mk | 4 +++- backends/ebpf/targets/test_target.py | 5 +---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index cafa78800d4..114b23e4dfb 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -359,7 +359,6 @@ EBPFMethodDeclaration::EBPFMethodDeclaration(const IR::Method *method) : method_ void EBPFMethodDeclaration::emit(CodeBuilder *builder) { auto *returnType = EBPFTypeFactory::instance->create(method_->type->returnType); - builder->append("static "); returnType->emit(builder); builder->append(" "); builder->append(method_->name); diff --git a/backends/ebpf/runtime/runtime.mk b/backends/ebpf/runtime/runtime.mk index 108243ff4e9..e7fa8905d8a 100644 --- a/backends/ebpf/runtime/runtime.mk +++ b/backends/ebpf/runtime/runtime.mk @@ -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 @@ -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) diff --git a/backends/ebpf/targets/test_target.py b/backends/ebpf/targets/test_target.py index a059e124d88..45a4c02c501 100644 --- a/backends/ebpf/targets/test_target.py +++ b/backends/ebpf/targets/test_target.py @@ -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") From 0378e15f3575fc424d8e92ab0a099d5e8030c48f Mon Sep 17 00:00:00 2001 From: fruffy Date: Wed, 1 May 2024 08:52:30 -0400 Subject: [PATCH 5/7] Try an inline declaration to fix Ubuntu 20.04 problems? --- backends/ebpf/ebpfType.cpp | 1 + testdata/extern_modules/extern-checksum-ebpf.c | 2 +- testdata/extern_modules/extern-conntrack-ebpf.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 114b23e4dfb..7b1656f98b9 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -359,6 +359,7 @@ EBPFMethodDeclaration::EBPFMethodDeclaration(const IR::Method *method) : method_ void EBPFMethodDeclaration::emit(CodeBuilder *builder) { auto *returnType = EBPFTypeFactory::instance->create(method_->type->returnType); + builder->append("extern "); returnType->emit(builder); builder->append(" "); builder->append(method_->name); diff --git a/testdata/extern_modules/extern-checksum-ebpf.c b/testdata/extern_modules/extern-checksum-ebpf.c index a9e4cae419c..97801d92c4e 100644 --- a/testdata/extern_modules/extern-checksum-ebpf.c +++ b/testdata/extern_modules/extern-checksum-ebpf.c @@ -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. */ -u8 verify_ipv4_checksum(const struct IPv4_h iphdr) +inline __attribute__((always_inline)) 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); diff --git a/testdata/extern_modules/extern-conntrack-ebpf.c b/testdata/extern_modules/extern-conntrack-ebpf.c index fd6f3681cf5..7f44769bb68 100644 --- a/testdata/extern_modules/extern-conntrack-ebpf.c +++ b/testdata/extern_modules/extern-conntrack-ebpf.c @@ -32,7 +32,7 @@ REGISTER_START() REGISTER_TABLE(tcp_reg, BPF_MAP_TYPE_HASH, sizeof(u32), sizeof(struct connInfo), MAX_ENTRIES) REGISTER_END() -u8 tcp_conntrack(struct Headers_t hdrs) +inline __attribute__((always_inline)) u8 tcp_conntrack(struct Headers_t hdrs) { u32 saddr = hdrs.ipv4.srcAddr; u32 daddr = hdrs.ipv4.dstAddr; From 95778d66a905a9eef1c26ad54745628fab095ddb Mon Sep 17 00:00:00 2001 From: fruffy Date: Thu, 2 May 2024 08:51:34 -0400 Subject: [PATCH 6/7] Use a different libbpf version? --- backends/ebpf/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index 99f36f96324..a505b94a1c1 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -21,8 +21,8 @@ if(NOT APPLE) set(FETCHCONTENT_QUIET OFF) fetchcontent_declare( bpfrepo - URL https://github.com/libbpf/libbpf/archive/refs/tags/v1.2.2.tar.gz - URL_HASH SHA256=32b0c41eabfbbe8e0c8aea784d7495387ff9171b5a338480a8fbaceb9da8d5e5 + URL https://github.com/libbpf/libbpf/archive/refs/tags/v1.4.1.tar.gz + URL_HASH SHA256=cc01a3a05d25e5978c20be7656f14eb8b6fcb120bb1c7e8041e497814fc273cb SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/runtime/contrib/libbpf USES_TERMINAL_DOWNLOAD TRUE GIT_PROGRESS TRUE From c030ea01661620446d46908c77570e636157776c Mon Sep 17 00:00:00 2001 From: fruffy Date: Thu, 2 May 2024 12:55:13 -0400 Subject: [PATCH 7/7] Revert to old techniques for eBPF code. --- backends/ebpf/ebpfProgram.cpp | 32 +++++++++++-------- backends/ebpf/targets/test_target.py | 5 ++- .../extern_modules/extern-checksum-ebpf.c | 2 +- .../extern_modules/extern-conntrack-ebpf.c | 2 +- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/backends/ebpf/ebpfProgram.cpp b/backends/ebpf/ebpfProgram.cpp index 24e145ea5c5..356efb2299a 100644 --- a/backends/ebpf/ebpfProgram.cpp +++ b/backends/ebpf/ebpfProgram.cpp @@ -196,20 +196,24 @@ void EBPFProgram::emitTypes(CodeBuilder *builder) { type->emit(builder); builder->newline(); } - if (const auto *method = d->to()) { - 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(); - } + // TODO: This code is disabled until we fix stability issues in Ubuntu 20.04. + // For an unclear reason we can not use definitions and declarations for eBPF externs there. + // All externs need to be defined as static inline, which clashes with these definitions. + // Context: https://github.com/p4lang/p4c/pull/4644 + // if (const auto *method = d->to()) { + // 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(); + // } } } diff --git a/backends/ebpf/targets/test_target.py b/backends/ebpf/targets/test_target.py index 45a4c02c501..a059e124d88 100644 --- a/backends/ebpf/targets/test_target.py +++ b/backends/ebpf/targets/test_target.py @@ -44,7 +44,10 @@ 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: - args += f"EXTERNOBJ+={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} " result = testutils.exec_process(args) if result.returncode != testutils.SUCCESS: testutils.log.error("Failed to build the filter") diff --git a/testdata/extern_modules/extern-checksum-ebpf.c b/testdata/extern_modules/extern-checksum-ebpf.c index 97801d92c4e..374ece9b262 100644 --- a/testdata/extern_modules/extern-checksum-ebpf.c +++ b/testdata/extern_modules/extern-checksum-ebpf.c @@ -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. */ -inline __attribute__((always_inline)) u8 verify_ipv4_checksum(const struct IPv4_h iphdr) +static inline 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); diff --git a/testdata/extern_modules/extern-conntrack-ebpf.c b/testdata/extern_modules/extern-conntrack-ebpf.c index 7f44769bb68..2b90d0a3b7e 100644 --- a/testdata/extern_modules/extern-conntrack-ebpf.c +++ b/testdata/extern_modules/extern-conntrack-ebpf.c @@ -32,7 +32,7 @@ REGISTER_START() REGISTER_TABLE(tcp_reg, BPF_MAP_TYPE_HASH, sizeof(u32), sizeof(struct connInfo), MAX_ENTRIES) REGISTER_END() -inline __attribute__((always_inline)) u8 tcp_conntrack(struct Headers_t hdrs) +static inline u8 tcp_conntrack(struct Headers_t hdrs) { u32 saddr = hdrs.ipv4.srcAddr; u32 daddr = hdrs.ipv4.dstAddr;