From patchwork Tue Oct 19 10:21:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543162 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=jaa/5I1e; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HYVDF0vtxz9sPB for ; Tue, 19 Oct 2021 21:22:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8841C40529; Tue, 19 Oct 2021 10:22:18 +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 HiFT7HwOQn_h; Tue, 19 Oct 2021 10:22:16 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id E18AE404EF; Tue, 19 Oct 2021 10:22:14 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D91D2C002A; Tue, 19 Oct 2021 10:22:12 +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 1084CC000D for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 66D3B81AF6 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.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 e7V6uL4dA0wv for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp1.osuosl.org (Postfix) with ESMTPS id E00A081AAC for ; Tue, 19 Oct 2021 10:22:07 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 3F4783F0B8 for ; Tue, 19 Oct 2021 10:22:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638926; bh=VW5LT5BaQZ5ZjBdpSen1UMLXyRUtCDQ97vMV84jPmZ4=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jaa/5I1eub2auekZZMmxlb1lB5gSX22YUzn2HHgE9Uc8pUro85Hale33zu4AFzEPV og5Vsk9nz7vv5fjHc4rjaEzu9Gee9EYObz+ZCpkY6uaYTwI7u7+N+AK/S9iINFW09u uyyqznz8P+OACor0colFo+cJXSjP58qxGPpkzB5CjXgIqQfnqNBg2rL85ujFt6hgD6 OPg3S668k7LgGm9fPFcoDm1wktXf2Kzfh/ZF2kYphkuCZNXNm7IQPc5kjLJArQ9emG FTyQE94ktsTUFOWbZv4an4uMl4gyWt28vz04A7vo7DGdjJ7+0+jTb9EiVkl+2hVA2N LQxq2svuMLIHA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:54 +0200 Message-Id: <20211019102205.3837601-1-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019101348.3833652-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 01/12] ovn-sb: Add requested_chassis column to Port_Binding. 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" To allow for ovn-controller to efficiently monitor all Port_Binding records destined to it, we add a new requested_chassis column with weakRef to the Chassis table. The ovn-controller can monitor this column and only process records for its chassis UUID before having claimed the port. northd will fill this column with UUID of Chassis referenced in Logical_Switch_Port options:requested-chassis by name or hostname. In a subsequent update to the controller we will improve the efficiency of the requested-chassis feature by using the new column instead of each chassis performing string comparison on this option for every Port_Binding record processed. Note that the CMS facing Northbound Logical_Switch_Port:options API remains the same. Signed-off-by: Frode Nordahl --- lib/chassis-index.c | 24 +++++++++ lib/chassis-index.h | 3 ++ northd/northd.c | 45 ++++++++++++++-- northd/northd.h | 1 + northd/ovn-northd.c | 9 +++- northd/ovn_northd.dl | 123 ++++++++++++++++++++++++++++++++++++++++--- ovn-sb.ovsschema | 10 ++-- ovn-sb.xml | 21 ++++++++ tests/ovn-northd.at | 45 ++++++++++++++++ 9 files changed, 266 insertions(+), 15 deletions(-) diff --git a/lib/chassis-index.c b/lib/chassis-index.c index 13120fe3e..4b38036cb 100644 --- a/lib/chassis-index.c +++ b/lib/chassis-index.c @@ -22,6 +22,12 @@ chassis_index_create(struct ovsdb_idl *idl) return ovsdb_idl_index_create1(idl, &sbrec_chassis_col_name); } +struct ovsdb_idl_index * +chassis_hostname_index_create(struct ovsdb_idl *idl) +{ + return ovsdb_idl_index_create1(idl, &sbrec_chassis_col_hostname); +} + /* Finds and returns the chassis with the given 'name', or NULL if no such * chassis exists. */ const struct sbrec_chassis * @@ -40,6 +46,24 @@ chassis_lookup_by_name(struct ovsdb_idl_index *sbrec_chassis_by_name, return retval; } +/* Finds and returns the chassis with the given 'hostname', or NULL if no such + * chassis exists. */ +const struct sbrec_chassis * +chassis_lookup_by_hostname(struct ovsdb_idl_index *sbrec_chassis_by_hostname, + const char *hostname) +{ + struct sbrec_chassis *target = sbrec_chassis_index_init_row( + sbrec_chassis_by_hostname); + sbrec_chassis_index_set_hostname(target, hostname); + + struct sbrec_chassis *retval = sbrec_chassis_index_find( + sbrec_chassis_by_hostname, target); + + sbrec_chassis_index_destroy_row(target); + + return retval; +} + struct ovsdb_idl_index * chassis_private_index_create(struct ovsdb_idl *idl) { diff --git a/lib/chassis-index.h b/lib/chassis-index.h index b9b331f34..bc654da13 100644 --- a/lib/chassis-index.h +++ b/lib/chassis-index.h @@ -19,9 +19,12 @@ struct ovsdb_idl; struct ovsdb_idl_index *chassis_index_create(struct ovsdb_idl *); +struct ovsdb_idl_index *chassis_hostname_index_create(struct ovsdb_idl *); const struct sbrec_chassis *chassis_lookup_by_name( struct ovsdb_idl_index *sbrec_chassis_by_name, const char *name); +const struct sbrec_chassis *chassis_lookup_by_hostname( + struct ovsdb_idl_index *sbrec_chassis_by_hostname, const char *hostname); struct ovsdb_idl_index *chassis_private_index_create(struct ovsdb_idl *); diff --git a/northd/northd.c b/northd/northd.c index 32ab3baf3..88a419390 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -3079,6 +3079,7 @@ ovn_update_ipv6_prefix(struct hmap *ports) static void ovn_port_update_sbrec(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, const struct ovn_port *op, struct hmap *chassis_qdisc_queues, struct sset *active_ha_chassis_grps) @@ -3260,6 +3261,36 @@ ovn_port_update_sbrec(struct northd_context *ctx, * ha_chassis_group cleared in the same transaction. */ sbrec_port_binding_set_ha_chassis_group(op->sb, NULL); } + + const char *requested_chassis; /* May be NULL. */ + bool reset_requested_chassis = false; + requested_chassis = smap_get(&op->nbsp->options, + "requested-chassis"); + if (requested_chassis) { + const struct sbrec_chassis *chassis; /* May be NULL. */ + chassis = chassis_lookup_by_name(sbrec_chassis_by_name, + requested_chassis); + chassis = chassis ? chassis : chassis_lookup_by_hostname( + sbrec_chassis_by_hostname, requested_chassis); + + if (chassis) { + sbrec_port_binding_set_requested_chassis(op->sb, chassis); + } else { + reset_requested_chassis = true; + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT( + 1, 1); + VLOG_WARN_RL( + &rl, + "Unknown chassis '%s' set as " + "options:requested-chassis on LSP '%s'.", + requested_chassis, op->nbsp->name); + } + } else if (op->sb->requested_chassis) { + reset_requested_chassis = true; + } + if (reset_requested_chassis) { + sbrec_port_binding_set_requested_chassis(op->sb, NULL); + } } else { const char *chassis = NULL; if (op->peer && op->peer->od && op->peer->od->nbr) { @@ -3940,6 +3971,7 @@ ovn_port_allocate_key(struct northd_context *ctx, struct hmap *ports, static void build_ports(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct hmap *datapaths, struct hmap *ports) { struct ovs_list sb_only, nb_only, both; @@ -3995,6 +4027,7 @@ build_ports(struct northd_context *ctx, tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp); } ovn_port_update_sbrec(ctx, sbrec_chassis_by_name, + sbrec_chassis_by_hostname, op, &chassis_qdisc_queues, &active_ha_chassis_grps); } @@ -4002,7 +4035,8 @@ build_ports(struct northd_context *ctx, /* Add southbound record for each unmatched northbound record. */ LIST_FOR_EACH_SAFE (op, next, list, &nb_only) { op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn); - ovn_port_update_sbrec(ctx, sbrec_chassis_by_name, op, + ovn_port_update_sbrec(ctx, sbrec_chassis_by_name, + sbrec_chassis_by_hostname, op, &chassis_qdisc_queues, &active_ha_chassis_grps); sbrec_port_binding_set_logical_port(op->sb, op->key); @@ -14354,6 +14388,7 @@ build_meter_groups(struct northd_context *ctx, static void ovnnb_db_run(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct ovsdb_idl_loop *sb_loop, struct hmap *datapaths, struct hmap *ports, struct ovs_list *lr_list, @@ -14455,7 +14490,8 @@ ovnnb_db_run(struct northd_context *ctx, build_datapaths(ctx, datapaths, lr_list); build_ovn_lbs(ctx, datapaths, &lbs); build_lrouter_lbs(datapaths, &lbs); - build_ports(ctx, sbrec_chassis_by_name, datapaths, ports); + build_ports(ctx, sbrec_chassis_by_name, sbrec_chassis_by_hostname, + datapaths, ports); build_ovn_lr_lbs(datapaths, &lbs); build_ovn_lb_svcs(ctx, ports, &lbs); build_ipam(datapaths, ports); @@ -14802,6 +14838,7 @@ ovnsb_db_run(struct northd_context *ctx, void ovn_db_run(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct ovsdb_idl_loop *ovnsb_idl_loop, const char *ovn_internal_version) { @@ -14814,8 +14851,8 @@ ovn_db_run(struct northd_context *ctx, int64_t start_time = time_wall_msec(); stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); - ovnnb_db_run(ctx, sbrec_chassis_by_name, ovnsb_idl_loop, - &datapaths, &ports, &lr_list, start_time, + ovnnb_db_run(ctx, sbrec_chassis_by_name, sbrec_chassis_by_hostname, + ovnsb_idl_loop, &datapaths, &ports, &lr_list, start_time, ovn_internal_version); stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec()); stopwatch_start(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec()); diff --git a/northd/northd.h b/northd/northd.h index ffa2bbb4e..d2a931ada 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -34,6 +34,7 @@ struct northd_context { void ovn_db_run(struct northd_context *ctx, struct ovsdb_idl_index *sbrec_chassis_by_name, + struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct ovsdb_idl_loop *ovnsb_idl_loop, const char *ovn_internal_version); diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 39aa96055..9c33378fb 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -716,6 +716,8 @@ main(int argc, char *argv[]) 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); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_requested_chassis); 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); @@ -787,6 +789,7 @@ main(int argc, char *argv[]) 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_hostname); 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); @@ -895,6 +898,9 @@ main(int argc, char *argv[]) struct ovsdb_idl_index *sbrec_chassis_by_name = chassis_index_create(ovnsb_idl_loop.idl); + struct ovsdb_idl_index *sbrec_chassis_by_hostname + = chassis_hostname_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); @@ -975,7 +981,8 @@ main(int argc, char *argv[]) } if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { - ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop, + ovn_db_run(&ctx, sbrec_chassis_by_name, + sbrec_chassis_by_hostname, &ovnsb_idl_loop, ovn_internal_version); if (ctx.ovnsb_txn) { check_and_add_supported_dhcp_opts_to_sb_db(&ctx); diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 99772932d..817b11bdc 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -105,6 +105,22 @@ sb::Out_Datapath_Binding(uuid, tunkey, load_balancers, external_ids) :- */ var load_balancers = set_empty(). +function get_requested_chassis(options: Map) : istring = { + var requested_chassis = match(options.get(i"requested-chassis")) { + None -> i"", + Some{requested_chassis} -> requested_chassis, + }; + requested_chassis +} + +relation RequestedChassis( + name: istring, + chassis: uuid, +) +RequestedChassis(name, chassis) :- + sb::Chassis(._uuid = chassis, .name=name). +RequestedChassis(hostname, chassis) :- + sb::Chassis(._uuid = chassis, .hostname=hostname). /* Proxy table for Out_Datapath_Binding: contains all Datapath_Binding fields, * except tunnel id, which is allocated separately (see PortTunKeyAllocation). */ @@ -120,10 +136,95 @@ relation OutProxy_Port_Binding ( tag: Option, mac: Set, nat_addresses: Set, - external_ids: Map + external_ids: Map, + requested_chassis: Option ) -/* Case 1: Create a Port_Binding per logical switch port that is not of type "router" */ +/* Case 1a: Create a Port_Binding per logical switch port that is not of type + * "router" */ +OutProxy_Port_Binding(._uuid = lsp._uuid, + .logical_port = lsp.name, + .__type = lsp.__type, + .gateway_chassis = set_empty(), + .ha_chassis_group = sp.hac_group_uuid, + .options = options, + .datapath = sw._uuid, + .parent_port = lsp.parent_name, + .tag = tag, + .mac = lsp.addresses, + .nat_addresses = set_empty(), + .external_ids = eids, + .requested_chassis = None) :- + sp in &SwitchPort(.lsp = lsp, .sw = sw), + SwitchPortNewDynamicTag(lsp._uuid, opt_tag), + var tag = match (opt_tag) { + None -> lsp.tag, + Some{t} -> Some{t} + }, + lsp.__type != i"router", + var chassis_name_or_hostname = get_requested_chassis(lsp.options), + chassis_name_or_hostname == i"", + var eids = { + var eids = lsp.external_ids; + match (lsp.external_ids.get(i"neutron:port_name")) { + None -> (), + Some{name} -> eids.insert(i"name", name) + }; + eids + }, + var options = { + var options = lsp.options; + if (sw.other_config.get(i"vlan-passthru") == Some{i"true"}) { + options.insert(i"vlan-passthru", i"true") + }; + options + }. + +/* Case 1b: Create a Port_Binding per logical switch port that is not of type + * "router" and has options "requested-chassis" pointing at chassis name or + * hostname. */ +OutProxy_Port_Binding(._uuid = lsp._uuid, + .logical_port = lsp.name, + .__type = lsp.__type, + .gateway_chassis = set_empty(), + .ha_chassis_group = sp.hac_group_uuid, + .options = options, + .datapath = sw._uuid, + .parent_port = lsp.parent_name, + .tag = tag, + .mac = lsp.addresses, + .nat_addresses = set_empty(), + .external_ids = eids, + .requested_chassis = Some{requested_chassis}) :- + sp in &SwitchPort(.lsp = lsp, .sw = sw), + SwitchPortNewDynamicTag(lsp._uuid, opt_tag), + var tag = match (opt_tag) { + None -> lsp.tag, + Some{t} -> Some{t} + }, + lsp.__type != i"router", + var chassis_name_or_hostname = get_requested_chassis(lsp.options), + chassis_name_or_hostname != i"", + RequestedChassis(chassis_name_or_hostname, requested_chassis), + var eids = { + var eids = lsp.external_ids; + match (lsp.external_ids.get(i"neutron:port_name")) { + None -> (), + Some{name} -> eids.insert(i"name", name) + }; + eids + }, + var options = { + var options = lsp.options; + if (sw.other_config.get(i"vlan-passthru") == Some{i"true"}) { + options.insert(i"vlan-passthru", i"true") + }; + options + }. + +/* Case 1c: Create a Port_Binding per logical switch port that is not of type + * "router" and has options "requested-chassis" pointing at non-existent + * chassis name or hostname. */ OutProxy_Port_Binding(._uuid = lsp._uuid, .logical_port = lsp.name, .__type = lsp.__type, @@ -135,7 +236,8 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .tag = tag, .mac = lsp.addresses, .nat_addresses = set_empty(), - .external_ids = eids) :- + .external_ids = eids, + .requested_chassis = None) :- sp in &SwitchPort(.lsp = lsp, .sw = sw), SwitchPortNewDynamicTag(lsp._uuid, opt_tag), var tag = match (opt_tag) { @@ -143,6 +245,9 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, Some{t} -> Some{t} }, lsp.__type != i"router", + var chassis_name_or_hostname = get_requested_chassis(lsp.options), + chassis_name_or_hostname != i"", + not RequestedChassis(chassis_name_or_hostname, _), var eids = { var eids = lsp.external_ids; match (lsp.external_ids.get(i"neutron:port_name")) { @@ -186,7 +291,8 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .tag = None, .mac = lsp.addresses, .nat_addresses = nat_addresses, - .external_ids = eids) :- + .external_ids = eids, + .requested_chassis = None) :- SwitchPortLBIPs(.port = &SwitchPort{.lsp = lsp, .sw = sw, .peer = peer}, .lbips = lbips), var eids = { @@ -280,7 +386,8 @@ OutProxy_Port_Binding(._uuid = lrp._uuid, .tag = None, // always empty for router ports .mac = set_singleton(i"${lrp.mac} ${lrp.networks.map(ival).to_vec().join(\" \")}"), .nat_addresses = set_empty(), - .external_ids = lrp.external_ids) :- + .external_ids = lrp.external_ids, + .requested_chassis = None) :- rp in &RouterPort(.lrp = lrp, .router = router, .peer = peer), RouterPortRAOptionsComplete(lrp._uuid, options0), (var __type, var options1) = match (router.options.get(i"chassis")) { @@ -475,7 +582,8 @@ OutProxy_Port_Binding(._uuid = cr_lrp_uuid, .tag = None, //always empty for router ports .mac = set_singleton(i"${lrp.mac} ${lrp.networks.map(ival).to_vec().join(\" \")}"), .nat_addresses = set_empty(), - .external_ids = lrp.external_ids) :- + .external_ids = lrp.external_ids, + .requested_chassis = None) :- DistributedGatewayPort(lrp, lr_uuid, cr_lrp_uuid), DistributedGatewayPortHAChassisGroup(lrp, hacg_uuid), var redirect_type = match (lrp.options.get(i"redirect-type")) { @@ -520,7 +628,8 @@ sb::Out_Port_Binding(._uuid = pbinding._uuid, .mac = pbinding.mac, .nat_addresses = pbinding.nat_addresses, .external_ids = pbinding.external_ids, - .up = Some{up}) :- + .up = Some{up}, + .requested_chassis = pbinding.requested_chassis) :- pbinding in OutProxy_Port_Binding(), PortTunKeyAllocation(pbinding._uuid, tunkey), QueueIDAllocation(pbinding._uuid, qid), diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index e5ab41db9..122614dd5 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.20.0", - "cksum": "605270161 26670", + "version": "20.21.0", + "cksum": "2362446865 26963", "tables": { "SB_Global": { "columns": { @@ -232,7 +232,11 @@ "external_ids": {"type": {"key": "string", "value": "string", "min": 0, - "max": "unlimited"}}}, + "max": "unlimited"}}, + "requested_chassis": {"type": {"key": {"type": "uuid", + "refTable": "Chassis", + "refType": "weak"}, + "min": 0, "max": 1}}}, "indexes": [["datapath", "tunnel_key"], ["logical_port"]], "isRoot": true}, "MAC_Binding": { diff --git a/ovn-sb.xml b/ovn-sb.xml index 2d4d47d10..150051f26 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -2983,6 +2983,27 @@ tcp.flags = RST; + + This column exists so that the ovn-controller can effectively monitor + all records destined for it, and is a + supplement to the option. The option is still required so that + the ovn-controller can check the CMS intent when the chassis pointed + to does not currently exist, which for example occurs when the + ovn-controller is stopped without passing the --restart argument. + + This column must be a + record. This is populated by + ovn-northd when the + is defined and contains a string matching the name or hostname of an + existing chassis. + diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 8b9049899..544820764 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -5401,3 +5401,48 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=?? AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([check options:requested-chassis fills requested_chassis col]) +ovn_start NORTHD_TYPE + +# Add chassis ch1. +check ovn-sbctl chassis-add ch1 geneve 127.0.0.2 +check ovn-sbctl chassis-add ch2 geneve 127.0.0.3 + +wait_row_count Chassis 2 + +ch1_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name="ch1"` +ch2_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name="ch2"` + +check ovn-sbctl set chassis $ch2_uuid hostname=ch2-hostname + +ovn-nbctl ls-add S1 +ovn-nbctl --wait=sb lsp-add S1 S1-vm1 +ovn-nbctl --wait=sb lsp-add S1 S1-vm2 + +wait_row_count Port_Binding 1 logical_port=S1-vm1 requested_chassis!=$ch1_uuid +wait_row_count Port_Binding 1 logical_port=S1-vm2 requested_chassis!=$ch2_uuid + +ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \ + options:requested-chassis=ch1 + +wait_row_count Port_Binding 1 logical_port=S1-vm1 requested_chassis=$ch1_uuid + +ovn-nbctl --wait=sb set logical_switch_port S1-vm2 \ + options:requested-chassis=ch2-hostname + +wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis=$ch2_uuid + +ovn-nbctl --wait=sb remove logical_switch_port S1-vm2 \ + options requested-chassis=ch2-hostname + +wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis!=$ch2_uuid + +ovn-nbctl --wait=sb set logical_switch_port S1-vm2 \ + options:requested-chassis=ch2 + +wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis=$ch2_uuid + +AT_CLEANUP +]) From patchwork Tue Oct 19 10:21:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543160 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=DSynTAef; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HYVD70nD4z9sPB for ; Tue, 19 Oct 2021 21:22:15 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 565C9404DF; Tue, 19 Oct 2021 10:22:13 +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 IZH69COrRBZC; Tue, 19 Oct 2021 10:22:12 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 04E96401BD; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C51F6C000F; Tue, 19 Oct 2021 10:22:10 +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 27844C000D for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 0971081B60 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.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 xlTk7DRDNCds for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp1.osuosl.org (Postfix) with ESMTPS id 233CA81AF6 for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 9D7D141BF0 for ; Tue, 19 Oct 2021 10:22:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638926; bh=NHGJfTh8KZQiOYU1cNhAhKWd73pswKfhmWLqnDv/+eY=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DSynTAefeHZXiANy9Br8LMpZPg+qMLRYZ6t0d/DYemN0nwxlrp/73U3FQr+0uG4VG Y1OvilhLRsejEtqsS8zZ04j2P9C3BeRQzqZY/U/3O+SprpAJ+AZBbGgiID/udZsK4K LX2Ky41lOtQg1/Y5tDHukSWawwbr0o5k0mum11N0q7fahBN0G5FQiRMtljYWZNwnFq OMAufKMTL52eDJ3/9lS9Ml/rpo+t77AHYL+mCVPgt8xSZZzkkUNHrcPoJ8w3lHX9ap XkVsyk30/H021plHMNOPlB/su7HGQxioEMHAaIIIfQyHmcil5Szus6EDtAU2TJu+I6 vbWWl4z5U2KmA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:55 +0200 Message-Id: <20211019102205.3837601-2-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 02/12] controller: Make use of Port_Binding:requested_chassis. 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" Improve the efficiency of the requested-chassis feature by using the new Southbound Port_Binding:requested_chassis column instead of each chassis performing string comparison for every Port_Binding record processed. Add test cases for currently uncovered existing functionality. One for setting the requested-chassis option to the empty string (""), this is in use by some CMS systems in conjunction with localports. Another for checking there is no release/claim thrashing on startup related to the controller removing and re-creating its chassis record on stop/start. Signed-off-by: Frode Nordahl --- controller/binding.c | 50 ++++++++++++------- controller/ovn-controller.c | 3 ++ tests/ovn.at | 99 +++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 18 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index c037b2352..aac96694a 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1056,11 +1056,27 @@ is_binding_lport_this_chassis(struct binding_lport *b_lport, static bool can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec, - const char *requested_chassis) -{ - return !requested_chassis || !requested_chassis[0] - || !strcmp(requested_chassis, chassis_rec->name) - || !strcmp(requested_chassis, chassis_rec->hostname); + const struct sbrec_port_binding *pb) +{ + /* We need to check for presence of the requested-chassis option in + * addittion to checking the pb->requested_chassis column because this + * column will be set to NULL whenever the option points to a non-existent + * chassis. As the controller routinely clears its own chassis record this + * might occur more often than one might think. */ + const char *requested_chassis_option = smap_get(&pb->options, + "requested-chassis"); + if (requested_chassis_option && requested_chassis_option[0] + && !pb->requested_chassis) { + /* The requested-chassis option is set, but the requested_chassis + * column is not filled. This means that the chassis the option + * points to is currently not running, or is in the process of starting + * up. In this case we must fall back to comparing the strings to + * avoid release/claim thrashing. */ + return !strcmp(requested_chassis_option, chassis_rec->name) + || !strcmp(requested_chassis_option, chassis_rec->hostname); + } + return !requested_chassis_option || !requested_chassis_option[0] + || chassis_rec == pb->requested_chassis; } /* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER, @@ -1098,7 +1114,7 @@ release_binding_lport(const struct sbrec_chassis *chassis_rec, static bool consider_vif_lport_(const struct sbrec_port_binding *pb, - bool can_bind, const char *vif_chassis, + bool can_bind, struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out, struct binding_lport *b_lport, @@ -1139,7 +1155,10 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, "requested-chassis %s", pb->logical_port, b_ctx_in->chassis_rec->name, - vif_chassis); + pb->requested_chassis ? + pb->requested_chassis->name : "(option points at " + "non-existent " + "chassis)"); } } @@ -1162,9 +1181,7 @@ consider_vif_lport(const struct sbrec_port_binding *pb, struct local_binding *lbinding, struct hmap *qos_map) { - const char *vif_chassis = smap_get(&pb->options, "requested-chassis"); - bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, - vif_chassis); + bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); if (!lbinding) { lbinding = local_binding_find(&b_ctx_out->lbinding_data->bindings, @@ -1194,8 +1211,8 @@ consider_vif_lport(const struct sbrec_port_binding *pb, } } - return consider_vif_lport_(pb, can_bind, vif_chassis, b_ctx_in, - b_ctx_out, b_lport, qos_map); + return consider_vif_lport_(pb, can_bind, b_ctx_in, b_ctx_out, + b_lport, qos_map); } static bool @@ -1279,12 +1296,9 @@ consider_container_lport(const struct sbrec_port_binding *pb, } ovs_assert(parent_b_lport && parent_b_lport->pb); - const char *vif_chassis = smap_get(&parent_b_lport->pb->options, - "requested-chassis"); - bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, - vif_chassis); + bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); - return consider_vif_lport_(pb, can_bind, vif_chassis, b_ctx_in, b_ctx_out, + return consider_vif_lport_(pb, can_bind, b_ctx_in, b_ctx_out, container_b_lport, qos_map); } @@ -1333,7 +1347,7 @@ consider_virtual_lport(const struct sbrec_port_binding *pb, } } - if (!consider_vif_lport_(pb, true, NULL, b_ctx_in, b_ctx_out, + if (!consider_vif_lport_(pb, true, b_ctx_in, b_ctx_out, virtual_b_lport, qos_map)) { return false; } diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 4202f32cc..a1382a67b 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -232,6 +232,9 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, sbrec_port_binding_add_clause_chassis(&pb, OVSDB_F_EQ, &chassis->header_.uuid); + sbrec_port_binding_add_clause_requested_chassis( + &pb, OVSDB_F_EQ, &chassis->header_.uuid); + /* Ensure that we find out about l2gateway and l3gateway ports that * should be present on this chassis. Otherwise, we might never find * out about those ports, if their datapaths don't otherwise have a VIF diff --git a/tests/ovn.at b/tests/ovn.at index 05eac4e5f..7cfdede77 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -28690,3 +28690,102 @@ grep lr0-sw1], [1], []) OVN_CLEANUP([hv1]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller requested-chassis localport]) +ovn_start + +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl add-port br-int lport \ + -- set interface lport external_ids:iface-id=sw0-lport ofport-request=13 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl add-port br-int lport \ + -- set interface lport external_ids:iface-id=sw0-lport ofport-request=13 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl lsp-add sw0 sw0-lport +check ovn-nbctl lsp-set-addresses sw0-lport "50:54:00:00:00:01 10.0.0.2" +check ovn-nbctl lsp-set-type sw0-lport localport + +# First confirm operation without requested-chassis +check_row_count Port_Binding 1 logical_port=sw0-lport 'up=true' + +AT_CHECK([as hv1 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [0], []) +AT_CHECK([as hv2 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [0], []) + +# Set requested-chassis to one of the HVs +check ovn-nbctl --wait=sb lsp-set-options sw0-lport requested-chassis="hv1" +AT_CHECK([as hv1 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [0], []) +AT_CHECK([as hv2 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [1], []) + +# Set requested-chassis to empty string +check ovn-nbctl --wait=sb lsp-set-options sw0-lport requested-chassis="" +AT_CHECK([as hv1 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [0], []) +AT_CHECK([as hv2 ovs-ofctl -O OpenFlow15 dump-flows br-int table=0 | grep -q in_port=13], [0], []) + +OVN_CLEANUP([hv1],[hv2]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - requested-chassis claim lport on startup]) +ovn_start + +net_add n1 +sim_add hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int vif1 -- \ + set Interface vif1 external-ids:iface-id=lsp1 + +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 set Logical_Switch_Port lsp1 \ + options:requested-chassis=hv1 + +wait_for_ports_up lsp1 + +lsp1_pb_uuid=$(ovn-sbctl --bare --columns _uuid \ + find Port_Binding logical_port=lsp1) + +# Stop ovn-controller on hv1 without the --restart flag +check as hv1 ovn-appctl -t ovn-controller exit + +# Pause northd to guarantee that ovn-controller starts before requested_chassis +# column is filled. +check as northd-backup ovn-appctl -t ovn-northd pause +check as northd ovn-appctl -t ovn-northd pause + +# Wait until requested_chassis is empty +OVS_WAIT_UNTIL([ + test x"3" = x$(ovn-sbctl get Port_Binding ${lsp1_pb_uuid} requested_chassis) | wc -c +]) + +# Start controller and wait for it to register itself +as hv1 start_daemon ovn-controller +wait_column "hv1" Chassis name + +# Start northd and wait for events to be processed +check as northd ovn-appctl -t ovn-northd resume +check as northd-backup ovn-appctl -t ovn-northd resume + +wait_for_ports_up lsp1 + +# Confirm that the controller did not refuse to claim its port on the initial +# run. +AT_CHECK([grep -q "Not claiming" hv1/ovn-controller.log], [1], []) + +OVN_CLEANUP([hv1]) +AT_CLEANUP +]) From patchwork Tue Oct 19 10:21:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543167 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=CR2+qlsP; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (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 4HYVDN6fS1z9sPB for ; Tue, 19 Oct 2021 21:22:28 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id E7D9983CB0; Tue, 19 Oct 2021 10:22:25 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org 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 Kt5CqXVDTc5B; Tue, 19 Oct 2021 10:22:21 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 743D783C55; Tue, 19 Oct 2021 10:22:19 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 88B9CC0031; Tue, 19 Oct 2021 10:22:15 +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 1C3CEC0024 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id F2DEB81B10 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org 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 Q5ehnh5vLQTa for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp1.osuosl.org (Postfix) with ESMTPS id 830C781B17 for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id E8FEF41BF5 for ; Tue, 19 Oct 2021 10:22:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638927; bh=Ge8gZWwck7np+yo+7hQKLNyeNDiptsrz0DU0E1Nb3QM=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=CR2+qlsPHLxdveA//eYW0STYZvNOCigB4g/gQi915Z2Du97BGG0Zx9gDVxLzZdB0m 7DAkxTJQBzc5FW2pV8OthIOFXAjNTOZd6B+VqEznNJhZm5lMru3QJN9dyGFvnoUkOo qt/qCI/0mMTt0wzBrq6eQNOzpwzKXDBBRgQA9rIbdJJsMGoKH2ChbIXNDeSpWxLTg3 xTzjXYKTWLkD35qTO3CuiW/IkZyp29PzxHgHLZGu67VHPYZe5+TKeJgA+/fbSSB+q8 5TcIpWd8PddIER6ewjT8/57rhfMMEfqGNDl5KP9sjXvw6t2OFhJ1DlCckzxk32MfBf 7ns7tJy9S7QiQ== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:56 +0200 Message-Id: <20211019102205.3837601-3-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 03/12] controller: Move OVS port functions to new module. 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" Up until now the controller patch module has been the only consumer of functions to maintain OVS ports and interfaces. With the introduction of infrastructure for plugging providers these functions will also be consumed by the controller binding module. As such we introduce a new module called ovsport where these shared utility functions can live and be consumed by multiple modules. Signed-off-by: Frode Nordahl --- controller/automake.mk | 4 +- controller/ovsport.c | 266 +++++++++++++++++++++++++++++++++++++++++ controller/ovsport.h | 60 ++++++++++ 3 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 controller/ovsport.c create mode 100644 controller/ovsport.h diff --git a/controller/automake.mk b/controller/automake.mk index 41f907d6e..ad2d68af2 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -35,7 +35,9 @@ controller_ovn_controller_SOURCES = \ controller/mac-learn.c \ controller/mac-learn.h \ controller/local_data.c \ - controller/local_data.h + controller/local_data.h \ + controller/ovsport.h \ + controller/ovsport.c controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += controller/ovn-controller.8 diff --git a/controller/ovsport.c b/controller/ovsport.c new file mode 100644 index 000000000..ec38c3fca --- /dev/null +++ b/controller/ovsport.c @@ -0,0 +1,266 @@ +/* Copyright (c) 2021 Canonical + * + * 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 "ovsport.h" + +#include "lib/vswitch-idl.h" +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(ovsport); + +/* Create a port and interface record and add it to 'bridge' in the Open + * vSwitch database represented by 'ovs_idl_txn'. + * + * 'name' is required and is used both for the name of the port and interface + * records. Depending on the contents of the optional 'iface_type' parameter + * the name may need to refer to an existing interface in the system. It is + * the caller's responsibility to ensure that no other port with the desired + * name already exists. + * + * 'iface_type' optionally specifies the type of interface, otherwise set it to + * NULL. + * + * 'port_external_ids' - the contents of the map will be used to fill the + * external_ids column of the created port record, otherwise set it to NULL. + * + * 'iface_external_ids' - the contents of the map will be used to fill the + * external_ids column of the created interface record, otherwise set it to + * NULL. + * + * 'iface_options' - the contents of the map will be used to fill the options + * column of the created interface record, otherwise set it to NULL. + * + * 'iface_mtu_request' - if a value > 0 is provided it will be filled into the + * mtu_request column of the created interface record. */ +void +ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn, + const struct ovsrec_bridge *bridge, + const char *name, + const char *iface_type, + const struct smap *port_external_ids, + const struct smap *iface_external_ids, + const struct smap *iface_options, + const int64_t iface_mtu_request) +{ + struct ovsrec_interface *iface; + iface = ovsrec_interface_insert(ovs_idl_txn); + ovsrec_interface_set_name(iface, name); + if (iface_type) { + ovsrec_interface_set_type(iface, iface_type); + } + ovsrec_interface_set_external_ids(iface, iface_external_ids); + ovsrec_interface_set_options(iface, iface_options); + ovsrec_interface_set_mtu_request( + iface, &iface_mtu_request, iface_mtu_request > 0); + + struct ovsrec_port *port; + port = ovsrec_port_insert(ovs_idl_txn); + ovsrec_port_set_name(port, name); + ovsrec_port_set_interfaces(port, &iface, 1); + ovsrec_port_set_external_ids(port, port_external_ids); + + ovsrec_bridge_verify_ports(bridge); + ovsrec_bridge_update_ports_addvalue(bridge, port); +} + +/* Remove 'port' from 'bridge' and delete the 'port' record and any records + * with a weakRef to it. */ +void +ovsport_remove(const struct ovsrec_bridge *bridge, + const struct ovsrec_port *port) +{ + ovsrec_bridge_verify_ports(bridge); + ovsrec_port_verify_interfaces(port); + for (struct ovsrec_interface *iface = *port->interfaces; + iface - *port->interfaces < port->n_interfaces; + iface++) { + ovsrec_interface_delete(iface); + } + ovsrec_bridge_update_ports_delvalue(bridge, port); + ovsrec_port_delete(port); +} + +static void update_interface_smap_column( + const struct ovsrec_interface *, const struct smap *, + const struct smap *, void (*fsetkey)(const struct ovsrec_interface *, + const char *, const char *)); +static void maintain_interface_smap_column( + const struct ovsrec_interface *, const struct sset *, + const struct smap *, const struct smap *, + void (*fsetkey)(const struct ovsrec_interface *, const char *, + const char *), + void (*fdelkey)(const struct ovsrec_interface *, + const char *)); + +/* Update interface record as represented by 'iface'. + * + * 'type' optionally specifies the type of interface, to unset type set to an + * empty string, to not update type set to NULL. + * + * 'external_ids' optionally provide a map of external_ids to update, to not + * update external_ids set to NULL. + * + * 'mnt_external_ids' optionally provide set of 'external_ids' to maintain. + * When set the function will make sure that all keys in the 'mnt_external_ids' + * set have values from the 'external_ids' map in the database. Every key that + * exists in 'mnt_external_ids' with no corresponding key in 'external_ids' + * will be removed from the database if present. Set to NULL to not maintain + * the record in this way. + * + * 'options' optionally provide a map of options to update, to not + * update options set to NULL. + * + * 'mnt_options' optionally provide set of 'options' to maintain. + * When set the function will make sure that all keys in the 'mnt_options' set + * have values from the 'options' map in the database. Every key that exists + * in 'mnt_options' with no corresponding key in 'options' will be removed from + * the database if present. Set to NULL to not maintain the record in this + * way. + * + * 'iface_mtu_request' - if a value > 0 is provided it will be filled into the + * mtu_request column of the created interface record. */ +void +ovsport_update_iface(const struct ovsrec_interface *iface, + const char *type, + const struct smap *external_ids, + const struct sset *mnt_external_ids, + const struct smap *options, + const struct sset *mnt_options, + const int64_t mtu_request) +{ + if (type && strcmp(iface->type, type)) { + ovsrec_interface_verify_type(iface); + ovsrec_interface_set_type(iface, type); + } + + if (external_ids && mnt_external_ids) { + ovsrec_interface_verify_external_ids(iface); + maintain_interface_smap_column( + iface, mnt_external_ids, external_ids, &iface->external_ids, + ovsrec_interface_update_external_ids_setkey, + ovsrec_interface_update_external_ids_delkey); + } else if (external_ids) { + ovsrec_interface_verify_external_ids(iface); + update_interface_smap_column( + iface, external_ids, &iface->external_ids, + ovsrec_interface_update_external_ids_setkey); + } + + if (options && mnt_options) { + ovsrec_interface_verify_options(iface); + maintain_interface_smap_column( + iface, mnt_options, options, &iface->options, + ovsrec_interface_update_options_setkey, + ovsrec_interface_update_options_delkey); + } else if (options) { + ovsrec_interface_verify_options(iface); + update_interface_smap_column( + iface, options, &iface->options, + ovsrec_interface_update_options_setkey); + } + + if (mtu_request > 0) { + if ((iface->mtu_request && *iface->mtu_request != mtu_request) + || !iface->mtu_request) + { + ovsrec_interface_verify_mtu_request(iface); + ovsrec_interface_set_mtu_request( + iface, &mtu_request, mtu_request > 0); + } + } else if (iface->mtu_request) { + ovsrec_interface_verify_mtu_request(iface); + ovsrec_interface_update_mtu_request_delvalue(iface, + *iface->mtu_request); + } +} + +const struct ovsrec_port * +ovsport_lookup_by_interfaces( + struct ovsdb_idl_index *ovsrec_port_by_interfaces, + struct ovsrec_interface **interfaces, + const size_t n_interfaces) +{ + struct ovsrec_port *port = ovsrec_port_index_init_row( + ovsrec_port_by_interfaces); + ovsrec_port_index_set_interfaces(port, interfaces, n_interfaces); + + const struct ovsrec_port *retval = ovsrec_port_index_find( + ovsrec_port_by_interfaces, port); + + ovsrec_port_index_destroy_row(port); + + return retval; +} + +const struct +ovsrec_port * ovsport_lookup_by_interface( + struct ovsdb_idl_index *ovsrec_port_by_interfaces, + struct ovsrec_interface *interface) +{ + struct ovsrec_interface *interfaces[] = {interface}; + + return ovsport_lookup_by_interfaces(ovsrec_port_by_interfaces, + interfaces, 1); +} + +/* Update an interface map column with the key/value pairs present in the + * provided smap, only applying changes when necessary. */ +static void +update_interface_smap_column( + const struct ovsrec_interface *iface, + const struct smap *smap, + const struct smap *db_smap, + void (*fsetkey)(const struct ovsrec_interface *, + const char *, const char *)) +{ + struct smap_node *node; + + SMAP_FOR_EACH (node, smap) { + const char *db_value = smap_get(db_smap, node->key); + + if (!db_value || strcmp(db_value, node->value)) { + fsetkey(iface, node->key, node->value); + } + } +} + +/* Like update_interface_smap_column, but also takes an sset with all the keys + * we want to maintain. Any key present in the sset but not in the provided + * smap will be removed from the database if present there. */ +static void +maintain_interface_smap_column( + const struct ovsrec_interface *iface, + const struct sset *mnt_items, + const struct smap *smap, + const struct smap *db_smap, + void (*fsetkey)(const struct ovsrec_interface *, + const char *, const char *), + void (*fdelkey)(const struct ovsrec_interface *, + const char *)) +{ + const char *ref_name; + + SSET_FOR_EACH (ref_name, mnt_items) { + const char *value = smap_get(smap, ref_name); + const char *db_value = smap_get(db_smap, ref_name); + if (!value && db_value) { + fdelkey(iface, ref_name); + } else if (value && (!db_value || strcmp(db_value, value))) + { + fsetkey(iface, ref_name, value); + } + } +} diff --git a/controller/ovsport.h b/controller/ovsport.h new file mode 100644 index 000000000..e355ff7ff --- /dev/null +++ b/controller/ovsport.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2021 Canonical + * + * 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 OVSPORT_H +#define OVSPORT_H 1 + +/* OVS Ports + * ========= + * + * This module contains utility functions for adding, removing and maintaining + * ports and their interface records on OVS bridges. */ + +#include "smap.h" +#include "sset.h" + +#include +#include + +struct ovsdb_idl_txn; +struct ovsrec_bridge; +struct ovsrec_port; +struct ovsrec_interface; +struct ovsdb_idl_index; + +void ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn, + const struct ovsrec_bridge *bridge, + const char *name, + const char *iface_type, + const struct smap *port_external_ids, + const struct smap *iface_external_ids, + const struct smap *iface_options, + const int64_t iface_mtu_request); +void ovsport_remove(const struct ovsrec_bridge *bridge, + const struct ovsrec_port *port); +void ovsport_update_iface(const struct ovsrec_interface *iface, + const char *type, + const struct smap *external_ids, + const struct sset *mnt_external_ids, + const struct smap *options, + const struct sset *mnt_options, + const int64_t mtu_request); +const struct ovsrec_port * ovsport_lookup_by_interfaces( + struct ovsdb_idl_index *, struct ovsrec_interface **, + const size_t n_interfaces); +const struct ovsrec_port * ovsport_lookup_by_interface( + struct ovsdb_idl_index *, struct ovsrec_interface *); + +#endif /* lib/ovsport.h */ From patchwork Tue Oct 19 10:21:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543161 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=hMbmCY10; 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 4HYVD95xPNz9sPB for ; Tue, 19 Oct 2021 21:22:17 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id B9E6540739; Tue, 19 Oct 2021 10:22:15 +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 LHV6g0h6Njdh; Tue, 19 Oct 2021 10:22:14 +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 A523C40703; Tue, 19 Oct 2021 10:22:13 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C7BD0C0026; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 86542C000D for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 731E94026B for ; Tue, 19 Oct 2021 10:22:09 +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 atqhX_NP2FPC for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp4.osuosl.org (Postfix) with ESMTPS id CB9784023F for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 4190241BF6 for ; Tue, 19 Oct 2021 10:22:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638927; bh=wfhStxVbg/X5SMKKSdhAa+c99+UoZWKNxffSDVizhvk=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hMbmCY10RmFuRTUA83Sv0z2t6y8NxboBIkbI7EoiYheAvvjReRVp02hQnGmQYeZg8 01bLwzCz9cSL9hh0Ef7okh7nCtpcl+bcb9OpYEZWpG+d12QuxLuz7WNAnihc5oqSe6 GuC96poslHhR2RH5Wycb447Ayhm2WmHEEb5Z0JQPed96OmVGV8DgSGTkYf1QhVMLW9 vRgcn3bUY1n/YamF5VUa5W5frBRIPA+Pr9QAkoQ9c22x9eRPh7byWw+Mbi7RmImdgL 7TDy98X3K5rBvVmyEUx4aqn3PjOt2pGfq/Q5gucTSHxiNIDhVBCi7AaDv+dnYSmhts yWyfvcQu/nwRA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:57 +0200 Message-Id: <20211019102205.3837601-4-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 04/12] patch: Consume ovsport functions. 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" Make use of the common functions for maintaining OVS ports. Signed-off-by: Frode Nordahl --- controller/patch.c | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/controller/patch.c b/controller/patch.c index a661025da..0d0d53894 100644 --- a/controller/patch.c +++ b/controller/patch.c @@ -16,6 +16,7 @@ #include #include "patch.h" +#include "ovsport.h" #include "hash.h" #include "lflow.h" @@ -91,28 +92,10 @@ create_patch_port(struct ovsdb_idl_txn *ovs_idl_txn, "ovn-controller: creating patch port '%s' from '%s' to '%s'", src_name, src->name, dst->name); - struct ovsrec_interface *iface; - iface = ovsrec_interface_insert(ovs_idl_txn); - ovsrec_interface_set_name(iface, src_name); - ovsrec_interface_set_type(iface, "patch"); - const struct smap options = SMAP_CONST1(&options, "peer", dst_name); - ovsrec_interface_set_options(iface, &options); - - struct ovsrec_port *port; - port = ovsrec_port_insert(ovs_idl_txn); - ovsrec_port_set_name(port, src_name); - ovsrec_port_set_interfaces(port, &iface, 1); - const struct smap ids = SMAP_CONST1(&ids, key, value); - ovsrec_port_set_external_ids(port, &ids); - - struct ovsrec_port **ports; - ports = xmalloc(sizeof *ports * (src->n_ports + 1)); - memcpy(ports, src->ports, sizeof *ports * src->n_ports); - ports[src->n_ports] = port; - ovsrec_bridge_verify_ports(src); - ovsrec_bridge_set_ports(src, ports, src->n_ports + 1); - - free(ports); + const struct smap if_options = SMAP_CONST1(&if_options, "peer", dst_name); + const struct smap port_ids = SMAP_CONST1(&port_ids, key, value); + ovsport_create(ovs_idl_txn, src, src_name, "patch", &port_ids, NULL, + &if_options, 0); } static void @@ -130,17 +113,7 @@ remove_port(const struct ovsrec_bridge_table *bridge_table, if (bridge->ports[i] != port) { continue; } - struct ovsrec_port **new_ports; - new_ports = xmemdup(bridge->ports, - sizeof *new_ports * (bridge->n_ports - 1)); - if (i != bridge->n_ports - 1) { - /* Removed port was not last */ - new_ports[i] = bridge->ports[bridge->n_ports - 1]; - } - ovsrec_bridge_verify_ports(bridge); - ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1); - free(new_ports); - ovsrec_port_delete(port); + ovsport_remove(bridge, port); return; } } From patchwork Tue Oct 19 10:21:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543164 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=pSPSL2/R; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::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 4HYVDJ6p21z9sPB for ; Tue, 19 Oct 2021 21:22:24 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id BF4894077F; Tue, 19 Oct 2021 10:22:20 +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 LCP1sNEi4kwg; Tue, 19 Oct 2021 10:22:19 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id A3F004075E; Tue, 19 Oct 2021 10:22:17 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BA055C002F; Tue, 19 Oct 2021 10:22:14 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id EB970C0022 for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id CA77B4023F for ; Tue, 19 Oct 2021 10:22:09 +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 ziifT6rhgoRk for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp4.osuosl.org (Postfix) with ESMTPS id 211AB40250 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id A053D41C06 for ; Tue, 19 Oct 2021 10:22:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638927; bh=PTxyAw3celBQYwXBnSmWt0TASaXGTZiT5kcgg7nA9zU=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pSPSL2/R5qYl7HgSvxrhEpIqRTJ2owo1WWJzHM3RE7ZwMZ/LBWtFXZs6nxyELWbA4 aqBoWVL0FPqOWzkqpY/0Yi3mo+Bk++y+DJ6Tr7ZA8Um0C93h05wKdn/RMu+bTZWjgB yVb3McW4BavhZuQvOogF1EYWxPzbo0C/e5pwfofTtfiXlFFld2Bh4xEieOGi1H2HhS kT1iIAwpKwecwB1YQovAJrB3n4oLgx2S3IqqDqWIbQAhqL2lJGa+OISUfvqRzc5695 1Du3asFaEuDOJe/e5wT+Txrh0TKAfVExNre+nCzkEV7anc8WMiyAT/7C3E8y0syVTd kJCSEcc5zFeHQ== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:58 +0200 Message-Id: <20211019102205.3837601-5-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 05/12] binding: Move can_bind helper to lport module. 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" The `can_bind_on_this_chassis` helper is useful outside of the binding module. Since it is related to lports renaming it to `lport_can_bind_on_this_chassis` and putting it into the lport module appears to be appropriate. Signed-off-by: Frode Nordahl --- controller/binding.c | 29 ++--------------------------- controller/lport.c | 25 +++++++++++++++++++++++++ controller/lport.h | 3 +++ 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index aac96694a..ecfddced5 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1054,31 +1054,6 @@ is_binding_lport_this_chassis(struct binding_lport *b_lport, b_lport->pb->chassis == chassis); } -static bool -can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec, - const struct sbrec_port_binding *pb) -{ - /* We need to check for presence of the requested-chassis option in - * addittion to checking the pb->requested_chassis column because this - * column will be set to NULL whenever the option points to a non-existent - * chassis. As the controller routinely clears its own chassis record this - * might occur more often than one might think. */ - const char *requested_chassis_option = smap_get(&pb->options, - "requested-chassis"); - if (requested_chassis_option && requested_chassis_option[0] - && !pb->requested_chassis) { - /* The requested-chassis option is set, but the requested_chassis - * column is not filled. This means that the chassis the option - * points to is currently not running, or is in the process of starting - * up. In this case we must fall back to comparing the strings to - * avoid release/claim thrashing. */ - return !strcmp(requested_chassis_option, chassis_rec->name) - || !strcmp(requested_chassis_option, chassis_rec->hostname); - } - return !requested_chassis_option || !requested_chassis_option[0] - || chassis_rec == pb->requested_chassis; -} - /* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER, * 'false' otherwise. */ static bool @@ -1181,7 +1156,7 @@ consider_vif_lport(const struct sbrec_port_binding *pb, struct local_binding *lbinding, struct hmap *qos_map) { - bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); + bool can_bind = lport_can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); if (!lbinding) { lbinding = local_binding_find(&b_ctx_out->lbinding_data->bindings, @@ -1296,7 +1271,7 @@ consider_container_lport(const struct sbrec_port_binding *pb, } ovs_assert(parent_b_lport && parent_b_lport->pb); - bool can_bind = can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); + bool can_bind = lport_can_bind_on_this_chassis(b_ctx_in->chassis_rec, pb); return consider_vif_lport_(pb, can_bind, b_ctx_in, b_ctx_out, container_b_lport, qos_map); diff --git a/controller/lport.c b/controller/lport.c index 25b4ef200..5ad40f6d3 100644 --- a/controller/lport.c +++ b/controller/lport.c @@ -108,6 +108,31 @@ lport_get_l3gw_peer(const struct sbrec_port_binding *pb, return get_peer_lport(pb, sbrec_port_binding_by_name); } +bool +lport_can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec, + const struct sbrec_port_binding *pb) +{ + /* We need to check for presence of the requested-chassis option in + * addittion to checking the pb->requested_chassis column because this + * column will be set to NULL whenever the option points to a non-existent + * chassis. As the controller routinely clears its own chassis record this + * might occur more often than one might think. */ + const char *requested_chassis_option = smap_get(&pb->options, + "requested-chassis"); + if (requested_chassis_option && requested_chassis_option[0] + && !pb->requested_chassis) { + /* The requested-chassis option is set, but the requested_chassis + * column is not filled. This means that the chassis the option + * points to is currently not running, or is in the process of starting + * up. In this case we must fall back to comparing the strings to + * avoid release/claim thrashing. */ + return !strcmp(requested_chassis_option, chassis_rec->name) + || !strcmp(requested_chassis_option, chassis_rec->hostname); + } + return !requested_chassis_option || !requested_chassis_option[0] + || chassis_rec == pb->requested_chassis; +} + const struct sbrec_datapath_binding * datapath_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, uint64_t dp_key) diff --git a/controller/lport.h b/controller/lport.h index 43b3d714d..4716c58f9 100644 --- a/controller/lport.h +++ b/controller/lport.h @@ -43,6 +43,9 @@ const struct sbrec_port_binding *lport_lookup_by_key( struct ovsdb_idl_index *sbrec_port_binding_by_key, uint64_t dp_key, uint64_t port_key); +bool lport_can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec, + const struct sbrec_port_binding *pb); + const struct sbrec_datapath_binding *datapath_lookup_by_key( struct ovsdb_idl_index *sbrec_datapath_binding_by_key, uint64_t dp_key); From patchwork Tue Oct 19 10:21:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543166 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=pHeED6ow; 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 4HYVDN13Lyz9sPf for ; Tue, 19 Oct 2021 21:22:28 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 6C434407BB; Tue, 19 Oct 2021 10:22:26 +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 ilp1YdrOj7gQ; Tue, 19 Oct 2021 10:22:25 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id 8911F4071B; Tue, 19 Oct 2021 10:22:24 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B5D7EC0036; Tue, 19 Oct 2021 10:22:18 +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 2AC8BC000F for ; Tue, 19 Oct 2021 10:22:12 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 2B94A81AF6 for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.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 TXWPhCfngQ82 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp1.osuosl.org (Postfix) with ESMTPS id 9693481AAC for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id E55B141C08 for ; Tue, 19 Oct 2021 10:22:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638928; bh=lxIZ/oZ90vCTtqWXp9uXF+RsCudRscI26bQb7alNM3U=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pHeED6ow1VSkxU8zSRHBonuYWp/ChNeLp78TMZeg2IR3ogMFG2+qkSPRR+D/FxOB1 wqPu67Q6HQcTVmlC9Z8uzpqb2Tr+iTTw7zOl4OCzwS/tLsbJV1R4rdCi+omSTIiP2u XK3nw7VsLjgK1ookehDPyfCAMA2l0dVfN2p3hXl9p5tWVYAi7aFB6uB5LuK1uylJX9 S2TpfNoloUrYCJmUkD17wbm0dGCOlRpUV4ZP3xmmV4GOquJdy0St7aQwHeRnEUKRSZ ao56rYnZb3+D3/zM+lzC9szcf79B0CqTwXDlPmvoQM6bvQAbxFsxs5eyvxamG9gFeT R5c3lsveqWoAA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:21:59 +0200 Message-Id: <20211019102205.3837601-6-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 06/12] physical: Make use of common can bind helper. 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" The physical module currently has an inverse version of `lport_can_bind_on_this_chassis` duplicated in its code. Make use of the common helper instead. Signed-off-by: Frode Nordahl --- controller/physical.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/controller/physical.c b/controller/physical.c index ac16a6a3b..aa1d44bc6 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -1069,11 +1069,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, } else { ofport = local_binding_get_lport_ofport(local_bindings, binding->logical_port); - const char *requested_chassis = smap_get(&binding->options, - "requested-chassis"); - if (ofport && requested_chassis && requested_chassis[0] && - strcmp(requested_chassis, chassis->name) && - strcmp(requested_chassis, chassis->hostname)) { + if (ofport && !lport_can_bind_on_this_chassis(chassis, binding)) { /* Even though there is an ofport for this port_binding, it is * requested on a different chassis. So ignore this ofport. */ From patchwork Tue Oct 19 10:22:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543163 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=V/S76/IA; 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 4HYVDF6qjSz9sPf for ; Tue, 19 Oct 2021 21:22:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id B31CF4074F; Tue, 19 Oct 2021 10:22:19 +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 mlsUi7uRDIl8; Tue, 19 Oct 2021 10:22:17 +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 2FAE34074E; Tue, 19 Oct 2021 10:22:16 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D18B1C002D; Tue, 19 Oct 2021 10:22:13 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8A665C000D for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 8770260B3A for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp3.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jhXjlXCf2nFO for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp3.osuosl.org (Postfix) with ESMTPS id CAAE6605A0 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 40E6D41C09 for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638928; bh=OImPuqS7zBWjSs1zTMK/OtgyFO2OzLGk8XUtxlmvQk0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=V/S76/IAY9hDGTNYR/V36MzOeF+NJsbOAUgUleFj43axJrJdX5x2HCj7mgoMDhJpT fYVWKFjMoB2cknJ7tvfkAMMMqzQEMxBDXulymDHHYCCK5XvRTLgKIE/VDLnUGFBpqU GePuwwwTf/Q79Z/6O9vYxXCewUyIiwku8i0Ff595mQUqoTmyto8FmgoOWrIyDU0cex 87ZUaiF6mHHPTU/AX9qLW6l6Mwa+uCN1xmpnjfWDwdNY6RoRIAjghqso8bKopWGOR/ 8uQYY+skoJMn7Ml2Xa+69XI10Pw3t3gwbSTCRi+/yy+Br3l5lCW2w2fEm+acsNym/0 aWzsC+nqrOAWg== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:00 +0200 Message-Id: <20211019102205.3837601-7-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 07/12] binding: Make local_binding data structure public. 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" The binding module maintains a shash of lports bound to the local chassis. Other modules have interest in the same data for lookup, and it would be wasteful to reimplement the same data structure elsewhere. The incremental processing engine already makes sharing of the data between nodes safe and convenient and this change makes it possible for a different module to consume the data. Signed-off-by: Frode Nordahl --- controller/binding.c | 34 +--------------------------------- controller/binding.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index ecfddced5..2fde7629c 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -507,36 +507,6 @@ update_active_pb_ras_pd(const struct sbrec_port_binding *pb, } } -/* Local bindings. binding.c module binds the logical port (represented by - * Port_Binding rows) and sets the 'chassis' column when it sees the - * OVS interface row (of type "" or "internal") with the - * external_ids:iface-id= set. - * - * This module also manages the other port_bindings. - * - * To better manage the local bindings with the associated OVS interfaces, - * 'struct local_binding' is used. A shash of these local bindings is - * maintained with the 'external_ids:iface-id' as the key to the shash. - * - * struct local_binding has 3 main fields: - * - name : 'external_ids:iface-id' of the OVS interface (key). - * - OVS interface row object. - * - List of 'binding_lport' objects with the primary lport - * in the front of the list (if present). - * - * An object of 'struct local_binding' is created: - * - For each interface that has external_ids:iface-id configured. - * - * - For each port binding (also referred as lport) of type 'LP_VIF' - * if it is a parent lport of container lports even if there is no - * corresponding OVS interface. - */ -struct local_binding { - char *name; - const struct ovsrec_interface *iface; - struct ovs_list binding_lports; -}; - /* This structure represents a logical port (or port binding) * which is associated with 'struct local_binding'. * @@ -559,8 +529,6 @@ static struct local_binding *local_binding_create( const char *name, const struct ovsrec_interface *); static void local_binding_add(struct shash *local_bindings, struct local_binding *); -static struct local_binding *local_binding_find( - const struct shash *local_bindings, const char *name); static void local_binding_destroy(struct local_binding *, struct shash *binding_lports); static void local_binding_delete(struct local_binding *, @@ -2520,7 +2488,7 @@ local_binding_create(const char *name, const struct ovsrec_interface *iface) return lbinding; } -static struct local_binding * +struct local_binding * local_binding_find(const struct shash *local_bindings, const char *name) { return shash_find_data(local_bindings, name); diff --git a/controller/binding.h b/controller/binding.h index 70cc37c78..430a8d9b1 100644 --- a/controller/binding.h +++ b/controller/binding.h @@ -104,11 +104,45 @@ struct binding_ctx_out { struct if_status_mgr *if_mgr; }; +/* Local bindings. binding.c module binds the logical port (represented by + * Port_Binding rows) and sets the 'chassis' column when it sees the + * OVS interface row (of type "" or "internal") with the + * external_ids:iface-id= set. + * + * This module also manages the other port_bindings. + * + * To better manage the local bindings with the associated OVS interfaces, + * 'struct local_binding' is used. A shash of these local bindings is + * maintained with the 'external_ids:iface-id' as the key to the shash. + * + * struct local_binding has 3 main fields: + * - name : 'external_ids:iface-id' of the OVS interface (key). + * - OVS interface row object. + * - List of 'binding_lport' objects with the primary lport + * in the front of the list (if present). + * + * An object of 'struct local_binding' is created: + * - For each interface that has external_ids:iface-id configured. + * + * - For each port binding (also referred as lport) of type 'LP_VIF' + * if it is a parent lport of container lports even if there is no + * corresponding OVS interface. + */ +struct local_binding { + char *name; + const struct ovsrec_interface *iface; + struct ovs_list binding_lports; +}; + + struct local_binding_data { struct shash bindings; struct shash lports; }; +struct local_binding *local_binding_find( + const struct shash *local_bindings, const char *name); + void local_binding_data_init(struct local_binding_data *); void local_binding_data_destroy(struct local_binding_data *); From patchwork Tue Oct 19 10:22:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543165 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=ADbfY+s/; 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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HYVDM4nmDz9sPB for ; Tue, 19 Oct 2021 21:22:27 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id B2CDA406EE; Tue, 19 Oct 2021 10:22:24 +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 Kgr0zHmVzSL0; Tue, 19 Oct 2021 10:22:22 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 5E8BA40544; Tue, 19 Oct 2021 10:22:21 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C9FCFC002A; Tue, 19 Oct 2021 10:22:16 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4780DC0022 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D1FA5605A0 for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp3.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id D2y-LYpvcEVC for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp3.osuosl.org (Postfix) with ESMTPS id 237CA60B1E for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 8D3FC3F0B8 for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638928; bh=6yfBy4GYaJiPo5YgBvIWiQN5vyEytFQt+cAAm0/i6y8=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ADbfY+s/Dl225pwH9ID4IFKMF23WzlFeteQRtwooIE/KFPohIlf//GymUlcQRR0TW vdkAbwL/Q5hgGz2g5xtNIBLNZql4g5edqgT7f/ME0IxURuHbvUgrDRwk28X22oIb07 893479kt6wXDZcbE01JH2FJ5PFOMX573ePyavuhiPJqJhVc2NqhAj6CAQLtb9ewNMa f0eDtjU4S6dJzztEULUbaof+v2y2LFGSX3dp87n1KX3HWX0vIKVWQTYqa2xhtxsiQs 4KO9laJKNkidKmBDxMNbdOaTiatAk84aWHW3k1Az9kJGVcsDSlFbVXSOKaArNMaaII h5z6KwLNQz2CA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:01 +0200 Message-Id: <20211019102205.3837601-8-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 08/12] ovn-controller: Move shared functions to ovn-util. 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" The `get_tunnel_type` (and associated enum) and `get_bridge` functions are used in modules other than the `ovn-controller` module. Since the `ovn-controller` module also has the `main` function this organization makes it hard or impossible to unit test. Signed-off-by: Frode Nordahl --- controller/local_data.h | 11 +++-------- controller/ovn-controller.c | 26 -------------------------- lib/ovn-util.c | 27 +++++++++++++++++++++++++++ lib/ovn-util.h | 18 +++++++++++++++++- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/controller/local_data.h b/controller/local_data.h index f6317e9ca..c790bc722 100644 --- a/controller/local_data.h +++ b/controller/local_data.h @@ -21,6 +21,9 @@ #include "lib/smap.h" #include "lib/simap.h" +/* OVN includes. */ +#include "lib/ovn-util.h" + struct sbrec_datapath_binding; struct sbrec_port_binding; struct sbrec_chassis; @@ -120,14 +123,6 @@ void tracked_datapath_lport_add(const struct sbrec_port_binding *, struct hmap *tracked_datapaths); void tracked_datapaths_destroy(struct hmap *tracked_datapaths); -/* Must be a bit-field ordered from most-preferred (higher number) to - * least-preferred (lower number). */ -enum chassis_tunnel_type { - GENEVE = 1 << 2, - STT = 1 << 1, - VXLAN = 1 << 0 -}; - /* Maps from a chassis to the OpenFlow port number of the tunnel that can be * used to reach that chassis. */ struct chassis_tunnel { diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index a1382a67b..c015f936c 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -140,32 +140,6 @@ struct pending_pkt { /* Registered ofctrl seqno type for nb_cfg propagation. */ static size_t ofctrl_seq_type_nb_cfg; -uint32_t -get_tunnel_type(const char *name) -{ - if (!strcmp(name, "geneve")) { - return GENEVE; - } else if (!strcmp(name, "stt")) { - return STT; - } else if (!strcmp(name, "vxlan")) { - return VXLAN; - } - - return 0; -} - -const struct ovsrec_bridge * -get_bridge(const struct ovsrec_bridge_table *bridge_table, const char *br_name) -{ - const struct ovsrec_bridge *br; - OVSREC_BRIDGE_TABLE_FOR_EACH (br, bridge_table) { - if (!strcmp(br->name, br_name)) { - return br; - } - } - return NULL; -} - static unsigned int update_sb_monitors(struct ovsdb_idl *ovnsb_idl, const struct sbrec_chassis *chassis, diff --git a/lib/ovn-util.c b/lib/ovn-util.c index 683ca37d9..19e3c2343 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -23,6 +23,7 @@ #include "include/ovn/actions.h" #include "openvswitch/ofp-parse.h" #include "openvswitch/vlog.h" +#include "lib/vswitch-idl.h" #include "ovn-dirs.h" #include "ovn-nb-idl.h" #include "ovn-sb-idl.h" @@ -791,3 +792,29 @@ ddlog_err(const char *msg) VLOG_ERR("%s", msg); } #endif + +uint32_t +get_tunnel_type(const char *name) +{ + if (!strcmp(name, "geneve")) { + return GENEVE; + } else if (!strcmp(name, "stt")) { + return STT; + } else if (!strcmp(name, "vxlan")) { + return VXLAN; + } + + return 0; +} + +const struct ovsrec_bridge * +get_bridge(const struct ovsrec_bridge_table *bridge_table, const char *br_name) +{ + const struct ovsrec_bridge *br; + OVSREC_BRIDGE_TABLE_FOR_EACH (br, bridge_table) { + if (!strcmp(br->name, br_name)) { + return br; + } + } + return NULL; +} diff --git a/lib/ovn-util.h b/lib/ovn-util.h index b0bc70a16..2fa92e069 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -285,4 +285,20 @@ void ddlog_warn(const char *msg); void ddlog_err(const char *msg); #endif -#endif + +/* Must be a bit-field ordered from most-preferred (higher number) to + * least-preferred (lower number). */ +enum chassis_tunnel_type { + GENEVE = 1 << 2, + STT = 1 << 1, + VXLAN = 1 << 0 +}; + +uint32_t get_tunnel_type(const char *name); + +struct ovsrec_bridge_table; +const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, + const char *br_name); + + +#endif /* OVN_UTIL_H */ From patchwork Tue Oct 19 10:22:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543169 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=fEvaLU6P; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (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 4HYVDT1QQzz9sPB for ; Tue, 19 Oct 2021 21:22:33 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id CEC3D60C31; Tue, 19 Oct 2021 10:22:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FokX_OZ4P7vz; Tue, 19 Oct 2021 10:22:28 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 2418160B8A; Tue, 19 Oct 2021 10:22:26 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B7F9FC0026; Tue, 19 Oct 2021 10:22:19 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3BAC7C0028 for ; Tue, 19 Oct 2021 10:22:12 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id EE80560B3A for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ElSRBUP_-ZuD for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp3.osuosl.org (Postfix) with ESMTPS id 68DCE60B2A for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id D6F0841BF0 for ; Tue, 19 Oct 2021 10:22:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638929; bh=EiWgYaOfjrkdkaD4XxWY8lq8IIi5XBiUHKmF6guL4mg=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fEvaLU6Pix84J1rfm0w3ULeBoWZ1YELNUZfDE5pcYyPwTpC2RQOF1pdyODNc3fWjP 4nhJC+qhuh51m8zngTrmk+waeKzN4lKiWyT5XZpE8LIVtAAAcV8+/CT+lkNK9tORor bsZ0iu2J91WhoyjichP+VuZu6w4ES2kYRFKY7DfhYotutEAmngG7kK9Dg/j98oH3VZ vwe/V+fd7GopEvKirvvlTj3VDITw8sIfzEhAtOyI11gWUl8fuzEGaASS5f/WcMlfad 9pIXYOK23TZqJstnlIuqkF4JueDrw9ZPOn3hu+G1Qjk/ZPiCaJjNh200g8wq4+2o/6 gC2imzRnDs/2g== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:02 +0200 Message-Id: <20211019102205.3837601-9-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 09/12] tests: Use built objects for unit test deps. 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" Currently the tests/automake.mk adds source files from the project as needed and rebuilds these for the unit test programs. Use the already built objects instead. Signed-off-by: Frode Nordahl --- tests/automake.mk | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/automake.mk b/tests/automake.mk index 5b890d644..c4a7c0a5b 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -243,17 +243,14 @@ tests_ovstest_SOURCES = \ tests/test-ovn.c \ controller/test-lflow-cache.c \ controller/test-ofctrl-seqno.c \ - controller/lflow-cache.c \ - controller/lflow-cache.h \ - controller/ofctrl-seqno.c \ - controller/ofctrl-seqno.h \ lib/test-ovn-features.c \ - northd/test-ipam.c \ - northd/ipam.c \ - northd/ipam.h + northd/test-ipam.c tests_ovstest_LDADD = $(OVS_LIBDIR)/daemon.lo \ - $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la + $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la \ + controller/lflow-cache.$(OBJEXT) \ + controller/ofctrl-seqno.$(OBJEXT) \ + northd/ipam.$(OBJEXT) # Python tests. CHECK_PYFILES = \ From patchwork Tue Oct 19 10:22:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543171 X-Patchwork-Delegate: zhouhan@gmail.com 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=DU7/RDJy; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (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 4HYVDs4Hztz9sPB for ; Tue, 19 Oct 2021 21:22:53 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 64BD660BC5; Tue, 19 Oct 2021 10:22:51 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aa_wPO6KPUjq; Tue, 19 Oct 2021 10:22:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 32BE760BFA; Tue, 19 Oct 2021 10:22:31 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0E71DC0055; Tue, 19 Oct 2021 10:22:22 +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 C4E59C002C for ; Tue, 19 Oct 2021 10:22:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8EC7581BBD for ; Tue, 19 Oct 2021 10:22:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.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 Uov20gbuLDz7 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp1.osuosl.org (Postfix) with ESMTPS id A9D2C81AAC for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 2B0F441BF5 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638929; bh=lLJofqSfXeKj1q+Pupl6ED8d1AGupPZNfYAgDkP/GuY=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DU7/RDJyVBeuTKYkIy8lbImhALrqoQozuSolnLh94ADDaxpmwZieDZKLPn3lo9Z8f bFXrUk+XqC6C8kCjm2a9sdQMGUjgefKoQG+TSNke+v0B+Hy3XaRCtwm1LO0iCdIrO7 9/6SPYSTECoaNKlzQ2H5HngygeMDSN7JIi253EZlXO8kZ6oYrfttrp7V1ZUzTdEMj5 FdC0D8UYlWm7edJ9FSMchTe32VVnL2N+LC2jDB1SXr6xwZS8e6xweG/Yvbxoo/R2qP E/2za3JMRNt0fUNUt6QJ+d1hy+1mcDWF/IBL6A4L4tIc/69Bn4Fhb7BWagzUmnRMYZ yDTsx/2w8K7uA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:03 +0200 Message-Id: <20211019102205.3837601-10-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 10/12] lib: Add infrastructure for plug providers. 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" New lib/plug-provider module contains the infrastructure for registering plug provider classes which may be hosted inside or outside the core OVN repository. New controller/plug module adds internal interface for interacting with the plug providers. Extend build system to allow enabling building of built-in plugging providers and linking an externally built plugging provider. Signed-off-by: Frode Nordahl --- Documentation/automake.mk | 2 + Documentation/topics/index.rst | 1 + Documentation/topics/plug_providers/index.rst | 32 + .../topics/plug_providers/plug-providers.rst | 196 +++++ acinclude.m4 | 49 ++ configure.ac | 2 + controller/automake.mk | 4 +- controller/plug.c | 670 ++++++++++++++++++ controller/plug.h | 83 +++ controller/test-plug.c | 70 ++ lib/automake.mk | 10 +- lib/plug-provider.c | 204 ++++++ lib/plug-provider.h | 164 +++++ lib/plug_providers/dummy/plug-dummy.c | 119 ++++ ovn-architecture.7.xml | 35 +- tests/automake.mk | 13 +- tests/ovn-plug.at | 8 + 17 files changed, 1646 insertions(+), 16 deletions(-) create mode 100644 Documentation/topics/plug_providers/index.rst create mode 100644 Documentation/topics/plug_providers/plug-providers.rst create mode 100644 controller/plug.c create mode 100644 controller/plug.h create mode 100644 controller/test-plug.c create mode 100644 lib/plug-provider.c create mode 100644 lib/plug-provider.h create mode 100644 lib/plug_providers/dummy/plug-dummy.c create mode 100644 tests/ovn-plug.at diff --git a/Documentation/automake.mk b/Documentation/automake.mk index b3fd3d62b..ff245d218 100644 --- a/Documentation/automake.mk +++ b/Documentation/automake.mk @@ -28,6 +28,8 @@ DOC_SOURCE = \ Documentation/topics/ovn-news-2.8.rst \ Documentation/topics/role-based-access-control.rst \ Documentation/topics/debugging-ddlog.rst \ + Documentation/topics/plug_providers/index.rst \ + Documentation/topics/plug_providers/plug-providers.rst \ Documentation/howto/index.rst \ Documentation/howto/docker.rst \ Documentation/howto/firewalld.rst \ diff --git a/Documentation/topics/index.rst b/Documentation/topics/index.rst index d58d5618b..12bd113b7 100644 --- a/Documentation/topics/index.rst +++ b/Documentation/topics/index.rst @@ -41,6 +41,7 @@ OVN high-availability role-based-access-control ovn-news-2.8 + plug_providers/index testing .. list-table:: diff --git a/Documentation/topics/plug_providers/index.rst b/Documentation/topics/plug_providers/index.rst new file mode 100644 index 000000000..837eeae15 --- /dev/null +++ b/Documentation/topics/plug_providers/index.rst @@ -0,0 +1,32 @@ +.. + 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. + + Convention for heading levels in OVN documentation: + + ======= Heading 0 (reserved for the title in a document) + ------- Heading 1 + ~~~~~~~ Heading 2 + +++++++ Heading 3 + ''''''' Heading 4 + + Avoid deeper levels because they do not render well. + +============== +Plug Providers +============== + + +.. toctree:: + :maxdepth: 2 + + plug-providers diff --git a/Documentation/topics/plug_providers/plug-providers.rst b/Documentation/topics/plug_providers/plug-providers.rst new file mode 100644 index 000000000..50fbd05f2 --- /dev/null +++ b/Documentation/topics/plug_providers/plug-providers.rst @@ -0,0 +1,196 @@ +.. + 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. + + Convention for heading levels in OVN documentation: + + ======= Heading 0 (reserved for the title in a document) + ------- Heading 1 + ~~~~~~~ Heading 2 + +++++++ Heading 3 + ''''''' Heading 4 + + Avoid deeper levels because they do not render well. + +============== +Plug Providers +============== + +Traditionally it has been the CMSes responsibility to create VIFs as part of +instance life cycle, and subsequently manage plug/unplug operations on the +integration bridge following the conventions described in the +`Open vSwitch Integration Guide`_ for mapping of VIFs to OVN logical port. + +With the advent of NICs connected to multiple distinct CPUs we can have a +topology where the instance runs on one host and Open vSwitch and OVN runs on +a different host, the smartnic control plane CPU. The host facing interfaces +will be visible to Open vSwitch and OVN as representor ports. + +The actions necessary for plugging and unplugging the representor port in +Open vSwitch running on the smartnic control plane CPU would be the same for +every CMS. + +Instead of every CMS having to develop their own version of an agent to do +the plugging, we provide a pluggable infrastructure in OVN that allows the +`ovn-controller` to perform the plugging on CMS direction. + +Hardware or platform specific details for initialization and lookup of +representor ports is provided by an plugging provider library hosted inside or +outside the core OVN repository, and linked at OVN build time. + +Life Cycle of an OVN plugged VIF +-------------------------------- + +1. CMS creates a record in the OVN Northbound Logical_Switch_Port table with + the options column containing the `plug-type` key with a value corresponding + to the `const char *type` provided by the plug provider implementation as + well as a `requested-chassis` key with a value pointing at the name or + hostname of the chassis it wants the VIF plugged on. Additional plug + provider specific key/value pairs must be provided for successful lookup. + +2. `ovn-northd` looks up the name or hostname provided in the + `requested-chassis` option and fills the OVN Southbound Port_Binding + requested_chassis column, it also copies relevant options over to the + Port_Binding record. + +3. `ovn-controller` monitors Southbound Port_Binding entries with a + requested_chassis column pointing at its chassis UUID and when it encounters + a entry with option `plug-type` and it has registered a plug provider + matching that type it will act on it even if no local binding exists yet. + +4. It will fill the `struct plug_port_ctx_in` as defined in `lib/plug.h` with + `op_type` set to 'PLUG_OP_CREATE' and make a call to the plug providers + `plug_port_prepare` callback function. Plug provider performs lookup and + fills the `struct plug_port_ctx_out` as defined in `lib/plug.h`. + +5. `ovn-controller` creates a port and interface record in the local OVSDB + using the details provided by the plug provider and also adds + `external-ids:iface-id` with value matching the logical port name and + `external-ids:ovn-plugged` with value matching the logical port `plug-type`. + When the port creation is done a call will first be made to the plug + providers `plug_port_finish` function and then to the + `plug_port_ctx_destroy` function to free any memory allocated by the plug + implementation. + +6. The Open vSwitch vswitchd will assign a ofport to the newly created + interface and on the next `ovn-controller` incremental engine loop iteration + flows will be installed. + +7. On any change to the Southbound Port_Binding record or full recomputation + the `ovn-controller` will in addition to normal flow processing make a call + to the plug provider again similar to the first creation in case anything + needs updating for the interface record. + +8. The port will be unplugged when an event occurs which would make the + `ovn-controller` release a logical port, for example the Logical_Switch_Port + and Port_Binding entry disappearing from the database or its + `requested_chassis` column being pointed to a different chassis. + + +The plug provider interface +--------------------------- + +The interface between internals of OVN and a plug provider is a set of +callbacks as defined by the `struct plug_class` in `lib/plug-provider.h`. + +It is important to note that these callbacks will be called in the critical +path of the `ovn-controller` processing loop, so care must be taken to make the +implementation as efficient as possible, and under no circumstance can any of +the callback functions make calls that block. + +On `ovn-controller` startup, plug providers made available at build time will +be registered by the identifier provided in the `const char *type` pointer, at +this time the `init` function pointer will be called if it is non-NULL. + +> **Note**: apart from the `const char *type` pointer, no attempt will be made +to access plug provider data or functions before the call to the `init` has +been made. + +On `ovn-controller` exit, the plug providers registered in the above mentioned +procedure will have their `destroy` function pointer called if it is non-NULL. + +If the plug provider has internal lookup tables that need to be maintained they +can define a `run` function which will be called as part of the +`ovn-controller` incremental processing engine loop. If there are any changes +encountered the function should return 'true' to signal that further processing +is necessary, 'false' otherwise. + +On update of Interface records the `ovn-controller` will pass on a `sset` +to the `ovsport_update_iface` function containing options the plug +implementation finds pertinent to maintain for successful operation. This +`sset` is retrieved by making a call to the plug implementation +`plug_get_maintained_iface_options` function pointer if it is non-NULL. This +allows presence of other users of the OVSDB maintaining a different set of +options on the same set of Interface records without wiping out their changes. + +Before creating or updating an existing interface record the plug provider +`plug_port_prepare` function pointer will be called with valid pointers to +`struct plug_port_ctx_in` and `struct plug_port_ctx_out` data structures. If +the plug provider implementation is able to perform lookup it should fill the +`struct plug_port_ctx_out` data structure and return 'true'. The +`ovn-controller` will then create or update the port/interface records and +then call `plug_port_finish` and `plug_port_ctx_destroy`. If the plug provider +implementation is unable to perform lookup or prepare the desired resource at +this time, it should return 'false' which will tell the `ovn-controller` to +signal a full recomputation is necessary, in this case it will also not call +`plug_port_finish`, it will however make a call to `plug_port_ctx_destroy`. + +Before removing port and interface records previously plugged by the +`ovn-controller` as identified by presence of the Interface +`external-ids:ovn-plugged` key, the `ovn-controller` will look up the +`plug-type` from `external-ids:ovn-plugged`, fill `struct plug_port_ctx_in` +with `op_type` set to 'PLUG_OP_REMOVE' and make a call to `plug_port_prepare`. +After the port and interface has been removed a call will be made to +`plug_port_finish`. Both calls will be made with the pointer to +`plug_port_ctx_out` set to 'NULL', and no call will be made to +`plug_port_ctx_destroy`. + +Building with in-tree plug providers +------------------------------------ + +Plug providers hosted in the OVN repository living under `lib/plug_providers`: + +To enable them, provide the `--enable-plug-providers` command line option to +the configure script when building OVN. + +Building with an externally provided plug provider +-------------------------------------------------- + +There is also infrastructure in place to support linking OVN with an externally +built plug provider. + +This external plug provider must define a NULL-terminated array of pointers +to `struct plug_class` data structures named `plug_provider_classes`. Example: + +.. code-block:: none + + const struct plug_class *plug_provider_classes[] = { + &plug_foo, + NULL, + }; + +The name of the repository for the external plug provider should be the same as +the name of the library it produces, and the built library artifact should be +placed in lib/.libs. Example: + +.. code-block:: none + + ovn-vif-foo/ + ovn-vif-foo/lib/.libs/libovn-vif-foo.la + +To enable such a plug provider provide the +`--with-plug-provider=/path/to/ovn-vif-foo` command line option to the +configure script when building OVN. + +.. LINKS +.. _Open vSwitch Integration Guide: + https://docs.openvswitch.org/en/latest/topics/integration/ diff --git a/acinclude.m4 b/acinclude.m4 index e7f829520..793a073d1 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -441,3 +441,52 @@ AC_DEFUN([OVN_CHECK_OVS], [ AC_MSG_CHECKING([OVS version]) AC_MSG_RESULT([$OVSVERSION]) ]) + +dnl OVN_CHECK_PLUG_PROVIDER +dnl +dnl Check for external plug provider +AC_DEFUN([OVN_CHECK_PLUG_PROVIDER], [ + AC_ARG_VAR([PLUG_PROVIDER]) + AC_ARG_WITH( + [plug-provider], + [AC_HELP_STRING([--with-plug-provider=/path/to/provider/repository], + [Specify path to a configured and built plug provider repository])], + [if test "$withval" = yes; then + if test -z "$PLUG_PROVIDER"; then + AC_MSG_ERROR([To build with external plug provider, specify the path to a configured and built plug provider repository --with-plug-provider or in \$PLUG_PROVIDER]), + fi + PLUG_PROVIDER="$(realpath $PLUG_PROVIDER)" + else + PLUG_PROVIDER="$(realpath $withval)" + fi + _plug_provider_name="$(basename $PLUG_PROVIDER)" + if test ! -f "$PLUG_PROVIDER/lib/.libs/lib${_plug_provider_name}.la"; then + AC_MSG_ERROR([$withval is not a configured and built plug provider library repository]) + fi + PLUG_PROVIDER_LDFLAGS="-L$PLUG_PROVIDER/lib/.libs -l$_plug_provider_name" + ], + [PLUG_PROVIDER=no]) + AC_MSG_CHECKING([for plug provider]) + AC_MSG_RESULT([$PLUG_PROVIDER]) + AC_SUBST([PLUG_PROVIDER_LDFLAGS]) + AM_CONDITIONAL([HAVE_PLUG_PROVIDER], [test "$PLUG_PROVIDER" != no]) + if test "$PLUG_PROVIDER" != no; then + AC_DEFINE([HAVE_PLUG_PROVIDER], [1], + [Build and link with external plug provider]) + fi +]) + +dnl OVN_ENABLE_PLUG +dnl +dnl Enable built-in plug providers +AC_DEFUN([OVN_ENABLE_PLUG], [ + AC_ARG_ENABLE( + [plug-providers], + [AC_HELP_STRING([--enable-plug-providers], [Enable building of built-in plug providers])], + [], [enable_plug=no]) + AM_CONDITIONAL([ENABLE_PLUG], [test "$enable_plug" != no]) + if test "$enable_plug" != no; then + AC_DEFINE([ENABLE_PLUG], [1], + [Build built-in plug providers]) + fi +]) diff --git a/configure.ac b/configure.ac index d1b9b4d55..715fe6740 100644 --- a/configure.ac +++ b/configure.ac @@ -172,6 +172,8 @@ OVS_ENABLE_SPARSE OVS_CHECK_DDLOG([0.47]) OVS_CHECK_PRAGMA_MESSAGE OVN_CHECK_OVS +OVN_CHECK_PLUG_PROVIDER +OVN_ENABLE_PLUG OVS_CTAGS_IDENTIFIERS AC_SUBST([OVS_CFLAGS]) AC_SUBST([OVS_LDFLAGS]) diff --git a/controller/automake.mk b/controller/automake.mk index ad2d68af2..09fbbb1af 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -37,7 +37,9 @@ controller_ovn_controller_SOURCES = \ controller/local_data.c \ controller/local_data.h \ controller/ovsport.h \ - controller/ovsport.c + controller/ovsport.c \ + controller/plug.h \ + controller/plug.c controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += controller/ovn-controller.8 diff --git a/controller/plug.c b/controller/plug.c new file mode 100644 index 000000000..99c56b7e1 --- /dev/null +++ b/controller/plug.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2021 Canonical + * + * 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 + +/* OVS includes */ +#include "lib/vswitch-idl.h" +#include "openvswitch/shash.h" +#include "openvswitch/vlog.h" + +/* OVN includes */ +#include "binding.h" +#include "lib/ovn-sb-idl.h" +#include "lport.h" +#include "ovsport.h" +#include "plug.h" +#include "plug-provider.h" + +VLOG_DEFINE_THIS_MODULE(plug); + +#define OVN_PLUGGED_EXT_ID "ovn-plugged" + +void +plug_register_ovs_idl(struct ovsdb_idl *ovs_idl) +{ + ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_mtu_request); +} + +/* Get the class level 'maintained_iface_options' set. */ +const struct sset * +plug_get_maintained_iface_options(const struct plug_class *plug_class) +{ + return plug_class->plug_get_maintained_iface_options ? + plug_class->plug_get_maintained_iface_options() : NULL; +} + +/* Prepare the logical port as identified by 'ctx_in' for port creation, update + * or removal as specified by 'ctx_in->op_type'. + * + * When 'ctx_in->op_type' is PLUG_OP_CREATE the plug implementation must fill + * 'ctx_out' with data to apply to the interface record maintained by OVN on + * its behalf. + * + * When 'ctx_in_op_type' is PLUG_OP_REMOVE 'ctx_out' should be set to NULL and + * the plug implementation must not attempt to use 'ctx_out'. + * + * The data in 'ctx_out' is owned by the plug implementation, and a call must + * be made to plug_port_ctx_destroy when done with it. */ +bool +plug_port_prepare(const struct plug_class *plug_class, + const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out) +{ + return plug_class->plug_port_prepare(ctx_in, ctx_out); +} + +/* Notify the plug implementation that a port creation, update or removal has + * been completed */ +void +plug_port_finish(const struct plug_class *plug_class, + const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out) +{ + plug_class->plug_port_finish(ctx_in, ctx_out); +} + +/* Free any data allocated to 'ctx_out' in a prevous call to + * plug_port_prepare. */ +void +plug_port_ctx_destroy(const struct plug_class *plug_class, + const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out) +{ + plug_class->plug_port_ctx_destroy(ctx_in, ctx_out); +} + +static struct plug_port_ctx * +build_port_ctx(const struct plug_class *plug, + const enum plug_op_type op_type, + const struct plug_ctx_in *plug_ctx_in, + const struct sbrec_port_binding *pb, + const struct ovsrec_interface *iface, + const char *iface_id) +{ + struct plug_port_ctx *new_ctx = xzalloc( + sizeof *new_ctx); + + new_ctx->plug = plug; + new_ctx->plug_port_ctx_in.op_type = op_type; + new_ctx->plug_port_ctx_in.ovs_table = plug_ctx_in->ovs_table; + new_ctx->plug_port_ctx_in.br_int = plug_ctx_in->br_int; + new_ctx->plug_port_ctx_in.lport_name = pb ? + xstrdup(pb->logical_port) : iface_id ? xstrdup(iface_id) : NULL; + /* Prepare plug_port_ctx_in smaps for use. + * + * Note that smap_init does not allocate memory. Any memory allocated by + * putting data into the plug_port_ctx_in smaps will be destroyed by calls + * to smap_destroy in destroy_port_ctx */ + smap_init(&new_ctx->plug_port_ctx_in.lport_options); + smap_init(&new_ctx->plug_port_ctx_in.iface_options); + + if (pb) { + smap_clone(&new_ctx->plug_port_ctx_in.lport_options, + &pb->options); + } + + if (iface) { + new_ctx->plug_port_ctx_in.iface_name = xstrdup(iface->name); + new_ctx->plug_port_ctx_in.iface_type = xstrdup(iface->type); + smap_clone(&new_ctx->plug_port_ctx_in.iface_options, + &iface->options); + } + + /* Prepare plug_port_ctx_out smaps for use. + * + * Note that smap_init does not allocate memory. Any memory allocated by + * putting data into the plug_port_ctx_out smaps is the responsibility of + * the plug provider through a call to plug_port_ctx_destroy. */ + smap_init(&new_ctx->plug_port_ctx_out.iface_options); + + return new_ctx; +} + +static void +destroy_port_ctx(struct plug_port_ctx *ctx) +{ + smap_destroy(&ctx->plug_port_ctx_in.lport_options); + smap_destroy(&ctx->plug_port_ctx_in.iface_options); + if (ctx->plug_port_ctx_in.lport_name) { + free((char *)ctx->plug_port_ctx_in.lport_name); + } + if (ctx->plug_port_ctx_in.iface_name) { + free((char *)ctx->plug_port_ctx_in.iface_name); + } + if (ctx->plug_port_ctx_in.iface_type) { + free((char *)ctx->plug_port_ctx_in.iface_type); + } + /* Note that data associated with ctx->plug_port_ctx_out must be destroyed + * by the plug provider implementation with a call to plug_port_ctx_destroy + * prior to calling this function */ + free(ctx); +} + +/* When we add deletion of rows to the transaction, the data structures + * associated with the rows will immediately be freed from the IDL, and as + * such we can no longer access them. + * + * Since IDL commits are handled asynchronously we can have a few engine + * iterations where the deleted data shows up when iterating over table + * contents, but the IDL *_is_deleted() call will not reliably categorize the + * data as deleted. This is in contrast to the IDL behaviour when some other + * process deletes data from the database, so this may be an OVS IDL bug, or it + * could be it's just expected that the program consuming the IDL will know not + * to access rows it has deleted. + * + * To deal with this, we keep a reference for ourself to avoid attempting to + * remove the same data multiple times while waiting for the transaction to + * commit. The tracking data will be cleared after commit at the end of the + * ovn-controller main loop. + */ +static void +transact_delete_port(const struct plug_ctx_in *plug_ctx_in, + const struct plug_ctx_out *plug_ctx_out, + const struct plug_port_ctx *plug_port_ctx, + const struct ovsrec_port *port) +{ + shash_add(plug_ctx_out->deleted_iface_ids, + plug_port_ctx->plug_port_ctx_in.lport_name, + plug_port_ctx); + ovsport_remove(plug_ctx_in->br_int, port); +} + +static void +transact_create_port(const struct plug_ctx_in *plug_ctx_in, + const struct plug_ctx_out *plug_ctx_out, + const struct plug_port_ctx *plug_port_ctx, + const struct smap *iface_external_ids, + const int64_t mtu_request) +{ + shash_add(plug_ctx_out->changed_iface_ids, + plug_port_ctx->plug_port_ctx_in.lport_name, + plug_port_ctx); + ovsport_create(plug_ctx_in->ovs_idl_txn, plug_ctx_in->br_int, + plug_port_ctx->plug_port_ctx_out.name, + plug_port_ctx->plug_port_ctx_out.type, + NULL, iface_external_ids, + &plug_port_ctx->plug_port_ctx_out.iface_options, + mtu_request); +} + +static void +transact_update_port(const struct ovsrec_interface *iface_rec, + const struct plug_ctx_in *plug_ctx_in OVS_UNUSED, + const struct plug_ctx_out *plug_ctx_out, + const struct plug_port_ctx *plug_port_ctx, + const struct smap *iface_external_ids, + const int64_t mtu_request) +{ + shash_add(plug_ctx_out->changed_iface_ids, + plug_port_ctx->plug_port_ctx_in.lport_name, + plug_port_ctx); + ovsport_update_iface(iface_rec, + plug_port_ctx->plug_port_ctx_out.type, + iface_external_ids, + NULL, + &plug_port_ctx->plug_port_ctx_out.iface_options, + plug_get_maintained_iface_options( + plug_port_ctx->plug), + mtu_request); +} + + +static bool +consider_unplug_iface(const struct ovsrec_interface *iface, + const struct sbrec_port_binding *pb, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + const char *plug_type = smap_get(&iface->external_ids, OVN_PLUGGED_EXT_ID); + const char *iface_id = smap_get(&iface->external_ids, "iface-id"); + const struct ovsrec_port *port = ovsport_lookup_by_interface( + plug_ctx_in->ovsrec_port_by_interfaces, + (struct ovsrec_interface *) iface); + + if (plug_type && iface_id && port) { + const struct plug_class *plug; + if (!(plug = plug_provider_get(plug_type))) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, + "Unable to open plug provider for " + "plug-type %s iface-id %s", + plug_type, iface_id); + /* While we are unable to handle this, asking for a recompute + * will not change that fact. */ + return true; + } + if (!plug_ctx_in->chassis_rec || !plug_ctx_in->br_int + || !plug_ctx_in->ovs_idl_txn) + { + /* Some of our prerequisites are not available, ask for a + * recompute. */ + return false; + } + + /* Our contract with the plug provider is that plug_port_finish + * will be called with a plug_port_ctx_in object once the data + * is actually deleted. + * + * Since this happens asynchronously we need to allocate memory for + * and duplicate any database references so that they stay valid. + * + * The data is freed with a call to destroy_port_ctx after the + * transaction completes at the end of the ovn-controller main + * loop. */ + struct plug_port_ctx *plug_port_ctx = build_port_ctx( + plug, PLUG_OP_REMOVE, plug_ctx_in, pb, iface, iface_id); + + if (!plug_port_prepare(plug, &plug_port_ctx->plug_port_ctx_in, NULL)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_INFO_RL(&rl, + "Not unplugging iface %s (iface-id %s) on direction " + "from plugging library.", + iface->name, iface_id); + destroy_port_ctx(plug_port_ctx); + return false; + } + VLOG_INFO("Unplugging port %s from %s for iface-id %s on this " + "chassis.", + port->name, + plug_ctx_in->br_int->name, + iface_id); + + /* Add and track delete operation to the transaction */ + transact_delete_port(plug_ctx_in, plug_ctx_out, + plug_port_ctx, port); + return true; + } + return true; +} + +static int64_t +get_plug_mtu_request(const struct smap *lport_options) +{ + return smap_get_int(lport_options, "plug-mtu-request", 0); +} + +static bool +consider_plug_lport_create__(const struct plug_class *plug, + const struct smap *iface_external_ids, + const struct sbrec_port_binding *pb, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + if (!plug_ctx_in->chassis_rec || !plug_ctx_in->br_int + || !plug_ctx_in->ovs_idl_txn) { + /* Some of our prerequisites are not available, ask for a recompute. */ + return false; + } + + /* Our contract with the plug provider is that plug_port_finish + * will be called with plug_port_ctx_in and plug_port_ctx_out objects + * once the port is actually created. + * + * Since this happens asynchronously we need to allocate memory for + * and duplicate any database references so that they stay valid. + * + * The data is freed with a call to destroy_port_ctx after the + * transaction completes at the end of the ovn-controller main + * loop. */ + struct plug_port_ctx *plug_port_ctx = build_port_ctx( + plug, PLUG_OP_CREATE, plug_ctx_in, pb, NULL, NULL); + + if (!plug_port_prepare(plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_INFO_RL(&rl, + "Not plugging lport %s on direction from plugging " + "library.", + pb->logical_port); + plug_port_ctx_destroy(plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out); + destroy_port_ctx(plug_port_ctx); + return false; + } + + VLOG_INFO("Plugging port %s into %s for lport %s on this " + "chassis.", + plug_port_ctx->plug_port_ctx_out.name, plug_ctx_in->br_int->name, + pb->logical_port); + transact_create_port(plug_ctx_in, plug_ctx_out, + plug_port_ctx, + iface_external_ids, + get_plug_mtu_request(&pb->options)); + return true; +} + +static bool +consider_plug_lport_update__(const struct plug_class *plug, + const struct smap *iface_external_ids, + const struct sbrec_port_binding *pb, + struct local_binding *lbinding, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + if (!plug_ctx_in->chassis_rec || !plug_ctx_in->br_int + || !plug_ctx_in->ovs_idl_txn) { + /* Some of our prerequisites are not available, ask for a recompute. */ + return false; + } + /* Our contract with the plug provider is that plug_port_finish + * will be called with plug_port_ctx_in and plug_port_ctx_out objects + * once the port is actually updated. + * + * Since this happens asynchronously we need to allocate memory for + * and duplicate any database references so that they stay valid. + * + * The data is freed with a call to destroy_port_ctx after the + * transaction completes at the end of the ovn-controller main + * loop. */ + struct plug_port_ctx *plug_port_ctx = build_port_ctx( + plug, PLUG_OP_CREATE, plug_ctx_in, pb, NULL, NULL); + + if (!plug_port_prepare(plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_INFO_RL(&rl, + "Not updating lport %s on direction from plugging " + "library.", + pb->logical_port); + plug_port_ctx_destroy(plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out); + destroy_port_ctx(plug_port_ctx); + return false; + } + + if (strcmp(lbinding->iface->name, plug_port_ctx->plug_port_ctx_out.name)) { + VLOG_WARN("Attempt of incompatible change to existing " + "port detected, please recreate port: %s", + pb->logical_port); + plug_port_ctx_destroy(plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out); + destroy_port_ctx(plug_port_ctx); + return false; + } + VLOG_DBG("updating iface for: %s", pb->logical_port); + transact_update_port(lbinding->iface, plug_ctx_in, plug_ctx_out, + plug_port_ctx, iface_external_ids, + get_plug_mtu_request(&pb->options)); + + return true; +} + +static bool +consider_plug_lport(const struct sbrec_port_binding *pb, + struct local_binding *lbinding, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + bool ret = true; + if (lport_can_bind_on_this_chassis(plug_ctx_in->chassis_rec, pb) + && pb->requested_chassis == plug_ctx_in->chassis_rec) { + const char *plug_type = smap_get(&pb->options, "plug-type"); + if (!plug_type) { + /* Nothing for us to do and we don't need a recompute. */ + return true; + } + + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + const struct plug_class *plug; + if (!(plug = plug_provider_get(plug_type))) { + VLOG_WARN_RL(&rl, + "Unable to open plug provider for plug-type: '%s' " + "lport %s", + plug_type, pb->logical_port); + /* While we are unable to handle this, asking for a recompute will + * not change that fact. */ + return true; + } + const struct smap iface_external_ids = SMAP_CONST2( + &iface_external_ids, + OVN_PLUGGED_EXT_ID, plug_type, + "iface-id", pb->logical_port); + if (lbinding && lbinding->iface) { + if (!smap_get(&lbinding->iface->external_ids, + OVN_PLUGGED_EXT_ID)) + { + VLOG_WARN_RL(&rl, + "CMS requested plugging of lport %s, but a port " + "that is not maintained by OVN already exsist " + "in local vSwitch: "UUID_FMT, + pb->logical_port, + UUID_ARGS(&lbinding->iface->header_.uuid)); + return false; + } + ret = consider_plug_lport_update__(plug, &iface_external_ids, pb, + lbinding, plug_ctx_in, + plug_ctx_out); + } else { + ret = consider_plug_lport_create__(plug, &iface_external_ids, pb, + plug_ctx_in, plug_ctx_out); + } + } + + return ret; +} + +static bool +plug_iface_touched_this_txn(const struct plug_ctx_out *plug_ctx_out, + const char *iface_id) +{ + return shash_find(plug_ctx_out->changed_iface_ids, iface_id) + || shash_find(plug_ctx_out->deleted_iface_ids, iface_id); +} + +static bool +plug_handle_lport_vif(const struct sbrec_port_binding *pb, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + if (plug_iface_touched_this_txn(plug_ctx_out, pb->logical_port)) { + return true; + } + bool handled = true; + struct local_binding *lbinding = local_binding_find( + plug_ctx_in->local_bindings, pb->logical_port); + + if (lport_can_bind_on_this_chassis(plug_ctx_in->chassis_rec, pb)) { + handled &= consider_plug_lport(pb, lbinding, + plug_ctx_in, plug_ctx_out); + } else if (lbinding && lbinding->iface) { + handled &= consider_unplug_iface(lbinding->iface, pb, + plug_ctx_in, plug_ctx_out); + } + return handled; +} + +static bool +plug_handle_iface(const struct ovsrec_interface *iface_rec, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + bool handled = true; + const char *plug_type = smap_get(&iface_rec->external_ids, + OVN_PLUGGED_EXT_ID); + const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id"); + if (!plug_type || !iface_id + || plug_iface_touched_this_txn(plug_ctx_out, iface_id)) { + return true; + } + struct local_binding *lbinding = local_binding_find( + plug_ctx_in->local_bindings, iface_id); + const struct sbrec_port_binding *pb = lport_lookup_by_name( + plug_ctx_in->sbrec_port_binding_by_name, iface_id); + if (pb && lbinding + && lport_can_bind_on_this_chassis(plug_ctx_in->chassis_rec, pb)) { + /* Something changed on a interface we have previously plugged, + * consider updating it */ + handled &= consider_plug_lport(pb, lbinding, + plug_ctx_in, plug_ctx_out); + } else if (!pb + || !lport_can_bind_on_this_chassis( + plug_ctx_in->chassis_rec, pb)) { + /* No lport for this interface or it is destined for different chassis, + * consuder unplugging it */ + handled &= consider_unplug_iface(iface_rec, pb, + plug_ctx_in, plug_ctx_out); + } + return handled; +} + +void +plug_run(struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + if (!plug_ctx_in->pb_handler_has_run) { + /* Avoid uneccessary unplug/plug thrashing. If we are starting up + * after having done a normal exit (unregistered our chassis record), + * we have to wait until northd has reinstated the requested_chassis + * pointer before table iterators and index lookups provide the + * expected data */ + return; + } + const struct ovsrec_interface *iface_rec; + OVSREC_INTERFACE_TABLE_FOR_EACH (iface_rec, + plug_ctx_in->iface_table) { + plug_handle_iface(iface_rec, plug_ctx_in, plug_ctx_out); + } + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_TABLE_FOR_EACH (pb, + plug_ctx_in->port_binding_table) { + enum en_lport_type lport_type = get_lport_type(pb); + if (lport_type == LP_VIF) { + plug_handle_lport_vif(pb, plug_ctx_in, plug_ctx_out); + } + } +} + +bool +plug_handle_port_binding_changes(struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + const struct sbrec_port_binding *pb; + bool handled = true; + + /* handle deleted lports */ + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED ( + pb, + plug_ctx_in->port_binding_table) { + if (!sbrec_port_binding_is_deleted(pb)) { + continue; + } + + enum en_lport_type lport_type = get_lport_type(pb); + if (lport_type == LP_VIF) { + struct local_binding *lbinding = local_binding_find( + plug_ctx_in->local_bindings, pb->logical_port); + if (lbinding && lbinding->iface + && !plug_iface_touched_this_txn(plug_ctx_out, + pb->logical_port)) { + handled &= consider_unplug_iface(lbinding->iface, pb, + plug_ctx_in, plug_ctx_out); + } + } + } + + /* handle any new or updated lports */ + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED ( + pb, + plug_ctx_in->port_binding_table) { + if (sbrec_port_binding_is_deleted(pb)) { + continue; + } + enum en_lport_type lport_type = get_lport_type(pb); + if (lport_type == LP_VIF) { + handled &= plug_handle_lport_vif(pb, plug_ctx_in, plug_ctx_out); + } + } + + return handled; +} + +bool +plug_handle_ovs_interface_changes(struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + bool handled = true; + const struct ovsrec_interface *iface_rec; + + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, + plug_ctx_in->iface_table) { + if (ovsrec_interface_is_deleted(iface_rec)) { + continue; + } + handled &= plug_handle_iface(iface_rec, plug_ctx_in, plug_ctx_out); + } + return handled; +} + +static void +plug_finish_deleted__(struct shash *deleted_iface_ids, bool txn_success) +{ + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, deleted_iface_ids) { + struct plug_port_ctx *plug_port_ctx = node->data; + if (txn_success) { + plug_port_finish(plug_port_ctx->plug, + &plug_port_ctx->plug_port_ctx_in, + NULL); + } + shash_delete(deleted_iface_ids, node); + destroy_port_ctx(plug_port_ctx); + } +} + +void +plug_clear_deleted(struct shash *deleted_iface_ids) { + plug_finish_deleted__(deleted_iface_ids, false); +} + +void +plug_finish_deleted(struct shash *deleted_iface_ids) { + plug_finish_deleted__(deleted_iface_ids, true); +} + +static void +plug_finish_changed__(struct shash *changed_iface_ids, bool txn_success) +{ + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, changed_iface_ids) { + struct plug_port_ctx *plug_port_ctx = node->data; + if (txn_success) { + plug_port_finish(plug_port_ctx->plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out); + } + plug_port_ctx_destroy(plug_port_ctx->plug, + &plug_port_ctx->plug_port_ctx_in, + &plug_port_ctx->plug_port_ctx_out); + shash_delete(changed_iface_ids, node); + destroy_port_ctx(plug_port_ctx); + } +} + +void +plug_clear_changed(struct shash *deleted_iface_ids) { + plug_finish_changed__(deleted_iface_ids, false); +} + +void +plug_finish_changed(struct shash *deleted_iface_ids) { + plug_finish_changed__(deleted_iface_ids, true); +} diff --git a/controller/plug.h b/controller/plug.h new file mode 100644 index 000000000..5647a25ac --- /dev/null +++ b/controller/plug.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 Canonical + * + * 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 PLUG_H +#define PLUG_H 1 + +/* + * Plug, the controller internal interface to the plug provider infrastructure. + */ + +#include "openvswitch/shash.h" +#include "smap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct plug_ctx_in { + struct ovsdb_idl_txn *ovs_idl_txn; + struct ovsdb_idl_index *sbrec_port_binding_by_name; + struct ovsdb_idl_index *ovsrec_port_by_interfaces; + const struct ovsrec_open_vswitch_table *ovs_table; + const struct ovsrec_bridge *br_int; + const struct ovsrec_interface_table *iface_table; + const struct sbrec_chassis *chassis_rec; + const struct sbrec_port_binding_table *port_binding_table; + const struct shash *local_bindings; + bool pb_handler_has_run; +}; + +struct plug_ctx_out { + struct shash *deleted_iface_ids; + struct shash *changed_iface_ids; +}; + +struct plug_class; +struct plug_port_ctx_out; +struct plug_port_ctx_in; + +const struct sset * plug_get_maintained_iface_options( + const struct plug_class *plug_class); + +bool plug_port_prepare(const struct plug_class *, + const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); +void plug_port_finish(const struct plug_class *, + const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); +void plug_port_ctx_destroy(const struct plug_class *, + const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); + +struct ovsdb_idl; + +void plug_register_ovs_idl(struct ovsdb_idl *ovs_idl); +void plug_run(struct plug_ctx_in *, struct plug_ctx_out *); +bool plug_handle_port_binding_changes(struct plug_ctx_in *, + struct plug_ctx_out *); +bool plug_handle_ovs_interface_changes(struct plug_ctx_in *, + struct plug_ctx_out *); +void plug_clear_changed(struct shash *deleted_iface_ids); +void plug_finish_changed(struct shash *changed_iface_ids); +void plug_clear_deleted(struct shash *deleted_iface_ids); +void plug_finish_deleted(struct shash *changed_iface_ids); + +#ifdef __cplusplus +} +#endif + +#endif /* plug.h */ diff --git a/controller/test-plug.c b/controller/test-plug.c new file mode 100644 index 000000000..683aa7df2 --- /dev/null +++ b/controller/test-plug.c @@ -0,0 +1,70 @@ +/* Copyright (c) 2021, Canonical + * + * 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 "plug.h" +#include "plug-provider.h" +#include "smap.h" +#include "sset.h" +#include "tests/ovstest.h" + +static void +test_plug(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + const struct plug_class *plug_class; + + ovs_assert(plug_provider_unregister("dummy") == EINVAL); + + ovs_assert(!plug_provider_register(&plug_dummy_class)); + plug_class = plug_provider_get("dummy"); + ovs_assert(plug_provider_register(&plug_dummy_class) == EEXIST); + + ovs_assert(sset_contains(plug_get_maintained_iface_options(plug_class), + "plug-dummy-option")); + + struct plug_port_ctx_in ctx_in = { + .op_type = PLUG_OP_CREATE, + .lport_name = "lsp1", + .lport_options = SMAP_INITIALIZER(&ctx_in.lport_options), + }; + struct plug_port_ctx_out ctx_out; + plug_port_prepare(plug_class, &ctx_in, &ctx_out); + ovs_assert(!strcmp(ctx_out.name, "lsp1")); + ovs_assert(!strcmp(ctx_out.type, "internal")); + ovs_assert(!strcmp(smap_get( + &ctx_out.iface_options, "plug-dummy-option"), "value")); + + plug_port_finish(plug_class, &ctx_in, &ctx_out); + plug_port_ctx_destroy(plug_class, &ctx_in, &ctx_out); + plug_provider_destroy_all(); +} + +static void +test_plug_main(int argc, char *argv[]) +{ + set_program_name(argv[0]); + static const struct ovs_cmdl_command commands[] = { + {"run", NULL, 0, 0, test_plug, OVS_RO}, + {NULL, NULL, 0, 0, NULL, OVS_RO}, + }; + struct ovs_cmdl_context ctx; + ctx.argc = argc - 1; + ctx.argv = argv + 1; + ovs_cmdl_run_command(&ctx, commands); +} + +OVSTEST_REGISTER("test-plug", test_plug_main); diff --git a/lib/automake.mk b/lib/automake.mk index 9f9f447d5..0c320c6f9 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -4,6 +4,11 @@ lib_libovn_la_LDFLAGS = \ -Wl,--version-script=$(top_builddir)/lib/libovn.sym \ $(OVS_LIBDIR)/libopenvswitch.la \ $(AM_LDFLAGS) + +if HAVE_PLUG_PROVIDER +lib_libovn_la_LDFLAGS += $(PLUG_PROVIDER_LDFLAGS) +endif + lib_libovn_la_SOURCES = \ lib/acl-log.c \ lib/acl-log.h \ @@ -33,7 +38,10 @@ lib_libovn_la_SOURCES = \ lib/inc-proc-eng.h \ lib/lb.c \ lib/lb.h \ - lib/stopwatch-names.h + lib/stopwatch-names.h \ + lib/plug-provider.h \ + lib/plug-provider.c \ + lib/plug_providers/dummy/plug-dummy.c nodist_lib_libovn_la_SOURCES = \ lib/ovn-dirs.c \ lib/ovn-nb-idl.c \ diff --git a/lib/plug-provider.c b/lib/plug-provider.c new file mode 100644 index 000000000..e7e463423 --- /dev/null +++ b/lib/plug-provider.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2021 Canonical + * + * 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 "plug-provider.h" + +#include +#include +#include + +#include "openvswitch/vlog.h" +#include "openvswitch/shash.h" +#include "smap.h" +#include "sset.h" +#include "lib/inc-proc-eng.h" + +VLOG_DEFINE_THIS_MODULE(plug_provider); + +#ifdef ENABLE_PLUG +static const struct plug_class *base_plug_classes[] = { +}; +#endif + +static struct shash plug_classes = SHASH_INITIALIZER(&plug_classes); + +/* Protects the 'plug_classes' shash. */ +static struct ovs_mutex plug_classes_mutex = OVS_MUTEX_INITIALIZER; + +/* Initialize the the plug infrastructure by registering known plug classes */ +void +plug_provider_initialize(void) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + + if (ovsthread_once_start(&once)) { +#ifdef ENABLE_PLUG + /* Register built-in plug provider classes */ + for (int i = 0; i < ARRAY_SIZE(base_plug_classes); i++) { + plug_provider_register(base_plug_classes[i]); + } +#endif +#ifdef HAVE_PLUG_PROVIDER + /* Register external plug provider classes. + * + * Note that we cannot use the ARRAY_SIZE macro here as + * plug_provider_classes is defined in external code which is not + * available at compile time. The convention is to use a + * NULL-terminated array instead. */ + for (const struct plug_class **pp = plug_provider_classes; + pp && *pp; + pp++) + { + plug_provider_register(*pp); + } +#endif + ovsthread_once_done(&once); + } +} + +static int +plug_provider_register__(const struct plug_class *new_class) +{ + struct plug_class *plug_class; + int error; + + if (shash_find(&plug_classes, new_class->type)) { + VLOG_WARN("attempted to register duplicate plug provider: %s", + new_class->type); + return EEXIST; + } + + error = new_class->init ? new_class->init() : 0; + if (error) { + VLOG_WARN("failed to initialize %s plug class: %s", + new_class->type, ovs_strerror(error)); + return error; + } + + plug_class = xmalloc(sizeof *plug_class); + memcpy(plug_class, new_class, sizeof *plug_class); + + shash_add(&plug_classes, new_class->type, plug_class); + + return 0; +} + +/* Register the new plug provider referred to in 'new_class' and perform any + * class level initialization as specified in its plug_class. */ +int +plug_provider_register(const struct plug_class *new_class) +{ + int error; + + ovs_mutex_lock(&plug_classes_mutex); + error = plug_provider_register__(new_class); + ovs_mutex_unlock(&plug_classes_mutex); + + return error; +} + +static int +plug_provider_unregister__(const char *type) +{ + int error; + struct shash_node *node; + struct plug_class *plug_class; + + node = shash_find(&plug_classes, type); + if (!node) { + return EINVAL; + } + + plug_class = node->data; + error = plug_class->destroy ? plug_class->destroy() : 0; + if (error) { + VLOG_WARN("failed to destroy %s plug class: %s", + plug_class->type, ovs_strerror(error)); + return error; + } + + shash_delete(&plug_classes, node); + free(plug_class); + + return 0; +} + +/* Unregister the plug provider identified by 'type' and perform any class + * level de-initialization as specified in its plug_class. */ +int +plug_provider_unregister(const char *type) +{ + int error; + + ovs_mutex_lock(&plug_classes_mutex); + error = plug_provider_unregister__(type); + ovs_mutex_unlock(&plug_classes_mutex); + + return error; +} + +/* Check whether there are any plug providers registered */ +bool +plug_provider_has_providers(void) +{ + return !shash_is_empty(&plug_classes); +} + +const struct plug_class * +plug_provider_get(const char *type) +{ + struct plug_class *plug_class; + + ovs_mutex_lock(&plug_classes_mutex); + plug_class = shash_find_data(&plug_classes, type); + ovs_mutex_unlock(&plug_classes_mutex); + + return plug_class; +} + +/* Iterate over plug providers and call their run function. + * + * Returns 'true' if any of the providers run functions return 'true', 'false' + * otherwise. + * + * A return value of 'true' means that data has changed. */ +bool +plug_provider_run_all(void) +{ + struct shash_node *node, *next; + bool changed = false; + + SHASH_FOR_EACH_SAFE (node, next, &plug_classes) { + struct plug_class *plug_class = node->data; + if (plug_class->run && plug_class->run(plug_class)) { + changed = true; + } + } + return changed; +} + +/* De-initialize and unregister the plug provider classes. */ +void +plug_provider_destroy_all(void) +{ + struct shash_node *node, *next; + + SHASH_FOR_EACH_SAFE (node, next, &plug_classes) { + struct plug_class *plug_class = node->data; + plug_provider_unregister(plug_class->type); + } +} diff --git a/lib/plug-provider.h b/lib/plug-provider.h new file mode 100644 index 000000000..a5ed22684 --- /dev/null +++ b/lib/plug-provider.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021 Canonical + * + * 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 PLUG_PROVIDER_H +#define PLUG_PROVIDER_H 1 + +/* Interface for plug providers. + * + * A plug provider implementation performs lookup and/or initialization of + * ports, typically representor ports, using generic non-blocking hardware + * interfaces. This allows the ovn-controller to, upon the CMS's request, + * create ports and interfaces in the chassis's Open vSwitch instances (also + * known as vif plugging). + * + * This module contains the infrastructure for registering plug providers which + * may be hosted inside or outside the core OVN repository. + */ + +#include + +#include "smap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct plug_class; +struct ovsdb_idl_txn; +struct ovsrec_bridge; + +enum plug_op_type { + PLUG_OP_CREATE = 1, /* Port is created or updated */ + PLUG_OP_REMOVE, /* Port is removed from this chassis */ +}; + +struct plug_port_ctx_in { + /* Operation being performed */ + enum plug_op_type op_type; + + /* These are provided so that the plug implementation may make decisions + * based on environmental factors such as settings in the open-vswitch + * table and datapath type settings on the integration bridge. */ + const struct ovsrec_open_vswitch_table *ovs_table; + const struct ovsrec_bridge *br_int; + + /* Name of logical port, can be useful for plugging library to track any + * per port resource initialization. */ + const char *lport_name; + + /* Logical port options, while OVN will forward the contents verbatim from + * the Southbound database, the convention is for the plugging library to + * only make decisions based on the plug-* options. */ + struct smap lport_options; + + /* When OVN knows about an existing interface record associated with this + * lport, these will be filled in with information about it. */ + const char *iface_name; + const char *iface_type; + struct smap iface_options; +}; + +struct plug_port_ctx_out { + /* The name to use for port and interface record. */ + char *name; + + /* Type of interface to create. */ + char *type; + + /* Options to set on the interface record. */ + struct smap iface_options; +}; + +struct plug_port_ctx { + const struct plug_class *plug; + struct plug_port_ctx_in plug_port_ctx_in; + struct plug_port_ctx_out plug_port_ctx_out; +}; + +struct plug_class { + /* Type of plugger in this class. */ + const char *type; + + /* Called when the plug provider is registered, typically at program + * startup. + * + * This function may be set to null if a plug class needs no + * initialization at registration time. */ + int (*init)(void); + + /* Called when the plug provider is unregistered, typically at program + * exit. + * + * This function may be set to null if a plug class needs no + * de-initialization at unregister time.*/ + int (*destroy)(void); + + /* Performs periodic work needed by plugger, if any is necessary. Returns + * 'true; if anything (i.e. lookup tables) changed, 'false' otherwise. + * + * A return value of 'true' will cause further processing in the + * incremental processing engine, a return value of 'false' will set the + * plug_provider_lookup node as unchanged. */ + bool (*run)(struct plug_class *); + + /* Retrieve Interface options this plugger will maintain. This set is used + * to know which items to remove when maintaining the database record. */ + const struct sset * (*plug_get_maintained_iface_options)(void); + + /* Pass plug_port_ctx_in to plug implementation to prepare for port + * creation/update. + * + * The plug implemantation can perform lookup or any per port + * initialization and should fill plug_port_ctx_out with data required for + * port/interface creation. The plug implementation should return true if + * it wants the caller to create/update a port/interface, false otherwise. + * + * Data in the plug_port_ctx_out struct is owned by the plugging library, + * and a call must be made to the plug_port_ctx_destroy callback to free + * up any allocations when done with port creation/update. + */ + bool (*plug_port_prepare)(const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); + + /* Notify plugging library that port update is done. */ + void (*plug_port_finish)(const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); + + /* Free any allocations made by the plug_port_prepare callback. */ + void (*plug_port_ctx_destroy)(const struct plug_port_ctx_in *, + struct plug_port_ctx_out *); +}; + +extern const struct plug_class plug_dummy_class; +#ifdef HAVE_PLUG_PROVIDER +extern const struct plug_class *plug_provider_classes[]; +#endif + +void plug_provider_initialize(void); +int plug_provider_register(const struct plug_class *); +int plug_provider_unregister(const char *type); +bool plug_provider_has_providers(void); +const struct plug_class * plug_provider_get(const char *); +bool plug_provider_run_all(void); +void plug_provider_destroy_all(void); +void plug_dummy_enable(void); + +#ifdef __cplusplus +} +#endif + +#endif /* plug-provider.h */ diff --git a/lib/plug_providers/dummy/plug-dummy.c b/lib/plug_providers/dummy/plug-dummy.c new file mode 100644 index 000000000..0909bab46 --- /dev/null +++ b/lib/plug_providers/dummy/plug-dummy.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Canonical + * + * 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 "lib/plug-provider.h" + +#include + +#include "openvswitch/vlog.h" +#include "smap.h" +#include "sset.h" + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +VLOG_DEFINE_THIS_MODULE(plug_dummy); + +static struct sset plug_dummy_maintained_iface_options; + +static int +plug_dummy_init(void) +{ + sset_init(&plug_dummy_maintained_iface_options); + sset_add(&plug_dummy_maintained_iface_options, "plug-dummy-option"); + + return 0; +} + +static int +plug_dummy_destroy(void) +{ + sset_destroy(&plug_dummy_maintained_iface_options); + + return 0; +} + +static const struct sset* +plug_dummy_get_maintained_iface_options(void) +{ + return &plug_dummy_maintained_iface_options; +} + +static bool +plug_dummy_run(struct plug_class *plug) +{ + VLOG_DBG("plug_dummy_run(%p)", plug); + + return false; +} + +static bool +plug_dummy_port_prepare(const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out) +{ + VLOG_DBG("plug_dummy_port_prepare: %s", ctx_in->lport_name); + + if (ctx_in->op_type == PLUG_OP_CREATE) { + size_t lport_name_len = strlen(ctx_in->lport_name); + ctx_out->name = xzalloc(IFNAMSIZ); + memcpy(ctx_out->name, ctx_in->lport_name, + (lport_name_len < IFNAMSIZ) ? lport_name_len : IFNAMSIZ - 1); + ctx_out->type = xstrdup("internal"); + smap_init(&ctx_out->iface_options); + smap_add(&ctx_out->iface_options, "plug-dummy-option", "value"); + } + + return true; +} + +static void +plug_dummy_port_finish(const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out OVS_UNUSED) +{ + VLOG_DBG("plug_dummy_port_finish: %s", ctx_in->lport_name); +} + +static void +plug_dummy_port_ctx_destroy(const struct plug_port_ctx_in *ctx_in, + struct plug_port_ctx_out *ctx_out) +{ + VLOG_DBG("plug_dummy_port_ctx_destroy: %s", ctx_in->lport_name); + ovs_assert(ctx_in->op_type == PLUG_OP_CREATE); + free(ctx_out->name); + free(ctx_out->type); + smap_destroy(&ctx_out->iface_options); +} + +const struct plug_class plug_dummy_class = { + .type = "dummy", + .init = plug_dummy_init, + .destroy = plug_dummy_destroy, + .plug_get_maintained_iface_options = + plug_dummy_get_maintained_iface_options, + .run = plug_dummy_run, + .plug_port_prepare = plug_dummy_port_prepare, + .plug_port_finish = plug_dummy_port_finish, + .plug_port_ctx_destroy = plug_dummy_port_ctx_destroy, +}; + +void +plug_dummy_enable(void) +{ + plug_provider_register(&plug_dummy_class); +} + diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml index a71798f68..027b3e858 100644 --- a/ovn-architecture.7.xml +++ b/ovn-architecture.7.xml @@ -67,8 +67,9 @@
  • One or more (usually many) hypervisors. Hypervisors must run Open vSwitch and implement the interface described in - Documentation/topics/integration.rst in the OVN source tree. - Any hypervisor platform supported by Open vSwitch is acceptable. + Documentation/topics/integration.rst in the Open vSwitch + source tree. Any hypervisor platform supported by Open vSwitch is + acceptable.
  • @@ -318,11 +319,19 @@
  • On a hypervisor, any VIFs that are to be attached to logical networks. - The hypervisor itself, or the integration between Open vSwitch and the - hypervisor (described in - Documentation/topics/integration.rst) takes care of this. - (This is not part of OVN or new to OVN; this is pre-existing integration - work that has already been done on hypervisors that support OVS.) + For instances connected through software emulated ports such as TUN/TAP + or VETH pairs, the hypervisor itself will normally create ports and plug + them into the integration bridge. For instances connected through + representor ports, typically used with hardware offload, the + ovn-controller may on CMS direction consult a plugging + provider library for representor port lookup and plug them into the + integration bridge (please refer to + Documentation/topics/plugging-providers.rst for more + information). In both cases the conventions described in + Documentation/topics/integration.rst in the Open vSwitch + source tree is followed to ensure mapping between OVN logical port and + VIF. (This is pre-existing integration work that has already been done + on hypervisors that support OVS.)
  • @@ -921,12 +930,12 @@ Eventually, a user powers on the VM that owns the VIF. On the hypervisor where the VM is powered on, the integration between the hypervisor and Open vSwitch (described in - Documentation/topics/integration.rst) adds the VIF to the OVN - integration bridge and stores vif-id in - external_ids:iface-id to indicate that the - interface is an instantiation of the new VIF. (None of this code is new - in OVN; this is pre-existing integration work that has already been done - on hypervisors that support OVS.) + Documentation/topics/integration.rst in the Open vSwitch + source tree) adds the VIF to the OVN integration bridge and stores + vif-id in external_ids:iface-id to + indicate that the interface is an instantiation of the new VIF. (None of + this code is new in OVN; this is pre-existing integration work that has + already been done on hypervisors that support OVS.)
  • diff --git a/tests/automake.mk b/tests/automake.mk index c4a7c0a5b..982db4984 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -38,7 +38,8 @@ TESTSUITE_AT = \ tests/ovn-ipam.at \ tests/ovn-features.at \ tests/ovn-lflow-cache.at \ - tests/ovn-ipsec.at + tests/ovn-ipsec.at \ + tests/ovn-plug.at SYSTEM_KMOD_TESTSUITE_AT = \ tests/system-common-macros.at \ @@ -243,13 +244,23 @@ tests_ovstest_SOURCES = \ tests/test-ovn.c \ controller/test-lflow-cache.c \ controller/test-ofctrl-seqno.c \ + controller/test-plug.c \ lib/test-ovn-features.c \ northd/test-ipam.c tests_ovstest_LDADD = $(OVS_LIBDIR)/daemon.lo \ $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la \ + controller/binding.$(OBJEXT) \ + controller/encaps.$(OBJEXT) \ + controller/ha-chassis.$(OBJEXT) \ + controller/if-status.$(OBJEXT) \ controller/lflow-cache.$(OBJEXT) \ + controller/local_data.$(OBJEXT) \ + controller/lport.$(OBJEXT) \ controller/ofctrl-seqno.$(OBJEXT) \ + controller/ovsport.$(OBJEXT) \ + controller/patch.$(OBJEXT) \ + controller/plug.$(OBJEXT) \ northd/ipam.$(OBJEXT) # Python tests. diff --git a/tests/ovn-plug.at b/tests/ovn-plug.at new file mode 100644 index 000000000..d5c6a1b6d --- /dev/null +++ b/tests/ovn-plug.at @@ -0,0 +1,8 @@ +# +# Unit tests for the lib/plug.c module. +# +AT_BANNER([OVN unit tests - plug]) + +AT_SETUP([unit test -- plugging infrastructure tests]) +AT_CHECK([ovstest test-plug run], [0], []) +AT_CLEANUP From patchwork Tue Oct 19 10:22:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543168 X-Patchwork-Delegate: zhouhan@gmail.com 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=HuH1PmFR; 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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HYVDQ68t4z9sPB for ; Tue, 19 Oct 2021 21:22:30 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 07A344071C; Tue, 19 Oct 2021 10:22: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 ko56eg1VrboR; Tue, 19 Oct 2021 10:22:25 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 2A489405FD; Tue, 19 Oct 2021 10:22:23 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DB6F9C002B; Tue, 19 Oct 2021 10:22:17 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id C0243C0025 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id A76F640719 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com 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 Cj6Cow5L5az0 for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp4.osuosl.org (Postfix) with ESMTPS id 0E7B24023F for ; Tue, 19 Oct 2021 10:22:10 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id 8984341BF6 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638929; bh=3B5uFKG7Fd7i+fTT/7ntEg+pZFqMeO9HfUv6r7qJIpg=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HuH1PmFROp12JtG48yiRVBpk09oRXD0iUYJ8JdysNaEhDR3gY2Pii0t40YLTO4J0o 8bF3dkw9Uu+c1HOuFLo02L+KecjJOeQsxzZSRVpOKCS8Lxy8fuDWmdMbWmRqyHtZrb 7lWp8Ynp6C7gaMmEhI4VH86jw3BxhswXwvdyNP1deJ4WoDNiH29wrSNrw8rAaoOI4b URhCo2tWEREw+/hzBD4e+hFSVfSkUOWaprdypWwUFYQejXFEUwHLGXB1n1HGibWnBs Hxv5yiCEhJTp9S4S1Ezi0KOx71a/ElWvRqUV6TXg1i58rrvBxp9asirHFDNP2KI5nv likvxb1QvQ2GQ== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:04 +0200 Message-Id: <20211019102205.3837601-11-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 11/12] ovn-controller: Prepare plug provider infrastructure. 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" Add port by interfaces index - To be able to effectively remove ports previously plugged by us we need to look up ports by interface records. Add `enable-dummy-plug` option - To enable testing of the plugging infrastructure without building OVN with an external plugging library we include a dummy implementation which can be enabled using this command line option. Signed-off-by: Frode Nordahl --- controller/ovn-controller.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index c015f936c..ef2bdadc8 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -56,6 +56,8 @@ #include "lib/ovn-sb-idl.h" #include "lib/ovn-util.h" #include "patch.h" +#include "plug.h" +#include "plug-provider.h" #include "physical.h" #include "pinctrl.h" #include "openvswitch/poll-loop.h" @@ -3082,11 +3084,17 @@ main(int argc, char *argv[]) patch_init(); pinctrl_init(); lflow_init(); + plug_provider_initialize(); /* Connect to OVS OVSDB instance. */ struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true)); ctrl_register_ovs_idl(ovs_idl_loop.idl); + + struct ovsdb_idl_index *ovsrec_port_by_interfaces + = ovsdb_idl_index_create1(ovs_idl_loop.idl, + &ovsrec_port_col_interfaces); + ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl); /* Configure OVN SB database. */ @@ -3350,6 +3358,8 @@ main(int argc, char *argv[]) sbrec_port_binding_by_datapath); engine_ovsdb_node_add_index(&en_sb_datapath_binding, "key", sbrec_datapath_binding_by_key); + engine_ovsdb_node_add_index(&en_ovs_port, "interfaces", + ovsrec_port_by_interfaces); struct ed_type_lflow_output *lflow_output_data = engine_get_internal_data(&en_lflow_output); @@ -3878,6 +3888,7 @@ loop_done: pinctrl_destroy(); patch_destroy(); if_status_mgr_destroy(if_mgr); + plug_provider_destroy_all(); ovsdb_idl_loop_destroy(&ovs_idl_loop); ovsdb_idl_loop_destroy(&ovnsb_idl_loop); @@ -3898,6 +3909,7 @@ parse_options(int argc, char *argv[]) VLOG_OPTION_ENUMS, OVN_DAEMON_OPTION_ENUMS, SSL_OPTION_ENUMS, + OPT_ENABLE_DUMMY_PLUG, }; static struct option long_options[] = { @@ -3908,6 +3920,7 @@ parse_options(int argc, char *argv[]) STREAM_SSL_LONG_OPTIONS, {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, + {"enable-dummy-plug", no_argument, NULL, OPT_ENABLE_DUMMY_PLUG}, {NULL, 0, NULL, 0} }; char *short_options = ovs_cmdl_long_options_to_short_options(long_options); @@ -3953,6 +3966,10 @@ parse_options(int argc, char *argv[]) stream_ssl_set_ca_cert_file(optarg, true); break; + case OPT_ENABLE_DUMMY_PLUG: + plug_dummy_enable(); + break; + case '?': exit(EXIT_FAILURE); From patchwork Tue Oct 19 10:22:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1543170 X-Patchwork-Delegate: zhouhan@gmail.com 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=TEs78vGP; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (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 4HYVDY4lTKz9sPB for ; Tue, 19 Oct 2021 21:22:37 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 4C3E560C26; Tue, 19 Oct 2021 10:22:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2jpsI0XouoSK; Tue, 19 Oct 2021 10:22:31 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 052E560C15; Tue, 19 Oct 2021 10:22:28 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 9CD3DC003C; Tue, 19 Oct 2021 10:22:20 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id C1604C0028 for ; Tue, 19 Oct 2021 10:22:12 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id A036440721 for ; Tue, 19 Oct 2021 10:22:12 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com 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 Dg0g8W74lddv for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from smtp-relay-canonical-1.canonical.com (smtp-relay-canonical-1.canonical.com [185.125.188.121]) by smtp4.osuosl.org (Postfix) with ESMTPS id 6466C4026B for ; Tue, 19 Oct 2021 10:22:11 +0000 (UTC) Received: from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250]) (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-1.canonical.com (Postfix) with ESMTPSA id D52E741C06 for ; Tue, 19 Oct 2021 10:22:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1634638930; bh=VyQrAJiK/56XMYXunyvHlBTDU0DBH3PMQIgF6mCLNpg=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TEs78vGPdo9jdnJd81PtZSEP0+ez3DL2C9txwDKBonOQUyTYyyn20vyPV3SEP+HXy yjbE3p+KNQ+qBVmXv6JdBjHdtyTZ5T/fZPrG8Gsxkp0JBAlFEHfc9QE1KzEcbs4bcE pBcgmPcXOEmuAlPFhdNijMyQg6lsxzAhUQp8J9oWcIrz7EFE9d2WwXVg8cCUhaL3SF eM1zLkCFgu4bNQfSaApxEL21a+yP7dIiQnDL1W51HIeFn16zxLguJ9mEQa72sKUT2h cNi/+ypSZNnazAeMCy5Vd7FDQsYzC4JdwKAigUizxYTNcjUY5NNSyjEo1YA1wiGnTY HKvtf3iVp5NMA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 19 Oct 2021 12:22:05 +0200 Message-Id: <20211019102205.3837601-12-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019102205.3837601-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> <20211019102205.3837601-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v7 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 | 222 +++++++++++++++++++++++++++++++++++- ovn-nb.xml | 21 ++++ tests/ovn-controller.at | 1 - tests/ovn-macros.at | 2 +- tests/ovn.at | 121 ++++++++++++++++++++ 5 files changed, 364 insertions(+), 3 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index ef2bdadc8..a92d2820a 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 \ @@ -2978,6 +2979,180 @@ 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) +{ + 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; + bool pb_handler_has_run; +}; + +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); + data->pb_handler_has_run = false; + 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); + + struct ed_type_plug_provider *plug_provider_data = data; + + 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; + plug_ctx_in->pb_handler_has_run = plug_provider_data->pb_handler_has_run; + + 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); + + struct ed_type_plug_provider *plug_provider_data = data; + + bool handled = plug_handle_port_binding_changes(&plug_ctx_in, + &plug_ctx_out); + + plug_provider_data->pb_handler_has_run = true; + + return handled; +} + +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; @@ -3214,6 +3389,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 @@ -3240,6 +3420,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. */ @@ -3800,7 +3998,18 @@ main(int argc, char *argv[]) engine_set_force_recompute(true); } - if (ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop) == 1) { + int ovs_txn_status = ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop); + if (!ovs_txn_status) { + /* The transaction failed. */ + struct ed_type_plug_provider *plug_provider_data = engine_get_data( + &en_plug_provider); + if (plug_provider_data) { + plug_clear_deleted(&plug_provider_data->deleted_iface_ids); + plug_clear_changed(&plug_provider_data->changed_iface_ids); + } + } else if (ovs_txn_status == 1) { + /* The transaction committed successfully + * (or it did not change anything in the database). */ ct_zones_data = engine_get_data(&en_ct_zones); if (ct_zones_data) { struct shash_node *iter, *iter_next; @@ -3813,6 +4022,17 @@ 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); + } + } else if (ovs_txn_status == -1) { + /* The commit is still in progress */ + } else { + OVS_NOT_REACHED(); } ovsdb_idl_track_clear(ovnsb_idl_loop.idl); diff --git a/ovn-nb.xml b/ovn-nb.xml index e31578fb6..c619f6bdd 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1031,6 +1031,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 7c683cbcc..41443a30a 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -803,6 +803,5 @@ OVN_CLEANUP_SBOX([hv]) OVN_CLEANUP_VSWITCH([main]) as ovn-sb OVS_APP_EXIT_AND_WAIT([ovsdb-server]) - 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] diff --git a/tests/ovn.at b/tests/ovn.at index 7cfdede77..168a0b301 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -28789,3 +28789,124 @@ AT_CHECK([grep -q "Not claiming" hv1/ovn-controller.log], [1], []) OVN_CLEANUP([hv1]) 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 + +sim_add hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 + +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 lsp-set-options lsp1 \ + requested-chassis=hv1 \ + plug-type=dummy \ + 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 lsp-set-options lsp2 \ + requested-chassis=hv2 \ + plug-type=dummy \ + plug-mtu-request=42 + +wait_for_ports_up lsp1 lsp2 + +lsp1_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp1) +iface1_uuid=$(as hv1 ovs-vsctl --bare --columns _uuid find Interface name=lsp1) + +lsp2_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp2) +iface2_uuid=$(as hv2 ovs-vsctl --bare --columns _uuid find Interface name=lsp2) + +# Check that the lport was plugged +AT_CHECK([test xvalue = x$(as hv1 ovs-vsctl get Interface ${iface1_uuid} options:plug-dummy-option)], [0], []) +AT_CHECK([test x42 = x$(as hv1 ovs-vsctl get Interface ${iface1_uuid} mtu_request)], [0], []) + +# Check that updating the lport updates the local iface +check ovn-nbctl --wait=hv lsp-set-options lsp1 \ + requested-chassis=hv1 \ + plug-type=dummy \ + plug-mtu-request=43 +OVS_WAIT_UNTIL([ + test x43 = x$(as hv1 ovs-vsctl get Interface ${iface1_uuid} mtu_request) +]) + +# Check that local modification of iface will trigger ovn-controller to update +# the iface record +check as hv1 ovs-vsctl set interface ${iface1_uuid} mtu_request=44 +OVS_WAIT_UNTIL([ + test x43 = x$(as hv1 ovs-vsctl get Interface ${iface1_uuid} mtu_request) +]) + +# Check that pointing requested-chassis somewhere else will unplug the port +check ovn-nbctl --wait=hv set Logical_Switch_Port lsp1 \ + options:requested-chassis=non-existent-chassis +OVS_WAIT_UNTIL([ + ! as hv1 ovs-vsctl get Interface ${iface1_uuid} _uuid +]) + +# Check that removing an lport will unplug it +AT_CHECK([test x${iface2_uuid} = x$(as hv2 ovs-vsctl get Interface ${iface2_uuid} _uuid)], [0], []) +check ovn-nbctl --wait=hv lsp-del ${lsp2_uuid} +OVS_WAIT_UNTIL([ + ! as hv2 ovs-vsctl get Interface ${iface2_uuid} _uuid +]) + +# Check that port is unplugged when we simulate presence of a port previously +# plugged by us in local OVSDB with no record in SB DB. +check as hv2 ovs-vsctl \ + -- add-port br-int vif1 + +# From one moment it's there... +vif1_uuid=$(as hv2 ovs-vsctl --bare --columns _uuid find Interface name=vif1) +OVS_WAIT_UNTIL([ + as hv2 ovs-vsctl get Interface ${vif1_uuid} _uuid +]) + +# Add the external-ids we expect +check as hv2 ovs-vsctl \ + -- set Interface ${vif1_uuid} \ + external-ids:ovn-plugged=dummy \ + external-ids:iface-id=non-existing-lsp + +# ...to the next moment it's gone. +OVS_WAIT_UNTIL([ + ! as hv2 ovs-vsctl get Interface ${vif1_uuid} _uuid +]) + +# Check that a warning is logged when CMS requests plugging of an interface +# with lbinding already plugged by someone else. +check as hv2 ovs-vsctl \ + -- add-port br-int vif3 \ + -- set Interface vif3 \ + external-ids:iface-id=lsp3 + +check ovn-nbctl lsp-add lsw0 lsp3 +check ovn-nbctl lsp-set-addresses lsp3 "f0:00:00:00:00:03 172.16.0.103" +check ovn-nbctl lsp-set-options lsp3 \ + requested-chassis=hv2 + +wait_for_ports_up lsp3 + +check ovn-nbctl --wait=hv lsp-set-options lsp3 \ + requested-chassis=hv2 \ + plug-type=dummy + +OVS_WAIT_UNTIL([ + grep -q "CMS requested plugging of lport lsp3" hv2/ovn-controller.log +]) + +OVN_CLEANUP([hv1],[hv2]) +AT_CLEANUP +]) From patchwork Mon Oct 25 15:59:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1545825 X-Patchwork-Delegate: zhouhan@gmail.com 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=EEQYTJdQ; 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 bilbo.ozlabs.org (Postfix) with ESMTPS id 4HdKQJ37lpz9t0k for ; Tue, 26 Oct 2021 02:59:18 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id E5666401AF; Mon, 25 Oct 2021 15:59:14 +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 QACXMA9nhyNK; Mon, 25 Oct 2021 15:59:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id DE414400B9; Mon, 25 Oct 2021 15:59:12 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 99040C0012; Mon, 25 Oct 2021 15:59:12 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0DE7BC000E for ; Mon, 25 Oct 2021 15:59:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DECF9402FF for ; Mon, 25 Oct 2021 15:59:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com 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 JmbFxGYLQIdf for ; Mon, 25 Oct 2021 15:59:10 +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 smtp4.osuosl.org (Postfix) with ESMTPS id ECD37402A8 for ; Mon, 25 Oct 2021 15:59:09 +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 E3E0C3FFE8; Mon, 25 Oct 2021 15:59:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1635177546; bh=oA04Js3SGeqVaevk1JmRg6k1WY9iDzcIan5j167LIx0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EEQYTJdQr4s+WQSBhwGmFOvDP+MwWFKFMfJYLAjPb+ffQGtnmxTbvnPf/ShkDareL /SWsHvyhsPFgblIsIHe2hk3p/7gJsWs2Id1svOUA9UB6TGlzNIHzE/qjBBdPt1o5IM G4vLp7vEO0BGTvm7c2bWBThCbcLHAleEDGtdXQKSzxy7yCIzKV3JoVNd6bwKNAOQ1h 9vt1VQjoug+Cg3fdxBa+oH1TQC2Xy05SrOx6Fa/qBQRneC90L/jstZdZcYvJ4rKp8L nGwjg++r386DRJLnzF4LZPAWTK2CC77oIH+W4Ktc0Gr7sKFmH61wqo6ZHl2Uypup3R Q6p48prIF9q5A== From: Frode Nordahl To: dev@openvswitch.org Date: Mon, 25 Oct 2021 17:59:04 +0200 Message-Id: <20211025155904.169183-1-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211019101348.3833652-1-frode.nordahl@canonical.com> References: <20211019101348.3833652-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 13/12 v7] NEWS: Add note on infrastructure for plug providers. 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" Signed-off-by: Frode Nordahl --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 5f448e67d..7a993a0be 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,13 @@ Post v21.09.0 if not desired. - Added Load_Balancer_Group support, which simplifies large scale configurations of load balancers. + - Introduced infrastructure for plug providers. When OVN is linked with an + appropriate plug implementation, such as OVN VIF [0], CMS can request OVN + to plug lports. This is particularly useful in topologies where the + ovn-controller process is running on SmartNIC control plane CPUs. Please + refer to Documentation/topics/plug_providers/plug-providers.rst for more + information. + [0] https://github.com/ovn-org/ovn-vif OVN v21.09.0 - 01 Oct 2021 --------------------------