From: Numan Siddique <num...@ovn.org> Signed-off-by: Numan Siddique <num...@ovn.org> --- br-controller/automake.mk | 6 +- br-controller/en-bridge-data.c | 45 +++++ br-controller/en-bridge-data.h | 16 ++ br-controller/en-lflow.c | 43 +++++ br-controller/en-lflow.h | 16 ++ br-controller/ovn-br-controller.c | 279 +++++++++++++++++++++++++++++- lib/inc-proc-eng.h | 11 ++ 7 files changed, 409 insertions(+), 7 deletions(-) create mode 100644 br-controller/en-bridge-data.c create mode 100644 br-controller/en-bridge-data.h create mode 100644 br-controller/en-lflow.c create mode 100644 br-controller/en-lflow.h
diff --git a/br-controller/automake.mk b/br-controller/automake.mk index 012e9a5ed8..497f440551 100644 --- a/br-controller/automake.mk +++ b/br-controller/automake.mk @@ -1,6 +1,10 @@ bin_PROGRAMS += br-controller/ovn-br-controller br_controller_ovn_br_controller_SOURCES = \ - br-controller/ovn-br-controller.c + br-controller/ovn-br-controller.c \ + br-controller/en-lflow.c \ + br-controller/en-lflow.h \ + br-controller/en-bridge-data.c \ + br-controller/en-bridge-data.h br_controller_ovn_br_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += br-controller/ovn-br-controller.8 diff --git a/br-controller/en-bridge-data.c b/br-controller/en-bridge-data.c new file mode 100644 index 0000000000..293ae895c0 --- /dev/null +++ b/br-controller/en-bridge-data.c @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> + +/* OVS includes. */ +#include "openvswitch/vlog.h" + +/* OVN includes. */ +#include "en-bridge-data.h" + +VLOG_DEFINE_THIS_MODULE(en_bridge_data); + +void * +en_bridge_data_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + +void +en_bridge_data_cleanup(void *data OVS_UNUSED) +{ +} + +enum engine_node_state +en_bridge_data_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED) +{ + return EN_UNCHANGED; +} diff --git a/br-controller/en-bridge-data.h b/br-controller/en-bridge-data.h new file mode 100644 index 0000000000..4a280b5cd1 --- /dev/null +++ b/br-controller/en-bridge-data.h @@ -0,0 +1,16 @@ +#ifndef EN_RUNTIME_DATA_H +#define EN_RUNTIME_DATA_H 1 + +#include <config.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> + +#include "lib/inc-proc-eng.h" + +enum engine_node_state en_bridge_data_run(struct engine_node *, void *data); +void *en_bridge_data_init(struct engine_node *node, struct engine_arg *arg); +void en_bridge_data_cleanup(void *data); + +#endif /* EN_RUNTIME_DATA_H */ diff --git a/br-controller/en-lflow.c b/br-controller/en-lflow.c new file mode 100644 index 0000000000..b1a6efbf5f --- /dev/null +++ b/br-controller/en-lflow.c @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> + +/* OVS includes. */ +#include "openvswitch/vlog.h" + +/* OVN includes. */ +#include "en-lflow.h" + +VLOG_DEFINE_THIS_MODULE(en_lflow); + +void *en_lflow_output_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + +void en_lflow_output_cleanup(void *data_ OVS_UNUSED) +{ +} + +enum engine_node_state +en_lflow_output_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED) +{ + return EN_UNCHANGED; +} diff --git a/br-controller/en-lflow.h b/br-controller/en-lflow.h new file mode 100644 index 0000000000..c3889cbdc9 --- /dev/null +++ b/br-controller/en-lflow.h @@ -0,0 +1,16 @@ +#ifndef EN_LFLOW_H +#define EN_LFLOW_H 1 + +#include <config.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> + +#include "lib/inc-proc-eng.h" + +enum engine_node_state en_lflow_output_run(struct engine_node *, void *data); +void *en_lflow_output_init(struct engine_node *node, struct engine_arg *arg); +void en_lflow_output_cleanup(void *data); + +#endif /* EN_LFLOW_H */ diff --git a/br-controller/ovn-br-controller.c b/br-controller/ovn-br-controller.c index 0fef0e5fee..27c5e28d0c 100644 --- a/br-controller/ovn-br-controller.c +++ b/br-controller/ovn-br-controller.c @@ -22,25 +22,30 @@ #include <string.h> /* OVS includes. */ -#include "openvswitch/vlog.h" #include "lib/command-line.h" #include "lib/daemon.h" #include "lib/dirs.h" #include "lib/fatal-signal.h" #include "lib/stream.h" #include "lib/stream-ssl.h" +#include "lib/vswitch-idl.h" #include "lib/unixctl.h" +#include "openvswitch/poll-loop.h" +#include "openvswitch/vlog.h" + /* OVN includes. */ +#include "en-bridge-data.h" +#include "en-lflow.h" #include "lib/ovn-br-idl.h" +#include "lib/inc-proc-eng.h" #include "lib/ovn-util.h" VLOG_DEFINE_THIS_MODULE(main); -static void parse_options(int argc, char *argv[]); +static char *parse_options(int argc, char *argv[]); OVS_NO_RETURN static void usage(void); - /* SSL/TLS options. */ static const char *ssl_private_key_file; static const char *ssl_certificate_file; @@ -49,20 +54,225 @@ static const char *ssl_ca_cert_file; /* --unixctl-path: Path to use for unixctl server socket. */ static char *unixctl_path; +#define BRCTL_NODES \ + BRCTL_NODE(br_global) \ + BRCTL_NODE(bridge) \ + BRCTL_NODE(logical_flow) + +enum brctl_engine_node { +#define BRCTL_NODE(NAME) BRCTL_##NAME, + BRCTL_NODES +#undef BRCTL_NODE +}; + +#define BRCTL_NODE(NAME) ENGINE_FUNC_BR(NAME); + BRCTL_NODES +#undef BRCTL_NODE + +#define OVS_NODES \ + OVS_NODE(open_vswitch) \ + OVS_NODE(bridge) \ + OVS_NODE(port) \ + OVS_NODE(interface) + +enum ovs_engine_node { +#define OVS_NODE(NAME) OVS_##NAME, + OVS_NODES +#undef OVS_NODE +}; + +#define OVS_NODE(NAME) ENGINE_FUNC_OVS(NAME); + OVS_NODES +#undef OVS_NODE + +/* Engine static functions. */ +static void * +en_br_controller_output_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + +static void +en_br_controller_output_cleanup(void *data OVS_UNUSED) +{ + +} + +static enum engine_node_state +en_br_controller_output_run(struct engine_node *node OVS_UNUSED, + void *data OVS_UNUSED) +{ + return EN_UPDATED; +} + +/* Static function declarations. */ +static void ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl); +static void update_br_db(struct ovsdb_idl *ovs_idl, + struct ovsdb_idl *ovn_br_idl); + int main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { + struct unixctl_server *unixctl; + struct ovn_exit_args exit_args = {0}; + int retval; + ovs_cmdl_proctitle_init(argc, argv); ovn_set_program_name(argv[0]); service_start(&argc, &argv); - parse_options(argc, argv); + char *ovs_remote = parse_options(argc, argv); fatal_ignore_sigpipe(); - return 0; + daemonize_start(true, false); + + char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); + retval = unixctl_server_create(abs_unixctl_path, &unixctl); + free(abs_unixctl_path); + if (retval) { + exit(EXIT_FAILURE); + } + unixctl_command_register("exit", "", 0, 1, ovn_exit_command_callback, + &exit_args); + + daemonize_complete(); + + /* Connect to OVS OVSDB instance. */ + struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( + ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true)); + ctrl_register_ovs_idl(ovs_idl_loop.idl); + + ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl); + + /* Configure OVN bridge database. */ + struct ovsdb_idl_loop ovnbr_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( + ovsdb_idl_create_unconnected(&ovnbrrec_idl_class, true)); + ovsdb_idl_set_leader_only(ovnbr_idl_loop.idl, false); + + ovsdb_idl_track_add_all(ovnbr_idl_loop.idl); + + unixctl_command_register("connection-status", "", 0, 0, + ovn_conn_show, ovnbr_idl_loop.idl); + + /* We don't want to monitor Connection table at all. So omit all the + * columns. */ + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_external_ids); + ovsdb_idl_omit(ovnbr_idl_loop.idl, + &ovnbrrec_connection_col_inactivity_probe); + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_is_connected); + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_max_backoff); + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_other_config); + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_status); + ovsdb_idl_omit(ovnbr_idl_loop.idl, &ovnbrrec_connection_col_target); + + /* Define inc-proc-engine nodes. */ + ENGINE_NODE(bridge_data); + ENGINE_NODE(lflow_output); + ENGINE_NODE(br_controller_output); + +#define BRCTL_NODE(NAME) ENGINE_NODE_BR(NAME); + BRCTL_NODES +#undef BRCTL_NODE + +#define OVS_NODE(NAME) ENGINE_NODE_OVS(NAME); + OVS_NODES +#undef OVS_NODE + + engine_add_input(&en_bridge_data, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_bridge_data, &en_ovs_bridge, NULL); + engine_add_input(&en_bridge_data, &en_ovs_port, NULL); + engine_add_input(&en_bridge_data, &en_ovs_interface, NULL); + + engine_add_input(&en_bridge_data, &en_ovnbr_br_global, NULL); + engine_add_input(&en_bridge_data, &en_ovnbr_bridge, NULL); + + engine_add_input(&en_lflow_output, &en_bridge_data, NULL); + engine_add_input(&en_lflow_output, &en_ovnbr_logical_flow, NULL); + engine_add_input(&en_br_controller_output, &en_lflow_output, NULL); + + struct engine_arg engine_arg = { + .ovs_idl = ovs_idl_loop.idl, + .ovnbr_idl = ovnbr_idl_loop.idl, + }; + engine_init(&en_br_controller_output, &engine_arg); + + unsigned int ovs_cond_seqno = UINT_MAX; + unsigned int ovnbr_cond_seqno = UINT_MAX; + + /* Main loop. */ + while (!exit_args.exiting) { + engine_init_run(); + + struct ovsdb_idl_txn *ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop); + unsigned int new_ovs_cond_seqno + = ovsdb_idl_get_condition_seqno(ovs_idl_loop.idl); + if (new_ovs_cond_seqno != ovs_cond_seqno) { + if (!new_ovs_cond_seqno) { + VLOG_INFO("OVS IDL reconnected, force recompute."); + engine_set_force_recompute(); + } + ovs_cond_seqno = new_ovs_cond_seqno; + } + + update_br_db(ovs_idl_loop.idl, ovnbr_idl_loop.idl); + struct ovsdb_idl_txn *ovnbr_idl_txn + = ovsdb_idl_loop_run(&ovnbr_idl_loop); + unsigned int new_ovnbr_cond_seqno + = ovsdb_idl_get_condition_seqno(ovnbr_idl_loop.idl); + if (new_ovnbr_cond_seqno != ovnbr_cond_seqno) { + if (!new_ovnbr_cond_seqno) { + VLOG_INFO("OVNBR IDL reconnected, force recompute."); + engine_set_force_recompute(); + } + ovnbr_cond_seqno = new_ovnbr_cond_seqno; + } + + struct engine_context eng_ctx = { + .ovs_idl_txn = ovs_idl_txn, + .ovnbr_idl_txn = ovnbr_idl_txn, + }; + + engine_set_context(&eng_ctx); + + const struct ovsrec_open_vswitch_table *ovs_table = + ovsrec_open_vswitch_table_get(ovs_idl_loop.idl); + const struct ovsrec_open_vswitch *cfg = + ovsrec_open_vswitch_table_first(ovs_table); + + if (ovsdb_idl_has_ever_connected(ovnbr_idl_loop.idl) && cfg) { + engine_run(true); + } + + unixctl_server_run(unixctl); + + unixctl_server_wait(unixctl); + if (exit_args.exiting) { + poll_immediate_wake(); + } + + ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop); + ovsdb_idl_loop_commit_and_wait(&ovnbr_idl_loop); + ovsdb_idl_track_clear(ovnbr_idl_loop.idl); + ovsdb_idl_track_clear(ovs_idl_loop.idl); + + poll_block(); + if (should_service_stop()) { + exit_args.exiting = true; + } + } + + engine_set_context(NULL); + engine_cleanup(); + + free(ovs_remote); + ovn_exit_args_finish(&exit_args); + unixctl_server_destroy(unixctl); + service_stop(); + exit(0); } /* static functions. */ -static void +static char * parse_options(int argc, char *argv[]) { enum { @@ -153,6 +363,17 @@ parse_options(int argc, char *argv[]) argc -= optind; argv += optind; + + char *ovs_remote = NULL; + if (argc == 0) { + ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir()); + } else if (argc == 1) { + ovs_remote = xstrdup(argv[0]); + } else { + VLOG_FATAL("exactly zero or one non-option argument required; " + "use --help for usage"); + } + return ovs_remote; } static void @@ -173,3 +394,49 @@ usage(void) " -V, --version display version information\n"); exit(EXIT_SUCCESS); } + +static void +ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) +{ + /* We do not monitor all tables by default, so modules must register + * their interest explicitly. + * When the same column is monitored in different modes by different + * modules, there is a chance that "track" flag added by + * ovsdb_idl_track_add_column by one module being overwritten by a + * following ovsdb_idl_add_column by another module. Before this is fixed + * in OVSDB IDL, we need to be careful about the order so that the "track" + * calls are after the "non-track" calls. */ + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_other_config); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_bridges); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_datapaths); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_bridge_col_name); + ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_ports); + ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_external_ids); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_port); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_port_col_name); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_port_col_interfaces); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_ofport); + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids); +} + +/* Retrieves the pointer to the OVN Bridge Controller database from 'ovs_idl' + * and updates 'brdb_idl' with that pointer. */ +static void +update_br_db(struct ovsdb_idl *ovs_idl, struct ovsdb_idl *ovnbr_idl) +{ + const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl); + if (!cfg) { + return; + } + + const char *remote = smap_get(&cfg->external_ids, "ovn-br-remote"); + ovsdb_idl_set_remote(ovnbr_idl, remote, true); +} diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h index d9174effa7..5a486f86f8 100644 --- a/lib/inc-proc-eng.h +++ b/lib/inc-proc-eng.h @@ -157,6 +157,7 @@ struct engine_context { struct ovsdb_idl_txn *ovs_idl_txn; struct ovsdb_idl_txn *ovnsb_idl_txn; struct ovsdb_idl_txn *ovnnb_idl_txn; + struct ovsdb_idl_txn *ovnbr_idl_txn; void *client_ctx; }; @@ -165,6 +166,7 @@ struct engine_context { struct engine_arg { struct ovsdb_idl *sb_idl; struct ovsdb_idl *nb_idl; + struct ovsdb_idl *ovnbr_idl; struct ovsdb_idl *ovs_idl; }; @@ -521,6 +523,11 @@ en_##DB_NAME##_##TBL_NAME##_compute_failure_info(struct engine_node *node) \ #define ENGINE_FUNC_NB(TBL_NAME) \ ENGINE_FUNC_OVSDB(nb, TBL_NAME) +/* Macro to define member functions of an engine node which represents + * a table of OVN BR DB */ +#define ENGINE_FUNC_BR(TBL_NAME) \ + ENGINE_FUNC_OVSDB(ovnbr, TBL_NAME) + /* Macro to define member functions of an engine node which represents * a table of open_vswitch DB */ #define ENGINE_FUNC_OVS(TBL_NAME) \ @@ -540,6 +547,10 @@ en_##DB_NAME##_##TBL_NAME##_compute_failure_info(struct engine_node *node) \ #define ENGINE_NODE_NB(TBL_NAME) \ ENGINE_NODE_OVSDB(nb, "NB", TBL_NAME, #TBL_NAME); +/* Macro to define an engine node which represents a table of OVN BR DB */ +#define ENGINE_NODE_BR(TBL_NAME) \ + ENGINE_NODE_OVSDB(ovnbr, "BR", TBL_NAME, #TBL_NAME); + /* Macro to define an engine node which represents a table of open_vswitch * DB */ #define ENGINE_NODE_OVS(TBL_NAME) \ -- 2.50.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev