From patchwork Tue Sep 28 12:56:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533882 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical.com header.i=@canonical.com header.a=rsa-sha256 header.s=20210705 header.b=b3LG8431; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HJfg06GPrz9sXS for ; Tue, 28 Sep 2021 22:57:32 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7B6A6407A2; Tue, 28 Sep 2021 12:57:30 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UiwAv3suwWgZ; Tue, 28 Sep 2021 12:57:27 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id B3AB84156F; Tue, 28 Sep 2021 12:57:19 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DCA69C0046; Tue, 28 Sep 2021 12:57:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2907BC002A for ; Tue, 28 Sep 2021 12:57:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 0D86C40555 for ; Tue, 28 Sep 2021 12:57:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp2.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com 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 k9l6yW7XrseL for ; Tue, 28 Sep 2021 12:57:01 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-0.canonical.com (smtp-relay-canonical-0.canonical.com [185.125.188.120]) by smtp2.osuosl.org (Postfix) with ESMTPS id 7701A4021F for ; Tue, 28 Sep 2021 12:57:01 +0000 (UTC) Received: from frode-threadripper.. (ti0189a330-1161.bb.online.no [88.88.219.141]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-canonical-0.canonical.com (Postfix) with ESMTPSA id D532340DD6; Tue, 28 Sep 2021 12:56:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632833820; bh=p9bcLJiz3xB55SyNyLwNQcoxtnrqLu07etSvSLRilI8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b3LG84319L777ri47a/ZZLKnf0veB9oBBmwK5qP6eU76NPG0zjhUjuvy+JLFg3DAa lbX3BfmS9bHAbxulR9wwXFeq8dU3xdeICWpYxxi8ilAW1pQJVyx805nMHjp3/aNva0 XXjwKKkQvSA1tmUdfFx8YxpDcbguM+SctiwbxBU7yQpT/3eoRfBXkrfpw5VkYAQpmB hSrmMO7IiCgrCmEgSASxdGzjGHXgUEYv5VVSiqpRybf9prW+MaaqbWPlArS7Tog8eo /XYz4NIOcgG1o01i1FjnzqvSePUT+tguKAGuEvpPYaxH5cs8cNdrZ7sIFtcT/K2wbq xF57RwaWFkefA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 14:56:53 +0200 Message-Id: <20210928125653.7329-13-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928125653.7329-1-frode.nordahl@canonical.com> References: <20210928125653.7329-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v5 12/12] controller: Consider plugging of ports on CMS request. 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" When OVN is linked with an appropriate plugging implementation, CMS can request OVN to plug individual lports into the local Open vSwitch instance. The port and instance record will be maintained during the lifetime of the lport and it will be removed on release of lport. Signed-off-by: Frode Nordahl --- controller/ovn-controller.c | 195 ++++++++++++++++++++++++++++++++++++ ovn-nb.xml | 21 ++++ tests/ovn-controller.at | 85 ++++++++++++++++ tests/ovn-macros.at | 2 +- 4 files changed, 302 insertions(+), 1 deletion(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index c615e8ab2..f5516a879 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -937,6 +937,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) binding_register_ovs_idl(ovs_idl); bfd_register_ovs_idl(ovs_idl); physical_register_ovs_idl(ovs_idl); + plug_register_ovs_idl(ovs_idl); } #define SB_NODES \ @@ -2977,6 +2978,171 @@ flow_output_lflow_output_handler(struct engine_node *node, return true; } +static void * +en_plug_provider_lookup_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + +static void +en_plug_provider_lookup_cleanup(void *data OVS_UNUSED) +{ + +} + +static void +en_plug_provider_lookup_run(struct engine_node *node, + void *data OVS_UNUSED) +{ + VLOG_INFO("en_plug_provider_lookup_run"); + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return; + } + + if (plug_provider_run_all()) { + engine_set_node_state(node, EN_UPDATED); + } else { + engine_set_node_state(node, EN_UNCHANGED); + + } +} + + +struct ed_type_plug_provider { + struct shash deleted_iface_ids; + struct shash changed_iface_ids; +}; + +static void * +en_plug_provider_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_plug_provider *data = xzalloc(sizeof *data); + + shash_init(&data->deleted_iface_ids); + shash_init(&data->changed_iface_ids); + return data; +} + +static void +en_plug_provider_cleanup(void *data) +{ + struct ed_type_plug_provider *plug_provider_data = data; + + shash_destroy_free_data(&plug_provider_data->deleted_iface_ids); + shash_destroy_free_data(&plug_provider_data->changed_iface_ids); +} + +static void +init_plug_ctx(struct engine_node *node, + void *data, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + struct ovsrec_open_vswitch_table *ovs_table = + (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( + engine_get_input("OVS_open_vswitch", node)); + struct ovsrec_bridge_table *bridge_table = + (struct ovsrec_bridge_table *)EN_OVSDB_GET( + engine_get_input("OVS_bridge", node)); + const char *chassis_id = get_ovs_chassis_id(ovs_table); + const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table); + + ovs_assert(br_int && chassis_id); + + struct ovsdb_idl_index *sbrec_chassis_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_chassis", node), + "name"); + + const struct sbrec_chassis *chassis + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); + ovs_assert(chassis); + + struct ovsrec_interface_table *iface_table = + (struct ovsrec_interface_table *)EN_OVSDB_GET( + engine_get_input("OVS_interface", node)); + + struct sbrec_port_binding_table *pb_table = + (struct sbrec_port_binding_table *)EN_OVSDB_GET( + engine_get_input("SB_port_binding", node)); + + struct ovsdb_idl_index *sbrec_port_binding_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_port_binding", node), + "name"); + + struct ovsdb_idl_index *ovsrec_port_by_interfaces = + engine_ovsdb_node_get_index( + engine_get_input("OVS_port", node), + "interfaces"); + + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + plug_ctx_in->ovs_idl_txn = engine_get_context()->ovs_idl_txn; + plug_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name; + plug_ctx_in->ovsrec_port_by_interfaces = ovsrec_port_by_interfaces; + plug_ctx_in->ovs_table = ovs_table; + plug_ctx_in->br_int = br_int; + plug_ctx_in->iface_table = iface_table; + plug_ctx_in->chassis_rec = chassis; + plug_ctx_in->port_binding_table = pb_table; + plug_ctx_in->local_bindings = &rt_data->lbinding_data.bindings; + + struct ed_type_plug_provider *plug_provider_data = data; + plug_ctx_out->deleted_iface_ids = &plug_provider_data->deleted_iface_ids; + plug_ctx_out->changed_iface_ids = &plug_provider_data->changed_iface_ids; +} + +static void +en_plug_provider_run(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return; + } + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + plug_run(&plug_ctx_in, &plug_ctx_out); + engine_set_node_state(node, EN_UPDATED); +} + +static bool +plug_provider_port_binding_handler(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return true; + } + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + + return plug_handle_port_binding_changes(&plug_ctx_in, &plug_ctx_out); +} + +static bool +plug_provider_ovs_interface_handler(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return true; + } + + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + + return plug_handle_ovs_interface_changes(&plug_ctx_in, &plug_ctx_out); +} + struct ovn_controller_exit_args { bool *exiting; bool *restart; @@ -3213,6 +3379,11 @@ main(int argc, char *argv[]) ENGINE_NODE(flow_output, "flow_output"); ENGINE_NODE(addr_sets, "addr_sets"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); + /* The plug provider has two engine nodes. One that checks for and reacts + * to change to plug provider lookup tables, and another that reacts to + * change to OVS interface, OVN Port_Binding and runtime data */ + ENGINE_NODE(plug_provider_lookup, "plug_provider_lookup"); + ENGINE_NODE(plug_provider, "plug_provider"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); SB_NODES @@ -3239,6 +3410,24 @@ main(int argc, char *argv[]) engine_add_input(&en_non_vif_data, &en_ovs_interface, non_vif_data_ovs_iface_handler); + engine_add_input(&en_plug_provider, &en_plug_provider_lookup, NULL); + engine_add_input(&en_plug_provider, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_plug_provider, &en_ovs_bridge, NULL); + engine_add_input(&en_plug_provider, &en_sb_chassis, NULL); + engine_add_input(&en_plug_provider, &en_runtime_data, + engine_noop_handler); + engine_add_input(&en_plug_provider, &en_sb_port_binding, + plug_provider_port_binding_handler); + engine_add_input(&en_plug_provider, &en_ovs_port, + engine_noop_handler); + engine_add_input(&en_plug_provider, &en_ovs_interface, + plug_provider_ovs_interface_handler); + /* The node needs somewhere to output to run */ + engine_add_input(&en_flow_output, &en_plug_provider, + engine_noop_handler); + + + /* Note: The order of inputs is important, all OVS interface changes must * be handled before any ct_zone changes. */ @@ -3812,6 +4001,12 @@ main(int argc, char *argv[]) } } } + struct ed_type_plug_provider *plug_provider_data = engine_get_data( + &en_plug_provider); + if (plug_provider_data) { + plug_finish_deleted(&plug_provider_data->deleted_iface_ids); + plug_finish_changed(&plug_provider_data->changed_iface_ids); + } } ovsdb_idl_track_clear(ovnsb_idl_loop.idl); diff --git a/ovn-nb.xml b/ovn-nb.xml index 390cc5a44..2774eb255 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1028,6 +1028,27 @@ DHCP reply.

