Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Modify linked_list tests to work with macro-ified inserts

The linked_list tests use macros and function pointers to reduce code
duplication. Earlier in the series, bpf_list_push_{front,back} were
modified to be macros, expanding to invoke actual kfuncs
bpf_list_push_{front,back}_impl. Due to this change, a code snippet
like:

void (*p)(void *, void *) = (void *)&bpf_list_##op;
p(hexpr, nexpr);

meant to do bpf_list_push_{front,back}(hexpr, nexpr), will no longer
work as it's no longer valid to do &bpf_list_push_{front,back} since
they're no longer functions.

This patch fixes issues of this type, along with two other minor changes
- one improvement and one fix - both related to the node argument to
list_push_{front,back}.

* The fix: migration of list_push tests away from (void *, void *)
func ptr uncovered that some tests were incorrectly passing pointer
to node, not pointer to struct bpf_list_node within the node. This
patch fixes such issues (CHECK(..., f) -> CHECK(..., &f->node))

* The improvement: In linked_list tests, the struct foo type has two
list_node fields: node and node2, at byte offsets 0 and 40 within
the struct, respectively. Currently node is used in ~all tests
involving struct foo and lists. The verifier needs to do some work
to account for the offset of bpf_list_node within the node type, so
using node2 instead of node exercises that logic more in the tests.
This patch migrates linked_list tests to use node2 instead of node.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Link: https://lore.kernel.org/r/20230415201811.343116-7-davemarchevsky@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Dave Marchevsky and committed by
Alexei Starovoitov
de67ba39 d2dcc67d

