{
.name = RTE_STR(stdout),
.type = RTE_BPF_XTYPE_VAR,
- .var = &stdout,
+ .var = {
+ .val = &stdout,
+ .desc = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(stdout),
+ },
+ },
},
{
.name = RTE_STR(rte_pktmbuf_dump),
.type = RTE_BPF_XTYPE_FUNC,
- .func = (void *)rte_pktmbuf_dump,
+ .func = {
+ .val = (void *)rte_pktmbuf_dump,
+ .nb_args = 3,
+ .args = {
+ [0] = {
+ .type = RTE_BPF_ARG_RAW,
+ .size = sizeof(uintptr_t),
+ },
+ [1] = {
+ .type = RTE_BPF_ARG_PTR_MBUF,
+ .size = sizeof(struct rte_mbuf),
+ },
+ [2] = {
+ .type = RTE_BPF_ARG_RAW,
+ .size = sizeof(uint32_t),
+ },
+ },
+ },
},
};
int32_t imm;
};
+/*
+ * eBPF allows functions with R1-R5 as arguments.
+ */
+#define EBPF_FUNC_MAX_ARGS (EBPF_REG_6 - EBPF_REG_1)
+
#ifdef __cplusplus
}
#endif
break;
/* call instructions */
case (BPF_JMP | EBPF_CALL):
- reg[EBPF_REG_0] = bpf->prm.xsym[ins->imm].func(
+ reg[EBPF_REG_0] = bpf->prm.xsym[ins->imm].func.val(
reg[EBPF_REG_1], reg[EBPF_REG_2],
reg[EBPF_REG_3], reg[EBPF_REG_4],
reg[EBPF_REG_5]);
#define RTE_BPF_LOG(lvl, fmt, args...) \
rte_log(RTE_LOG_## lvl, rte_bpf_logtype, fmt, ##args)
+static inline size_t
+bpf_size(uint32_t bpf_op_sz)
+{
+ if (bpf_op_sz == BPF_B)
+ return sizeof(uint8_t);
+ else if (bpf_op_sz == BPF_H)
+ return sizeof(uint16_t);
+ else if (bpf_op_sz == BPF_W)
+ return sizeof(uint32_t);
+ else if (bpf_op_sz == EBPF_DW)
+ return sizeof(uint64_t);
+ return 0;
+}
+
#ifdef __cplusplus
}
#endif
uint8_t u8[4];
};
-static size_t
-bpf_size(uint32_t bpf_op_sz)
-{
- if (bpf_op_sz == BPF_B)
- return sizeof(uint8_t);
- else if (bpf_op_sz == BPF_H)
- return sizeof(uint16_t);
- else if (bpf_op_sz == BPF_W)
- return sizeof(uint32_t);
- else if (bpf_op_sz == EBPF_DW)
- return sizeof(uint64_t);
- return 0;
-}
-
/*
* In many cases for imm8 we can produce shorter code.
*/
break;
/* call instructions */
case (BPF_JMP | EBPF_CALL):
- emit_call(st, (uintptr_t)bpf->prm.xsym[ins->imm].func);
+ emit_call(st,
+ (uintptr_t)bpf->prm.xsym[ins->imm].func.val);
break;
/* return instruction */
case (BPF_JMP | EBPF_EXIT):
return bpf;
}
+/*
+ * Check that user provided external symbol.
+ */
+static int
+bpf_check_xsym(const struct rte_bpf_xsym *xsym)
+{
+ uint32_t i;
+
+ if (xsym->name == NULL)
+ return -EINVAL;
+
+ if (xsym->type == RTE_BPF_XTYPE_VAR) {
+ if (xsym->var.desc.type == RTE_BPF_ARG_UNDEF)
+ return -EINVAL;
+ } else if (xsym->type == RTE_BPF_XTYPE_FUNC) {
+
+ if (xsym->func.nb_args > EBPF_FUNC_MAX_ARGS)
+ return -EINVAL;
+
+ /* check function arguments */
+ for (i = 0; i != xsym->func.nb_args; i++) {
+ if (xsym->func.args[i].type == RTE_BPF_ARG_UNDEF)
+ return -EINVAL;
+ }
+
+ /* check return value info */
+ if (xsym->func.ret.type != RTE_BPF_ARG_UNDEF &&
+ xsym->func.ret.size == 0)
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
__rte_experimental struct rte_bpf *
rte_bpf_load(const struct rte_bpf_prm *prm)
{
struct rte_bpf *bpf;
int32_t rc;
+ uint32_t i;
- if (prm == NULL || prm->ins == NULL) {
+ if (prm == NULL || prm->ins == NULL ||
+ (prm->nb_xsym != 0 && prm->xsym == NULL)) {
rte_errno = EINVAL;
return NULL;
}
+ rc = 0;
+ for (i = 0; i != prm->nb_xsym && rc == 0; i++)
+ rc = bpf_check_xsym(prm->xsym + i);
+
+ if (rc != 0) {
+ rte_errno = -rc;
+ RTE_BPF_LOG(ERR, "%s: %d-th xsym is invalid\n", __func__, i);
+ return NULL;
+ }
+
bpf = bpf_load(prm);
if (bpf == NULL) {
rte_errno = ENOMEM;
ins[idx].imm = fidx;
/* for variable we need to store its absolute address */
else {
- ins[idx].imm = (uintptr_t)prm->xsym[fidx].var;
+ ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
ins[idx + 1].imm =
- (uint64_t)(uintptr_t)prm->xsym[fidx].var >> 32;
+ (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
}
return 0;
*/
struct rte_bpf_arg {
enum rte_bpf_arg_type type;
- size_t size; /**< for pointer types, size of data it points to */
+ /**
+ * for ptr type - max size of data buffer it points to
+ * for raw type - the size (in bytes) of the value
+ */
+ size_t size;
size_t buf_size;
/**< for mbuf ptr type, max size of rte_mbuf data buffer */
};
const char *name; /**< name */
enum rte_bpf_xtype type; /**< type */
union {
- uint64_t (*func)(uint64_t, uint64_t, uint64_t,
+ struct {
+ uint64_t (*val)(uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t);
- void *var;
- }; /**< value */
+ uint32_t nb_args;
+ struct rte_bpf_arg args[EBPF_FUNC_MAX_ARGS];
+ /**< Function arguments descriptions. */
+ struct rte_bpf_arg ret; /**< function return value. */
+ } func;
+ struct {
+ void *val; /**< actual memory location */
+ struct rte_bpf_arg desc; /**< type, size, etc. */
+ } var; /**< external variable */
+ };
};
/**
{
.name = RTE_STR(dummy_func1),
.type = RTE_BPF_XTYPE_FUNC,
- .func = (void *)dummy_func1,
+ .func = {
+ .val = (void *)dummy_func1,
+ .nb_args = 3,
+ .args = {
+ [0] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ [1] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(uint32_t),
+ },
+ [2] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(uint64_t),
+ },
+ },
+ },
},
};