+ + + + If set, OVN will attempt to perform plugging of this VIF. In order + to get this port plugged by the OVN controller, OVN must be built + with support for VIF plugging. The default behavior is for the CMS + to do the VIF plugging. Each plug provider have their own options + namespaced by name, for example "plug:representor:key". + + Please refer to the plug provider documentation located in + Documentation/topics/plug_providers/ for more information. + + + + Requested MTU for plugged interfaces. When set the OVN controller + will fill the column + of the Open vSwitch database's + table. This in turn will + make OVS vswitchd update the MTU of the linked interface. + + diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index a1169c569..2400aa1b7 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -795,6 +795,91 @@ OVN_CLEANUP_SBOX([hv]) OVN_CLEANUP_VSWITCH([main]) as ovn-sb OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - plugging]) +AT_KEYWORDS([plugging]) + +ovn_start + +net_add n1 +sim_add hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovn-appctl -t ovn-controller vlog/set + +sim_add hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovn-appctl -t ovn-controller vlog/set + +check ovn-nbctl ls-add lsw0 +check ovn-nbctl lsp-add lsw0 lsp1 +check ovn-nbctl lsp-set-addresses lsp1 "f0:00:00:00:00:01 172.16.0.101" +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=hv1 \ + options:plug-type=dummy \ + options:plug-mtu-request=42 + +check ovn-nbctl lsp-add lsw0 lsp2 +check ovn-nbctl lsp-set-addresses lsp2 "f0:00:00:00:00:02 172.16.0.102" +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp2 \ + options:requested-chassis=hv2 \ + options:plug-type=dummy \ + options:plug-mtu-request=42 + +wait_column "true" Port_Binding up logical_port=lsp1 +wait_column "true" Port_Binding up logical_port=lsp2 + +as hv1 + +# Check that the lport was plugged +AT_CHECK([as hv1 ovs-vsctl find interface name=lsp1 options:plug-dummy-option=value | grep -q "options.*value"]) +AT_CHECK([as hv1 ovs-vsctl find interface name=lsp1 mtu_request=42 | grep -q "mtu_request.*42"]) + +# Check that updating the lport updates the local iface +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=hv1 \ + options:plug-type=dummy \ + options:plug-mtu-request=43 +OVS_WAIT_UNTIL([ + as hv1 ovs-vsctl find interface mtu_request=43 | grep -q "mtu_request.*43" +]) + +# Check that local modification of iface will trigger ovn-controller to update +# the iface record +iface_uuid=$(as hv1 ovs-vsctl --bare --columns _uuid find interface name=lsp1) +as hv1 ovs-vsctl set interface ${iface_uuid} mtu_request=44 +OVS_WAIT_UNTIL([ + as hv1 ovs-vsctl find interface mtu_request=43 | grep -q "mtu_request.*43" +]) + +lsp_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp1) +iface_uuid=$(as hv1 ovs-vsctl --bare --columns _uuid find Interface name=lsp1) +# Check that pointing requested-chassis somewhere else will unplug the port +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=non-existent-chassis +OVS_WAIT_UNTIL([ + grep -q "Releasing lport lsp1" hv1/ovn-controller.log +]) +OVS_WAIT_UNTIL([ + grep -q "Unplugging port lsp1" hv1/ovn-controller.log +]) +as hv1 ovs-vsctl find interface name=lsp1 +OVS_WAIT_UNTIL([ + ! as hv1 ovs-vsctl get Interface ${iface_uuid} _uuid +]) + +# Check that removing an lport will unplug it +lsp_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp2) +iface_uuid=$(as hv2 ovs-vsctl --bare --columns _uuid find Interface name=lsp1) +check ovn-nbctl --wait=sb lsp-del ${lsp_uuid} +OVS_WAIT_UNTIL([ + ! as hv2 ovs-vsctl get Interface ${iface_uuid} _uuid +]) +OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP ]) diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at index f06f2e68e..b3c2d72fa 100644 --- a/tests/ovn-macros.at +++ b/tests/ovn-macros.at @@ -327,7 +327,7 @@ ovn_az_attach() { -- --may-exist add-br br-int \ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \ || return 1 - start_daemon ovn-controller || return 1 + start_daemon ovn-controller --enable-dummy-plug || return 1 } # ovn_attach NETWORK BRIDGE IP [MASKLEN]