#include <linux/filter.h>
 #include <linux/bpf_perf_event.h>
 #include <linux/bpf.h>
+#include <linux/if_ether.h>
 
 #include <bpf/bpf.h>
 
 #define MAX_INSNS      512
 #define MAX_FIXUPS     8
 #define MAX_NR_MAPS    4
+#define POINTER_VALUE  0xcafe4all
+#define TEST_DATA_LEN  64
 
 #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS     (1 << 0)
 #define F_LOAD_WITH_STRICT_ALIGNMENT           (1 << 1)
        int fixup_map_in_map[MAX_FIXUPS];
        const char *errstr;
        const char *errstr_unpriv;
+       uint32_t retval;
        enum {
                UNDEF,
                ACCEPT,
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
+               .retval = -3,
        },
        {
                "unreachable",
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
+               .retval = 1,
        },
        {
                "test8 ld_imm64",
                .errstr_unpriv = "R0 leaks addr",
                .result = ACCEPT,
                .result_unpriv = REJECT,
+               .retval = POINTER_VALUE,
        },
        {
                "check valid spill/fill, skb mark",
                .errstr_unpriv = "R1 pointer comparison",
                .result_unpriv = REJECT,
                .result = ACCEPT,
+               .retval = -ENOENT,
        },
        {
                "jump test 4",
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
+               .retval = 0xfaceb00c,
        },
        {
                "PTR_TO_STACK store/load - bad alignment on off",
                .result = ACCEPT,
                .result_unpriv = REJECT,
                .errstr_unpriv = "R0 leaks addr",
+               .retval = POINTER_VALUE,
        },
        {
                "unpriv: add const to pointer",
                        BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0),
                        BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
                                     BPF_FUNC_get_hash_recalc),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 1,
        },
        {
                "direct packet access: test12 (and, good access)",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 1,
        },
        {
                "direct packet access: test13 (branches, good access)",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 1,
        },
        {
                "direct packet access: test14 (pkt_ptr += 0, CONST_IMM, good access)",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 1,
        },
        {
                "direct packet access: test15 (spill with xadd)",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 1,
        },
        {
                "direct packet access: test28 (marking on <=, bad access)",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = 0 /* csum_diff of 64-byte packet */,
        },
        {
                "helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = 42 /* ultimate return value */,
        },
        {
                "ld_ind: check calling conv, r1",
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
+               .retval = 1,
        },
        {
                "check bpf_perf_event_data->sample_period byte load permitted",
                },
                .fixup_map1 = { 3 },
                .result = ACCEPT,
+               .retval = POINTER_VALUE,
                .result_unpriv = REJECT,
                .errstr_unpriv = "R0 leaks addr as return value"
        },
                },
                .fixup_map1 = { 3 },
                .result = ACCEPT,
+               .retval = POINTER_VALUE,
                .result_unpriv = REJECT,
                .errstr_unpriv = "R0 leaks addr as return value"
        },
                        BPF_EXIT_INSN(),
                },
                .result = ACCEPT,
+               .retval = TEST_DATA_LEN,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        },
        {
                .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
                .result_unpriv = REJECT,
                .result = ACCEPT,
+               .retval = 1,
        },
        {
                "calls: overlapping caller/callee",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_ACT,
                .result = ACCEPT,
+               .retval = TEST_DATA_LEN,
        },
        {
                "calls: callee using args1",
                .errstr_unpriv = "allowed for root only",
                .result_unpriv = REJECT,
                .result = ACCEPT,
+               .retval = POINTER_VALUE,
        },
        {
                "calls: callee using wrong args2",
                .errstr_unpriv = "allowed for root only",
                .result_unpriv = REJECT,
                .result = ACCEPT,
+               .retval = TEST_DATA_LEN + TEST_DATA_LEN - ETH_HLEN - ETH_HLEN,
        },
        {
                "calls: callee changing pkt pointers",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = TEST_DATA_LEN + TEST_DATA_LEN,
        },
        {
                "calls: calls with stack arith",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = 42,
        },
        {
                "calls: calls with misaligned stack access",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = 43,
        },
        {
                "calls: calls control flow, jump test 2",
                },
                .prog_type = BPF_PROG_TYPE_XDP,
                .result = ACCEPT,
+               .retval = 42,
        },
        {
                "calls: write into callee stack frame",
                },
                .result = ACCEPT,
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+               .retval = POINTER_VALUE,
        },
        {
                "calls: pkt_ptr spill into caller stack 2",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = 1,
        },
        {
                "calls: pkt_ptr spill into caller stack 4",
                },
                .prog_type = BPF_PROG_TYPE_SCHED_CLS,
                .result = ACCEPT,
+               .retval = 1,
        },
        {
                "calls: pkt_ptr spill into caller stack 5",
        int fd_prog, expected_ret, reject_from_alignment;
        struct bpf_insn *prog = test->insns;
        int prog_len = probe_filter_length(prog);
+       char data_in[TEST_DATA_LEN] = {};
        int prog_type = test->prog_type;
        int map_fds[MAX_NR_MAPS];
        const char *expected_err;
-       int i;
+       uint32_t retval;
+       int i, err;
 
        for (i = 0; i < MAX_NR_MAPS; i++)
                map_fds[i] = -1;
                }
        }
 
+       if (fd_prog >= 0) {
+               err = bpf_prog_test_run(fd_prog, 1, data_in, sizeof(data_in),
+                                       NULL, NULL, &retval, NULL);
+               if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
+                       printf("Unexpected bpf_prog_test_run error\n");
+                       goto fail_log;
+               }
+               if (!err && retval != test->retval &&
+                   test->retval != POINTER_VALUE) {
+                       printf("FAIL retval %d != %d\n", retval, test->retval);
+                       goto fail_log;
+               }
+       }
        (*passes)++;
        printf("OK%s\n", reject_from_alignment ?
               " (NOTE: reject due to unknown alignment)" : "");