From: Magnus Karlsson <magnus.karls...@intel.com> This commit adds support for running the benchmark using a veth pair.
Signed-off-by: Magnus Karlsson <magnus.karls...@intel.com> --- samples/tpacket4/tpbench.c | 189 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 163 insertions(+), 26 deletions(-) diff --git a/samples/tpacket4/tpbench.c b/samples/tpacket4/tpbench.c index 46fb83009e06..2479f182d1b8 100644 --- a/samples/tpacket4/tpbench.c +++ b/samples/tpacket4/tpbench.c @@ -65,8 +65,18 @@ enum benchmark_type { static enum tpacket_version opt_tpver = PV4; static enum benchmark_type opt_bench = BENCH_RXDROP; static const char *opt_if = ""; +static int opt_veth; static int opt_zerocopy; +static const char *veth_if1 = "vm1"; +static const char *veth_if2 = "vm2"; + +/* For process synchronization */ +static int shmid; +volatile unsigned int *sync_var; +#define SLEEP_STEP 10 +#define MAX_SLEEP (1000000 / (SLEEP_STEP)) + struct tpacket2_queue { void *ring; @@ -296,13 +306,53 @@ static void process_swap_mac(void *queue_pair, unsigned int start, } } +static unsigned long get_nsecs(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000UL + ts.tv_nsec; +} + static void run_benchmark(const char *interface_name) { unsigned int start, end; struct tp2_queue_pair *qp; + if (opt_veth) { + shmid = shmget(14082017, sizeof(unsigned int), + IPC_CREAT | 666); + sync_var = shmat(shmid, 0, 0); + if (sync_var == (unsigned int *)-1) { + printf("You are probably not running as root\n"); + exit(EXIT_FAILURE); + } + *sync_var = 0; + + if (fork() == 0) { + opt_if = veth_if2; + interface_name = veth_if2; + } else { + unsigned int i; + + /* Wait for child */ + for (i = 0; *sync_var == 0 && i < MAX_SLEEP; i++) + usleep(SLEEP_STEP); + if (i >= MAX_SLEEP) { + printf("Wait for vm2 timed out. Exiting.\n"); + exit(EXIT_FAILURE); + } + } + } + qp = benchmark.configure(interface_name); + /* Notify parent that interface configuration completed */ + if (opt_veth && !strcmp(interface_name, "vm2")) + *sync_var = 1; + + start_time = get_nsecs(); + for (;;) { for (;;) { benchmark.rx(qp, &start, &end); @@ -320,14 +370,6 @@ static void run_benchmark(const char *interface_name) } } -static unsigned long get_nsecs(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000UL + ts.tv_nsec; -} - static void *tp2_configure(const char *interface_name) { int sfd, noqdisc, ret, ver = TPACKET_V2; @@ -386,6 +428,36 @@ static void *tp2_configure(const char *interface_name) ret = bind(sfd, (struct sockaddr *)&ll, sizeof(ll)); lassert(ret == 0); + if (opt_veth && !strcmp(interface_name, "vm1")) { + struct tpacket2_queue *txq = &tqp->tx; + int i; + + for (i = 0; i < opt_veth; i++) { + unsigned int idx = txq->last_used_idx & + (txq->ring_size - 1); + struct tpacket2_hdr *hdr; + unsigned int len; + + hdr = (struct tpacket2_hdr *)(txq->ring + + (idx << txq->frame_size_log2)); + len = gen_eth_frame((char *)hdr + TPACKET2_HDRLEN - + sizeof(struct sockaddr_ll), i + 1); + hdr->tp_snaplen = len; + hdr->tp_len = len; + + u_smp_wmb(); + + hdr->tp_status = TP_STATUS_SEND_REQUEST; + txq->last_used_idx++; + } + + ret = sendto(sfd, NULL, 0, MSG_DONTWAIT, NULL, 0); + if (!(ret >= 0 || errno == EAGAIN || errno == ENOBUFS)) + lassert(0); + + tx_npkts += opt_veth; + } + setup_tx_frame(); return tqp; @@ -556,6 +628,36 @@ static void *tp3_configure(const char *interface_name) ret = bind(sfd, (struct sockaddr *)&ll, sizeof(ll)); lassert(ret == 0); + if (opt_veth && !strcmp(interface_name, "vm1")) { + struct tpacket2_queue *txq = &tqp->tx; + int i; + + for (i = 0; i < opt_veth; i++) { + unsigned int idx = txq->last_used_idx & + (txq->ring_size - 1); + struct tpacket3_hdr *hdr; + unsigned int len; + + hdr = (struct tpacket3_hdr *)(txq->ring + + (idx << txq->frame_size_log2)); + len = gen_eth_frame((char *)hdr + TPACKET3_HDRLEN - + sizeof(struct sockaddr_ll), i + 1); + hdr->tp_snaplen = len; + hdr->tp_len = len; + + u_smp_wmb(); + + hdr->tp_status = TP_STATUS_SEND_REQUEST; + txq->last_used_idx++; + } + + ret = sendto(sfd, NULL, 0, MSG_DONTWAIT, NULL, 0); + if (!(ret >= 0 || errno == EAGAIN || errno == ENOBUFS)) + lassert(0); + + tx_npkts += opt_veth; + } + setup_tx_frame(); return tqp; @@ -783,6 +885,28 @@ static inline int tp4q_enqueue(struct tpacket4_queue *q, return 0; } +static inline void *tp4_get_data(void *queue_pair, unsigned int idx, + unsigned int *len) +{ + struct tp4_queue_pair *qp = (struct tp4_queue_pair *)queue_pair; + struct tp4_umem *umem = qp->umem; + struct tpacket4_desc *d; + + d = &qp->rx.ring[idx & qp->rx.ring_mask]; + *len = d->len; + + return (char *)umem->buffer + (d->idx << umem->frame_size_log2) + + d->offset; +} + +static inline void *tp4_get_buffer(void *queue_pair, unsigned int idx) +{ + struct tp4_queue_pair *qp = (struct tp4_queue_pair *)queue_pair; + struct tp4_umem *umem = qp->umem; + + return (char *)umem->buffer + (idx << umem->frame_size_log2); +} + static void *tp4_configure(const char *interface_name) { int sfd, noqdisc, ret, ver = TPACKET_V4; @@ -848,7 +972,27 @@ static void *tp4_configure(const char *interface_name) lassert(ret == 0); } - for (i = 0; i < (tqp->rx.ring_mask + 1)/4; i++) { + if (opt_veth >= (tqp->rx.ring_mask + 1)/4) { + printf("Veth batch size too large.\n"); + exit(EXIT_FAILURE); + } + + if (opt_veth && !strcmp(interface_name, "vm1")) { + for (i = 0; i < opt_veth; i++) { + struct tpacket4_desc desc = {.idx = i}; + unsigned int len; + + len = gen_eth_frame(tp4_get_buffer(tqp, i), i + 1); + + desc.len = len; + ret = tp4q_enqueue(&tqp->tx, &desc, 1); + lassert(ret == 0); + } + ret = sendto(sfd, NULL, 0, MSG_DONTWAIT, NULL, 0); + lassert(ret != -1); + } + + for (i = opt_veth; i < (tqp->rx.ring_mask + 1)/4; i++) { struct tpacket4_desc desc = {}; desc.idx = i; @@ -902,21 +1046,6 @@ static inline void tp4_rx_release(void *queue_pair, unsigned int start, q->num_free = 0; } -static inline void *tp4_get_data(void *queue_pair, unsigned int idx, - unsigned int *len) -{ - struct tp4_queue_pair *qp = (struct tp4_queue_pair *)queue_pair; - struct tp4_umem *umem = qp->umem; - struct tpacket4_desc *d; - - d = &qp->rx.ring[idx & qp->rx.ring_mask]; - *len = d->len; - - return (char *)umem->buffer + (d->idx << umem->frame_size_log2) - + d->offset; -} - - static inline unsigned long tp4_get_data_desc(void *queue_pair, unsigned int idx, unsigned int *len, @@ -1126,6 +1255,7 @@ static struct option long_options[] = { {"l2fwd", no_argument, 0, 'l'}, {"zerocopy", required_argument, 0, 'z'}, {"interface", required_argument, 0, 'i'}, + {"veth", required_argument, 0, 'e'}, {0, 0, 0, 0} }; @@ -1152,7 +1282,7 @@ static void parse_command_line(int argc, char **argv) opterr = 0; for (;;) { - c = getopt_long(argc, argv, "v:rtlz:i:", long_options, + c = getopt_long(argc, argv, "v:rtlz:i:e:", long_options, &option_index); if (c == -1) break; @@ -1182,6 +1312,9 @@ static void parse_command_line(int argc, char **argv) case 'i': opt_if = optarg; break; + case 'e': + opt_veth = atoi(optarg); + break; default: usage(); } @@ -1192,6 +1325,11 @@ static void parse_command_line(int argc, char **argv) usage(); } + if (opt_veth) { + opt_bench = BENCH_L2FWD; + opt_if = veth_if1; + } + ret = if_nametoindex(opt_if); if (!ret) { fprintf(stderr, "ERROR: interface \"%s\" does not exist\n", @@ -1246,7 +1384,6 @@ int main(int argc, char **argv) parse_command_line(argc, argv); print_benchmark(true); benchmark = *get_benchmark(opt_tpver, opt_bench); - start_time = get_nsecs(); run_benchmark(opt_if); return 0; -- 2.11.0