+73 -67
+3 -3
tools/testing/selftests/bpf/prog_tests/linked_list.c
··· 84 84 { "double_push_back", "arg#1 expected pointer to allocated object" }, 85 85 { "no_node_value_type", "bpf_list_node not found at offset=0" }, 86 86 { "incorrect_value_type", 87 - "operation on bpf_list_head expects arg#1 bpf_list_node at offset=0 in struct foo, " 87 + "operation on bpf_list_head expects arg#1 bpf_list_node at offset=40 in struct foo, " 88 88 "but arg is at offset=0 in struct bar" }, 89 89 { "incorrect_node_var_off", "variable ptr_ access var_off=(0x0; 0xffffffff) disallowed" }, 90 - { "incorrect_node_off1", "bpf_list_node not found at offset=1" }, 91 - { "incorrect_node_off2", "arg#1 offset=40, but expected bpf_list_node at offset=0 in struct foo" }, 90 + { "incorrect_node_off1", "bpf_list_node not found at offset=41" }, 91 + { "incorrect_node_off2", "arg#1 offset=0, but expected bpf_list_node at offset=40 in struct foo" }, 92 92 { "no_head_type", "bpf_list_head not found at offset=0" }, 93 93 { "incorrect_head_var_off1", "R1 doesn't have constant offset" }, 94 94 { "incorrect_head_var_off2", "variable ptr_ access var_off=(0x0; 0xffffffff) disallowed" },
+17 -17
tools/testing/selftests/bpf/progs/linked_list.c
··· 25 25 n = bpf_list_pop_front(head); 26 26 bpf_spin_unlock(lock); 27 27 if (n) { 28 - bpf_obj_drop(container_of(n, struct foo, node)); 28 + bpf_obj_drop(container_of(n, struct foo, node2)); 29 29 bpf_obj_drop(f); 30 30 return 3; 31 31 } ··· 34 34 n = bpf_list_pop_back(head); 35 35 bpf_spin_unlock(lock); 36 36 if (n) { 37 - bpf_obj_drop(container_of(n, struct foo, node)); 37 + bpf_obj_drop(container_of(n, struct foo, node2)); 38 38 bpf_obj_drop(f); 39 39 return 4; 40 40 } ··· 42 42 43 43 bpf_spin_lock(lock); 44 44 f->data = 42; 45 - bpf_list_push_front(head, &f->node); 45 + bpf_list_push_front(head, &f->node2); 46 46 bpf_spin_unlock(lock); 47 47 if (leave_in_map) 48 48 return 0; ··· 51 51 bpf_spin_unlock(lock); 52 52 if (!n) 53 53 return 5; 54 - f = container_of(n, struct foo, node); 54 + f = container_of(n, struct foo, node2); 55 55 if (f->data != 42) { 56 56 bpf_obj_drop(f); 57 57 return 6; ··· 59 59 60 60 bpf_spin_lock(lock); 61 61 f->data = 13; 62 - bpf_list_push_front(head, &f->node); 62 + bpf_list_push_front(head, &f->node2); 63 63 bpf_spin_unlock(lock); 64 64 bpf_spin_lock(lock); 65 65 n = bpf_list_pop_front(head); 66 66 bpf_spin_unlock(lock); 67 67 if (!n) 68 68 return 7; 69 - f = container_of(n, struct foo, node); 69 + f = container_of(n, struct foo, node2); 70 70 if (f->data != 13) { 71 71 bpf_obj_drop(f); 72 72 return 8; ··· 77 77 n = bpf_list_pop_front(head); 78 78 bpf_spin_unlock(lock); 79 79 if (n) { 80 - bpf_obj_drop(container_of(n, struct foo, node)); 80 + bpf_obj_drop(container_of(n, struct foo, node2)); 81 81 return 9; 82 82 } 83 83 ··· 85 85 n = bpf_list_pop_back(head); 86 86 bpf_spin_unlock(lock); 87 87 if (n) { 88 - bpf_obj_drop(container_of(n, struct foo, node)); 88 + bpf_obj_drop(container_of(n, struct foo, node2)); 89 89 return 10; 90 90 } 91 91 return 0; ··· 119 119 f[i + 1]->data = i + 1; 120 120 121 121 bpf_spin_lock(lock); 122 - bpf_list_push_front(head, &f[i]->node); 123 - bpf_list_push_front(head, &f[i + 1]->node); 122 + bpf_list_push_front(head, &f[i]->node2); 123 + bpf_list_push_front(head, &f[i + 1]->node2); 124 124 bpf_spin_unlock(lock); 125 125 } 126 126 ··· 130 130 bpf_spin_unlock(lock); 131 131 if (!n) 132 132 return 3; 133 - pf = container_of(n, struct foo, node); 133 + pf = container_of(n, struct foo, node2); 134 134 if (pf->data != (ARRAY_SIZE(f) - i - 1)) { 135 135 bpf_obj_drop(pf); 136 136 return 4; 137 137 } 138 138 bpf_spin_lock(lock); 139 - bpf_list_push_back(head, &pf->node); 139 + bpf_list_push_back(head, &pf->node2); 140 140 bpf_spin_unlock(lock); 141 141 } 142 142 ··· 149 149 bpf_spin_unlock(lock); 150 150 if (!n) 151 151 return 5; 152 - pf = container_of(n, struct foo, node); 152 + pf = container_of(n, struct foo, node2); 153 153 if (pf->data != i) { 154 154 bpf_obj_drop(pf); 155 155 return 6; ··· 160 160 n = bpf_list_pop_back(head); 161 161 bpf_spin_unlock(lock); 162 162 if (n) { 163 - bpf_obj_drop(container_of(n, struct foo, node)); 163 + bpf_obj_drop(container_of(n, struct foo, node2)); 164 164 return 7; 165 165 } 166 166 ··· 168 168 n = bpf_list_pop_front(head); 169 169 bpf_spin_unlock(lock); 170 170 if (n) { 171 - bpf_obj_drop(container_of(n, struct foo, node)); 171 + bpf_obj_drop(container_of(n, struct foo, node2)); 172 172 return 8; 173 173 } 174 174 return 0; ··· 199 199 200 200 bpf_spin_lock(lock); 201 201 f->data = 42; 202 - bpf_list_push_front(head, &f->node); 202 + bpf_list_push_front(head, &f->node2); 203 203 bpf_spin_unlock(lock); 204 204 205 205 if (leave_in_map) ··· 210 210 bpf_spin_unlock(lock); 211 211 if (!n) 212 212 return 4; 213 - f = container_of(n, struct foo, node); 213 + f = container_of(n, struct foo, node2); 214 214 if (f->data != 42) { 215 215 bpf_obj_drop(f); 216 216 return 5;
+2 -2
tools/testing/selftests/bpf/progs/linked_list.h
··· 22 22 struct map_value { 23 23 struct bpf_spin_lock lock; 24 24 int data; 25 - struct bpf_list_head head __contains(foo, node); 25 + struct bpf_list_head head __contains(foo, node2); 26 26 }; 27 27 28 28 struct array_map { ··· 50 50 #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) 51 51 52 52 private(A) struct bpf_spin_lock glock; 53 - private(A) struct bpf_list_head ghead __contains(foo, node); 53 + private(A) struct bpf_list_head ghead __contains(foo, node2); 54 54 private(B) struct bpf_spin_lock glock2; 55 55 56 56 #endif
+51 -45
tools/testing/selftests/bpf/progs/linked_list_fail.c
··· 73 73 int test##_missing_lock_##op(void *ctx) \ 74 74 { \ 75 75 INIT; \ 76 - void (*p)(void *, void *) = (void *)&bpf_list_##op; \ 77 - p(hexpr, nexpr); \ 76 + bpf_list_##op(hexpr, nexpr); \ 78 77 return 0; \ 79 78 } 80 79 81 - CHECK(kptr, push_front, &f->head, b); 82 - CHECK(kptr, push_back, &f->head, b); 80 + CHECK(kptr, push_front, &f->head, &b->node); 81 + CHECK(kptr, push_back, &f->head, &b->node); 83 82 84 - CHECK(global, push_front, &ghead, f); 85 - CHECK(global, push_back, &ghead, f); 83 + CHECK(global, push_front, &ghead, &f->node2); 84 + CHECK(global, push_back, &ghead, &f->node2); 86 85 87 - CHECK(map, push_front, &v->head, f); 88 - CHECK(map, push_back, &v->head, f); 86 + CHECK(map, push_front, &v->head, &f->node2); 87 + CHECK(map, push_back, &v->head, &f->node2); 89 88 90 - CHECK(inner_map, push_front, &iv->head, f); 91 - CHECK(inner_map, push_back, &iv->head, f); 89 + CHECK(inner_map, push_front, &iv->head, &f->node2); 90 + CHECK(inner_map, push_back, &iv->head, &f->node2); 92 91 93 92 #undef CHECK 94 93 ··· 134 135 int test##_incorrect_lock_##op(void *ctx) \ 135 136 { \ 136 137 INIT; \ 137 - void (*p)(void *, void*) = (void *)&bpf_list_##op; \ 138 138 bpf_spin_lock(lexpr); \ 139 - p(hexpr, nexpr); \ 139 + bpf_list_##op(hexpr, nexpr); \ 140 140 return 0; \ 141 141 } 142 142 143 143 #define CHECK_OP(op) \ 144 - CHECK(kptr_kptr, op, &f1->lock, &f2->head, b); \ 145 - CHECK(kptr_global, op, &f1->lock, &ghead, f); \ 146 - CHECK(kptr_map, op, &f1->lock, &v->head, f); \ 147 - CHECK(kptr_inner_map, op, &f1->lock, &iv->head, f); \ 144 + CHECK(kptr_kptr, op, &f1->lock, &f2->head, &b->node); \ 145 + CHECK(kptr_global, op, &f1->lock, &ghead, &f->node2); \ 146 + CHECK(kptr_map, op, &f1->lock, &v->head, &f->node2); \ 147 + CHECK(kptr_inner_map, op, &f1->lock, &iv->head, &f->node2); \ 148 148 \ 149 - CHECK(global_global, op, &glock2, &ghead, f); \ 150 - CHECK(global_kptr, op, &glock, &f1->head, b); \ 151 - CHECK(global_map, op, &glock, &v->head, f); \ 152 - CHECK(global_inner_map, op, &glock, &iv->head, f); \ 149 + CHECK(global_global, op, &glock2, &ghead, &f->node2); \ 150 + CHECK(global_kptr, op, &glock, &f1->head, &b->node); \ 151 + CHECK(global_map, op, &glock, &v->head, &f->node2); \ 152 + CHECK(global_inner_map, op, &glock, &iv->head, &f->node2); \ 153 153 \ 154 - CHECK(map_map, op, &v->lock, &v2->head, f); \ 155 - CHECK(map_kptr, op, &v->lock, &f2->head, b); \ 156 - CHECK(map_global, op, &v->lock, &ghead, f); \ 157 - CHECK(map_inner_map, op, &v->lock, &iv->head, f); \ 154 + CHECK(map_map, op, &v->lock, &v2->head, &f->node2); \ 155 + CHECK(map_kptr, op, &v->lock, &f2->head, &b->node); \ 156 + CHECK(map_global, op, &v->lock, &ghead, &f->node2); \ 157 + CHECK(map_inner_map, op, &v->lock, &iv->head, &f->node2); \ 158 158 \ 159 - CHECK(inner_map_inner_map, op, &iv->lock, &iv2->head, f); \ 160 - CHECK(inner_map_kptr, op, &iv->lock, &f2->head, b); \ 161 - CHECK(inner_map_global, op, &iv->lock, &ghead, f); \ 162 - CHECK(inner_map_map, op, &iv->lock, &v->head, f); 159 + CHECK(inner_map_inner_map, op, &iv->lock, &iv2->head, &f->node2);\ 160 + CHECK(inner_map_kptr, op, &iv->lock, &f2->head, &b->node); \ 161 + CHECK(inner_map_global, op, &iv->lock, &ghead, &f->node2); \ 162 + CHECK(inner_map_map, op, &iv->lock, &v->head, &f->node2); 163 163 164 164 CHECK_OP(push_front); 165 165 CHECK_OP(push_back); ··· 338 340 f = bpf_obj_new(typeof(*f)); 339 341 if (!f) 340 342 return 0; 341 - return *(int *)&f->node; 343 + return *(int *)&f->node2; 342 344 } 343 345 344 346 SEC("?tc") ··· 349 351 f = bpf_obj_new(typeof(*f)); 350 352 if (!f) 351 353 return 0; 352 - *(int *)&f->node = 0; 354 + *(int *)&f->node2 = 0; 353 355 return 0; 354 356 } 355 357 356 358 static __always_inline 357 - int use_after_unlock(void (*op)(void *head, void *node)) 359 + int use_after_unlock(bool push_front) 358 360 { 359 361 struct foo *f; 360 362 ··· 363 365 return 0; 364 366 bpf_spin_lock(&glock); 365 367 f->data = 42; 366 - op(&ghead, &f->node); 368 + if (push_front) 369 + bpf_list_push_front(&ghead, &f->node2); 370 + else 371 + bpf_list_push_back(&ghead, &f->node2); 367 372 bpf_spin_unlock(&glock); 368 373 369 374 return f->data; ··· 375 374 SEC("?tc") 376 375 int use_after_unlock_push_front(void *ctx) 377 376 { 378 - return use_after_unlock((void *)bpf_list_push_front); 377 + return use_after_unlock(true); 379 378 } 380 379 381 380 SEC("?tc") 382 381 int use_after_unlock_push_back(void *ctx) 383 382 { 384 - return use_after_unlock((void *)bpf_list_push_back); 383 + return use_after_unlock(false); 385 384 } 386 385 387 386 static __always_inline 388 - int list_double_add(void (*op)(void *head, void *node)) 387 + int list_double_add(bool push_front) 389 388 { 390 389 struct foo *f; 391 390 ··· 393 392 if (!f) 394 393 return 0; 395 394 bpf_spin_lock(&glock); 396 - op(&ghead, &f->node); 397 - op(&ghead, &f->node); 395 + if (push_front) { 396 + bpf_list_push_front(&ghead, &f->node2); 397 + bpf_list_push_front(&ghead, &f->node2); 398 + } else { 399 + bpf_list_push_back(&ghead, &f->node2); 400 + bpf_list_push_back(&ghead, &f->node2); 401 + } 398 402 bpf_spin_unlock(&glock); 399 403 400 404 return 0; ··· 408 402 SEC("?tc") 409 403 int double_push_front(void *ctx) 410 404 { 411 - return list_double_add((void *)bpf_list_push_front); 405 + return list_double_add(true); 412 406 } 413 407 414 408 SEC("?tc") 415 409 int double_push_back(void *ctx) 416 410 { 417 - return list_double_add((void *)bpf_list_push_back); 411 + return list_double_add(false); 418 412 } 419 413 420 414 SEC("?tc") ··· 456 450 if (!f) 457 451 return 0; 458 452 bpf_spin_lock(&glock); 459 - bpf_list_push_front(&ghead, (void *)&f->node + ctx->protocol); 453 + bpf_list_push_front(&ghead, (void *)&f->node2 + ctx->protocol); 460 454 bpf_spin_unlock(&glock); 461 455 462 456 return 0; ··· 471 465 if (!f) 472 466 return 0; 473 467 bpf_spin_lock(&glock); 474 - bpf_list_push_front(&ghead, (void *)&f->node + 1); 468 + bpf_list_push_front(&ghead, (void *)&f->node2 + 1); 475 469 bpf_spin_unlock(&glock); 476 470 477 471 return 0; ··· 486 480 if (!f) 487 481 return 0; 488 482 bpf_spin_lock(&glock); 489 - bpf_list_push_front(&ghead, &f->node2); 483 + bpf_list_push_front(&ghead, &f->node); 490 484 bpf_spin_unlock(&glock); 491 485 492 486 return 0; ··· 516 510 if (!f) 517 511 return 0; 518 512 bpf_spin_lock(&glock); 519 - bpf_list_push_front((void *)&ghead + ctx->protocol, &f->node); 513 + bpf_list_push_front((void *)&ghead + ctx->protocol, &f->node2); 520 514 bpf_spin_unlock(&glock); 521 515 522 516 return 0; ··· 531 525 if (!f) 532 526 return 0; 533 527 bpf_spin_lock(&glock); 534 - bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node); 528 + bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node2); 535 529 bpf_spin_unlock(&glock); 536 530 537 531 return 0; ··· 569 563 return 0; 570 564 571 565 bpf_spin_lock(&glock); 572 - bpf_list_push_front((void *)&ghead + 1, &f->node); 566 + bpf_list_push_front((void *)&ghead + 1, &f->node2); 573 567 bpf_spin_unlock(&glock); 574 568 575 569 return 0;