diff options
author | John Fastabend <john.fastabend@gmail.com> | 2018-10-16 14:08:09 -0400 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2018-10-16 20:30:32 -0400 |
commit | 753fb2ee09345e0730e610b2ee3a01964fe22a63 (patch) | |
tree | 91c572d5fd4344b131082e7a1e5e033245dc21b8 | |
parent | 02c558b2d5d679fbbcaa5b9689484c7e0f8abb7b (diff) |
bpf: sockmap, add msg_peek tests to test_sockmap
Add tests that do a MSG_PEEK recv followed by a regular receive to
test flag support.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r-- | tools/testing/selftests/bpf/test_sockmap.c | 167 |
1 files changed, 115 insertions, 52 deletions
diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 7cb69ce6dfa2..cbd1c0be8680 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c | |||
@@ -80,6 +80,7 @@ int txmsg_end; | |||
80 | int txmsg_ingress; | 80 | int txmsg_ingress; |
81 | int txmsg_skb; | 81 | int txmsg_skb; |
82 | int ktls; | 82 | int ktls; |
83 | int peek_flag; | ||
83 | 84 | ||
84 | static const struct option long_options[] = { | 85 | static const struct option long_options[] = { |
85 | {"help", no_argument, NULL, 'h' }, | 86 | {"help", no_argument, NULL, 'h' }, |
@@ -102,6 +103,7 @@ static const struct option long_options[] = { | |||
102 | {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, | 103 | {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, |
103 | {"txmsg_skb", no_argument, &txmsg_skb, 1 }, | 104 | {"txmsg_skb", no_argument, &txmsg_skb, 1 }, |
104 | {"ktls", no_argument, &ktls, 1 }, | 105 | {"ktls", no_argument, &ktls, 1 }, |
106 | {"peek", no_argument, &peek_flag, 1 }, | ||
105 | {0, 0, NULL, 0 } | 107 | {0, 0, NULL, 0 } |
106 | }; | 108 | }; |
107 | 109 | ||
@@ -352,33 +354,40 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt, | |||
352 | return 0; | 354 | return 0; |
353 | } | 355 | } |
354 | 356 | ||
355 | static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | 357 | static void msg_free_iov(struct msghdr *msg) |
356 | struct msg_stats *s, bool tx, | ||
357 | struct sockmap_options *opt) | ||
358 | { | 358 | { |
359 | struct msghdr msg = {0}; | 359 | int i; |
360 | int err, i, flags = MSG_NOSIGNAL; | 360 | |
361 | for (i = 0; i < msg->msg_iovlen; i++) | ||
362 | free(msg->msg_iov[i].iov_base); | ||
363 | free(msg->msg_iov); | ||
364 | msg->msg_iov = NULL; | ||
365 | msg->msg_iovlen = 0; | ||
366 | } | ||
367 | |||
368 | static int msg_alloc_iov(struct msghdr *msg, | ||
369 | int iov_count, int iov_length, | ||
370 | bool data, bool xmit) | ||
371 | { | ||
372 | unsigned char k = 0; | ||
361 | struct iovec *iov; | 373 | struct iovec *iov; |
362 | unsigned char k; | 374 | int i; |
363 | bool data_test = opt->data_test; | ||
364 | bool drop = opt->drop_expected; | ||
365 | 375 | ||
366 | iov = calloc(iov_count, sizeof(struct iovec)); | 376 | iov = calloc(iov_count, sizeof(struct iovec)); |
367 | if (!iov) | 377 | if (!iov) |
368 | return errno; | 378 | return errno; |
369 | 379 | ||
370 | k = 0; | ||
371 | for (i = 0; i < iov_count; i++) { | 380 | for (i = 0; i < iov_count; i++) { |
372 | unsigned char *d = calloc(iov_length, sizeof(char)); | 381 | unsigned char *d = calloc(iov_length, sizeof(char)); |
373 | 382 | ||
374 | if (!d) { | 383 | if (!d) { |
375 | fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); | 384 | fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); |
376 | goto out_errno; | 385 | goto unwind_iov; |
377 | } | 386 | } |
378 | iov[i].iov_base = d; | 387 | iov[i].iov_base = d; |
379 | iov[i].iov_len = iov_length; | 388 | iov[i].iov_len = iov_length; |
380 | 389 | ||
381 | if (data_test && tx) { | 390 | if (data && xmit) { |
382 | int j; | 391 | int j; |
383 | 392 | ||
384 | for (j = 0; j < iov_length; j++) | 393 | for (j = 0; j < iov_length; j++) |
@@ -386,9 +395,60 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
386 | } | 395 | } |
387 | } | 396 | } |
388 | 397 | ||
389 | msg.msg_iov = iov; | 398 | msg->msg_iov = iov; |
390 | msg.msg_iovlen = iov_count; | 399 | msg->msg_iovlen = iov_count; |
391 | k = 0; | 400 | |
401 | return 0; | ||
402 | unwind_iov: | ||
403 | for (i--; i >= 0 ; i--) | ||
404 | free(msg->msg_iov[i].iov_base); | ||
405 | return -ENOMEM; | ||
406 | } | ||
407 | |||
408 | static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) | ||
409 | { | ||
410 | int i, j, bytes_cnt = 0; | ||
411 | unsigned char k = 0; | ||
412 | |||
413 | for (i = 0; i < msg->msg_iovlen; i++) { | ||
414 | unsigned char *d = msg->msg_iov[i].iov_base; | ||
415 | |||
416 | for (j = 0; | ||
417 | j < msg->msg_iov[i].iov_len && size; j++) { | ||
418 | if (d[j] != k++) { | ||
419 | fprintf(stderr, | ||
420 | "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", | ||
421 | i, j, d[j], k - 1, d[j+1], k); | ||
422 | return -EIO; | ||
423 | } | ||
424 | bytes_cnt++; | ||
425 | if (bytes_cnt == chunk_sz) { | ||
426 | k = 0; | ||
427 | bytes_cnt = 0; | ||
428 | } | ||
429 | size--; | ||
430 | } | ||
431 | } | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | ||
436 | struct msg_stats *s, bool tx, | ||
437 | struct sockmap_options *opt) | ||
438 | { | ||
439 | struct msghdr msg = {0}, msg_peek = {0}; | ||
440 | int err, i, flags = MSG_NOSIGNAL; | ||
441 | bool drop = opt->drop_expected; | ||
442 | bool data = opt->data_test; | ||
443 | |||
444 | err = msg_alloc_iov(&msg, iov_count, iov_length, data, tx); | ||
445 | if (err) | ||
446 | goto out_errno; | ||
447 | if (peek_flag) { | ||
448 | err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx); | ||
449 | if (err) | ||
450 | goto out_errno; | ||
451 | } | ||
392 | 452 | ||
393 | if (tx) { | 453 | if (tx) { |
394 | clock_gettime(CLOCK_MONOTONIC, &s->start); | 454 | clock_gettime(CLOCK_MONOTONIC, &s->start); |
@@ -408,19 +468,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
408 | } | 468 | } |
409 | clock_gettime(CLOCK_MONOTONIC, &s->end); | 469 | clock_gettime(CLOCK_MONOTONIC, &s->end); |
410 | } else { | 470 | } else { |
411 | int slct, recv, max_fd = fd; | 471 | int slct, recvp = 0, recv, max_fd = fd; |
412 | int fd_flags = O_NONBLOCK; | 472 | int fd_flags = O_NONBLOCK; |
413 | struct timeval timeout; | 473 | struct timeval timeout; |
414 | float total_bytes; | 474 | float total_bytes; |
415 | int bytes_cnt = 0; | ||
416 | int chunk_sz; | ||
417 | fd_set w; | 475 | fd_set w; |
418 | 476 | ||
419 | if (opt->sendpage) | ||
420 | chunk_sz = iov_length * cnt; | ||
421 | else | ||
422 | chunk_sz = iov_length * iov_count; | ||
423 | |||
424 | fcntl(fd, fd_flags); | 477 | fcntl(fd, fd_flags); |
425 | total_bytes = (float)iov_count * (float)iov_length * (float)cnt; | 478 | total_bytes = (float)iov_count * (float)iov_length * (float)cnt; |
426 | err = clock_gettime(CLOCK_MONOTONIC, &s->start); | 479 | err = clock_gettime(CLOCK_MONOTONIC, &s->start); |
@@ -452,6 +505,19 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
452 | goto out_errno; | 505 | goto out_errno; |
453 | } | 506 | } |
454 | 507 | ||
508 | errno = 0; | ||
509 | if (peek_flag) { | ||
510 | flags |= MSG_PEEK; | ||
511 | recvp = recvmsg(fd, &msg_peek, flags); | ||
512 | if (recvp < 0) { | ||
513 | if (errno != EWOULDBLOCK) { | ||
514 | clock_gettime(CLOCK_MONOTONIC, &s->end); | ||
515 | goto out_errno; | ||
516 | } | ||
517 | } | ||
518 | flags = 0; | ||
519 | } | ||
520 | |||
455 | recv = recvmsg(fd, &msg, flags); | 521 | recv = recvmsg(fd, &msg, flags); |
456 | if (recv < 0) { | 522 | if (recv < 0) { |
457 | if (errno != EWOULDBLOCK) { | 523 | if (errno != EWOULDBLOCK) { |
@@ -463,27 +529,23 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
463 | 529 | ||
464 | s->bytes_recvd += recv; | 530 | s->bytes_recvd += recv; |
465 | 531 | ||
466 | if (data_test) { | 532 | if (data) { |
467 | int j; | 533 | int chunk_sz = opt->sendpage ? |
468 | 534 | iov_length * cnt : | |
469 | for (i = 0; i < msg.msg_iovlen; i++) { | 535 | iov_length * iov_count; |
470 | unsigned char *d = iov[i].iov_base; | 536 | |
471 | 537 | errno = msg_verify_data(&msg, recv, chunk_sz); | |
472 | for (j = 0; | 538 | if (errno) { |
473 | j < iov[i].iov_len && recv; j++) { | 539 | perror("data verify msg failed\n"); |
474 | if (d[j] != k++) { | 540 | goto out_errno; |
475 | errno = -EIO; | 541 | } |
476 | fprintf(stderr, | 542 | if (recvp) { |
477 | "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", | 543 | errno = msg_verify_data(&msg_peek, |
478 | i, j, d[j], k - 1, d[j+1], k); | 544 | recvp, |
479 | goto out_errno; | 545 | chunk_sz); |
480 | } | 546 | if (errno) { |
481 | bytes_cnt++; | 547 | perror("data verify msg_peek failed\n"); |
482 | if (bytes_cnt == chunk_sz) { | 548 | goto out_errno; |
483 | k = 0; | ||
484 | bytes_cnt = 0; | ||
485 | } | ||
486 | recv--; | ||
487 | } | 549 | } |
488 | } | 550 | } |
489 | } | 551 | } |
@@ -491,14 +553,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
491 | clock_gettime(CLOCK_MONOTONIC, &s->end); | 553 | clock_gettime(CLOCK_MONOTONIC, &s->end); |
492 | } | 554 | } |
493 | 555 | ||
494 | for (i = 0; i < iov_count; i++) | 556 | msg_free_iov(&msg); |
495 | free(iov[i].iov_base); | 557 | msg_free_iov(&msg_peek); |
496 | free(iov); | 558 | return err; |
497 | return 0; | ||
498 | out_errno: | 559 | out_errno: |
499 | for (i = 0; i < iov_count; i++) | 560 | msg_free_iov(&msg); |
500 | free(iov[i].iov_base); | 561 | msg_free_iov(&msg_peek); |
501 | free(iov); | ||
502 | return errno; | 562 | return errno; |
503 | } | 563 | } |
504 | 564 | ||
@@ -565,9 +625,10 @@ static int sendmsg_test(struct sockmap_options *opt) | |||
565 | } | 625 | } |
566 | if (opt->verbose) | 626 | if (opt->verbose) |
567 | fprintf(stdout, | 627 | fprintf(stdout, |
568 | "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n", | 628 | "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n", |
569 | s.bytes_sent, sent_Bps, sent_Bps/giga, | 629 | s.bytes_sent, sent_Bps, sent_Bps/giga, |
570 | s.bytes_recvd, recvd_Bps, recvd_Bps/giga); | 630 | s.bytes_recvd, recvd_Bps, recvd_Bps/giga, |
631 | peek_flag ? "(peek_msg)" : ""); | ||
571 | if (err && txmsg_cork) | 632 | if (err && txmsg_cork) |
572 | err = 0; | 633 | err = 0; |
573 | exit(err ? 1 : 0); | 634 | exit(err ? 1 : 0); |
@@ -999,6 +1060,8 @@ static void test_options(char *options) | |||
999 | strncat(options, "skb,", OPTSTRING); | 1060 | strncat(options, "skb,", OPTSTRING); |
1000 | if (ktls) | 1061 | if (ktls) |
1001 | strncat(options, "ktls,", OPTSTRING); | 1062 | strncat(options, "ktls,", OPTSTRING); |
1063 | if (peek_flag) | ||
1064 | strncat(options, "peek,", OPTSTRING); | ||
1002 | } | 1065 | } |
1003 | 1066 | ||
1004 | static int __test_exec(int cgrp, int test, struct sockmap_options *opt) | 1067 | static int __test_exec(int cgrp, int test, struct sockmap_options *opt) |