From patchwork Tue Sep 28 15:53:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533974 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=B1eRFtTb; 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 4HJkZL3cXFz9sW8 for ; Wed, 29 Sep 2021 01:53:46 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id F1C104058F; Tue, 28 Sep 2021 15:53:43 +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 11DAZYZwzota; Tue, 28 Sep 2021 15:53:41 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id D4B994056F; Tue, 28 Sep 2021 15:53:39 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BDA2EC0028; Tue, 28 Sep 2021 15:53:37 +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 9E410C000D for ; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 80ED281A9C for ; Tue, 28 Sep 2021 15:53:34 +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 as3Dj_EMaTSq for ; Tue, 28 Sep 2021 15:53:33 +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 F042781A4E for ; Tue, 28 Sep 2021 15:53:32 +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-1.canonical.com (Postfix) with ESMTPSA id 1007B41979; Tue, 28 Sep 2021 15:53:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844410; bh=LDsCPbC1rkm27ZbmBl0UqXYFaltvAV+SxdJY0bztW94=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B1eRFtTb/Vk2tllXjbSGZp26MemUAlH7BYcDXPrVOuaFUJU1XNCJGTfSNKHp9Ipz1 GwBsAXOHMHZwpN8h9Erk8wvB7T1PD7ZKOE8fzM9wqGU2TIC89DxHMRUF7LK5SIh9p8 1lS0IX+LRgAlHa+8Wk6Ssp/Cwn8tLIa573JWoNNtOBf85p1bevPb9tsnnftfXOEXd6 sBtN/tY7MDKuEBhAyn2KGnRxzwuzlowJ+22UIMf8R5AFVeVwzNd87rDsPa/M7aWJeN Lv7Xi47Q4K5CEH6/LJT4tz6eGvDvlbHuX3LVbzkX2/v3lJreJ5OXyC6/a7Xq3H6Hmt ZeJ5SH0Rhkn3g== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:14 +0200 Message-Id: <20210928155325.2290444-2-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 Acked-by: Numan Siddique --- 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 cf2467fe1..eb0e5d6de 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -2982,6 +2982,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) @@ -3163,6 +3164,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) { @@ -3791,6 +3822,7 @@ ovn_port_allocate_key(struct hmap *ports, struct ovn_port *op) 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; @@ -3846,6 +3878,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); } @@ -3853,7 +3886,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); @@ -14208,6 +14242,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, @@ -14309,7 +14344,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); @@ -14656,6 +14692,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) { @@ -14668,8 +14705,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 22913f05a..e379623a6 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 5de554455..258b58e98 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -5223,3 +5223,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 Sep 28 15:53:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533973 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=s9WUzUBf; 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 4HJkZG1PRcz9sW8 for ; Wed, 29 Sep 2021 01:53:40 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id C3D4C607A5; Tue, 28 Sep 2021 15:53:37 +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 sznNL4Z_BfsM; Tue, 28 Sep 2021 15:53:37 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 180B960777; Tue, 28 Sep 2021 15:53:36 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C1A38C000F; Tue, 28 Sep 2021 15:53:35 +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 07ABFC000D for ; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D5F5160777 for ; Tue, 28 Sep 2021 15:53:33 +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 Zpphr3PG8i1G for ; Tue, 28 Sep 2021 15:53:33 +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 2E20660745 for ; Tue, 28 Sep 2021 15:53:33 +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-1.canonical.com (Postfix) with ESMTPSA id 7E56241997; Tue, 28 Sep 2021 15:53:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844410; bh=3KGbHByI+nRlbdHO61jdYdI7hIjwRUaEKI554OxW2tU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=s9WUzUBf83M3kbu13KkxGBZ/UjxVj/GPE1cqCqnh9Go4/z6YEknniKOu4Utm9BnvU eenzyU7V+c8oeRt2N6y4AfYUT+Mz3/caM8zGK3g2T3+sqnWITcJc76yl4Lhtt2M09f tGW0LRO1IEPcLE3P3FDba0+kRoH9um6f/bXze1uJjRJ+ivjcuflZ0vx4LT/3obv1+i LGFJnpR5OR9r7Tf/FyGmmJuQ/NW3DV8BTS4e9+xOt8YON6AcRPiWPdaBwf2a1Xh5jm FrPEyc8akLkixH6S5ZjQZXP00rSkrEWV4+9Hx5pCfQe1eOgBDD3ujnYjpWIkatQLxR ucbli2yxxGkuA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:15 +0200 Message-Id: <20210928155325.2290444-3-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 02/12] test: Fix options:requested-chassis with hostname X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" This test currently passes, but is broken in two ways. 1) The `fetch_column` helper should be used to retrieve the value of hostname, not `fetch` wich results in a "fetch: command not found" error which is currently not caught by the test. As a consequence the requested-chassis option was set to the empty string ("") and not the chassis hostname. 2) When we introduced testing with TLS+RBAC in c948d6bb05b4 the ovn_az_attach helper was updated to set the hostname to match system-id. This of course also makes the name and hostname columns in the Chassis record contain the same value which made this test no longer do what it says on the tin. Update test to explicitly set the value to be used for requested-chassis option in the Chassis hostname record, and add a check for it not being empty nor equal to chassis name. Fixes: 4afe409e95c7 ("tests: Introduce new testing helpers.") Fixes: c948d6bb05b4 ("tests: Test with SSL and RBAC for controller by default") Signed-off-by: Frode Nordahl --- tests/ovn.at | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ovn.at b/tests/ovn.at index 172b5c713..13e97cfd2 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -13471,13 +13471,15 @@ ovn-nbctl lsp-add ls0 lsp0 net_add n1 sim_add hv1 as hv1 +ovs-vsctl set Open_vSwitch . external-ids:hostname=hv1-hostname ovs-vsctl add-br br-phys ovn_attach n1 br-phys 192.168.0.11 ovs-vsctl -- add-port br-int hv1-vif0 -- set Interface hv1-vif0 ofport-request=1 wait_row_count Chassis 1 name=hv1 -hv1_hostname=$(fetch Chassis hostname name=hv1) +hv1_hostname=$(fetch_column Chassis hostname name=hv1) echo "hv1_hostname=${hv1_hostname}" +AT_CHECK([test -n "${hv1_hostname}" -a "${hv1_hostname}" != hv1], [1], []) check ovn-nbctl --wait=hv lsp-set-options lsp0 requested-chassis=${hv1_hostname} as hv1 ovs-vsctl set interface hv1-vif0 external-ids:iface-id=lsp0 From patchwork Tue Sep 28 15:53:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533975 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=WQkjkBXW; 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 4HJkZL50Czz9t0T for ; Wed, 29 Sep 2021 01:53:46 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 9BB81403AB; Tue, 28 Sep 2021 15:53:40 +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 6HdzAGlORNUy; Tue, 28 Sep 2021 15:53:39 +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 B2AB2403A5; Tue, 28 Sep 2021 15:53:38 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C1CBAC0025; Tue, 28 Sep 2021 15:53:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2EC34C000D for ; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 1E0BA40105 for ; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp2.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=canonical.com Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Sw9CItpWOpik for ; Tue, 28 Sep 2021 15:53:33 +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 smtp2.osuosl.org (Postfix) with ESMTPS id F1F62400C5 for ; Tue, 28 Sep 2021 15:53:32 +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-1.canonical.com (Postfix) with ESMTPSA id E845841998; Tue, 28 Sep 2021 15:53:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844411; bh=9lqgAmFZqsKw21DcvKE0oDPubzOWutf482atpC/5UCE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WQkjkBXW+sFHw/S2b3ZS6JzLuLE4PH9dXIR7tX/0UatkUzVFje40pFHiD+n8UTDdA R/Cghoo7UkXPL+9SkQdiYDX6PMBpylD9l1Rz9gQO4gXte5OdyJ3/12ju8vcGKciw8s Qbu0iRx9rf1elUpBwxWGWBiVZd6egZuFVbaF8EHHAgxFP603WIXaqPEnhH+tohQKJY Mmo5ZhTXpk0k45X0WbbuyT5i949zWWlljcgVmpcG50Y9JK5kYX4mPqi4DQjkqSoGdt QvvGKW6yJNEOeVqozZA5TX15w411mu0OnN1jd9nn1JH8pf6MVGeZYjiSG7+DC/R+RA LBtg7hAdrVATQ== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:16 +0200 Message-Id: <20210928155325.2290444-4-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 03/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. Signed-off-by: Frode Nordahl --- controller/binding.c | 36 +++++++++++++++++++----------------- controller/ovn-controller.c | 3 +++ controller/physical.c | 12 +++++++----- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index c037b2352..a2eb86c89 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1056,11 +1056,15 @@ 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) + const struct sbrec_port_binding *pb) { - return !requested_chassis || !requested_chassis[0] - || !strcmp(requested_chassis, chassis_rec->name) - || !strcmp(requested_chassis, chassis_rec->hostname); + /* 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. */ + return !smap_get(&pb->options, "requested-chassis") + || chassis_rec == pb->requested_chassis; } /* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER, @@ -1098,7 +1102,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 +1143,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 +1169,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 +1199,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 +1284,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 +1335,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 a719beb0e..b0e4174aa 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/controller/physical.c b/controller/physical.c index 0cfb158c8..780093638 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -1066,11 +1066,13 @@ 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)) { + /* 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. */ + if (ofport && smap_get(&binding->options, "requested-chassis") + && binding->requested_chassis != chassis) { /* Even though there is an ofport for this port_binding, it is * requested on a different chassis. So ignore this ofport. */ From patchwork Tue Sep 28 15:53:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533977 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=iePZOA3Q; 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 4HJkZP6WxWz9sW8 for ; Wed, 29 Sep 2021 01:53:49 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 8A32360779; Tue, 28 Sep 2021 15:53:45 +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 8LB1Ryu9ykhG; Tue, 28 Sep 2021 15:53:42 +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 509EF60B38; Tue, 28 Sep 2021 15:53:41 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 00863C0024; Tue, 28 Sep 2021 15:53:39 +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 F07A2C000D for ; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id D38F8403A0 for ; Tue, 28 Sep 2021 15:53:34 +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 7I-wns-xgekf for ; Tue, 28 Sep 2021 15:53:33 +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 7C317401ED for ; Tue, 28 Sep 2021 15:53:33 +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-1.canonical.com (Postfix) with ESMTPSA id 4FA3B4199A; Tue, 28 Sep 2021 15:53:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844411; bh=Ge8gZWwck7np+yo+7hQKLNyeNDiptsrz0DU0E1Nb3QM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iePZOA3QH11YVQx7hm2vlG59CcR7IOdskSdrPOSycQAHto8BAMPAC2kCmzlDHlUU3 j3xbFagGRvuY0yDGRAJT123xKoNyfJAlagMvWKK2o3dFGDdE97T0AEfjrjEXHtC7jb 0aUWZyMui2vGB1HL2zBusL8WBFiI1tSlgKzbh3cOtFkec7clGal0IDUY83OFFhVVkY mqKdS02D95GhQfxjx9O6md7zl72mGS/tkdALcw79vAoxPc9uh9et4RNZYWzpxSSbUe oEj81dJUDulUcsgJ9n9YK+WywS4s1lDxEa3JVKu9Lu619i88k7jwPBb8rbOPrb+NiZ 8DBy0z7ZkuD6g== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:17 +0200 Message-Id: <20210928155325.2290444-5-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 04/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 Acked-by: Numan Siddique --- 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 Sep 28 15:53:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533976 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=p0VQ/YHJ; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::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 4HJkZN5NTTz9sW8 for ; Wed, 29 Sep 2021 01:53:48 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A798F823C6; Tue, 28 Sep 2021 15:53:45 +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 6AvbkyidSAZ8; Tue, 28 Sep 2021 15:53:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id EC4658247F; Tue, 28 Sep 2021 15:53:42 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0BA5EC0025; Tue, 28 Sep 2021 15:53:40 +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 1F30EC000D for ; Tue, 28 Sep 2021 15:53:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1CAF5401ED for ; Tue, 28 Sep 2021 15:53:35 +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 FYLuJ03liMyx for ; Tue, 28 Sep 2021 15:53:34 +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 7BD5340336 for ; Tue, 28 Sep 2021 15:53:34 +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-1.canonical.com (Postfix) with ESMTPSA id CF1C14199B; Tue, 28 Sep 2021 15:53:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844412; bh=wfhStxVbg/X5SMKKSdhAa+c99+UoZWKNxffSDVizhvk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=p0VQ/YHJ3xRaBGdmhjHxjHEbJ0gxktWXV8ubG1vVd7oLvyvLKu93tKrxdkNdz7x+d 3VYEgBJEtCFHswsOkjJm8zHQ4FgXco5CXHxrs6dTndvmflrlajD8L+7qHwiXxZCeL4 fR//vnQptywgNxYhDqQs0lbhHnbw01YmK5ANNB3Q2WOBiF1p3oQuD4HZ9U9QA+GmDf 5OunMuf1o7VzWTFrjrmmbyjhDzls2kTxyvK5/EvJkJKV5VScjg8ngaaXTgBkZ1Xi7c SNB5qesG+++1Pacs3g7LZ1d3bMdXriQpnZCoLxHVzTWVnYc6QYCwT1J2X5sGrzcZY1 3AphDq5iLtkOw== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:18 +0200 Message-Id: <20210928155325.2290444-6-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 05/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 Acked-by: Numan Siddique --- 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 Sep 28 15:53:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533978 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=Bss/fppm; 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 4HJkZR1G6Xz9sW8 for ; Wed, 29 Sep 2021 01:53:51 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 6039740593; Tue, 28 Sep 2021 15:53:47 +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 BbWU5F3rlSOh; Tue, 28 Sep 2021 15:53:45 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id A7D32400C5; Tue, 28 Sep 2021 15:53:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DEBC5C000F; Tue, 28 Sep 2021 15:53:40 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 51A0CC000D for ; Tue, 28 Sep 2021 15:53:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 425F181A9C for ; Tue, 28 Sep 2021 15:53:35 +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 PPnMsmXr01h8 for ; Tue, 28 Sep 2021 15:53:34 +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 876D081A4E for ; Tue, 28 Sep 2021 15:53:34 +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-1.canonical.com (Postfix) with ESMTPSA id 476F6419A3; Tue, 28 Sep 2021 15:53:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844412; bh=9I3lCbCR8BmgrAbZg13UxzAQr4QklMHkv7RXa2rPzf4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Bss/fppmcEWOwf7E0vcNGl0AADY6pg+RxNBD0OJXZcm4Y+4yt9IIa32SI1rn5BB2/ ahIANogilfL+1UfsRNagHVYEHwXNLM2pnZJKPjAe/LRez/QInBCUGejkd/6sGQESOC 5XbgnKHBfjYtrZm1Qr5XZPgMEDQ/mWckDWJ6BjtAstsbEkBznHbJdbrTVtc4tPCgI7 I78htgJSbFjawY2t8pHxUIgIz46hXMBeVcjJ/z7EkJ5CqnC1hGMk8+Z1r6+f0mWXZ0 TaXbz5oKbC5Cg6s8MMIr48DN9dw2fG7mNvxAxNNJnzjZpOpvKYSztKhegm+DYsGm2R lgb+sUJHzgY7Q== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:19 +0200 Message-Id: <20210928155325.2290444-7-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 06/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 | 17 ++--------------- controller/lport.c | 14 ++++++++++++++ controller/lport.h | 3 +++ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index a2eb86c89..ecfddced5 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1054,19 +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. */ - return !smap_get(&pb->options, "requested-chassis") - || chassis_rec == pb->requested_chassis; -} - /* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER, * 'false' otherwise. */ static bool @@ -1169,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, @@ -1284,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..f6cab3c7c 100644 --- a/controller/lport.c +++ b/controller/lport.c @@ -108,6 +108,20 @@ 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. */ + return !smap_get(&pb->options, "requested-chassis") + || 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 Sep 28 15:53:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533979 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=hgmtlEvJ; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::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 4HJkZS2KHtz9sW8 for ; Wed, 29 Sep 2021 01:53:52 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 33CEC81D19; Tue, 28 Sep 2021 15:53:48 +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 DDlHCABHDfVB; Tue, 28 Sep 2021 15:53:47 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 1E73B8269C; Tue, 28 Sep 2021 15:53:46 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B669CC0031; Tue, 28 Sep 2021 15:53:41 +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 708C5C000D for ; Tue, 28 Sep 2021 15:53:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 5294B60779 for ; Tue, 28 Sep 2021 15:53:35 +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 rmztrHej3h4k for ; Tue, 28 Sep 2021 15:53:34 +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 94FC960745 for ; Tue, 28 Sep 2021 15:53:34 +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-1.canonical.com (Postfix) with ESMTPSA id B0EF8419A4; Tue, 28 Sep 2021 15:53:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844412; bh=OImPuqS7zBWjSs1zTMK/OtgyFO2OzLGk8XUtxlmvQk0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hgmtlEvJgkwa2SNpQsQeJGx4XP2n76sgLPTxg2dnQnVS+pDteRF8Gv5pLd1sH717b wYw91JozHqYMHha27z8Nb1yksVrnISZir2RjmbAjw+2SojfREw16Z7rvtYJx6GvVsq bYytluzmylRpT263f5zMXDQ+GAd48ZUcjkr14YiR73QDVOJYzNA2X2D6Xbl/SMzQ38 vht0cueoj2Zw+7239zn8d9DlNh8ps8IhWKxNfmgLL/7dklyPftgiOil9LfX5LCOwru UxB9xNLInCigLfyGepb+KXOsLdgd/a5FinP0FWXEfVD7vCEyZ80SSc4DszR7K3Aztk aRwkL0wteAnJA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:20 +0200 Message-Id: <20210928155325.2290444-8-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 Acked-by: Numan Siddique --- 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 Sep 28 15:53:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533980 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=dSBlM2Yc; 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 4HJkZV5BTnz9sW8 for ; Wed, 29 Sep 2021 01:53:54 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 73CA541590; Tue, 28 Sep 2021 15:53:52 +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 xYFsqJxvX0I7; Tue, 28 Sep 2021 15:53:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id C691241490; Tue, 28 Sep 2021 15:53:48 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 77836C0040; Tue, 28 Sep 2021 15:53:43 +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 880BFC000D for ; Tue, 28 Sep 2021 15:53:36 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id BBA4E60779 for ; Tue, 28 Sep 2021 15:53:35 +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 Qsr32U37tH2C for ; Tue, 28 Sep 2021 15:53:35 +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 02AD860777 for ; Tue, 28 Sep 2021 15:53:34 +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-1.canonical.com (Postfix) with ESMTPSA id 5DD2641998; Tue, 28 Sep 2021 15:53:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844413; bh=v6A/7jmscQGjrr1aNmYjpeJjCacQ3uwe6o9O8fIAj8w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dSBlM2Yc5OCO/khWQ+3L3AIoJph25idZ+UMingaAqXpwNoU5lkYRkQy9zPASBMyu6 XiI5G+Ol/b2TGsX4FRWL4HBczslDBeK5CZ7XD7sbgZZ9WrDIqJQirtO5QGRe3Wi2AX xamEnAYQgz0bRCGbyrVDPvGA+W5C+B7Myz7GI1VuMmEKe5Ye00NHrdbJLzads+8k79 sbtQGmwtX9xEpUsZmc/50IIqmcx+62H3L3cwySBFkiM6PhGwSi0fe1FlPpCmbu/ZC1 yM4ugUsej32T23VET0gdUzWZ01KInIktFQPPnIhjpdqZ2IVyyaFHg5cJG9mlk3dkKD e6DqUGffrXi/w== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:21 +0200 Message-Id: <20210928155325.2290444-9-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 Acked-by: Numan Siddique --- controller/local_data.h | 11 +++-------- controller/ovn-controller.c | 26 -------------------------- controller/ovn-controller.h | 5 ----- lib/ovn-util.c | 27 +++++++++++++++++++++++++++ lib/ovn-util.h | 18 +++++++++++++++++- 5 files changed, 47 insertions(+), 40 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 b0e4174aa..8e35188c6 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/controller/ovn-controller.h b/controller/ovn-controller.h index 78a53312f..827b7442d 100644 --- a/controller/ovn-controller.h +++ b/controller/ovn-controller.h @@ -40,13 +40,8 @@ struct ct_zone_pending_entry { enum ct_zone_pending_state state; }; -const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, - const char *br_name); - struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); -uint32_t get_tunnel_type(const char *name); - struct pb_ld_binding { const struct sbrec_port_binding *pb; const struct local_datapath *ld; 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 Sep 28 15:53:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533981 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=JhdqVWVQ; 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 4HJkZY4ZXpz9sW8 for ; Wed, 29 Sep 2021 01:53:57 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 90909407BA; Tue, 28 Sep 2021 15:53:54 +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 Ob4QB25xX1OP; Tue, 28 Sep 2021 15:53:53 +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 9ECB6407AD; Tue, 28 Sep 2021 15:53:50 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C0EC5C002F; Tue, 28 Sep 2021 15:53:44 +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 08BB6C0026 for ; Tue, 28 Sep 2021 15:53:37 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 433696078F for ; Tue, 28 Sep 2021 15:53:36 +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 aSDzuijKHzQp for ; Tue, 28 Sep 2021 15:53:35 +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 9FA3960745 for ; Tue, 28 Sep 2021 15:53:35 +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-1.canonical.com (Postfix) with ESMTPSA id DACA141304; Tue, 28 Sep 2021 15:53:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844414; bh=EiWgYaOfjrkdkaD4XxWY8lq8IIi5XBiUHKmF6guL4mg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JhdqVWVQrec+HXEUaYYHH+MMMVrZUbkNKSA+Y7iGaPsZpQe0/iaPBa/v7tynMrRIB LRLKxPcv3+/IdyK3AWw6aLwdTOd9fPS0uV449DKDs4Vi5DRY13p2DtV4YJ9H2Jwbwk xQN4SLaCD6E2bpvLt4bpE+Db4nl5P1pdySsJXIQKVrJQqx9udQrM9VkR9dyhVJ7ypt GLQrBFBiX0w5aveaFauQzV28tPXqmAXWFZk47kROohoNG2ruITnJT5SkY8+liHkLUV lA5F1MJGqhLU/NIjyNoLNF4ZM1GsjAjTf5ulb70qnbU6zmm0pcTwW0ykqIOPX7gPa2 NEz/GoDWLr2yg== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:22 +0200 Message-Id: <20210928155325.2290444-10-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 Acked-by: Numan Siddique --- 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 Sep 28 15:53:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533985 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=bNKbZT4L; 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 4HJkZq22Lmz9sW8 for ; Wed, 29 Sep 2021 01:54:11 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 93BFC4059D; Tue, 28 Sep 2021 15:54:08 +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 CqiY4qGkp1VD; Tue, 28 Sep 2021 15:54:03 +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 8C5B34071C; Tue, 28 Sep 2021 15:53:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id F0AE5C0026; Tue, 28 Sep 2021 15:53:48 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 217B4C002D for ; Tue, 28 Sep 2021 15:53:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 107A581CE1 for ; Tue, 28 Sep 2021 15:53:39 +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 1LaIXwjT0pkm for ; Tue, 28 Sep 2021 15:53:36 +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 0876D81A4E for ; Tue, 28 Sep 2021 15:53:35 +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-1.canonical.com (Postfix) with ESMTPSA id 5C73641997; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844414; bh=fVQW+zMavAKSEPxm+JshFeptSgfzyNsSjmIqZ6b8eCI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bNKbZT4LTkQ8VhCpKYQkYe63dnkoxs6p5mZ507XLvCKF54HHSEIYipTZpFhzmFoqX L/dBVsj5YQsEq2ZYFDH9jyXop09I3tuP06jhVGSitSisoE043FSp97ikvN4Gxyzh3g sSFijlzO5shy8rTYpF2TL2m9bNagFAkUVie+64IcNyRfz/tn0Gtv11padsW2WNNtIi kh+8lBf3GcAEVA38tlGi5N45mYf5cBwdZNbcHrPsbvxs+wgrLM7JIcDK1lYvpef5yJ rRtuDnqo+PoWbDzvr+taqFh1zIJYK2E6BCDOd0SCLCEntjadovVkexJ6MfD3yjCw9P 4TAWYrPKQDFzA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:23 +0200 Message-Id: <20210928155325.2290444-11-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 | 636 ++++++++++++++++++ controller/plug.h | 80 +++ 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 | 121 ++++ ovn-architecture.7.xml | 35 +- tests/automake.mk | 13 +- tests/ovn-plug.at | 8 + 17 files changed, 1611 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..cf6f26a98 --- /dev/null +++ b/controller/plug.c @@ -0,0 +1,636 @@ +/* + * 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(); +} + +/* 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) +{ + if (ctx_out) { + memset(ctx_out, 0, sizeof(*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; + smap_init((struct smap *)&new_ctx->plug_port_ctx_in.lport_options); + smap_init((struct smap *)&new_ctx->plug_port_ctx_in.iface_options); + + if (pb) { + smap_clone((struct smap *)&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((struct smap *)&new_ctx->plug_port_ctx_in.iface_options, + &iface->options); + } + + return new_ctx; +} + +static void +destroy_port_ctx(struct plug_port_ctx *ctx) +{ + smap_destroy((struct smap *)&ctx->plug_port_ctx_in.lport_options); + smap_destroy((struct smap *)&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); + } + 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 upon successful 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_lport(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 = NULL; + plug_type = smap_get(&iface->external_ids, + OVN_PLUGGED_EXT_ID); + + if (plug_type) { + 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 (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' 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; + } + 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 (lport %s) on direction " + "from plugging library.", + iface->name, pb ? pb->logical_port : "(none)"); + destroy_port_ctx(plug_port_ctx); + return false; + } + VLOG_INFO("Unplugging port %s from %s for lport %s on this " + "chassis.", + port->name, + plug_ctx_in->br_int->name, + pb ? pb->logical_port : "(none)"); + + /* 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)) { + 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_is_deleted_iface_id(const struct plug_ctx_out *plug_ctx_out, + const char *iface_id) +{ + return shash_find(plug_ctx_out->deleted_iface_ids, iface_id) != NULL; +} + +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_is_deleted_iface_id(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 + && !shash_find( + plug_ctx_out->deleted_iface_ids, pb->logical_port)) { + handled &= consider_unplug_lport(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_is_deleted_iface_id(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_lport(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) +{ + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_TABLE_FOR_EACH (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) { + plug_handle_lport_vif(pb, plug_ctx_in, plug_ctx_out); + } + } + const struct ovsrec_interface *iface_rec; + OVSREC_INTERFACE_TABLE_FOR_EACH (iface_rec, + plug_ctx_in->iface_table) { + if (ovsrec_interface_is_deleted(iface_rec)) { + continue; + } + plug_handle_iface(iface_rec, 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_is_deleted_iface_id(plug_ctx_out, pb->logical_port)) { + handled &= consider_unplug_lport(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; +} + +void +plug_finish_deleted(struct shash *deleted_iface_ids) +{ + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, deleted_iface_ids) { + struct plug_port_ctx *plug_port_ctx = node->data; + 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_finish_changed(struct shash *changed_iface_ids) +{ + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, changed_iface_ids) { + struct plug_port_ctx *plug_port_ctx = node->data; + 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); + } +} diff --git a/controller/plug.h b/controller/plug.h new file mode 100644 index 000000000..d18e1c522 --- /dev/null +++ b/controller/plug.h @@ -0,0 +1,80 @@ +/* + * 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; +}; + +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_finish_deleted(struct shash *deleted_iface_ids); +void plug_finish_changed(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..a6c4b8062 --- /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..c26b172d2 --- /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. */ + const 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; + const 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..6518d8698 --- /dev/null +++ b/lib/plug_providers/dummy/plug-dummy.c @@ -0,0 +1,121 @@ +/* + * 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"); + ctx_out->iface_options = xmalloc(sizeof *ctx_out->iface_options); + 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); + free(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 3d2910358..152367a89 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 Sep 28 15:53:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533984 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=dgOm4wLQ; 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 4HJkZn0Yq4z9sW8 for ; Wed, 29 Sep 2021 01:54:09 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C48B5827CA; Tue, 28 Sep 2021 15:54:06 +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 PfnGC01MycQb; Tue, 28 Sep 2021 15:54:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 4F1BE82572; Tue, 28 Sep 2021 15:53:57 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C3AB5C0032; Tue, 28 Sep 2021 15:53:49 +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 26486C002E for ; Tue, 28 Sep 2021 15:53:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 14FAB606F7 for ; Tue, 28 Sep 2021 15:53:37 +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 IB-gwpG-HCWr for ; Tue, 28 Sep 2021 15:53:36 +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 70A3860745 for ; Tue, 28 Sep 2021 15:53:36 +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-1.canonical.com (Postfix) with ESMTPSA id CF5204199A; Tue, 28 Sep 2021 15:53:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844415; bh=vNySEbzHt+057bOyVvp4XvSEej1FhGpqTsYZ/qJ9WNQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dgOm4wLQve+UAm9EKmODrjQi0z10VuTK92mpmbC2Hzlhp+YI6xn2OnxCiIGyWukPb XdoLSAA4OqXQ8ZyL5m+/2JrS6LPscaGr1QU4iUJJWqg5H5wE/o4S1VkDdy1+hX+52P sL0efgnoyeXfjfMhcq7228rQMUbzXRL0Npcjwew/r6QvSxTCzAv1DII1N8aS5Mwod9 ZjQYrGgubHCpocl6JwxuMfY4OFhfDPX2nL8653H3JkN1/ZjcL148l3a+ue3aGFWcEh tdHIpkLkDrMK6DrjOWuXvyllX9XwWIXX4PiRqQWxv8Kj1z3iqHAevT4eYvt3UhcYyJ 6RCgarbfUUSPA== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:24 +0200 Message-Id: <20210928155325.2290444-12-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 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 8e35188c6..c615e8ab2 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" @@ -3081,11 +3083,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. */ @@ -3349,6 +3357,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); @@ -3877,6 +3887,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); @@ -3897,6 +3908,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[] = { @@ -3907,6 +3919,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); @@ -3952,6 +3965,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 Sep 28 15:53:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1533982 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=B7AaKJfO; 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 4HJkZd6gsZz9sW8 for ; Wed, 29 Sep 2021 01:54:01 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id E5641415A8; Tue, 28 Sep 2021 15:53:59 +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 DTKOQkN5D5ge; Tue, 28 Sep 2021 15:53:57 +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 ED7F6407C7; Tue, 28 Sep 2021 15:53:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5ED2CC0031; Tue, 28 Sep 2021 15:53:47 +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 234BAC002B for ; Tue, 28 Sep 2021 15:53:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id F0C27403A5 for ; Tue, 28 Sep 2021 15:53:37 +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 8tomrxDdllSI for ; Tue, 28 Sep 2021 15:53:37 +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 CBFFA403A0 for ; Tue, 28 Sep 2021 15:53:36 +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-1.canonical.com (Postfix) with ESMTPSA id 40CAE41998; Tue, 28 Sep 2021 15:53:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632844415; bh=p9bcLJiz3xB55SyNyLwNQcoxtnrqLu07etSvSLRilI8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B7AaKJfOw+ObIR4AOEJSWRv0TKXabDkycImG9Z+evum+7V3M2cwa1GScJ47EF9dDU A0+FgPQNq4NWbIYGezTjRu8HD3Y9bQ4OOU93q+tyObZ/ZRKUuAIzg7nGewtMdimCA7 oUXz3BAzMAHxX4+TemwxEJRq3J/SJCbtFutc9hle0rmufgD4qAd1sWtE7JRZAhe6wY jq6ipLmcS+eILZ+0wuB0n7vpwA+ZDnHIduw80uOIpjUWXBB/588n++0W19MXeo3nZt FLXDIpSIwAK1no1/z1QRtDTSgXAissNoeWcxaiqoYY9MyKBu4vn8iOhu0jB7L23JaB wUge1GYDQetTg== From: Frode Nordahl To: dev@openvswitch.org Date: Tue, 28 Sep 2021 17:53:25 +0200 Message-Id: <20210928155325.2290444-13-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 12/12] controller: Consider plugging of ports on CMS request. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When OVN is linked with an appropriate plugging implementation, CMS can request OVN to plug individual lports into the local Open vSwitch instance. The port and instance record will be maintained during the lifetime of the lport and it will be removed on release of lport. Signed-off-by: Frode Nordahl --- controller/ovn-controller.c | 195 ++++++++++++++++++++++++++++++++++++ ovn-nb.xml | 21 ++++ tests/ovn-controller.at | 85 ++++++++++++++++ tests/ovn-macros.at | 2 +- 4 files changed, 302 insertions(+), 1 deletion(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index c615e8ab2..f5516a879 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -937,6 +937,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) binding_register_ovs_idl(ovs_idl); bfd_register_ovs_idl(ovs_idl); physical_register_ovs_idl(ovs_idl); + plug_register_ovs_idl(ovs_idl); } #define SB_NODES \ @@ -2977,6 +2978,171 @@ flow_output_lflow_output_handler(struct engine_node *node, return true; } +static void * +en_plug_provider_lookup_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + return NULL; +} + +static void +en_plug_provider_lookup_cleanup(void *data OVS_UNUSED) +{ + +} + +static void +en_plug_provider_lookup_run(struct engine_node *node, + void *data OVS_UNUSED) +{ + VLOG_INFO("en_plug_provider_lookup_run"); + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return; + } + + if (plug_provider_run_all()) { + engine_set_node_state(node, EN_UPDATED); + } else { + engine_set_node_state(node, EN_UNCHANGED); + + } +} + + +struct ed_type_plug_provider { + struct shash deleted_iface_ids; + struct shash changed_iface_ids; +}; + +static void * +en_plug_provider_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_plug_provider *data = xzalloc(sizeof *data); + + shash_init(&data->deleted_iface_ids); + shash_init(&data->changed_iface_ids); + return data; +} + +static void +en_plug_provider_cleanup(void *data) +{ + struct ed_type_plug_provider *plug_provider_data = data; + + shash_destroy_free_data(&plug_provider_data->deleted_iface_ids); + shash_destroy_free_data(&plug_provider_data->changed_iface_ids); +} + +static void +init_plug_ctx(struct engine_node *node, + void *data, + struct plug_ctx_in *plug_ctx_in, + struct plug_ctx_out *plug_ctx_out) +{ + struct ovsrec_open_vswitch_table *ovs_table = + (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( + engine_get_input("OVS_open_vswitch", node)); + struct ovsrec_bridge_table *bridge_table = + (struct ovsrec_bridge_table *)EN_OVSDB_GET( + engine_get_input("OVS_bridge", node)); + const char *chassis_id = get_ovs_chassis_id(ovs_table); + const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table); + + ovs_assert(br_int && chassis_id); + + struct ovsdb_idl_index *sbrec_chassis_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_chassis", node), + "name"); + + const struct sbrec_chassis *chassis + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); + ovs_assert(chassis); + + struct ovsrec_interface_table *iface_table = + (struct ovsrec_interface_table *)EN_OVSDB_GET( + engine_get_input("OVS_interface", node)); + + struct sbrec_port_binding_table *pb_table = + (struct sbrec_port_binding_table *)EN_OVSDB_GET( + engine_get_input("SB_port_binding", node)); + + struct ovsdb_idl_index *sbrec_port_binding_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_port_binding", node), + "name"); + + struct ovsdb_idl_index *ovsrec_port_by_interfaces = + engine_ovsdb_node_get_index( + engine_get_input("OVS_port", node), + "interfaces"); + + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + plug_ctx_in->ovs_idl_txn = engine_get_context()->ovs_idl_txn; + plug_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name; + plug_ctx_in->ovsrec_port_by_interfaces = ovsrec_port_by_interfaces; + plug_ctx_in->ovs_table = ovs_table; + plug_ctx_in->br_int = br_int; + plug_ctx_in->iface_table = iface_table; + plug_ctx_in->chassis_rec = chassis; + plug_ctx_in->port_binding_table = pb_table; + plug_ctx_in->local_bindings = &rt_data->lbinding_data.bindings; + + struct ed_type_plug_provider *plug_provider_data = data; + plug_ctx_out->deleted_iface_ids = &plug_provider_data->deleted_iface_ids; + plug_ctx_out->changed_iface_ids = &plug_provider_data->changed_iface_ids; +} + +static void +en_plug_provider_run(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return; + } + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + plug_run(&plug_ctx_in, &plug_ctx_out); + engine_set_node_state(node, EN_UPDATED); +} + +static bool +plug_provider_port_binding_handler(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return true; + } + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + + return plug_handle_port_binding_changes(&plug_ctx_in, &plug_ctx_out); +} + +static bool +plug_provider_ovs_interface_handler(struct engine_node *node, + void *data) +{ + if (!plug_provider_has_providers()) { + engine_set_node_state(node, EN_UNCHANGED); + return true; + } + + struct plug_ctx_in plug_ctx_in; + struct plug_ctx_out plug_ctx_out; + init_plug_ctx(node, data, &plug_ctx_in, &plug_ctx_out); + + return plug_handle_ovs_interface_changes(&plug_ctx_in, &plug_ctx_out); +} + struct ovn_controller_exit_args { bool *exiting; bool *restart; @@ -3213,6 +3379,11 @@ main(int argc, char *argv[]) ENGINE_NODE(flow_output, "flow_output"); ENGINE_NODE(addr_sets, "addr_sets"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); + /* The plug provider has two engine nodes. One that checks for and reacts + * to change to plug provider lookup tables, and another that reacts to + * change to OVS interface, OVN Port_Binding and runtime data */ + ENGINE_NODE(plug_provider_lookup, "plug_provider_lookup"); + ENGINE_NODE(plug_provider, "plug_provider"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); SB_NODES @@ -3239,6 +3410,24 @@ main(int argc, char *argv[]) engine_add_input(&en_non_vif_data, &en_ovs_interface, non_vif_data_ovs_iface_handler); + engine_add_input(&en_plug_provider, &en_plug_provider_lookup, NULL); + engine_add_input(&en_plug_provider, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_plug_provider, &en_ovs_bridge, NULL); + engine_add_input(&en_plug_provider, &en_sb_chassis, NULL); + engine_add_input(&en_plug_provider, &en_runtime_data, + engine_noop_handler); + engine_add_input(&en_plug_provider, &en_sb_port_binding, + plug_provider_port_binding_handler); + engine_add_input(&en_plug_provider, &en_ovs_port, + engine_noop_handler); + engine_add_input(&en_plug_provider, &en_ovs_interface, + plug_provider_ovs_interface_handler); + /* The node needs somewhere to output to run */ + engine_add_input(&en_flow_output, &en_plug_provider, + engine_noop_handler); + + + /* Note: The order of inputs is important, all OVS interface changes must * be handled before any ct_zone changes. */ @@ -3812,6 +4001,12 @@ main(int argc, char *argv[]) } } } + struct ed_type_plug_provider *plug_provider_data = engine_get_data( + &en_plug_provider); + if (plug_provider_data) { + plug_finish_deleted(&plug_provider_data->deleted_iface_ids); + plug_finish_changed(&plug_provider_data->changed_iface_ids); + } } ovsdb_idl_track_clear(ovnsb_idl_loop.idl); diff --git a/ovn-nb.xml b/ovn-nb.xml index 390cc5a44..2774eb255 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1028,6 +1028,27 @@ DHCP reply.

    + + + + If set, OVN will attempt to perform plugging of this VIF. In order + to get this port plugged by the OVN controller, OVN must be built + with support for VIF plugging. The default behavior is for the CMS + to do the VIF plugging. Each plug provider have their own options + namespaced by name, for example "plug:representor:key". + + Please refer to the plug provider documentation located in + Documentation/topics/plug_providers/ for more information. + + + + Requested MTU for plugged interfaces. When set the OVN controller + will fill the column + of the Open vSwitch database's + table. This in turn will + make OVS vswitchd update the MTU of the linked interface. + + diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index a1169c569..2400aa1b7 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -795,6 +795,91 @@ OVN_CLEANUP_SBOX([hv]) OVN_CLEANUP_VSWITCH([main]) as ovn-sb OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - plugging]) +AT_KEYWORDS([plugging]) + +ovn_start + +net_add n1 +sim_add hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovn-appctl -t ovn-controller vlog/set + +sim_add hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovn-appctl -t ovn-controller vlog/set + +check ovn-nbctl ls-add lsw0 +check ovn-nbctl lsp-add lsw0 lsp1 +check ovn-nbctl lsp-set-addresses lsp1 "f0:00:00:00:00:01 172.16.0.101" +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=hv1 \ + options:plug-type=dummy \ + options:plug-mtu-request=42 + +check ovn-nbctl lsp-add lsw0 lsp2 +check ovn-nbctl lsp-set-addresses lsp2 "f0:00:00:00:00:02 172.16.0.102" +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp2 \ + options:requested-chassis=hv2 \ + options:plug-type=dummy \ + options:plug-mtu-request=42 + +wait_column "true" Port_Binding up logical_port=lsp1 +wait_column "true" Port_Binding up logical_port=lsp2 + +as hv1 + +# Check that the lport was plugged +AT_CHECK([as hv1 ovs-vsctl find interface name=lsp1 options:plug-dummy-option=value | grep -q "options.*value"]) +AT_CHECK([as hv1 ovs-vsctl find interface name=lsp1 mtu_request=42 | grep -q "mtu_request.*42"]) + +# Check that updating the lport updates the local iface +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=hv1 \ + options:plug-type=dummy \ + options:plug-mtu-request=43 +OVS_WAIT_UNTIL([ + as hv1 ovs-vsctl find interface mtu_request=43 | grep -q "mtu_request.*43" +]) + +# Check that local modification of iface will trigger ovn-controller to update +# the iface record +iface_uuid=$(as hv1 ovs-vsctl --bare --columns _uuid find interface name=lsp1) +as hv1 ovs-vsctl set interface ${iface_uuid} mtu_request=44 +OVS_WAIT_UNTIL([ + as hv1 ovs-vsctl find interface mtu_request=43 | grep -q "mtu_request.*43" +]) + +lsp_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp1) +iface_uuid=$(as hv1 ovs-vsctl --bare --columns _uuid find Interface name=lsp1) +# Check that pointing requested-chassis somewhere else will unplug the port +check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \ + options:requested-chassis=non-existent-chassis +OVS_WAIT_UNTIL([ + grep -q "Releasing lport lsp1" hv1/ovn-controller.log +]) +OVS_WAIT_UNTIL([ + grep -q "Unplugging port lsp1" hv1/ovn-controller.log +]) +as hv1 ovs-vsctl find interface name=lsp1 +OVS_WAIT_UNTIL([ + ! as hv1 ovs-vsctl get Interface ${iface_uuid} _uuid +]) + +# Check that removing an lport will unplug it +lsp_uuid=$(ovn-nbctl --bare --columns _uuid find Logical_Switch_Port name=lsp2) +iface_uuid=$(as hv2 ovs-vsctl --bare --columns _uuid find Interface name=lsp1) +check ovn-nbctl --wait=sb lsp-del ${lsp_uuid} +OVS_WAIT_UNTIL([ + ! as hv2 ovs-vsctl get Interface ${iface_uuid} _uuid +]) +OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP ]) diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at index f06f2e68e..b3c2d72fa 100644 --- a/tests/ovn-macros.at +++ b/tests/ovn-macros.at @@ -327,7 +327,7 @@ ovn_az_attach() { -- --may-exist add-br br-int \ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \ || return 1 - start_daemon ovn-controller || return 1 + start_daemon ovn-controller --enable-dummy-plug || return 1 } # ovn_attach NETWORK BRIDGE IP [MASKLEN] From patchwork Wed Sep 29 07:39:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frode Nordahl X-Patchwork-Id: 1534222 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=Q92BwklQ; 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 4HK7YW0T06z9svs for ; Wed, 29 Sep 2021 17:39:24 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 0A3A9606AE; Wed, 29 Sep 2021 07:39:23 +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 kcc6oxio1f_G; Wed, 29 Sep 2021 07:39:22 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 5A82960688; Wed, 29 Sep 2021 07:39:21 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A5290C0011; Wed, 29 Sep 2021 07:39: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 D1C82C000D for ; Wed, 29 Sep 2021 07:39:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id AF59E40468 for ; Wed, 29 Sep 2021 07:39:19 +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 Xtgw5N7l6PdM for ; Wed, 29 Sep 2021 07:39:18 +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 60F5640448 for ; Wed, 29 Sep 2021 07:39:18 +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-1.canonical.com (Postfix) with ESMTPSA id 743CF41976; Wed, 29 Sep 2021 07:39:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1632901155; bh=GRPRchUdyKugStsRq88xizU26MIdnKtZyy+BpSsHOTk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Q92BwklQQNYm9Xeb6OxICMswY2gZnVJvBYslSOaCOIYqm+XoJO6pJs/q3wXBGIogo LQDYREyRDNEqvEHJYj3pN5DzzD0nqtG8VYSgyOrrH4Byixnt6UZjHZg6CHab0Ez6Db 60BBfKc8YPFMjrzMKgKGMUmgwk91EbB5BC+sPaCh6q0CCw8TGAaNmFzBeYk8NYmo4y w5yn17SJ6iFn6d95Hz0XMK9JuheZcJqfxO4tCMfTBWlmcnxQxjMGoTRvOI50+VWKyT Uhu7ELE1TPNOx9MZIJVw+JvoTFqz6AH2LBZyIploy3O/23lX3RLrTnMZdqSqZJ5j6v s9UX+z+PmIiaA== From: Frode Nordahl To: dev@openvswitch.org Date: Wed, 29 Sep 2021 09:39:13 +0200 Message-Id: <20210929073913.2726985-1-frode.nordahl@canonical.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210928155325.2290444-1-frode.nordahl@canonical.com> References: <20210928155325.2290444-1-frode.nordahl@canonical.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v6 13/12] ovn-controller: Remove unnecessary log call 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" A INFO level log call used during development was left behind in the en_plug_provider_lookup_run function. Remove it. --- controller/ovn-controller.c | 1 - 1 file changed, 1 deletion(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index f5516a879..7ec377f03 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2995,7 +2995,6 @@ static void en_plug_provider_lookup_run(struct engine_node *node, void *data OVS_UNUSED) { - VLOG_INFO("en_plug_provider_lookup_run"); if (!plug_provider_has_providers()) { engine_set_node_state(node, EN_UNCHANGED); return;