bpf: fix pseudo calls for BPF programs loaded from ELF

Message ID 20190517140942.20724-1-konstantin.ananyev@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers
Series bpf: fix pseudo calls for BPF programs loaded from ELF |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/intel-Performance-Testing success Performance Testing PASS
ci/mellanox-Performance-Testing success Performance Testing PASS
ci/Intel-compilation success Compilation OK

Commit Message

Ananyev, Konstantin May 17, 2019, 2:09 p.m. UTC
  clang 6.0 and onwards, for the external function call generates
BPF_PSEUDO_CALL instruction:
call pseudo +-off -> call another bpf function.
More details about that change: https://lwn.net/Articles/741773/
DPDK BPF implementation right now doesn't support multiple BPF
functions per module.
To overcome that problem, and preserve existing functionality
(ability to call allowed by user external functions),
bpf_elf_load() clears EBPF_PSEUDO_CALL value.
For details how to reproduce the issue:
https://bugs.dpdk.org/show_bug.cgi?id=259

Fixes: 5dba93ae5f2d ("bpf: add ability to load eBPF program from ELF object file")
Cc: stable@dpdk.org

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
 lib/librte_bpf/bpf_def.h      |  8 ++++++++
 lib/librte_bpf/bpf_load_elf.c | 15 +++++++++++++--
 lib/librte_bpf/rte_bpf.h      |  3 +++
 3 files changed, 24 insertions(+), 2 deletions(-)
  

Comments

Thomas Monjalon June 5, 2019, 4:33 p.m. UTC | #1
17/05/2019 16:09, Konstantin Ananyev:
> clang 6.0 and onwards, for the external function call generates
> BPF_PSEUDO_CALL instruction:
> call pseudo +-off -> call another bpf function.
> More details about that change: https://lwn.net/Articles/741773/
> DPDK BPF implementation right now doesn't support multiple BPF
> functions per module.
> To overcome that problem, and preserve existing functionality
> (ability to call allowed by user external functions),
> bpf_elf_load() clears EBPF_PSEUDO_CALL value.
> For details how to reproduce the issue:
> https://bugs.dpdk.org/show_bug.cgi?id=259
> 
> Fixes: 5dba93ae5f2d ("bpf: add ability to load eBPF program from ELF object file")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

Applied, thanks
  

Patch

diff --git a/lib/librte_bpf/bpf_def.h b/lib/librte_bpf/bpf_def.h
index c10f3aec4..d39992997 100644
--- a/lib/librte_bpf/bpf_def.h
+++ b/lib/librte_bpf/bpf_def.h
@@ -120,6 +120,14 @@  enum {
 	EBPF_REG_NUM,
 };
 
+/*
+ * When EBPF_CALL instruction has src_reg == EBPF_PSEUDO_CALL,
+ * it should be treated as pseudo-call instruction, where
+ * imm value contains pc-relative offset to another EBPF function.
+ * Right now DPDK EBPF library doesn't support it.
+ */
+#define	EBPF_PSEUDO_CALL	EBPF_REG_1
+
 /*
  * eBPF instruction format
  */
diff --git a/lib/librte_bpf/bpf_load_elf.c b/lib/librte_bpf/bpf_load_elf.c
index 96d3630fe..926317b6f 100644
--- a/lib/librte_bpf/bpf_load_elf.c
+++ b/lib/librte_bpf/bpf_load_elf.c
@@ -77,10 +77,21 @@  resolve_xsym(const char *sn, size_t ofs, struct ebpf_insn *ins, size_t ins_sz,
 		return -ENOENT;
 
 	/* for function we just need an index in our xsym table */
-	if (type == RTE_BPF_XTYPE_FUNC)
+	if (type == RTE_BPF_XTYPE_FUNC) {
+
+		/* we don't support multiple functions per BPF module,
+		 * so treat EBPF_PSEUDO_CALL to extrernal function
+		 * as an ordinary EBPF_CALL.
+		 */
+		if (ins[idx].src_reg == EBPF_PSEUDO_CALL) {
+			RTE_BPF_LOG(INFO, "%s(%u): "
+				"EBPF_PSEUDO_CALL to external function: %s\n",
+				__func__, idx, sn);
+			ins[idx].src_reg = EBPF_REG_0;
+		}
 		ins[idx].imm = fidx;
 	/* for variable we need to store its absolute address */
-	else {
+	} else {
 		ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
 		ins[idx + 1].imm =
 			(uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
diff --git a/lib/librte_bpf/rte_bpf.h b/lib/librte_bpf/rte_bpf.h
index ab92af8fe..c8b960176 100644
--- a/lib/librte_bpf/rte_bpf.h
+++ b/lib/librte_bpf/rte_bpf.h
@@ -134,6 +134,9 @@  rte_bpf_load(const struct rte_bpf_prm *prm);
 /**
  * Create a new eBPF execution context and load BPF code from given ELF
  * file into it.
+ * Note that if the function will encounter EBPF_PSEUDO_CALL instruction
+ * that references external symbol, it will treat is as standard BPF_CALL
+ * to the external helper function.
  *
  * @param prm
  *  Parameters used to create and initialise the BPF execution context.