/* callback for array and lru timers */ staticint timer_cb1(void *map, int *key, struct bpf_timer *timer)
{ /* increment bss variable twice. * Once via array timer callback and once via lru timer callback
*/
bss_data += 5;
/* *key == 0 - the callback was called for array timer. * *key == 4 - the callback was called from lru timer.
*/ if (*key == ARRAY) { struct bpf_timer *lru_timer; int lru_key = LRU;
/* rearm array timer to be called again in ~35 seconds */ if (bpf_timer_start(timer, 1ull << 35, 0) != 0)
err |= 1;
lru_timer = bpf_map_lookup_elem(&lru, &lru_key); if (!lru_timer) return 0;
bpf_timer_set_callback(lru_timer, timer_cb1); if (bpf_timer_start(lru_timer, 0, 0) != 0)
err |= 2;
} elseif (*key == LRU) { int lru_key, i;
for (i = LRU + 1;
i <= 100 /* for current LRU eviction algorithm this number * should be larger than ~ lru->max_entries * 2
*/
i++) { struct elem init = {};
/* lru_key cannot be used as loop induction variable * otherwise the loop will be unbounded.
*/
lru_key = i;
/* add more elements into lru map to push out current * element and force deletion of this timer
*/
bpf_map_update_elem(map, &lru_key, &init, 0); /* look it up to bump it into active list */
bpf_map_lookup_elem(map, &lru_key);
/* keep adding until *key changes underneath, * which means that key/timer memory was reused
*/ if (*key != LRU) break;
}
/* check that the timer was removed */ if (bpf_timer_cancel(timer) != -EINVAL)
err |= 4;
ok |= 1;
} return 0;
}
SEC("fentry/bpf_fentry_test1") int BPF_PROG2(test1, int, a)
{ struct bpf_timer *arr_timer, *lru_timer; struct elem init = {}; int lru_key = LRU; int array_key = ARRAY;
/* init more timers to check that array destruction * doesn't leak timer memory.
*/
array_key = 0;
arr_timer = bpf_map_lookup_elem(&array, &array_key); if (!arr_timer) return 0;
bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC); return 0;
}
/* callback for prealloc and non-prealloca hashtab timers */ staticint timer_cb2(void *map, int *key, struct hmap_elem *val)
{ if (*key == HTAB)
callback_check--; else
callback2_check--; if (val->counter > 0 && --val->counter) { /* re-arm the timer again to execute after 1 usec */
bpf_timer_start(&val->timer, 1000, 0);
} elseif (*key == HTAB) { struct bpf_timer *arr_timer; int array_key = ARRAY;
/* cancel arr_timer otherwise bpf_fentry_test1 prog * will stay alive forever.
*/
arr_timer = bpf_map_lookup_elem(&array, &array_key); if (!arr_timer) return 0; if (bpf_timer_cancel(arr_timer) != 1) /* bpf_timer_cancel should return 1 to indicate * that arr_timer was active at this time
*/
err |= 8;
/* try to cancel ourself. It shouldn't deadlock. */ if (bpf_timer_cancel(&val->timer) != -EDEADLK)
err |= 16;
/* delete this key and this timer anyway. * It shouldn't deadlock either.
*/
bpf_map_delete_elem(map, key);
/* in preallocated hashmap both 'key' and 'val' could have been * reused to store another map element (like in LRU above), * but in controlled test environment the below test works. * It's not a use-after-free. The memory is owned by the map.
*/ if (bpf_timer_start(&val->timer, 1000, 0) != -EINVAL)
err |= 32;
ok |= 2;
} else { if (*key != HTAB_MALLOC)
err |= 64;
/* try to cancel ourself. It shouldn't deadlock. */ if (bpf_timer_cancel(&val->timer) != -EDEADLK)
err |= 128;
/* delete this key and this timer anyway. * It shouldn't deadlock either.
*/
bpf_map_delete_elem(map, key);
ok |= 4;
} return 0;
}
int bpf_timer_test(void)
{ struct hmap_elem *val; int key = HTAB, key_malloc = HTAB_MALLOC;
val = bpf_map_lookup_elem(&hmap, &key); if (val) { if (bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME) != 0)
err |= 512;
bpf_timer_set_callback(&val->timer, timer_cb2);
bpf_timer_start(&val->timer, 1000, 0);
}
val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); if (val) { if (bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME) != 0)
err |= 1024;
bpf_timer_set_callback(&val->timer, timer_cb2);
bpf_timer_start(&val->timer, 1000, 0);
} return 0;
}
SEC("fentry/bpf_fentry_test2") int BPF_PROG2(test2, int, a, int, b)
{ struct hmap_elem init = {}, *val; int key = HTAB, key_malloc = HTAB_MALLOC;
init.counter = 10; /* number of times to trigger timer_cb2 */
bpf_map_update_elem(&hmap, &key, &init, 0);
val = bpf_map_lookup_elem(&hmap, &key); if (val)
bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); /* update the same key to free the timer */
bpf_map_update_elem(&hmap, &key, &init, 0);
bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); if (val)
bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); /* update the same key to free the timer */
bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
/* init more timers to check that htab operations * don't leak timer memory.
*/
key = 0;
bpf_map_update_elem(&hmap, &key, &init, 0);
val = bpf_map_lookup_elem(&hmap, &key); if (val)
bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
bpf_map_delete_elem(&hmap, &key);
bpf_map_update_elem(&hmap, &key, &init, 0);
val = bpf_map_lookup_elem(&hmap, &key); if (val)
bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
/* and with non-prealloc htab */
key_malloc = 0;
bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); if (val)
bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
bpf_map_delete_elem(&hmap_malloc, &key_malloc);
bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); if (val)
bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
return bpf_timer_test();
}
/* callback for absolute timer */ staticint timer_cb3(void *map, int *key, struct bpf_timer *timer)
{
abs_data += 6;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.