Merge branch 'master' of ssh://github.com/openvswitch/ovs into master_new
[cascardo/ovs.git] / utilities / ovs-benchmark.c
1 /*
2  * Copyright (c) 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include <errno.h>
20 #include <getopt.h>
21 #include <limits.h>
22 #include <poll.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <stddef.h>
27 #include <unistd.h>
28
29 #include "command-line.h"
30 #include "poll-loop.h"
31 #include "socket-util.h"
32 #include "timeval.h"
33 #include "util.h"
34 #include "openvswitch/vlog.h"
35
36 #define DEFAULT_PORT 6630
37
38 #define MAX_SOCKETS 65535
39 static int n_batches = 1;
40 static int n_sockets = 100;
41
42 static struct in_addr local_addr;
43 static unsigned short int local_min_port, local_max_port;
44
45 static struct in_addr remote_addr;
46 static unsigned short int remote_min_port, remote_max_port;
47
48 static double max_rate;
49
50 static double timeout;
51
52 static const struct ovs_cmdl_command *get_all_commands(void);
53
54 static void parse_options(int argc, char *argv[]);
55 static void usage(void);
56
57 static int
58 do_poll(struct pollfd *fds, int nfds, int timeout)
59 {
60     int retval;
61 #ifndef _WIN32
62     do {
63         retval = poll(fds, nfds, timeout);
64     } while (retval < 0 && errno == EINTR);
65 #else
66     retval = WSAPoll(fds, nfds, timeout);
67 #endif
68     return retval;
69 }
70
71 static long long int
72 time_in_msec(void)
73 {
74     struct timeval tv;
75
76     xgettimeofday(&tv);
77
78     return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
79 }
80
81 int
82 main(int argc, char *argv[])
83 {
84     struct ovs_cmdl_context ctx = { .argc = 0, };
85     set_program_name(argv[0]);
86     vlog_set_levels(NULL, VLF_ANY_DESTINATION, VLL_EMER);
87     parse_options(argc, argv);
88     ctx.argc = argc - optind;
89     ctx.argv = argv + optind;
90     ovs_cmdl_run_command(&ctx, get_all_commands());
91     return 0;
92 }
93
94 static void
95 parse_target(const char *s_, struct in_addr *addr,
96              unsigned short int *min, unsigned short int *max)
97 {
98     char *s = xstrdup(s_);
99     char *colon;
100     int error;
101
102     colon = strchr(s, ':');
103     if (colon) {
104         *colon = '\0';
105     }
106
107     if (*s != '\0') {
108         error = lookup_hostname(s, addr);
109         if (error) {
110             ovs_fatal(error, "failed to look up IP address for \"%s\"", s_);
111         }
112     } else {
113         addr->s_addr = htonl(INADDR_ANY);
114     }
115
116     *min = *max = 0;
117     if (colon && colon[1] != '\0') {
118         const char *ports = colon + 1;
119         if (ovs_scan(ports, "%hu-%hu", min, max)) {
120             if (*min > *max) {
121                 ovs_fatal(0, "%s: minimum is greater than maximum", s_);
122             }
123         } else if (ovs_scan(ports, "%hu", min)) {
124             *max = *min;
125         } else {
126             ovs_fatal(0, "%s: number or range expected", s_);
127         }
128     }
129
130     free(s);
131 }
132
133 static void
134 parse_options(int argc, char *argv[])
135 {
136     static const struct option long_options[] = {
137         {"local", required_argument, NULL, 'l'},
138         {"remote", required_argument, NULL, 'r'},
139         {"batches", required_argument, NULL, 'b'},
140         {"sockets", required_argument, NULL, 's'},
141         {"max-rate", required_argument, NULL, 'c'},
142         {"timeout", required_argument, NULL, 'T'},
143         {"help", no_argument, NULL, 'h'},
144         {"version", no_argument, NULL, 'V'},
145         {NULL, 0, NULL, 0},
146     };
147     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
148
149     local_addr.s_addr = htonl(INADDR_ANY);
150     local_min_port = local_max_port = 0;
151
152     remote_addr.s_addr = htonl(0);
153     remote_min_port = remote_max_port = 0;
154
155     for (;;) {
156         int c;
157
158         c = getopt_long(argc, argv, short_options, long_options, NULL);
159         if (c == -1) {
160             break;
161         }
162
163         switch (c) {
164         case 'l':
165             parse_target(optarg,
166                          &local_addr, &local_min_port, &local_max_port);
167             break;
168
169         case 'r':
170             parse_target(optarg,
171                          &remote_addr, &remote_min_port, &remote_max_port);
172             if (remote_addr.s_addr == htonl(INADDR_ANY)) {
173                 ovs_fatal(0, "remote IP address is required");
174             }
175             break;
176
177         case 'b':
178             n_batches = atoi(optarg);
179             if (n_batches < 0) {
180                 ovs_fatal(0, "--batches or -b argument must be at least 1");
181             }
182             break;
183
184         case 's':
185             n_sockets = atoi(optarg);
186             if (n_sockets < 1 || n_sockets > MAX_SOCKETS) {
187                 ovs_fatal(0, "--sockets or -s argument must be between 1 "
188                           "and %d (inclusive)", MAX_SOCKETS);
189             }
190             break;
191
192         case 'c':
193             max_rate = atof(optarg);
194             if (max_rate <= 0.0) {
195                 ovs_fatal(0, "--max-rate or -c argument must be positive");
196             }
197             break;
198
199         case 'T':
200             timeout = atoi(optarg);
201             if (!timeout) {
202                 ovs_fatal(0, "-T or --timeout argument must be positive");
203             }
204             break;
205
206         case 'h':
207             usage();
208
209         case 'V':
210             ovs_print_version(0, 0);
211             exit(EXIT_SUCCESS);
212
213         case '?':
214             exit(EXIT_FAILURE);
215
216         default:
217             abort();
218         }
219     }
220     free(short_options);
221 }
222
223 static void
224 usage(void)
225 {
226     printf("\
227 %s: Open vSwitch flow setup benchmark utility\n\
228 usage: %s [OPTIONS] COMMAND [ARG...]\n\
229   latency                     connect many times all at once\n\
230   rate                        measure sustained flow setup rate\n\
231   listen                      accept TCP connections\n\
232   help                        display this help message\n\
233 \n\
234 Command options:\n\
235   -l, --local [IP][:PORTS]    use local IP and range of PORTS\n\
236   -r, --remote IP[:PORTS]     connect to remote IP and PORTS\n\
237   -s, --sockets N             number of sockets for \"rate\" or \"latency\"\n\
238   -b, --batches N             number of connection batches for \"latency\"\n\
239   -c, --max-rate NPERSEC      connection rate limit for \"rate\"\n\
240   -T, --timeout MAXSECS       max number of seconds to run for \"rate\"\n\
241 \n\
242 Other options:\n\
243   -h, --help                  display this help message\n\
244   -V, --version               display version information\n",
245            program_name, program_name);
246     exit(EXIT_SUCCESS);
247 }
248
249 static void
250 cmd_listen(struct ovs_cmdl_context *ctx OVS_UNUSED)
251 {
252     struct pollfd *fds;
253     int n_fds;
254     int port;
255     int i;
256
257     if (!local_min_port && !local_max_port) {
258         local_min_port = local_max_port = DEFAULT_PORT;
259     }
260     fds = xmalloc((1 + local_max_port - local_min_port) * sizeof *fds);
261     n_fds = 0;
262     for (port = local_min_port; port <= local_max_port; port++) {
263         struct sockaddr_in sin;
264         unsigned int yes = 1;
265         int error;
266         int fd;
267
268         /* Create socket, set SO_REUSEADDR. */
269         fd = socket(AF_INET, SOCK_STREAM, 0);
270         if (fd < 0) {
271             ovs_fatal(errno, "failed to create socket");
272         }
273         error = set_nonblocking(fd);
274         if (error) {
275             ovs_fatal(error, "failed to set non-blocking mode");
276         }
277         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
278             ovs_fatal(errno, "setsockopt(SO_REUSEADDR) failed");
279         }
280
281         /* Bind. */
282         sin.sin_family = AF_INET;
283         sin.sin_addr = remote_addr;
284         sin.sin_port = htons(port);
285         if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
286             ovs_fatal(errno, "bind failed");
287         }
288
289         /* Listen. */
290         if (listen(fd, 10000) < 0) {
291             ovs_fatal(errno, "listen failed");
292         }
293
294         fds[n_fds].fd = fd;
295         fds[n_fds].events = POLLIN;
296         n_fds++;
297     }
298
299     for (;;) {
300         int retval;
301
302         retval = do_poll(fds, n_fds, -1);
303         if (retval < 0) {
304             ovs_fatal(errno, "poll failed");
305         }
306
307         for (i = 0; i < n_fds; i++) {
308             if (fds[i].revents & POLLIN) {
309                 int newfd;
310
311                 do {
312                     newfd = accept(fds[i].fd, NULL, NULL);
313                 } while (newfd < 0 && errno == EINTR);
314
315                 if (newfd >= 0) {
316                     close(newfd);
317                 } else if (errno != EAGAIN) {
318                     ovs_fatal(errno, "accept failed");
319                 }
320             }
321         }
322     }
323 }
324
325 /* Increments '*value' within the range 'min...max' inclusive.  Returns true
326  * if '*value' wraps around to 'min', otherwise false. */
327 static bool
328 increment(unsigned short int *value,
329           unsigned short int min, unsigned short int max)
330 {
331     if (*value < max) {
332         ++*value;
333         return false;
334     } else {
335         *value = min;
336         return true;
337     }
338 }
339
340 static void
341 next_ports(unsigned short int *local_port, unsigned short int *remote_port)
342 {
343     if (increment(local_port, local_min_port, local_max_port)) {
344         increment(remote_port, remote_min_port, remote_max_port);
345     }
346 }
347
348 static void
349 bind_local_port(int fd, unsigned short int *local_port,
350                 unsigned short int *remote_port)
351 {
352     int error;
353
354     if (!local_min_port && !local_max_port) {
355         next_ports(local_port, remote_port);
356         return;
357     }
358
359     do {
360         struct sockaddr_in local;
361
362         memset(&local, 0, sizeof local);
363         local.sin_family = AF_INET;
364         local.sin_addr = local_addr;
365         local.sin_port = htons(*local_port);
366         error = (bind(fd, (struct sockaddr *) &local, sizeof local) < 0
367                  ? errno : 0);
368         next_ports(local_port, remote_port);
369     } while (error == EADDRINUSE || error == EINTR);
370     if (error) {
371         ovs_fatal(error, "bind failed");
372     }
373 }
374
375 static void
376 cmd_rate(struct ovs_cmdl_context *ctx OVS_UNUSED)
377 {
378     unsigned short int local_port;
379     unsigned short int remote_port;
380     unsigned int completed = 0;
381     unsigned int failures = 0;
382     long long int start, prev;
383     struct pollfd *fds;
384     int n_fds;
385
386     if (!remote_addr.s_addr) {
387         ovs_fatal(0, "remote address must be specified with -r or --remote");
388     }
389     if (!remote_min_port && !remote_max_port) {
390         remote_min_port = remote_max_port = DEFAULT_PORT;
391     }
392
393     local_port = local_min_port;
394     remote_port = remote_min_port;
395     fds = xmalloc(n_sockets * sizeof *fds);
396     n_fds = 0;
397     start = prev = time_in_msec();
398     for (;;) {
399         long long int now;
400         long long int may_open;
401         int delay;
402         int error;
403         int j;
404
405         if (max_rate > 0) {
406             long long int cur_total = completed + n_fds;
407             long long int max_total = (time_in_msec() - start) * (max_rate / 1000.0);
408             if (max_total > cur_total) {
409                 may_open = MIN(n_sockets, max_total - cur_total);
410             } else {
411                 may_open = 0;
412             }
413             delay = 1000.0 / max_rate;
414         } else {
415             may_open = n_sockets;
416             delay = 1000;
417         }
418
419         while (may_open-- > 0 && n_fds < n_sockets) {
420             struct sockaddr_in remote;
421             int error;
422             int fd;
423
424             fd = socket(AF_INET, SOCK_STREAM, 0);
425             if (fd < 0) {
426                 ovs_fatal(errno, "socket failed");
427             }
428
429             error = set_nonblocking(fd);
430             if (error) {
431                 ovs_fatal(error, "set_nonblocking failed");
432             }
433
434             bind_local_port(fd, &local_port, &remote_port);
435
436             memset(&remote, 0, sizeof remote);
437             remote.sin_family = AF_INET;
438             remote.sin_addr = remote_addr;
439             remote.sin_port = htons(remote_port);
440             if (connect(fd, (struct sockaddr *) &remote, sizeof remote) < 0) {
441                 if (errno == EINPROGRESS) {
442                     fds[n_fds].fd = fd;
443                     fds[n_fds].events = POLLOUT;
444                     fds[n_fds].revents = 0;
445                     n_fds++;
446                 } else if (errno != ECONNREFUSED) {
447                     ovs_fatal(errno, "connect");
448                 }
449             } else {
450                 /* Success, I guess. */
451                 shutdown(fd, 2);
452                 close(fd);
453                 completed++;
454             }
455         }
456
457         if (n_fds == n_sockets) {
458             delay = 1000;
459         }
460
461         error = do_poll(fds, n_fds, delay);
462         if (error) {
463             ovs_fatal(errno, "poll");
464         }
465
466         for (j = 0; j < n_fds; ) {
467             if (fds[j].revents) {
468                 if (fds[j].revents & POLLERR) {
469                     failures++;
470                 }
471                 shutdown(fds[j].fd, 2);
472                 close(fds[j].fd);
473                 fds[j] = fds[--n_fds];
474                 completed++;
475             } else {
476                 j++;
477             }
478         }
479
480         now = time_in_msec();
481         if (now >= prev + 1000) {
482             long long int elapsed = now - start;
483             printf("%.3f s elapsed, %u OK, %u failed, avg %.1f/s\n",
484                    elapsed / 1000.0, completed - failures, failures,
485                    completed / (elapsed / 1000.0));
486             fflush(stdout);
487             prev = now;
488
489             if (timeout && elapsed > timeout * 1000LL) {
490                 break;
491             }
492         }
493     }
494     free(fds);
495 }
496
497 static void
498 timer_end(long long int start, bool error,
499           int *min, int *max, unsigned long long int *total)
500 {
501     int elapsed = time_in_msec() - start;
502     static int last_elapsed = INT_MIN;
503     char c = error ? '!' : '.';
504
505     if (last_elapsed != elapsed) {
506         if (last_elapsed != INT_MIN) {
507             putchar('\n');
508         }
509         printf("%5d %c", elapsed, c);
510         fflush(stdout);
511         last_elapsed = elapsed;
512     } else {
513         putchar(c);
514         fflush(stdout);
515     }
516
517     if (elapsed < *min) {
518         *min = elapsed;
519     }
520     if (elapsed > *max) {
521         *max = elapsed;
522     }
523     *total += elapsed;
524 }
525
526 static void
527 cmd_latency(struct ovs_cmdl_context *ctx OVS_UNUSED)
528 {
529     unsigned short int local_port;
530     unsigned short int remote_port;
531     int min = INT_MAX;
532     int max = 0;
533     unsigned long long int total = 0;
534     int i;
535
536     if (!remote_addr.s_addr) {
537         ovs_fatal(0, "remote address must be specified with -r or --rate");
538     }
539     if (!remote_min_port && !remote_max_port) {
540         remote_min_port = remote_max_port = DEFAULT_PORT;
541     }
542
543     local_port = local_min_port;
544     remote_port = remote_min_port;
545     for (i = 0; i < n_batches; i++) {
546         struct pollfd fds[MAX_SOCKETS];
547         long long int start;
548         int n_fds;
549         int j;
550
551         start = time_in_msec();
552         n_fds = 0;
553         for (j = 0; j < n_sockets; j++) {
554             struct sockaddr_in remote;
555             int error;
556             int fd;
557
558             fd = socket(AF_INET, SOCK_STREAM, 0);
559             if (fd < 0) {
560                 ovs_fatal(errno, "socket failed");
561             }
562
563             error = set_nonblocking(fd);
564             if (error) {
565                 ovs_fatal(error, "set_nonblocking failed");
566             }
567
568             bind_local_port(fd, &local_port, &remote_port);
569
570             memset(&remote, 0, sizeof remote);
571             remote.sin_family = AF_INET;
572             remote.sin_addr = remote_addr;
573             remote.sin_port = htons(remote_port);
574             if (connect(fd, (struct sockaddr *) &remote, sizeof remote) < 0) {
575                 if (errno == EINPROGRESS) {
576                     fds[n_fds].fd = fd;
577                     fds[n_fds].events = POLLOUT;
578                     fds[n_fds].revents = 0;
579                     n_fds++;
580                 } else if (errno != ECONNREFUSED) {
581                     ovs_fatal(errno, "connect");
582                 }
583             } else {
584                 /* Success, I guess. */
585                 close(fd);
586                 timer_end(start, 0, &min, &max, &total);
587             }
588         }
589
590         while (n_fds > 0) {
591             int error;
592
593             error = do_poll(fds, n_fds, -1);
594             if (error) {
595                 ovs_fatal(errno, "poll");
596             }
597
598             for (j = 0; j < n_fds; ) {
599                 if (fds[j].revents) {
600                     timer_end(start,
601                               fds[j].revents & (POLLERR|POLLHUP) ? 1 : 0,
602                               &min, &max, &total);
603                     close(fds[j].fd);
604                     fds[j] = fds[--n_fds];
605                 } else {
606                     j++;
607                 }
608             }
609         }
610         putchar('\n');
611     }
612
613     printf("min %d ms, max %d ms, avg %llu ms\n",
614            min, max, total / (1ULL * n_sockets * n_batches));
615 }
616
617 static void
618 cmd_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
619 {
620     usage();
621 }
622
623 static const struct ovs_cmdl_command all_commands[] = {
624     { "listen", NULL, 0, 0, cmd_listen },
625     { "rate", NULL, 0, 0, cmd_rate },
626     { "latency", NULL, 0, 0, cmd_latency },
627     { "help", NULL, 0, 0, cmd_help },
628     { NULL, NULL, 0, 0, NULL },
629 };
630
631 static const struct ovs_cmdl_command *get_all_commands(void)
632 {
633   return all_commands;
634 }