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

Extend eBPF kernel target with support for additional BPF helpers and more types of BPF maps #3119

Merged
merged 4 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion backends/ebpf/ebpfProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void EBPFProgram::emitC(CodeBuilder* builder, cstring header) {
builder->append("REGISTER_END()\n");
builder->newline();
builder->emitIndent();
builder->target->emitCodeSection(builder, functionName);
builder->target->emitCodeSection(builder, "prog");
builder->emitIndent();
builder->target->emitMain(builder, functionName, model.CPacketName.str());
builder->blockStart();
Expand Down
100 changes: 93 additions & 7 deletions backends/ebpf/runtime/ebpf_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,108 @@ struct bpf_elf_map {
__u32 flags;
__u32 id;
__u32 pinning;
__u32 inner_id;
__u32 inner_idx;
};

/* simple descriptor which replaces the kernel sk_buff structure */
#define SK_BUFF struct __sk_buff

/* from iproute2, annotate table with BTF which allows to read types at runtime */
#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \
struct ____btf_map_##name { \
type_key key; \
type_val value; \
}; \
struct ____btf_map_##name \
__attribute__ ((section(".maps." #name), used)) \
____btf_map_##name = {};

#define REGISTER_START()
#ifndef BTF
/* Note: pinning exports the table name globally, do not remove */
#define REGISTER_TABLE(NAME, TYPE, KEY_SIZE, VALUE_SIZE, MAX_ENTRIES) \
#define REGISTER_TABLE(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \
struct bpf_elf_map SEC("maps") NAME = { \
.type = TYPE, \
.size_key = sizeof(KEY_TYPE), \
.size_value = sizeof(VALUE_TYPE), \
.max_elem = MAX_ENTRIES, \
.pinning = 2, \
.flags = 0, \
};
#define REGISTER_TABLE_INNER(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, ID, INNER_IDX) \
struct bpf_elf_map SEC("maps") NAME = { \
.type = TYPE, \
.size_key = sizeof(KEY_TYPE), \
.size_value = sizeof(VALUE_TYPE), \
.max_elem = MAX_ENTRIES, \
.pinning = 2, \
.flags = 0, \
.id = ID, \
.inner_idx = INNER_IDX, \
};
#define REGISTER_TABLE_OUTER(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, INNER_ID, INNER_NAME) \
struct bpf_elf_map SEC("maps") NAME = { \
.type = TYPE, \
.size_key = sizeof(KEY_TYPE), \
.size_value = sizeof(VALUE_TYPE), \
.max_elem = MAX_ENTRIES, \
.pinning = 2, \
.flags = 0, \
.inner_id = INNER_ID, \
};
#define REGISTER_TABLE_FLAGS(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, FLAGS) \
struct bpf_elf_map SEC("maps") NAME = { \
.type = TYPE, \
.size_key = KEY_SIZE, \
.size_value = VALUE_SIZE, \
.max_elem = MAX_ENTRIES, \
.pinning = 2, \
.flags = 0, \
.type = TYPE, \
.size_key = sizeof(KEY_TYPE), \
.size_value = sizeof(VALUE_TYPE), \
.max_elem = MAX_ENTRIES, \
.pinning = 2, \
.flags = FLAGS, \
};
#else
#define REGISTER_TABLE(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES) \
struct { \
__uint(type, TYPE); \
KEY_TYPE *key; \
VALUE_TYPE *value; \
__uint(max_entries, MAX_ENTRIES); \
__uint(pinning, LIBBPF_PIN_BY_NAME); \
} NAME SEC(".maps");
#define REGISTER_TABLE_FLAGS(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, FLAGS) \
struct { \
__uint(type, TYPE); \
KEY_TYPE *key; \
VALUE_TYPE *value; \
__uint(max_entries, MAX_ENTRIES); \
__uint(pinning, LIBBPF_PIN_BY_NAME); \
__uint(map_flags, FLAGS); \
} NAME SEC(".maps");
#define REGISTER_TABLE_INNER(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, ID, INNER_IDX) \
struct NAME { \
__uint(type, TYPE); \
KEY_TYPE *key; \
VALUE_TYPE *value; \
__uint(max_entries, MAX_ENTRIES); \
} NAME SEC(".maps");
#define REGISTER_TABLE_OUTER(NAME, TYPE, KEY_TYPE, VALUE_TYPE, MAX_ENTRIES, INNER_ID, INNER_NAME) \
struct { \
__uint(type, TYPE); \
KEY_TYPE *key; \
VALUE_TYPE *value; \
__uint(max_entries, MAX_ENTRIES); \
__uint(pinning, LIBBPF_PIN_BY_NAME); \
__array(values, struct INNER_NAME); \
} NAME SEC(".maps");
#define REGISTER_TABLE_NO_KEY_TYPE(NAME, TYPE, KEY_SIZE, VALUE_TYPE, MAX_ENTRIES) \
struct { \
__uint(type, TYPE); \
__uint(key_size, KEY_SIZE); \
VALUE_TYPE *value; \
__uint(max_entries, MAX_ENTRIES); \
__uint(pinning, LIBBPF_PIN_BY_NAME); \
} NAME SEC(".maps");
#endif
#define REGISTER_END()

#define BPF_MAP_LOOKUP_ELEM(table, key) \
Expand Down
2 changes: 1 addition & 1 deletion backends/ebpf/runtime/kernel.mk
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ CLANG ?= clang
override INCLUDES+= -I$(ROOT_DIR) -I$(ROOT_DIR)usr/include/ -I$(ROOT_DIR)contrib/libbpf/include/uapi/
override LIBS+=
# Optimization flags to save space
override CFLAGS+= -O2 -g -D__KERNEL__ -D__ASM_SYSREG_H \
override CFLAGS+= -O2 -g -c -D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value -Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
Expand Down
118 changes: 101 additions & 17 deletions backends/ebpf/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ void KernelSamplesTarget::emitIncludes(Util::SourceCodeBuilder* builder) const {
builder->newline();
}

void KernelSamplesTarget::emitResizeBuffer(Util::SourceCodeBuilder *builder,
cstring buffer, cstring offsetVar) const {
builder->appendFormat("bpf_skb_adjust_room(%s, %s, 1, 0)",
buffer, offsetVar);
}

void KernelSamplesTarget::emitTableLookup(Util::SourceCodeBuilder* builder, cstring tblName,
cstring key, cstring value) const {
builder->appendFormat("%s = BPF_MAP_LOOKUP_ELEM(%s, &%s)",
value.c_str(), tblName.c_str(), key.c_str());
if (!value.isNullOrEmpty())
builder->appendFormat("%s = ", value.c_str());
builder->appendFormat("BPF_MAP_LOOKUP_ELEM(%s, &%s)",
tblName.c_str(), key.c_str());
}

void KernelSamplesTarget::emitTableUpdate(Util::SourceCodeBuilder* builder, cstring tblName,
Expand All @@ -62,19 +70,86 @@ void KernelSamplesTarget::emitTableDecl(Util::SourceCodeBuilder* builder,
cstring tblName, TableKind tableKind,
cstring keyType, cstring valueType,
unsigned size) const {
cstring kind;
if (tableKind == TableHash)
kind = "BPF_MAP_TYPE_HASH";
else if (tableKind == TableArray)
kind = "BPF_MAP_TYPE_ARRAY";
else if (tableKind == TableLPMTrie)
kind = "BPF_MAP_TYPE_LPM_TRIE";
else
BUG("%1%: unsupported table kind", tableKind);
builder->appendFormat("REGISTER_TABLE(%s, %s, ", tblName.c_str(), kind.c_str());
builder->appendFormat("sizeof(%s), sizeof(%s), %d)",
keyType.c_str(), valueType.c_str(), size);
cstring kind, flags;
cstring registerTable = "REGISTER_TABLE(%s, %s, %s, %s, %d)";
cstring registerTableWithFlags = "REGISTER_TABLE_FLAGS(%s, %s, %s, %s, %d, %s)";

kind = getBPFMapType(tableKind);

if (keyType != "u32" && (tableKind == TablePerCPUArray || tableKind == TableArray)) {
// it's more safe to overwrite user-provided key type,
osinstom marked this conversation as resolved.
Show resolved Hide resolved
// as array map must have u32 key type.
keyType = "u32";
::warning(ErrorType::WARN_INVALID,
"Invalid key type (%1%) for table kind %2%, replacing with u32",
keyType, kind);
} else if (tableKind == TableProgArray && (keyType != "u32" || valueType != "u32")) {
keyType = "u32";
valueType = "u32";
::warning(ErrorType::WARN_INVALID,
"Invalid key type (%1%) or value type (%2%) for table kind %3%, "
"replacing with u32",
keyType, valueType, kind);
}

if (tableKind == TableLPMTrie) {
flags = "BPF_F_NO_PREALLOC";
}

if (flags.isNullOrEmpty()) {
builder->appendFormat(registerTable, tblName.c_str(),
kind.c_str(), keyType.c_str(),
valueType.c_str(), size);
} else {
builder->appendFormat(registerTableWithFlags, tblName.c_str(),
kind.c_str(), keyType.c_str(),
valueType.c_str(), size, flags);
}
builder->newline();
annotateTableWithBTF(builder, tblName, keyType, valueType);
}

void KernelSamplesTarget::emitTableDeclSpinlock(Util::SourceCodeBuilder* builder,
cstring tblName, TableKind tableKind,
cstring keyType, cstring valueType,
unsigned size) const {
if (tableKind == TableHash || tableKind == TableArray) {
emitTableDecl(builder, tblName, tableKind, keyType, valueType, size);
} else {
BUG("%1%: unsupported table kind with spinlock", tableKind);
}
}

void
KernelSamplesTarget::emitMapInMapDecl(Util::SourceCodeBuilder *builder, cstring innerName,
TableKind innerTableKind, cstring innerKeyType,
cstring innerValueType, unsigned int innerSize,
cstring outerName, TableKind outerTableKind,
cstring outerKeyType, unsigned int outerSize) const {
if (outerTableKind != TableArray && outerTableKind != TableHash) {
BUG("Unsupported type of outer map for map-in-map");
}

cstring registerOuterTable = "REGISTER_TABLE_OUTER(%s, %s_OF_MAPS, %s, %s, %d, %d, %s)";
cstring registerInnerTable = "REGISTER_TABLE_INNER(%s, %s, %s, %s, %d, %d, %d)";

innerMapIndex++;

cstring kind = getBPFMapType(innerTableKind);
builder->appendFormat(registerInnerTable, innerName,
kind, innerKeyType, innerValueType,
innerSize, innerMapIndex, innerMapIndex);
builder->newline();
annotateTableWithBTF(builder, innerName, innerKeyType, innerValueType);

kind = getBPFMapType(outerTableKind);
cstring keyType = outerTableKind == TableArray ? "__u32" : outerKeyType;
builder->appendFormat(registerOuterTable, outerName,
kind, keyType,
"__u32", outerSize, innerMapIndex,
innerName);
builder->newline();
annotateTableWithBTF(builder, outerName, keyType, "__u32");
}

void KernelSamplesTarget::emitLicense(Util::SourceCodeBuilder* builder, cstring license) const {
Expand All @@ -85,7 +160,7 @@ void KernelSamplesTarget::emitLicense(Util::SourceCodeBuilder* builder, cstring

void KernelSamplesTarget::emitCodeSection(
Util::SourceCodeBuilder* builder, cstring sectionName) const {
builder->appendFormat("SEC(\"prog\")\n", sectionName.c_str());
builder->appendFormat("SEC(\"%s\")\n", sectionName.c_str());
mihaibudiu marked this conversation as resolved.
Show resolved Hide resolved
mihaibudiu marked this conversation as resolved.
Show resolved Hide resolved
}

void KernelSamplesTarget::emitMain(Util::SourceCodeBuilder* builder,
Expand Down Expand Up @@ -141,6 +216,13 @@ void KernelSamplesTarget::emitTraceMessage(Util::SourceCodeBuilder* builder, con
builder->newline();
}

void KernelSamplesTarget::annotateTableWithBTF(Util::SourceCodeBuilder* builder, cstring name,
cstring keyType, cstring valueType) const {
builder->appendFormat("BPF_ANNOTATE_KV_PAIR(%s, %s, %s)",
name.c_str(), keyType.c_str(), valueType.c_str());
builder->newline();
}

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

void TestTarget::emitIncludes(Util::SourceCodeBuilder* builder) const {
Expand All @@ -162,8 +244,10 @@ void TestTarget::emitTableDecl(Util::SourceCodeBuilder* builder,

void BccTarget::emitTableLookup(Util::SourceCodeBuilder* builder, cstring tblName,
cstring key, cstring value) const {
builder->appendFormat("%s = %s.lookup(&%s)",
value.c_str(), tblName.c_str(), key.c_str());
if (!value.isNullOrEmpty())
builder->appendFormat("%s = ", value.c_str());
builder->appendFormat("%s.lookup(&%s)",
tblName.c_str(), key.c_str());
}

void BccTarget::emitTableUpdate(Util::SourceCodeBuilder* builder, cstring tblName,
Expand Down
Loading