Branch data Line data Source code
1 : : /* Copyright (c) 2015, 2016 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 "ovn-controller.h"
19 : :
20 : : #include <errno.h>
21 : : #include <getopt.h>
22 : : #include <signal.h>
23 : : #include <stdlib.h>
24 : : #include <string.h>
25 : :
26 : : #include "binding.h"
27 : : #include "chassis.h"
28 : : #include "command-line.h"
29 : : #include "compiler.h"
30 : : #include "daemon.h"
31 : : #include "dirs.h"
32 : : #include "openvswitch/dynamic-string.h"
33 : : #include "encaps.h"
34 : : #include "fatal-signal.h"
35 : : #include "openvswitch/hmap.h"
36 : : #include "lflow.h"
37 : : #include "lib/vswitch-idl.h"
38 : : #include "lport.h"
39 : : #include "ofctrl.h"
40 : : #include "openvswitch/vconn.h"
41 : : #include "openvswitch/vlog.h"
42 : : #include "ovn/actions.h"
43 : : #include "ovn/lib/ovn-sb-idl.h"
44 : : #include "ovn/lib/ovn-util.h"
45 : : #include "patch.h"
46 : : #include "physical.h"
47 : : #include "pinctrl.h"
48 : : #include "poll-loop.h"
49 : : #include "lib/bitmap.h"
50 : : #include "lib/hash.h"
51 : : #include "smap.h"
52 : : #include "sset.h"
53 : : #include "stream-ssl.h"
54 : : #include "stream.h"
55 : : #include "unixctl.h"
56 : : #include "util.h"
57 : :
58 : 94 : VLOG_DEFINE_THIS_MODULE(main);
59 : :
60 : : static unixctl_cb_func ovn_controller_exit;
61 : : static unixctl_cb_func ct_zone_list;
62 : :
63 : : #define DEFAULT_BRIDGE_NAME "br-int"
64 : : #define DEFAULT_PROBE_INTERVAL_MSEC 5000
65 : :
66 : : static void update_probe_interval(struct controller_ctx *);
67 : : static void parse_options(int argc, char *argv[]);
68 : : OVS_NO_RETURN static void usage(void);
69 : :
70 : : static char *ovs_remote;
71 : :
72 : : struct local_datapath *
73 : 569304 : get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
74 : : {
75 : 569304 : struct hmap_node *node = hmap_first_with_hash(local_datapaths, tunnel_key);
76 : 569304 : return (node
77 : : ? CONTAINER_OF(node, struct local_datapath, hmap_node)
78 : : : NULL);
79 : : }
80 : :
81 : : struct patched_datapath *
82 : 120153 : get_patched_datapath(const struct hmap *patched_datapaths, uint32_t tunnel_key)
83 : : {
84 : 120153 : struct hmap_node *node = hmap_first_with_hash(patched_datapaths,
85 : : tunnel_key);
86 : 120153 : return (node
87 : : ? CONTAINER_OF(node, struct patched_datapath, hmap_node)
88 : : : NULL);
89 : : }
90 : :
91 : : const struct sbrec_chassis *
92 : 9062 : get_chassis(struct ovsdb_idl *ovnsb_idl, const char *chassis_id)
93 : : {
94 : : const struct sbrec_chassis *chassis_rec;
95 : :
96 [ + + ]: 13683 : SBREC_CHASSIS_FOR_EACH(chassis_rec, ovnsb_idl) {
97 [ + + ]: 13488 : if (!strcmp(chassis_rec->name, chassis_id)) {
98 : 8867 : break;
99 : : }
100 : : }
101 : :
102 : 9062 : return chassis_rec;
103 : : }
104 : :
105 : : uint32_t
106 : 16615 : get_tunnel_type(const char *name)
107 : : {
108 [ + + ]: 16615 : if (!strcmp(name, "geneve")) {
109 : 8597 : return GENEVE;
110 [ + + ]: 8018 : } else if (!strcmp(name, "stt")) {
111 : 32 : return STT;
112 [ + - ]: 7986 : } else if (!strcmp(name, "vxlan")) {
113 : 7986 : return VXLAN;
114 : : }
115 : :
116 : 0 : return 0;
117 : : }
118 : :
119 : : const struct ovsrec_bridge *
120 : 3572 : get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)
121 : : {
122 : : const struct ovsrec_bridge *br;
123 [ + - ]: 6184 : OVSREC_BRIDGE_FOR_EACH (br, ovs_idl) {
124 [ + + ]: 6184 : if (!strcmp(br->name, br_name)) {
125 : 3572 : return br;
126 : : }
127 : : }
128 : 0 : return NULL;
129 : : }
130 : :
131 : : static const struct ovsrec_bridge *
132 : 0 : create_br_int(struct controller_ctx *ctx,
133 : : const struct ovsrec_open_vswitch *cfg,
134 : : const char *bridge_name)
135 : : {
136 [ # # ]: 0 : if (!ctx->ovs_idl_txn) {
137 : 0 : return NULL;
138 : : }
139 : :
140 : 0 : ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
141 : : "ovn-controller: creating integration bridge '%s'", bridge_name);
142 : :
143 : : struct ovsrec_interface *iface;
144 : 0 : iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
145 : 0 : ovsrec_interface_set_name(iface, bridge_name);
146 : 0 : ovsrec_interface_set_type(iface, "internal");
147 : :
148 : : struct ovsrec_port *port;
149 : 0 : port = ovsrec_port_insert(ctx->ovs_idl_txn);
150 : 0 : ovsrec_port_set_name(port, bridge_name);
151 : 0 : ovsrec_port_set_interfaces(port, &iface, 1);
152 : :
153 : : struct ovsrec_bridge *bridge;
154 : 0 : bridge = ovsrec_bridge_insert(ctx->ovs_idl_txn);
155 : 0 : ovsrec_bridge_set_name(bridge, bridge_name);
156 : 0 : ovsrec_bridge_set_fail_mode(bridge, "secure");
157 : 0 : const struct smap oc = SMAP_CONST1(&oc, "disable-in-band", "true");
158 : 0 : ovsrec_bridge_set_other_config(bridge, &oc);
159 : 0 : ovsrec_bridge_set_ports(bridge, &port, 1);
160 : :
161 : : struct ovsrec_bridge **bridges;
162 : 0 : size_t bytes = sizeof *bridges * cfg->n_bridges;
163 : 0 : bridges = xmalloc(bytes + sizeof *bridges);
164 : 0 : memcpy(bridges, cfg->bridges, bytes);
165 : 0 : bridges[cfg->n_bridges] = bridge;
166 : 0 : ovsrec_open_vswitch_verify_bridges(cfg);
167 : 0 : ovsrec_open_vswitch_set_bridges(cfg, bridges, cfg->n_bridges + 1);
168 : :
169 : 0 : return bridge;
170 : : }
171 : :
172 : : static const struct ovsrec_bridge *
173 : 3305 : get_br_int(struct controller_ctx *ctx)
174 : : {
175 : : const struct ovsrec_open_vswitch *cfg;
176 : 3305 : cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
177 [ - + ]: 3305 : if (!cfg) {
178 : 0 : return NULL;
179 : : }
180 : :
181 : 3305 : const char *br_int_name = smap_get_def(&cfg->external_ids, "ovn-bridge",
182 : : DEFAULT_BRIDGE_NAME);
183 : :
184 : : const struct ovsrec_bridge *br;
185 : 3305 : br = get_bridge(ctx->ovs_idl, br_int_name);
186 [ - + ]: 3305 : if (!br) {
187 : 0 : return create_br_int(ctx, cfg, br_int_name);
188 : : }
189 : 3305 : return br;
190 : : }
191 : :
192 : : static const char *
193 : 3305 : get_chassis_id(const struct ovsdb_idl *ovs_idl)
194 : : {
195 : 3305 : const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
196 [ + - ]: 3305 : const char *chassis_id = cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
197 : :
198 [ - + ]: 3305 : if (!chassis_id) {
199 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
200 [ # # ]: 0 : VLOG_WARN_RL(&rl, "'system-id' in Open_vSwitch database is missing.");
201 : : }
202 : :
203 : 3305 : return chassis_id;
204 : : }
205 : :
206 : : /* Retrieves the OVN Southbound remote location from the
207 : : * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
208 : : *
209 : : * XXX ovn-controller does not support this changing mid-run, but that should
210 : : * be addressed later. */
211 : : static char *
212 : 3211 : get_ovnsb_remote(struct ovsdb_idl *ovs_idl)
213 : : {
214 : : while (1) {
215 : 3211 : ovsdb_idl_run(ovs_idl);
216 : :
217 : 3211 : const struct ovsrec_open_vswitch *cfg
218 : : = ovsrec_open_vswitch_first(ovs_idl);
219 [ + - ]: 3211 : if (cfg) {
220 : 3211 : const char *remote = smap_get(&cfg->external_ids, "ovn-remote");
221 [ + - ]: 3211 : if (remote) {
222 : 3211 : return xstrdup(remote);
223 : : }
224 : : }
225 : :
226 [ # # ]: 0 : VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
227 : 0 : ovsdb_idl_wait(ovs_idl);
228 : 0 : poll_block();
229 : 0 : }
230 : : }
231 : :
232 : : static void
233 : 3167 : update_ct_zones(struct sset *lports, struct hmap *patched_datapaths,
234 : : struct simap *ct_zones, unsigned long *ct_zone_bitmap)
235 : : {
236 : : struct simap_node *ct_zone, *ct_zone_next;
237 : 3167 : int scan_start = 1;
238 : : struct patched_datapath *pd;
239 : : const char *user;
240 : 3167 : struct sset all_users = SSET_INITIALIZER(&all_users);
241 : :
242 [ + + ][ + + ]: 16767 : SSET_FOR_EACH(user, lports) {
[ + + ]
243 : 13600 : sset_add(&all_users, user);
244 : : }
245 : :
246 : : /* Local patched datapath (gateway routers) need zones assigned. */
247 [ + + ][ - + ]: 10153 : HMAP_FOR_EACH(pd, hmap_node, patched_datapaths) {
248 [ + + ]: 6986 : if (!pd->local) {
249 : 6507 : continue;
250 : : }
251 : :
252 : 479 : char *dnat = alloc_nat_zone_key(&pd->key, "dnat");
253 : 479 : char *snat = alloc_nat_zone_key(&pd->key, "snat");
254 : 479 : sset_add(&all_users, dnat);
255 : 479 : sset_add(&all_users, snat);
256 : 479 : free(dnat);
257 : 479 : free(snat);
258 : : }
259 : :
260 : : /* Delete zones that do not exist in above sset. */
261 [ + + ][ - + ]: 17582 : SIMAP_FOR_EACH_SAFE(ct_zone, ct_zone_next, ct_zones) {
[ + + ]
262 [ + + ]: 14415 : if (!sset_contains(&all_users, ct_zone->name)) {
263 : 97 : bitmap_set0(ct_zone_bitmap, ct_zone->data);
264 : 97 : simap_delete(ct_zones, ct_zone);
265 : : }
266 : : }
267 : :
268 : : /* xxx This is wasteful to assign a zone to each port--even if no
269 : : * xxx security policy is applied. */
270 : :
271 : : /* Assign a unique zone id for each logical port and two zones
272 : : * to a gateway router. */
273 [ + + ][ + + ]: 17725 : SSET_FOR_EACH(user, &all_users) {
[ + + ]
274 : : size_t zone;
275 : :
276 [ + + ]: 14558 : if (simap_contains(ct_zones, user)) {
277 : 14318 : continue;
278 : : }
279 : :
280 : : /* We assume that there are 64K zones and that we own them all. */
281 : 240 : zone = bitmap_scan(ct_zone_bitmap, 0, scan_start, MAX_CT_ZONES + 1);
282 [ - + ]: 240 : if (zone == MAX_CT_ZONES + 1) {
283 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
284 [ # # ]: 0 : VLOG_WARN_RL(&rl, "exhausted all ct zones");
285 : 0 : return;
286 : : }
287 : 240 : scan_start = zone + 1;
288 : :
289 : 240 : bitmap_set1(ct_zone_bitmap, zone);
290 : 240 : simap_put(ct_zones, user, zone);
291 : :
292 : : /* xxx We should erase any old entries for this
293 : : * xxx zone, but we need a generic interface to the conntrack
294 : : * xxx table. */
295 : : }
296 : :
297 : 3167 : sset_destroy(&all_users);
298 : : }
299 : :
300 : : static int64_t
301 : 3167 : get_nb_cfg(struct ovsdb_idl *idl)
302 : : {
303 : 3167 : const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl);
304 [ + + ]: 3167 : return sb ? sb->nb_cfg : 0;
305 : : }
306 : :
307 : : int
308 : 47 : main(int argc, char *argv[])
309 : : {
310 : : struct unixctl_server *unixctl;
311 : : bool exiting;
312 : : int retval;
313 : :
314 : 47 : ovs_cmdl_proctitle_init(argc, argv);
315 : 47 : set_program_name(argv[0]);
316 : 47 : service_start(&argc, &argv);
317 : 47 : parse_options(argc, argv);
318 : 47 : fatal_ignore_sigpipe();
319 : :
320 : 47 : daemonize_start(false);
321 : :
322 : 44 : retval = unixctl_server_create(NULL, &unixctl);
323 [ - + ]: 44 : if (retval) {
324 : 0 : exit(EXIT_FAILURE);
325 : : }
326 : 44 : unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
327 : :
328 : : /* Initialize group ids for loadbalancing. */
329 : : struct group_table group_table;
330 : 44 : group_table.group_ids = bitmap_allocate(MAX_OVN_GROUPS);
331 : 44 : bitmap_set1(group_table.group_ids, 0); /* Group id 0 is invalid. */
332 : 44 : hmap_init(&group_table.desired_groups);
333 : 44 : hmap_init(&group_table.existing_groups);
334 : :
335 : 44 : daemonize_complete();
336 : :
337 : 44 : ovsrec_init();
338 : 44 : sbrec_init();
339 : :
340 : 44 : ofctrl_init(&group_table);
341 : 44 : pinctrl_init();
342 : 44 : lflow_init();
343 : :
344 : : /* Connect to OVS OVSDB instance. We do not monitor all tables by
345 : : * default, so modules must register their interest explicitly. */
346 : 44 : struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
347 : : ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true));
348 : 44 : ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_open_vswitch);
349 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl,
350 : : &ovsrec_open_vswitch_col_external_ids);
351 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_open_vswitch_col_bridges);
352 : 44 : ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_interface);
353 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_name);
354 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_type);
355 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_options);
356 : 44 : ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_port);
357 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_name);
358 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_interfaces);
359 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_external_ids);
360 : 44 : ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_bridge);
361 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_ports);
362 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_name);
363 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_fail_mode);
364 : 44 : ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_other_config);
365 : 44 : chassis_register_ovs_idl(ovs_idl_loop.idl);
366 : 44 : encaps_register_ovs_idl(ovs_idl_loop.idl);
367 : 44 : binding_register_ovs_idl(ovs_idl_loop.idl);
368 : 44 : physical_register_ovs_idl(ovs_idl_loop.idl);
369 : 44 : ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl);
370 : :
371 : : /* Connect to OVN SB database. */
372 : 44 : char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
373 : 44 : struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
374 : : ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
375 : 44 : ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg);
376 : :
377 : : /* Track the southbound idl. */
378 : 44 : ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
379 : :
380 : 44 : ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
381 : :
382 : : /* Initialize connection tracking zones. */
383 : 44 : struct simap ct_zones = SIMAP_INITIALIZER(&ct_zones);
384 : : unsigned long ct_zone_bitmap[BITMAP_N_LONGS(MAX_CT_ZONES)];
385 : 44 : memset(ct_zone_bitmap, 0, sizeof ct_zone_bitmap);
386 : 44 : bitmap_set1(ct_zone_bitmap, 0); /* Zone 0 is reserved. */
387 : 44 : unixctl_command_register("ct-zone-list", "", 0, 0,
388 : : ct_zone_list, &ct_zones);
389 : :
390 : : /* Main loop. */
391 : 44 : exiting = false;
392 [ + + ]: 3211 : while (!exiting) {
393 : : /* Check OVN SB database. */
394 : 3167 : char *new_ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
395 [ + + ]: 3167 : if (strcmp(ovnsb_remote, new_ovnsb_remote)) {
396 : 2 : free(ovnsb_remote);
397 : 2 : ovnsb_remote = new_ovnsb_remote;
398 : 2 : ovsdb_idl_set_remote(ovnsb_idl_loop.idl, ovnsb_remote, true);
399 : : } else {
400 : 3165 : free(new_ovnsb_remote);
401 : : }
402 : :
403 : 12668 : struct controller_ctx ctx = {
404 : 3167 : .ovs_idl = ovs_idl_loop.idl,
405 : 3167 : .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
406 : 3167 : .ovnsb_idl = ovnsb_idl_loop.idl,
407 : 3167 : .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
408 : : };
409 : :
410 : 3167 : update_probe_interval(&ctx);
411 : :
412 : : /* Contains "struct local_datapath" nodes whose hash values are the
413 : : * tunnel_key of datapaths with at least one local port binding. */
414 : 3167 : struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
415 : :
416 : 3167 : struct hmap patched_datapaths = HMAP_INITIALIZER(&patched_datapaths);
417 : 3167 : struct sset all_lports = SSET_INITIALIZER(&all_lports);
418 : :
419 : 3167 : const struct ovsrec_bridge *br_int = get_br_int(&ctx);
420 : 3167 : const char *chassis_id = get_chassis_id(ctx.ovs_idl);
421 : :
422 : 3167 : const struct sbrec_chassis *chassis = NULL;
423 [ + - ]: 3167 : if (chassis_id) {
424 : 3167 : chassis = chassis_run(&ctx, chassis_id, br_int);
425 : 3167 : encaps_run(&ctx, br_int, chassis_id);
426 : 3167 : binding_run(&ctx, br_int, chassis_id, &local_datapaths,
427 : : &all_lports);
428 : : }
429 : :
430 [ + - ][ + - ]: 3167 : if (br_int && chassis_id) {
431 : 3167 : patch_run(&ctx, br_int, chassis_id, &local_datapaths,
432 : : &patched_datapaths);
433 : :
434 : : static struct lport_index lports;
435 : : static struct mcgroup_index mcgroups;
436 : 3167 : lport_index_init(&lports, ctx.ovnsb_idl);
437 : 3167 : mcgroup_index_init(&mcgroups, ctx.ovnsb_idl);
438 : :
439 : 3167 : enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
440 : :
441 : 3167 : pinctrl_run(&ctx, &lports, br_int, chassis_id, &local_datapaths);
442 : 3167 : update_ct_zones(&all_lports, &patched_datapaths, &ct_zones,
443 : : ct_zone_bitmap);
444 : :
445 : 3167 : struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
446 : 3167 : lflow_run(&ctx, &lports, &mcgroups, &local_datapaths,
447 : : &patched_datapaths, &group_table, &ct_zones,
448 : : &flow_table);
449 : :
450 : 3167 : physical_run(&ctx, mff_ovn_geneve,
451 : : br_int, chassis_id, &ct_zones, &flow_table,
452 : : &local_datapaths, &patched_datapaths);
453 : :
454 : 3167 : ofctrl_put(&flow_table, get_nb_cfg(ctx.ovnsb_idl));
455 : 3167 : hmap_destroy(&flow_table);
456 [ + + ]: 3167 : if (ctx.ovnsb_idl_txn) {
457 : 2670 : int64_t cur_cfg = ofctrl_get_cur_cfg();
458 [ - + ][ # # ]: 2670 : if (cur_cfg && cur_cfg != chassis->nb_cfg) {
459 : 0 : sbrec_chassis_set_nb_cfg(chassis, cur_cfg);
460 : : }
461 : : }
462 : 3167 : mcgroup_index_destroy(&mcgroups);
463 : 3167 : lport_index_destroy(&lports);
464 : : }
465 : :
466 : 3167 : sset_destroy(&all_lports);
467 : :
468 : : struct local_datapath *cur_node, *next_node;
469 [ + + ][ - + ]: 8345 : HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) {
[ + + ]
470 : 5178 : hmap_remove(&local_datapaths, &cur_node->hmap_node);
471 : 5178 : free(cur_node->logical_port);
472 : 5178 : free(cur_node);
473 : : }
474 : 3167 : hmap_destroy(&local_datapaths);
475 : :
476 : : struct patched_datapath *pd_cur_node, *pd_next_node;
477 [ + + ][ - + ]: 10153 : HMAP_FOR_EACH_SAFE (pd_cur_node, pd_next_node, hmap_node,
[ + + ]
478 : : &patched_datapaths) {
479 : 6986 : hmap_remove(&patched_datapaths, &pd_cur_node->hmap_node);
480 : 6986 : free(pd_cur_node);
481 : : }
482 : 3167 : hmap_destroy(&patched_datapaths);
483 : :
484 : 3167 : unixctl_server_run(unixctl);
485 : :
486 : 3167 : unixctl_server_wait(unixctl);
487 [ + + ]: 3167 : if (exiting) {
488 : 44 : poll_immediate_wake();
489 : : }
490 : :
491 [ + - ]: 3167 : if (br_int) {
492 : 3167 : ofctrl_wait();
493 : 3167 : pinctrl_wait(&ctx);
494 : : }
495 : 3167 : ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
496 : 3167 : ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
497 : 3167 : ovsdb_idl_track_clear(ovnsb_idl_loop.idl);
498 : 3167 : ovsdb_idl_track_clear(ovs_idl_loop.idl);
499 : 3167 : poll_block();
500 [ - + ]: 3167 : if (should_service_stop()) {
501 : 3167 : exiting = true;
502 : : }
503 : : }
504 : :
505 : : /* It's time to exit. Clean up the databases. */
506 : 44 : bool done = false;
507 [ + + ]: 182 : while (!done) {
508 : 552 : struct controller_ctx ctx = {
509 : 138 : .ovs_idl = ovs_idl_loop.idl,
510 : 138 : .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
511 : 138 : .ovnsb_idl = ovnsb_idl_loop.idl,
512 : 138 : .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
513 : : };
514 : :
515 : 138 : const struct ovsrec_bridge *br_int = get_br_int(&ctx);
516 : 138 : const char *chassis_id = get_chassis_id(ctx.ovs_idl);
517 : :
518 : : /* Run all of the cleanup functions, even if one of them returns false.
519 : : * We're done if all of them return true. */
520 : 138 : done = binding_cleanup(&ctx, chassis_id);
521 [ + + ][ + + ]: 138 : done = chassis_cleanup(&ctx, chassis_id) && done;
522 [ + + ][ + + ]: 138 : done = encaps_cleanup(&ctx, br_int) && done;
523 [ + + ]: 138 : if (done) {
524 : 44 : poll_immediate_wake();
525 : : }
526 : :
527 : 138 : ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
528 : 138 : ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
529 : 138 : poll_block();
530 : : }
531 : :
532 : 44 : unixctl_server_destroy(unixctl);
533 : 44 : lflow_destroy();
534 : 44 : ofctrl_destroy();
535 : 44 : pinctrl_destroy();
536 : :
537 : 44 : simap_destroy(&ct_zones);
538 : :
539 : 44 : bitmap_free(group_table.group_ids);
540 : 44 : hmap_destroy(&group_table.desired_groups);
541 : :
542 : : struct group_info *installed, *next_group;
543 [ + + ][ - + ]: 50 : HMAP_FOR_EACH_SAFE(installed, next_group, hmap_node,
[ + + ]
544 : : &group_table.existing_groups) {
545 : 6 : hmap_remove(&group_table.existing_groups, &installed->hmap_node);
546 : 6 : ds_destroy(&installed->group);
547 : 6 : free(installed);
548 : : }
549 : 44 : hmap_destroy(&group_table.existing_groups);
550 : :
551 : 44 : ovsdb_idl_loop_destroy(&ovs_idl_loop);
552 : 44 : ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
553 : :
554 : 44 : free(ovnsb_remote);
555 : 44 : free(ovs_remote);
556 : 44 : service_stop();
557 : :
558 : 44 : exit(retval);
559 : : }
560 : :
561 : : static void
562 : 47 : parse_options(int argc, char *argv[])
563 : : {
564 : : enum {
565 : : OPT_PEER_CA_CERT = UCHAR_MAX + 1,
566 : : OPT_BOOTSTRAP_CA_CERT,
567 : : VLOG_OPTION_ENUMS,
568 : : DAEMON_OPTION_ENUMS
569 : : };
570 : :
571 : : static struct option long_options[] = {
572 : : {"help", no_argument, NULL, 'h'},
573 : : {"version", no_argument, NULL, 'V'},
574 : : VLOG_LONG_OPTIONS,
575 : : DAEMON_LONG_OPTIONS,
576 : : STREAM_SSL_LONG_OPTIONS,
577 : : {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
578 : : {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
579 : : {NULL, 0, NULL, 0}
580 : : };
581 : 47 : char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
582 : :
583 : : for (;;) {
584 : : int c;
585 : :
586 : 282 : c = getopt_long(argc, argv, short_options, long_options, NULL);
587 [ + + ]: 282 : if (c == -1) {
588 : 47 : break;
589 : : }
590 : :
591 [ - - + + : 235 : switch (c) {
- - + - +
+ - - - -
- - - - -
- ]
592 : : case 'h':
593 : 0 : usage();
594 : :
595 : : case 'V':
596 : 0 : ovs_print_version(OFP13_VERSION, OFP13_VERSION);
597 : 0 : exit(EXIT_SUCCESS);
598 : :
599 : 94 : VLOG_OPTION_HANDLERS
600 : 141 : DAEMON_OPTION_HANDLERS
601 : 0 : STREAM_SSL_OPTION_HANDLERS
602 : :
603 : : case OPT_PEER_CA_CERT:
604 : 0 : stream_ssl_set_peer_ca_cert_file(optarg);
605 : 0 : break;
606 : :
607 : : case OPT_BOOTSTRAP_CA_CERT:
608 : 0 : stream_ssl_set_ca_cert_file(optarg, true);
609 : 0 : break;
610 : :
611 : : case '?':
612 : 0 : exit(EXIT_FAILURE);
613 : :
614 : : default:
615 : 0 : abort();
616 : : }
617 : 235 : }
618 : 47 : free(short_options);
619 : :
620 : 47 : argc -= optind;
621 : 47 : argv += optind;
622 : :
623 [ + - ]: 47 : if (argc == 0) {
624 : 47 : ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
625 [ # # ]: 0 : } else if (argc == 1) {
626 : 0 : ovs_remote = xstrdup(argv[0]);
627 : : } else {
628 : 0 : VLOG_FATAL("exactly zero or one non-option argument required; "
629 : : "use --help for usage");
630 : : }
631 : 47 : }
632 : :
633 : : static void
634 : 0 : usage(void)
635 : : {
636 : 0 : printf("%s: OVN controller\n"
637 : : "usage %s [OPTIONS] [OVS-DATABASE]\n"
638 : : "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
639 : : program_name, program_name);
640 : 0 : stream_usage("OVS-DATABASE", true, false, false);
641 : 0 : daemon_usage();
642 : 0 : vlog_usage();
643 : 0 : printf("\nOther options:\n"
644 : : " -h, --help display this help message\n"
645 : : " -V, --version display version information\n");
646 : 0 : exit(EXIT_SUCCESS);
647 : : }
648 : :
649 : : static void
650 : 44 : ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
651 : : const char *argv[] OVS_UNUSED, void *exiting_)
652 : : {
653 : 44 : bool *exiting = exiting_;
654 : 44 : *exiting = true;
655 : :
656 : 44 : unixctl_command_reply(conn, NULL);
657 : 44 : }
658 : :
659 : : static void
660 : 0 : ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
661 : : const char *argv[] OVS_UNUSED, void *ct_zones_)
662 : : {
663 : 0 : struct simap *ct_zones = ct_zones_;
664 : 0 : struct ds ds = DS_EMPTY_INITIALIZER;
665 : : struct simap_node *zone;
666 : :
667 [ # # ][ # # ]: 0 : SIMAP_FOR_EACH(zone, ct_zones) {
668 : 0 : ds_put_format(&ds, "%s %d\n", zone->name, zone->data);
669 : : }
670 : :
671 : 0 : unixctl_command_reply(conn, ds_cstr(&ds));
672 : 0 : ds_destroy(&ds);
673 : 0 : }
674 : :
675 : : /* Get the desired SB probe timer from the OVS database and configure it into
676 : : * the SB database. */
677 : : static void
678 : 3167 : update_probe_interval(struct controller_ctx *ctx)
679 : : {
680 : 3167 : const struct ovsrec_open_vswitch *cfg
681 : 3167 : = ovsrec_open_vswitch_first(ctx->ovs_idl);
682 : 3167 : int interval = (cfg
683 : 3167 : ? smap_get_int(&cfg->external_ids,
684 : : "ovn-remote-probe-interval",
685 : : DEFAULT_PROBE_INTERVAL_MSEC)
686 [ + - ]: 3167 : : DEFAULT_PROBE_INTERVAL_MSEC);
687 : 3167 : ovsdb_idl_set_probe_interval(ctx->ovnsb_idl, interval);
688 : 3167 : }
|