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