Commit 9fd7aca2 authored by David S. Miller's avatar David S. Miller

Merge branch 'bpf-misc-updates'

Daniel Borkmann says:

====================
Misc BPF updates

This set contains a couple of misc updates: stack usage reduction
for perf_sample_data in tracing progs, reduction of stale data in
verifier on register state transitions that I still had in my queue
and few selftest improvements as well as bpf_set_hash() helper for
tc programs.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 41e8e404 ded092cd
...@@ -513,6 +513,11 @@ union bpf_attr { ...@@ -513,6 +513,11 @@ union bpf_attr {
* Get the owner uid of the socket stored inside sk_buff. * Get the owner uid of the socket stored inside sk_buff.
* @skb: pointer to skb * @skb: pointer to skb
* Return: uid of the socket owner on success or overflowuid if failed. * Return: uid of the socket owner on success or overflowuid if failed.
*
* u32 bpf_set_hash(skb, hash)
* Set full skb->hash.
* @skb: pointer to skb
* @hash: hash to set
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -562,7 +567,8 @@ union bpf_attr { ...@@ -562,7 +567,8 @@ union bpf_attr {
FN(xdp_adjust_head), \ FN(xdp_adjust_head), \
FN(probe_read_str), \ FN(probe_read_str), \
FN(get_socket_cookie), \ FN(get_socket_cookie), \
FN(get_socket_uid), FN(get_socket_uid), \
FN(set_hash),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
...@@ -1346,8 +1346,8 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) ...@@ -1346,8 +1346,8 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env)
if (reg->type != PTR_TO_PACKET && if (reg->type != PTR_TO_PACKET &&
reg->type != PTR_TO_PACKET_END) reg->type != PTR_TO_PACKET_END)
continue; continue;
reg->type = UNKNOWN_VALUE; __mark_reg_unknown_value(state->spilled_regs,
reg->imm = 0; i / BPF_REG_SIZE);
} }
} }
...@@ -1952,6 +1952,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -1952,6 +1952,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
*/ */
regs[insn->dst_reg].type = CONST_IMM; regs[insn->dst_reg].type = CONST_IMM;
regs[insn->dst_reg].imm = insn->imm; regs[insn->dst_reg].imm = insn->imm;
regs[insn->dst_reg].id = 0;
regs[insn->dst_reg].max_value = insn->imm; regs[insn->dst_reg].max_value = insn->imm;
regs[insn->dst_reg].min_value = insn->imm; regs[insn->dst_reg].min_value = insn->imm;
regs[insn->dst_reg].min_align = calc_align(insn->imm); regs[insn->dst_reg].min_align = calc_align(insn->imm);
...@@ -2409,6 +2410,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -2409,6 +2410,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
regs[insn->dst_reg].type = CONST_IMM; regs[insn->dst_reg].type = CONST_IMM;
regs[insn->dst_reg].imm = imm; regs[insn->dst_reg].imm = imm;
regs[insn->dst_reg].id = 0;
return 0; return 0;
} }
...@@ -2828,6 +2830,8 @@ static bool states_equal(struct bpf_verifier_env *env, ...@@ -2828,6 +2830,8 @@ static bool states_equal(struct bpf_verifier_env *env,
return false; return false;
if (i % BPF_REG_SIZE) if (i % BPF_REG_SIZE)
continue; continue;
if (old->stack_slot_type[i] != STACK_SPILL)
continue;
if (memcmp(&old->spilled_regs[i / BPF_REG_SIZE], if (memcmp(&old->spilled_regs[i / BPF_REG_SIZE],
&cur->spilled_regs[i / BPF_REG_SIZE], &cur->spilled_regs[i / BPF_REG_SIZE],
sizeof(old->spilled_regs[0]))) sizeof(old->spilled_regs[0])))
......
...@@ -266,14 +266,16 @@ static const struct bpf_func_proto bpf_perf_event_read_proto = { ...@@ -266,14 +266,16 @@ static const struct bpf_func_proto bpf_perf_event_read_proto = {
.arg2_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING,
}; };
static DEFINE_PER_CPU(struct perf_sample_data, bpf_sd);
static __always_inline u64 static __always_inline u64
__bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
u64 flags, struct perf_raw_record *raw) u64 flags, struct perf_raw_record *raw)
{ {
struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_array *array = container_of(map, struct bpf_array, map);
struct perf_sample_data *sd = this_cpu_ptr(&bpf_sd);
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
u64 index = flags & BPF_F_INDEX_MASK; u64 index = flags & BPF_F_INDEX_MASK;
struct perf_sample_data sample_data;
struct bpf_event_entry *ee; struct bpf_event_entry *ee;
struct perf_event *event; struct perf_event *event;
...@@ -294,9 +296,9 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, ...@@ -294,9 +296,9 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
if (unlikely(event->oncpu != cpu)) if (unlikely(event->oncpu != cpu))
return -EOPNOTSUPP; return -EOPNOTSUPP;
perf_sample_data_init(&sample_data, 0, 0); perf_sample_data_init(sd, 0, 0);
sample_data.raw = raw; sd->raw = raw;
perf_event_output(event, &sample_data, regs); perf_event_output(event, sd, regs);
return 0; return 0;
} }
......
...@@ -1874,6 +1874,24 @@ static const struct bpf_func_proto bpf_set_hash_invalid_proto = { ...@@ -1874,6 +1874,24 @@ static const struct bpf_func_proto bpf_set_hash_invalid_proto = {
.arg1_type = ARG_PTR_TO_CTX, .arg1_type = ARG_PTR_TO_CTX,
}; };
BPF_CALL_2(bpf_set_hash, struct sk_buff *, skb, u32, hash)
{
/* Set user specified hash as L4(+), so that it gets returned
* on skb_get_hash() call unless BPF prog later on triggers a
* skb_clear_hash().
*/
__skb_set_sw_hash(skb, hash, true);
return 0;
}
static const struct bpf_func_proto bpf_set_hash_proto = {
.func = bpf_set_hash,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
};
BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto, BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto,
u16, vlan_tci) u16, vlan_tci)
{ {
...@@ -2744,6 +2762,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) ...@@ -2744,6 +2762,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return &bpf_get_hash_recalc_proto; return &bpf_get_hash_recalc_proto;
case BPF_FUNC_set_hash_invalid: case BPF_FUNC_set_hash_invalid:
return &bpf_set_hash_invalid_proto; return &bpf_set_hash_invalid_proto;
case BPF_FUNC_set_hash:
return &bpf_set_hash_proto;
case BPF_FUNC_perf_event_output: case BPF_FUNC_perf_event_output:
return &bpf_skb_event_output_proto; return &bpf_skb_event_output_proto;
case BPF_FUNC_get_smp_processor_id: case BPF_FUNC_get_smp_processor_id:
...@@ -2774,12 +2794,6 @@ xdp_func_proto(enum bpf_func_id func_id) ...@@ -2774,12 +2794,6 @@ xdp_func_proto(enum bpf_func_id func_id)
} }
} }
static const struct bpf_func_proto *
cg_skb_func_proto(enum bpf_func_id func_id)
{
return sk_filter_func_proto(func_id);
}
static const struct bpf_func_proto * static const struct bpf_func_proto *
lwt_inout_func_proto(enum bpf_func_id func_id) lwt_inout_func_proto(enum bpf_func_id func_id)
{ {
...@@ -3344,7 +3358,7 @@ const struct bpf_verifier_ops xdp_prog_ops = { ...@@ -3344,7 +3358,7 @@ const struct bpf_verifier_ops xdp_prog_ops = {
}; };
const struct bpf_verifier_ops cg_skb_prog_ops = { const struct bpf_verifier_ops cg_skb_prog_ops = {
.get_func_proto = cg_skb_func_proto, .get_func_proto = sk_filter_func_proto,
.is_valid_access = sk_filter_is_valid_access, .is_valid_access = sk_filter_is_valid_access,
.convert_ctx_access = bpf_convert_ctx_access, .convert_ctx_access = bpf_convert_ctx_access,
.test_run = bpf_prog_test_run_skb, .test_run = bpf_prog_test_run_skb,
......
...@@ -513,6 +513,11 @@ union bpf_attr { ...@@ -513,6 +513,11 @@ union bpf_attr {
* Get the owner uid of the socket stored inside sk_buff. * Get the owner uid of the socket stored inside sk_buff.
* @skb: pointer to skb * @skb: pointer to skb
* Return: uid of the socket owner on success or overflowuid if failed. * Return: uid of the socket owner on success or overflowuid if failed.
*
* u32 bpf_set_hash(skb, hash)
* Set full skb->hash.
* @skb: pointer to skb
* @hash: hash to set
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -562,7 +567,8 @@ union bpf_attr { ...@@ -562,7 +567,8 @@ union bpf_attr {
FN(xdp_adjust_head), \ FN(xdp_adjust_head), \
FN(probe_read_str), \ FN(probe_read_str), \
FN(get_socket_cookie), \ FN(get_socket_cookie), \
FN(get_socket_uid), FN(get_socket_uid), \
FN(set_hash),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/resource.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/bpf_perf_event.h> #include <linux/bpf_perf_event.h>
...@@ -432,6 +434,9 @@ static int do_test(unsigned int from, unsigned int to) ...@@ -432,6 +434,9 @@ static int do_test(unsigned int from, unsigned int to)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
unsigned int from = 0, to = ARRAY_SIZE(tests); unsigned int from = 0, to = ARRAY_SIZE(tests);
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
setrlimit(RLIMIT_MEMLOCK, &rinf);
if (argc == 3) { if (argc == 3) {
unsigned int l = atoi(argv[argc - 2]); unsigned int l = atoi(argv[argc - 2]);
......
...@@ -239,6 +239,54 @@ static void test_hashmap_percpu(int task, void *data) ...@@ -239,6 +239,54 @@ static void test_hashmap_percpu(int task, void *data)
close(fd); close(fd);
} }
static void test_hashmap_walk(int task, void *data)
{
int fd, i, max_entries = 100000;
long long key, value, next_key;
bool next_key_valid = true;
fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
max_entries, map_flags);
if (fd < 0) {
printf("Failed to create hashmap '%s'!\n", strerror(errno));
exit(1);
}
for (i = 0; i < max_entries; i++) {
key = i; value = key;
assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
}
for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
&next_key) == 0; i++) {
key = next_key;
assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
}
assert(i == max_entries);
assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
for (i = 0; next_key_valid; i++) {
next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;
assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
value++;
assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
key = next_key;
}
assert(i == max_entries);
for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
&next_key) == 0; i++) {
key = next_key;
assert(bpf_map_lookup_elem(fd, &key, &value) == 0);
assert(value - 1 == key);
}
assert(i == max_entries);
close(fd);
}
static void test_arraymap(int task, void *data) static void test_arraymap(int task, void *data)
{ {
int key, next_key, fd; int key, next_key, fd;
...@@ -464,6 +512,7 @@ static void test_map_stress(void) ...@@ -464,6 +512,7 @@ static void test_map_stress(void)
run_parallel(100, test_hashmap, NULL); run_parallel(100, test_hashmap, NULL);
run_parallel(100, test_hashmap_percpu, NULL); run_parallel(100, test_hashmap_percpu, NULL);
run_parallel(100, test_hashmap_sizes, NULL); run_parallel(100, test_hashmap_sizes, NULL);
run_parallel(100, test_hashmap_walk, NULL);
run_parallel(100, test_arraymap, NULL); run_parallel(100, test_arraymap, NULL);
run_parallel(100, test_arraymap_percpu, NULL); run_parallel(100, test_arraymap_percpu, NULL);
...@@ -549,6 +598,7 @@ static void run_all_tests(void) ...@@ -549,6 +598,7 @@ static void run_all_tests(void)
{ {
test_hashmap(0, NULL); test_hashmap(0, NULL);
test_hashmap_percpu(0, NULL); test_hashmap_percpu(0, NULL);
test_hashmap_walk(0, NULL);
test_arraymap(0, NULL); test_arraymap(0, NULL);
test_arraymap_percpu(0, NULL); test_arraymap_percpu(0, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment