From patchwork Thu Sep 16 15:49:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Gray X-Patchwork-Id: 1528956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=YaHnIfC0; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H9M2z00kVz9sR4 for ; Fri, 17 Sep 2021 01:49:30 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id C1D2040541; Thu, 16 Sep 2021 15:49:27 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id whqj3Rrl9xJm; Thu, 16 Sep 2021 15:49:24 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id AD68E4043F; Thu, 16 Sep 2021 15:49:22 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C5F8CC0011; Thu, 16 Sep 2021 15:49:21 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0AC3CC0011 for ; Thu, 16 Sep 2021 15:49:21 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id E793581BD9 for ; Thu, 16 Sep 2021 15:49:19 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=fail (1024-bit key) reason="fail (body has been altered)" header.d=redhat.com Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id z4rrowKQPcQF for ; Thu, 16 Sep 2021 15:49:17 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id ED54680E3D for ; Thu, 16 Sep 2021 15:49:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1631807356; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=55idawPsIIXFTfpMdazDEfkEsGPbPzH45zsA5QW+t1Q=; b=YaHnIfC0/QH++Iqdi8CjXkbNImdLwhRPqO8gsasANg0ojcXDqTawDE5IxWkL7LJo7QolQY 8gOpJcA3pVTX8K1yAJPyT2K9PSVu7ExbNgBk0xLS9lTSz+XhXsxLLiy6cFatzXsWg5Dkz1 1pNfIIJTM51N0c5h7P0+ajsgPVulxbE= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-490-xQtv3xNLMNCLbjKwL4lRUw-1; Thu, 16 Sep 2021 11:49:14 -0400 X-MC-Unique: xQtv3xNLMNCLbjKwL4lRUw-1 Received: by mail-qk1-f199.google.com with SMTP id e22-20020a05620a209600b003d5ff97bff7so40701194qka.1 for ; Thu, 16 Sep 2021 08:49:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DC2n/vPR777DC2O3DaYGnKPN+mtcTjteWLrsGdM/S/I=; b=Y3vmrWQclrQgTNxx6NGlIozItD+Li31lYTrwLg/vffq9K7qOR20reX3VpdxI+DhI6W zyJlK9idWXI9m2OAMecBmo5Zba62KM6i3VqYWc7E770aSnT2z3hU5KME2FrNBsLIFSvs 7ii+SpEe/MnpMgSYyf7iAyygAjBoLXWSH/N11U3g9rt8DjBHMIS/kDGcCOd2p4bQ+Es2 Iv5/ATUn8Vx7gI96ERqgzDpR44yMQq5cuHtBiuokFqBOGxggGk2Db0cpPKeqj+0v9Agn KeV0MrRBkbUBWrXjG0ek1vLF8GwRYZNOTqaOECoaog35f5Sqr4kNQJVwJH4GI4YTZ3H4 qX2Q== X-Gm-Message-State: AOAM531B7oZGfdbncndIUZm8J5FmIw4a5CT8HjrCdtkJ/HUXrd/8ifI8 8ERJSFsJsucBMhYwJaaGLC94k13Orr7BE7e9Kzl+MRgQqn1sqxH+yjh9WLlTtay9gcEG32yMeUj 5f7gc3HdpD+tMZVXrBIMOa4YkYfx3rkfrDY9BLzhgQwTyVq2ET1Hts2J/v6Id4sugBFXg X-Received: by 2002:a05:620a:7d5:: with SMTP id 21mr5564343qkb.339.1631807353297; Thu, 16 Sep 2021 08:49:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzpz5QiiSyl/XDajr1nH36TBwySf4y/7uz39XPA/E7kLd5iAeeMcEAnneZgiKY9Kn6r3sieXQ== X-Received: by 2002:a05:620a:7d5:: with SMTP id 21mr5564238qkb.339.1631807351958; Thu, 16 Sep 2021 08:49:11 -0700 (PDT) Received: from wsfd-netdev91.ntdv.lab.eng.bos.redhat.com (nat-pool-bos-t.redhat.com. [66.187.233.206]) by smtp.gmail.com with ESMTPSA id w185sm2642898qkd.30.2021.09.16.08.49.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Sep 2021 08:49:11 -0700 (PDT) From: Mark Gray To: dev@openvswitch.org Date: Thu, 16 Sep 2021 11:49:09 -0400 Message-Id: <20210916154909.1892866-3-mark.d.gray@redhat.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210916154909.1892866-1-mark.d.gray@redhat.com> References: <20210916154909.1892866-1-mark.d.gray@redhat.com> MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=mark.d.gray@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: numans@redhat.com Subject: [ovs-dev] [PATCH ovn v5 2/2] northd: Split northd.c X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" This commit splits northd into two parts. One part, ovn-northd.c, is responsible for the `ovn-northd` application, and the other is responsible for northd processing. This takes one step towards a more modular northd code base. Signed-off-by: Mark Gray --- northd/automake.mk | 2 + northd/northd.c | 1106 +----------------------------------------- northd/northd.h | 42 ++ northd/ovn-northd.c | 1107 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1167 insertions(+), 1090 deletions(-) create mode 100644 northd/northd.h create mode 100644 northd/ovn-northd.c diff --git a/northd/automake.mk b/northd/automake.mk index 306b533a486b..35ad8c09d9ba 100644 --- a/northd/automake.mk +++ b/northd/automake.mk @@ -2,6 +2,8 @@ bin_PROGRAMS += northd/ovn-northd northd_ovn_northd_SOURCES = \ northd/northd.c \ + northd/northd.h \ + northd/ovn-northd.c \ northd/ipam.c \ northd/ipam.h northd_ovn_northd_LDADD = \ diff --git a/northd/northd.c b/northd/northd.c index 2fc8b073f5a3..688a6e4efb53 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -14,17 +14,13 @@ #include -#include #include #include #include "bitmap.h" -#include "command-line.h" -#include "daemon.h" #include "dirs.h" #include "ipam.h" #include "openvswitch/dynamic-string.h" -#include "fatal-signal.h" #include "hash.h" #include "hmapx.h" #include "openvswitch/hmap.h" @@ -40,13 +36,12 @@ #include "lib/ovn-util.h" #include "lib/lb.h" #include "memory.h" -#include "ovs-numa.h" +#include "northd.h" #include "lib/ovn-parallel-hmap.h" #include "ovn/actions.h" #include "ovn/features.h" #include "ovn/logical-fields.h" #include "packets.h" -#include "openvswitch/poll-loop.h" #include "simap.h" #include "smap.h" #include "sset.h" @@ -54,41 +49,12 @@ #include "stopwatch.h" #include "lib/stopwatch-names.h" #include "stream.h" -#include "stream-ssl.h" #include "timeval.h" -#include "unixctl.h" #include "util.h" #include "uuid.h" #include "openvswitch/vlog.h" -VLOG_DEFINE_THIS_MODULE(ovn_northd); - -static unixctl_cb_func ovn_northd_exit; -static unixctl_cb_func ovn_northd_pause; -static unixctl_cb_func ovn_northd_resume; -static unixctl_cb_func ovn_northd_is_paused; -static unixctl_cb_func ovn_northd_status; -static unixctl_cb_func cluster_state_reset_cmd; - -struct northd_context { - struct ovsdb_idl *ovnnb_idl; - struct ovsdb_idl *ovnsb_idl; - struct ovsdb_idl_txn *ovnnb_txn; - struct ovsdb_idl_txn *ovnsb_txn; - struct ovsdb_idl_index *sbrec_chassis_by_name; - struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name; - struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; - struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; -}; - -struct northd_state { - bool had_lock; - bool paused; -}; - -static const char *ovnnb_db; -static const char *ovnsb_db; -static const char *unixctl_path; +VLOG_DEFINE_THIS_MODULE(northd); static bool controller_event_en; @@ -110,12 +76,6 @@ static bool use_ct_inv_match = true; #define DEFAULT_PROBE_INTERVAL_MSEC 5000 static int northd_probe_interval_nb = 0; static int northd_probe_interval_sb = 0; - -/* SSL options */ -static const char *ssl_private_key_file; -static const char *ssl_certificate_file; -static const char *ssl_ca_cert_file; - #define MAX_OVN_TAGS 4096 /* Pipeline stages. */ @@ -403,29 +363,6 @@ ovn_stage_to_datapath_type(enum ovn_stage stage) } } -static void -usage(void) -{ - printf("\ -%s: OVN northbound management daemon\n\ -usage: %s [OPTIONS]\n\ -\n\ -Options:\n\ - --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\ - (default: %s)\n\ - --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\n\ - (default: %s)\n\ - --dry-run start in paused state (do not commit db changes)\n\ - --unixctl=SOCKET override default control socket name\n\ - -h, --help display this help message\n\ - -o, --options list available options\n\ - -V, --version display version information\n\ -", program_name, program_name, default_nb_db(), default_sb_db()); - daemon_usage(); - vlog_usage(); - stream_usage("database", true, true, false); -} - struct ovn_chassis_qdisc_queues { struct hmap_node key_node; uint32_t queue_id; @@ -4360,7 +4297,7 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od, static bool use_logical_dp_groups = false; static bool use_parallel_build = true; -static struct hashrow_locks lflow_locks; +static struct hashrow_locks *lflow_locks; /* Adds a row with the specified contents to the Logical_Flow table. * Version to use when locking is required. @@ -4415,11 +4352,11 @@ ovn_lflow_add_at_with_hash(struct hmap *lflow_map, struct ovn_datapath *od, ovs_assert(ovn_stage_to_datapath_type(stage) == ovn_datapath_get_type(od)); if (use_logical_dp_groups && use_parallel_build) { - lock_hash_row(&lflow_locks, hash); + lock_hash_row(lflow_locks, hash); lflow = do_ovn_lflow_add(lflow_map, od, hash, stage, priority, match, actions, io_port, stage_hint, where, ctrl_meter); - unlock_hash_row(&lflow_locks, hash); + unlock_hash_row(lflow_locks, hash); } else { lflow = do_ovn_lflow_add(lflow_map, od, hash, stage, priority, match, actions, io_port, stage_hint, where, ctrl_meter); @@ -4455,9 +4392,9 @@ ovn_dp_group_add_with_reference(struct ovn_lflow *lflow_ref, } if (use_parallel_build) { - lock_hash_row(&lflow_locks, hash); + lock_hash_row(lflow_locks, hash); hmapx_add(&lflow_ref->od_group, od); - unlock_hash_row(&lflow_locks, hash); + unlock_hash_row(lflow_locks, hash); } else { hmapx_add(&lflow_ref->od_group, od); } @@ -13176,7 +13113,7 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, fast_hmap_size_for(&lflows, max_seen_lflow_size); if (use_parallel_build) { - update_hashrow_locks(&lflows, &lflow_locks); + update_hashrow_locks(&lflows, lflow_locks); } build_lswitch_and_lrouter_flows(datapaths, ports, port_groups, &lflows, mcgroups, @@ -14246,8 +14183,11 @@ ovnnb_db_run(struct northd_context *ctx, smap_destroy(&options); /* Update the probe interval. */ - northd_probe_interval_nb = get_probe_interval(ovnnb_db, nb); - northd_probe_interval_sb = get_probe_interval(ovnsb_db, nb); + northd_probe_interval_nb = get_probe_interval(ctx->ovnnb_db, nb); + northd_probe_interval_sb = get_probe_interval(ctx->ovnsb_db, nb); + + ovsdb_idl_set_probe_interval(ctx->ovnnb_idl, northd_probe_interval_nb); + ovsdb_idl_set_probe_interval(ctx->ovnsb_idl, northd_probe_interval_sb); use_parallel_build = (smap_get_bool(&nb->options, "use_parallel_build", false) && @@ -14539,373 +14479,6 @@ handle_port_binding_changes(struct northd_context *ctx, struct hmap *ports, } } -static struct gen_opts_map supported_dhcp_opts[] = { - OFFERIP, - DHCP_OPT_NETMASK, - DHCP_OPT_ROUTER, - DHCP_OPT_DNS_SERVER, - DHCP_OPT_LOG_SERVER, - DHCP_OPT_LPR_SERVER, - DHCP_OPT_SWAP_SERVER, - DHCP_OPT_POLICY_FILTER, - DHCP_OPT_ROUTER_SOLICITATION, - DHCP_OPT_NIS_SERVER, - DHCP_OPT_NTP_SERVER, - DHCP_OPT_SERVER_ID, - DHCP_OPT_TFTP_SERVER, - DHCP_OPT_CLASSLESS_STATIC_ROUTE, - DHCP_OPT_MS_CLASSLESS_STATIC_ROUTE, - DHCP_OPT_IP_FORWARD_ENABLE, - DHCP_OPT_ROUTER_DISCOVERY, - DHCP_OPT_ETHERNET_ENCAP, - DHCP_OPT_DEFAULT_TTL, - DHCP_OPT_TCP_TTL, - DHCP_OPT_MTU, - DHCP_OPT_LEASE_TIME, - DHCP_OPT_T1, - DHCP_OPT_T2, - DHCP_OPT_WPAD, - DHCP_OPT_BOOTFILE, - DHCP_OPT_PATH_PREFIX, - DHCP_OPT_TFTP_SERVER_ADDRESS, - DHCP_OPT_HOSTNAME, - DHCP_OPT_DOMAIN_NAME, - DHCP_OPT_ARP_CACHE_TIMEOUT, - DHCP_OPT_TCP_KEEPALIVE_INTERVAL, - DHCP_OPT_DOMAIN_SEARCH_LIST, - DHCP_OPT_BOOTFILE_ALT, - DHCP_OPT_BROADCAST_ADDRESS, - DHCP_OPT_NETBIOS_NAME_SERVER, - DHCP_OPT_NETBIOS_NODE_TYPE, -}; - -static struct gen_opts_map supported_dhcpv6_opts[] = { - DHCPV6_OPT_IA_ADDR, - DHCPV6_OPT_SERVER_ID, - DHCPV6_OPT_DOMAIN_SEARCH, - DHCPV6_OPT_DNS_SERVER -}; - -static void -check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx) -{ - struct hmap dhcp_opts_to_add = HMAP_INITIALIZER(&dhcp_opts_to_add); - for (size_t i = 0; (i < sizeof(supported_dhcp_opts) / - sizeof(supported_dhcp_opts[0])); i++) { - hmap_insert(&dhcp_opts_to_add, &supported_dhcp_opts[i].hmap_node, - dhcp_opt_hash(supported_dhcp_opts[i].name)); - } - - const struct sbrec_dhcp_options *opt_row, *opt_row_next; - SBREC_DHCP_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) { - struct gen_opts_map *dhcp_opt = - dhcp_opts_find(&dhcp_opts_to_add, opt_row->name); - if (dhcp_opt) { - if (!strcmp(dhcp_opt->type, opt_row->type) && - dhcp_opt->code == opt_row->code) { - hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node); - } else { - sbrec_dhcp_options_delete(opt_row); - } - } else { - sbrec_dhcp_options_delete(opt_row); - } - } - - struct gen_opts_map *opt; - HMAP_FOR_EACH (opt, hmap_node, &dhcp_opts_to_add) { - struct sbrec_dhcp_options *sbrec_dhcp_option = - sbrec_dhcp_options_insert(ctx->ovnsb_txn); - sbrec_dhcp_options_set_name(sbrec_dhcp_option, opt->name); - sbrec_dhcp_options_set_code(sbrec_dhcp_option, opt->code); - sbrec_dhcp_options_set_type(sbrec_dhcp_option, opt->type); - } - - hmap_destroy(&dhcp_opts_to_add); -} - -static void -check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx) -{ - struct hmap dhcpv6_opts_to_add = HMAP_INITIALIZER(&dhcpv6_opts_to_add); - for (size_t i = 0; (i < sizeof(supported_dhcpv6_opts) / - sizeof(supported_dhcpv6_opts[0])); i++) { - hmap_insert(&dhcpv6_opts_to_add, &supported_dhcpv6_opts[i].hmap_node, - dhcp_opt_hash(supported_dhcpv6_opts[i].name)); - } - - const struct sbrec_dhcpv6_options *opt_row, *opt_row_next; - SBREC_DHCPV6_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) { - struct gen_opts_map *dhcp_opt = - dhcp_opts_find(&dhcpv6_opts_to_add, opt_row->name); - if (dhcp_opt) { - hmap_remove(&dhcpv6_opts_to_add, &dhcp_opt->hmap_node); - } else { - sbrec_dhcpv6_options_delete(opt_row); - } - } - - struct gen_opts_map *opt; - HMAP_FOR_EACH(opt, hmap_node, &dhcpv6_opts_to_add) { - struct sbrec_dhcpv6_options *sbrec_dhcpv6_option = - sbrec_dhcpv6_options_insert(ctx->ovnsb_txn); - sbrec_dhcpv6_options_set_name(sbrec_dhcpv6_option, opt->name); - sbrec_dhcpv6_options_set_code(sbrec_dhcpv6_option, opt->code); - sbrec_dhcpv6_options_set_type(sbrec_dhcpv6_option, opt->type); - } - - hmap_destroy(&dhcpv6_opts_to_add); -} - -static const char *rbac_chassis_auth[] = - {"name"}; -static const char *rbac_chassis_update[] = - {"nb_cfg", "external_ids", "encaps", "vtep_logical_switches", - "other_config", "transport_zones"}; - -static const char *rbac_chassis_private_auth[] = - {"name"}; -static const char *rbac_chassis_private_update[] = - {"nb_cfg", "nb_cfg_timestamp", "chassis", "external_ids"}; - -static const char *rbac_encap_auth[] = - {"chassis_name"}; -static const char *rbac_encap_update[] = - {"type", "options", "ip"}; - -static const char *rbac_controller_event_auth[] = - {""}; -static const char *rbac_controller_event_update[] = - {"chassis", "event_info", "event_type", "seq_num"}; - - -static const char *rbac_fdb_auth[] = - {""}; -static const char *rbac_fdb_update[] = - {"dp_key", "mac", "port_key"}; - -static const char *rbac_port_binding_auth[] = - {""}; -static const char *rbac_port_binding_update[] = - {"chassis", "encap", "up", "virtual_parent"}; - -static const char *rbac_mac_binding_auth[] = - {""}; -static const char *rbac_mac_binding_update[] = - {"logical_port", "ip", "mac", "datapath"}; - -static const char *rbac_svc_monitor_auth[] = - {""}; -static const char *rbac_svc_monitor_auth_update[] = - {"status"}; -static const char *rbac_igmp_group_auth[] = - {""}; -static const char *rbac_igmp_group_update[] = - {"address", "chassis", "datapath", "ports"}; - -static struct rbac_perm_cfg { - const char *table; - const char **auth; - int n_auth; - bool insdel; - const char **update; - int n_update; - const struct sbrec_rbac_permission *row; -} rbac_perm_cfg[] = { - { - .table = "Chassis", - .auth = rbac_chassis_auth, - .n_auth = ARRAY_SIZE(rbac_chassis_auth), - .insdel = true, - .update = rbac_chassis_update, - .n_update = ARRAY_SIZE(rbac_chassis_update), - .row = NULL - },{ - .table = "Chassis_Private", - .auth = rbac_chassis_private_auth, - .n_auth = ARRAY_SIZE(rbac_chassis_private_auth), - .insdel = true, - .update = rbac_chassis_private_update, - .n_update = ARRAY_SIZE(rbac_chassis_private_update), - .row = NULL - },{ - .table = "Controller_Event", - .auth = rbac_controller_event_auth, - .n_auth = ARRAY_SIZE(rbac_controller_event_auth), - .insdel = true, - .update = rbac_controller_event_update, - .n_update = ARRAY_SIZE(rbac_controller_event_update), - .row = NULL - },{ - .table = "Encap", - .auth = rbac_encap_auth, - .n_auth = ARRAY_SIZE(rbac_encap_auth), - .insdel = true, - .update = rbac_encap_update, - .n_update = ARRAY_SIZE(rbac_encap_update), - .row = NULL - },{ - .table = "FDB", - .auth = rbac_fdb_auth, - .n_auth = ARRAY_SIZE(rbac_fdb_auth), - .insdel = true, - .update = rbac_fdb_update, - .n_update = ARRAY_SIZE(rbac_fdb_update), - .row = NULL - },{ - .table = "Port_Binding", - .auth = rbac_port_binding_auth, - .n_auth = ARRAY_SIZE(rbac_port_binding_auth), - .insdel = false, - .update = rbac_port_binding_update, - .n_update = ARRAY_SIZE(rbac_port_binding_update), - .row = NULL - },{ - .table = "MAC_Binding", - .auth = rbac_mac_binding_auth, - .n_auth = ARRAY_SIZE(rbac_mac_binding_auth), - .insdel = true, - .update = rbac_mac_binding_update, - .n_update = ARRAY_SIZE(rbac_mac_binding_update), - .row = NULL - },{ - .table = "Service_Monitor", - .auth = rbac_svc_monitor_auth, - .n_auth = ARRAY_SIZE(rbac_svc_monitor_auth), - .insdel = false, - .update = rbac_svc_monitor_auth_update, - .n_update = ARRAY_SIZE(rbac_svc_monitor_auth_update), - .row = NULL - },{ - .table = "IGMP_Group", - .auth = rbac_igmp_group_auth, - .n_auth = ARRAY_SIZE(rbac_igmp_group_auth), - .insdel = true, - .update = rbac_igmp_group_update, - .n_update = ARRAY_SIZE(rbac_igmp_group_update), - .row = NULL - },{ - .table = NULL, - .auth = NULL, - .n_auth = 0, - .insdel = false, - .update = NULL, - .n_update = 0, - .row = NULL - } -}; - -static bool -ovn_rbac_validate_perm(const struct sbrec_rbac_permission *perm) -{ - struct rbac_perm_cfg *pcfg; - int i, j, n_found; - - for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { - if (!strcmp(perm->table, pcfg->table)) { - break; - } - } - if (!pcfg->table) { - return false; - } - if (perm->n_authorization != pcfg->n_auth || - perm->n_update != pcfg->n_update) { - return false; - } - if (perm->insert_delete != pcfg->insdel) { - return false; - } - /* verify perm->authorization vs. pcfg->auth */ - n_found = 0; - for (i = 0; i < pcfg->n_auth; i++) { - for (j = 0; j < perm->n_authorization; j++) { - if (!strcmp(pcfg->auth[i], perm->authorization[j])) { - n_found++; - break; - } - } - } - if (n_found != pcfg->n_auth) { - return false; - } - - /* verify perm->update vs. pcfg->update */ - n_found = 0; - for (i = 0; i < pcfg->n_update; i++) { - for (j = 0; j < perm->n_update; j++) { - if (!strcmp(pcfg->update[i], perm->update[j])) { - n_found++; - break; - } - } - } - if (n_found != pcfg->n_update) { - return false; - } - - /* Success, db state matches expected state */ - pcfg->row = perm; - return true; -} - -static void -ovn_rbac_create_perm(struct rbac_perm_cfg *pcfg, - struct northd_context *ctx, - const struct sbrec_rbac_role *rbac_role) -{ - struct sbrec_rbac_permission *rbac_perm; - - rbac_perm = sbrec_rbac_permission_insert(ctx->ovnsb_txn); - sbrec_rbac_permission_set_table(rbac_perm, pcfg->table); - sbrec_rbac_permission_set_authorization(rbac_perm, - pcfg->auth, - pcfg->n_auth); - sbrec_rbac_permission_set_insert_delete(rbac_perm, pcfg->insdel); - sbrec_rbac_permission_set_update(rbac_perm, - pcfg->update, - pcfg->n_update); - sbrec_rbac_role_update_permissions_setkey(rbac_role, pcfg->table, - rbac_perm); -} - -static void -check_and_update_rbac(struct northd_context *ctx) -{ - const struct sbrec_rbac_role *rbac_role = NULL; - const struct sbrec_rbac_permission *perm_row, *perm_next; - const struct sbrec_rbac_role *role_row, *role_row_next; - struct rbac_perm_cfg *pcfg; - - for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { - pcfg->row = NULL; - } - - SBREC_RBAC_PERMISSION_FOR_EACH_SAFE (perm_row, perm_next, ctx->ovnsb_idl) { - if (!ovn_rbac_validate_perm(perm_row)) { - sbrec_rbac_permission_delete(perm_row); - } - } - SBREC_RBAC_ROLE_FOR_EACH_SAFE (role_row, role_row_next, ctx->ovnsb_idl) { - if (strcmp(role_row->name, "ovn-controller")) { - sbrec_rbac_role_delete(role_row); - } else { - rbac_role = role_row; - } - } - - if (!rbac_role) { - rbac_role = sbrec_rbac_role_insert(ctx->ovnsb_txn); - sbrec_rbac_role_set_name(rbac_role, "ovn-controller"); - } - - for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { - if (!pcfg->row) { - ovn_rbac_create_perm(pcfg, ctx, rbac_role); - } - } -} - /* Updates the sb_cfg and hv_cfg columns in the northbound NB_Global table. */ static void update_northbound_cfg(struct northd_context *ctx, @@ -14978,7 +14551,7 @@ ovnsb_db_run(struct northd_context *ctx, shash_destroy(&ha_ref_chassis_map); } -static void +void ovn_db_run(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, struct ovsdb_idl_loop *ovnsb_idl_loop, @@ -14989,6 +14562,8 @@ ovn_db_run(struct northd_context *ctx, ovs_list_init(&lr_list); hmap_init(&datapaths); hmap_init(&ports); + use_parallel_build = ctx->use_parallel_build; + lflow_locks = ctx->lflow_locks; int64_t start_time = time_wall_msec(); stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); @@ -15001,653 +14576,4 @@ ovn_db_run(struct northd_context *ctx, stopwatch_stop(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); destroy_datapaths_and_ports(&datapaths, &ports, &lr_list); } - -static void -parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED, - bool *paused) -{ - enum { - OVN_DAEMON_OPTION_ENUMS, - VLOG_OPTION_ENUMS, - SSL_OPTION_ENUMS, - OPT_DRY_RUN, - OPT_DUMMY_NUMA, - }; - static const struct option long_options[] = { - {"ovnsb-db", required_argument, NULL, 'd'}, - {"ovnnb-db", required_argument, NULL, 'D'}, - {"unixctl", required_argument, NULL, 'u'}, - {"help", no_argument, NULL, 'h'}, - {"options", no_argument, NULL, 'o'}, - {"version", no_argument, NULL, 'V'}, - {"dry-run", no_argument, NULL, OPT_DRY_RUN}, - {"dummy-numa", required_argument, NULL, OPT_DUMMY_NUMA}, - OVN_DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - STREAM_SSL_LONG_OPTIONS, - {NULL, 0, NULL, 0}, - }; - char *short_options = ovs_cmdl_long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - switch (c) { - OVN_DAEMON_OPTION_HANDLERS; - VLOG_OPTION_HANDLERS; - - case 'p': - ssl_private_key_file = optarg; - break; - - case 'c': - ssl_certificate_file = optarg; - break; - - case 'C': - ssl_ca_cert_file = optarg; - break; - - case 'd': - ovnsb_db = optarg; - break; - - case 'D': - ovnnb_db = optarg; - break; - - case 'u': - unixctl_path = optarg; - break; - - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case 'o': - ovs_cmdl_print_options(long_options); - exit(EXIT_SUCCESS); - - case 'V': - ovn_print_version(0, 0); - exit(EXIT_SUCCESS); - - case OPT_DUMMY_NUMA: - ovs_numa_set_dummy(optarg); - break; - - case OPT_DRY_RUN: - *paused = true; - break; - - default: - break; - } - } - - if (!ovnsb_db || !ovnsb_db[0]) { - ovnsb_db = default_sb_db(); - } - - if (!ovnnb_db || !ovnnb_db[0]) { - ovnnb_db = default_nb_db(); - } - - free(short_options); -} - -static void -add_column_noalert(struct ovsdb_idl *idl, - const struct ovsdb_idl_column *column) -{ - ovsdb_idl_add_column(idl, column); - ovsdb_idl_omit_alert(idl, column); -} - -static void -update_ssl_config(void) -{ - if (ssl_private_key_file && ssl_certificate_file) { - stream_ssl_set_key_and_cert(ssl_private_key_file, - ssl_certificate_file); - } - if (ssl_ca_cert_file) { - stream_ssl_set_ca_cert_file(ssl_ca_cert_file, false); - } -} - -int -main(int argc, char *argv[]) -{ - int res = EXIT_SUCCESS; - struct unixctl_server *unixctl; - int retval; - bool exiting; - struct northd_state state = { - .had_lock = false, - .paused = false - }; - - fatal_ignore_sigpipe(); - ovs_cmdl_proctitle_init(argc, argv); - ovn_set_program_name(argv[0]); - service_start(&argc, &argv); - parse_options(argc, argv, &state.paused); - - daemonize_start(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, 0, ovn_northd_exit, &exiting); - unixctl_command_register("pause", "", 0, 0, ovn_northd_pause, &state); - unixctl_command_register("resume", "", 0, 0, ovn_northd_resume, &state); - unixctl_command_register("is-paused", "", 0, 0, ovn_northd_is_paused, - &state); - unixctl_command_register("status", "", 0, 0, ovn_northd_status, &state); - - bool reset_ovnsb_idl_min_index = false; - unixctl_command_register("sb-cluster-state-reset", "", 0, 0, - cluster_state_reset_cmd, - &reset_ovnsb_idl_min_index); - - bool reset_ovnnb_idl_min_index = false; - unixctl_command_register("nb-cluster-state-reset", "", 0, 0, - cluster_state_reset_cmd, - &reset_ovnnb_idl_min_index); - - daemonize_complete(); - - init_hash_row_locks(&lflow_locks); - use_parallel_build = can_parallelize_hashes(false); - - /* We want to detect (almost) all changes to the ovn-nb db. */ - struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( - ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true)); - ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, - &nbrec_nb_global_col_nb_cfg_timestamp); - ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_sb_cfg); - ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, - &nbrec_nb_global_col_sb_cfg_timestamp); - ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_hv_cfg); - ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, - &nbrec_nb_global_col_hv_cfg_timestamp); - - unixctl_command_register("nb-connection-status", "", 0, 0, - ovn_conn_show, ovnnb_idl_loop.idl); - - /* We want to detect only selected changes to the ovn-sb db. */ - struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( - ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true)); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_ipsec); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_logical_flow_col_logical_datapath); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_logical_flow_col_logical_dp_group); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_logical_flow_col_controller_meter); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_logical_flow_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, - &sbrec_table_logical_dp_group); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_logical_dp_group_col_datapaths); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_multicast_group_col_datapath); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_multicast_group_col_tunnel_key); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_datapath_binding_col_tunnel_key); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_datapath_binding_col_load_balancers); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_datapath_binding_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_logical_port); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_tunnel_key); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_parent_port); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_nat_addresses); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_gateway_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_ha_chassis_group); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_virtual_parent); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_up); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_gateway_chassis_col_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_gateway_chassis_col_name); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_gateway_chassis_col_priority); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_gateway_chassis_col_external_ids); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_gateway_chassis_col_options); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_port_binding_col_external_ids); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_datapath); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_ip); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_mac); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_mac_binding_col_logical_port); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcp_options); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_code); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_type); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_name); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcpv6_options); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_code); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_type); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_name); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_address_set); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_group); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_name); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_ports); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dns); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_datapaths); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_records); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_role); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_name); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_permissions); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_permission); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_rbac_permission_col_table); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_rbac_permission_col_authorization); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_rbac_permission_col_insert_delete); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis_private); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_chassis_private_col_name); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_chassis_private_col_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_chassis_private_col_nb_cfg); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_chassis_private_col_nb_cfg_timestamp); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_col_chassis); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_col_priority); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis_group); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_group_col_name); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_group_col_ha_chassis); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_group_col_external_ids); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ha_chassis_group_col_ref_chassis); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_igmp_group); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_address); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_datapath); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_chassis); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_ports); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ip_multicast); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_datapath); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_enabled); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_querier); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_eth_src); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_ip4_src); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_ip6_src); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_table_size); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_idle_timeout); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_query_interval); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_ip_multicast_col_query_max_resp); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_service_monitor); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_ip); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_logical_port); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_port); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_options); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_status); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_protocol); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_src_mac); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_src_ip); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_service_monitor_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_load_balancer); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_datapaths); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_name); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_vips); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_protocol); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_options); - add_column_noalert(ovnsb_idl_loop.idl, - &sbrec_load_balancer_col_external_ids); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_bfd); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_logical_port); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_dst_ip); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_status); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_tx); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_rx); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_detect_mult); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc); - ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port); - - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_fdb); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_dp_key); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_port_key); - - struct ovsdb_idl_index *sbrec_chassis_by_name - = chassis_index_create(ovnsb_idl_loop.idl); - - struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name - = ha_chassis_group_index_create(ovnsb_idl_loop.idl); - - struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp - = mcast_group_index_create(ovnsb_idl_loop.idl); - - struct ovsdb_idl_index *sbrec_ip_mcast_by_dp - = ip_mcast_index_create(ovnsb_idl_loop.idl); - - unixctl_command_register("sb-connection-status", "", 0, 0, - ovn_conn_show, ovnsb_idl_loop.idl); - - char *ovn_internal_version = ovn_get_internal_version(); - VLOG_INFO("OVN internal version is : [%s]", ovn_internal_version); - - stopwatch_create(NORTHD_LOOP_STOPWATCH_NAME, SW_MS); - stopwatch_create(OVNNB_DB_RUN_STOPWATCH_NAME, SW_MS); - stopwatch_create(OVNSB_DB_RUN_STOPWATCH_NAME, SW_MS); - stopwatch_create(BUILD_LFLOWS_CTX_STOPWATCH_NAME, SW_MS); - stopwatch_create(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, SW_MS); - stopwatch_create(BUILD_LFLOWS_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_DATAPATHS_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_PORTS_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_LBS_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_IGMP_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_DP_GROUPS_STOPWATCH_NAME, SW_MS); - - /* Main loop. */ - exiting = false; - - while (!exiting) { - update_ssl_config(); - memory_run(); - if (memory_should_report()) { - struct simap usage = SIMAP_INITIALIZER(&usage); - - /* Nothing special to report yet. */ - memory_report(&usage); - simap_destroy(&usage); - } - - if (!state.paused) { - if (!ovsdb_idl_has_lock(ovnsb_idl_loop.idl) && - !ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl)) - { - /* Ensure that only a single ovn-northd is active in the - * deployment by acquiring a lock called "ovn_northd" on the - * southbound database and then only performing DB transactions - * if the lock is held. - */ - ovsdb_idl_set_lock(ovnsb_idl_loop.idl, "ovn_northd"); - } - - struct northd_context ctx = { - .ovnnb_idl = ovnnb_idl_loop.idl, - .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop), - .ovnsb_idl = ovnsb_idl_loop.idl, - .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), - .sbrec_chassis_by_name = sbrec_chassis_by_name, - .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name, - .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp, - .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp, - }; - - if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { - VLOG_INFO("ovn-northd lock acquired. " - "This ovn-northd instance is now active."); - state.had_lock = true; - } else if (state.had_lock && - !ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) - { - VLOG_INFO("ovn-northd lock lost. " - "This ovn-northd instance is now on standby."); - state.had_lock = false; - } - - if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { - ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop, - ovn_internal_version); - if (ctx.ovnsb_txn) { - check_and_add_supported_dhcp_opts_to_sb_db(&ctx); - check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx); - check_and_update_rbac(&ctx); - } - } - - ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop); - ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); - } else { - /* ovn-northd is paused - * - we still want to handle any db updates and update the - * local IDL. Otherwise, when it is resumed, the local IDL - * copy will be out of sync. - * - but we don't want to create any txns. - * */ - if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl) || - ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl)) - { - /* make sure we don't hold the lock while paused */ - VLOG_INFO("This ovn-northd instance is now paused."); - ovsdb_idl_set_lock(ovnsb_idl_loop.idl, NULL); - state.had_lock = false; - } - - ovsdb_idl_run(ovnnb_idl_loop.idl); - ovsdb_idl_run(ovnsb_idl_loop.idl); - ovsdb_idl_wait(ovnnb_idl_loop.idl); - ovsdb_idl_wait(ovnsb_idl_loop.idl); - } - - unixctl_server_run(unixctl); - unixctl_server_wait(unixctl); - memory_wait(); - if (exiting) { - poll_immediate_wake(); - } - - - ovsdb_idl_set_probe_interval(ovnnb_idl_loop.idl, - northd_probe_interval_nb); - ovsdb_idl_set_probe_interval(ovnsb_idl_loop.idl, - northd_probe_interval_sb); - - if (reset_ovnsb_idl_min_index) { - VLOG_INFO("Resetting southbound database cluster state"); - ovsdb_idl_reset_min_index(ovnsb_idl_loop.idl); - reset_ovnsb_idl_min_index = false; - } - - if (reset_ovnnb_idl_min_index) { - VLOG_INFO("Resetting northbound database cluster state"); - ovsdb_idl_reset_min_index(ovnnb_idl_loop.idl); - reset_ovnnb_idl_min_index = false; - } - - stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); - poll_block(); - if (should_service_stop()) { - exiting = true; - } - stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); - } - - - free(ovn_internal_version); - unixctl_server_destroy(unixctl); - ovsdb_idl_loop_destroy(&ovnnb_idl_loop); - ovsdb_idl_loop_destroy(&ovnsb_idl_loop); - service_stop(); - - exit(res); -} - -static void -ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) -{ - bool *exiting = exiting_; - *exiting = true; - - unixctl_command_reply(conn, NULL); -} - -static void -ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *state_) -{ - struct northd_state *state = state_; - state->paused = true; - - unixctl_command_reply(conn, NULL); -} - -static void -ovn_northd_resume(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *state_) -{ - struct northd_state *state = state_; - state->paused = false; - - unixctl_command_reply(conn, NULL); -} - -static void -ovn_northd_is_paused(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *state_) -{ - struct northd_state *state = state_; - if (state->paused) { - unixctl_command_reply(conn, "true"); - } else { - unixctl_command_reply(conn, "false"); - } -} - -static void -ovn_northd_status(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *state_) -{ - struct northd_state *state = state_; - char *status; - - if (state->paused) { - status = "paused"; - } else { - status = state->had_lock ? "active" : "standby"; - } - - /* - * Use a labelled formatted output so we can add more to the status command - * later without breaking any consuming scripts - */ - struct ds s = DS_EMPTY_INITIALIZER; - ds_put_format(&s, "Status: %s\n", status); - unixctl_command_reply(conn, ds_cstr(&s)); - ds_destroy(&s); -} - -static void -cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *idl_reset_) -{ - bool *idl_reset = idl_reset_; - - *idl_reset = true; - poll_immediate_wake(); - unixctl_command_reply(conn, NULL); -} diff --git a/northd/northd.h b/northd/northd.h new file mode 100644 index 000000000000..3209d4224803 --- /dev/null +++ b/northd/northd.h @@ -0,0 +1,42 @@ +/* + * 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. + */ +#ifndef NORTHD_H +#define NORTHD_H 1 + +#include "ovsdb-idl.h" +#include "lib/ovn-parallel-hmap.h" + +struct northd_context { + const char *ovnnb_db; + const char *ovnsb_db; + struct ovsdb_idl *ovnnb_idl; + struct ovsdb_idl *ovnsb_idl; + struct ovsdb_idl_txn *ovnnb_txn; + struct ovsdb_idl_txn *ovnsb_txn; + struct ovsdb_idl_index *sbrec_chassis_by_name; + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name; + struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp; + struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; + + bool use_parallel_build; + struct hashrow_locks *lflow_locks; +}; + +void +ovn_db_run(struct northd_context *ctx, + struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_loop *ovnsb_idl_loop, + const char *ovn_internal_version); + +#endif /* NORTHD_H */ diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c new file mode 100644 index 000000000000..ecdc64852577 --- /dev/null +++ b/northd/ovn-northd.c @@ -0,0 +1,1107 @@ +/* + * 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 + +#include +#include +#include + +#include "lib/chassis-index.h" +#include "command-line.h" +#include "daemon.h" +#include "fatal-signal.h" +#include "lib/ip-mcast-index.h" +#include "lib/mcast-group-index.h" +#include "memory.h" +#include "northd.h" +#include "ovs-numa.h" +#include "ovsdb-idl.h" +#include "lib/ovn-l7.h" +#include "lib/ovn-nb-idl.h" +#include "lib/ovn-parallel-hmap.h" +#include "lib/ovn-sb-idl.h" +#include "openvswitch/poll-loop.h" +#include "simap.h" +#include "stopwatch.h" +#include "lib/stopwatch-names.h" +#include "stream.h" +#include "stream-ssl.h" +#include "unixctl.h" +#include "util.h" +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(ovn_northd); + +static unixctl_cb_func ovn_northd_exit; +static unixctl_cb_func ovn_northd_pause; +static unixctl_cb_func ovn_northd_resume; +static unixctl_cb_func ovn_northd_is_paused; +static unixctl_cb_func ovn_northd_status; +static unixctl_cb_func cluster_state_reset_cmd; + +struct northd_state { + bool had_lock; + bool paused; +}; + +static const char *ovnnb_db; +static const char *ovnsb_db; +static const char *unixctl_path; + +/* SSL options */ +static const char *ssl_private_key_file; +static const char *ssl_certificate_file; +static const char *ssl_ca_cert_file; + +static bool use_parallel_build = true; +static struct hashrow_locks lflow_locks; + +static const char *rbac_chassis_auth[] = + {"name"}; +static const char *rbac_chassis_update[] = + {"nb_cfg", "external_ids", "encaps", "vtep_logical_switches", + "other_config", "transport_zones"}; + +static const char *rbac_chassis_private_auth[] = + {"name"}; +static const char *rbac_chassis_private_update[] = + {"nb_cfg", "nb_cfg_timestamp", "chassis", "external_ids"}; + +static const char *rbac_encap_auth[] = + {"chassis_name"}; +static const char *rbac_encap_update[] = + {"type", "options", "ip"}; + +static const char *rbac_controller_event_auth[] = + {""}; +static const char *rbac_controller_event_update[] = + {"chassis", "event_info", "event_type", "seq_num"}; + + +static const char *rbac_fdb_auth[] = + {""}; +static const char *rbac_fdb_update[] = + {"dp_key", "mac", "port_key"}; + +static const char *rbac_port_binding_auth[] = + {""}; +static const char *rbac_port_binding_update[] = + {"chassis", "encap", "up", "virtual_parent"}; + +static const char *rbac_mac_binding_auth[] = + {""}; +static const char *rbac_mac_binding_update[] = + {"logical_port", "ip", "mac", "datapath"}; + +static const char *rbac_svc_monitor_auth[] = + {""}; +static const char *rbac_svc_monitor_auth_update[] = + {"status"}; +static const char *rbac_igmp_group_auth[] = + {""}; +static const char *rbac_igmp_group_update[] = + {"address", "chassis", "datapath", "ports"}; + +static struct rbac_perm_cfg { + const char *table; + const char **auth; + int n_auth; + bool insdel; + const char **update; + int n_update; + const struct sbrec_rbac_permission *row; +} rbac_perm_cfg[] = { + { + .table = "Chassis", + .auth = rbac_chassis_auth, + .n_auth = ARRAY_SIZE(rbac_chassis_auth), + .insdel = true, + .update = rbac_chassis_update, + .n_update = ARRAY_SIZE(rbac_chassis_update), + .row = NULL + },{ + .table = "Chassis_Private", + .auth = rbac_chassis_private_auth, + .n_auth = ARRAY_SIZE(rbac_chassis_private_auth), + .insdel = true, + .update = rbac_chassis_private_update, + .n_update = ARRAY_SIZE(rbac_chassis_private_update), + .row = NULL + },{ + .table = "Controller_Event", + .auth = rbac_controller_event_auth, + .n_auth = ARRAY_SIZE(rbac_controller_event_auth), + .insdel = true, + .update = rbac_controller_event_update, + .n_update = ARRAY_SIZE(rbac_controller_event_update), + .row = NULL + },{ + .table = "Encap", + .auth = rbac_encap_auth, + .n_auth = ARRAY_SIZE(rbac_encap_auth), + .insdel = true, + .update = rbac_encap_update, + .n_update = ARRAY_SIZE(rbac_encap_update), + .row = NULL + },{ + .table = "FDB", + .auth = rbac_fdb_auth, + .n_auth = ARRAY_SIZE(rbac_fdb_auth), + .insdel = true, + .update = rbac_fdb_update, + .n_update = ARRAY_SIZE(rbac_fdb_update), + .row = NULL + },{ + .table = "Port_Binding", + .auth = rbac_port_binding_auth, + .n_auth = ARRAY_SIZE(rbac_port_binding_auth), + .insdel = false, + .update = rbac_port_binding_update, + .n_update = ARRAY_SIZE(rbac_port_binding_update), + .row = NULL + },{ + .table = "MAC_Binding", + .auth = rbac_mac_binding_auth, + .n_auth = ARRAY_SIZE(rbac_mac_binding_auth), + .insdel = true, + .update = rbac_mac_binding_update, + .n_update = ARRAY_SIZE(rbac_mac_binding_update), + .row = NULL + },{ + .table = "Service_Monitor", + .auth = rbac_svc_monitor_auth, + .n_auth = ARRAY_SIZE(rbac_svc_monitor_auth), + .insdel = false, + .update = rbac_svc_monitor_auth_update, + .n_update = ARRAY_SIZE(rbac_svc_monitor_auth_update), + .row = NULL + },{ + .table = "IGMP_Group", + .auth = rbac_igmp_group_auth, + .n_auth = ARRAY_SIZE(rbac_igmp_group_auth), + .insdel = true, + .update = rbac_igmp_group_update, + .n_update = ARRAY_SIZE(rbac_igmp_group_update), + .row = NULL + },{ + .table = NULL, + .auth = NULL, + .n_auth = 0, + .insdel = false, + .update = NULL, + .n_update = 0, + .row = NULL + } +}; + +static struct gen_opts_map supported_dhcp_opts[] = { + OFFERIP, + DHCP_OPT_NETMASK, + DHCP_OPT_ROUTER, + DHCP_OPT_DNS_SERVER, + DHCP_OPT_LOG_SERVER, + DHCP_OPT_LPR_SERVER, + DHCP_OPT_SWAP_SERVER, + DHCP_OPT_POLICY_FILTER, + DHCP_OPT_ROUTER_SOLICITATION, + DHCP_OPT_NIS_SERVER, + DHCP_OPT_NTP_SERVER, + DHCP_OPT_SERVER_ID, + DHCP_OPT_TFTP_SERVER, + DHCP_OPT_CLASSLESS_STATIC_ROUTE, + DHCP_OPT_MS_CLASSLESS_STATIC_ROUTE, + DHCP_OPT_IP_FORWARD_ENABLE, + DHCP_OPT_ROUTER_DISCOVERY, + DHCP_OPT_ETHERNET_ENCAP, + DHCP_OPT_DEFAULT_TTL, + DHCP_OPT_TCP_TTL, + DHCP_OPT_MTU, + DHCP_OPT_LEASE_TIME, + DHCP_OPT_T1, + DHCP_OPT_T2, + DHCP_OPT_WPAD, + DHCP_OPT_BOOTFILE, + DHCP_OPT_PATH_PREFIX, + DHCP_OPT_TFTP_SERVER_ADDRESS, + DHCP_OPT_HOSTNAME, + DHCP_OPT_DOMAIN_NAME, + DHCP_OPT_ARP_CACHE_TIMEOUT, + DHCP_OPT_TCP_KEEPALIVE_INTERVAL, + DHCP_OPT_DOMAIN_SEARCH_LIST, + DHCP_OPT_BOOTFILE_ALT, + DHCP_OPT_BROADCAST_ADDRESS, + DHCP_OPT_NETBIOS_NAME_SERVER, + DHCP_OPT_NETBIOS_NODE_TYPE, +}; + +static struct gen_opts_map supported_dhcpv6_opts[] = { + DHCPV6_OPT_IA_ADDR, + DHCPV6_OPT_SERVER_ID, + DHCPV6_OPT_DOMAIN_SEARCH, + DHCPV6_OPT_DNS_SERVER +}; + +static bool +ovn_rbac_validate_perm(const struct sbrec_rbac_permission *perm) +{ + struct rbac_perm_cfg *pcfg; + int i, j, n_found; + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + if (!strcmp(perm->table, pcfg->table)) { + break; + } + } + if (!pcfg->table) { + return false; + } + if (perm->n_authorization != pcfg->n_auth || + perm->n_update != pcfg->n_update) { + return false; + } + if (perm->insert_delete != pcfg->insdel) { + return false; + } + /* verify perm->authorization vs. pcfg->auth */ + n_found = 0; + for (i = 0; i < pcfg->n_auth; i++) { + for (j = 0; j < perm->n_authorization; j++) { + if (!strcmp(pcfg->auth[i], perm->authorization[j])) { + n_found++; + break; + } + } + } + if (n_found != pcfg->n_auth) { + return false; + } + + /* verify perm->update vs. pcfg->update */ + n_found = 0; + for (i = 0; i < pcfg->n_update; i++) { + for (j = 0; j < perm->n_update; j++) { + if (!strcmp(pcfg->update[i], perm->update[j])) { + n_found++; + break; + } + } + } + if (n_found != pcfg->n_update) { + return false; + } + + /* Success, db state matches expected state */ + pcfg->row = perm; + return true; +} + +static void +ovn_rbac_create_perm(struct rbac_perm_cfg *pcfg, + struct northd_context *ctx, + const struct sbrec_rbac_role *rbac_role) +{ + struct sbrec_rbac_permission *rbac_perm; + + rbac_perm = sbrec_rbac_permission_insert(ctx->ovnsb_txn); + sbrec_rbac_permission_set_table(rbac_perm, pcfg->table); + sbrec_rbac_permission_set_authorization(rbac_perm, + pcfg->auth, + pcfg->n_auth); + sbrec_rbac_permission_set_insert_delete(rbac_perm, pcfg->insdel); + sbrec_rbac_permission_set_update(rbac_perm, + pcfg->update, + pcfg->n_update); + sbrec_rbac_role_update_permissions_setkey(rbac_role, pcfg->table, + rbac_perm); +} + +static void +check_and_update_rbac(struct northd_context *ctx) +{ + const struct sbrec_rbac_role *rbac_role = NULL; + const struct sbrec_rbac_permission *perm_row, *perm_next; + const struct sbrec_rbac_role *role_row, *role_row_next; + struct rbac_perm_cfg *pcfg; + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + pcfg->row = NULL; + } + + SBREC_RBAC_PERMISSION_FOR_EACH_SAFE (perm_row, perm_next, ctx->ovnsb_idl) { + if (!ovn_rbac_validate_perm(perm_row)) { + sbrec_rbac_permission_delete(perm_row); + } + } + SBREC_RBAC_ROLE_FOR_EACH_SAFE (role_row, role_row_next, ctx->ovnsb_idl) { + if (strcmp(role_row->name, "ovn-controller")) { + sbrec_rbac_role_delete(role_row); + } else { + rbac_role = role_row; + } + } + + if (!rbac_role) { + rbac_role = sbrec_rbac_role_insert(ctx->ovnsb_txn); + sbrec_rbac_role_set_name(rbac_role, "ovn-controller"); + } + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + if (!pcfg->row) { + ovn_rbac_create_perm(pcfg, ctx, rbac_role); + } + } +} + +static void +check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx) +{ + struct hmap dhcp_opts_to_add = HMAP_INITIALIZER(&dhcp_opts_to_add); + for (size_t i = 0; (i < sizeof(supported_dhcp_opts) / + sizeof(supported_dhcp_opts[0])); i++) { + hmap_insert(&dhcp_opts_to_add, &supported_dhcp_opts[i].hmap_node, + dhcp_opt_hash(supported_dhcp_opts[i].name)); + } + + const struct sbrec_dhcp_options *opt_row, *opt_row_next; + SBREC_DHCP_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) { + struct gen_opts_map *dhcp_opt = + dhcp_opts_find(&dhcp_opts_to_add, opt_row->name); + if (dhcp_opt) { + if (!strcmp(dhcp_opt->type, opt_row->type) && + dhcp_opt->code == opt_row->code) { + hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node); + } else { + sbrec_dhcp_options_delete(opt_row); + } + } else { + sbrec_dhcp_options_delete(opt_row); + } + } + + struct gen_opts_map *opt; + HMAP_FOR_EACH (opt, hmap_node, &dhcp_opts_to_add) { + struct sbrec_dhcp_options *sbrec_dhcp_option = + sbrec_dhcp_options_insert(ctx->ovnsb_txn); + sbrec_dhcp_options_set_name(sbrec_dhcp_option, opt->name); + sbrec_dhcp_options_set_code(sbrec_dhcp_option, opt->code); + sbrec_dhcp_options_set_type(sbrec_dhcp_option, opt->type); + } + + hmap_destroy(&dhcp_opts_to_add); +} + +static void +check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx) +{ + struct hmap dhcpv6_opts_to_add = HMAP_INITIALIZER(&dhcpv6_opts_to_add); + for (size_t i = 0; (i < sizeof(supported_dhcpv6_opts) / + sizeof(supported_dhcpv6_opts[0])); i++) { + hmap_insert(&dhcpv6_opts_to_add, &supported_dhcpv6_opts[i].hmap_node, + dhcp_opt_hash(supported_dhcpv6_opts[i].name)); + } + + const struct sbrec_dhcpv6_options *opt_row, *opt_row_next; + SBREC_DHCPV6_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) { + struct gen_opts_map *dhcp_opt = + dhcp_opts_find(&dhcpv6_opts_to_add, opt_row->name); + if (dhcp_opt) { + hmap_remove(&dhcpv6_opts_to_add, &dhcp_opt->hmap_node); + } else { + sbrec_dhcpv6_options_delete(opt_row); + } + } + + struct gen_opts_map *opt; + HMAP_FOR_EACH(opt, hmap_node, &dhcpv6_opts_to_add) { + struct sbrec_dhcpv6_options *sbrec_dhcpv6_option = + sbrec_dhcpv6_options_insert(ctx->ovnsb_txn); + sbrec_dhcpv6_options_set_name(sbrec_dhcpv6_option, opt->name); + sbrec_dhcpv6_options_set_code(sbrec_dhcpv6_option, opt->code); + sbrec_dhcpv6_options_set_type(sbrec_dhcpv6_option, opt->type); + } + + hmap_destroy(&dhcpv6_opts_to_add); +} + +static void +usage(void) +{ + printf("\ +%s: OVN northbound management daemon\n\ +usage: %s [OPTIONS]\n\ +\n\ +Options:\n\ + --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\ + (default: %s)\n\ + --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\n\ + (default: %s)\n\ + --dry-run start in paused state (do not commit db changes)\n\ + --unixctl=SOCKET override default control socket name\n\ + -h, --help display this help message\n\ + -o, --options list available options\n\ + -V, --version display version information\n\ +", program_name, program_name, default_nb_db(), default_sb_db()); + daemon_usage(); + vlog_usage(); + stream_usage("database", true, true, false); +} + +static void +parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED, + bool *paused) +{ + enum { + OVN_DAEMON_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + SSL_OPTION_ENUMS, + OPT_DRY_RUN, + OPT_DUMMY_NUMA, + }; + static const struct option long_options[] = { + {"ovnsb-db", required_argument, NULL, 'd'}, + {"ovnnb-db", required_argument, NULL, 'D'}, + {"unixctl", required_argument, NULL, 'u'}, + {"help", no_argument, NULL, 'h'}, + {"options", no_argument, NULL, 'o'}, + {"version", no_argument, NULL, 'V'}, + {"dry-run", no_argument, NULL, OPT_DRY_RUN}, + {"dummy-numa", required_argument, NULL, OPT_DUMMY_NUMA}, + OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {NULL, 0, NULL, 0}, + }; + char *short_options = ovs_cmdl_long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + OVN_DAEMON_OPTION_HANDLERS; + VLOG_OPTION_HANDLERS; + + case 'p': + ssl_private_key_file = optarg; + break; + + case 'c': + ssl_certificate_file = optarg; + break; + + case 'C': + ssl_ca_cert_file = optarg; + break; + + case 'd': + ovnsb_db = optarg; + break; + + case 'D': + ovnnb_db = optarg; + break; + + case 'u': + unixctl_path = optarg; + break; + + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'o': + ovs_cmdl_print_options(long_options); + exit(EXIT_SUCCESS); + + case 'V': + ovn_print_version(0, 0); + exit(EXIT_SUCCESS); + + case OPT_DUMMY_NUMA: + ovs_numa_set_dummy(optarg); + break; + + case OPT_DRY_RUN: + *paused = true; + break; + + default: + break; + } + } + + if (!ovnsb_db || !ovnsb_db[0]) { + ovnsb_db = default_sb_db(); + } + + if (!ovnnb_db || !ovnnb_db[0]) { + ovnnb_db = default_nb_db(); + } + + free(short_options); +} + +static void +add_column_noalert(struct ovsdb_idl *idl, + const struct ovsdb_idl_column *column) +{ + ovsdb_idl_add_column(idl, column); + ovsdb_idl_omit_alert(idl, column); +} + +static void +update_ssl_config(void) +{ + if (ssl_private_key_file && ssl_certificate_file) { + stream_ssl_set_key_and_cert(ssl_private_key_file, + ssl_certificate_file); + } + if (ssl_ca_cert_file) { + stream_ssl_set_ca_cert_file(ssl_ca_cert_file, false); + } +} + +int +main(int argc, char *argv[]) +{ + int res = EXIT_SUCCESS; + struct unixctl_server *unixctl; + int retval; + bool exiting; + struct northd_state state = { + .had_lock = false, + .paused = false + }; + + fatal_ignore_sigpipe(); + ovs_cmdl_proctitle_init(argc, argv); + ovn_set_program_name(argv[0]); + service_start(&argc, &argv); + parse_options(argc, argv, &state.paused); + + daemonize_start(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, 0, ovn_northd_exit, &exiting); + unixctl_command_register("pause", "", 0, 0, ovn_northd_pause, &state); + unixctl_command_register("resume", "", 0, 0, ovn_northd_resume, &state); + unixctl_command_register("is-paused", "", 0, 0, ovn_northd_is_paused, + &state); + unixctl_command_register("status", "", 0, 0, ovn_northd_status, &state); + + bool reset_ovnsb_idl_min_index = false; + unixctl_command_register("sb-cluster-state-reset", "", 0, 0, + cluster_state_reset_cmd, + &reset_ovnsb_idl_min_index); + + bool reset_ovnnb_idl_min_index = false; + unixctl_command_register("nb-cluster-state-reset", "", 0, 0, + cluster_state_reset_cmd, + &reset_ovnnb_idl_min_index); + + daemonize_complete(); + + init_hash_row_locks(&lflow_locks); + use_parallel_build = can_parallelize_hashes(false); + + /* We want to detect (almost) all changes to the ovn-nb db. */ + struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( + ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true)); + ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, + &nbrec_nb_global_col_nb_cfg_timestamp); + ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_sb_cfg); + ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, + &nbrec_nb_global_col_sb_cfg_timestamp); + ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_hv_cfg); + ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, + &nbrec_nb_global_col_hv_cfg_timestamp); + + unixctl_command_register("nb-connection-status", "", 0, 0, + ovn_conn_show, ovnnb_idl_loop.idl); + + /* We want to detect only selected changes to the ovn-sb db. */ + struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( + ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true)); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_ipsec); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_logical_flow_col_logical_datapath); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_logical_flow_col_logical_dp_group); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_logical_flow_col_controller_meter); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_logical_flow_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, + &sbrec_table_logical_dp_group); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_logical_dp_group_col_datapaths); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_multicast_group_col_datapath); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_multicast_group_col_tunnel_key); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_datapath_binding_col_tunnel_key); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_datapath_binding_col_load_balancers); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_datapath_binding_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_logical_port); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_tunnel_key); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_parent_port); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_nat_addresses); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_gateway_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_ha_chassis_group); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_virtual_parent); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_up); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_gateway_chassis_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_priority); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_external_ids); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_options); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_external_ids); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_datapath); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_ip); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_mac); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_mac_binding_col_logical_port); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcp_options); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_code); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_type); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_name); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcpv6_options); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_code); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_type); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_name); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_address_set); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_group); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_ports); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dns); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_datapaths); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_records); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_role); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_permissions); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_permission); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_table); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_authorization); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_insert_delete); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis_private); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_chassis_private_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_chassis_private_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_chassis_private_col_nb_cfg); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_chassis_private_col_nb_cfg_timestamp); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_col_chassis); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_col_priority); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis_group); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_group_col_name); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_group_col_ha_chassis); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_group_col_external_ids); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ha_chassis_group_col_ref_chassis); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_igmp_group); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_address); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_datapath); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_ports); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ip_multicast); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_datapath); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_enabled); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_querier); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_eth_src); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_ip4_src); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_ip6_src); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_table_size); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_idle_timeout); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_query_interval); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_ip_multicast_col_query_max_resp); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_service_monitor); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_ip); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_logical_port); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_port); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_options); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_status); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_protocol); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_src_mac); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_src_ip); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_service_monitor_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_load_balancer); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_datapaths); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_vips); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_protocol); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_options); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_load_balancer_col_external_ids); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_bfd); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_logical_port); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_dst_ip); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_status); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_tx); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_rx); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_detect_mult); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_fdb); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_dp_key); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_port_key); + + struct ovsdb_idl_index *sbrec_chassis_by_name + = chassis_index_create(ovnsb_idl_loop.idl); + + struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name + = ha_chassis_group_index_create(ovnsb_idl_loop.idl); + + struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp + = mcast_group_index_create(ovnsb_idl_loop.idl); + + struct ovsdb_idl_index *sbrec_ip_mcast_by_dp + = ip_mcast_index_create(ovnsb_idl_loop.idl); + + unixctl_command_register("sb-connection-status", "", 0, 0, + ovn_conn_show, ovnsb_idl_loop.idl); + + char *ovn_internal_version = ovn_get_internal_version(); + VLOG_INFO("OVN internal version is : [%s]", ovn_internal_version); + + stopwatch_create(NORTHD_LOOP_STOPWATCH_NAME, SW_MS); + stopwatch_create(OVNNB_DB_RUN_STOPWATCH_NAME, SW_MS); + stopwatch_create(OVNSB_DB_RUN_STOPWATCH_NAME, SW_MS); + stopwatch_create(BUILD_LFLOWS_CTX_STOPWATCH_NAME, SW_MS); + stopwatch_create(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, SW_MS); + stopwatch_create(BUILD_LFLOWS_STOPWATCH_NAME, SW_MS); + stopwatch_create(LFLOWS_DATAPATHS_STOPWATCH_NAME, SW_MS); + stopwatch_create(LFLOWS_PORTS_STOPWATCH_NAME, SW_MS); + stopwatch_create(LFLOWS_LBS_STOPWATCH_NAME, SW_MS); + stopwatch_create(LFLOWS_IGMP_STOPWATCH_NAME, SW_MS); + stopwatch_create(LFLOWS_DP_GROUPS_STOPWATCH_NAME, SW_MS); + + /* Main loop. */ + exiting = false; + + while (!exiting) { + update_ssl_config(); + memory_run(); + if (memory_should_report()) { + struct simap usage = SIMAP_INITIALIZER(&usage); + + /* Nothing special to report yet. */ + memory_report(&usage); + simap_destroy(&usage); + } + + if (!state.paused) { + if (!ovsdb_idl_has_lock(ovnsb_idl_loop.idl) && + !ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl)) + { + /* Ensure that only a single ovn-northd is active in the + * deployment by acquiring a lock called "ovn_northd" on the + * southbound database and then only performing DB transactions + * if the lock is held. + */ + ovsdb_idl_set_lock(ovnsb_idl_loop.idl, "ovn_northd"); + } + + struct northd_context ctx = { + .ovnnb_db = ovnnb_db, + .ovnsb_db = ovnsb_db, + .ovnnb_idl = ovnnb_idl_loop.idl, + .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop), + .ovnsb_idl = ovnsb_idl_loop.idl, + .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), + .sbrec_chassis_by_name = sbrec_chassis_by_name, + .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name, + .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp, + .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp, + .lflow_locks = &lflow_locks, + .use_parallel_build = use_parallel_build, + }; + + if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { + VLOG_INFO("ovn-northd lock acquired. " + "This ovn-northd instance is now active."); + state.had_lock = true; + } else if (state.had_lock && + !ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) + { + VLOG_INFO("ovn-northd lock lost. " + "This ovn-northd instance is now on standby."); + state.had_lock = false; + } + + if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { + ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop, + ovn_internal_version); + if (ctx.ovnsb_txn) { + check_and_add_supported_dhcp_opts_to_sb_db(&ctx); + check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx); + check_and_update_rbac(&ctx); + } + } + + ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop); + ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); + } else { + /* ovn-northd is paused + * - we still want to handle any db updates and update the + * local IDL. Otherwise, when it is resumed, the local IDL + * copy will be out of sync. + * - but we don't want to create any txns. + * */ + if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl) || + ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl)) + { + /* make sure we don't hold the lock while paused */ + VLOG_INFO("This ovn-northd instance is now paused."); + ovsdb_idl_set_lock(ovnsb_idl_loop.idl, NULL); + state.had_lock = false; + } + + ovsdb_idl_run(ovnnb_idl_loop.idl); + ovsdb_idl_run(ovnsb_idl_loop.idl); + ovsdb_idl_wait(ovnnb_idl_loop.idl); + ovsdb_idl_wait(ovnsb_idl_loop.idl); + } + + unixctl_server_run(unixctl); + unixctl_server_wait(unixctl); + memory_wait(); + if (exiting) { + poll_immediate_wake(); + } + + if (reset_ovnsb_idl_min_index) { + VLOG_INFO("Resetting southbound database cluster state"); + ovsdb_idl_reset_min_index(ovnsb_idl_loop.idl); + reset_ovnsb_idl_min_index = false; + } + + if (reset_ovnnb_idl_min_index) { + VLOG_INFO("Resetting northbound database cluster state"); + ovsdb_idl_reset_min_index(ovnnb_idl_loop.idl); + reset_ovnnb_idl_min_index = false; + } + + stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); + poll_block(); + if (should_service_stop()) { + exiting = true; + } + stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); + } + + + free(ovn_internal_version); + unixctl_server_destroy(unixctl); + ovsdb_idl_loop_destroy(&ovnnb_idl_loop); + ovsdb_idl_loop_destroy(&ovnsb_idl_loop); + service_stop(); + + exit(res); +} + +static void +ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *exiting_) +{ + bool *exiting = exiting_; + *exiting = true; + + unixctl_command_reply(conn, NULL); +} + +static void +ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *state_) +{ + struct northd_state *state = state_; + state->paused = true; + + unixctl_command_reply(conn, NULL); +} + +static void +ovn_northd_resume(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *state_) +{ + struct northd_state *state = state_; + state->paused = false; + + unixctl_command_reply(conn, NULL); +} + +static void +ovn_northd_is_paused(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *state_) +{ + struct northd_state *state = state_; + if (state->paused) { + unixctl_command_reply(conn, "true"); + } else { + unixctl_command_reply(conn, "false"); + } +} + +static void +ovn_northd_status(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *state_) +{ + struct northd_state *state = state_; + char *status; + + if (state->paused) { + status = "paused"; + } else { + status = state->had_lock ? "active" : "standby"; + } + + /* + * Use a labelled formatted output so we can add more to the status command + * later without breaking any consuming scripts + */ + struct ds s = DS_EMPTY_INITIALIZER; + ds_put_format(&s, "Status: %s\n", status); + unixctl_command_reply(conn, ds_cstr(&s)); + ds_destroy(&s); +} + +static void +cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *idl_reset_) +{ + bool *idl_reset = idl_reset_; + + *idl_reset = true; + poll_immediate_wake(); + unixctl_command_reply(conn, NULL); +}