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