423ce1955869d2fbb0064118d6c93970302013a7
[cascardo/ovs.git] / utilities / ovs-controller.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <errno.h>
20 #include <getopt.h>
21 #include <limits.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "command-line.h"
27 #include "compiler.h"
28 #include "daemon.h"
29 #include "fault.h"
30 #include "learning-switch.h"
31 #include "ofpbuf.h"
32 #include "openflow/openflow.h"
33 #include "poll-loop.h"
34 #include "rconn.h"
35 #include "timeval.h"
36 #include "unixctl.h"
37 #include "util.h"
38 #include "vconn-ssl.h"
39 #include "vconn.h"
40
41 #include "vlog.h"
42 #define THIS_MODULE VLM_controller
43
44 #define MAX_SWITCHES 16
45 #define MAX_LISTENERS 16
46
47 struct switch_ {
48     struct lswitch *lswitch;
49     struct rconn *rconn;
50 };
51
52 /* Learn the ports on which MAC addresses appear? */
53 static bool learn_macs = true;
54
55 /* Set up flows?  (If not, every packet is processed at the controller.) */
56 static bool setup_flows = true;
57
58 /* --max-idle: Maximum idle time, in seconds, before flows expire. */
59 static int max_idle = 60;
60
61 static int do_switching(struct switch_ *);
62 static void new_switch(struct switch_ *, struct vconn *, const char *name);
63 static void parse_options(int argc, char *argv[]);
64 static void usage(void) NO_RETURN;
65
66 int
67 main(int argc, char *argv[])
68 {
69     struct unixctl_server *unixctl;
70     struct switch_ switches[MAX_SWITCHES];
71     struct pvconn *listeners[MAX_LISTENERS];
72     int n_switches, n_listeners;
73     int retval;
74     int i;
75
76     set_program_name(argv[0]);
77     register_fault_handlers();
78     time_init();
79     vlog_init();
80     parse_options(argc, argv);
81     signal(SIGPIPE, SIG_IGN);
82
83     if (argc - optind < 1) {
84         ovs_fatal(0, "at least one vconn argument required; "
85                   "use --help for usage");
86     }
87
88     n_switches = n_listeners = 0;
89     for (i = optind; i < argc; i++) {
90         const char *name = argv[i];
91         struct vconn *vconn;
92         int retval;
93
94         retval = vconn_open(name, OFP_VERSION, &vconn);
95         if (!retval) {
96             if (n_switches >= MAX_SWITCHES) {
97                 ovs_fatal(0, "max %d switch connections", n_switches);
98             }
99             new_switch(&switches[n_switches++], vconn, name);
100             continue;
101         } else if (retval == EAFNOSUPPORT) {
102             struct pvconn *pvconn;
103             retval = pvconn_open(name, &pvconn);
104             if (!retval) {
105                 if (n_listeners >= MAX_LISTENERS) {
106                     ovs_fatal(0, "max %d passive connections", n_listeners);
107                 }
108                 listeners[n_listeners++] = pvconn;
109             }
110         }
111         if (retval) {
112             VLOG_ERR("%s: connect: %s", name, strerror(retval));
113         }
114     }
115     if (n_switches == 0 && n_listeners == 0) {
116         ovs_fatal(0, "no active or passive switch connections");
117     }
118
119     die_if_already_running();
120     daemonize();
121
122     retval = unixctl_server_create(NULL, &unixctl);
123     if (retval) {
124         ovs_fatal(retval, "Could not listen for unixctl connections");
125     }
126
127     while (n_switches > 0 || n_listeners > 0) {
128         int iteration;
129         int i;
130
131         /* Accept connections on listening vconns. */
132         for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) {
133             struct vconn *new_vconn;
134             int retval;
135
136             retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn);
137             if (!retval || retval == EAGAIN) {
138                 if (!retval) {
139                     new_switch(&switches[n_switches++], new_vconn, "tcp");
140                 }
141                 i++;
142             } else {
143                 pvconn_close(listeners[i]);
144                 listeners[i] = listeners[--n_listeners];
145             }
146         }
147
148         /* Do some switching work.  Limit the number of iterations so that
149          * callbacks registered with the poll loop don't starve. */
150         for (iteration = 0; iteration < 50; iteration++) {
151             bool progress = false;
152             for (i = 0; i < n_switches; ) {
153                 struct switch_ *this = &switches[i];
154                 int retval = do_switching(this);
155                 if (!retval || retval == EAGAIN) {
156                     if (!retval) {
157                         progress = true;
158                     }
159                     i++;
160                 } else {
161                     rconn_destroy(this->rconn);
162                     lswitch_destroy(this->lswitch);
163                     switches[i] = switches[--n_switches];
164                 }
165             }
166             if (!progress) {
167                 break;
168             }
169         }
170         for (i = 0; i < n_switches; i++) {
171             struct switch_ *this = &switches[i];
172             lswitch_run(this->lswitch, this->rconn);
173         }
174
175         unixctl_server_run(unixctl);
176
177         /* Wait for something to happen. */
178         if (n_switches < MAX_SWITCHES) {
179             for (i = 0; i < n_listeners; i++) {
180                 pvconn_wait(listeners[i]);
181             }
182         }
183         for (i = 0; i < n_switches; i++) {
184             struct switch_ *sw = &switches[i];
185             rconn_run_wait(sw->rconn);
186             rconn_recv_wait(sw->rconn);
187             lswitch_wait(sw->lswitch);
188         }
189         unixctl_server_wait(unixctl);
190         poll_block();
191     }
192
193     return 0;
194 }
195
196 static void
197 new_switch(struct switch_ *sw, struct vconn *vconn, const char *name)
198 {
199     sw->rconn = rconn_new_from_vconn(name, vconn);
200     sw->lswitch = lswitch_create(sw->rconn, learn_macs,
201                                  setup_flows ? max_idle : -1);
202 }
203
204 static int
205 do_switching(struct switch_ *sw)
206 {
207     unsigned int packets_sent;
208     struct ofpbuf *msg;
209
210     packets_sent = rconn_packets_sent(sw->rconn);
211
212     msg = rconn_recv(sw->rconn);
213     if (msg) {
214         lswitch_process_packet(sw->lswitch, sw->rconn, msg);
215         ofpbuf_delete(msg);
216     }
217     rconn_run(sw->rconn);
218
219     return (!rconn_is_alive(sw->rconn) ? EOF
220             : rconn_packets_sent(sw->rconn) != packets_sent ? 0
221             : EAGAIN);
222 }
223
224 static void
225 parse_options(int argc, char *argv[])
226 {
227     enum {
228         OPT_MAX_IDLE = UCHAR_MAX + 1,
229         OPT_PEER_CA_CERT,
230         VLOG_OPTION_ENUMS
231     };
232     static struct option long_options[] = {
233         {"hub",         no_argument, 0, 'H'},
234         {"noflow",      no_argument, 0, 'n'},
235         {"max-idle",    required_argument, 0, OPT_MAX_IDLE},
236         {"help",        no_argument, 0, 'h'},
237         {"version",     no_argument, 0, 'V'},
238         DAEMON_LONG_OPTIONS,
239         VLOG_LONG_OPTIONS,
240 #ifdef HAVE_OPENSSL
241         VCONN_SSL_LONG_OPTIONS
242         {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
243 #endif
244         {0, 0, 0, 0},
245     };
246     char *short_options = long_options_to_short_options(long_options);
247
248     for (;;) {
249         int indexptr;
250         int c;
251
252         c = getopt_long(argc, argv, short_options, long_options, &indexptr);
253         if (c == -1) {
254             break;
255         }
256
257         switch (c) {
258         case 'H':
259             learn_macs = false;
260             break;
261
262         case 'n':
263             setup_flows = false;
264             break;
265
266         case OPT_MAX_IDLE:
267             if (!strcmp(optarg, "permanent")) {
268                 max_idle = OFP_FLOW_PERMANENT;
269             } else {
270                 max_idle = atoi(optarg);
271                 if (max_idle < 1 || max_idle > 65535) {
272                     ovs_fatal(0, "--max-idle argument must be between 1 and "
273                               "65535 or the word 'permanent'");
274                 }
275             }
276             break;
277
278         case 'h':
279             usage();
280
281         case 'V':
282             OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION);
283             exit(EXIT_SUCCESS);
284
285         VLOG_OPTION_HANDLERS
286         DAEMON_OPTION_HANDLERS
287
288 #ifdef HAVE_OPENSSL
289         VCONN_SSL_OPTION_HANDLERS
290
291         case OPT_PEER_CA_CERT:
292             vconn_ssl_set_peer_ca_cert_file(optarg);
293             break;
294 #endif
295
296         case '?':
297             exit(EXIT_FAILURE);
298
299         default:
300             abort();
301         }
302     }
303     free(short_options);
304 }
305
306 static void
307 usage(void)
308 {
309     printf("%s: OpenFlow controller\n"
310            "usage: %s [OPTIONS] METHOD\n"
311            "where METHOD is any OpenFlow connection method.\n",
312            program_name, program_name);
313     vconn_usage(true, true, false);
314     daemon_usage();
315     vlog_usage();
316     printf("\nOther options:\n"
317            "  -H, --hub               act as hub instead of learning switch\n"
318            "  -n, --noflow            pass traffic, but don't add flows\n"
319            "  --max-idle=SECS         max idle time for new flows\n"
320            "  -h, --help              display this help message\n"
321            "  -V, --version           display version information\n");
322     exit(EXIT_SUCCESS);
323 }