From patchwork Thu Aug 19 11:08:51 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518593
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=lDfBmmU/;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28l1bTQz9t0T
for ; Thu, 19 Aug 2021 21:09:27 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id AF9EB80E43;
Thu, 19 Aug 2021 11:09:21 +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 T3hFCw1Vn8Rs; Thu, 19 Aug 2021 11:09:17 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp1.osuosl.org (Postfix) with ESMTPS id BCC1180F30;
Thu, 19 Aug 2021 11:09:16 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id C8AA4C0024;
Thu, 19 Aug 2021 11:09:14 +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 E4889C000E
for ; Thu, 19 Aug 2021 11:09:13 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id D269C605F2
for ; Thu, 19 Aug 2021 11:09:13 +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 yAAsNxkrN9y7 for ;
Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp3.osuosl.org (Postfix) with ESMTPS id 2AA4C60605
for ; Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
Received: from frode-threadripper.. (ti0189a330-1161.bb.online.no
[88.88.219.141])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id DBA67411F3
for ; Thu, 19 Aug 2021 11:09:03 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371344;
bh=lKDaNUTWQS6rq6fSi+S/gVwSK0sMglX3SHo7OePRYlc=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=lDfBmmU/IFdHRwXha9IEGB0jZjLlNfeB6EmYZiHL2oP0rtGbhNVBk00/LSBYrshia
Vr810k+bd1+Rb1kZznLcnxz54JoignK+HfIFhYucjGJjkDBVlA5RU4iLoK2MreHyYM
eMli9Z3FlXguCmikB1KQe/b4iZvmIOe/9GN7sIvSQ5fr7DyMhb/huXEheeyBOwNvEz
dQWCX5sD66lTy8x4uq3VrVDz4cTlVephEV8ArTA+klcjG88jcMNjJCRlZRebEh+aCl
njFy8MVZM0BiS2pNkWD0KJa887Hfj20BYgMRfK3KO7X3WGlbR619dl4uiiKjtDo+qh
E7Gxnm4EOJWgA==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:51 +0200
Message-Id: <20210819110857.2229769-2-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 1/7] ovn-sb: Add plugged_by 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 use of optional plugging support we add a new
plugged_by column with weakRef to the Chassis table. The
ovn-controller can monitor this column and only process events
for its chassis UUID.
ovn-northd will fill this column with UUID of Chassis referenced
in Logical_Switch_Port options:requested-chassis when
options:plug-type is defined.
Signed-off-by: Frode Nordahl
---
northd/ovn-northd.c | 31 ++++++++++++++++++++++++++++++
ovn-nb.xml | 38 ++++++++++++++++++++++++++++++++++++
ovn-sb.ovsschema | 10 +++++++---
ovn-sb.xml | 15 +++++++++++++++
tests/ovn-northd.at | 47 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 138 insertions(+), 3 deletions(-)
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 3d8e21a4f..a66f92ddd 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -3222,6 +3222,35 @@ 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 *plug_type; /* May be NULL. */
+ const char *requested_chassis; /* May be NULL. */
+ bool reset_plugged_by = false;
+ plug_type = smap_get(&op->nbsp->options, "plug-type");
+ requested_chassis = smap_get(&op->nbsp->options,
+ "requested-chassis");
+ if (plug_type && requested_chassis) {
+ const struct sbrec_chassis *chassis; /* May be NULL. */
+ chassis = chassis_lookup_by_name(sbrec_chassis_by_name,
+ requested_chassis);
+ if (chassis) {
+ sbrec_port_binding_set_plugged_by(op->sb, chassis);
+ } else {
+ reset_plugged_by = 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->plugged_by) {
+ reset_plugged_by = true;
+ }
+ if (reset_plugged_by) {
+ sbrec_port_binding_set_plugged_by(op->sb, NULL);
+ }
} else {
const char *chassis = NULL;
if (op->peer && op->peer->od && op->peer->od->nbr) {
@@ -15066,6 +15095,8 @@ main(int argc, char *argv[])
add_column_noalert(ovnsb_idl_loop.idl,
&sbrec_port_binding_col_nat_addresses);
ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);
+ ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+ &sbrec_port_binding_col_plugged_by);
ovsdb_idl_add_column(ovnsb_idl_loop.idl,
&sbrec_port_binding_col_gateway_chassis);
ovsdb_idl_add_column(ovnsb_idl_loop.idl,
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 8a942b54c..2812a0d11 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -1020,6 +1020,44 @@
DHCP reply.
+
+
+
+ These options apply to logical ports with
+ and
+ set.
+
+
+
+ If set, OVN will attempt to 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.
+ Supported values: representor
+
+
+
+ MAC address for identifying PF device. When
+ is also set, this
+ option is used to identify PF to use as base to locate the correct
+ VF representor port. When
+ is not set this
+ option is used to locate a PF representor port.
+
+
+
+ Logical VF number relative to PF device specified in
+ .
+
+
+
+ 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/ovn-sb.ovsschema b/ovn-sb.ovsschema
index e5ab41db9..4df326ff4 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": "888060012 26935",
"tables": {
"SB_Global": {
"columns": {
@@ -232,7 +232,11 @@
"external_ids": {"type": {"key": "string",
"value": "string",
"min": 0,
- "max": "unlimited"}}},
+ "max": "unlimited"}},
+ "plugged_by": {"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 687555c47..d32e9b6f2 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -2983,6 +2983,21 @@ tcp.flags = RST;
+
+ Chassis that should plug this port, this column must be a
+ record. This is populated by
+ ovn-northd
when the and is defined. 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.
+
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 93bb0e1da..5324f484b 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -5208,3 +5208,50 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sort], [0], [dnl
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([check requested-chassis and plug-type fills plugged_by col])
+AT_KEYWORDS([plugging])
+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
+check ovn-sbctl chassis-add ch3 geneve 127.0.0.4
+
+wait_row_count Chassis 3
+
+ch1_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name="ch1"`
+ch2_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name="ch2"`
+ch3_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name="ch3"`
+
+ovn-nbctl ls-add S1
+ovn-nbctl --wait=sb lsp-add S1 S1-vm1
+
+ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \
+ options:requested-chassis=ch1
+
+wait_row_count Port_Binding 1 logical_port=S1-vm1 plugged_by!=$ch1_uuid
+
+ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \
+ options:plug-type=representor
+
+wait_row_count Port_Binding 1 logical_port=S1-vm1 plugged_by=$ch1_uuid
+
+ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \
+ options:requested-chassis=ch2 options:plug-type=representor
+
+wait_row_count Port_binding 1 logical-port=S1-vm1 plugged_by=$ch2_uuid
+
+ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \
+ options:requested-chassis=ch3 options:plug-type=representor
+
+wait_row_count Port_binding 1 logical-port=S1-vm1 plugged_by=$ch3_uuid
+
+ovn-nbctl --wait=sb remove logical_switch_port S1-vm1 \
+ options plug-type=representor
+
+wait_row_count Port_binding 1 logical-port=S1-vm1 plugged_by!=$ch3_uuid
+
+AT_CLEANUP
+])
From patchwork Thu Aug 19 11:08:52 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518594
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=Qil5mg3m;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28n75Byz9t18
for ; Thu, 19 Aug 2021 21:09:29 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id 9459F42525;
Thu, 19 Aug 2021 11:09:26 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp4.osuosl.org ([127.0.0.1])
by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id 9ATgHnLJV-vA; Thu, 19 Aug 2021 11:09:21 +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 190B0407DF;
Thu, 19 Aug 2021 11:09:18 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 3F868C002B;
Thu, 19 Aug 2021 11:09:17 +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 312CBC0022
for ; Thu, 19 Aug 2021 11:09:14 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id 1E8FC80EC0
for ; Thu, 19 Aug 2021 11:09:14 +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 vZ-9Tv1TSxVe for ;
Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp1.osuosl.org (Postfix) with ESMTPS id 33F8480EC5
for ; Thu, 19 Aug 2021 11:09:08 +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 2FD98411F4
for ; Thu, 19 Aug 2021 11:09:04 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371344;
bh=Ju+iF58/m4tSnfmLdxzGT2ocB+xm5t2Nnpb5OFDScBI=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=Qil5mg3m2ThtFZfQKtHgL43GVYth5M3h21iJWvEtNIByPCMKENhXlHpfyWIS9S/An
neOyZFgSz/7BXExITKbHgvvjU1qbNzu8TtYJkmWBHD2g04WF/8I5mWbTxyjr/qemu9
nwbuLKQdcdmYwOjt4eQIfJ7rpeLq0VqMPC7zyU3GIhzLyGdgsMx/R1sEBhZTd87Fub
zYi6kopfzal5iEp1o9UuAnYKraOfpL2HgtXUA/HnhCLuRN5qz50CnyGfUeX4ar6n7u
Z4hxYnXfb4AB3ZgHsp8Q5OOhqMpXe6JFBtkvKYsOUYpquVwV64O2F0mEsgofZq7DUS
RzL73+tQ/aLmg==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:52 +0200
Message-Id: <20210819110857.2229769-3-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 2/7] northd-ddlog: Handle
Port_Binding:plugged_by.
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 patch brings northd-ddlog up to speed with the same feature
added to the C version of northd.
Signed-off-by: Frode Nordahl
---
northd/ovn_northd.dl | 68 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 8 deletions(-)
diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
index 9cf4c373b..45132cf98 100644
--- a/northd/ovn_northd.dl
+++ b/northd/ovn_northd.dl
@@ -105,7 +105,6 @@ sb::Out_Datapath_Binding(uuid, tunkey, load_balancers, external_ids) :-
*/
var load_balancers = set_empty().
-
/* Proxy table for Out_Datapath_Binding: contains all Datapath_Binding fields,
* except tunnel id, which is allocated separately (see PortTunKeyAllocation). */
relation OutProxy_Port_Binding (
@@ -120,10 +119,11 @@ relation OutProxy_Port_Binding (
tag: Option,
mac: Set,
nat_addresses: Set,
- external_ids: Map
+ external_ids: Map,
+ plugged_by: 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,
@@ -135,7 +135,8 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
.tag = tag,
.mac = lsp.addresses,
.nat_addresses = set_empty(),
- .external_ids = eids) :-
+ .external_ids = eids,
+ .plugged_by = None) :-
sp in &SwitchPort(.lsp = lsp, .sw = sw),
SwitchPortNewDynamicTag(lsp._uuid, opt_tag),
var tag = match (opt_tag) {
@@ -160,6 +161,53 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
options
}.
+/* Case 1b: Create a Port_Binding per logical switch port that is not of type "router" and has options "plug-type" and "requested-chassis" */
+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,
+ .plugged_by = plugged_by) :-
+ 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 != "router",
+ var eids = {
+ var eids = lsp.external_ids;
+ match (lsp.external_ids.get("neutron:port_name")) {
+ None -> (),
+ Some{name} -> eids.insert("name", name)
+ };
+ eids
+ },
+ var options = {
+ var options = lsp.options;
+ match (sw.other_config.get("vlan-passthru")) {
+ Some{"true"} -> options.insert("vlan-passthru", "true"),
+ _ -> ()
+ };
+ options
+ },
+ var chassis_name = match (options.get("plug-type")) {
+ Some{_} -> match(options.get("requested-chassis")) {
+ Some{chassis_name} -> chassis_name,
+ None -> "",
+ },
+ None -> "",
+ },
+ chassis_name != "",
+ chassis_rec in sb::Chassis(.name = chassis_name),
+ var plugged_by = Some{chassis_rec._uuid}.
/* Case 2: Create a Port_Binding per logical switch port of type "router" */
OutProxy_Port_Binding(._uuid = lsp._uuid,
@@ -173,7 +221,8 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
.tag = None,
.mac = lsp.addresses,
.nat_addresses = nat_addresses,
- .external_ids = eids) :-
+ .external_ids = eids,
+ .plugged_by = None) :-
&SwitchPort(.lsp = lsp, .sw = sw, .peer = peer),
var eids = {
var eids = lsp.external_ids;
@@ -263,7 +312,8 @@ OutProxy_Port_Binding(._uuid = lrp._uuid,
.tag = None, // always empty for router ports
.mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"),
.nat_addresses = set_empty(),
- .external_ids = lrp.external_ids) :-
+ .external_ids = lrp.external_ids,
+ .plugged_by = None) :-
rp in &RouterPort(.lrp = lrp, .router = router, .peer = peer),
RouterPortRAOptionsComplete(lrp._uuid, options0),
(var __type, var options1) = match (router.options.get("chassis")) {
@@ -471,7 +521,8 @@ OutProxy_Port_Binding(// lrp._uuid is already in use; generate a new UUID by
.tag = None, //always empty for router ports
.mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"),
.nat_addresses = set_empty(),
- .external_ids = lrp.external_ids) :-
+ .external_ids = lrp.external_ids,
+ .plugged_by = None) :-
DistributedGatewayPort(lrp, lr_uuid),
DistributedGatewayPortHAChassisGroup(lrp, hacg_uuid),
var redirect_type = match (lrp.options.get("redirect-type")) {
@@ -516,7 +567,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},
+ .plugged_by = pbinding.plugged_by) :-
pbinding in OutProxy_Port_Binding(),
PortTunKeyAllocation(pbinding._uuid, tunkey),
QueueIDAllocation(pbinding._uuid, qid),
From patchwork Thu Aug 19 11:08:53 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518596
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=Q8E9xHON;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28s6cngz9t18
for ; Thu, 19 Aug 2021 21:09:33 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id 05A8B4252C;
Thu, 19 Aug 2021 11:09:27 +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 ZVo-bCf7LUGD; Thu, 19 Aug 2021 11:09:21 +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 48733407F2;
Thu, 19 Aug 2021 11:09:19 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 0EFC4C0022;
Thu, 19 Aug 2021 11:09:18 +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 D1338C0025
for ; Thu, 19 Aug 2021 11:09:14 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id ABCF540781
for ; Thu, 19 Aug 2021 11:09:14 +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 s4pDcfBO7BMv for ;
Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp4.osuosl.org (Postfix) with ESMTPS id 367D0407AA
for ; Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
Received: from frode-threadripper.. (ti0189a330-1161.bb.online.no
[88.88.219.141])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id 71519411F5
for ; Thu, 19 Aug 2021 11:09:04 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371344;
bh=qDKddMr2hyQXl8C/ogw0w+X+UyAodDsypoaem7LcOPI=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=Q8E9xHONEWU6C6CIbXF2yt7hbDoW1uti/Yc+oyrsuptJ26auwUJ08LmUojt0gLaS6
juj/VDeJLoHccmwQm4E0QFYXePnaS5qWJVRI0GATI3aPFmyLGNh+XhI4O/VLyj8hY8
oO2Gb5M9VIyaLcEz0JG1XmTax1KxOcAkirdW1zlZp3qDKDRSVeaj2IGM2DI9ohJ1Ng
ZSG5zqm34WuyBmM+uYrZ154Zl8sULjjNDR/53I6DeQ85neUBhQSTY71Cu1YBwpQZCZ
cjUrhZygGYDlD63CetO7q1YpTrhDc5m5EikPawT4VS48xJpCdjh1fLEN/GPK59xZZs
fPWMg4jOrUMRQ==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:53 +0200
Message-Id: <20210819110857.2229769-4-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 3/7] controller: Move OVS port functions to
new module.
X-BeenThere: ovs-dev@openvswitch.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id:
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
Up until now the controller patch module has been the only
consumer of functions to maintain OVS ports and interfaces.
With the introduction of infrastructure for plugging providers
these functions will also be consumed by the controller binding
module.
As such we introduce a new module called ovsport where these
shared utility functions can live and be consumed by multiple
modules.
Signed-off-by: Frode Nordahl
---
controller/automake.mk | 4 +-
controller/ovsport.c | 256 +++++++++++++++++++++++++++++++++++++++++
controller/ovsport.h | 60 ++++++++++
3 files changed, 319 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..b1183e9ed
--- /dev/null
+++ b/controller/ovsport.c
@@ -0,0 +1,256 @@
+/* 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 callers responsibility to ensure that no other port with the desired
+ * name already exist.
+ *
+ * 'iface_type' optionally specifies the type of intercace, 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_update_ports_addvalue(bridge, port);
+ ovsrec_bridge_verify_ports(bridge);
+}
+
+/* Remove 'port' from 'bridge' and delete the 'port' recrd and any records
+ * with a weakRef to it. */
+void
+ovsport_remove(const struct ovsrec_bridge *bridge,
+ const struct ovsrec_port *port)
+{
+ ovsrec_bridge_update_ports_delvalue(bridge, port);
+ ovsrec_bridge_verify_ports(bridge);
+ 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
+ * exist 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 exist 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_set_type(iface, type);
+ }
+
+ if (external_ids && mnt_external_ids) {
+ 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) {
+ update_interface_smap_column(
+ iface, external_ids, &iface->external_ids,
+ ovsrec_interface_update_external_ids_setkey);
+ }
+
+ if (options && mnt_options) {
+ maintain_interface_smap_column(
+ iface, mnt_options, options, &iface->options,
+ ovsrec_interface_update_options_setkey,
+ ovsrec_interface_update_options_delkey);
+ } else if (options) {
+ 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_set_mtu_request(
+ iface, &mtu_request, mtu_request > 0);
+ }
+ } else if (iface->mtu_request) {
+ 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))
+ || !db_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 ((db_value && value && strcmp(db_value, value))
+ || (value && !db_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 Thu Aug 19 11:08:54 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518592
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=phf5kV42;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28g40QQz9t18
for ; Thu, 19 Aug 2021 21:09:21 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id 44C8080C35;
Thu, 19 Aug 2021 11:09:19 +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 nv6lqdyrKQNT; Thu, 19 Aug 2021 11:09:15 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp1.osuosl.org (Postfix) with ESMTPS id 4372580EC0;
Thu, 19 Aug 2021 11:09:14 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 1CC58C0010;
Thu, 19 Aug 2021 11:09:14 +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 5A11DC000E
for ; Thu, 19 Aug 2021 11:09:13 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id 4962A80EC0
for ; Thu, 19 Aug 2021 11:09:13 +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 LyVaO3NWYTWe for ;
Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp1.osuosl.org (Postfix) with ESMTPS id 33F6880EC2
for ; Thu, 19 Aug 2021 11:09:09 +0000 (UTC)
Received: from frode-threadripper.. (ti0189a330-1161.bb.online.no
[88.88.219.141])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id C7E1B411FB
for ; Thu, 19 Aug 2021 11:09:04 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371344;
bh=wfhStxVbg/X5SMKKSdhAa+c99+UoZWKNxffSDVizhvk=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=phf5kV42RIPINepuyOJc/ABjKm9SHZgELzdzoikpyutDeOuL1/BuLezW8HVA1Ro7R
0oOXBVheLd3cMuNg/G3lCMj8EQfKT7DHoi0rNJJyyxOaAabMYD5K5cvKkDRhpZNdSF
iOQYAtvrnrzoIg0nUQmGrXHg7o5NY+0B4DMgeIryybmuQ6WyoWbQMeECkGdsmvmwd4
QkMG/NVqizepFE9uQVTfuJ2L1elcRyfSpj9BpyQo3HC/ejQoS1ClB501Tu0pJYZRoU
QLkniGj2BR+Tr/tkTKAge9pc9dHGQX3LKs9AoEZlI9yYNBAjkJZdUERW787V83HS7z
M/xG2K+2Fvynw==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:54 +0200
Message-Id: <20210819110857.2229769-5-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 4/7] patch: Consume ovsport functions.
X-BeenThere: ovs-dev@openvswitch.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id:
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
Make use of the common functions for maintaining OVS ports.
Signed-off-by: Frode Nordahl
---
controller/patch.c | 39 ++++++---------------------------------
1 file changed, 6 insertions(+), 33 deletions(-)
diff --git a/controller/patch.c b/controller/patch.c
index a661025da..0d0d53894 100644
--- a/controller/patch.c
+++ b/controller/patch.c
@@ -16,6 +16,7 @@
#include
#include "patch.h"
+#include "ovsport.h"
#include "hash.h"
#include "lflow.h"
@@ -91,28 +92,10 @@ create_patch_port(struct ovsdb_idl_txn *ovs_idl_txn,
"ovn-controller: creating patch port '%s' from '%s' to '%s'",
src_name, src->name, dst->name);
- struct ovsrec_interface *iface;
- iface = ovsrec_interface_insert(ovs_idl_txn);
- ovsrec_interface_set_name(iface, src_name);
- ovsrec_interface_set_type(iface, "patch");
- const struct smap options = SMAP_CONST1(&options, "peer", dst_name);
- ovsrec_interface_set_options(iface, &options);
-
- struct ovsrec_port *port;
- port = ovsrec_port_insert(ovs_idl_txn);
- ovsrec_port_set_name(port, src_name);
- ovsrec_port_set_interfaces(port, &iface, 1);
- const struct smap ids = SMAP_CONST1(&ids, key, value);
- ovsrec_port_set_external_ids(port, &ids);
-
- struct ovsrec_port **ports;
- ports = xmalloc(sizeof *ports * (src->n_ports + 1));
- memcpy(ports, src->ports, sizeof *ports * src->n_ports);
- ports[src->n_ports] = port;
- ovsrec_bridge_verify_ports(src);
- ovsrec_bridge_set_ports(src, ports, src->n_ports + 1);
-
- free(ports);
+ const struct smap if_options = SMAP_CONST1(&if_options, "peer", dst_name);
+ const struct smap port_ids = SMAP_CONST1(&port_ids, key, value);
+ ovsport_create(ovs_idl_txn, src, src_name, "patch", &port_ids, NULL,
+ &if_options, 0);
}
static void
@@ -130,17 +113,7 @@ remove_port(const struct ovsrec_bridge_table *bridge_table,
if (bridge->ports[i] != port) {
continue;
}
- struct ovsrec_port **new_ports;
- new_ports = xmemdup(bridge->ports,
- sizeof *new_ports * (bridge->n_ports - 1));
- if (i != bridge->n_ports - 1) {
- /* Removed port was not last */
- new_ports[i] = bridge->ports[bridge->n_ports - 1];
- }
- ovsrec_bridge_verify_ports(bridge);
- ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1);
- free(new_ports);
- ovsrec_port_delete(port);
+ ovsport_remove(bridge, port);
return;
}
}
From patchwork Thu Aug 19 11:08:55 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518599
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=maZPhwSO;
dkim-atps=neutral
Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest
SHA256)
(No client certificate requested)
by ozlabs.org (Postfix) with ESMTPS id 4Gr28y4YL9z9t0T
for ; Thu, 19 Aug 2021 21:09:38 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp2.osuosl.org (Postfix) with ESMTP id 3A50740740;
Thu, 19 Aug 2021 11:09:36 +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 T9vhnDai2s4C; Thu, 19 Aug 2021 11:09:30 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp2.osuosl.org (Postfix) with ESMTPS id EFC27404E5;
Thu, 19 Aug 2021 11:09:24 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 5C0D0C0030;
Thu, 19 Aug 2021 11:09:21 +0000 (UTC)
X-Original-To: dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])
by lists.linuxfoundation.org (Postfix) with ESMTP id E856CC002A
for ; Thu, 19 Aug 2021 11:09:16 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id C342680F25
for ; Thu, 19 Aug 2021 11:09:16 +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 8nJlFxFBRhAP for ;
Thu, 19 Aug 2021 11:09:10 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp1.osuosl.org (Postfix) with ESMTPS id A770680EB0
for ; Thu, 19 Aug 2021 11:09:10 +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 170A9411FC
for ; Thu, 19 Aug 2021 11:09:05 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371345;
bh=vPGz3VEAE9DaQBI0zDX/ufAMU4wxRAK4eBu+IrLo27s=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=maZPhwSO7yLFlOxp53Kt1ejJsD+KjKjupz7cWBjnvAUnScFcUIuyPLj4XZkl3qVY8
n7WRCmfu2wTYAYnzwQqxv5E0lfyVKhC6vQQa3zIVgx9nkOcT6XBTyxZV0fEIrYz76a
3tkpWvlUbaHMMqR8tU20DAAjlb613FdApWgF7qH0CcerEEiC7sHdPcOYsXa6xeqrXt
xntWf6Digk1iqFA7YLcSDuOLUBI+8d2vPRkyHbEu4adILZHbzdUwwFLPVJ6elamYgC
etl02NLY06xRD01Dn4cZS6DZJTDmyvSSdJ2aY5r/UB3vYqtVDOXLQjXpX6a8JRoaT0
bxTn72QNRbFCA==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:55 +0200
Message-Id: <20210819110857.2229769-6-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 5/7] lib: Add infrastructure for plugging
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 module contains the infrastructure for registering and
instantiating plugging classes which may be hosted inside or
outside the core OVN repository. The data structures and functions
for interacting with these plugging classes also live there.
Extend build system to allow linking a externally built plugging
provider.
Signed-off-by: Frode Nordahl
---
acinclude.m4 | 34 +++++
configure.ac | 1 +
lib/automake.mk | 12 +-
lib/plug-dummy.c | 144 +++++++++++++++++++
lib/plug-dummy.h | 33 +++++
lib/plug-provider.h | 109 ++++++++++++++
lib/plug.c | 342 ++++++++++++++++++++++++++++++++++++++++++++
lib/plug.h | 101 +++++++++++++
lib/test-plug.c | 80 +++++++++++
tests/automake.mk | 4 +-
tests/ovn-plug.at | 8 ++
11 files changed, 866 insertions(+), 2 deletions(-)
create mode 100644 lib/plug-dummy.c
create mode 100644 lib/plug-dummy.h
create mode 100644 lib/plug-provider.h
create mode 100644 lib/plug.c
create mode 100644 lib/plug.h
create mode 100644 lib/test-plug.c
create mode 100644 tests/ovn-plug.at
diff --git a/acinclude.m4 b/acinclude.m4
index e7f829520..ba7a01c49 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -441,3 +441,37 @@ 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 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
+])
diff --git a/configure.ac b/configure.ac
index df0b98295..73e3bfe8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -172,6 +172,7 @@ OVS_ENABLE_SPARSE
OVS_CHECK_DDLOG([0.38])
OVS_CHECK_PRAGMA_MESSAGE
OVN_CHECK_OVS
+OVN_CHECK_PLUG_PROVIDER
OVS_CTAGS_IDENTIFIERS
AC_SUBST([OVS_CFLAGS])
AC_SUBST([OVS_LDFLAGS])
diff --git a/lib/automake.mk b/lib/automake.mk
index ddfe33948..086fbd62d 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -3,6 +3,11 @@ lib_libovn_la_LDFLAGS = \
$(OVS_LTINFO) \
-Wl,--version-script=$(top_builddir)/lib/libovn.sym \
$(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 \
@@ -32,7 +37,12 @@ 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.h \
+ lib/plug.c \
+ lib/plug-dummy.h \
+ lib/plug-dummy.c
nodist_lib_libovn_la_SOURCES = \
lib/ovn-dirs.c \
lib/ovn-nb-idl.c \
diff --git a/lib/plug-dummy.c b/lib/plug-dummy.c
new file mode 100644
index 000000000..efa413b19
--- /dev/null
+++ b/lib/plug-dummy.c
@@ -0,0 +1,144 @@
+/*
+ * 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-dummy.h"
+#include "plug-provider.h"
+#include "plug.h"
+
+#include
+
+#include "openvswitch/vlog.h"
+#include "smap.h"
+#include "sset.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+VLOG_DEFINE_THIS_MODULE(plug_dummy);
+
+struct plug_dummy {
+ struct plug plug;
+};
+
+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 int
+plug_dummy_open(const struct plug_class *class, struct plug **plugp)
+{
+ struct plug_dummy *plug;
+
+ plug = xmalloc(sizeof *plug);
+ plug->plug.plug_class = class;
+ *plugp = &plug->plug;
+
+ VLOG_DBG("plug_dummy_open(%p)", plug);
+ return 0;
+}
+
+static int
+plug_dummy_close(struct plug *plug)
+{
+ VLOG_DBG("plug_dummy_close(%p)", plug);
+ free(plug);
+
+ return 0;
+}
+
+static bool
+plug_dummy_run(struct plug *plug)
+{
+ VLOG_DBG("plug_dummy_run(%p)", plug);
+
+ return true;
+}
+
+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",
+ .maintained_iface_options = &plug_dummy_maintained_iface_options,
+ .init = plug_dummy_init,
+ .destroy = plug_dummy_destroy,
+ .open = plug_dummy_open,
+ .close = plug_dummy_close,
+ .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_register_provider(&plug_dummy_class);
+}
+
diff --git a/lib/plug-dummy.h b/lib/plug-dummy.h
new file mode 100644
index 000000000..6ea33671e
--- /dev/null
+++ b/lib/plug-dummy.h
@@ -0,0 +1,33 @@
+/*
+ * 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_DUMMY_H
+#define PLUG_DUMMY_H 1
+
+/*
+ * The dummy plugger, allows for experimenting with plugging in a sandbox */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void plug_dummy_enable(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* plug-dummy.h */
diff --git a/lib/plug-provider.h b/lib/plug-provider.h
new file mode 100644
index 000000000..5ffbe088f
--- /dev/null
+++ b/lib/plug-provider.h
@@ -0,0 +1,109 @@
+/*
+ * 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
+
+/* Provider interface to pluggers. A plugger 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).
+ */
+
+#include
+
+#include "plug.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct plug {
+ const struct plug_class *plug_class;
+};
+
+struct plug_class {
+ /* Type of plugger in this class. */
+ const char *type;
+
+ /* Interface options this plugger will maintain. This set is used
+ * to know which items to remove when maintaining the database record. */
+ struct sset *maintained_iface_options;
+
+ /* 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);
+
+ /* Creates a new plug class instance.
+ *
+ * If successful, stores a pointer to the plug instance in '*plugp' */
+ int (*open)(const struct plug_class *class, struct plug **plugp);
+
+ /* Closes plug class instance and frees associated memory. */
+ int (*close)(struct plug *plug);
+
+ /* Performs periodic work needed by plugger, if any is necessary. Returns
+ * true if something changed, false otherwise.
+ *
+ * Note that work performed by plugger in this function must under no
+ * circumstances block. */
+ bool (*run)(struct plug *plug);
+
+ /* 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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* plug-provider.h */
diff --git a/lib/plug.c b/lib/plug.c
new file mode 100644
index 000000000..8d717bb37
--- /dev/null
+++ b/lib/plug.c
@@ -0,0 +1,342 @@
+/*
+ * 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 "plug.h"
+
+#include
+#include
+#include
+
+#include "openvswitch/vlog.h"
+#include "openvswitch/shash.h"
+#include "smap.h"
+#include "sset.h"
+
+VLOG_DEFINE_THIS_MODULE(plug);
+
+struct registered_plug_class {
+ const struct plug_class *plug_class;
+ int refcount;
+};
+static struct shash plug_classes = SHASH_INITIALIZER(&plug_classes);
+static struct shash plug_instances = SHASH_INITIALIZER(&plug_instances);
+
+/* Protects 'plug_classes', including the refcount. */
+static struct ovs_mutex plug_classes_mutex = OVS_MUTEX_INITIALIZER;
+/* Protects 'plug_instances' */
+static struct ovs_mutex plug_instances_mutex = OVS_MUTEX_INITIALIZER;
+
+/* Initialize the the plug infrastructure by registering known plug classes */
+static void
+plug_initialize(void)
+{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+ if (ovsthread_once_start(&once)) {
+#ifdef HAVE_PLUG_PROVIDER
+ for (const struct plug_class **pp = plug_provider_classes;
+ pp && *pp;
+ pp++)
+ {
+ plug_register_provider(*pp);
+ }
+#endif
+ ovsthread_once_done(&once);
+ }
+}
+
+static int
+plug_register_provider__(const struct plug_class *new_class)
+{
+ struct registered_plug_class *rc;
+ 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;
+ }
+
+ rc = xmalloc(sizeof *rc);
+ rc->plug_class = new_class;
+ rc->refcount = 0;
+
+ shash_add(&plug_classes, new_class->type, rc);
+
+ 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_register_provider(const struct plug_class *new_class)
+{
+ int error;
+
+ ovs_mutex_lock(&plug_classes_mutex);
+ error = plug_register_provider__(new_class);
+ ovs_mutex_unlock(&plug_classes_mutex);
+
+ return error;
+}
+
+static int
+plug_unregister_provider__(const char *type)
+{
+ int error;
+ struct shash_node *node;
+ struct registered_plug_class *rc;
+
+ node = shash_find(&plug_classes, type);
+ if (!node) {
+ return EINVAL;
+ }
+
+ rc = node->data;
+ if (rc->refcount) {
+ VLOG_WARN("attempted to unregister in use plug provider: %s", type);
+ return EBUSY;
+ }
+
+ error = rc->plug_class->destroy ? rc->plug_class->destroy() : 0;
+ if (error) {
+ VLOG_WARN("failed to destroy %s plug class: %s",
+ rc->plug_class->type, ovs_strerror(error));
+ return error;
+ }
+
+ shash_delete(&plug_classes, node);
+ free(rc);
+
+ return 0;
+}
+
+/* Unregister the plug provider identified by 'type' and perform any class
+ * level de-initialization as specified in its plug_class. */
+int
+plug_unregister_provider(const char *type)
+{
+ int error;
+
+ plug_initialize();
+
+ ovs_mutex_lock(&plug_classes_mutex);
+ error = plug_unregister_provider__(type);
+ ovs_mutex_unlock(&plug_classes_mutex);
+
+ return error;
+}
+
+static void
+plug_class_unref(struct registered_plug_class *rc)
+{
+ ovs_mutex_lock(&plug_classes_mutex);
+ ovs_assert(rc->refcount);
+ rc->refcount--;
+ ovs_mutex_unlock(&plug_classes_mutex);
+}
+
+static struct registered_plug_class *
+plug_class_lookup(const char *type)
+{
+ struct registered_plug_class *rc;
+
+ ovs_mutex_lock(&plug_classes_mutex);
+ rc = shash_find_data(&plug_classes, type);
+ if (rc) {
+ rc->refcount++;
+ }
+ ovs_mutex_unlock(&plug_classes_mutex);
+
+ return rc;
+}
+
+static int
+plug_open__(const char *type, struct plug **plugp)
+{
+ struct plug *plug = NULL;
+ int error;
+ struct registered_plug_class *rc;
+
+ plug_initialize();
+ rc = plug_class_lookup(type);
+ if (!rc) {
+ VLOG_WARN("unable to open plug provider of unknown type: %s", type);
+ error = EINVAL;
+ goto out;
+ }
+
+ error = rc->plug_class->open(rc->plug_class, &plug);
+ if (error) {
+ plug_class_unref(rc);
+ }
+
+out:
+ *plugp = error ? NULL: plug;
+ return error;
+}
+
+/* Create, or retrieve the already created instance of plug class from a
+ * previous call to plug_open, identified by 'type' and store a reference to it
+ * in '*plugp'.
+ *
+ * The plug implementation will perform any initialization and allocations it
+ * needs, and the plug infrastructure will store a reference to it. Subsequent
+ * calls to this function with the same 'type' parameter will return the same
+ * object, until the instance is removed with a call to plug_close. */
+int
+plug_open(const char *type, struct plug **plugp)
+{
+ struct plug *instance = shash_find_data(&plug_instances, type);
+ int error;
+
+ if (instance) {
+ *plugp = instance;
+ return 0;
+ }
+
+ error = plug_open__(type, plugp);
+ if (error) {
+ return error;
+ }
+
+ ovs_mutex_lock(&plug_instances_mutex);
+ shash_add(&plug_instances, type, *plugp);
+ ovs_mutex_unlock(&plug_instances_mutex);
+
+ return 0;
+}
+
+/* Close the plug class instance previously created by a call to 'plug_open'.
+ *
+ * The plug implementation will perform any destruction of its data and the
+ * plug infrastructure will remove its references to it. */
+void
+plug_close(struct plug *plug)
+{
+ if (plug) {
+ ovs_mutex_lock(&plug_instances_mutex);
+ shash_find_and_delete(&plug_instances, plug->plug_class->type);
+ ovs_mutex_unlock(&plug_instances_mutex);
+
+ struct registered_plug_class *rc;
+ rc = shash_find_data(&plug_classes, plug->plug_class->type);
+ rc->plug_class->close(plug);
+ plug_class_unref(rc);
+ }
+}
+
+/* Close any previously instantiated plug classes and unregister the plug
+ * providers. */
+void
+plug_destroy_all(void)
+{
+ struct shash_node *node, *next;
+
+ SHASH_FOR_EACH_SAFE (node, next, &plug_instances) {
+ struct plug *plug = node->data;
+ plug_close(plug);
+ }
+
+ SHASH_FOR_EACH_SAFE (node, next, &plug_classes) {
+ struct registered_plug_class *rc = node->data;
+ plug_unregister_provider(rc->plug_class->type);
+ }
+}
+
+/* Iterate over previously instantiated plug classes and call their 'run'
+ * function if defined.
+ *
+ * If any of the instances report they have changed something this function
+ * will return 'true', otherwise it will return 'false'. */
+bool
+plug_run_instances(void)
+{
+ struct shash_node *node;
+ bool something_changed = false;
+
+ ovs_mutex_lock(&plug_instances_mutex);
+
+ SHASH_FOR_EACH (node, &plug_instances) {
+ struct plug *instance = node->data;
+ if (instance->plug_class->run(instance)) {
+ something_changed = true;
+ }
+ }
+
+ ovs_mutex_unlock(&plug_instances_mutex);
+
+ return something_changed;
+}
+
+/* Get the class level 'maintained_iface_options' set. */
+struct sset *
+plug_class_get_maintained_iface_options(const struct plug *plug)
+{
+ return plug->plug_class->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 *plug,
+ 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->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 *plug,
+ const struct plug_port_ctx_in *ctx_in,
+ struct plug_port_ctx_out *ctx_out)
+{
+ plug->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 *plug,
+ const struct plug_port_ctx_in *ctx_in,
+ struct plug_port_ctx_out *ctx_out)
+{
+ plug->plug_class->plug_port_ctx_destroy(ctx_in, ctx_out);
+}
diff --git a/lib/plug.h b/lib/plug.h
new file mode 100644
index 000000000..6117bd52a
--- /dev/null
+++ b/lib/plug.h
@@ -0,0 +1,101 @@
+/*
+ * 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 plugging interface. This module contains the infrastructure for
+ * registering and instantiating plugging classes which may be hosted inside
+ * or outside the core OVN repository. The data structures and functions for
+ * interacting with these plugging classes also live here.
+ */
+
+#include "smap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct plug;
+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;
+
+ /* Whether the chassis uses DPDK */
+ bool use_dpdk;
+
+ /* 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;
+};
+
+
+int plug_register_provider(const struct plug_class *);
+int plug_unregister_provider(const char *type);
+void plug_destroy_all(void);
+int plug_open(const char *type, struct plug **);
+void plug_close(struct plug *);
+bool plug_run_instances(void);
+
+struct sset * plug_class_get_maintained_iface_options(const struct plug *);
+
+bool plug_port_prepare(const struct plug *,
+ const struct plug_port_ctx_in *,
+ struct plug_port_ctx_out *);
+void plug_port_finish(const struct plug *,
+ const struct plug_port_ctx_in *,
+ struct plug_port_ctx_out *);
+void plug_port_ctx_destroy(const struct plug *,
+ const struct plug_port_ctx_in *,
+ struct plug_port_ctx_out *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* plug.h */
diff --git a/lib/test-plug.c b/lib/test-plug.c
new file mode 100644
index 000000000..b17b08a70
--- /dev/null
+++ b/lib/test-plug.c
@@ -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.
+ */
+
+#include
+#include
+
+#include "plug.h"
+#include "plug-dummy.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)
+{
+ struct plug *plug;
+
+ ovs_assert(plug_unregister_provider("dummy") == EINVAL);
+ ovs_assert(plug_open("dummy", &plug) == EINVAL);
+
+ ovs_assert(!plug_register_provider(&plug_dummy_class));
+ ovs_assert(plug_register_provider(&plug_dummy_class) == EEXIST);
+ ovs_assert(!plug_run_instances());
+
+ ovs_assert(!plug_open("dummy", &plug));
+ ovs_assert(plug_unregister_provider("dummy") == EBUSY);
+
+ ovs_assert(sset_contains(
+ plug_class_get_maintained_iface_options(plug),
+ "plug-dummy-option"));
+ ovs_assert(plug_run_instances());
+
+ struct smap fake_lport_options = SMAP_INITIALIZER(&fake_lport_options);
+ struct plug_port_ctx_in ctx_in = {
+ .op_type = PLUG_OP_CREATE,
+ .use_dpdk = false,
+ .lport_name = "lsp1",
+ .lport_options = &fake_lport_options,
+ };
+ struct plug_port_ctx_out ctx_out;
+ plug_port_prepare(plug, &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, &ctx_in, &ctx_out);
+ plug_port_ctx_destroy(plug, &ctx_in, &ctx_out);
+ plug_close(plug);
+ plug_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/tests/automake.mk b/tests/automake.mk
index 5b890d644..ad8978541 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 \
@@ -248,6 +249,7 @@ tests_ovstest_SOURCES = \
controller/ofctrl-seqno.c \
controller/ofctrl-seqno.h \
lib/test-ovn-features.c \
+ lib/test-plug.c \
northd/test-ipam.c \
northd/ipam.c \
northd/ipam.h
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 Thu Aug 19 11:08:56 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518598
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=e0iWJeqm;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28x24Mlz9t18
for ; Thu, 19 Aug 2021 21:09:37 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id D3BC74047F;
Thu, 19 Aug 2021 11:09:29 +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 XBD6qgQJuj7c; Thu, 19 Aug 2021 11:09:25 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp4.osuosl.org (Postfix) with ESMTPS id D0F10424F7;
Thu, 19 Aug 2021 11:09:20 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id E70C0C0025;
Thu, 19 Aug 2021 11:09:18 +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 05CB5C0027
for ; Thu, 19 Aug 2021 11:09:15 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp2.osuosl.org (Postfix) with ESMTP id DC62E400F2
for ; Thu, 19 Aug 2021 11:09:14 +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 H-nGdrJdS6et for ;
Thu, 19 Aug 2021 11:09:10 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp2.osuosl.org (Postfix) with ESMTPS id BF54B400BE
for ; Thu, 19 Aug 2021 11:09:10 +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 60FAA411FE
for ; Thu, 19 Aug 2021 11:09:05 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371345;
bh=6XY7JsEPmUNIi5B6J6yDWj/vpyHmH3TusC4uijkaSBU=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=e0iWJeqm6NRwVIt9DjSDl6PwvY7OWGGc71oJojdVjdo8M8aqFn015paVjhEOGikN1
nZ8FVtn2C8DpG0SzJnrBBpEhxLS5f8m7w+TAHZzSiz7Gl4EzwpuPB4ExpHd19tPtI9
3eyqHZo3oelyeDRYR2W4cblBmbvcjPrgRo911XXtpCakhdH2yP9Hm59tL2TqMVbfYj
RmDWbuumKobgqNznhX2eiW9eb+2v5FsEMFYHv/1J08M0UyKgCjHe9yGdHM0MkoBrNv
V0zBNwiaV/xupYtd/7/9aUG9yMDqFKRb6ehCSr/P1DJclbQaZL2N1ohSEOOkDfY7zi
7NRe6rhdGmz1g==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:56 +0200
Message-Id: <20210819110857.2229769-7-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 6/7] ovn-controller: Prepare plugging
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 monitor for `plugged_by` column.
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/binding.h | 1 +
controller/ovn-controller.c | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/controller/binding.h b/controller/binding.h
index f1abc4b9c..8f4521806 100644
--- a/controller/binding.h
+++ b/controller/binding.h
@@ -46,6 +46,7 @@ struct binding_ctx_in {
struct ovsdb_idl_index *sbrec_datapath_binding_by_key;
struct ovsdb_idl_index *sbrec_port_binding_by_datapath;
struct ovsdb_idl_index *sbrec_port_binding_by_name;
+ struct ovsdb_idl_index *ovsrec_port_by_interfaces;
const struct ovsrec_port_table *port_table;
const struct ovsrec_qos_table *qos_table;
const struct sbrec_port_binding_table *port_binding_table;
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 678419ab3..7c583b959 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -55,7 +55,9 @@
#include "lib/mcast-group-index.h"
#include "lib/ovn-sb-idl.h"
#include "lib/ovn-util.h"
+#include "lib/plug-dummy.h"
#include "patch.h"
+#include "plug.h"
#include "physical.h"
#include "pinctrl.h"
#include "openvswitch/poll-loop.h"
@@ -232,6 +234,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_plugged_by(&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
@@ -1239,6 +1244,11 @@ init_binding_ctx(struct engine_node *node,
engine_get_input("SB_port_binding", node),
"datapath");
+ struct ovsdb_idl_index *ovsrec_port_by_interfaces =
+ engine_ovsdb_node_get_index(
+ engine_get_input("OVS_port", node),
+ "interfaces");
+
struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
b_ctx_in->ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn;
@@ -1246,6 +1256,7 @@ init_binding_ctx(struct engine_node *node,
b_ctx_in->sbrec_datapath_binding_by_key = sbrec_datapath_binding_by_key;
b_ctx_in->sbrec_port_binding_by_datapath = sbrec_port_binding_by_datapath;
b_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
+ b_ctx_in->ovsrec_port_by_interfaces = ovsrec_port_by_interfaces;
b_ctx_in->port_table = port_table;
b_ctx_in->iface_table = iface_table;
b_ctx_in->qos_table = qos_table;
@@ -3099,6 +3110,11 @@ main(int argc, char *argv[])
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. */
@@ -3362,6 +3378,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);
@@ -3883,6 +3901,7 @@ loop_done:
pinctrl_destroy();
patch_destroy();
if_status_mgr_destroy(if_mgr);
+ plug_destroy_all();
ovsdb_idl_loop_destroy(&ovs_idl_loop);
ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
@@ -3902,6 +3921,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[] = {
@@ -3912,6 +3932,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);
@@ -3957,6 +3978,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 Thu Aug 19 11:08:57 2021
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Frode Nordahl
X-Patchwork-Id: 1518597
X-Patchwork-Delegate: zhouhan@gmail.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
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=)
Authentication-Results: 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=Nb/Gm6OH;
dkim-atps=neutral
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 ozlabs.org (Postfix) with ESMTPS id 4Gr28x23vVz9t0T
for ; Thu, 19 Aug 2021 21:09:37 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id B08968186E;
Thu, 19 Aug 2021 11:09:34 +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 QbhtciWONdjq; Thu, 19 Aug 2021 11:09:30 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp1.osuosl.org (Postfix) with ESMTPS id 8565D809EB;
Thu, 19 Aug 2021 11:09:23 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id B19ACC002D;
Thu, 19 Aug 2021 11:09:20 +0000 (UTC)
X-Original-To: dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])
by lists.linuxfoundation.org (Postfix) with ESMTP id 2A9F8C0028
for ; Thu, 19 Aug 2021 11:09:16 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id 07B5560BD3
for ; Thu, 19 Aug 2021 11:09:16 +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 CO_A0BEixsVK for ;
Thu, 19 Aug 2021 11:09:11 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from smtp-relay-canonical-1.canonical.com
(smtp-relay-canonical-1.canonical.com [185.125.188.121])
by smtp3.osuosl.org (Postfix) with ESMTPS id DC1D3606E9
for ; Thu, 19 Aug 2021 11:09:10 +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 AF4D8411FF
for ; Thu, 19 Aug 2021 11:09:05 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;
s=20210705; t=1629371345;
bh=e+J9y7bTB1vUdmTkTUwIkiu1EEInTPjNOrg67U29OH0=;
h=From:To:Subject:Date:Message-Id:In-Reply-To:References:
MIME-Version;
b=Nb/Gm6OH6FEug/YzC1gP0cBM/qpvFBFb2xi/QznCQD48kjWGEV84j54K4zVZfQGBy
cB3wwf+GU3eJpySn9iGl1MSeFkbzUC3pgGQJgLbrrykaq+oRVAnxryoX/Ly4nsZIpc
XTMVguCUiPY96IXNFJnZG/9WLz3jG/ZPCRxnJIZq7RzSlMrtEZMZwDOH052jdn+d6a
P7Y0HQ390vZiHRe0nBH+Z0SAYA9vGtbJIEqBWcbA194qbUg1W8EZlQk0F9xgQkaZag
v/2U1F/FwFQh4OzZEtU/RfarpCWzUryQbBHo4jq9AND/wRgWnQVhSAQu+tAaGiNMUz
+W/FhKh3TQgtQ==
From: Frode Nordahl
To: dev@openvswitch.org
Date: Thu, 19 Aug 2021 13:08:57 +0200
Message-Id: <20210819110857.2229769-8-frode.nordahl@canonical.com>
X-Mailer: git-send-email 2.32.0
In-Reply-To: <20210819110857.2229769-1-frode.nordahl@canonical.com>
References: <20210819110857.2229769-1-frode.nordahl@canonical.com>
MIME-Version: 1.0
Subject: [ovs-dev] [PATCH ovn v3 7/7] binding: 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/binding.c | 269 +++++++++++++++++++++++++++++++++++++++-
tests/ovn-controller.at | 31 +++++
tests/ovn-macros.at | 2 +-
3 files changed, 296 insertions(+), 6 deletions(-)
diff --git a/controller/binding.c b/controller/binding.c
index 52eb47b79..7499fd9a2 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -23,6 +23,7 @@
#include "lib/netdev.h"
#include "lib/vswitch-idl.h"
#include "openvswitch/hmap.h"
+#include "openvswitch/uuid.h"
#include "openvswitch/vlog.h"
/* OVN includes. */
@@ -35,7 +36,9 @@
#include "local_data.h"
#include "lport.h"
#include "ovn-controller.h"
+#include "ovsport.h"
#include "patch.h"
+#include "plug.h"
VLOG_DEFINE_THIS_MODULE(binding);
@@ -45,6 +48,8 @@ VLOG_DEFINE_THIS_MODULE(binding);
*/
#define OVN_INSTALLED_EXT_ID "ovn-installed"
+#define OVN_PLUGGED_EXT_ID "ovn-plugged"
+
#define OVN_QOS_TYPE "linux-htb"
struct qos_queue {
@@ -71,10 +76,13 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name);
+ ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_type);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd_status);
ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_status);
+ ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_options);
+ ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_mtu_request);
ovsdb_idl_add_table(ovs_idl, &ovsrec_table_qos);
ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_type);
@@ -1046,6 +1054,18 @@ is_binding_lport_this_chassis(struct binding_lport *b_lport,
b_lport->pb->chassis == chassis);
}
+static bool
+chassis_uses_dpdk(const struct ovsrec_open_vswitch_table *ovs_table,
+ const struct ovsrec_bridge *br_int)
+{
+ const struct ovsrec_open_vswitch *cfg;
+
+ cfg = ovsrec_open_vswitch_table_first(ovs_table);
+
+ return (cfg && cfg->dpdk_initialized &&
+ !strcmp(br_int->datapath_type, "netdev"));
+}
+
static bool
can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec,
const char *requested_chassis)
@@ -1055,6 +1075,15 @@ can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec,
|| !strcmp(requested_chassis, chassis_rec->hostname);
}
+static bool
+can_plug_on_this_chassis(const struct sbrec_chassis *chassis_rec,
+ const struct sbrec_port_binding *pb)
+{
+ return (pb && chassis_rec && pb->plugged_by
+ && uuid_equals(&chassis_rec->header_.uuid,
+ &pb->plugged_by->header_.uuid));
+}
+
/* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER,
* 'false' otherwise. */
static bool
@@ -1088,6 +1117,51 @@ release_binding_lport(const struct sbrec_chassis *chassis_rec,
return true;
}
+static void
+consider_unplug_lport(const struct sbrec_port_binding *pb,
+ struct binding_ctx_in *b_ctx_in,
+ struct local_binding *lbinding)
+{
+ const char *plug_type = NULL;
+ if (lbinding && lbinding->iface) {
+ plug_type = smap_get(&lbinding->iface->external_ids,
+ OVN_PLUGGED_EXT_ID);
+ }
+
+ if (plug_type) {
+ const struct ovsrec_port *port = ovsport_lookup_by_interface(
+ b_ctx_in->ovsrec_port_by_interfaces,
+ (struct ovsrec_interface *) lbinding->iface);
+ if (port) {
+ struct plug *plug;
+ if (plug_open(plug_type, &plug)) {
+ 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);
+ return;
+ }
+ const struct plug_port_ctx_in plug_ctx_in = {
+ .op_type = PLUG_OP_REMOVE,
+ .use_dpdk = chassis_uses_dpdk(b_ctx_in->ovs_table,
+ b_ctx_in->br_int),
+ .lport_name = (const char *)pb->logical_port,
+ .lport_options = (const struct smap *)&pb->options,
+ .iface_name = lbinding->iface->name,
+ .iface_type = lbinding->iface->type,
+ .iface_options = &lbinding->iface->options,
+ };
+ plug_port_prepare(plug, &plug_ctx_in, NULL);
+ VLOG_INFO("Unplugging port %s from %s for lport %s on this "
+ "chassis.",
+ port->name, b_ctx_in->br_int->name, pb->logical_port);
+ ovsport_remove(b_ctx_in->br_int, port);
+ plug_port_finish(plug, &plug_ctx_in, NULL);
+ }
+ }
+}
+
static bool
consider_vif_lport_(const struct sbrec_port_binding *pb,
bool can_bind, const char *vif_chassis,
@@ -1138,15 +1212,184 @@ consider_vif_lport_(const struct sbrec_port_binding *pb,
if (pb->chassis == b_ctx_in->chassis_rec) {
/* Release the lport if there is no lbinding. */
if (!lbinding_set || !can_bind) {
- return release_lport(pb, !b_ctx_in->ovnsb_idl_txn,
- b_ctx_out->tracked_dp_bindings,
- b_ctx_out->if_mgr);
+ bool handled = release_lport(pb, !b_ctx_in->ovnsb_idl_txn,
+ b_ctx_out->tracked_dp_bindings,
+ b_ctx_out->if_mgr);
+ if (handled && b_lport && b_lport->lbinding) {
+ consider_unplug_lport(pb, b_ctx_in, b_lport->lbinding);
+ }
+ return handled;
}
}
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 *plug,
+ const struct smap *iface_external_ids,
+ const struct sbrec_port_binding *pb,
+ struct binding_ctx_in *b_ctx_in)
+{
+ bool ret = true;
+ struct plug_port_ctx_in plug_ctx_in = {
+ .op_type = PLUG_OP_CREATE,
+ .use_dpdk = chassis_uses_dpdk(b_ctx_in->ovs_table,
+ b_ctx_in->br_int),
+ .lport_name = (const char *)pb->logical_port,
+ .lport_options = (const struct smap *)&pb->options,
+ };
+ struct plug_port_ctx_out plug_ctx_out;
+
+ if (!plug_port_prepare(plug, &plug_ctx_in, &plug_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);
+ ret = false;
+ goto out;
+ }
+
+ VLOG_INFO("Plugging port %s into %s for lport %s on this "
+ "chassis.",
+ plug_ctx_out.name, b_ctx_in->br_int->name,
+ pb->logical_port);
+ ovsport_create(b_ctx_in->ovs_idl_txn, b_ctx_in->br_int,
+ plug_ctx_out.name, plug_ctx_out.type,
+ NULL, iface_external_ids,
+ plug_ctx_out.iface_options,
+ get_plug_mtu_request(&pb->options));
+
+ plug_port_finish(plug, &plug_ctx_in, &plug_ctx_out);
+
+out:
+ plug_port_ctx_destroy(plug, &plug_ctx_in, &plug_ctx_out);
+
+ return ret;
+}
+
+static bool
+consider_plug_lport_update__(const struct plug *plug,
+ const struct smap *iface_external_ids,
+ const struct sbrec_port_binding *pb,
+ struct binding_ctx_in *b_ctx_in,
+ struct local_binding *lbinding)
+{
+ bool ret = true;
+ struct plug_port_ctx_in plug_ctx_in = {
+ .op_type = PLUG_OP_CREATE,
+ .use_dpdk = chassis_uses_dpdk(b_ctx_in->ovs_table,
+ b_ctx_in->br_int),
+ .lport_name = (const char *)pb->logical_port,
+ .lport_options = (const struct smap *)&pb->options,
+ .iface_name = lbinding->iface->name,
+ .iface_type = lbinding->iface->type,
+ .iface_options = &lbinding->iface->options,
+ };
+ struct plug_port_ctx_out plug_ctx_out;
+
+ if (!plug_port_prepare(plug, &plug_ctx_in, &plug_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);
+ ret = false;
+ goto out;
+ }
+
+ if (strcmp(lbinding->iface->name, plug_ctx_out.name)) {
+ VLOG_WARN("Attempt of incompatible change to existing "
+ "port detected, please recreate port: %s",
+ pb->logical_port);
+ ret = false;
+ goto out;
+ }
+ VLOG_DBG("updating iface for: %s", pb->logical_port);
+ ovsport_update_iface(lbinding->iface, plug_ctx_out.type,
+ iface_external_ids,
+ NULL,
+ plug_ctx_out.iface_options,
+ plug_class_get_maintained_iface_options(
+ plug),
+ get_plug_mtu_request(&pb->options));
+
+ plug_port_finish(plug, &plug_ctx_in, &plug_ctx_out);
+out:
+ plug_port_ctx_destroy(plug, &plug_ctx_in, &plug_ctx_out);
+
+ return ret;
+}
+
+static bool
+consider_plug_lport(const struct sbrec_port_binding *pb,
+ struct binding_ctx_in *b_ctx_in,
+ struct local_binding *lbinding)
+{
+ if (!b_ctx_in->chassis_rec || !b_ctx_in->br_int || !b_ctx_in->ovs_idl_txn)
+ {
+ return false;
+ }
+ bool ret = true;
+
+ if (can_plug_on_this_chassis(b_ctx_in->chassis_rec, pb)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+ const char *plug_type = smap_get(&pb->options, "plug-type");
+ if (!plug_type) {
+ /* This should never happen, but better safe than sorry */
+ VLOG_WARN_RL(&rl,
+ "Possible database inconsistency detected: "
+ "Port_Binding->plugged_by points at this chassis, "
+ "but Port_Binding->options:plug-type not set. "
+ "lport %s",
+ pb->logical_port);
+ return false;
+ }
+
+ struct plug *plug;
+ if (plug_open(plug_type, &plug)) {
+ VLOG_WARN_RL(&rl,
+ "Unable to open plug provider for plug-type: '%s' "
+ "lport %s",
+ plug_type, pb->logical_port);
+ return false;
+ }
+ 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));
+ ret = false;
+ goto out;
+ }
+ ret = consider_plug_lport_update__(plug, &iface_external_ids, pb,
+ b_ctx_in, lbinding);
+ } else {
+ ret = consider_plug_lport_create__(plug, &iface_external_ids, pb,
+ b_ctx_in);
+ }
+ }
+
+out:
+ return ret;
+}
+
static bool
consider_vif_lport(const struct sbrec_port_binding *pb,
struct binding_ctx_in *b_ctx_in,
@@ -1170,6 +1413,11 @@ consider_vif_lport(const struct sbrec_port_binding *pb,
b_lport = local_binding_add_lport(binding_lports, lbinding, pb, LP_VIF);
}
+ /* Consider if we should create or update local port/interface record for
+ * this lport. Note that a newly created port/interface will get its flows
+ * installed on the next loop iteration as we won't wait for OVS vSwitchd
+ * to configure and assign a ofport to the interface. */
+ consider_plug_lport(pb, b_ctx_in, lbinding);
return consider_vif_lport_(pb, can_bind, vif_chassis, b_ctx_in,
b_ctx_out, b_lport, qos_map);
}
@@ -1563,6 +1811,10 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out)
const struct sbrec_port_binding *pb;
};
+ /* For any open plug provider instances, perform periodic non-blocking
+ * maintenance */
+ plug_run_instances();
+
/* Run through each binding record to see if it is resident on this
* chassis and update the binding accordingly. This includes both
* directly connected logical ports and children of those ports
@@ -2097,8 +2349,11 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb,
lbinding = b_lport->lbinding;
bound = is_binding_lport_this_chassis(b_lport, b_ctx_in->chassis_rec);
- /* Remove b_lport from local_binding. */
- binding_lport_delete(binding_lports, b_lport);
+ if (b_lport->lbinding) {
+ consider_unplug_lport(pb, b_ctx_in, b_lport->lbinding);
+ }
+ /* Remove b_lport from local_binding. */
+ binding_lport_delete(binding_lports, b_lport);
}
if (bound && lbinding && lport_type == LP_VIF) {
@@ -2676,6 +2931,10 @@ local_binding_handle_stale_binding_lports(struct local_binding *lbinding,
handled = release_binding_lport(b_ctx_in->chassis_rec, b_lport,
!b_ctx_in->ovnsb_idl_txn,
b_ctx_out);
+ if (handled && b_lport && b_lport->lbinding) {
+ consider_unplug_lport(b_lport->pb, b_ctx_in,
+ b_lport->lbinding);
+ }
binding_lport_delete(&b_ctx_out->lbinding_data->lports,
b_lport);
}
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index e8550a5dc..c7f61457b 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -692,3 +692,34 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep controller | grep userdata=0
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-controller - plugging])
+AT_KEYWORDS([plugging])
+
+ovn_start
+
+net_add n1
+sim_add hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+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.100"
+check ovn-nbctl --wait=sb set Logical_Switch_Port lsp1 \
+ options:requested-chassis=hv1 \
+ options:plug-type=dummy \
+ options:plug-mtu-request=42
+
+wait_column "true" Port_Binding up logical_port=lsp1
+
+as hv1
+
+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"])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
index b5a01b2b5..f26e84f3d 100644
--- a/tests/ovn-macros.at
+++ b/tests/ovn-macros.at
@@ -325,7 +325,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]