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

Reply via email to