9908f8d0309a3cb51fd78d211bfea867ed19ed77
[cascardo/ovs.git] / ovn / controller-vtep / ovn-controller-vtep.c
1 /* Copyright (c) 2015 Nicira, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <config.h>
17
18 #include <errno.h>
19 #include <getopt.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "command-line.h"
25 #include "compiler.h"
26 #include "daemon.h"
27 #include "dirs.h"
28 #include "dynamic-string.h"
29 #include "fatal-signal.h"
30 #include "poll-loop.h"
31 #include "stream.h"
32 #include "stream-ssl.h"
33 #include "unixctl.h"
34 #include "util.h"
35 #include "openvswitch/vconn.h"
36 #include "openvswitch/vlog.h"
37 #include "ovn/lib/ovn-sb-idl.h"
38 #include "vtep/vtep-idl.h"
39
40 #include "binding.h"
41 #include "gateway.h"
42 #include "vtep.h"
43 #include "ovn-controller-vtep.h"
44
45 static unixctl_cb_func ovn_controller_vtep_exit;
46
47 static void parse_options(int argc, char *argv[]);
48 OVS_NO_RETURN static void usage(void);
49
50 static char *vtep_remote;
51 static char *ovnsb_remote;
52 static char *default_db_;
53
54 int
55 main(int argc, char *argv[])
56 {
57     struct unixctl_server *unixctl;
58     bool exiting;
59     int retval;
60
61     ovs_cmdl_proctitle_init(argc, argv);
62     set_program_name(argv[0]);
63     service_start(&argc, &argv);
64     parse_options(argc, argv);
65     fatal_ignore_sigpipe();
66
67     daemonize_start();
68
69     retval = unixctl_server_create(NULL, &unixctl);
70     if (retval) {
71         exit(EXIT_FAILURE);
72     }
73     unixctl_command_register("exit", "", 0, 0, ovn_controller_vtep_exit,
74                              &exiting);
75
76     daemonize_complete();
77
78     vteprec_init();
79     sbrec_init();
80
81     /* Connect to VTEP database. */
82     struct ovsdb_idl_loop vtep_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
83         ovsdb_idl_create(vtep_remote, &vteprec_idl_class, true, true));
84     ovsdb_idl_get_initial_snapshot(vtep_idl_loop.idl);
85
86     /* Connect to OVN SB database. */
87     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
88         ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
89     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
90
91     /* Main loop. */
92     exiting = false;
93     while (!exiting) {
94         struct controller_vtep_ctx ctx = {
95             .vtep_idl = vtep_idl_loop.idl,
96             .vtep_idl_txn = ovsdb_idl_loop_run(&vtep_idl_loop),
97             .ovnsb_idl = ovnsb_idl_loop.idl,
98             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
99         };
100
101         gateway_run(&ctx);
102         binding_run(&ctx);
103         vtep_run(&ctx);
104         unixctl_server_run(unixctl);
105
106         unixctl_server_wait(unixctl);
107         if (exiting) {
108             poll_immediate_wake();
109         }
110         ovsdb_idl_loop_commit_and_wait(&vtep_idl_loop);
111         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
112         poll_block();
113         if (should_service_stop()) {
114             exiting = true;
115         }
116     }
117
118     /* It's time to exit.  Clean up the databases. */
119     bool done = false;
120     while (!done) {
121         struct controller_vtep_ctx ctx = {
122             .vtep_idl = vtep_idl_loop.idl,
123             .vtep_idl_txn = ovsdb_idl_loop_run(&vtep_idl_loop),
124             .ovnsb_idl = ovnsb_idl_loop.idl,
125             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
126         };
127
128         /* Run all of the cleanup functions, even if one of them returns false.
129          * We're done if all of them return true. */
130         done = binding_cleanup(&ctx);
131         done = gateway_cleanup(&ctx) && done;
132         done = vtep_cleanup(&ctx) && done;
133         if (done) {
134             poll_immediate_wake();
135         }
136
137         ovsdb_idl_loop_commit_and_wait(&vtep_idl_loop);
138         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
139         poll_block();
140     }
141
142     unixctl_server_destroy(unixctl);
143
144     ovsdb_idl_loop_destroy(&vtep_idl_loop);
145     ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
146
147     free(ovnsb_remote);
148     free(vtep_remote);
149     free(default_db_);
150     service_stop();
151
152     exit(retval);
153 }
154
155 static const char *
156 default_db(void)
157 {
158     if (!default_db_) {
159         default_db_ = xasprintf("unix:%s/db.sock", ovs_rundir());
160     }
161     return default_db_;
162 }
163
164 static void
165 parse_options(int argc, char *argv[])
166 {
167     enum {
168         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
169         OPT_BOOTSTRAP_CA_CERT,
170         VLOG_OPTION_ENUMS,
171         DAEMON_OPTION_ENUMS
172     };
173
174     static struct option long_options[] = {
175         {"ovnsb-db", required_argument, NULL, 'd'},
176         {"vtep-db", required_argument, NULL, 'D'},
177         {"help", no_argument, NULL, 'h'},
178         {"version", no_argument, NULL, 'V'},
179         VLOG_LONG_OPTIONS,
180         DAEMON_LONG_OPTIONS,
181         STREAM_SSL_LONG_OPTIONS,
182         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
183         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
184         {NULL, 0, NULL, 0}
185     };
186     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
187
188     for (;;) {
189         int c;
190
191         c = getopt_long(argc, argv, short_options, long_options, NULL);
192         if (c == -1) {
193             break;
194         }
195
196         switch (c) {
197         case 'd':
198             ovnsb_remote = xstrdup(optarg);
199             break;
200
201         case 'D':
202             vtep_remote = xstrdup(optarg);
203             break;
204
205         case 'h':
206             usage();
207
208         case 'V':
209             ovs_print_version(OFP13_VERSION, OFP13_VERSION);
210             exit(EXIT_SUCCESS);
211
212         VLOG_OPTION_HANDLERS
213         DAEMON_OPTION_HANDLERS
214         STREAM_SSL_OPTION_HANDLERS
215
216         case OPT_PEER_CA_CERT:
217             stream_ssl_set_peer_ca_cert_file(optarg);
218             break;
219
220         case OPT_BOOTSTRAP_CA_CERT:
221             stream_ssl_set_ca_cert_file(optarg, true);
222             break;
223
224         case '?':
225             exit(EXIT_FAILURE);
226
227         default:
228             abort();
229         }
230     }
231     free(short_options);
232
233     argc -= optind;
234     argv += optind;
235
236     if (!ovnsb_remote) {
237         ovnsb_remote = xstrdup(default_db());
238     }
239
240     if (!vtep_remote) {
241         vtep_remote = xstrdup(default_db());
242     }
243 }
244
245 static void
246 usage(void)
247 {
248     printf("\
249 %s: OVN controller VTEP\n\
250 usage %s [OPTIONS]\n\
251 \n\
252 Options:\n\
253   --vtep-db=DATABASE        connect to vtep database at DATABASE\n\
254                             (default: %s)\n\
255   --ovnsb-db=DATABASE       connect to ovn-sb database at DATABASE\n\
256                             (default: %s)\n\
257   -h, --help                display this help message\n\
258   -o, --options             list available options\n\
259   -V, --version             display version information\n\
260 ", program_name, program_name, default_db(), default_db());
261     stream_usage("database", true, false, false);
262     daemon_usage();
263     vlog_usage();
264     exit(EXIT_SUCCESS);
265 }
266
267 \f
268 static void
269 ovn_controller_vtep_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
270                        const char *argv[] OVS_UNUSED, void *exiting_)
271 {
272     bool *exiting = exiting_;
273     *exiting = true;
274
275     unixctl_command_reply(conn, NULL);
276 }