bpf: sockmap sample, add data verification option
To verify data is not being dropped or corrupted this adds an option to verify test-patterns on recv. Signed-off-by: John Fastabend <john.fastabend@gmail.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
e67463cb5d
commit
6bce9d2ca6
|
@ -68,6 +68,7 @@ static const struct option long_options[] = {
|
||||||
{"iov_count", required_argument, NULL, 'i' },
|
{"iov_count", required_argument, NULL, 'i' },
|
||||||
{"length", required_argument, NULL, 'l' },
|
{"length", required_argument, NULL, 'l' },
|
||||||
{"test", required_argument, NULL, 't' },
|
{"test", required_argument, NULL, 't' },
|
||||||
|
{"data_test", no_argument, NULL, 'd' },
|
||||||
{"txmsg", no_argument, &txmsg_pass, 1 },
|
{"txmsg", no_argument, &txmsg_pass, 1 },
|
||||||
{"txmsg_noisy", no_argument, &txmsg_noisy, 1 },
|
{"txmsg_noisy", no_argument, &txmsg_noisy, 1 },
|
||||||
{"txmsg_redir", no_argument, &txmsg_redir, 1 },
|
{"txmsg_redir", no_argument, &txmsg_redir, 1 },
|
||||||
|
@ -208,45 +209,49 @@ struct msg_stats {
|
||||||
static int msg_loop_sendpage(int fd, int iov_length, int cnt,
|
static int msg_loop_sendpage(int fd, int iov_length, int cnt,
|
||||||
struct msg_stats *s)
|
struct msg_stats *s)
|
||||||
{
|
{
|
||||||
off_t offset = 0;
|
unsigned char k = 0;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
int i, fp;
|
int i, fp;
|
||||||
|
|
||||||
file = fopen(".sendpage_tst.tmp", "w+");
|
file = fopen(".sendpage_tst.tmp", "w+");
|
||||||
fseek(file, iov_length * cnt, SEEK_CUR);
|
for (i = 0; i < iov_length * cnt; i++, k++)
|
||||||
fprintf(file, "A");
|
fwrite(&k, sizeof(char), 1, file);
|
||||||
|
fflush(file);
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
fp = fileno(file);
|
fp = open(".sendpage_tst.tmp", O_RDONLY);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &s->start);
|
clock_gettime(CLOCK_MONOTONIC, &s->start);
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
int sent = sendfile(fd, fp, &offset, iov_length);
|
int sent = sendfile(fd, fp, NULL, iov_length);
|
||||||
|
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
perror("send loop error:");
|
perror("send loop error:");
|
||||||
fclose(file);
|
close(fp);
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
s->bytes_sent += sent;
|
s->bytes_sent += sent;
|
||||||
}
|
}
|
||||||
clock_gettime(CLOCK_MONOTONIC, &s->end);
|
clock_gettime(CLOCK_MONOTONIC, &s->end);
|
||||||
fclose(file);
|
close(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
|
static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
|
||||||
struct msg_stats *s, bool tx)
|
struct msg_stats *s, bool tx, bool data_test)
|
||||||
{
|
{
|
||||||
struct msghdr msg = {0};
|
struct msghdr msg = {0};
|
||||||
int err, i, flags = MSG_NOSIGNAL;
|
int err, i, flags = MSG_NOSIGNAL;
|
||||||
struct iovec *iov;
|
struct iovec *iov;
|
||||||
|
unsigned char k;
|
||||||
|
|
||||||
iov = calloc(iov_count, sizeof(struct iovec));
|
iov = calloc(iov_count, sizeof(struct iovec));
|
||||||
if (!iov)
|
if (!iov)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
|
k = 0;
|
||||||
for (i = 0; i < iov_count; i++) {
|
for (i = 0; i < iov_count; i++) {
|
||||||
char *d = calloc(iov_length, sizeof(char));
|
unsigned char *d = calloc(iov_length, sizeof(char));
|
||||||
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
|
fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
|
||||||
|
@ -254,10 +259,18 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
|
||||||
}
|
}
|
||||||
iov[i].iov_base = d;
|
iov[i].iov_base = d;
|
||||||
iov[i].iov_len = iov_length;
|
iov[i].iov_len = iov_length;
|
||||||
|
|
||||||
|
if (data_test && tx) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < iov_length; j++)
|
||||||
|
d[j] = k++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = iov_count;
|
msg.msg_iovlen = iov_count;
|
||||||
|
k = 0;
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &s->start);
|
clock_gettime(CLOCK_MONOTONIC, &s->start);
|
||||||
|
@ -311,6 +324,26 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
|
||||||
}
|
}
|
||||||
|
|
||||||
s->bytes_recvd += recv;
|
s->bytes_recvd += recv;
|
||||||
|
|
||||||
|
if (data_test) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (i = 0; i < msg.msg_iovlen; i++) {
|
||||||
|
unsigned char *d = iov[i].iov_base;
|
||||||
|
|
||||||
|
for (j = 0;
|
||||||
|
j < iov[i].iov_len && recv; j++) {
|
||||||
|
if (d[j] != k++) {
|
||||||
|
errno = -EIO;
|
||||||
|
fprintf(stderr,
|
||||||
|
"detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
|
||||||
|
i, j, d[j], k - 1, d[j+1], k + 1);
|
||||||
|
goto out_errno;
|
||||||
|
}
|
||||||
|
recv--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clock_gettime(CLOCK_MONOTONIC, &s->end);
|
clock_gettime(CLOCK_MONOTONIC, &s->end);
|
||||||
}
|
}
|
||||||
|
@ -338,8 +371,15 @@ static inline float recvdBps(struct msg_stats s)
|
||||||
return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
|
return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sockmap_options {
|
||||||
|
int verbose;
|
||||||
|
bool base;
|
||||||
|
bool sendpage;
|
||||||
|
bool data_test;
|
||||||
|
};
|
||||||
|
|
||||||
static int sendmsg_test(int iov_count, int iov_buf, int cnt,
|
static int sendmsg_test(int iov_count, int iov_buf, int cnt,
|
||||||
int verbose, bool base, bool sendpage)
|
struct sockmap_options *opt)
|
||||||
{
|
{
|
||||||
float sent_Bps = 0, recvd_Bps = 0;
|
float sent_Bps = 0, recvd_Bps = 0;
|
||||||
int rx_fd, txpid, rxpid, err = 0;
|
int rx_fd, txpid, rxpid, err = 0;
|
||||||
|
@ -348,16 +388,17 @@ static int sendmsg_test(int iov_count, int iov_buf, int cnt,
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
if (base)
|
if (opt->base)
|
||||||
rx_fd = p1;
|
rx_fd = p1;
|
||||||
else
|
else
|
||||||
rx_fd = p2;
|
rx_fd = p2;
|
||||||
|
|
||||||
rxpid = fork();
|
rxpid = fork();
|
||||||
if (rxpid == 0) {
|
if (rxpid == 0) {
|
||||||
if (sendpage)
|
if (opt->sendpage)
|
||||||
iov_count = 1;
|
iov_count = 1;
|
||||||
err = msg_loop(rx_fd, iov_count, iov_buf, cnt, &s, false);
|
err = msg_loop(rx_fd, iov_count, iov_buf,
|
||||||
|
cnt, &s, false, opt->data_test);
|
||||||
if (err)
|
if (err)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
|
"msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
|
||||||
|
@ -380,10 +421,11 @@ static int sendmsg_test(int iov_count, int iov_buf, int cnt,
|
||||||
|
|
||||||
txpid = fork();
|
txpid = fork();
|
||||||
if (txpid == 0) {
|
if (txpid == 0) {
|
||||||
if (sendpage)
|
if (opt->sendpage)
|
||||||
err = msg_loop_sendpage(c1, iov_buf, cnt, &s);
|
err = msg_loop_sendpage(c1, iov_buf, cnt, &s);
|
||||||
else
|
else
|
||||||
err = msg_loop(c1, iov_count, iov_buf, cnt, &s, true);
|
err = msg_loop(c1, iov_count, iov_buf,
|
||||||
|
cnt, &s, true, opt->data_test);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -409,7 +451,7 @@ static int sendmsg_test(int iov_count, int iov_buf, int cnt,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int forever_ping_pong(int rate, int verbose)
|
static int forever_ping_pong(int rate, struct sockmap_options *opt)
|
||||||
{
|
{
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
char buf[1024] = {0};
|
char buf[1024] = {0};
|
||||||
|
@ -474,7 +516,7 @@ static int forever_ping_pong(int rate, int verbose)
|
||||||
if (rate)
|
if (rate)
|
||||||
sleep(rate);
|
sleep(rate);
|
||||||
|
|
||||||
if (verbose) {
|
if (opt->verbose) {
|
||||||
printf(".");
|
printf(".");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
|
@ -494,13 +536,14 @@ enum {
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int iov_count = 1, length = 1024, rate = 1, verbose = 0, tx_prog_fd;
|
int iov_count = 1, length = 1024, rate = 1, tx_prog_fd;
|
||||||
struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
|
struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
|
||||||
int opt, longindex, err, cg_fd = 0;
|
int opt, longindex, err, cg_fd = 0;
|
||||||
|
struct sockmap_options options = {0};
|
||||||
int test = PING_PONG;
|
int test = PING_PONG;
|
||||||
char filename[256];
|
char filename[256];
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, ":hvc:r:i:l:t:",
|
while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:",
|
||||||
long_options, &longindex)) != -1) {
|
long_options, &longindex)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
/* Cgroup configuration */
|
/* Cgroup configuration */
|
||||||
|
@ -517,7 +560,7 @@ int main(int argc, char **argv)
|
||||||
rate = atoi(optarg);
|
rate = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = 1;
|
options.verbose = 1;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
iov_count = atoi(optarg);
|
iov_count = atoi(optarg);
|
||||||
|
@ -525,6 +568,9 @@ int main(int argc, char **argv)
|
||||||
case 'l':
|
case 'l':
|
||||||
length = atoi(optarg);
|
length = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
options.data_test = true;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (strcmp(optarg, "ping") == 0) {
|
if (strcmp(optarg, "ping") == 0) {
|
||||||
test = PING_PONG;
|
test = PING_PONG;
|
||||||
|
@ -655,20 +701,24 @@ run:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (test == PING_PONG)
|
if (test == PING_PONG)
|
||||||
err = forever_ping_pong(rate, verbose);
|
err = forever_ping_pong(rate, &options);
|
||||||
else if (test == SENDMSG)
|
else if (test == SENDMSG) {
|
||||||
err = sendmsg_test(iov_count, length, rate,
|
options.base = false;
|
||||||
verbose, false, false);
|
options.sendpage = false;
|
||||||
else if (test == SENDPAGE)
|
err = sendmsg_test(iov_count, length, rate, &options);
|
||||||
err = sendmsg_test(iov_count, length, rate,
|
} else if (test == SENDPAGE) {
|
||||||
verbose, false, true);
|
options.base = false;
|
||||||
else if (test == BASE)
|
options.sendpage = true;
|
||||||
err = sendmsg_test(iov_count, length, rate,
|
err = sendmsg_test(iov_count, length, rate, &options);
|
||||||
verbose, true, false);
|
} else if (test == BASE) {
|
||||||
else if (test == BASE_SENDPAGE)
|
options.base = true;
|
||||||
err = sendmsg_test(iov_count, length, rate,
|
options.sendpage = false;
|
||||||
verbose, true, true);
|
err = sendmsg_test(iov_count, length, rate, &options);
|
||||||
else
|
} else if (test == BASE_SENDPAGE) {
|
||||||
|
options.base = true;
|
||||||
|
options.sendpage = true;
|
||||||
|
err = sendmsg_test(iov_count, length, rate, &options);
|
||||||
|
} else
|
||||||
fprintf(stderr, "unknown test\n");
|
fprintf(stderr, "unknown test\n");
|
||||||
out:
|
out:
|
||||||
bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
|
bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
|
||||||
|
|
Loading…
Reference in New Issue