Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says: ==================== pull-request: bpf 2019-05-16 The following pull-request contains BPF updates for your *net* tree. The main changes are: 1) Fix a use after free in __dev_map_entry_free(), from Eric. 2) Several sockmap related bug fixes: a splat in strparser if it was never initialized, remove duplicate ingress msg list purging which can race, fix msg->sg.size accounting upon skb to msg conversion, and last but not least fix a timeout bug in tcp_bpf_wait_data(), from John. 3) Fix LRU map to avoid messing with eviction heuristics upon syscall lookup, e.g. map walks from user space side will then lead to eviction of just recently created entries on updates as it would mark all map entries, from Daniel. 4) Don't bail out when libbpf feature probing fails. Also various smaller fixes to flow_dissector test, from Stanislav. 5) Fix missing brackets for BTF_INT_OFFSET() in UAPI, from Gary. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c7d5ec26ea
|
@ -131,7 +131,7 @@ The following sections detail encoding of each kind.
|
||||||
``btf_type`` is followed by a ``u32`` with the following bits arrangement::
|
``btf_type`` is followed by a ``u32`` with the following bits arrangement::
|
||||||
|
|
||||||
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
||||||
#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16)
|
#define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16)
|
||||||
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
||||||
|
|
||||||
The ``BTF_INT_ENCODING`` has the following attributes::
|
The ``BTF_INT_ENCODING`` has the following attributes::
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct bpf_map_ops {
|
||||||
void (*map_free)(struct bpf_map *map);
|
void (*map_free)(struct bpf_map *map);
|
||||||
int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key);
|
int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key);
|
||||||
void (*map_release_uref)(struct bpf_map *map);
|
void (*map_release_uref)(struct bpf_map *map);
|
||||||
|
void *(*map_lookup_elem_sys_only)(struct bpf_map *map, void *key);
|
||||||
|
|
||||||
/* funcs callable from userspace and from eBPF programs */
|
/* funcs callable from userspace and from eBPF programs */
|
||||||
void *(*map_lookup_elem)(struct bpf_map *map, void *key);
|
void *(*map_lookup_elem)(struct bpf_map *map, void *key);
|
||||||
|
|
|
@ -83,7 +83,7 @@ struct btf_type {
|
||||||
* is the 32 bits arrangement:
|
* is the 32 bits arrangement:
|
||||||
*/
|
*/
|
||||||
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
||||||
#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16)
|
#define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16)
|
||||||
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
||||||
|
|
||||||
/* Attributes stored in the BTF_INT_ENCODING */
|
/* Attributes stored in the BTF_INT_ENCODING */
|
||||||
|
|
|
@ -164,6 +164,9 @@ static void dev_map_free(struct bpf_map *map)
|
||||||
bpf_clear_redirect_map(map);
|
bpf_clear_redirect_map(map);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
|
/* Make sure prior __dev_map_entry_free() have completed. */
|
||||||
|
rcu_barrier();
|
||||||
|
|
||||||
/* To ensure all pending flush operations have completed wait for flush
|
/* To ensure all pending flush operations have completed wait for flush
|
||||||
* bitmap to indicate all flush_needed bits to be zero on _all_ cpus.
|
* bitmap to indicate all flush_needed bits to be zero on _all_ cpus.
|
||||||
* Because the above synchronize_rcu() ensures the map is disconnected
|
* Because the above synchronize_rcu() ensures the map is disconnected
|
||||||
|
|
|
@ -527,11 +527,13 @@ static u32 htab_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
|
||||||
return insn - insn_buf;
|
return insn - insn_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *htab_lru_map_lookup_elem(struct bpf_map *map, void *key)
|
static __always_inline void *__htab_lru_map_lookup_elem(struct bpf_map *map,
|
||||||
|
void *key, const bool mark)
|
||||||
{
|
{
|
||||||
struct htab_elem *l = __htab_map_lookup_elem(map, key);
|
struct htab_elem *l = __htab_map_lookup_elem(map, key);
|
||||||
|
|
||||||
if (l) {
|
if (l) {
|
||||||
|
if (mark)
|
||||||
bpf_lru_node_set_ref(&l->lru_node);
|
bpf_lru_node_set_ref(&l->lru_node);
|
||||||
return l->key + round_up(map->key_size, 8);
|
return l->key + round_up(map->key_size, 8);
|
||||||
}
|
}
|
||||||
|
@ -539,6 +541,16 @@ static void *htab_lru_map_lookup_elem(struct bpf_map *map, void *key)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *htab_lru_map_lookup_elem(struct bpf_map *map, void *key)
|
||||||
|
{
|
||||||
|
return __htab_lru_map_lookup_elem(map, key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *htab_lru_map_lookup_elem_sys(struct bpf_map *map, void *key)
|
||||||
|
{
|
||||||
|
return __htab_lru_map_lookup_elem(map, key, false);
|
||||||
|
}
|
||||||
|
|
||||||
static u32 htab_lru_map_gen_lookup(struct bpf_map *map,
|
static u32 htab_lru_map_gen_lookup(struct bpf_map *map,
|
||||||
struct bpf_insn *insn_buf)
|
struct bpf_insn *insn_buf)
|
||||||
{
|
{
|
||||||
|
@ -1250,6 +1262,7 @@ const struct bpf_map_ops htab_lru_map_ops = {
|
||||||
.map_free = htab_map_free,
|
.map_free = htab_map_free,
|
||||||
.map_get_next_key = htab_map_get_next_key,
|
.map_get_next_key = htab_map_get_next_key,
|
||||||
.map_lookup_elem = htab_lru_map_lookup_elem,
|
.map_lookup_elem = htab_lru_map_lookup_elem,
|
||||||
|
.map_lookup_elem_sys_only = htab_lru_map_lookup_elem_sys,
|
||||||
.map_update_elem = htab_lru_map_update_elem,
|
.map_update_elem = htab_lru_map_update_elem,
|
||||||
.map_delete_elem = htab_lru_map_delete_elem,
|
.map_delete_elem = htab_lru_map_delete_elem,
|
||||||
.map_gen_lookup = htab_lru_map_gen_lookup,
|
.map_gen_lookup = htab_lru_map_gen_lookup,
|
||||||
|
@ -1281,7 +1294,6 @@ static void *htab_lru_percpu_map_lookup_elem(struct bpf_map *map, void *key)
|
||||||
|
|
||||||
int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value)
|
int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value)
|
||||||
{
|
{
|
||||||
struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
|
|
||||||
struct htab_elem *l;
|
struct htab_elem *l;
|
||||||
void __percpu *pptr;
|
void __percpu *pptr;
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
|
@ -1297,8 +1309,9 @@ int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value)
|
||||||
l = __htab_map_lookup_elem(map, key);
|
l = __htab_map_lookup_elem(map, key);
|
||||||
if (!l)
|
if (!l)
|
||||||
goto out;
|
goto out;
|
||||||
if (htab_is_lru(htab))
|
/* We do not mark LRU map element here in order to not mess up
|
||||||
bpf_lru_node_set_ref(&l->lru_node);
|
* eviction heuristics when user space does a map walk.
|
||||||
|
*/
|
||||||
pptr = htab_elem_get_ptr(l, map->key_size);
|
pptr = htab_elem_get_ptr(l, map->key_size);
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
bpf_long_memcpy(value + off,
|
bpf_long_memcpy(value + off,
|
||||||
|
|
|
@ -808,6 +808,9 @@ static int map_lookup_elem(union bpf_attr *attr)
|
||||||
err = map->ops->map_peek_elem(map, value);
|
err = map->ops->map_peek_elem(map, value);
|
||||||
} else {
|
} else {
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
if (map->ops->map_lookup_elem_sys_only)
|
||||||
|
ptr = map->ops->map_lookup_elem_sys_only(map, key);
|
||||||
|
else
|
||||||
ptr = map->ops->map_lookup_elem(map, key);
|
ptr = map->ops->map_lookup_elem(map, key);
|
||||||
if (IS_ERR(ptr)) {
|
if (IS_ERR(ptr)) {
|
||||||
err = PTR_ERR(ptr);
|
err = PTR_ERR(ptr);
|
||||||
|
|
|
@ -1297,7 +1297,8 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODULES
|
#ifdef CONFIG_MODULES
|
||||||
int bpf_event_notify(struct notifier_block *nb, unsigned long op, void *module)
|
static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
|
||||||
|
void *module)
|
||||||
{
|
{
|
||||||
struct bpf_trace_module *btm, *tmp;
|
struct bpf_trace_module *btm, *tmp;
|
||||||
struct module *mod = module;
|
struct module *mod = module;
|
||||||
|
@ -1336,7 +1337,7 @@ static struct notifier_block bpf_module_nb = {
|
||||||
.notifier_call = bpf_event_notify,
|
.notifier_call = bpf_event_notify,
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init bpf_event_init(void)
|
static int __init bpf_event_init(void)
|
||||||
{
|
{
|
||||||
register_module_notifier(&bpf_module_nb);
|
register_module_notifier(&bpf_module_nb);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -411,6 +411,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
|
||||||
sk_mem_charge(sk, skb->len);
|
sk_mem_charge(sk, skb->len);
|
||||||
copied = skb->len;
|
copied = skb->len;
|
||||||
msg->sg.start = 0;
|
msg->sg.start = 0;
|
||||||
|
msg->sg.size = copied;
|
||||||
msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge;
|
msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge;
|
||||||
msg->skb = skb;
|
msg->skb = skb;
|
||||||
|
|
||||||
|
@ -554,7 +555,9 @@ static void sk_psock_destroy_deferred(struct work_struct *gc)
|
||||||
struct sk_psock *psock = container_of(gc, struct sk_psock, gc);
|
struct sk_psock *psock = container_of(gc, struct sk_psock, gc);
|
||||||
|
|
||||||
/* No sk_callback_lock since already detached. */
|
/* No sk_callback_lock since already detached. */
|
||||||
strp_stop(&psock->parser.strp);
|
|
||||||
|
/* Parser has been stopped */
|
||||||
|
if (psock->progs.skb_parser)
|
||||||
strp_done(&psock->parser.strp);
|
strp_done(&psock->parser.strp);
|
||||||
|
|
||||||
cancel_work_sync(&psock->work);
|
cancel_work_sync(&psock->work);
|
||||||
|
|
|
@ -27,7 +27,10 @@ static int tcp_bpf_wait_data(struct sock *sk, struct sk_psock *psock,
|
||||||
int flags, long timeo, int *err)
|
int flags, long timeo, int *err)
|
||||||
{
|
{
|
||||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!timeo)
|
||||||
|
return ret;
|
||||||
|
|
||||||
add_wait_queue(sk_sleep(sk), &wait);
|
add_wait_queue(sk_sleep(sk), &wait);
|
||||||
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||||
|
@ -528,8 +531,6 @@ static void tcp_bpf_remove(struct sock *sk, struct sk_psock *psock)
|
||||||
{
|
{
|
||||||
struct sk_psock_link *link;
|
struct sk_psock_link *link;
|
||||||
|
|
||||||
sk_psock_cork_free(psock);
|
|
||||||
__sk_psock_purge_ingress_msg(psock);
|
|
||||||
while ((link = sk_psock_link_pop(psock))) {
|
while ((link = sk_psock_link_pop(psock))) {
|
||||||
sk_psock_unlink(sk, link);
|
sk_psock_unlink(sk, link);
|
||||||
sk_psock_free_link(link);
|
sk_psock_free_link(link);
|
||||||
|
|
|
@ -83,7 +83,7 @@ struct btf_type {
|
||||||
* is the 32 bits arrangement:
|
* is the 32 bits arrangement:
|
||||||
*/
|
*/
|
||||||
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
||||||
#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16)
|
#define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16)
|
||||||
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
||||||
|
|
||||||
/* Attributes stored in the BTF_INT_ENCODING */
|
/* Attributes stored in the BTF_INT_ENCODING */
|
||||||
|
|
|
@ -1696,7 +1696,7 @@ bpf_object__probe_caps(struct bpf_object *obj)
|
||||||
for (i = 0; i < ARRAY_SIZE(probe_fn); i++) {
|
for (i = 0; i < ARRAY_SIZE(probe_fn); i++) {
|
||||||
ret = probe_fn[i](obj);
|
ret = probe_fn[i](obj);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
pr_debug("Probe #%d failed with %d.\n", i, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -242,12 +242,12 @@ void test_flow_dissector(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0);
|
err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0);
|
||||||
CHECK(err, "bpf_prog_attach", "err %d errno %d", err, errno);
|
CHECK(err, "bpf_prog_attach", "err %d errno %d\n", err, errno);
|
||||||
|
|
||||||
tap_fd = create_tap("tap0");
|
tap_fd = create_tap("tap0");
|
||||||
CHECK(tap_fd < 0, "create_tap", "tap_fd %d errno %d", tap_fd, errno);
|
CHECK(tap_fd < 0, "create_tap", "tap_fd %d errno %d\n", tap_fd, errno);
|
||||||
err = ifup("tap0");
|
err = ifup("tap0");
|
||||||
CHECK(err, "ifup", "err %d errno %d", err, errno);
|
CHECK(err, "ifup", "err %d errno %d\n", err, errno);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||||
struct bpf_flow_keys flow_keys = {};
|
struct bpf_flow_keys flow_keys = {};
|
||||||
|
@ -255,7 +255,7 @@ void test_flow_dissector(void)
|
||||||
__u32 key = 0;
|
__u32 key = 0;
|
||||||
|
|
||||||
err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
|
err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
|
||||||
CHECK(err < 0, "tx_tap", "err %d errno %d", err, errno);
|
CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);
|
||||||
|
|
||||||
err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
|
err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
|
||||||
CHECK_ATTR(err, tests[i].name, "bpf_map_lookup_elem %d\n", err);
|
CHECK_ATTR(err, tests[i].name, "bpf_map_lookup_elem %d\n", err);
|
||||||
|
@ -264,5 +264,6 @@ void test_flow_dissector(void)
|
||||||
CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
|
CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bpf_prog_detach(prog_fd, BPF_FLOW_DISSECTOR);
|
||||||
bpf_object__close(obj);
|
bpf_object__close(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <bpf/bpf.h>
|
#include <bpf/bpf.h>
|
||||||
|
#include <bpf/libbpf.h>
|
||||||
|
|
||||||
#include "bpf_util.h"
|
#include "bpf_util.h"
|
||||||
#include "bpf_rlimit.h"
|
#include "bpf_rlimit.h"
|
||||||
|
#include "../../../include/linux/filter.h"
|
||||||
|
|
||||||
#define LOCAL_FREE_TARGET (128)
|
#define LOCAL_FREE_TARGET (128)
|
||||||
#define PERCPU_FREE_TARGET (4)
|
#define PERCPU_FREE_TARGET (4)
|
||||||
|
@ -40,6 +42,68 @@ static int create_map(int map_type, int map_flags, unsigned int size)
|
||||||
return map_fd;
|
return map_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key,
|
||||||
|
void *value)
|
||||||
|
{
|
||||||
|
struct bpf_load_program_attr prog;
|
||||||
|
struct bpf_create_map_attr map;
|
||||||
|
struct bpf_insn insns[] = {
|
||||||
|
BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, fd),
|
||||||
|
BPF_LD_IMM64(BPF_REG_3, key),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||||
|
BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 42),
|
||||||
|
BPF_JMP_IMM(BPF_JA, 0, 0, 1),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
};
|
||||||
|
__u8 data[64] = {};
|
||||||
|
int mfd, pfd, ret, zero = 0;
|
||||||
|
__u32 retval = 0;
|
||||||
|
|
||||||
|
memset(&map, 0, sizeof(map));
|
||||||
|
map.map_type = BPF_MAP_TYPE_ARRAY;
|
||||||
|
map.key_size = sizeof(int);
|
||||||
|
map.value_size = sizeof(unsigned long long);
|
||||||
|
map.max_entries = 1;
|
||||||
|
|
||||||
|
mfd = bpf_create_map_xattr(&map);
|
||||||
|
if (mfd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
insns[0].imm = mfd;
|
||||||
|
|
||||||
|
memset(&prog, 0, sizeof(prog));
|
||||||
|
prog.prog_type = BPF_PROG_TYPE_SCHED_CLS;
|
||||||
|
prog.insns = insns;
|
||||||
|
prog.insns_cnt = ARRAY_SIZE(insns);
|
||||||
|
prog.license = "GPL";
|
||||||
|
|
||||||
|
pfd = bpf_load_program_xattr(&prog, NULL, 0);
|
||||||
|
if (pfd < 0) {
|
||||||
|
close(mfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bpf_prog_test_run(pfd, 1, data, sizeof(data),
|
||||||
|
NULL, NULL, &retval, NULL);
|
||||||
|
if (ret < 0 || retval != 42) {
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
assert(!bpf_map_lookup_elem(mfd, &zero, value));
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
close(pfd);
|
||||||
|
close(mfd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int map_subset(int map0, int map1)
|
static int map_subset(int map0, int map1)
|
||||||
{
|
{
|
||||||
unsigned long long next_key = 0;
|
unsigned long long next_key = 0;
|
||||||
|
@ -87,7 +151,7 @@ static int sched_next_online(int pid, int *next_to_try)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Size of the LRU amp is 2
|
/* Size of the LRU map is 2
|
||||||
* Add key=1 (+1 key)
|
* Add key=1 (+1 key)
|
||||||
* Add key=2 (+1 key)
|
* Add key=2 (+1 key)
|
||||||
* Lookup Key=1
|
* Lookup Key=1
|
||||||
|
@ -157,7 +221,7 @@ static void test_lru_sanity0(int map_type, int map_flags)
|
||||||
* stop LRU from removing key=1
|
* stop LRU from removing key=1
|
||||||
*/
|
*/
|
||||||
key = 1;
|
key = 1;
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
assert(value[0] == 1234);
|
assert(value[0] == 1234);
|
||||||
|
|
||||||
key = 3;
|
key = 3;
|
||||||
|
@ -167,7 +231,8 @@ static void test_lru_sanity0(int map_type, int map_flags)
|
||||||
|
|
||||||
/* key=2 has been removed from the LRU */
|
/* key=2 has been removed from the LRU */
|
||||||
key = 2;
|
key = 2;
|
||||||
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1);
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
assert(map_equal(lru_map_fd, expected_map_fd));
|
assert(map_equal(lru_map_fd, expected_map_fd));
|
||||||
|
|
||||||
|
@ -221,7 +286,7 @@ static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
|
||||||
/* Lookup 1 to tgt_free/2 */
|
/* Lookup 1 to tgt_free/2 */
|
||||||
end_key = 1 + batch_size;
|
end_key = 1 + batch_size;
|
||||||
for (key = 1; key < end_key; key++) {
|
for (key = 1; key < end_key; key++) {
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
}
|
}
|
||||||
|
@ -322,10 +387,11 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
|
||||||
end_key = 1 + batch_size;
|
end_key = 1 + batch_size;
|
||||||
value[0] = 4321;
|
value[0] = 4321;
|
||||||
for (key = 1; key < end_key; key++) {
|
for (key = 1; key < end_key; key++) {
|
||||||
assert(bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
assert(!bpf_map_update_elem(lru_map_fd, &key, value,
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
assert(value[0] == 4321);
|
assert(value[0] == 4321);
|
||||||
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
|
@ -404,7 +470,7 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
|
||||||
/* Lookup key 1 to tgt_free*3/2 */
|
/* Lookup key 1 to tgt_free*3/2 */
|
||||||
end_key = tgt_free + batch_size;
|
end_key = tgt_free + batch_size;
|
||||||
for (key = 1; key < end_key; key++) {
|
for (key = 1; key < end_key; key++) {
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
}
|
}
|
||||||
|
@ -463,7 +529,7 @@ static void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
|
||||||
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
|
||||||
for (key = 1; key <= tgt_free; key++) {
|
for (key = 1; key <= tgt_free; key++) {
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
}
|
}
|
||||||
|
@ -494,16 +560,16 @@ static void do_test_lru_sanity5(unsigned long long last_key, int map_fd)
|
||||||
unsigned long long key, value[nr_cpus];
|
unsigned long long key, value[nr_cpus];
|
||||||
|
|
||||||
/* Ensure the last key inserted by previous CPU can be found */
|
/* Ensure the last key inserted by previous CPU can be found */
|
||||||
assert(!bpf_map_lookup_elem(map_fd, &last_key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value));
|
||||||
|
|
||||||
value[0] = 1234;
|
value[0] = 1234;
|
||||||
|
|
||||||
key = last_key + 1;
|
key = last_key + 1;
|
||||||
assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
|
assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
|
||||||
assert(!bpf_map_lookup_elem(map_fd, &key, value));
|
assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value));
|
||||||
|
|
||||||
/* Cannot find the last key because it was removed by LRU */
|
/* Cannot find the last key because it was removed by LRU */
|
||||||
assert(bpf_map_lookup_elem(map_fd, &last_key, value));
|
assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test map with only one element */
|
/* Test map with only one element */
|
||||||
|
@ -590,8 +656,8 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
|
||||||
/* Make ref bit sticky for key: [1, tgt_free] */
|
/* Make ref bit sticky for key: [1, tgt_free] */
|
||||||
for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
|
for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
|
||||||
/* Mark the ref bit */
|
/* Mark the ref bit */
|
||||||
assert(!bpf_map_lookup_elem(lru_map_fd, &stable_key,
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd,
|
||||||
value));
|
stable_key, value));
|
||||||
}
|
}
|
||||||
assert(!bpf_map_update_elem(lru_map_fd, &key, value,
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value,
|
||||||
BPF_NOEXIST));
|
BPF_NOEXIST));
|
||||||
|
@ -612,6 +678,198 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
|
||||||
printf("Pass\n");
|
printf("Pass\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Size of the LRU map is 2
|
||||||
|
* Add key=1 (+1 key)
|
||||||
|
* Add key=2 (+1 key)
|
||||||
|
* Lookup Key=1 (datapath)
|
||||||
|
* Lookup Key=2 (syscall)
|
||||||
|
* Add Key=3
|
||||||
|
* => Key=2 will be removed by LRU
|
||||||
|
* Iterate map. Only found key=1 and key=3
|
||||||
|
*/
|
||||||
|
static void test_lru_sanity7(int map_type, int map_flags)
|
||||||
|
{
|
||||||
|
unsigned long long key, value[nr_cpus];
|
||||||
|
int lru_map_fd, expected_map_fd;
|
||||||
|
int next_cpu = 0;
|
||||||
|
|
||||||
|
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
|
||||||
|
map_flags);
|
||||||
|
|
||||||
|
assert(sched_next_online(0, &next_cpu) != -1);
|
||||||
|
|
||||||
|
if (map_flags & BPF_F_NO_COMMON_LRU)
|
||||||
|
lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
|
||||||
|
else
|
||||||
|
lru_map_fd = create_map(map_type, map_flags, 2);
|
||||||
|
assert(lru_map_fd != -1);
|
||||||
|
|
||||||
|
expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
|
||||||
|
assert(expected_map_fd != -1);
|
||||||
|
|
||||||
|
value[0] = 1234;
|
||||||
|
|
||||||
|
/* insert key=1 element */
|
||||||
|
|
||||||
|
key = 1;
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
|
BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* BPF_NOEXIST means: add new element if it doesn't exist */
|
||||||
|
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
|
||||||
|
/* key=1 already exists */
|
||||||
|
&& errno == EEXIST);
|
||||||
|
|
||||||
|
/* insert key=2 element */
|
||||||
|
|
||||||
|
/* check that key=2 is not found */
|
||||||
|
key = 2;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
/* BPF_EXIST means: update existing element */
|
||||||
|
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
|
||||||
|
/* key=2 is not there */
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* insert key=3 element */
|
||||||
|
|
||||||
|
/* check that key=3 is not found */
|
||||||
|
key = 3;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
/* check that key=1 can be found and mark the ref bit to
|
||||||
|
* stop LRU from removing key=1
|
||||||
|
*/
|
||||||
|
key = 1;
|
||||||
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
|
assert(value[0] == 1234);
|
||||||
|
|
||||||
|
/* check that key=2 can be found and do _not_ mark ref bit.
|
||||||
|
* this will be evicted on next update.
|
||||||
|
*/
|
||||||
|
key = 2;
|
||||||
|
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
||||||
|
assert(value[0] == 1234);
|
||||||
|
|
||||||
|
key = 3;
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
|
BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* key=2 has been removed from the LRU */
|
||||||
|
key = 2;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
assert(map_equal(lru_map_fd, expected_map_fd));
|
||||||
|
|
||||||
|
close(expected_map_fd);
|
||||||
|
close(lru_map_fd);
|
||||||
|
|
||||||
|
printf("Pass\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Size of the LRU map is 2
|
||||||
|
* Add key=1 (+1 key)
|
||||||
|
* Add key=2 (+1 key)
|
||||||
|
* Lookup Key=1 (syscall)
|
||||||
|
* Lookup Key=2 (datapath)
|
||||||
|
* Add Key=3
|
||||||
|
* => Key=1 will be removed by LRU
|
||||||
|
* Iterate map. Only found key=2 and key=3
|
||||||
|
*/
|
||||||
|
static void test_lru_sanity8(int map_type, int map_flags)
|
||||||
|
{
|
||||||
|
unsigned long long key, value[nr_cpus];
|
||||||
|
int lru_map_fd, expected_map_fd;
|
||||||
|
int next_cpu = 0;
|
||||||
|
|
||||||
|
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
|
||||||
|
map_flags);
|
||||||
|
|
||||||
|
assert(sched_next_online(0, &next_cpu) != -1);
|
||||||
|
|
||||||
|
if (map_flags & BPF_F_NO_COMMON_LRU)
|
||||||
|
lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
|
||||||
|
else
|
||||||
|
lru_map_fd = create_map(map_type, map_flags, 2);
|
||||||
|
assert(lru_map_fd != -1);
|
||||||
|
|
||||||
|
expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
|
||||||
|
assert(expected_map_fd != -1);
|
||||||
|
|
||||||
|
value[0] = 1234;
|
||||||
|
|
||||||
|
/* insert key=1 element */
|
||||||
|
|
||||||
|
key = 1;
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* BPF_NOEXIST means: add new element if it doesn't exist */
|
||||||
|
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
|
||||||
|
/* key=1 already exists */
|
||||||
|
&& errno == EEXIST);
|
||||||
|
|
||||||
|
/* insert key=2 element */
|
||||||
|
|
||||||
|
/* check that key=2 is not found */
|
||||||
|
key = 2;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
/* BPF_EXIST means: update existing element */
|
||||||
|
assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
|
||||||
|
/* key=2 is not there */
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
|
BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* insert key=3 element */
|
||||||
|
|
||||||
|
/* check that key=3 is not found */
|
||||||
|
key = 3;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
/* check that key=1 can be found and do _not_ mark ref bit.
|
||||||
|
* this will be evicted on next update.
|
||||||
|
*/
|
||||||
|
key = 1;
|
||||||
|
assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
|
||||||
|
assert(value[0] == 1234);
|
||||||
|
|
||||||
|
/* check that key=2 can be found and mark the ref bit to
|
||||||
|
* stop LRU from removing key=2
|
||||||
|
*/
|
||||||
|
key = 2;
|
||||||
|
assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
|
||||||
|
assert(value[0] == 1234);
|
||||||
|
|
||||||
|
key = 3;
|
||||||
|
assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
|
||||||
|
assert(!bpf_map_update_elem(expected_map_fd, &key, value,
|
||||||
|
BPF_NOEXIST));
|
||||||
|
|
||||||
|
/* key=1 has been removed from the LRU */
|
||||||
|
key = 1;
|
||||||
|
assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
|
||||||
|
errno == ENOENT);
|
||||||
|
|
||||||
|
assert(map_equal(lru_map_fd, expected_map_fd));
|
||||||
|
|
||||||
|
close(expected_map_fd);
|
||||||
|
close(lru_map_fd);
|
||||||
|
|
||||||
|
printf("Pass\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
|
int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
|
||||||
|
@ -637,6 +895,8 @@ int main(int argc, char **argv)
|
||||||
test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
|
test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
|
||||||
test_lru_sanity5(map_types[t], map_flags[f]);
|
test_lru_sanity5(map_types[t], map_flags[f]);
|
||||||
test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
|
test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
|
||||||
|
test_lru_sanity7(map_types[t], map_flags[f]);
|
||||||
|
test_lru_sanity8(map_types[t], map_flags[f]);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue