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