From patchwork Thu Dec 14 01:04:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875915 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDf83cWzz23nF for ; Thu, 14 Dec 2023 12:04:48 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8BAF5831F5; Thu, 14 Dec 2023 01:04:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8BAF5831F5 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 TlMCBEjmThQK; Thu, 14 Dec 2023 01:04:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 891988301F; Thu, 14 Dec 2023 01:04:43 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 891988301F Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5D14EC0DCE; Thu, 14 Dec 2023 01:04:43 +0000 (UTC) X-Original-To: ovs-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 AAC7AC0DD0 for ; Thu, 14 Dec 2023 01:04:41 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8687982F77 for ; Thu, 14 Dec 2023 01:04:41 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8687982F77 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 rKewgKgfYmV9 for ; Thu, 14 Dec 2023 01:04:40 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp1.osuosl.org (Postfix) with ESMTPS id 9852D823DD for ; Thu, 14 Dec 2023 01:04:40 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 9852D823DD Received: by mail.gandi.net (Postfix) with ESMTPSA id 633F9240002; Thu, 14 Dec 2023 01:04:38 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:03 +0100 Message-ID: <20231214010431.1664005-2-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 01/22] ovsdb-server.at: Enbale debug logs in active-backup tests. 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" It's almost impossible to debug test failures without them. Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- tests/ovsdb-server.at | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index d36c3c117..35286db37 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -1830,9 +1830,14 @@ replication_schema > schema AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore]) AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore]) -AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-server -vfile --detach --no-chdir \ + --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], + [0], [ignore], [ignore]) -AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=2.pid --remote=punix:db2.sock --unixctl=unixctl2 db2], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-server -vfile --detach --no-chdir \ + --log-file=ovsdb-server2.log --pidfile=2.pid \ + --remote=punix:db2.sock --unixctl=unixctl2 db2], + [0], [ignore], [ignore]) dnl Try to connect without specifying the active server. AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/connect-active-ovsdb-server], [0], @@ -2153,9 +2158,16 @@ AT_CHECK([ovsdb-tool transact db2 \ dnl Start both 'db1' and 'db2'. on_exit 'kill `cat *.pid`' -AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock --unixctl="`pwd`"/unixctl db1 --active ], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-server -vfile --detach --no-chdir \ + --log-file=ovsdb-server1.log --pidfile \ + --remote=punix:db.sock \ + --unixctl="$(pwd)"/unixctl db1 --active ], + [0], [ignore], [ignore]) -AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=2.pid --remote=punix:db2.sock --unixctl="`pwd`"/unixctl2 db2], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-server -vfile --detach --no-chdir \ + --log-file=ovsdb-server2.log --pidfile=2.pid \ + --remote=punix:db2.sock --unixctl="$(pwd)"/unixctl2 db2], + [0], [ignore], [ignore]) OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status |grep active]) OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status |grep active]) From patchwork Thu Dec 14 01:04:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875917 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfD3X1sz23nn for ; Thu, 14 Dec 2023 12:04:52 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id B7BAA83339; Thu, 14 Dec 2023 01:04:49 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org B7BAA83339 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 pPBjgAk84xGY; Thu, 14 Dec 2023 01:04:47 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 74B7D8308D; Thu, 14 Dec 2023 01:04:46 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 74B7D8308D Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 445C9C0072; Thu, 14 Dec 2023 01:04:46 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id D2885C0037 for ; Thu, 14 Dec 2023 01:04:44 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id AAD6941C2B for ; Thu, 14 Dec 2023 01:04:44 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org AAD6941C2B 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 2VymWaE0_VqO for ; Thu, 14 Dec 2023 01:04:44 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp4.osuosl.org (Postfix) with ESMTPS id 5C0FD41BB6 for ; Thu, 14 Dec 2023 01:04:43 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5C0FD41BB6 Received: by mail.gandi.net (Postfix) with ESMTPSA id 34899240005; Thu, 14 Dec 2023 01:04:41 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:04 +0100 Message-ID: <20231214010431.1664005-3-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 02/22] tests: ovsdb: Use diff -up format for replay test. 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" It's easier to analyze failures when the lines that are different are shown next to each other. Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- tests/ovsdb-client.at | 6 +++--- tests/ovsdb-server.at | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ovsdb-client.at b/tests/ovsdb-client.at index 68fb962bd..dcddb2587 100644 --- a/tests/ovsdb-client.at +++ b/tests/ovsdb-client.at @@ -270,8 +270,8 @@ AT_CHECK([ovsdb-client --replay=./replay_dir dnl dnl Waiting for client to exit the same way as it exited during recording. OVS_WAIT_WHILE([test -e ovsdb-client.pid]) -AT_CHECK([diff monitor.stdout monitor-replay.stdout]) -AT_CHECK([diff monitor.stderr monitor-replay.stderr]) +AT_CHECK([diff -u monitor.stdout monitor-replay.stdout]) +AT_CHECK([diff -u monitor.stderr monitor-replay.stderr]) dnl Stripping out timestamps, PIDs and poll_loop warnings from the log. dnl Also stripping socket_util errors as sockets are not used in replay. @@ -284,6 +284,6 @@ m4_define([CLEAN_LOG_FILE], CLEAN_LOG_FILE([monitor.log], [monitor.log.clear]) CLEAN_LOG_FILE([monitor-replay.log], [monitor-replay.log.clear]) -AT_CHECK([diff monitor.log.clear monitor-replay.log.clear]) +AT_CHECK([diff -u monitor.log.clear monitor-replay.log.clear]) AT_CLEANUP diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 35286db37..6eb758e22 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -2394,6 +2394,6 @@ CLEAN_LOG_FILE([2.log], [2.log.clear]) dnl Checking that databases and logs are equal. AT_CHECK([diff db.clear ./replay_dir/db.copy.clear]) -AT_CHECK([diff 1.log.clear 2.log.clear]) +AT_CHECK([diff -u 1.log.clear 2.log.clear]) AT_CLEANUP From patchwork Thu Dec 14 01:04:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875918 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfF5BdVz23nF for ; Thu, 14 Dec 2023 12:04:53 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 99A3341E55; Thu, 14 Dec 2023 01:04:51 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 99A3341E55 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 6AjwrKyU2MIN; Thu, 14 Dec 2023 01:04:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id 10FCB41E0C; Thu, 14 Dec 2023 01:04:49 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 10FCB41E0C Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D6073C0DCF; Thu, 14 Dec 2023 01:04:48 +0000 (UTC) X-Original-To: ovs-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 315AEC0DD0 for ; Thu, 14 Dec 2023 01:04:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id EB33561ACD for ; Thu, 14 Dec 2023 01:04:46 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org EB33561ACD X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id khVJaPGfLWQp for ; Thu, 14 Dec 2023 01:04:46 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp3.osuosl.org (Postfix) with ESMTPS id E2B6261AC9 for ; Thu, 14 Dec 2023 01:04:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org E2B6261AC9 Received: by mail.gandi.net (Postfix) with ESMTPSA id 8C35D240003; Thu, 14 Dec 2023 01:04:43 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:05 +0100 Message-ID: <20231214010431.1664005-4-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 03/22] jsonrpc: Sort JSON objects while printing debug messages. 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" We compare the logs in some tests, for example record/replay tests. And those fail if for some reason the JSON object traversal happens in the different order. Sort the output in debug logs in order to fix sporadic test failures. Should not affect performance in real-world cases as the actual outgoing message is still not sorted. Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- lib/jsonrpc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c index c8ce5362e..3db5f76e2 100644 --- a/lib/jsonrpc.c +++ b/lib/jsonrpc.c @@ -221,19 +221,19 @@ jsonrpc_log_msg(const struct jsonrpc *rpc, const char *title, } if (msg->params) { ds_put_cstr(&s, ", params="); - json_to_ds(msg->params, 0, &s); + json_to_ds(msg->params, JSSF_SORT, &s); } if (msg->result) { ds_put_cstr(&s, ", result="); - json_to_ds(msg->result, 0, &s); + json_to_ds(msg->result, JSSF_SORT, &s); } if (msg->error) { ds_put_cstr(&s, ", error="); - json_to_ds(msg->error, 0, &s); + json_to_ds(msg->error, JSSF_SORT, &s); } if (msg->id) { ds_put_cstr(&s, ", id="); - json_to_ds(msg->id, 0, &s); + json_to_ds(msg->id, JSSF_SORT, &s); } VLOG_DBG("%s: %s %s%s", rpc->name, title, jsonrpc_msg_type_to_string(msg->type), ds_cstr(&s)); From patchwork Thu Dec 14 01:04:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875919 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfQ09y9z23nF for ; Thu, 14 Dec 2023 12:05:02 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C7C6B83843; Thu, 14 Dec 2023 01:04:59 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org C7C6B83843 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 xdOhhIuZvAen; Thu, 14 Dec 2023 01:04:57 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 9503C8352B; Thu, 14 Dec 2023 01:04:56 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 9503C8352B Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7A5AEC0072; Thu, 14 Dec 2023 01:04:56 +0000 (UTC) X-Original-To: ovs-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 250AFC0DCF for ; Thu, 14 Dec 2023 01:04:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 0241461ACE for ; Thu, 14 Dec 2023 01:04:51 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 0241461ACE X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id d49XJ9mqLom0 for ; Thu, 14 Dec 2023 01:04:48 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp3.osuosl.org (Postfix) with ESMTPS id 9AE4561AD0 for ; Thu, 14 Dec 2023 01:04:48 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 9AE4561AD0 Received: by mail.gandi.net (Postfix) with ESMTPSA id 60EA5240002; Thu, 14 Dec 2023 01:04:46 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:06 +0100 Message-ID: <20231214010431.1664005-5-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 04/22] ovsdb: jsonrpc-server: Fix the DSCP value in default options. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" The DSCP_DEFAULT is not zero and is a value that supposed to be used for all connections by default. Fixes: f125905cdd3d ("Allow configuring DSCP on controller and manager connections.") Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- ovsdb/jsonrpc-server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index a3ca48a7b..45f7c8038 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -215,6 +215,7 @@ ovsdb_jsonrpc_default_options(const char *target) options->probe_interval = (stream_or_pstream_needs_probes(target) ? RECONNECT_DEFAULT_PROBE_INTERVAL : 0); + options->dscp = DSCP_DEFAULT; return options; } From patchwork Thu Dec 14 01:04:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875920 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfW106fz23nF for ; Thu, 14 Dec 2023 12:05:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 19058436E0; Thu, 14 Dec 2023 01:05:05 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 19058436E0 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 AcBRcrYFlzR0; Thu, 14 Dec 2023 01:05:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 6DF01436A2; Thu, 14 Dec 2023 01:05:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 6DF01436A2 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 31303C0DD0; Thu, 14 Dec 2023 01:05:02 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 59CE4C0072 for ; Thu, 14 Dec 2023 01:05:00 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 5C31941E58 for ; Thu, 14 Dec 2023 01:04:52 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5C31941E58 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 nQR4Dnz2CsLg for ; Thu, 14 Dec 2023 01:04:51 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp4.osuosl.org (Postfix) with ESMTPS id 4310441E48 for ; Thu, 14 Dec 2023 01:04:51 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 4310441E48 Received: by mail.gandi.net (Postfix) with ESMTPSA id E3225240003; Thu, 14 Dec 2023 01:04:48 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:07 +0100 Message-ID: <20231214010431.1664005-6-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 05/22] ovsdb: trigger: Do not allow conversion in read-only mode. 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" It's not a big problem, but it would be nice to ensure that the backup database cannot be locally converted. Fixes: e51879e99b3e ("ovsdb: Make OVSDB backup sever read only") Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- ovsdb/trigger.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c index 0edcdd89c..2a48ccc64 100644 --- a/ovsdb/trigger.c +++ b/ovsdb/trigger.c @@ -278,6 +278,14 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now) return false; } + if (t->read_only) { + trigger_convert_error( + t, ovsdb_error("not allowed", "conversion is not allowed " + "for read-only database %s", + t->db->schema->name)); + return false; + } + /* Validate parameters. */ const struct json *params = t->request->params; if (params->type != JSON_ARRAY || params->array.n != 2) { From patchwork Thu Dec 14 01:04:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875921 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfk2bx4z1ySd for ; Thu, 14 Dec 2023 12:05:18 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 884D642069; Thu, 14 Dec 2023 01:05:16 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 884D642069 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 MYMWxGk7EGSU; Thu, 14 Dec 2023 01:05:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id 952734203A; Thu, 14 Dec 2023 01:05:14 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 952734203A Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 57390C0072; Thu, 14 Dec 2023 01:05:14 +0000 (UTC) X-Original-To: ovs-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 08E9AC0037 for ; Thu, 14 Dec 2023 01:05:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 289F9617BA for ; Thu, 14 Dec 2023 01:04:57 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 289F9617BA X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hD22yuSF4Ew7 for ; Thu, 14 Dec 2023 01:04:54 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp3.osuosl.org (Postfix) with ESMTPS id 0DF02617B6 for ; Thu, 14 Dec 2023 01:04:53 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 0DF02617B6 Received: by mail.gandi.net (Postfix) with ESMTPSA id E39EC240002; Thu, 14 Dec 2023 01:04:51 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:08 +0100 Message-ID: <20231214010431.1664005-7-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 06/22] ovsdb: Allow database itself to be read-only. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Currently, the read-only option can be set on connections or JSON-RPC server as a whole. However, there is no way to allow modifications in one database, but not in the other. Adding an internal read-only flag for a database itself. Will be used later for running active and backup databases in a single process. Marking the _Server database as read only is not necessary, because modifications of internal databases are not allowed anyway, but it doesn't hurt. Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- ovsdb/jsonrpc-server.c | 3 ++- ovsdb/ovsdb-server.c | 3 +++ ovsdb/ovsdb.c | 2 ++ ovsdb/ovsdb.h | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 45f7c8038..4ea4c7a4b 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -1148,7 +1148,8 @@ ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, /* Insert into trigger table. */ t = xmalloc(sizeof *t); bool disconnect_all = ovsdb_trigger_init( - &s->up, db, &t->trigger, request, time_msec(), s->read_only, + &s->up, db, &t->trigger, request, time_msec(), + s->read_only || db->read_only, s->remote->role, jsonrpc_session_get_id(s->js)); t->id = json_clone(request->id); hmap_insert(&s->triggers, &t->hmap_node, hash); diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 4d29043f4..c294ebe67 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -831,8 +831,11 @@ add_server_db(struct server_config *config) db->filename = xstrdup(""); db->db = ovsdb_create(schema, ovsdb_storage_create_unbacked(NULL)); + db->db->read_only = true; + bool ok OVS_UNUSED = ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db); ovs_assert(ok); + add_db(config, db); } diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c index f67b836d7..298616a64 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c @@ -464,6 +464,8 @@ ovsdb_create(struct ovsdb_schema *schema, struct ovsdb_storage *storage) db->n_atoms = 0; + db->read_only = false; + db->is_relay = false; ovs_list_init(&db->txn_forward_new); hmap_init(&db->txn_forward_sent); diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h index d45630e8f..325900bc6 100644 --- a/ovsdb/ovsdb.h +++ b/ovsdb/ovsdb.h @@ -114,6 +114,9 @@ struct ovsdb { size_t n_atoms; /* Total number of ovsdb atoms in the database. */ + bool read_only; /* If 'true', JSON-RPC clients are not allowed to change + * the data. */ + /* Relay mode. */ bool is_relay; /* True, if database is in relay mode. */ /* List that holds transactions waiting to be forwarded to the server. */ From patchwork Thu Dec 14 01:04:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875922 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDfy0dXBz1ySd for ; Thu, 14 Dec 2023 12:05:29 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id DAFC961B3C; Thu, 14 Dec 2023 01:05:27 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org DAFC961B3C X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XNSd9HgZhR2j; Thu, 14 Dec 2023 01:05:26 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 72CFA61B34; Thu, 14 Dec 2023 01:05:25 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 72CFA61B34 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4A13BC0DCE; Thu, 14 Dec 2023 01:05:25 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0BEBEC0037 for ; Thu, 14 Dec 2023 01:05:24 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id E95CE41DFE for ; Thu, 14 Dec 2023 01:04:58 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org E95CE41DFE 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 e3lFN43NdF0n for ; Thu, 14 Dec 2023 01:04:58 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp4.osuosl.org (Postfix) with ESMTPS id CD79841E19 for ; Thu, 14 Dec 2023 01:04:57 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org CD79841E19 Received: by mail.gandi.net (Postfix) with ESMTPSA id B6F45240002; Thu, 14 Dec 2023 01:04:55 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:09 +0100 Message-ID: <20231214010431.1664005-8-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 07/22] jsonrpc-server: Add functions to convert jsonrpc options to/from json. 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" These functions will be needed when we'll need to load/save configuration of each OVSDB remote separately. The parsing function is written in a way that it updates the provided options and doesn't create a new structure. This is done in order for different callers to have their own default values and only update them with what is provided by the user explicitly. For example, replication and relay have different default probe intervals. Signed-off-by: Ilya Maximets Acked-by: Mike Pattrick --- ovsdb/jsonrpc-server.c | 66 ++++++++++++++++++++++++++++++++++++++++++ ovsdb/jsonrpc-server.h | 6 ++++ 2 files changed, 72 insertions(+) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 4ea4c7a4b..51b7db886 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -219,6 +219,72 @@ ovsdb_jsonrpc_default_options(const char *target) return options; } +struct json * +ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options) +{ + struct json *json = json_object_create(); + + json_object_put(json, "max-backoff", + json_integer_create(options->max_backoff)); + json_object_put(json, "inactivity-probe", + json_integer_create(options->probe_interval)); + json_object_put(json, "read-only", + json_boolean_create(options->read_only)); + json_object_put(json, "dscp", json_integer_create(options->dscp)); + if (options->role) { + json_object_put(json, "role", json_string_create(options->role)); + } + + return json; +} + +void +ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *options, + const struct json *json) +{ + const struct json *max_backoff, *probe_interval, *read_only, *dscp, *role; + struct ovsdb_parser parser; + struct ovsdb_error *error; + + ovsdb_parser_init(&parser, json, "JSON-RPC options"); + + max_backoff = ovsdb_parser_member(&parser, "max-backoff", + OP_INTEGER | OP_OPTIONAL); + if (max_backoff) { + options->max_backoff = json_integer(max_backoff); + } + + probe_interval = ovsdb_parser_member(&parser, "inactivity-probe", + OP_INTEGER | OP_OPTIONAL); + if (probe_interval) { + options->probe_interval = json_integer(probe_interval); + } + + read_only = ovsdb_parser_member(&parser, "read-only", + OP_BOOLEAN | OP_OPTIONAL); + if (read_only) { + options->read_only = json_boolean(read_only); + } + + dscp = ovsdb_parser_member(&parser, "dscp", OP_INTEGER | OP_OPTIONAL); + if (dscp) { + options->dscp = json_integer(dscp); + } + + role = ovsdb_parser_member(&parser, "role", OP_STRING | OP_OPTIONAL); + if (role) { + options->role = nullable_xstrdup(json_string(role)); + } + + error = ovsdb_parser_finish(&parser); + if (error) { + char *s = ovsdb_error_to_string_free(error); + + VLOG_WARN("%s", s); + free(s); + } +} + /* Sets 'svr''s current set of remotes to the names in 'new_remotes', with * options in the struct ovsdb_jsonrpc_options supplied as the data values. * diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index e0653aa39..9c49966c1 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -42,6 +42,12 @@ struct ovsdb_jsonrpc_options { struct ovsdb_jsonrpc_options * ovsdb_jsonrpc_default_options(const char *target); +struct json *ovsdb_jsonrpc_options_to_json( + const struct ovsdb_jsonrpc_options *) + OVS_WARN_UNUSED_RESULT; +void ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *, + const struct json *); + void ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *, const struct shash *); From patchwork Thu Dec 14 01:04:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875923 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDgC6QPcz1ySd for ; Thu, 14 Dec 2023 12:05:43 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 187E06F4DE; Thu, 14 Dec 2023 01:05:42 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 187E06F4DE X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0RRPCpUskiwm; Thu, 14 Dec 2023 01:05:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 5C2D861AE1; Thu, 14 Dec 2023 01:05:39 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 5C2D861AE1 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 30AAAC0072; Thu, 14 Dec 2023 01:05:39 +0000 (UTC) X-Original-To: ovs-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 26E55C0DCE for ; Thu, 14 Dec 2023 01:05:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C8DDD834C7 for ; Thu, 14 Dec 2023 01:05:03 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org C8DDD834C7 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 zAPYosKc2csT for ; Thu, 14 Dec 2023 01:05:02 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp1.osuosl.org (Postfix) with ESMTPS id B170483412 for ; Thu, 14 Dec 2023 01:05:01 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org B170483412 Received: by mail.gandi.net (Postfix) with ESMTPSA id 7A50C240002; Thu, 14 Dec 2023 01:04:59 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:10 +0100 Message-ID: <20231214010431.1664005-9-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 08/22] ovsdb: Track jsonrpc options per remote. 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" Store KSON-RPC options for each remote separately, so it will be possible to have different configurations per remote in the future. These are also stored to and loaded from the temporary file that OVSDB is using to restore runtime configuration of the server restarted by the monitor process after a crash. Signed-off-by: Ilya Maximets --- ovsdb/jsonrpc-server.c | 11 ++++ ovsdb/jsonrpc-server.h | 6 +- ovsdb/ovsdb-server.c | 136 ++++++++++++++++++++++++++++------------- 3 files changed, 110 insertions(+), 43 deletions(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 51b7db886..299afbb1d 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -219,6 +219,17 @@ ovsdb_jsonrpc_default_options(const char *target) return options; } +struct ovsdb_jsonrpc_options * +ovsdb_jsonrpc_options_clone(const struct ovsdb_jsonrpc_options *options) +{ + struct ovsdb_jsonrpc_options *clone; + + clone = xmemdup(options, sizeof *options); + clone->role = nullable_xstrdup(options->role); + + return clone; +} + struct json * ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options) { diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index 9c49966c1..39366ad70 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -39,8 +39,10 @@ struct ovsdb_jsonrpc_options { int dscp; /* Dscp value for manager connections */ char *role; /* Role, for role-based access controls */ }; -struct ovsdb_jsonrpc_options * -ovsdb_jsonrpc_default_options(const char *target); +struct ovsdb_jsonrpc_options *ovsdb_jsonrpc_default_options( + const char *target); +struct ovsdb_jsonrpc_options *ovsdb_jsonrpc_options_clone( + const struct ovsdb_jsonrpc_options *); struct json *ovsdb_jsonrpc_options_to_json( const struct ovsdb_jsonrpc_options *) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index c294ebe67..7f65cadfe 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -101,7 +101,7 @@ static unixctl_cb_func ovsdb_server_get_sync_status; static unixctl_cb_func ovsdb_server_get_db_storage_status; struct server_config { - struct sset *remotes; + struct shash *remotes; struct shash *all_dbs; FILE *config_tmpfile; char **sync_from; @@ -130,29 +130,34 @@ static void remove_db(struct server_config *, struct shash_node *db, char *); static void close_db(struct server_config *, struct db *, char *); static void parse_options(int argc, char *argvp[], - struct sset *db_filenames, struct sset *remotes, + struct sset *db_filenames, struct shash *remotes, char **unixctl_pathp, char **run_command, char **sync_from, char **sync_exclude, bool *is_backup); OVS_NO_RETURN static void usage(void); +static struct ovsdb_jsonrpc_options *add_remote( + struct shash *remotes, const char *target, + const struct ovsdb_jsonrpc_options *); +static void free_remotes(struct shash *remotes); + static char *reconfigure_remotes(struct ovsdb_jsonrpc_server *, const struct shash *all_dbs, - struct sset *remotes); + struct shash *remotes); static char *reconfigure_ssl(const struct shash *all_dbs); static void report_error_if_changed(char *error, char **last_errorp); static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc, - const struct sset *remotes, + const struct shash *remotes, struct shash *all_dbs); static void update_server_status(struct shash *all_dbs); -static void save_config__(FILE *config_file, const struct sset *remotes, +static void save_config__(FILE *config_file, const struct shash *remotes, const struct sset *db_filenames, const char *sync_from, const char *sync_exclude, bool is_backup); static void save_config(struct server_config *); -static void load_config(FILE *config_file, struct sset *remotes, +static void load_config(FILE *config_file, struct shash *remotes, struct sset *db_filenames, char **sync_from, char **sync_exclude, bool *is_backup); @@ -184,7 +189,7 @@ log_and_free_error(struct ovsdb_error *error) static void main_loop(struct server_config *config, struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs, - struct unixctl_server *unixctl, struct sset *remotes, + struct unixctl_server *unixctl, struct shash *remotes, struct process *run_process, bool *exiting, bool *is_backup) { char *remotes_error, *ssl_error; @@ -318,7 +323,8 @@ main(int argc, char *argv[]) char *run_command = NULL; struct unixctl_server *unixctl; struct ovsdb_jsonrpc_server *jsonrpc; - struct sset remotes, db_filenames; + struct sset db_filenames; + struct shash remotes; char *sync_from, *sync_exclude; bool is_backup; const char *db_filename; @@ -514,7 +520,7 @@ main(int argc, char *argv[]) } ovsdb_jsonrpc_server_destroy(jsonrpc); shash_destroy(&all_dbs); - sset_destroy(&remotes); + free_remotes(&remotes); sset_destroy(&db_filenames); free(sync_from); free(sync_exclude); @@ -971,13 +977,16 @@ query_db_string(const struct shash *all_dbs, const char *name, } static struct ovsdb_jsonrpc_options * -add_remote(struct shash *remotes, const char *target) +add_remote(struct shash *remotes, const char *target, + const struct ovsdb_jsonrpc_options *options_) { struct ovsdb_jsonrpc_options *options; options = shash_find_data(remotes, target); if (!options) { - options = ovsdb_jsonrpc_default_options(target); + options = options_ + ? ovsdb_jsonrpc_options_clone(options_) + : ovsdb_jsonrpc_default_options(target); shash_add(remotes, target, options); } @@ -995,6 +1004,7 @@ free_remotes(struct shash *remotes) free(options->role); } shash_destroy_free_data(remotes); + shash_init(remotes); } } @@ -1015,7 +1025,7 @@ add_manager_options(struct shash *remotes, const struct ovsdb_row *row) return; } - options = add_remote(remotes, target); + options = add_remote(remotes, target, NULL); if (ovsdb_util_read_integer_column(row, "max_backoff", &max_backoff)) { options->max_backoff = max_backoff; } @@ -1075,7 +1085,7 @@ query_db_remotes(const char *name, const struct shash *all_dbs, datum = &row->fields[column->index]; for (i = 0; i < datum->n; i++) { - add_remote(remotes, json_string(datum->keys[i].s)); + add_remote(remotes, json_string(datum->keys[i].s), NULL); } } } else if (column->type.key.type == OVSDB_TYPE_UUID @@ -1223,19 +1233,24 @@ commit_txn(struct ovsdb_txn *txn, const char *name) static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc, - const struct sset *remotes, + const struct shash *remotes, struct shash *all_dbs) { - struct shash_node *node; - SHASH_FOR_EACH (node, all_dbs) { - struct db *db = node->data; + struct shash_node *db_node; + + SHASH_FOR_EACH (db_node, all_dbs) { + struct db *db = db_node->data; + if (!db->db || ovsdb_storage_is_clustered(db->db->storage)) { continue; } struct ovsdb_txn *txn = ovsdb_txn_create(db->db); - const char *remote; - SSET_FOR_EACH (remote, remotes) { + const struct shash_node *remote_node; + + SHASH_FOR_EACH (remote_node, remotes) { + const char *remote = remote_node->name; + update_remote_rows(all_dbs, db, remote, jsonrpc, txn); } commit_txn(txn, "remote status"); @@ -1342,19 +1357,22 @@ update_server_status(struct shash *all_dbs) /* Reconfigures ovsdb-server's remotes based on information in the database. */ static char * reconfigure_remotes(struct ovsdb_jsonrpc_server *jsonrpc, - const struct shash *all_dbs, struct sset *remotes) + const struct shash *all_dbs, struct shash *remotes) { struct ds errors = DS_EMPTY_INITIALIZER; struct shash resolved_remotes; - const char *name; + struct shash_node *node; /* Configure remotes. */ shash_init(&resolved_remotes); - SSET_FOR_EACH (name, remotes) { + SHASH_FOR_EACH (node, remotes) { + const struct ovsdb_jsonrpc_options *options = node->data; + const char *name = node->name; + if (!strncmp(name, "db:", 3)) { query_db_remotes(name, all_dbs, &resolved_remotes, &errors); } else { - add_remote(&resolved_remotes, name); + add_remote(&resolved_remotes, name, options); } } ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes); @@ -1719,7 +1737,7 @@ ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, : parse_db_column(config->all_dbs, remote, &db, &table, &column)); if (!retval) { - if (sset_add(config->remotes, remote)) { + if (add_remote(config->remotes, remote, NULL)) { save_config(config); } unixctl_command_reply(conn, NULL); @@ -1736,11 +1754,12 @@ ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *config_) { struct server_config *config = config_; - struct sset_node *node; + struct ovsdb_jsonrpc_options *options; - node = sset_find(config->remotes, argv[1]); - if (node) { - sset_delete(config->remotes, node); + options = shash_find_and_delete(config->remotes, argv[1]); + if (options) { + free(options->role); + free(options); save_config(config); unixctl_command_reply(conn, NULL); } else { @@ -1753,15 +1772,15 @@ static void ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *remotes_) { - struct sset *remotes = remotes_; - const char **list, **p; + const struct shash *remotes = remotes_; + const struct shash_node **list; struct ds s; ds_init(&s); - list = sset_sort(remotes); - for (p = list; *p; p++) { - ds_put_format(&s, "%s\n", *p); + list = shash_sort(remotes); + for (size_t i = 0; i < shash_count(remotes); i++) { + ds_put_format(&s, "%s\n", list[i]->name); } free(list); @@ -1996,7 +2015,7 @@ ovsdb_server_get_db_storage_status(struct unixctl_conn *conn, static void parse_options(int argc, char *argv[], - struct sset *db_filenames, struct sset *remotes, + struct sset *db_filenames, struct shash *remotes, char **unixctl_pathp, char **run_command, char **sync_from, char **sync_exclude, bool *active) { @@ -2047,7 +2066,7 @@ parse_options(int argc, char *argv[], *sync_from = NULL; *sync_exclude = NULL; sset_init(db_filenames); - sset_init(remotes); + shash_init(remotes); for (;;) { int c; @@ -2058,7 +2077,7 @@ parse_options(int argc, char *argv[], switch (c) { case OPT_REMOTE: - sset_add(remotes, optarg); + add_remote(remotes, optarg, NULL); break; case OPT_UNIXCTL: @@ -2197,10 +2216,24 @@ sset_to_json(const struct sset *sset) return array; } +static struct json * +remotes_to_json(const struct shash *remotes) +{ + const struct shash_node *node; + struct json *json; + + json = json_object_create(); + SHASH_FOR_EACH (node, remotes) { + json_object_put(json, node->name, + ovsdb_jsonrpc_options_to_json(node->data)); + } + return json; +} + /* Truncates and replaces the contents of 'config_file' by a representation of * 'remotes' and 'db_filenames'. */ static void -save_config__(FILE *config_file, const struct sset *remotes, +save_config__(FILE *config_file, const struct shash *remotes, const struct sset *db_filenames, const char *sync_from, const char *sync_exclude, bool is_backup) { @@ -2213,7 +2246,7 @@ save_config__(FILE *config_file, const struct sset *remotes, } obj = json_object_create(); - json_object_put(obj, "remotes", sset_to_json(remotes)); + json_object_put(obj, "remotes", remotes_to_json(remotes)); json_object_put(obj, "db_filenames", sset_to_json(db_filenames)); if (sync_from) { json_object_put(obj, "sync_from", json_string_create(sync_from)); @@ -2273,11 +2306,32 @@ sset_from_json(struct sset *sset, const struct json *array) } } +static void +remotes_from_json(struct shash *remotes, const struct json *json) +{ + struct ovsdb_jsonrpc_options *options; + const struct shash_node *node; + const struct shash *object; + + free_remotes(remotes); + + ovs_assert(json); + ovs_assert(json->type == JSON_OBJECT); + + object = json_object(json); + SHASH_FOR_EACH (node, object) { + options = ovsdb_jsonrpc_default_options(node->name); + ovsdb_jsonrpc_options_update_from_json(options, node->data); + shash_add(remotes, node->name, options); + } +} + /* Clears and replaces 'remotes' and 'dbnames' by a configuration read from * 'config_file', which must have been previously written by save_config(). */ static void -load_config(FILE *config_file, struct sset *remotes, struct sset *db_filenames, - char **sync_from, char **sync_exclude, bool *is_backup) +load_config(FILE *config_file, struct shash *remotes, + struct sset *db_filenames, char **sync_from, + char **sync_exclude, bool *is_backup) { struct json *json; @@ -2290,7 +2344,7 @@ load_config(FILE *config_file, struct sset *remotes, struct sset *db_filenames, } ovs_assert(json->type == JSON_OBJECT); - sset_from_json(remotes, shash_find_data(json_object(json), "remotes")); + remotes_from_json(remotes, shash_find_data(json_object(json), "remotes")); sset_from_json(db_filenames, shash_find_data(json_object(json), "db_filenames")); From patchwork Thu Dec 14 01:04:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875924 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDgf26fMz1ySd for ; Thu, 14 Dec 2023 12:06:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 7A4416F510; Thu, 14 Dec 2023 01:06:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 7A4416F510 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JWMUf8NwFfQQ; Thu, 14 Dec 2023 01:06:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id A2E7161B01; Thu, 14 Dec 2023 01:06:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A2E7161B01 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 75603C0072; Thu, 14 Dec 2023 01:06:02 +0000 (UTC) X-Original-To: ovs-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 2B151C0DCE for ; Thu, 14 Dec 2023 01:06:01 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id ED2B161AFA for ; Thu, 14 Dec 2023 01:05:06 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org ED2B161AFA X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PpCR5wYBc1QK for ; Thu, 14 Dec 2023 01:05:05 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp3.osuosl.org (Postfix) with ESMTPS id 61BF561B1B for ; Thu, 14 Dec 2023 01:05:05 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 61BF561B1B Received: by mail.gandi.net (Postfix) with ESMTPSA id 443E6240002; Thu, 14 Dec 2023 01:05:03 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:11 +0100 Message-ID: <20231214010431.1664005-10-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 09/22] ovsdb: Extract relay string parsing into a separate function. 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" Small refactoring so we can re-use this function in later commits. Signed-off-by: Ilya Maximets --- ovsdb/ovsdb-server.c | 45 +++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 7f65cadfe..7e95b3813 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -316,6 +316,34 @@ main_loop(struct server_config *config, free(remotes_error); } +/* Parsing the relay in format 'relay:DB_NAME:'. + * On success, returns 'true', 'name' is set to DB_NAME, 'remotes' to + * ''. Caller is responsible of freeing 'name' and + * 'remotes'. On failure, returns 'false'. */ +static bool +parse_relay_args(const char *arg, char **name, char **remote) +{ + const char *relay_prefix = "relay:"; + const int relay_prefix_len = strlen(relay_prefix); + bool is_relay; + + is_relay = !strncmp(arg, relay_prefix, relay_prefix_len); + if (!is_relay) { + return false; + } + + *remote = strchr(arg + relay_prefix_len, ':'); + + if (!*remote || (*remote)[0] == '\0') { + *remote = NULL; + return false; + } + arg += relay_prefix_len; + *name = xmemdup0(arg, *remote - arg); + *remote = xstrdup(*remote + 1); + return true; +} + int main(int argc, char *argv[]) { @@ -732,15 +760,13 @@ add_db(struct server_config *config, struct db *db) static struct ovsdb_error * OVS_WARN_UNUSED_RESULT open_db(struct server_config *config, const char *filename) { - const char *relay_prefix = "relay:"; - const char *relay_remotes = NULL; - const int relay_prefix_len = strlen(relay_prefix); struct ovsdb_storage *storage; + char *relay_remotes = NULL; struct ovsdb_error *error; bool is_relay; char *name; - is_relay = !strncmp(filename, relay_prefix, relay_prefix_len); + is_relay = parse_relay_args(filename, &name, &relay_remotes); if (!is_relay) { /* If we know that the file is already open, return a good error * message. Otherwise, if the file is open, we'll fail later on with @@ -755,15 +781,7 @@ open_db(struct server_config *config, const char *filename) } name = xstrdup(filename); } else { - /* Parsing the relay in format 'relay:DB_NAME:'*/ - relay_remotes = strchr(filename + relay_prefix_len, ':'); - - if (!relay_remotes || relay_remotes[0] == '\0') { - return ovsdb_error(NULL, "%s: invalid syntax", filename); - } - name = xmemdup0(filename, relay_remotes - filename); - storage = ovsdb_storage_create_unbacked(name + relay_prefix_len); - relay_remotes++; /* Skip the ':'. */ + storage = ovsdb_storage_create_unbacked(name); } struct ovsdb_schema *schema; @@ -813,6 +831,7 @@ open_db(struct server_config *config, const char *filename) if (is_relay) { ovsdb_relay_add_db(db->db, relay_remotes, update_schema, config, *config->relay_source_probe_interval); + free(relay_remotes); } return NULL; } From patchwork Thu Dec 14 01:04:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875926 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhC42JQz1ySd for ; Thu, 14 Dec 2023 12:06:35 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 583B4436B1; Thu, 14 Dec 2023 01:06:33 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 583B4436B1 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 ikkuFvBIAYqy; Thu, 14 Dec 2023 01:06:30 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 1A0F043706; Thu, 14 Dec 2023 01:06:29 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 1A0F043706 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id ED3EDC0072; Thu, 14 Dec 2023 01:06:28 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 028C6C0037 for ; Thu, 14 Dec 2023 01:06:27 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1ED0641E42 for ; Thu, 14 Dec 2023 01:05:12 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 1ED0641E42 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 iuFAYmqYlmdd for ; Thu, 14 Dec 2023 01:05:08 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp4.osuosl.org (Postfix) with ESMTPS id 45F6041B4A for ; Thu, 14 Dec 2023 01:05:08 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 45F6041B4A Received: by mail.gandi.net (Postfix) with ESMTPSA id 16929240003; Thu, 14 Dec 2023 01:05:05 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:12 +0100 Message-ID: <20231214010431.1664005-11-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 10/22] ovsdb: replication: Isolate databases from each other. 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" Refactoring of the replication code, so each database is handled separately from each other. Supposed to work the same way as before with the only difference that each backup database will have its own connection to the source and will have its own state machine. From the user's perspective, the only visible difference is that ovsdb-server/sync-status appctl now shows the status of each database separately. If one of the connections is permanently broken, all the databases will be switched to active. This is done in order to preserve the old behavior where we had only one connection. Signed-off-by: Ilya Maximets --- ovsdb/ovsdb-server.c | 74 +++-- ovsdb/replication.c | 676 ++++++++++++++++++++----------------------- ovsdb/replication.h | 36 +-- 3 files changed, 384 insertions(+), 402 deletions(-) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 7e95b3813..9a3b0add1 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -166,12 +166,12 @@ ovsdb_replication_init(const char *sync_from, const char *exclude, struct shash *all_dbs, const struct uuid *server_uuid, int probe_interval) { - replication_init(sync_from, exclude, server_uuid, probe_interval); struct shash_node *node; SHASH_FOR_EACH (node, all_dbs) { struct db *db = node->data; if (node->name[0] != '_' && db->db) { - replication_add_local_db(node->name, db->db); + replication_set_db(db->db, sync_from, exclude, + server_uuid, probe_interval); } } } @@ -228,11 +228,20 @@ main_loop(struct server_config *config, report_error_if_changed(reconfigure_ssl(all_dbs), &ssl_error); ovsdb_jsonrpc_server_run(jsonrpc); + replication_run(); if (*is_backup) { - replication_run(); - if (!replication_is_alive()) { - disconnect_active_server(); - *is_backup = false; + SHASH_FOR_EACH (node, all_dbs) { + struct db *db = node->data; + if (db->db->name[0] != '_' && !replication_is_alive(db->db)) { + *is_backup = false; + break; + } + } + if (!*is_backup) { + SHASH_FOR_EACH (node, all_dbs) { + struct db *db = node->data; + replication_remove_db(db->db); + } } } @@ -283,10 +292,8 @@ main_loop(struct server_config *config, update_server_status(all_dbs); memory_wait(); - if (*is_backup) { - replication_wait(); - } + replication_wait(); ovsdb_relay_wait(); ovsdb_jsonrpc_server_wait(jsonrpc); @@ -518,7 +525,7 @@ main(int argc, char *argv[]) &server_config); unixctl_command_register("ovsdb-server/get-sync-exclude-tables", "", 0, 0, ovsdb_server_get_sync_exclude_tables, - NULL); + &server_config); unixctl_command_register("ovsdb-server/sync-status", "", 0, 0, ovsdb_server_get_sync_status, &server_config); @@ -606,6 +613,9 @@ close_db(struct server_config *config, struct db *db, char *comment) if (db->db->is_relay) { ovsdb_relay_del_db(db->db); } + if (*config->is_backup) { + replication_remove_db(db->db); + } ovsdb_destroy(db->db); free(db->filename); free(db); @@ -1500,8 +1510,12 @@ ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; + struct shash_node *node; - disconnect_active_server(); + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + replication_remove_db(db->db); + } *config->is_backup = false; save_config(config); unixctl_command_reply(conn, NULL); @@ -1520,7 +1534,11 @@ ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, *config->replication_probe_interval = probe_interval; save_config(config); if (*config->is_backup) { - replication_set_probe_interval(probe_interval); + const struct uuid *server_uuid; + server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); + ovsdb_replication_init(*config->sync_from, *config->sync_exclude, + config->all_dbs, server_uuid, + *config->replication_probe_interval); } unixctl_command_reply(conn, NULL); } else { @@ -1557,7 +1575,7 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, { struct server_config *config = config_; - char *err = set_excluded_tables(argv[1], true); + char *err = parse_excluded_tables(argv[1]); if (!err) { free(*config->sync_exclude); *config->sync_exclude = xstrdup(argv[1]); @@ -1569,7 +1587,6 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, config->all_dbs, server_uuid, *config->replication_probe_interval); } - err = set_excluded_tables(argv[1], false); } unixctl_command_reply(conn, err); free(err); @@ -1579,11 +1596,11 @@ static void ovsdb_server_get_sync_exclude_tables(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, - void *arg_ OVS_UNUSED) + void *config_) { - char *reply = get_excluded_tables(); - unixctl_command_reply(conn, reply); - free(reply); + struct server_config *config = config_; + + unixctl_command_reply(conn, *config->sync_exclude); } static void @@ -1842,13 +1859,6 @@ remove_db(struct server_config *config, struct shash_node *node, char *comment) shash_delete(config->all_dbs, node); save_config(config); - if (*config->is_backup) { - const struct uuid *server_uuid; - server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); - ovsdb_replication_init(*config->sync_from, *config->sync_exclude, - config->all_dbs, server_uuid, - *config->replication_probe_interval); - } } static void @@ -1990,7 +2000,17 @@ ovsdb_server_get_sync_status(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_put_format(&ds, "state: %s\n", is_backup ? "backup" : "active"); if (is_backup) { - ds_put_and_free_cstr(&ds, replication_status()); + const struct shash_node **db_nodes = shash_sort(config->all_dbs); + + for (size_t i = 0; i < shash_count(config->all_dbs); i++) { + const struct db *db = db_nodes[i]->data; + + if (db->db && db->db->name[0] != '_') { + ds_put_and_free_cstr(&ds, replication_status(db->db)); + ds_put_char(&ds, '\n'); + } + } + free(db_nodes); } unixctl_command_reply(conn, ds_cstr(&ds)); @@ -2154,7 +2174,7 @@ parse_options(int argc, char *argv[], break; case OPT_SYNC_EXCLUDE: { - char *err = set_excluded_tables(optarg, false); + char *err = parse_excluded_tables(optarg); if (err) { ovs_fatal(0, "%s", err); } diff --git a/ovsdb/replication.c b/ovsdb/replication.c index 477c69d70..d0d48aad5 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -38,16 +38,7 @@ VLOG_DEFINE_THIS_MODULE(replication); -static char *sync_from; static struct uuid server_uuid; -static struct jsonrpc_session *session; -static unsigned int session_seqno = UINT_MAX; - -static struct jsonrpc_msg *create_monitor_request(struct ovsdb_schema *); -static void add_monitored_table(struct ovsdb_table_schema *table, - struct json *monitor_requests); - -static struct ovsdb_error *reset_database(struct ovsdb *db); static struct ovsdb_error *process_notification(struct json *, struct ovsdb *); static struct ovsdb_error *process_table_update(struct json *table_update, @@ -55,27 +46,6 @@ static struct ovsdb_error *process_table_update(struct json *table_update, struct ovsdb *database, struct ovsdb_txn *txn); -/* Maps from db name to sset of table names. */ -static struct shash excluded_tables = SHASH_INITIALIZER(&excluded_tables); - -static void excluded_tables_clear(void); -static void excluded_tables_add(const char *database, const char *table); -static bool excluded_tables_find(const char *database, const char *table); - - -/* Keep track of request IDs of all outstanding OVSDB requests. */ -static struct hmap request_ids = HMAP_INITIALIZER(&request_ids); - -struct request_ids_hmap_node { - struct hmap_node hmap; - struct json *request_id; - struct ovsdb *db; /* associated database */ -}; -void request_ids_add(const struct json *id, struct ovsdb *db); -bool request_ids_lookup_and_free(const struct json *id, struct ovsdb **db); -static void request_ids_destroy(void); -void request_ids_clear(void); - enum ovsdb_replication_state { RPL_S_INIT, RPL_S_SERVER_ID_REQUESTED, @@ -85,168 +55,231 @@ enum ovsdb_replication_state { RPL_S_REPLICATING, RPL_S_ERR /* Error, no longer replicating. */ }; -static enum ovsdb_replication_state state; - struct replication_db { struct ovsdb *db; + bool schema_version_higher; /* Points to the schema received from the active server if * the local db schema version is higher. NULL otherwise. */ struct ovsdb_schema *active_db_schema; + + char *sync_from; + char *excluded_tables_str; + struct sset excluded_tables; + + struct json *request_id; /* Id of the outstanding OVSDB request. */ + + struct jsonrpc_session *session; + unsigned int session_seqno; + + enum ovsdb_replication_state state; }; static bool is_replication_possible(struct ovsdb_schema *local_db_schema, struct ovsdb_schema *active_db_schema); +static struct jsonrpc_msg *create_monitor_request(struct replication_db *, + struct ovsdb_schema *); +static void add_monitored_table(struct ovsdb_table_schema *table, + struct json *monitor_requests); + + /* All DBs known to ovsdb-server. The actual replication dbs are stored * in 'replication dbs', which is a subset of all dbs and remote dbs whose * schema matches. */ -static struct shash local_dbs = SHASH_INITIALIZER(&local_dbs); -static struct shash *replication_dbs; +static struct shash replication_dbs = SHASH_INITIALIZER(&replication_dbs); + +static void replication_db_destroy(struct replication_db *); +static struct ovsdb_error *reset_database(struct replication_db *); -static struct shash *replication_dbs_create(void); -static void replication_dbs_destroy(void); /* Find 'struct ovsdb' by name within 'replication_dbs' */ static struct replication_db *find_db(const char *db_name); + +static char *set_excluded_tables(struct replication_db *, const char *excluded) + OVS_WARN_UNUSED_RESULT; + +static void request_id_set(struct replication_db *, const struct json *id); +static void request_id_clear(struct replication_db *); +static bool request_id_compare_and_free(struct replication_db *, + const struct json *id); void -replication_init(const char *sync_from_, const char *exclude_tables, - const struct uuid *server, int probe_interval) +replication_set_db(struct ovsdb *db, const char *sync_from, + const char *exclude_tables, const struct uuid *server, + int probe_interval) { - free(sync_from); - sync_from = xstrdup(sync_from_); - /* Caller should have verified that the 'exclude_tables' is - * parseable. An error here is unexpected. */ - ovs_assert(!set_excluded_tables(exclude_tables, false)); + struct replication_db *rdb = find_db(db->name); - replication_dbs_destroy(); + if (uuid_is_zero(&server_uuid)) { + /* Keep a copy of local server uuid. */ + server_uuid = *server; + } else { + ovs_assert(uuid_equals(&server_uuid, server)); + } + + ovs_assert(sync_from); + + if (rdb + && nullable_string_is_equal(rdb->excluded_tables_str, exclude_tables) + && nullable_string_is_equal(rdb->sync_from, sync_from)) { + jsonrpc_session_set_probe_interval(rdb->session, probe_interval); + return; + } - shash_clear(&local_dbs); - if (session) { - jsonrpc_session_close(session); + if (!rdb) { + rdb = xzalloc(sizeof *rdb); + rdb->db = db; + sset_init(&rdb->excluded_tables); + rdb->schema_version_higher = false; + shash_add(&replication_dbs, db->name, rdb); + } else { + replication_db_destroy(rdb); } - session = jsonrpc_session_open(sync_from, true); - session_seqno = UINT_MAX; + rdb->sync_from = xstrdup(sync_from); + rdb->excluded_tables_str = nullable_xstrdup(exclude_tables); + /* Caller should have verified that the 'exclude_tables' is + * parseable. An error here is unexpected. */ + ovs_assert(!set_excluded_tables(rdb, exclude_tables)); - jsonrpc_session_set_probe_interval(session, probe_interval); + rdb->session = jsonrpc_session_open(rdb->sync_from, true); + rdb->session_seqno = UINT_MAX; - /* Keep a copy of local server uuid. */ - server_uuid = *server; + jsonrpc_session_set_probe_interval(rdb->session, probe_interval); - state = RPL_S_INIT; + rdb->state = RPL_S_INIT; } void -replication_add_local_db(const char *database, struct ovsdb *db) +replication_remove_db(const struct ovsdb *db) { - shash_add_assert(&local_dbs, database, db); + struct replication_db *rdb; + + rdb = shash_find_and_delete(&replication_dbs, db->name); + if (rdb) { + replication_db_destroy(rdb); + free(rdb); + } } -static void -send_schema_requests(const struct json *result) +static bool +json_array_contains_string(const struct json *js, const char *str) { - for (size_t i = 0; i < result->array.n; i++) { - const struct json *name = result->array.elems[i]; - if (name->type == JSON_STRING) { - /* Send one schema request for each remote DB. */ - const char *db_name = json_string(name); - struct replication_db *rdb = find_db(db_name); - if (rdb) { - struct jsonrpc_msg *request = - jsonrpc_create_request( - "get_schema", - json_array_create_1( - json_string_create(db_name)), - NULL); - - request_ids_add(request->id, rdb->db); - jsonrpc_session_send(session, request); - } + bool found = false; + + for (size_t i = 0; i < js->array.n; i++) { + const struct json *elem = js->array.elems[i]; + + if (elem->type == JSON_STRING && !strcmp(json_string(elem), str)) { + found = true; + break; } } + return found; } -void -replication_run(void) +static void +send_schema_request(struct replication_db *rdb) +{ + struct jsonrpc_msg *request = + jsonrpc_create_request( + "get_schema", + json_array_create_1(json_string_create(rdb->db->name)), + NULL); + + request_id_set(rdb, request->id); + jsonrpc_session_send(rdb->session, request); +} + +static void +replication_run_db(struct replication_db *rdb) { - if (!session) { + if (!rdb->session) { return; } - jsonrpc_session_run(session); + jsonrpc_session_run(rdb->session); - for (int i = 0; jsonrpc_session_is_connected(session) && i < 50; i++) { + for (int i = 0; i < 50; i++) { struct jsonrpc_msg *msg; unsigned int seqno; - seqno = jsonrpc_session_get_seqno(session); - if (seqno != session_seqno || state == RPL_S_INIT) { - session_seqno = seqno; - request_ids_clear(); + if (!jsonrpc_session_is_connected(rdb->session)) { + break; + } + + seqno = jsonrpc_session_get_seqno(rdb->session); + if (seqno != rdb->session_seqno || rdb->state == RPL_S_INIT) { + rdb->session_seqno = seqno; + request_id_clear(rdb); + struct jsonrpc_msg *request; request = jsonrpc_create_request("get_server_id", json_array_create_empty(), NULL); - request_ids_add(request->id, NULL); - jsonrpc_session_send(session, request); + request_id_set(rdb, request->id); + jsonrpc_session_send(rdb->session, request); - state = RPL_S_SERVER_ID_REQUESTED; - VLOG_DBG("send server ID request."); + rdb->state = RPL_S_SERVER_ID_REQUESTED; + VLOG_DBG("%s: send server ID request.", rdb->db->name); } - msg = jsonrpc_session_recv(session); + msg = jsonrpc_session_recv(rdb->session); if (!msg) { continue; } - if (msg->type == JSONRPC_NOTIFY && state != RPL_S_ERR + if (msg->type == JSONRPC_NOTIFY && rdb->state != RPL_S_ERR && !strcmp(msg->method, "update")) { if (msg->params->type == JSON_ARRAY && msg->params->array.n == 2 && msg->params->array.elems[0]->type == JSON_STRING) { char *db_name = msg->params->array.elems[0]->string; - struct replication_db *rdb = find_db(db_name); - if (rdb) { + + if (!strcmp(db_name, rdb->db->name)) { struct ovsdb_error *error; error = process_notification(msg->params->array.elems[1], rdb->db); if (error) { ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; } + } else { + VLOG_WARN("%s: received update for unexpected database %s", + rdb->db->name, db_name); + rdb->state = RPL_S_ERR; } } } else if (msg->type == JSONRPC_REPLY) { - struct replication_db *rdb; - struct ovsdb *db; - if (!request_ids_lookup_and_free(msg->id, &db)) { - VLOG_WARN("received unexpected reply"); + if (!request_id_compare_and_free(rdb, msg->id)) { + VLOG_WARN("%s: received unexpected reply.", rdb->db->name); goto next; } - switch (state) { + switch (rdb->state) { case RPL_S_SERVER_ID_REQUESTED: { struct uuid uuid; if (msg->result->type != JSON_STRING || !uuid_from_string(&uuid, json_string(msg->result))) { struct ovsdb_error *error; error = ovsdb_error("get_server_id failed", - "Server ID is not valid UUID"); + "%s: Server ID is not valid UUID", + rdb->db->name); ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; break; } if (uuid_equals(&uuid, &server_uuid)) { struct ovsdb_error *error; error = ovsdb_error("Server ID check failed", - "Self replicating is not allowed"); + "%s: Self replicating is not allowed", + rdb->db->name); ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; break; } @@ -254,25 +287,32 @@ replication_run(void) request = jsonrpc_create_request("list_dbs", json_array_create_empty(), NULL); - request_ids_add(request->id, NULL); - jsonrpc_session_send(session, request); + request_id_set(rdb, request->id); + jsonrpc_session_send(rdb->session, request); - replication_dbs_destroy(); - replication_dbs = replication_dbs_create(); - state = RPL_S_DB_REQUESTED; + rdb->state = RPL_S_DB_REQUESTED; break; } case RPL_S_DB_REQUESTED: if (msg->result->type != JSON_ARRAY) { struct ovsdb_error *error; error = ovsdb_error("list_dbs failed", - "list_dbs response is not array"); + "%s: list_dbs response is not array", + rdb->db->name); + ovsdb_error_assert(error); + rdb->state = RPL_S_ERR; + } else if (!json_array_contains_string(msg->result, + rdb->db->name)) { + struct ovsdb_error *error; + error = ovsdb_error("list_dbs failed", + "%s: database name is not in the list", + rdb->db->name); ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; } else { - send_schema_requests(msg->result); - VLOG_DBG("Send schema requests"); - state = RPL_S_SCHEMA_REQUESTED; + send_schema_request(rdb); + VLOG_DBG("%s: send schema request.", rdb->db->name); + rdb->state = RPL_S_SCHEMA_REQUESTED; } break; @@ -283,19 +323,22 @@ replication_run(void) error = ovsdb_schema_from_json(msg->result, &schema); if (error) { ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; + break; } - rdb = find_db(schema->name); - if (!rdb) { + if (strcmp(rdb->db->name, schema->name)) { /* Unexpected schema. */ - VLOG_WARN("unexpected schema %s", schema->name); - state = RPL_S_ERR; + VLOG_WARN("%s: unexpected schema %s.", + rdb->db->name, schema->name); + rdb->state = RPL_S_ERR; + ovsdb_schema_destroy(schema); + break; } else if (!ovsdb_schema_equal(schema, rdb->db->schema)) { /* Schmea version mismatch. */ - VLOG_INFO("Schema version mismatch, checking if %s can " - "still be replicated or not.", - schema->name); + VLOG_INFO("%s: Schema version mismatch, checking if %s can" + " still be replicated or not.", + rdb->db->name, schema->name); if (is_replication_possible(rdb->db->schema, schema)) { VLOG_INFO("%s can be replicated.", schema->name); rdb->schema_version_higher = true; @@ -305,68 +348,48 @@ replication_run(void) rdb->active_db_schema = schema; } else { VLOG_INFO("%s cannot be replicated.", schema->name); - struct replication_db *r = - shash_find_and_delete(replication_dbs, - schema->name); - if (r->active_db_schema) { - ovsdb_schema_destroy(r->active_db_schema); - } - free(r); + rdb->state = RPL_S_ERR; ovsdb_schema_destroy(schema); + break; } } else { ovsdb_schema_destroy(schema); } - /* After receiving schemas, reset the local databases that - * will be monitored and send out monitor requests for them. */ - if (hmap_is_empty(&request_ids)) { - struct shash_node *node; - - if (shash_is_empty(replication_dbs)) { - VLOG_WARN("Nothing to replicate."); - state = RPL_S_ERR; - } else { - SHASH_FOR_EACH (node, replication_dbs) { - rdb = node->data; - struct jsonrpc_msg *request = - create_monitor_request( - rdb->schema_version_higher ? - rdb->active_db_schema : rdb->db->schema); - - request_ids_add(request->id, rdb->db); - jsonrpc_session_send(session, request); - VLOG_DBG("Send monitor requests"); - state = RPL_S_MONITOR_REQUESTED; - } - } - } + /* Send out a monitor request. */ + struct jsonrpc_msg *request = + create_monitor_request(rdb, rdb->schema_version_higher + ? rdb->active_db_schema + : rdb->db->schema); + + request_id_set(rdb, request->id); + jsonrpc_session_send(rdb->session, request); + VLOG_DBG("%s: send monitor request.", rdb->db->name); + rdb->state = RPL_S_MONITOR_REQUESTED; break; } case RPL_S_MONITOR_REQUESTED: { /* Reply to monitor requests. */ struct ovsdb_error *error; - VLOG_INFO("Monitor request received. Resetting the database"); + VLOG_INFO("%s: Monitor reply received. " + "Resetting the database.", rdb->db->name); /* Resetting the database here has few risks. If the * process_notification() fails, the database is completely * lost locally. In case that node becomes active, then * there is a chance of complete data loss in the active/standy * cluster. */ - error = reset_database(db); + error = reset_database(rdb); if (!error) { - error = process_notification(msg->result, db); + error = process_notification(msg->result, rdb->db); } if (error) { ovsdb_error_assert(error); - state = RPL_S_ERR; + rdb->state = RPL_S_ERR; } else { - /* Transition to replicating state after receiving - * all replies of "monitor" requests. */ - if (hmap_is_empty(&request_ids)) { - VLOG_DBG("Listening to monitor updates"); - state = RPL_S_REPLICATING; - } + VLOG_DBG("%s: Listening to monitor updates.", + rdb->db->name); + rdb->state = RPL_S_REPLICATING; } break; } @@ -378,7 +401,7 @@ replication_run(void) case RPL_S_INIT: case RPL_S_REPLICATING: default: - OVS_NOT_REACHED(); + VLOG_WARN("%s: received unexpected reply.", rdb->db->name); } } next: @@ -386,24 +409,40 @@ replication_run(void) } } +void +replication_run(void) +{ + struct shash_node *node; + + SHASH_FOR_EACH (node, &replication_dbs) { + replication_run_db(node->data); + } +} + void replication_wait(void) { - if (session) { - jsonrpc_session_wait(session); - jsonrpc_session_recv_wait(session); + struct shash_node *node; + + SHASH_FOR_EACH (node, &replication_dbs) { + struct replication_db *rdb = node->data; + + if (rdb->session) { + jsonrpc_session_wait(rdb->session); + jsonrpc_session_recv_wait(rdb->session); + } } } -/* Parse 'excluded' to rebuild 'excluded_tables'. If 'dryrun' is false, the - * current set of excluded tables will be wiped out, regardless of whether - * 'excluded' can be parsed. If 'dryrun' is true, only parses 'excluded' and +/* Parse 'excluded' to rebuild 'rdb->excluded_tables'. If 'rdb' is not NULL, + * the current set of excluded tables will be wiped out, regardless of whether + * 'excluded' can be parsed. If 'rdb' is NULL, only parses 'excluded' and * reports any errors, without modifying the list of exclusions. * - * On error, returns the error string, which the caller is - * responsible for freeing. Returns NULL otherwise. */ -char * OVS_WARN_UNUSED_RESULT -set_excluded_tables(const char *excluded, bool dryrun) + * On error, returns the error string, which the caller is responsible for + * freeing. Returns NULL otherwise. */ +static char * OVS_WARN_UNUSED_RESULT +set_excluded_tables__(struct replication_db *rdb, const char *excluded) { struct sset set = SSET_INITIALIZER(&set); char *err = NULL; @@ -411,17 +450,22 @@ set_excluded_tables(const char *excluded, bool dryrun) if (excluded) { const char *longname; - if (!dryrun) { - /* Can only add to an empty shash. */ - excluded_tables_clear(); + if (rdb) { + /* Can only add to an empty set. */ + sset_clear(&rdb->excluded_tables); } sset_from_delimited_string(&set, excluded, " ,"); SSET_FOR_EACH (longname, &set) { + if (rdb && !strchr(longname, ':')) { + sset_add(&rdb->excluded_tables, longname); + continue; + } + char *database = xstrdup(longname), *table = NULL; strtok_r(database, ":", &table); - if (table && !dryrun) { - excluded_tables_add(database, table); + if (table && rdb && !strcmp(rdb->db->name, database)) { + sset_add(&rdb->excluded_tables, table); } free(database); @@ -434,120 +478,74 @@ set_excluded_tables(const char *excluded, bool dryrun) done: sset_destroy(&set); - if (err && !dryrun) { + if (err && rdb) { /* On error, destroy the partially built 'excluded_tables'. */ - excluded_tables_clear(); + sset_clear(&rdb->excluded_tables); } return err; } char * OVS_WARN_UNUSED_RESULT -get_excluded_tables(void) +parse_excluded_tables(const char *excluded) { - struct shash_node *node; - struct sset set = SSET_INITIALIZER(&set); - - SHASH_FOR_EACH (node, &excluded_tables) { - const char *database = node->name; - const char *table; - struct sset *tables = node->data; - - SSET_FOR_EACH (table, tables) { - sset_add_and_free(&set, xasprintf("%s:%s", database, table)); - } - } - - /* Output the table list in an sorted order, so that - * the output string will not depend on the hash function - * that used to implement the hmap data structure. This is - * only useful for writting unit tests. */ - const char **sorted = sset_sort(&set); - struct ds ds = DS_EMPTY_INITIALIZER; - size_t i; - for (i = 0; i < sset_count(&set); i++) { - ds_put_format(&ds, "%s,", sorted[i]); - } - - ds_chomp(&ds, ','); - - free(sorted); - sset_destroy(&set); - - return ds_steal_cstr(&ds); + return set_excluded_tables__(NULL, excluded); } -static void -excluded_tables_clear(void) +static char * OVS_WARN_UNUSED_RESULT +set_excluded_tables(struct replication_db *rdb, const char *excluded) { - struct shash_node *node; - SHASH_FOR_EACH (node, &excluded_tables) { - struct sset *tables = node->data; - sset_destroy(tables); - } - - shash_clear_free_data(&excluded_tables); + return set_excluded_tables__(rdb, excluded); } -static void -excluded_tables_add(const char *database, const char *table) +char * OVS_WARN_UNUSED_RESULT +get_excluded_tables(const struct ovsdb *db) { - struct sset *tables = shash_find_data(&excluded_tables, database); + const struct replication_db *rdb = find_db(db->name); - if (!tables) { - tables = xmalloc(sizeof *tables); - sset_init(tables); - shash_add(&excluded_tables, database, tables); + if (!rdb) { + return xstrdup(""); } - sset_add(tables, table); -} + struct sset set = SSET_INITIALIZER(&set); + const char *table; + char *result; -static bool -excluded_tables_find(const char *database, const char *table) -{ - struct sset *tables = shash_find_data(&excluded_tables, database); - return tables && sset_contains(tables, table); -} + SSET_FOR_EACH (table, &rdb->excluded_tables) { + sset_add_and_free(&set, xasprintf("%s:%s", rdb->db->name, table)); + } -void -disconnect_active_server(void) -{ - jsonrpc_session_close(session); - session = NULL; + result = sset_join(&set, ",", ""); + sset_destroy(&set); + + return result; } void replication_destroy(void) { - excluded_tables_clear(); - shash_destroy(&excluded_tables); + struct shash_node *node; - if (sync_from) { - free(sync_from); - sync_from = NULL; + SHASH_FOR_EACH (node, &replication_dbs) { + replication_db_destroy(node->data); } - - request_ids_destroy(); - replication_dbs_destroy(); - - shash_destroy(&local_dbs); + shash_destroy_free_data(&replication_dbs); } static struct replication_db * find_db(const char *db_name) { - return shash_find_data(replication_dbs, db_name); + return shash_find_data(&replication_dbs, db_name); } static struct ovsdb_error * -reset_database(struct ovsdb *db) +reset_database(struct replication_db *rdb) { - struct ovsdb_txn *txn = ovsdb_txn_create(db); + struct ovsdb_txn *txn = ovsdb_txn_create(rdb->db); struct shash_node *table_node; - SHASH_FOR_EACH (table_node, &db->tables) { + SHASH_FOR_EACH (table_node, &rdb->db->tables) { /* Delete all rows if the table is not excluded. */ - if (!excluded_tables_find(db->schema->name, table_node->name)) { + if (!sset_contains(&rdb->excluded_tables, table_node->name)) { struct ovsdb_table *table = table_node->data; struct ovsdb_row *row; HMAP_FOR_EACH_SAFE (row, hmap_node, &table->rows) { @@ -565,7 +563,7 @@ reset_database(struct ovsdb *db) * Caller is responsible for disposing 'request'. */ static struct jsonrpc_msg * -create_monitor_request(struct ovsdb_schema *schema) +create_monitor_request(struct replication_db *rdb, struct ovsdb_schema *schema) { struct jsonrpc_msg *request; struct json *monitor; @@ -579,7 +577,7 @@ create_monitor_request(struct ovsdb_schema *schema) struct ovsdb_table_schema *table = nodes[j]->data; /* Monitor all tables not excluded. */ - if (!excluded_tables_find(db_name, table->name)) { + if (!sset_contains(&rdb->excluded_tables, table->name)) { add_monitored_table(table, monitor_request); } } @@ -689,114 +687,76 @@ process_table_update(struct json *table_update, const char *table_name, return NULL; } -void -request_ids_add(const struct json *id, struct ovsdb *db) +static void +request_id_set(struct replication_db *rdb, const struct json *id) { - struct request_ids_hmap_node *node = xmalloc(sizeof *node); + ovs_assert(!rdb->request_id); + rdb->request_id = json_clone(id); +} - node->request_id = json_clone(id); - node->db = db; - hmap_insert(&request_ids, &node->hmap, json_hash(id, 0)); +static void +request_id_clear(struct replication_db *rdb) +{ + json_destroy(rdb->request_id); + rdb->request_id = NULL; } -/* Look up 'id' from 'request_ids', if found, remove the found id from - * 'request_ids' and free its memory. If not found, 'request_ids' does - * not change. Sets '*db' to the database for the request (NULL if not - * found). +/* Compare 'id' with sent 'request_id'. If it mtches, clear the current + * 'request_id'. If it doesn't match, 'request_id' does not change. * - * Return true if 'id' is found, false otherwise. + * Return true if 'id' matches, false otherwise. */ -bool -request_ids_lookup_and_free(const struct json *id, struct ovsdb **db) +static bool +request_id_compare_and_free(struct replication_db *rdb, const struct json *id) { - struct request_ids_hmap_node *node; - - HMAP_FOR_EACH_WITH_HASH (node, hmap, json_hash(id, 0), &request_ids) { - if (json_equal(id, node->request_id)) { - hmap_remove(&request_ids, &node->hmap); - *db = node->db; - json_destroy(node->request_id); - free(node); - return true; - } + if (rdb->request_id && json_equal(id, rdb->request_id)) { + request_id_clear(rdb); + return true; } - - *db = NULL; return false; } static void -request_ids_destroy(void) +replication_db_destroy(struct replication_db *rdb) { - struct request_ids_hmap_node *node; - - HMAP_FOR_EACH_POP (node, hmap, &request_ids) { - json_destroy(node->request_id); - free(node); + if (!rdb) { + return; } - hmap_destroy(&request_ids); -} -void -request_ids_clear(void) -{ - request_ids_destroy(); - hmap_init(&request_ids); -} + free(rdb->sync_from); + rdb->sync_from = NULL; -static struct shash * -replication_dbs_create(void) -{ - struct shash *new = xmalloc(sizeof *new); - shash_init(new); + free(rdb->excluded_tables_str); + rdb->excluded_tables_str = NULL; + sset_destroy(&rdb->excluded_tables); - struct shash_node *node; - SHASH_FOR_EACH (node, &local_dbs) { - struct replication_db *repl_db = xmalloc(sizeof *repl_db); - repl_db->db = node->data; - repl_db->schema_version_higher = false; - repl_db->active_db_schema = NULL; - shash_add(new, node->name, repl_db); - } + request_id_clear(rdb); - return new; -} - -static void -replication_dbs_destroy(void) -{ - if (!replication_dbs) { - return; + if (rdb->session) { + jsonrpc_session_close(rdb->session); + rdb->session = NULL; } - struct shash_node *node; - - SHASH_FOR_EACH_SAFE (node, replication_dbs) { - hmap_remove(&replication_dbs->map, &node->node); - struct replication_db *rdb = node->data; - if (rdb->active_db_schema) { - ovsdb_schema_destroy(rdb->active_db_schema); - } - free(rdb); - free(node->name); - free(node); + if (rdb->active_db_schema) { + ovsdb_schema_destroy(rdb->active_db_schema); + rdb->active_db_schema = NULL; } - hmap_destroy(&replication_dbs->map); - free(replication_dbs); - replication_dbs = NULL; + rdb->schema_version_higher = false; } /* Return true if replication just started or is ongoing. * Return false if the connection failed, or the replication * was not able to start. */ bool -replication_is_alive(void) +replication_is_alive(const struct ovsdb *db) { - if (session) { - return jsonrpc_session_is_alive(session) && state != RPL_S_ERR; + const struct replication_db *rdb = find_db(db->name); + + if (!rdb || !rdb->session) { + return false; } - return false; + return jsonrpc_session_is_alive(rdb->session) && rdb->state != RPL_S_ERR; } /* Return the last error reported on a connection by 'session'. The @@ -806,60 +766,60 @@ replication_is_alive(void) * Return a negative value if replication session has error, or the * replication was not able to start. */ int -replication_get_last_error(void) +replication_get_last_error(const struct ovsdb *db) { + const struct replication_db *rdb = find_db(db->name); int err = 0; - if (session) { - err = jsonrpc_session_get_last_error(session); + if (rdb && rdb->session) { + err = jsonrpc_session_get_last_error(rdb->session); if (!err) { - err = (state == RPL_S_ERR) ? ENOENT : 0; + err = (rdb->state == RPL_S_ERR) ? ENOENT : 0; } } return err; } -char * -replication_status(void) +char * OVS_WARN_UNUSED_RESULT +replication_status(const struct ovsdb *db) { - bool alive = session && jsonrpc_session_is_alive(session); + const struct replication_db *rdb = find_db(db->name); + + if (!rdb) { + return xasprintf("%s is not configured for replication", db->name); + } + + bool alive = rdb->session && jsonrpc_session_is_alive(rdb->session); struct ds ds = DS_EMPTY_INITIALIZER; + ds_put_format(&ds, "database: %s\n", db->name); if (alive) { - switch(state) { + switch (rdb->state) { case RPL_S_INIT: case RPL_S_SERVER_ID_REQUESTED: case RPL_S_DB_REQUESTED: case RPL_S_SCHEMA_REQUESTED: case RPL_S_MONITOR_REQUESTED: - ds_put_format(&ds, "connecting: %s", sync_from); + ds_put_format(&ds, "connecting: %s", rdb->sync_from); break; case RPL_S_REPLICATING: { - struct shash_node *node; - - ds_put_format(&ds, "replicating: %s\n", sync_from); - ds_put_cstr(&ds, "database:"); - SHASH_FOR_EACH (node, replication_dbs) { - ds_put_format(&ds, " %s,", node->name); - } - ds_chomp(&ds, ','); + ds_put_format(&ds, "replicating: %s\n", rdb->sync_from); - if (!shash_is_empty(&excluded_tables)) { - ds_put_char(&ds, '\n'); + if (!sset_is_empty(&rdb->excluded_tables)) { ds_put_cstr(&ds, "exclude: "); - ds_put_and_free_cstr(&ds, get_excluded_tables()); + ds_put_and_free_cstr(&ds, get_excluded_tables(db)); } break; } case RPL_S_ERR: - ds_put_format(&ds, "Replication to (%s) failed\n", sync_from); + ds_put_format(&ds, "Replication to (%s) failed", rdb->sync_from); break; default: OVS_NOT_REACHED(); } } else { - ds_put_format(&ds, "not connected to %s", sync_from); + ds_put_format(&ds, "not connected to %s", rdb->sync_from); } return ds_steal_cstr(&ds); } @@ -913,10 +873,12 @@ is_replication_possible(struct ovsdb_schema *local_db_schema, } void -replication_set_probe_interval(int probe_interval) +replication_set_probe_interval(const struct ovsdb *db, int probe_interval) { - if (session) { - jsonrpc_session_set_probe_interval(session, probe_interval); + const struct replication_db *rdb = find_db(db->name); + + if (rdb && rdb->session) { + jsonrpc_session_set_probe_interval(rdb->session, probe_interval); } } diff --git a/ovsdb/replication.h b/ovsdb/replication.h index 6d1be820f..f5e226753 100644 --- a/ovsdb/replication.h +++ b/ovsdb/replication.h @@ -26,41 +26,41 @@ struct ovsdb; * API Usage *=========== * - * - replication_init() needs to be called whenever OVSDB server switches into + * - replication_set_db() needs to be called whenever database switches into * the backup mode. * - * - replication_add_local_db() should be called immediately after to add all - * known database that OVSDB server owns, one at a time. + * - replication_remove_db() needs to be called whenever backup database + * switches into an active mode. * * - replication_destroy() should be called when OVSDB server shutdown to * reclaim resources. * * - replication_run(), replication_wait(), replication_is_alive() and * replication_get_last_error() should be call within the main loop - * whenever OVSDB server runs in the backup mode. + * whenever OVSDB has backup databases. * - * - set_excluded_tables(), get_excluded_tables(), disconnect_active_server() - * and replication_usage() are support functions used mainly by unixctl - * commands. + * - parse_excluded_tables(), get_excluded_tables() and replication_usage() + * are support functions used mainly by unixctl commands. */ #define REPLICATION_DEFAULT_PROBE_INTERVAL 60000 -void replication_init(const char *sync_from, const char *exclude_tables, - const struct uuid *server, int probe_interval); +void replication_set_db(struct ovsdb *, const char *sync_from, + const char *exclude_tables, const struct uuid *server, + int probe_interval); +void replication_remove_db(const struct ovsdb *); + void replication_run(void); void replication_wait(void); void replication_destroy(void); void replication_usage(void); -void replication_add_local_db(const char *databse, struct ovsdb *db); -bool replication_is_alive(void); -int replication_get_last_error(void); -char *replication_status(void); -void replication_set_probe_interval(int); +bool replication_is_alive(const struct ovsdb *); +int replication_get_last_error(const struct ovsdb *); +char *replication_status(const struct ovsdb *); +void replication_set_probe_interval(const struct ovsdb *, int probe_interval); -char *set_excluded_tables(const char *excluded, bool dryrun) - OVS_WARN_UNUSED_RESULT; -char *get_excluded_tables(void) OVS_WARN_UNUSED_RESULT; -void disconnect_active_server(void); +char *parse_excluded_tables(const char *excluded) OVS_WARN_UNUSED_RESULT; +char *get_excluded_tables(const struct ovsdb *) OVS_WARN_UNUSED_RESULT; +void disconnect_active_server(const struct ovsdb *); #endif /* ovsdb/replication.h */ From patchwork Thu Dec 14 01:04:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875925 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDgz60DMz1ySd for ; Thu, 14 Dec 2023 12:06:23 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 14310420F2; Thu, 14 Dec 2023 01:06:22 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 14310420F2 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 b-67R6aSyegj; Thu, 14 Dec 2023 01:06:21 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id 5BE0041E79; Thu, 14 Dec 2023 01:06:20 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5BE0041E79 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 260C9C0072; Thu, 14 Dec 2023 01:06:20 +0000 (UTC) X-Original-To: ovs-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 8DADDC0037 for ; Thu, 14 Dec 2023 01:06:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id F0B6B61B06 for ; Thu, 14 Dec 2023 01:05:12 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org F0B6B61B06 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id P_B3IBm7kxP8 for ; Thu, 14 Dec 2023 01:05:12 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp3.osuosl.org (Postfix) with ESMTPS id 3034060F2C for ; Thu, 14 Dec 2023 01:05:11 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 3034060F2C Received: by mail.gandi.net (Postfix) with ESMTPSA id 07D1F240002; Thu, 14 Dec 2023 01:05:09 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:13 +0100 Message-ID: <20231214010431.1664005-12-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 11/22] ovsdb: replication: Automatically switch read-only mode. 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 database is added to the replication, it should no longer accept transactions that can modify it. When it's removed from the replication, it should be writable again. Add this logic to the replication module itself, so it can be removed from the main ovsdb-server later. Signed-off-by: Ilya Maximets --- ovsdb/replication.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ovsdb/replication.c b/ovsdb/replication.c index d0d48aad5..3c59d4039 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -150,6 +150,7 @@ replication_set_db(struct ovsdb *db, const char *sync_from, jsonrpc_session_set_probe_interval(rdb->session, probe_interval); rdb->state = RPL_S_INIT; + rdb->db->read_only = true; } void @@ -743,6 +744,7 @@ replication_db_destroy(struct replication_db *rdb) } rdb->schema_version_higher = false; + rdb->db->read_only = false; } /* Return true if replication just started or is ongoing. From patchwork Thu Dec 14 01:04:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875927 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhL3hgSz1ySd for ; Thu, 14 Dec 2023 12:06:42 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 906614370A; Thu, 14 Dec 2023 01:06:40 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 906614370A 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 uUUjU27UK3pg; Thu, 14 Dec 2023 01:06:33 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 2E5E043748; Thu, 14 Dec 2023 01:06:32 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 2E5E043748 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 216EFC0DDB; Thu, 14 Dec 2023 01:06:31 +0000 (UTC) X-Original-To: ovs-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 30F73C0DCF for ; Thu, 14 Dec 2023 01:06:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 8D04283367 for ; Thu, 14 Dec 2023 01:05:19 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8D04283367 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 7DPTxwrwaYzB for ; Thu, 14 Dec 2023 01:05:16 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp1.osuosl.org (Postfix) with ESMTPS id 20F678316A for ; Thu, 14 Dec 2023 01:05:15 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 20F678316A Received: by mail.gandi.net (Postfix) with ESMTPSA id BDDEE240002; Thu, 14 Dec 2023 01:05:13 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:14 +0100 Message-ID: <20231214010431.1664005-13-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 12/22] ovsdb-server: Database config isolation. 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 a new structure 'db_config' that holds the user-provided configuration of the database. And attach this configuration to each of the databases on the server. Each database has a service model: standalone, clustered, relay or active-backup. Relays and A-B databases have a source, each source has its own set of JSON-RPC session options. A-B also have an indicator of it being active or backup and an optional list of tables to exclude from replication. All of that should be stored per database in the temporary configuration file that is used in order to restore the config after the OVSDB crash. For that, the save/load functions are also updates. This change is written in generic way assuming all the databases can have different configuration including service model. The only user-visible change here is a slight modification of the ovsdb-server/sync-status appctl, since it now needs to skip databases that are not active-backup and also should report active-backup databases that are currently active, i.e. not added to the replication module. If the service model is not defined in the configuration, it is assumed to be standalone or clustered, and determined from the storage type while opening the database. Since the database 'source' connections can't use 'role' or 'read-only' options, a new flag added to corresponding JSON parsing functions to skip these fields. Signed-off-by: Ilya Maximets --- ovsdb/jsonrpc-server.c | 31 +- ovsdb/jsonrpc-server.h | 5 +- ovsdb/ovsdb-server.c | 775 +++++++++++++++++++++++++++++++---------- ovsdb/replication.c | 1 - tests/ovsdb-server.at | 8 +- 5 files changed, 623 insertions(+), 197 deletions(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 299afbb1d..81e9e48a0 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -231,7 +231,8 @@ ovsdb_jsonrpc_options_clone(const struct ovsdb_jsonrpc_options *options) } struct json * -ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options) +ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options, + bool jsonrpc_session_only) { struct json *json = json_object_create(); @@ -239,9 +240,15 @@ ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options) json_integer_create(options->max_backoff)); json_object_put(json, "inactivity-probe", json_integer_create(options->probe_interval)); + json_object_put(json, "dscp", json_integer_create(options->dscp)); + + if (jsonrpc_session_only) { + /* Caller is not interested in OVSDB-specific options. */ + return json; + } + json_object_put(json, "read-only", json_boolean_create(options->read_only)); - json_object_put(json, "dscp", json_integer_create(options->dscp)); if (options->role) { json_object_put(json, "role", json_string_create(options->role)); } @@ -251,7 +258,8 @@ ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options) void ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *options, - const struct json *json) + const struct json *json, + bool jsonrpc_session_only) { const struct json *max_backoff, *probe_interval, *read_only, *dscp, *role; struct ovsdb_parser parser; @@ -271,22 +279,29 @@ ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *options, options->probe_interval = json_integer(probe_interval); } + dscp = ovsdb_parser_member(&parser, "dscp", OP_INTEGER | OP_OPTIONAL); + if (dscp) { + options->dscp = json_integer(dscp); + } + + if (jsonrpc_session_only) { + /* Caller is not interested to OVSDB-specific options. */ + goto exit; + } + read_only = ovsdb_parser_member(&parser, "read-only", OP_BOOLEAN | OP_OPTIONAL); if (read_only) { options->read_only = json_boolean(read_only); } - dscp = ovsdb_parser_member(&parser, "dscp", OP_INTEGER | OP_OPTIONAL); - if (dscp) { - options->dscp = json_integer(dscp); - } - role = ovsdb_parser_member(&parser, "role", OP_STRING | OP_OPTIONAL); if (role) { + free(options->role); options->role = nullable_xstrdup(json_string(role)); } +exit: error = ovsdb_parser_finish(&parser); if (error) { char *s = ovsdb_error_to_string_free(error); diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index 39366ad70..0d8f87da7 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -45,10 +45,11 @@ struct ovsdb_jsonrpc_options *ovsdb_jsonrpc_options_clone( const struct ovsdb_jsonrpc_options *); struct json *ovsdb_jsonrpc_options_to_json( - const struct ovsdb_jsonrpc_options *) + const struct ovsdb_jsonrpc_options *, bool jsonrpc_session_only) OVS_WARN_UNUSED_RESULT; void ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *, - const struct json *); + const struct json *, + bool jsonrpc_session_only); void ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *, const struct shash *); diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 9a3b0add1..d7a823220 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -42,6 +42,7 @@ #include "ovsdb-data.h" #include "ovsdb-types.h" #include "ovsdb-error.h" +#include "ovsdb-parser.h" #include "openvswitch/poll-loop.h" #include "process.h" #include "replication.h" @@ -65,12 +66,6 @@ VLOG_DEFINE_THIS_MODULE(ovsdb_server); -struct db { - char *filename; - struct ovsdb *db; - struct uuid row_uuid; -}; - /* SSL configuration. */ static char *private_key_file; static char *certificate_file; @@ -100,16 +95,79 @@ static unixctl_cb_func ovsdb_server_get_sync_exclude_tables; static unixctl_cb_func ovsdb_server_get_sync_status; static unixctl_cb_func ovsdb_server_get_db_storage_status; +#define SERVICE_MODELS \ + SERVICE_MODEL(UNDEFINED, undefined) \ + SERVICE_MODEL(STANDALONE, standalone) \ + SERVICE_MODEL(CLUSTERED, clustered) \ + SERVICE_MODEL(ACTIVE_BACKUP, active-backup) \ + SERVICE_MODEL(RELAY, relay) + +enum service_model { +#define SERVICE_MODEL(ENUM, NAME) SM_##ENUM, + SERVICE_MODELS +#undef SERVICE_MODEL +}; + +static const char * +service_model_to_string(enum service_model model) +{ + switch (model) { +#define SERVICE_MODEL(ENUM, NAME) \ + case SM_##ENUM: return #NAME; + SERVICE_MODELS +#undef SERVICE_MODEL + default: OVS_NOT_REACHED(); + } +} + +static enum service_model +service_model_from_string(const char *model) +{ +#define SERVICE_MODEL(ENUM, NAME) \ + if (!strcmp(model, #NAME)) { \ + return SM_##ENUM; \ + } + SERVICE_MODELS +#undef SERVICE_MODEL + + VLOG_WARN("Unrecognized database service model: '%s'", model); + + return SM_UNDEFINED; +} + +struct db_config { + enum service_model model; + char *source; /* sync-from for backup or relay source. */ + struct ovsdb_jsonrpc_options *options; /* For 'source' connection. */ + + /* Configuration specific to SM_ACTIVE_BACKUP. */ + struct { + char *sync_exclude; /* Tables to exclude. */ + bool backup; /* If true, the database is read-only and receives + * updates from the 'source'. */ + } ab; +}; + +struct db { + struct ovsdb *db; + char *filename; + struct db_config *config; + struct uuid row_uuid; +}; + struct server_config { struct shash *remotes; - struct shash *all_dbs; - FILE *config_tmpfile; + struct shash *all_dbs; /* All the currently serviced databases. + * 'struct db' by a schema name. */ + struct ovsdb_jsonrpc_server *jsonrpc; + + /* Command line + appctl configuration. */ char **sync_from; char **sync_exclude; bool *is_backup; int *replication_probe_interval; int *relay_source_probe_interval; - struct ovsdb_jsonrpc_server *jsonrpc; + FILE *config_tmpfile; }; static unixctl_cb_func ovsdb_server_add_remote; static unixctl_cb_func ovsdb_server_remove_remote; @@ -123,14 +181,15 @@ static unixctl_cb_func ovsdb_server_tlog_list; static void read_db(struct server_config *, struct db *); static struct ovsdb_error *open_db(struct server_config *, - const char *filename) + const char *filename, + const struct db_config *) OVS_WARN_UNUSED_RESULT; static void add_server_db(struct server_config *); static void remove_db(struct server_config *, struct shash_node *db, char *); static void close_db(struct server_config *, struct db *, char *); static void parse_options(int argc, char *argvp[], - struct sset *db_filenames, struct shash *remotes, + struct shash *db_conf, struct shash *remotes, char **unixctl_pathp, char **run_command, char **sync_from, char **sync_exclude, bool *is_backup); @@ -153,29 +212,14 @@ static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc, static void update_server_status(struct shash *all_dbs); static void save_config__(FILE *config_file, const struct shash *remotes, - const struct sset *db_filenames, + const struct shash *db_conf, const char *sync_from, const char *sync_exclude, bool is_backup); static void save_config(struct server_config *); static void load_config(FILE *config_file, struct shash *remotes, - struct sset *db_filenames, char **sync_from, + struct shash *db_conf, char **sync_from, char **sync_exclude, bool *is_backup); -static void -ovsdb_replication_init(const char *sync_from, const char *exclude, - struct shash *all_dbs, const struct uuid *server_uuid, - int probe_interval) -{ - struct shash_node *node; - SHASH_FOR_EACH (node, all_dbs) { - struct db *db = node->data; - if (node->name[0] != '_' && db->db) { - replication_set_db(db->db, sync_from, exclude, - server_uuid, probe_interval); - } - } -} - static void log_and_free_error(struct ovsdb_error *error) { @@ -186,11 +230,52 @@ log_and_free_error(struct ovsdb_error *error) } } +static void +ovsdb_server_replication_remove_db(struct db *db) +{ + replication_remove_db(db->db); + db->config->ab.backup = false; +} + +static void +ovsdb_server_replication_run(struct server_config *config) +{ + struct shash_node *node; + bool all_alive = true; + + replication_run(); + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + + if (db->config->model == SM_ACTIVE_BACKUP && db->config->ab.backup + && !replication_is_alive(db->db)) { + ovsdb_server_replication_remove_db(db); + all_alive = false; + } + } + + /* If one connection is broken, switch all databases to active, + * since they are configured via the same command line / appctl. */ + if (!all_alive && *config->is_backup) { + *config->is_backup = false; + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + + if (db->config->model == SM_ACTIVE_BACKUP + && db->config->ab.backup) { + ovsdb_server_replication_remove_db(db); + } + } + } +} + static void main_loop(struct server_config *config, struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs, struct unixctl_server *unixctl, struct shash *remotes, - struct process *run_process, bool *exiting, bool *is_backup) + struct process *run_process, bool *exiting) { char *remotes_error, *ssl_error; struct shash_node *node; @@ -220,7 +305,7 @@ main_loop(struct server_config *config, * the set of remotes that reconfigure_remotes() uses. */ unixctl_server_run(unixctl); - ovsdb_jsonrpc_server_set_read_only(jsonrpc, *is_backup); + ovsdb_jsonrpc_server_set_read_only(jsonrpc, false); report_error_if_changed( reconfigure_remotes(jsonrpc, all_dbs, remotes), @@ -228,23 +313,7 @@ main_loop(struct server_config *config, report_error_if_changed(reconfigure_ssl(all_dbs), &ssl_error); ovsdb_jsonrpc_server_run(jsonrpc); - replication_run(); - if (*is_backup) { - SHASH_FOR_EACH (node, all_dbs) { - struct db *db = node->data; - if (db->db->name[0] != '_' && !replication_is_alive(db->db)) { - *is_backup = false; - break; - } - } - if (!*is_backup) { - SHASH_FOR_EACH (node, all_dbs) { - struct db *db = node->data; - replication_remove_db(db->db); - } - } - } - + ovsdb_server_replication_run(config); ovsdb_relay_run(); SHASH_FOR_EACH_SAFE (node, all_dbs) { @@ -351,6 +420,92 @@ parse_relay_args(const char *arg, char **name, char **remote) return true; } +static void +db_config_destroy(struct db_config *conf) +{ + if (!conf) { + return; + } + + free(conf->source); + if (conf->options) { + free(conf->options->role); + free(conf->options); + } + free(conf->ab.sync_exclude); + free(conf); +} + +static struct db_config * +db_config_clone(const struct db_config *c) +{ + struct db_config *conf = xmemdup(c, sizeof *c); + + conf->source = nullable_xstrdup(c->source); + if (c->options) { + conf->options = ovsdb_jsonrpc_options_clone(c->options); + } + conf->ab.sync_exclude = nullable_xstrdup(c->ab.sync_exclude); + + return conf; +} + +static struct ovsdb_jsonrpc_options * +get_jsonrpc_options(const char *target, enum service_model model) +{ + struct ovsdb_jsonrpc_options *options; + + options = ovsdb_jsonrpc_default_options(target); + if (model == SM_ACTIVE_BACKUP) { + options->probe_interval = REPLICATION_DEFAULT_PROBE_INTERVAL; + } else if (model == SM_RELAY) { + options->probe_interval = RELAY_SOURCE_DEFAULT_PROBE_INTERVAL; + } + + return options; +} + +static void +add_database_config(struct shash *db_conf, const char *opt, + const char *sync_from, const char *sync_exclude, + bool active) +{ + struct db_config *conf = xzalloc(sizeof *conf); + char *filename = NULL; + + if (parse_relay_args(opt, &filename, &conf->source)) { + conf->model = SM_RELAY; + conf->options = get_jsonrpc_options(conf->source, conf->model); + } else if (sync_from) { + conf->model = SM_ACTIVE_BACKUP; + conf->source = xstrdup(sync_from); + conf->options = get_jsonrpc_options(conf->source, conf->model); + conf->ab.sync_exclude = nullable_xstrdup(sync_exclude); + conf->ab.backup = !active; + filename = xstrdup(opt); + } else { + conf->model = SM_UNDEFINED; /* We'll update once the file is open. */ + filename = xstrdup(opt); + } + + conf = shash_replace_nocopy(db_conf, filename, conf); + if (conf) { + VLOG_WARN("Duplicate database configuration: %s", filename); + db_config_destroy(conf); + } +} + +static void +free_database_configs(struct shash *db_conf) +{ + struct shash_node *node; + + SHASH_FOR_EACH (node, db_conf) { + db_config_destroy(node->data); + } + shash_clear(db_conf); +} + int main(int argc, char *argv[]) { @@ -358,11 +513,10 @@ main(int argc, char *argv[]) char *run_command = NULL; struct unixctl_server *unixctl; struct ovsdb_jsonrpc_server *jsonrpc; - struct sset db_filenames; + struct shash db_conf; struct shash remotes; char *sync_from, *sync_exclude; bool is_backup; - const char *db_filename; struct process *run_process; bool exiting; int retval; @@ -381,7 +535,7 @@ main(int argc, char *argv[]) dns_resolve_init(true); bool active = false; - parse_options(argc, argv, &db_filenames, &remotes, &unixctl_path, + parse_options(argc, argv, &db_conf, &remotes, &unixctl_path, &run_command, &sync_from, &sync_exclude, &active); is_backup = sync_from && !active; @@ -400,13 +554,15 @@ main(int argc, char *argv[]) server_config.remotes = &remotes; server_config.config_tmpfile = config_tmpfile; - save_config__(config_tmpfile, &remotes, &db_filenames, sync_from, + save_config__(config_tmpfile, &remotes, &db_conf, sync_from, sync_exclude, is_backup); + free_remotes(&remotes); + free_database_configs(&db_conf); daemonize_start(false, false); /* Load the saved config. */ - load_config(config_tmpfile, &remotes, &db_filenames, &sync_from, + load_config(config_tmpfile, &remotes, &db_conf, &sync_from, &sync_exclude, &is_backup); /* Start ovsdb jsonrpc server. When running as a backup server, @@ -425,13 +581,16 @@ main(int argc, char *argv[]) perf_counters_init(); - SSET_FOR_EACH (db_filename, &db_filenames) { - struct ovsdb_error *error = open_db(&server_config, db_filename); + SHASH_FOR_EACH (node, &db_conf) { + struct ovsdb_error *error = open_db(&server_config, + node->name, node->data); if (error) { char *s = ovsdb_error_to_string_free(error); ovs_fatal(0, "%s", s); } + db_config_destroy(node->data); } + shash_clear(&db_conf); add_server_db(&server_config); char *error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes); @@ -538,15 +697,8 @@ main(int argc, char *argv[]) unixctl_command_register("ovsdb-server/disable-monitor-cond", "", 0, 0, ovsdb_server_disable_monitor_cond, jsonrpc); - if (is_backup) { - const struct uuid *server_uuid; - server_uuid = ovsdb_jsonrpc_server_get_uuid(jsonrpc); - ovsdb_replication_init(sync_from, sync_exclude, &all_dbs, server_uuid, - replication_probe_interval); - } - main_loop(&server_config, jsonrpc, &all_dbs, unixctl, &remotes, - run_process, &exiting, &is_backup); + run_process, &exiting); SHASH_FOR_EACH_SAFE (node, &all_dbs) { struct db *db = node->data; @@ -556,7 +708,8 @@ main(int argc, char *argv[]) ovsdb_jsonrpc_server_destroy(jsonrpc); shash_destroy(&all_dbs); free_remotes(&remotes); - sset_destroy(&db_filenames); + free_database_configs(&db_conf); + shash_destroy(&db_conf); free(sync_from); free(sync_exclude); unixctl_server_destroy(unixctl); @@ -580,7 +733,7 @@ main(int argc, char *argv[]) * * "False negatives" are possible. */ static bool -is_already_open(struct server_config *config OVS_UNUSED, +is_already_open(struct server_config *server_config OVS_UNUSED, const char *filename OVS_UNUSED) { #ifndef _WIN32 @@ -589,11 +742,12 @@ is_already_open(struct server_config *config OVS_UNUSED, if (!stat(filename, &s)) { struct shash_node *node; - SHASH_FOR_EACH (node, config->all_dbs) { + SHASH_FOR_EACH (node, server_config->all_dbs) { struct db *db = node->data; struct stat s2; - if (!stat(db->filename, &s2) + if (db->config->model != SM_RELAY + && !stat(db->filename, &s2) && s.st_dev == s2.st_dev && s.st_ino == s2.st_ino) { return true; @@ -606,16 +760,19 @@ is_already_open(struct server_config *config OVS_UNUSED, } static void -close_db(struct server_config *config, struct db *db, char *comment) +close_db(struct server_config *server_config, struct db *db, char *comment) { if (db) { - ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db, comment); - if (db->db->is_relay) { + ovsdb_jsonrpc_server_remove_db(server_config->jsonrpc, + db->db, comment); + if (db->config->model == SM_RELAY) { ovsdb_relay_del_db(db->db); } - if (*config->is_backup) { - replication_remove_db(db->db); + if (db->config->model == SM_ACTIVE_BACKUP + && db->config->ab.backup) { + ovsdb_server_replication_remove_db(db); } + db_config_destroy(db->config); ovsdb_destroy(db->db); free(db->filename); free(db); @@ -768,20 +925,17 @@ add_db(struct server_config *config, struct db *db) } static struct ovsdb_error * OVS_WARN_UNUSED_RESULT -open_db(struct server_config *config, const char *filename) +open_db(struct server_config *server_config, + const char *filename, const struct db_config *conf) { struct ovsdb_storage *storage; - char *relay_remotes = NULL; struct ovsdb_error *error; - bool is_relay; - char *name; - is_relay = parse_relay_args(filename, &name, &relay_remotes); - if (!is_relay) { + if (conf->model != SM_RELAY) { /* If we know that the file is already open, return a good error * message. Otherwise, if the file is open, we'll fail later on with * a harder to interpret file locking error. */ - if (is_already_open(config, filename)) { + if (is_already_open(server_config, filename)) { return ovsdb_error(NULL, "%s: already open", filename); } @@ -789,59 +943,78 @@ open_db(struct server_config *config, const char *filename) if (error) { return error; } - name = xstrdup(filename); } else { - storage = ovsdb_storage_create_unbacked(name); + storage = ovsdb_storage_create_unbacked(filename); + } + + enum service_model model = conf->model; + if (model == SM_UNDEFINED || model == SM_STANDALONE + || model == SM_CLUSTERED) { + /* Check the actual service model from the storage. */ + model = ovsdb_storage_is_clustered(storage) + ? SM_CLUSTERED : SM_STANDALONE; + } + if (conf->model != SM_UNDEFINED && conf->model != model) { + ovsdb_storage_close(storage); + return ovsdb_error(NULL, "%s: database is %s and not %s", + filename, service_model_to_string(model), + service_model_to_string(conf->model)); } struct ovsdb_schema *schema; - if (is_relay || ovsdb_storage_is_clustered(storage)) { + if (model == SM_RELAY || model == SM_CLUSTERED) { schema = NULL; } else { struct json *txn_json; error = ovsdb_storage_read(storage, &schema, &txn_json, NULL); if (error) { ovsdb_storage_close(storage); - free(name); return error; } ovs_assert(schema && !txn_json); } struct db *db = xzalloc(sizeof *db); - db->filename = name; + db->filename = xstrdup(filename); + db->config = db_config_clone(conf); + db->config->model = model; db->db = ovsdb_create(schema, storage); - ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db); + ovsdb_jsonrpc_server_add_db(server_config->jsonrpc, db->db); /* Enable txn history for clustered and relay modes. It is not enabled for * other modes for now, since txn id is available for clustered and relay * modes only. */ - ovsdb_txn_history_init(db->db, - is_relay || ovsdb_storage_is_clustered(storage)); + ovsdb_txn_history_init(db->db, model == SM_RELAY || model == SM_CLUSTERED); - read_db(config, db); + read_db(server_config, db); error = (db->db->name[0] == '_' ? ovsdb_error(NULL, "%s: names beginning with \"_\" are reserved", db->db->name) - : shash_find(config->all_dbs, db->db->name) + : shash_find(server_config->all_dbs, db->db->name) ? ovsdb_error(NULL, "%s: duplicate database name", db->db->name) : NULL); if (error) { char *error_s = ovsdb_error_to_string(error); - close_db(config, db, + close_db(server_config, db, xasprintf("cannot complete opening %s database (%s)", db->db->name, error_s)); free(error_s); return error; } - add_db(config, db); + add_db(server_config, db); + + if (model == SM_RELAY) { + ovsdb_relay_add_db(db->db, conf->source, update_schema, server_config, + conf->options->probe_interval); + } + if (model == SM_ACTIVE_BACKUP && conf->ab.backup) { + const struct uuid *server_uuid; - if (is_relay) { - ovsdb_relay_add_db(db->db, relay_remotes, update_schema, config, - *config->relay_source_probe_interval); - free(relay_remotes); + server_uuid = ovsdb_jsonrpc_server_get_uuid(server_config->jsonrpc); + replication_set_db(db->db, conf->source, conf->ab.sync_exclude, + server_uuid, conf->options->probe_interval); } return NULL; } @@ -865,6 +1038,8 @@ add_server_db(struct server_config *config) /* We don't need txn_history for server_db. */ db->filename = xstrdup(""); + db->config = xzalloc(sizeof *db->config); + db->config->model = SM_UNDEFINED; db->db = ovsdb_create(schema, ovsdb_storage_create_unbacked(NULL)); db->db->read_only = true; @@ -1457,11 +1632,20 @@ ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; + struct shash_node *node; - if (*config->sync_from) { - free(*config->sync_from); - } + free(*config->sync_from); *config->sync_from = xstrdup(argv[1]); + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + + if (db->config->model == SM_ACTIVE_BACKUP) { + free(db->config->source); + db->config->source = xstrdup(argv[1]); + } + } + save_config(config); unixctl_command_reply(conn, NULL); @@ -1485,20 +1669,39 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; + struct shash_node *node; char *msg = NULL; - if ( !*config->sync_from) { + if (!*config->sync_from) { msg = "Unable to connect: active server is not specified.\n"; } else { const struct uuid *server_uuid; server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); - ovsdb_replication_init(*config->sync_from, *config->sync_exclude, - config->all_dbs, server_uuid, - *config->replication_probe_interval); - if (!*config->is_backup) { - *config->is_backup = true; - save_config(config); + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + struct db_config *conf = db->config; + + /* This command also converts standalone databases to AB. */ + if (conf->model == SM_STANDALONE) { + conf->model = SM_ACTIVE_BACKUP; + conf->source = xstrdup(*config->sync_from); + conf->options = ovsdb_jsonrpc_default_options(conf->source); + conf->options->probe_interval = + *config->replication_probe_interval; + conf->ab.sync_exclude = + nullable_xstrdup(*config->sync_exclude); + conf->ab.backup = false; + } + + if (conf->model == SM_ACTIVE_BACKUP && !conf->ab.backup) { + replication_set_db(db->db, conf->source, conf->ab.sync_exclude, + server_uuid, conf->options->probe_interval); + conf->ab.backup = true; + } } + *config->is_backup = true; + save_config(config); } unixctl_command_reply(conn, msg); } @@ -1514,7 +1717,11 @@ ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn, SHASH_FOR_EACH (node, config->all_dbs) { struct db *db = node->data; - replication_remove_db(db->db); + struct db_config *conf = db->config; + + if (conf->model == SM_ACTIVE_BACKUP && conf->ab.backup) { + ovsdb_server_replication_remove_db(db); + } } *config->is_backup = false; save_config(config); @@ -1528,23 +1735,35 @@ ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; - + struct shash_node *node; int probe_interval; - if (str_to_int(argv[1], 10, &probe_interval)) { - *config->replication_probe_interval = probe_interval; - save_config(config); - if (*config->is_backup) { - const struct uuid *server_uuid; - server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); - ovsdb_replication_init(*config->sync_from, *config->sync_exclude, - config->all_dbs, server_uuid, - *config->replication_probe_interval); - } - unixctl_command_reply(conn, NULL); - } else { - unixctl_command_reply( + + if (!str_to_int(argv[1], 10, &probe_interval)) { + unixctl_command_reply_error( conn, "Invalid probe interval, integer value expected"); + return; + } + + const struct uuid *server_uuid; + server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); + + *config->replication_probe_interval = probe_interval; + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + struct db_config *conf = db->config; + + if (conf->model == SM_ACTIVE_BACKUP) { + conf->options->probe_interval = probe_interval; + if (conf->ab.backup) { + replication_set_db(db->db, conf->source, conf->ab.sync_exclude, + server_uuid, conf->options->probe_interval); + } + } } + + save_config(config); + unixctl_command_reply(conn, NULL); } static void @@ -1554,17 +1773,30 @@ ovsdb_server_set_relay_source_interval(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; + struct shash_node *node; int probe_interval; - if (str_to_int(argv[1], 10, &probe_interval)) { - *config->relay_source_probe_interval = probe_interval; - save_config(config); - ovsdb_relay_set_probe_interval(probe_interval); - unixctl_command_reply(conn, NULL); - } else { + if (!str_to_int(argv[1], 10, &probe_interval)) { unixctl_command_reply_error( conn, "Invalid probe interval, integer value expected"); + return; + } + + *config->relay_source_probe_interval = probe_interval; + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + struct db_config *conf = db->config; + + if (conf->model == SM_RELAY) { + conf->options->probe_interval = probe_interval; + } } + + ovsdb_relay_set_probe_interval(probe_interval); + save_config(config); + + unixctl_command_reply(conn, NULL); } static void @@ -1574,20 +1806,36 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, void *config_) { struct server_config *config = config_; + struct shash_node *node; char *err = parse_excluded_tables(argv[1]); - if (!err) { - free(*config->sync_exclude); - *config->sync_exclude = xstrdup(argv[1]); - save_config(config); - if (*config->is_backup) { - const struct uuid *server_uuid; - server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); - ovsdb_replication_init(*config->sync_from, *config->sync_exclude, - config->all_dbs, server_uuid, - *config->replication_probe_interval); + if (err) { + goto exit; + } + + const struct uuid *server_uuid; + server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); + + free(*config->sync_exclude); + *config->sync_exclude = xstrdup(argv[1]); + + SHASH_FOR_EACH (node, config->all_dbs) { + struct db *db = node->data; + struct db_config *conf = db->config; + + if (conf->model == SM_ACTIVE_BACKUP) { + free(conf->ab.sync_exclude); + conf->ab.sync_exclude = xstrdup(argv[1]); + if (conf->ab.backup) { + replication_set_db(db->db, conf->source, conf->ab.sync_exclude, + server_uuid, conf->options->probe_interval); + } } } + + save_config(config); + +exit: unixctl_command_reply(conn, err); free(err); } @@ -1832,22 +2080,26 @@ ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED, { struct server_config *config = config_; const char *filename = argv[1]; + const struct shash_node *node; + struct shash db_conf; + + shash_init(&db_conf); + add_database_config(&db_conf, filename, *config->sync_from, + *config->sync_exclude, !config->is_backup); + ovs_assert(shash_count(&db_conf) == 1); + node = shash_first(&db_conf); - char *error = ovsdb_error_to_string_free(open_db(config, filename)); + char *error = ovsdb_error_to_string_free(open_db(config, + node->name, node->data)); if (!error) { save_config(config); - if (*config->is_backup) { - const struct uuid *server_uuid; - server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc); - ovsdb_replication_init(*config->sync_from, *config->sync_exclude, - config->all_dbs, server_uuid, - *config->replication_probe_interval); - } unixctl_command_reply(conn, NULL); } else { unixctl_command_reply_error(conn, error); free(error); } + db_config_destroy(node->data); + shash_destroy(&db_conf); } static void @@ -1994,23 +2246,34 @@ ovsdb_server_get_sync_status(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *config_) { struct server_config *config = config_; - bool is_backup = *config->is_backup; struct ds ds = DS_EMPTY_INITIALIZER; + bool any_backup = false; - ds_put_format(&ds, "state: %s\n", is_backup ? "backup" : "active"); + const struct shash_node **db_nodes = shash_sort(config->all_dbs); - if (is_backup) { - const struct shash_node **db_nodes = shash_sort(config->all_dbs); + for (size_t i = 0; i < shash_count(config->all_dbs); i++) { + const struct db *db = db_nodes[i]->data; - for (size_t i = 0; i < shash_count(config->all_dbs); i++) { - const struct db *db = db_nodes[i]->data; + if (db->config->model != SM_ACTIVE_BACKUP) { + continue; + } - if (db->db && db->db->name[0] != '_') { - ds_put_and_free_cstr(&ds, replication_status(db->db)); - ds_put_char(&ds, '\n'); - } + any_backup = true; + + ds_put_format(&ds, "database: %s\n", db->db->name); + ds_put_format(&ds, "state: %s\n", + db->config->ab.backup ? "backup" : "active"); + if (db->config->ab.backup) { + ds_put_and_free_cstr(&ds, replication_status(db->db)); } - free(db_nodes); + if (i + 1 < shash_count(config->all_dbs)) { + ds_put_char(&ds, '\n'); + } + } + free(db_nodes); + + if (!any_backup) { + ds_put_cstr(&ds, "state: active\n"); } unixctl_command_reply(conn, ds_cstr(&ds)); @@ -2054,7 +2317,7 @@ ovsdb_server_get_db_storage_status(struct unixctl_conn *conn, static void parse_options(int argc, char *argv[], - struct sset *db_filenames, struct shash *remotes, + struct shash *db_conf, struct shash *remotes, char **unixctl_pathp, char **run_command, char **sync_from, char **sync_exclude, bool *active) { @@ -2104,7 +2367,7 @@ parse_options(int argc, char *argv[], *sync_from = NULL; *sync_exclude = NULL; - sset_init(db_filenames); + shash_init(db_conf); shash_init(remotes); for (;;) { int c; @@ -2210,10 +2473,15 @@ parse_options(int argc, char *argv[], argv += optind; if (argc > 0) { for (int i = 0; i < argc; i++) { - sset_add(db_filenames, argv[i]); + add_database_config(db_conf, argv[i], *sync_from, *sync_exclude, + *active); } } else if (add_default_db) { - sset_add_and_free(db_filenames, xasprintf("%s/conf.db", ovs_dbdir())); + char *filename = xasprintf("%s/conf.db", ovs_dbdir()); + + add_database_config(db_conf, filename, *sync_from, *sync_exclude, + *active); + free(filename); } } @@ -2264,16 +2532,63 @@ remotes_to_json(const struct shash *remotes) json = json_object_create(); SHASH_FOR_EACH (node, remotes) { json_object_put(json, node->name, - ovsdb_jsonrpc_options_to_json(node->data)); + ovsdb_jsonrpc_options_to_json(node->data, false)); + } + return json; +} + +static struct json * +db_config_to_json(const struct db_config *conf) +{ + struct json *json; + + json = json_object_create(); + + if (conf->model != SM_UNDEFINED) { + json_object_put(json, "service-model", + json_string_create( + service_model_to_string(conf->model))); + } + + if (conf->source) { + struct json *source = json_object_create(); + + json_object_put(source, conf->source, + ovsdb_jsonrpc_options_to_json(conf->options, true)); + json_object_put(json, "source", source); + } + + if (conf->model == SM_ACTIVE_BACKUP) { + if (conf->ab.sync_exclude) { + struct sset set = SSET_INITIALIZER(&set); + + sset_from_delimited_string(&set, conf->ab.sync_exclude, " ,"); + json_object_put(json, "exclude-tables", sset_to_json(&set)); + sset_destroy(&set); + } + json_object_put(json, "backup", json_boolean_create(conf->ab.backup)); + } + return json; +} + +static struct json * +databases_to_json(const struct shash *db_conf) +{ + const struct shash_node *node; + struct json *json; + + json = json_object_create(); + SHASH_FOR_EACH (node, db_conf) { + json_object_put(json, node->name, db_config_to_json(node->data)); } return json; } /* Truncates and replaces the contents of 'config_file' by a representation of - * 'remotes' and 'db_filenames'. */ + * 'remotes', 'db_conf' and a few global replication paramaters. */ static void save_config__(FILE *config_file, const struct shash *remotes, - const struct sset *db_filenames, const char *sync_from, + const struct shash *db_conf, const char *sync_from, const char *sync_exclude, bool is_backup) { struct json *obj; @@ -2286,7 +2601,8 @@ save_config__(FILE *config_file, const struct shash *remotes, obj = json_object_create(); json_object_put(obj, "remotes", remotes_to_json(remotes)); - json_object_put(obj, "db_filenames", sset_to_json(db_filenames)); + json_object_put(obj, "databases", databases_to_json(db_conf)); + if (sync_from) { json_object_put(obj, "sync_from", json_string_create(sync_from)); } @@ -2312,56 +2628,147 @@ save_config__(FILE *config_file, const struct shash *remotes, static void save_config(struct server_config *config) { - struct sset db_filenames; struct shash_node *node; + struct shash db_conf; - sset_init(&db_filenames); + shash_init(&db_conf); SHASH_FOR_EACH (node, config->all_dbs) { struct db *db = node->data; + if (node->name[0] != '_') { - sset_add(&db_filenames, db->filename); + shash_add(&db_conf, db->filename, db->config); } } - save_config__(config->config_tmpfile, config->remotes, &db_filenames, + save_config__(config->config_tmpfile, config->remotes, &db_conf, *config->sync_from, *config->sync_exclude, *config->is_backup); - sset_destroy(&db_filenames); + shash_destroy(&db_conf); } static void -sset_from_json(struct sset *sset, const struct json *array) +remotes_from_json(struct shash *remotes, const struct json *json) { - size_t i; + struct ovsdb_jsonrpc_options *options; + const struct shash_node *node; + const struct shash *object; - sset_clear(sset); + free_remotes(remotes); - ovs_assert(array); - ovs_assert(array->type == JSON_ARRAY); - for (i = 0; i < array->array.n; i++) { - const struct json *elem = array->array.elems[i]; - sset_add(sset, json_string(elem)); + ovs_assert(json); + ovs_assert(json->type == JSON_OBJECT); + + object = json_object(json); + SHASH_FOR_EACH (node, object) { + options = ovsdb_jsonrpc_default_options(node->name); + ovsdb_jsonrpc_options_update_from_json(options, node->data, false); + shash_add(remotes, node->name, options); } } +static struct db_config * +db_config_from_json(const char *name, const struct json *json) +{ + const struct json *model, *source, *sync_exclude, *backup; + struct db_config *conf = xzalloc(sizeof *conf); + struct ovsdb_parser parser; + struct ovsdb_error *error; + + ovsdb_parser_init(&parser, json, "database %s", name); + + model = ovsdb_parser_member(&parser, "service-model", + OP_STRING | OP_OPTIONAL); + conf->model = model ? service_model_from_string(json_string(model)) + : SM_UNDEFINED; + + if (conf->model == SM_ACTIVE_BACKUP) { + backup = ovsdb_parser_member(&parser, "backup", OP_BOOLEAN); + conf->ab.backup = backup ? json_boolean(backup) : false; + + sync_exclude = ovsdb_parser_member(&parser, "exclude-tables", + OP_ARRAY | OP_OPTIONAL); + if (sync_exclude) { + const struct json_array *exclude = json_array(sync_exclude); + struct sset set = SSET_INITIALIZER(&set); + + for (size_t i = 0; i < exclude->n; i++) { + if (exclude->elems[i]->type != JSON_STRING) { + ovsdb_parser_raise_error(&parser, + "'exclude-tables' must contain strings"); + break; + } + sset_add(&set, json_string(exclude->elems[i])); + } + conf->ab.sync_exclude = sset_join(&set, ",", ""); + sset_destroy(&set); + } + } + + if (conf->model == SM_ACTIVE_BACKUP || conf->model == SM_RELAY) { + enum ovsdb_parser_types type = OP_OBJECT; + + if (conf->model == SM_ACTIVE_BACKUP && !conf->ab.backup) { + /* Active database doesn't have to have a source. */ + type |= OP_OPTIONAL; + } + source = ovsdb_parser_member(&parser, "source", type); + + if (source && shash_count(json_object(source)) != 1) { + ovsdb_parser_raise_error(&parser, + "'source' should be an object with exactly one element"); + } else if (source) { + const struct shash_node *node = shash_first(json_object(source)); + const struct json *options; + + ovs_assert(node); + conf->source = xstrdup(node->name); + options = node->data; + + conf->options = get_jsonrpc_options(conf->source, conf->model); + + if (options->type == JSON_OBJECT) { + ovsdb_jsonrpc_options_update_from_json(conf->options, + options, true); + } else if (options->type != JSON_NULL) { + ovsdb_parser_raise_error(&parser, + "JSON-RPC options is not a JSON object or null"); + } + } + } + + error = ovsdb_parser_finish(&parser); + if (error) { + char *s = ovsdb_error_to_string_free(error); + + VLOG_WARN("%s", s); + free(s); + db_config_destroy(conf); + return NULL; + } + + return conf; +} + + static void -remotes_from_json(struct shash *remotes, const struct json *json) +databases_from_json(struct shash *db_conf, const struct json *json) { - struct ovsdb_jsonrpc_options *options; const struct shash_node *node; const struct shash *object; - free_remotes(remotes); + free_database_configs(db_conf); ovs_assert(json); ovs_assert(json->type == JSON_OBJECT); object = json_object(json); SHASH_FOR_EACH (node, object) { - options = ovsdb_jsonrpc_default_options(node->name); - ovsdb_jsonrpc_options_update_from_json(options, node->data); - shash_add(remotes, node->name, options); + struct db_config *conf = db_config_from_json(node->name, node->data); + + if (conf) { + shash_add(db_conf, node->name, conf); + } } } @@ -2369,7 +2776,7 @@ remotes_from_json(struct shash *remotes, const struct json *json) * 'config_file', which must have been previously written by save_config(). */ static void load_config(FILE *config_file, struct shash *remotes, - struct sset *db_filenames, char **sync_from, + struct shash *db_conf, char **sync_from, char **sync_exclude, bool *is_backup) { struct json *json; @@ -2384,8 +2791,8 @@ load_config(FILE *config_file, struct shash *remotes, ovs_assert(json->type == JSON_OBJECT); remotes_from_json(remotes, shash_find_data(json_object(json), "remotes")); - sset_from_json(db_filenames, - shash_find_data(json_object(json), "db_filenames")); + databases_from_json(db_conf, + shash_find_data(json_object(json), "databases")); struct json *string; string = shash_find_data(json_object(json), "sync_from"); diff --git a/ovsdb/replication.c b/ovsdb/replication.c index 3c59d4039..3a062b078 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -795,7 +795,6 @@ replication_status(const struct ovsdb *db) bool alive = rdb->session && jsonrpc_session_is_alive(rdb->session); struct ds ds = DS_EMPTY_INITIALIZER; - ds_put_format(&ds, "database: %s\n", db->name); if (alive) { switch (rdb->state) { case RPL_S_INIT: diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 6eb758e22..45aa80cd6 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -1988,7 +1988,9 @@ OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status |grep re dnl Switch the 'db1' to active AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/disconnect-active-ovsdb-server]) -AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status], [0], [state: active +AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status], [0], [dnl +database: mydb +state: active ]) dnl Issue a transaction to 'db1' @@ -2007,7 +2009,9 @@ AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/connect-active-ovsdb-server dnl Verify the change happend OVS_WAIT_UNTIL([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/sync-status |grep replicating]) -AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status], [0], [state: active +AT_CHECK([ovs-appctl -t "`pwd`"/unixctl2 ovsdb-server/sync-status], [0], [dnl +database: mydb +state: active ]) dnl Issue an transaction to 'db2' which is now active. From patchwork Thu Dec 14 01:04:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875929 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhP4y2Jz1ySd for ; Thu, 14 Dec 2023 12:06:45 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8EDB743769; Thu, 14 Dec 2023 01:06:42 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 8EDB743769 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 1aGdvs-HFMgp; Thu, 14 Dec 2023 01:06:41 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 648DB43742; Thu, 14 Dec 2023 01:06:39 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 648DB43742 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1DC34C0DCF; Thu, 14 Dec 2023 01:06:39 +0000 (UTC) X-Original-To: ovs-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 265AFC0037 for ; Thu, 14 Dec 2023 01:06:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 356D861B26 for ; Thu, 14 Dec 2023 01:05:21 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 356D861B26 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HeMIlK9LXic0 for ; Thu, 14 Dec 2023 01:05:20 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp3.osuosl.org (Postfix) with ESMTPS id BEE9161B1F for ; Thu, 14 Dec 2023 01:05:19 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org BEE9161B1F Received: by mail.gandi.net (Postfix) with ESMTPSA id 9552E240003; Thu, 14 Dec 2023 01:05:17 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:15 +0100 Message-ID: <20231214010431.1664005-14-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 13/22] ovsdb-server: Add no-op config-file option. 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" Adding a --config-file option that will be used in the future to allow users to provide the database server configuration via a JSON file. For now, it does nothing useful, but we define it as mutually exclusive with all the command line options and UnixCtl commands that configure values that will be available via a config file. This will ensure that we don't have too many ways of configuring the same thing at the same time. New appctl command 'ovsdb-server/reload' is going to signal OVSDB server that it needs to re-read the configuration file. While at it, adding a missing 'usage' line for '--no-dbs'. This option is rarely used, so it doesn't seem to be worth a separate fix. Signed-off-by: Ilya Maximets --- ovsdb/ovsdb-server.c | 110 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index d7a823220..3765cf066 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -95,6 +95,13 @@ static unixctl_cb_func ovsdb_server_get_sync_exclude_tables; static unixctl_cb_func ovsdb_server_get_sync_status; static unixctl_cb_func ovsdb_server_get_db_storage_status; +/* Holds the name of the configuration file passed via --config-file. + * Mutually exclusive with command-line and unixctl configuration + * that can otherwise be done via configuration file. */ +static char *config_file_path = NULL; +/* UnixCtl command to reload configuration from a configuration file. */ +static unixctl_cb_func ovsdb_server_reload; + #define SERVICE_MODELS \ SERVICE_MODEL(UNDEFINED, undefined) \ SERVICE_MODEL(STANDALONE, standalone) \ @@ -639,6 +646,8 @@ main(int argc, char *argv[]) ovsdb_server_memory_trim_on_compaction, NULL); unixctl_command_register("ovsdb-server/reconnect", "", 0, 0, ovsdb_server_reconnect, jsonrpc); + unixctl_command_register("ovsdb-server/reload", "", 0, 0, + ovsdb_server_reload, &server_config); unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1, ovsdb_server_add_remote, &server_config); @@ -714,6 +723,7 @@ main(int argc, char *argv[]) free(sync_exclude); unixctl_server_destroy(unixctl); replication_destroy(); + free(config_file_path); if (run_process && process_exited(run_process)) { int status = process_status(run_process); @@ -1626,6 +1636,23 @@ report_error_if_changed(char *error, char **last_errorp) } } +static bool +check_config_file_on_unixctl(struct unixctl_conn *conn) +{ + struct ds ds = DS_EMPTY_INITIALIZER; + + if (!config_file_path) { + return false; + } + + ds_put_format(&ds, "Update the %s and use ovsdb-server/reload instead", + config_file_path); + unixctl_command_reply_error(conn, ds_cstr(&ds)); + ds_destroy(&ds); + + return true; +} + static void ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], @@ -1634,6 +1661,10 @@ ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn, struct server_config *config = config_; struct shash_node *node; + if (check_config_file_on_unixctl(conn)) { + return; + } + free(*config->sync_from); *config->sync_from = xstrdup(argv[1]); @@ -1672,6 +1703,10 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, struct shash_node *node; char *msg = NULL; + if (check_config_file_on_unixctl(conn)) { + return; + } + if (!*config->sync_from) { msg = "Unable to connect: active server is not specified.\n"; } else { @@ -1715,6 +1750,10 @@ ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn, struct server_config *config = config_; struct shash_node *node; + if (check_config_file_on_unixctl(conn)) { + return; + } + SHASH_FOR_EACH (node, config->all_dbs) { struct db *db = node->data; struct db_config *conf = db->config; @@ -1738,6 +1777,10 @@ ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, struct shash_node *node; int probe_interval; + if (check_config_file_on_unixctl(conn)) { + return; + } + if (!str_to_int(argv[1], 10, &probe_interval)) { unixctl_command_reply_error( conn, "Invalid probe interval, integer value expected"); @@ -1776,6 +1819,10 @@ ovsdb_server_set_relay_source_interval(struct unixctl_conn *conn, struct shash_node *node; int probe_interval; + if (check_config_file_on_unixctl(conn)) { + return; + } + if (!str_to_int(argv[1], 10, &probe_interval)) { unixctl_command_reply_error( conn, "Invalid probe interval, integer value expected"); @@ -1808,6 +1855,10 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, struct server_config *config = config_; struct shash_node *node; + if (check_config_file_on_unixctl(conn)) { + return; + } + char *err = parse_excluded_tables(argv[1]); if (err) { goto exit; @@ -2002,6 +2053,21 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED, unixctl_command_reply(conn, NULL); } +/* "ovsdb-server/reload": makes ovsdb-server open a configuration file on + * 'config_file_path', read it and sync the runtime configuration with it. */ +static void +ovsdb_server_reload(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *config_ OVS_UNUSED) +{ + if (!config_file_path) { + unixctl_command_reply_error(conn, + "Configuration file was not specified on command line"); + } else { + unixctl_command_reply_error(conn, + "Configuration file support is not implemented yet"); + } +} + /* "ovsdb-server/add-remote REMOTE": adds REMOTE to the set of remotes that * ovsdb-server services. */ static void @@ -2016,6 +2082,10 @@ ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, const struct db *db; char *retval; + if (check_config_file_on_unixctl(conn)) { + return; + } + retval = (strncmp("db:", remote, 3) ? NULL : parse_db_column(config->all_dbs, remote, @@ -2040,6 +2110,10 @@ ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED, struct server_config *config = config_; struct ovsdb_jsonrpc_options *options; + if (check_config_file_on_unixctl(conn)) { + return; + } + options = shash_find_and_delete(config->remotes, argv[1]); if (options) { free(options->role); @@ -2083,6 +2157,10 @@ ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED, const struct shash_node *node; struct shash db_conf; + if (check_config_file_on_unixctl(conn)) { + return; + } + shash_init(&db_conf); add_database_config(&db_conf, filename, *config->sync_from, *config->sync_exclude, !config->is_backup); @@ -2120,6 +2198,10 @@ ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED, struct server_config *config = config_; struct shash_node *node; + if (check_config_file_on_unixctl(conn)) { + return; + } + node = shash_find(config->all_dbs, argv[1]); if (!node) { unixctl_command_reply_error(conn, "Failed to find the database."); @@ -2333,6 +2415,7 @@ parse_options(int argc, char *argv[], OPT_NO_DBS, OPT_FILE_COLUMN_DIFF, OPT_FILE_NO_DATA_CONVERSION, + OPT_CONFIG_FILE, VLOG_OPTION_ENUMS, DAEMON_OPTION_ENUMS, SSL_OPTION_ENUMS, @@ -2360,6 +2443,7 @@ parse_options(int argc, char *argv[], {"disable-file-column-diff", no_argument, NULL, OPT_FILE_COLUMN_DIFF}, {"disable-file-no-data-conversion", no_argument, NULL, OPT_FILE_NO_DATA_CONVERSION}, + {"config-file", required_argument, NULL, OPT_CONFIG_FILE}, {NULL, 0, NULL, 0}, }; char *short_options = ovs_cmdl_long_options_to_short_options(long_options); @@ -2460,6 +2544,11 @@ parse_options(int argc, char *argv[], ovsdb_no_data_conversion_disable(); break; + case OPT_CONFIG_FILE: + config_file_path = abs_file_name(ovs_dbdir(), optarg); + add_default_db = false; + break; + case '?': exit(EXIT_FAILURE); @@ -2471,7 +2560,19 @@ parse_options(int argc, char *argv[], argc -= optind; argv += optind; - if (argc > 0) { + + if (config_file_path) { + if (*sync_from || *sync_exclude || *active) { + ovs_fatal(0, "--config-file is mutually exclusive with " + "--sync-from, --sync-exclude and --active"); + } + if (shash_count(remotes)) { + ovs_fatal(0, "--config-file is mutually exclusive with --remote"); + } + if (argc > 0) { + ovs_fatal(0, "Databases should be specified in a config file"); + } + } else if (argc > 0) { for (int i = 0; i < argc; i++) { add_database_config(db_conf, argv[i], *sync_from, *sync_exclude, *active); @@ -2496,6 +2597,12 @@ usage(void) printf("\nJSON-RPC options (may be specified any number of times):\n" " --remote=REMOTE connect or listen to REMOTE\n"); stream_usage("JSON-RPC", true, true, true); + printf("\nConfiguration file:\n" + " --config-file PATH Use configuration file as a source of\n" + " database and JSON-RPC configuration.\n" + " Mutually exclusive with the DATABASE,\n" + " JSON-RPC and Syncing options.\n" + " Assumes --no-dbs.\n"); daemon_usage(); vlog_usage(); replication_usage(); @@ -2503,6 +2610,7 @@ usage(void) printf("\nOther options:\n" " --run COMMAND run COMMAND as subprocess then exit\n" " --unixctl=SOCKET override default control socket name\n" + " --no-dbs do not add default database\n" " --disable-file-column-diff\n" " don't use column diff in database file\n" " -h, --help display this help message\n" From patchwork Thu Dec 14 01:04:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875928 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhN1NCdz1ySd for ; Thu, 14 Dec 2023 12:06:44 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 671E283B60; Thu, 14 Dec 2023 01:06:41 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 671E283B60 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 CAotd3_hKQEO; Thu, 14 Dec 2023 01:06:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id ED22683B6F; Thu, 14 Dec 2023 01:06:34 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org ED22683B6F Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 570FDC0DD8; Thu, 14 Dec 2023 01:06:33 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4BA63C0DD9 for ; Thu, 14 Dec 2023 01:06:31 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id AEF0043704 for ; Thu, 14 Dec 2023 01:05:23 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org AEF0043704 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 wU0bV-F03KWI for ; Thu, 14 Dec 2023 01:05:23 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp2.osuosl.org (Postfix) with ESMTPS id B6491436D9 for ; Thu, 14 Dec 2023 01:05:22 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org B6491436D9 Received: by mail.gandi.net (Postfix) with ESMTPSA id 81D89240002; Thu, 14 Dec 2023 01:05:20 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:16 +0100 Message-ID: <20231214010431.1664005-15-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 14/22] jsonrpc-server: Re-add remotes on role changes. 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" It is currently not possible for the role to change in runtime (unless a manual DB transaction is crafted), but it will be with addition of a config file. If the role changes, listening socket will be closed, and all the connections to this remote will be terminated. Signed-off-by: Ilya Maximets --- ovsdb/jsonrpc-server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 81e9e48a0..f3b4961f3 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -330,7 +330,8 @@ ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *svr, if (!options) { VLOG_INFO("%s: remote deconfigured", node->name); ovsdb_jsonrpc_server_del_remote(node); - } else if (options->dscp != remote->dscp) { + } else if (options->dscp != remote->dscp + || !nullable_string_is_equal(options->role, remote->role)) { ovsdb_jsonrpc_server_del_remote(node); } } From patchwork Thu Dec 14 01:04:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875931 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhr1RmFz1ySd for ; Thu, 14 Dec 2023 12:07:08 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id B8102437B1; Thu, 14 Dec 2023 01:07:05 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org B8102437B1 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 tJEC288O1hdH; Thu, 14 Dec 2023 01:07:04 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 0A498437A5; Thu, 14 Dec 2023 01:07:03 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0A498437A5 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BC832C0DDA; Thu, 14 Dec 2023 01:07:00 +0000 (UTC) X-Original-To: ovs-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 53E8FC0DCF for ; Thu, 14 Dec 2023 01:06:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id DB61761B08 for ; Thu, 14 Dec 2023 01:05:26 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org DB61761B08 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CfxcXRAuXEA7 for ; Thu, 14 Dec 2023 01:05:26 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp3.osuosl.org (Postfix) with ESMTPS id D13D661B23 for ; Thu, 14 Dec 2023 01:05:25 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org D13D661B23 Received: by mail.gandi.net (Postfix) with ESMTPSA id B4AE4240002; Thu, 14 Dec 2023 01:05:23 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:17 +0100 Message-ID: <20231214010431.1664005-16-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 15/22] jsonrpc: Add function to update all options at once. 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" It's useful to have a way to update all the JSON-RPC session options all at once and not call 3 separate functions every time. This may also allow the internals of these options to be better abstracted, i.e. allow users to not know what are these options exactly. Signed-off-by: Ilya Maximets --- lib/jsonrpc.c | 9 +++++++++ lib/jsonrpc.h | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c index 3db5f76e2..f1ef70950 100644 --- a/lib/jsonrpc.c +++ b/lib/jsonrpc.c @@ -1337,6 +1337,15 @@ jsonrpc_session_set_dscp(struct jsonrpc_session *s, uint8_t dscp) } } +void +jsonrpc_session_set_options(struct jsonrpc_session *s, + const struct jsonrpc_session_options *options) +{ + jsonrpc_session_set_max_backoff(s, options->max_backoff); + jsonrpc_session_set_probe_interval(s, options->probe_interval); + jsonrpc_session_set_dscp(s, options->dscp); +} + /* Sets thresholds for send backlog. If send backlog contains more than * 'max_n_msgs' messages or is larger than 'max_backlog_bytes' bytes, * connection will be closed (then reconnected, if that feature is enabled). */ diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h index 2aa97d3fe..1baffcd80 100644 --- a/lib/jsonrpc.h +++ b/lib/jsonrpc.h @@ -139,6 +139,14 @@ void jsonrpc_session_enable_reconnect(struct jsonrpc_session *); void jsonrpc_session_force_reconnect(struct jsonrpc_session *); void jsonrpc_session_reset_backoff(struct jsonrpc_session *); +struct jsonrpc_session_options { + int max_backoff; /* Maximum reconnection backoff, in msec. */ + int probe_interval; /* Max idle time before probing, in msec. */ + uint8_t dscp; /* Dscp value for passive connections. */ +}; + +void jsonrpc_session_set_options(struct jsonrpc_session *, + const struct jsonrpc_session_options *); void jsonrpc_session_set_max_backoff(struct jsonrpc_session *, int max_backoff); void jsonrpc_session_set_probe_interval(struct jsonrpc_session *, From patchwork Thu Dec 14 01:04:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875930 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhm5fk3z1ySd for ; Thu, 14 Dec 2023 12:07:04 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 0C3004379C; Thu, 14 Dec 2023 01:07:02 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0C3004379C 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 KZURiIS73zfc; Thu, 14 Dec 2023 01:07:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id CC0854378D; Thu, 14 Dec 2023 01:06:58 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org CC0854378D Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8B627C0037; Thu, 14 Dec 2023 01:06:58 +0000 (UTC) X-Original-To: ovs-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 435BAC0072 for ; Thu, 14 Dec 2023 01:06:56 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A1796811E7 for ; Thu, 14 Dec 2023 01:05:30 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org A1796811E7 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 d-JP441K5Iun for ; Thu, 14 Dec 2023 01:05:29 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp1.osuosl.org (Postfix) with ESMTPS id 2F8BF8130E for ; Thu, 14 Dec 2023 01:05:28 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 2F8BF8130E Received: by mail.gandi.net (Postfix) with ESMTPSA id 0567A240002; Thu, 14 Dec 2023 01:05:26 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:18 +0100 Message-ID: <20231214010431.1664005-17-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 16/22] ovsdb: Embed jsonrpc session options into ovsdb jsonrpc options. 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" Just introduced structure 'jsonrpc_session_options' is the same as part of the 'ovsdb_jsonrpc_options'. In fact, these options do really belong to a lower layer. So, replace a copy of these fields with a structure, so it can be easily passed to jsonrpc's 'jsonrpc_session_set_options()'. Not creating separate JSON parsing/formatting functions to avoid creating an extra nesting level for the users who will write the JSON definition in a configuration file. I.e. keeping the JSON object flat. Also, not changing the 'db_config->options' to be 'jsonrpc_session_options', even though we don't need the 'role' or 'read-only' fields. This allows us to use the same JSON parsing function for both the remotes ans database sources. Can be changed in the future, but for now keeping as is to avoid extra code complication. Signed-off-by: Ilya Maximets --- ovsdb/jsonrpc-server.c | 40 ++++++++++++++++------------------------ ovsdb/jsonrpc-server.h | 5 ++--- ovsdb/ovsdb-server.c | 31 +++++++++++++++++-------------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index f3b4961f3..5b3b5f451 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -211,11 +211,12 @@ struct ovsdb_jsonrpc_options * ovsdb_jsonrpc_default_options(const char *target) { struct ovsdb_jsonrpc_options *options = xzalloc(sizeof *options); - options->max_backoff = RECONNECT_DEFAULT_MAX_BACKOFF; - options->probe_interval = (stream_or_pstream_needs_probes(target) - ? RECONNECT_DEFAULT_PROBE_INTERVAL - : 0); - options->dscp = DSCP_DEFAULT; + struct jsonrpc_session_options *rpc_opt = &options->rpc; + + rpc_opt->max_backoff = RECONNECT_DEFAULT_MAX_BACKOFF; + rpc_opt->probe_interval = (stream_or_pstream_needs_probes(target) + ? RECONNECT_DEFAULT_PROBE_INTERVAL : 0); + rpc_opt->dscp = DSCP_DEFAULT; return options; } @@ -237,10 +238,10 @@ ovsdb_jsonrpc_options_to_json(const struct ovsdb_jsonrpc_options *options, struct json *json = json_object_create(); json_object_put(json, "max-backoff", - json_integer_create(options->max_backoff)); + json_integer_create(options->rpc.max_backoff)); json_object_put(json, "inactivity-probe", - json_integer_create(options->probe_interval)); - json_object_put(json, "dscp", json_integer_create(options->dscp)); + json_integer_create(options->rpc.probe_interval)); + json_object_put(json, "dscp", json_integer_create(options->rpc.dscp)); if (jsonrpc_session_only) { /* Caller is not interested in OVSDB-specific options. */ @@ -270,18 +271,18 @@ ovsdb_jsonrpc_options_update_from_json(struct ovsdb_jsonrpc_options *options, max_backoff = ovsdb_parser_member(&parser, "max-backoff", OP_INTEGER | OP_OPTIONAL); if (max_backoff) { - options->max_backoff = json_integer(max_backoff); + options->rpc.max_backoff = json_integer(max_backoff); } probe_interval = ovsdb_parser_member(&parser, "inactivity-probe", OP_INTEGER | OP_OPTIONAL); if (probe_interval) { - options->probe_interval = json_integer(probe_interval); + options->rpc.probe_interval = json_integer(probe_interval); } dscp = ovsdb_parser_member(&parser, "dscp", OP_INTEGER | OP_OPTIONAL); if (dscp) { - options->dscp = json_integer(dscp); + options->rpc.dscp = json_integer(dscp); } if (jsonrpc_session_only) { @@ -330,7 +331,7 @@ ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *svr, if (!options) { VLOG_INFO("%s: remote deconfigured", node->name); ovsdb_jsonrpc_server_del_remote(node); - } else if (options->dscp != remote->dscp + } else if (options->rpc.dscp != remote->dscp || !nullable_string_is_equal(options->role, remote->role)) { ovsdb_jsonrpc_server_del_remote(node); } @@ -360,7 +361,7 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr, struct pstream *listener; int error; - error = jsonrpc_pstream_open(name, &listener, options->dscp); + error = jsonrpc_pstream_open(name, &listener, options->rpc.dscp); switch (error) { case 0: case EAFNOSUPPORT: @@ -368,7 +369,7 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr, remote->server = svr; remote->listener = listener; ovs_list_init(&remote->sessions); - remote->dscp = options->dscp; + remote->dscp = options->rpc.dscp; remote->read_only = options->read_only; remote->role = nullable_xstrdup(options->role); shash_add(&svr->remotes, name, remote); @@ -678,15 +679,6 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s) return jsonrpc_session_is_alive(s->js) ? 0 : ETIMEDOUT; } -static void -ovsdb_jsonrpc_session_set_options(struct ovsdb_jsonrpc_session *session, - const struct ovsdb_jsonrpc_options *options) -{ - jsonrpc_session_set_max_backoff(session->js, options->max_backoff); - jsonrpc_session_set_probe_interval(session->js, options->probe_interval); - jsonrpc_session_set_dscp(session->js, options->dscp); -} - static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *remote) { @@ -805,7 +797,7 @@ ovsdb_jsonrpc_session_set_all_options( struct ovsdb_jsonrpc_session *s; LIST_FOR_EACH (s, node, &remote->sessions) { - ovsdb_jsonrpc_session_set_options(s, options); + jsonrpc_session_set_options(s->js, &options->rpc); } } diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index 0d8f87da7..2fe381010 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -18,6 +18,7 @@ #include #include "openvswitch/types.h" +#include "jsonrpc.h" struct ovsdb; struct shash; @@ -33,10 +34,8 @@ void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *); /* Options for a remote. */ struct ovsdb_jsonrpc_options { - int max_backoff; /* Maximum reconnection backoff, in msec. */ - int probe_interval; /* Max idle time before probing, in msec. */ + struct jsonrpc_session_options rpc; /* JSON-RPC options. */ bool read_only; /* Only read-only transactions are allowed. */ - int dscp; /* Dscp value for manager connections */ char *role; /* Role, for role-based access controls */ }; struct ovsdb_jsonrpc_options *ovsdb_jsonrpc_default_options( diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 3765cf066..eceed7b54 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -464,9 +464,9 @@ get_jsonrpc_options(const char *target, enum service_model model) options = ovsdb_jsonrpc_default_options(target); if (model == SM_ACTIVE_BACKUP) { - options->probe_interval = REPLICATION_DEFAULT_PROBE_INTERVAL; + options->rpc.probe_interval = REPLICATION_DEFAULT_PROBE_INTERVAL; } else if (model == SM_RELAY) { - options->probe_interval = RELAY_SOURCE_DEFAULT_PROBE_INTERVAL; + options->rpc.probe_interval = RELAY_SOURCE_DEFAULT_PROBE_INTERVAL; } return options; @@ -1017,14 +1017,14 @@ open_db(struct server_config *server_config, if (model == SM_RELAY) { ovsdb_relay_add_db(db->db, conf->source, update_schema, server_config, - conf->options->probe_interval); + conf->options->rpc.probe_interval); } if (model == SM_ACTIVE_BACKUP && conf->ab.backup) { const struct uuid *server_uuid; server_uuid = ovsdb_jsonrpc_server_get_uuid(server_config->jsonrpc); replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, conf->options->probe_interval); + server_uuid, conf->options->rpc.probe_interval); } return NULL; } @@ -1241,11 +1241,11 @@ add_manager_options(struct shash *remotes, const struct ovsdb_row *row) options = add_remote(remotes, target, NULL); if (ovsdb_util_read_integer_column(row, "max_backoff", &max_backoff)) { - options->max_backoff = max_backoff; + options->rpc.max_backoff = max_backoff; } if (ovsdb_util_read_integer_column(row, "inactivity_probe", &probe_interval)) { - options->probe_interval = probe_interval; + options->rpc.probe_interval = probe_interval; } if (ovsdb_util_read_bool_column(row, "read_only", &read_only)) { options->read_only = read_only; @@ -1257,13 +1257,13 @@ add_manager_options(struct shash *remotes, const struct ovsdb_row *row) options->role = xstrdup(role); } - options->dscp = DSCP_DEFAULT; + options->rpc.dscp = DSCP_DEFAULT; dscp_string = ovsdb_util_read_map_string_column(row, "other_config", "dscp"); if (dscp_string) { int dscp = atoi(dscp_string); if (dscp >= 0 && dscp <= 63) { - options->dscp = dscp; + options->rpc.dscp = dscp; } } } @@ -1722,7 +1722,7 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, conf->model = SM_ACTIVE_BACKUP; conf->source = xstrdup(*config->sync_from); conf->options = ovsdb_jsonrpc_default_options(conf->source); - conf->options->probe_interval = + conf->options->rpc.probe_interval = *config->replication_probe_interval; conf->ab.sync_exclude = nullable_xstrdup(*config->sync_exclude); @@ -1731,7 +1731,8 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, if (conf->model == SM_ACTIVE_BACKUP && !conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, conf->options->probe_interval); + server_uuid, + conf->options->rpc.probe_interval); conf->ab.backup = true; } } @@ -1797,10 +1798,11 @@ ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, struct db_config *conf = db->config; if (conf->model == SM_ACTIVE_BACKUP) { - conf->options->probe_interval = probe_interval; + conf->options->rpc.probe_interval = probe_interval; if (conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, conf->options->probe_interval); + server_uuid, + conf->options->rpc.probe_interval); } } } @@ -1836,7 +1838,7 @@ ovsdb_server_set_relay_source_interval(struct unixctl_conn *conn, struct db_config *conf = db->config; if (conf->model == SM_RELAY) { - conf->options->probe_interval = probe_interval; + conf->options->rpc.probe_interval = probe_interval; } } @@ -1879,7 +1881,8 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, conf->ab.sync_exclude = xstrdup(argv[1]); if (conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, conf->options->probe_interval); + server_uuid, + conf->options->rpc.probe_interval); } } } From patchwork Thu Dec 14 01:04:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875932 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDhr5ksPz23nm for ; Thu, 14 Dec 2023 12:07:08 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id EC28783BDE; Thu, 14 Dec 2023 01:07:06 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org EC28783BDE 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 05C5iovTcRG9; Thu, 14 Dec 2023 01:07:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id A469883BEF; Thu, 14 Dec 2023 01:07:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org A469883BEF Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 892A6C0DCF; Thu, 14 Dec 2023 01:07:03 +0000 (UTC) X-Original-To: ovs-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 38F9AC0DD7 for ; Thu, 14 Dec 2023 01:07:02 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id D1FC0834F5 for ; Thu, 14 Dec 2023 01:05:32 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org D1FC0834F5 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 8qlzdeEJ5zWi for ; Thu, 14 Dec 2023 01:05:32 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp1.osuosl.org (Postfix) with ESMTPS id B7253812E6 for ; Thu, 14 Dec 2023 01:05:31 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org B7253812E6 Received: by mail.gandi.net (Postfix) with ESMTPSA id A2DD7240004; Thu, 14 Dec 2023 01:05:29 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:19 +0100 Message-ID: <20231214010431.1664005-18-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 17/22] ovsdb: replication: Allow to set all jsonrpc options. 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" Set all the options for the source connection, not only the inactivity probe interval. Signed-off-by: Ilya Maximets --- ovsdb/ovsdb-server.c | 11 ++++------- ovsdb/replication.c | 6 +++--- ovsdb/replication.h | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index eceed7b54..6eced3896 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -1024,7 +1024,7 @@ open_db(struct server_config *server_config, server_uuid = ovsdb_jsonrpc_server_get_uuid(server_config->jsonrpc); replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, conf->options->rpc.probe_interval); + server_uuid, &conf->options->rpc); } return NULL; } @@ -1731,8 +1731,7 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn, if (conf->model == SM_ACTIVE_BACKUP && !conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, - conf->options->rpc.probe_interval); + server_uuid, &conf->options->rpc); conf->ab.backup = true; } } @@ -1801,8 +1800,7 @@ ovsdb_server_set_active_ovsdb_server_probe_interval(struct unixctl_conn *conn, conf->options->rpc.probe_interval = probe_interval; if (conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, - conf->options->rpc.probe_interval); + server_uuid, &conf->options->rpc); } } } @@ -1881,8 +1879,7 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn, conf->ab.sync_exclude = xstrdup(argv[1]); if (conf->ab.backup) { replication_set_db(db->db, conf->source, conf->ab.sync_exclude, - server_uuid, - conf->options->rpc.probe_interval); + server_uuid, &conf->options->rpc); } } } diff --git a/ovsdb/replication.c b/ovsdb/replication.c index 3a062b078..858a833bb 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -108,7 +108,7 @@ static bool request_id_compare_and_free(struct replication_db *, void replication_set_db(struct ovsdb *db, const char *sync_from, const char *exclude_tables, const struct uuid *server, - int probe_interval) + const struct jsonrpc_session_options *options) { struct replication_db *rdb = find_db(db->name); @@ -124,7 +124,7 @@ replication_set_db(struct ovsdb *db, const char *sync_from, if (rdb && nullable_string_is_equal(rdb->excluded_tables_str, exclude_tables) && nullable_string_is_equal(rdb->sync_from, sync_from)) { - jsonrpc_session_set_probe_interval(rdb->session, probe_interval); + jsonrpc_session_set_options(rdb->session, options); return; } @@ -147,7 +147,7 @@ replication_set_db(struct ovsdb *db, const char *sync_from, rdb->session = jsonrpc_session_open(rdb->sync_from, true); rdb->session_seqno = UINT_MAX; - jsonrpc_session_set_probe_interval(rdb->session, probe_interval); + jsonrpc_session_set_options(rdb->session, options); rdb->state = RPL_S_INIT; rdb->db->read_only = true; diff --git a/ovsdb/replication.h b/ovsdb/replication.h index f5e226753..a2ed5f02e 100644 --- a/ovsdb/replication.h +++ b/ovsdb/replication.h @@ -20,6 +20,7 @@ #include struct ovsdb; +struct jsonrpc_session_options; /* Replication module runs when OVSDB server runs in the backup mode. * @@ -47,7 +48,7 @@ struct ovsdb; void replication_set_db(struct ovsdb *, const char *sync_from, const char *exclude_tables, const struct uuid *server, - int probe_interval); + const struct jsonrpc_session_options *); void replication_remove_db(const struct ovsdb *); void replication_run(void); From patchwork Thu Dec 14 01:04:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875934 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDj51MQ1z1ySd for ; Thu, 14 Dec 2023 12:07:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 5AE074372E; Thu, 14 Dec 2023 01:07:19 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 5AE074372E 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 NVFO-gQTrWKH; Thu, 14 Dec 2023 01:07:18 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 10F69437CB; Thu, 14 Dec 2023 01:07:17 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 10F69437CB Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id EB06CC0072; Thu, 14 Dec 2023 01:07:16 +0000 (UTC) X-Original-To: ovs-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 0338BC0037 for ; Thu, 14 Dec 2023 01:07:16 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 33C3A61AD0 for ; Thu, 14 Dec 2023 01:05:35 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 33C3A61AD0 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id iMdFg8pEKGc9 for ; Thu, 14 Dec 2023 01:05:34 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp3.osuosl.org (Postfix) with ESMTPS id 6831661AD2 for ; Thu, 14 Dec 2023 01:05:34 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 6831661AD2 Received: by mail.gandi.net (Postfix) with ESMTPSA id 52FD9240002; Thu, 14 Dec 2023 01:05:32 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:20 +0100 Message-ID: <20231214010431.1664005-19-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 18/22] ovsdb-cs: Add function to set all jsonrpc session options. 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" Allow setting all the options for the source connection, not only the inactivity probe interval. Signed-off-by: Ilya Maximets --- lib/ovsdb-cs.c | 10 ++++++++++ lib/ovsdb-cs.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c index c7c147cc0..b5eda88ad 100644 --- a/lib/ovsdb-cs.c +++ b/lib/ovsdb-cs.c @@ -791,6 +791,16 @@ ovsdb_cs_get_last_error(const struct ovsdb_cs *cs) } } +/* Sets all the JSON-RPC session 'options' for 'cs''s current session. */ +void +ovsdb_cs_set_jsonrpc_options(const struct ovsdb_cs *cs, + const struct jsonrpc_session_options *options) +{ + if (cs->session) { + jsonrpc_session_set_options(cs->session, options); + } +} + /* Sets the "probe interval" for 'cs''s current session to 'probe_interval', in * milliseconds. */ void diff --git a/lib/ovsdb-cs.h b/lib/ovsdb-cs.h index 4cf9ca2b9..bcc3dcd71 100644 --- a/lib/ovsdb-cs.h +++ b/lib/ovsdb-cs.h @@ -32,6 +32,7 @@ #include "openvswitch/uuid.h" struct json; +struct jsonrpc_session_options; struct ovsdb_cs; struct ovsdb_cs_ops { @@ -131,6 +132,8 @@ bool ovsdb_cs_is_alive(const struct ovsdb_cs *); bool ovsdb_cs_is_connected(const struct ovsdb_cs *); int ovsdb_cs_get_last_error(const struct ovsdb_cs *); +void ovsdb_cs_set_jsonrpc_options(const struct ovsdb_cs *, + const struct jsonrpc_session_options *); void ovsdb_cs_set_probe_interval(const struct ovsdb_cs *, int probe_interval); /* Conditional monitoring (specifying that only rows matching particular From patchwork Thu Dec 14 01:04:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875933 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDj005Dnz1ySd for ; Thu, 14 Dec 2023 12:07:16 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A565483C5E; Thu, 14 Dec 2023 01:07:13 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org A565483C5E 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 tD97kBRG1r7u; Thu, 14 Dec 2023 01:07:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 8470183C3E; Thu, 14 Dec 2023 01:07:10 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8470183C3E Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 59A77C0072; Thu, 14 Dec 2023 01:07:10 +0000 (UTC) X-Original-To: ovs-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 279E8C0DCF for ; Thu, 14 Dec 2023 01:07:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id CB042812DE for ; Thu, 14 Dec 2023 01:05:37 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org CB042812DE 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 vHfhBkch79jg for ; Thu, 14 Dec 2023 01:05:37 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp1.osuosl.org (Postfix) with ESMTPS id E395A83518 for ; Thu, 14 Dec 2023 01:05:36 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org E395A83518 Received: by mail.gandi.net (Postfix) with ESMTPSA id CA7B4240004; Thu, 14 Dec 2023 01:05:34 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:21 +0100 Message-ID: <20231214010431.1664005-20-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 19/22] ovsdb: relay: Allow setting all jsonrpc session options. 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" Allow setting all the JSON-RPC session options at once. While at it, allow updating options the same way the source can be updated while calling 'ovsdb_relay_add_db()' if the relay is already configured. Signed-off-by: Ilya Maximets --- ovsdb/ovsdb-server.c | 2 +- ovsdb/relay.c | 6 ++++-- ovsdb/relay.h | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 6eced3896..9726a8d72 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -1017,7 +1017,7 @@ open_db(struct server_config *server_config, if (model == SM_RELAY) { ovsdb_relay_add_db(db->db, conf->source, update_schema, server_config, - conf->options->rpc.probe_interval); + &conf->options->rpc); } if (model == SM_ACTIVE_BACKUP && conf->ab.backup) { const struct uuid *server_uuid; diff --git a/ovsdb/relay.c b/ovsdb/relay.c index 27ff196b7..71a5b8e1c 100644 --- a/ovsdb/relay.c +++ b/ovsdb/relay.c @@ -127,7 +127,8 @@ static struct ovsdb_cs_ops relay_cs_ops = { void ovsdb_relay_add_db(struct ovsdb *db, const char *remote, schema_change_callback schema_change_cb, - void *schema_change_aux, int probe_interval) + void *schema_change_aux, + const struct jsonrpc_session_options *options) { struct relay_ctx *ctx; @@ -138,6 +139,7 @@ ovsdb_relay_add_db(struct ovsdb *db, const char *remote, ctx = shash_find_data(&relay_dbs, db->name); if (ctx) { ovsdb_cs_set_remote(ctx->cs, remote, true); + ovsdb_cs_set_jsonrpc_options(ctx->cs, options); VLOG_DBG("%s: relay source set to '%s'", db->name, remote); return; } @@ -152,7 +154,7 @@ ovsdb_relay_add_db(struct ovsdb *db, const char *remote, shash_add(&relay_dbs, db->name, ctx); ovsdb_cs_set_leader_only(ctx->cs, false); ovsdb_cs_set_remote(ctx->cs, remote, true); - ovsdb_cs_set_probe_interval(ctx->cs, probe_interval); + ovsdb_cs_set_jsonrpc_options(ctx->cs, options); VLOG_DBG("added database: %s, %s", db->name, remote); } diff --git a/ovsdb/relay.h b/ovsdb/relay.h index 218caad65..19cd3ef60 100644 --- a/ovsdb/relay.h +++ b/ovsdb/relay.h @@ -22,6 +22,7 @@ #include "reconnect.h" struct json; +struct jsonrpc_session_options; struct ovsdb; struct ovsdb_schema; struct uuid; @@ -37,7 +38,8 @@ typedef struct ovsdb_error *(*schema_change_callback)( void ovsdb_relay_add_db(struct ovsdb *, const char *remote, schema_change_callback schema_change_cb, - void *schema_change_aux, int probe_interval); + void *schema_change_aux, + const struct jsonrpc_session_options *); void ovsdb_relay_del_db(struct ovsdb *); void ovsdb_relay_run(void); void ovsdb_relay_wait(void); From patchwork Thu Dec 14 01:04:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875935 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDjC6fQSz1ySd for ; Thu, 14 Dec 2023 12:07:27 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id AC581437A1; Thu, 14 Dec 2023 01:07:25 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org AC581437A1 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 NkePbHPRdJ9E; Thu, 14 Dec 2023 01:07:21 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id D48A0436CC; Thu, 14 Dec 2023 01:07:20 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org D48A0436CC Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AF4C3C0072; Thu, 14 Dec 2023 01:07:19 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0B64AC0072 for ; Thu, 14 Dec 2023 01:07:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 06551436DF for ; Thu, 14 Dec 2023 01:05:44 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 06551436DF 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 0WJH3BDn4bM6 for ; Thu, 14 Dec 2023 01:05:40 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by smtp2.osuosl.org (Postfix) with ESMTPS id 6B23A43710 for ; Thu, 14 Dec 2023 01:05:39 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 6B23A43710 Received: by mail.gandi.net (Postfix) with ESMTPSA id 1DEE0240002; Thu, 14 Dec 2023 01:05:36 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:22 +0100 Message-ID: <20231214010431.1664005-21-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 20/22] ovsdb-server: Allow user-provided config files. 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" OVSDB server maintains a temporary file with the current database configuration for the case it is restarted by a monitor process after a crash. On startup the configuration from command line arguments is stored there in a JSON format, also whenever user changes the configuration with different UnixCtl commands, those changes are getting added to the file. When restarted from the crash it reads the configuration from the file and continues with all the necessary remotes and databases. This change allows it to be an external user-provided file that OVSDB server will read the configuration from. The file can be specified with a --config-file command line argument and it is mutually exclusive with most other command line arguments that set up remotes or databases, it is also mutually exclusive with use of appctl commands that modify same configurations, e.g. add/remove-db or add/remove-remote. If the user wants to change the configuration of a running server, they may change the file and call ovsdb-server/reload appctl. OVSDB server will open a file, read and parse it, compare the new configuration with the current one and adjust the running configuration as needed. OVSDB server will try to keep existing databases and connections intact, if the change can be applied without disrupting the normal operation. User-provided files are not trustworthy, so extra checks were added to ensure a correct file format. If the file cannot be correctly parsed, e.g. contains invalid JSON, no changes will be applied and the server will keep using the previous configuration until the next reload. If config-file is provided for active-backup databases, permanent disconnection of one of the backup databases no longer leads to switching all other databases to 'active'. Only the disconnected one will transition, since all of them have their own records in the configuration file. With this change, users can run all types of databases within the same ovsdb-server process at the same time. Simple configuration may look like this: { "remotes": { "punix:db.sock": {}, "pssl:6641": { "inactivity-probe": 16000, "read-only": false, "role": "ovn-controller" } }, "databases": { "conf.db": {}, "sb.db": { "service-model": "clustered" }, "OVN_Northbound": { "service-model": "relay", "source": { "ssl:[fe:::1]:6642,ssl:[fe:::2]:6642": { "max-backoff": 8000, "inactivity-probe": 10000 } } } } } Signed-off-by: Ilya Maximets --- Documentation/ref/ovsdb.7.rst | 86 +++++- Documentation/topics/ovsdb-relay.rst | 19 ++ NEWS | 4 + ovsdb/ovsdb-server.1.in | 96 ++++++- ovsdb/ovsdb-server.c | 384 ++++++++++++++++++++++----- 5 files changed, 513 insertions(+), 76 deletions(-) diff --git a/Documentation/ref/ovsdb.7.rst b/Documentation/ref/ovsdb.7.rst index 84b153d24..42e5f4089 100644 --- a/Documentation/ref/ovsdb.7.rst +++ b/Documentation/ref/ovsdb.7.rst @@ -155,6 +155,22 @@ standalone database, configure the server to listen on a "connection method" that the client can reach, then point the client to that connection method. See `Connection Methods`_ below for information about connection methods. +Open vSwitch 3.3 introduced support for configuration files via +``--config-file`` command line option. The configuration file for a server +with a **standalone** database may look like this:: + + { + "remotes": { "": {} }, + "databases": { + "": { + "service-model": "standalone" + } + } + } + +The ``"service-model"`` key can be omitted. In this case ``ovsdb-server`` +will infer the service model from the database file itself. + Active-Backup Database Service Model ------------------------------------ @@ -177,10 +193,36 @@ database file from the active server. Then use connects to the active server. At that point, the backup server will fetch a copy of the active database and keep it up-to-date until it is killed. +Open vSwitch 3.3 introduced support for configuration files via +``--config-file`` command line option. The configuration file for a backup +server in this case may look like this:: + + { + "remotes": { "": {} }, + "databases": { + "": { + "service-model": "active-backup", + "backup": true, + "source": { + "": { + "inactivity-probe": , + "max-backoff": + } + } + } + } + } + +All the fields in the ``""`` description above are required. +Options for the ``""`` connection method (``"inactivity-probe"``, etc.) +can be omitted. + When the active server in an active-backup server pair fails, an administrator can switch the backup server to an active role with the ``ovs-appctl`` command ``ovsdb-server/disconnect-active-ovsdb-server``. Clients then have read/write -access to the now-active server. Of course, administrators are slow to respond +access to the now-active server. When the ``--config-file`` is in use, the +same can be achieved by changing the ``"backup"`` value in the file and running +``ovsdb-server/reload`` command. Of course, administrators are slow to respond compared to software, so in practice external management software detects the active server's failure and changes the backup server's role. For example, the "Integration Guide for Centralized Control" in the OVN documentation describes @@ -236,6 +278,22 @@ To set up a clustered database, first initialize it on a single node by running arguments, the ``create-cluster`` command can create an empty database or copy a standalone database's contents into the new database. +Open vSwitch 3.3 introduced support for configuration files via +``--config-file`` command line option. The configuration file for a server +with a **clustered** database may look like this:: + + { + "remotes": { "": {} }, + "databases": { + "": { + "service-model": "clustered" + } + } + } + +The ``"service-model"`` key can be omitted. In this case ``ovsdb-server`` +will infer the service model from the database file itself. + To configure a client to use a clustered database, first configure all of the servers to listen on a connection method that the client can reach, then point the client to all of the servers' connection methods, comma-separated. See @@ -505,6 +563,29 @@ server. ```` could contain a comma-separated list of connection methods, e.g. to connect to any server of the clustered database. Multiple relay servers could be started for the same relay source. +Open vSwitch 3.3 introduced support for configuration files via +``--config-file`` command line option. The configuration file for a relay +database server in this case may look like this:: + + { + "remotes": { "": {} }, + "databases": { + "": { + "service-model": "relay", + "source": { + "": { + "inactivity-probe": , + "max-backoff": + } + } + } + } + } + +Both the ``"service-model"`` and the ``"source"`` are required. Options for +the ``""`` connection method (``"inactivity-probe"``, etc.) +can be omitted. + Since the way relays handle read and write transactions is very similar to the clustered model where "cluster" means "set of relay servers connected to the same relay source", "follower" means "relay server" and the "leader" @@ -629,7 +710,8 @@ Creating a Database Creating and starting up the service for a new database was covered separately for each database service model in the `Service -Models`_ section, above. +Models`_ section, above. Single ``ovsdb-server`` process may serve +any number of databases with different service models at the same time. Backing Up and Restoring a Database ----------------------------------- diff --git a/Documentation/topics/ovsdb-relay.rst b/Documentation/topics/ovsdb-relay.rst index 50a3c6d07..63ea5329b 100644 --- a/Documentation/topics/ovsdb-relay.rst +++ b/Documentation/topics/ovsdb-relay.rst @@ -105,6 +105,25 @@ started like this:: $ ... $ ovsdb-server --remote=ptcp:6642:172.16.0.K relay:OVN_Southbound:$REMOTES +Open vSwitch 3.3 introduced support for configuration files via +``--config-file`` command line option. The configuration file for a relay +database servers in this case may look like this:: + + { + "remotes": { "ptcp:6642:172.16.0.X": {} }, + "databases": { + "OVN_Southbound": { + "service-model": "relay", + "source": { + "$REMOTES": {} + } + } + } + } + +See ``ovsdb-server(1)`` and ``Relay Service Model`` in ``ovsdb(7)`` for more +configuration options. + Every relay server could connect to any of the cluster members of their choice, fairness of load distribution is achieved by shuffling remotes. diff --git a/NEWS b/NEWS index 63f2842ae..977e88174 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ Post-v3.2.0 from older version is supported but it may trigger more leader elections during the process, and error logs complaining unrecognized fields may be observed on old nodes. + * New command line option --config-file that allows a fine control over + remotes and database configuration, including setting options for + connection methods for relays and active-backup replication. + For more details see ovsdb-server(1) and ovsdb(7). - ovs-appctl: * 'ofproto/trace' now reports OpenFlow rules that make up a conjunctive flow match. diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in index da7a6fd5d..91d6a6e0f 100644 --- a/ovsdb/ovsdb-server.1.in +++ b/ovsdb/ovsdb-server.1.in @@ -12,6 +12,7 @@ ovsdb\-server \- Open vSwitch database server [\fIdatabase\fR]\&... [\fIrelay:schema_name:remote\fR]\&... [\fB\-\-remote=\fIremote\fR]\&... +[\fB\-\-config\-file=\fIfile\fR] [\fB\-\-run=\fIcommand\fR] .so lib/daemon-syn.man .so lib/service-syn.man @@ -44,6 +45,11 @@ If none of database files or relay databases is specified, the default is initialized using, for example, \fBovsdb\-tool\fR's \fBcreate\fR, \fBcreate\-cluster\fR, or \fBjoin\-cluster\fR command. .PP +All types of databases can alternatively be added using a configuration +file provided via \fB\-\-config\-file\fR option. This option is mutually +exclusive with specifying \fIdatabase\fR on the command line. For a detailed +description of a configuration file format see \fBovsdb\fR(7). +.PP This OVSDB implementation supports standalone, active-backup, relay and clustered database service models, as well as database replication. See the Service Models section of \fBovsdb\fR(7) for more information. @@ -105,6 +111,74 @@ It is an error for \fIcolumn\fR to have another type. .IP To connect or listen on multiple connection methods, use multiple \fB\-\-remote\fR options. +.IP +Alternatively, remotes can be specified in a "remotes" section of a +configuration file, if provided using \fB\-\-config\-file\fR option. +\fB\-\-config\-file\fR and \fB\-\-remote\fR options are mutually +exclusive. +. +.IP "\fB\-\-config-file=\fIfile\fR" +Specifies a configuration file for \fBovsdb\-server\fR. This \fIfile\fR +can contain connection methods and databases used by the server. +The \fIfile\fR contains a JSON object with two main elements: +.RS +.IP "\fBremotes\fR" +JSON object that contains a set of connection methods in a following format: +"\fItarget\fR": { "\fIoption\fR": \fIvalue\fR, ... }. Where \fItarget\fR +is in the same format as \fIremote\fR in \fB\-\-remote\fR option. +\fIoption\fR can be \fBmax-backoff\fR (integer), \fBinactivity-probe\fR +(integer), \fBread-only\fR (boolean), \fBrole\fR (string) or \fBdscp\fR +(integer) with their allowed \fIvalue\fRs respectively. The meaning of these +\fIoption\fRs is the same as in configuration of \fIremote\fR via a database +row with \fB\-\-remote\fR option. +.IP "\fBdatabases\fR" +JSON object that describes databases that should be added to the +\fBovsdb\-server\fR in the following format: "\fIname\fR":{ "\fIoption\fR": +\fIvalue\fR, ... }. Where \fIname\fR is either a file name of a previously +created and initialized database or a schema name in case of relay +databases. Available \fIoption\fRs are: +.RS +.IP "\fBservice-model\fR (string)" +Describes the service model of this database. One of: \fBstandalone\fR, +\fBclustered\fR, \fBactive-backup\fR or \fBrelay\fR. This option is +required for all types, except for standalone and clustered. For these +databases the service model will be inferred from the file, if not +specified explicitly. \fBovsdb-server\fR will refuse to add a database +if the specified \fBservice-model\fR doesn't match with the provided file. +.IP "\fBsource\fR (JSON object; active-backup or relay)" +Describes the connection method to the active database or to the relay +source. It is a JSON object with exactly one element in the same format +as elements of "\fBremotes\fR", except that \fBread-only\fR and \fBrole\fR +options are not applicable. E.g. \fB"source": { "unix:db.sock": { +"inactivity-probe": 10000, "max-backoff": 8000 } }\fR +.IP "\fBbackup\fR (boolean; active-backup only)" +If set to \fBtrue\fR, \fBovsdb-server\fR will use this database as a +backup for the specified \fBsource\fR. Will be served as an active +database otherwise. +.IP "\fBexclude-tables\fR (JSON array of strings; active-backup only)" +List of table names that should be excluded from replication in backup mode, +e.g. \fB"exclude-tables": [ "Table_One", "Table_Two" ]\fR. +.RE +.RE +.IP +Content of the most basic configuration file may look like this: +\fB{ "remotes": { "pssl:6640": {} }, "databases": { "conf.db": {} } }\fR +.IP +Examples of configuration files for different service models can be +found in in \fBovsdb\fR(7). +.IP +\fB\-\-config-file\fR option is mutually exclusive with \fB\-\-remote\fR +as well as with specifying \fIdatabase\fR on a command line. It is also +mutually exclusive with all the \fBActive-Backup Options\fR and all the +\fBRUNTIME MANAGEMENT COMMANDS\fR that can change the configuration of +the server in conflict with the content of the file, i.e. all the commands +that manipulate with remotes and databases. Read-only commands can still +be used. +.IP +In case of changes in the \fIfile\fR, users should run +\fBovsdb-server/reload\fR command with \fBovs-appctl\fR(8) in order for +changes to take effect. +.RE . .IP "\fB\-\-run=\fIcommand\fR]" Ordinarily \fBovsdb\-server\fR runs forever, or until it is told to @@ -178,6 +252,8 @@ allow the syncing options to be specified using command line options, yet start the server, as the default, active server. To switch the running server to backup mode, use \fBovs-appctl(1)\fR to execute the \fBovsdb\-server/connect\-active\-ovsdb\-server\fR command. +.PP +These options are mutually exclusive with \fB\-\-config\-file\fR. .SS "Public Key Infrastructure Options" The options described below for configuring the SSL public key infrastructure accept a special syntax for obtaining their @@ -230,6 +306,8 @@ clients. Adds a remote, as if \fB\-\-remote=\fIremote\fR had been specified on the \fBovsdb\-server\fR command line. (If \fIremote\fR is already a remote, this command succeeds without changing the configuration.) +.IP +Mutually exclusive with \fB\-\-config\-file\fR option. . .IP "\fBovsdb\-server/remove\-remote \fIremote\fR" Removes the specified \fIremote\fR from the configuration, failing @@ -241,6 +319,8 @@ configuring a \fBdb:\fIdb\fB,\fItable\fB,\fIcolumn\fR remote. (You can remove a database source with \fBovsdb\-server/remove\-remote \fBdb:\fIdb\fB,\fItable\fB,\fIcolumn\fR, but not individual remotes found indirectly through the database.) +.IP +Mutually exclusive with \fB\-\-config\-file\fR option. . .IP "\fBovsdb\-server/list\-remotes" Outputs a list of the currently configured remotes named on @@ -254,6 +334,8 @@ Adds the \fIdatabase\fR to the running \fBovsdb\-server\fR. \fIdatabase\fR could be a database file or a relay description in the following format: \fIrelay:schema_name:remote\fR. The database file must already have been created and initialized using, for example, \fBovsdb\-tool create\fR. +.IP +Mutually exclusive with \fB\-\-config\-file\fR option. . .IP "\fBovsdb\-server/remove\-db \fIdatabase\fR" Removes \fIdatabase\fR from the running \fBovsdb\-server\fR. \fIdatabase\fR @@ -268,6 +350,8 @@ Any public key infrastructure options specified through this database (e.g. \fB\-\-private\-key=db:\fIdatabase,\fR... on the command line) will be disabled until another database with the same name is added again (with \fBovsdb\-server/add\-db\fR). +.IP +Mutually exclusive with \fB\-\-config\-file\fR option. . .IP "\fBovsdb\-server/list\-dbs" Outputs a list of the currently configured databases added either through @@ -286,6 +370,9 @@ These commands query and update the role of \fBovsdb\-server\fR within an active-backup pair of servers. See \fBActive-Backup Options\fR, above, and \fBActive-Backup Database Service Model\fR in \fBovsdb\fR(7) for more information. +.PP +All \fBActive-Backup Commands\fR that change the state of \fBovsdb\-server\fR +are mutually exclusive with \fB\-\-config\-file\fR option. . .IP "\fBovsdb\-server/set\-active\-ovsdb\-server \fIserver" Sets the active \fIserver\fR from which \fBovsdb\-server\fR connects through @@ -324,11 +411,10 @@ Gets the tables that are currently excluded from synchronization. Prints a summary of replication run time information. The \fBstate\fR information is always provided, indicating whether the server is running in the \fIactive\fR or the \fIbackup\fR mode. -When running in backup mode, replication connection status, which -can be either \fIconnecting\fR, \fIreplicating\fR or \fIerror\fR, are shown. -When the connection is in \fIreplicating\fR state, further output shows -the list of databases currently replicating, and the tables that are -excluded. +For all databases with active-backup service model, replication connection +status, which can be either \fIconnecting\fR, \fIreplicating\fR or +\fIerror\fR, are shown. When the connection is in \fIreplicating\fR state, +further output shows the tables that are currently excluded from replication. . .SS "Cluster Commands" These commands support the \fBovsdb\-server\fR clustered service model. diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 9726a8d72..05b91a197 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -195,6 +195,13 @@ static void add_server_db(struct server_config *); static void remove_db(struct server_config *, struct shash_node *db, char *); static void close_db(struct server_config *, struct db *, char *); +static struct ovsdb_error *update_schema(struct ovsdb *, + const struct ovsdb_schema *, + const struct uuid *txnid, + bool conversion_with_no_data, + void *aux) + OVS_WARN_UNUSED_RESULT; + static void parse_options(int argc, char *argvp[], struct shash *db_conf, struct shash *remotes, char **unixctl_pathp, char **run_command, @@ -223,7 +230,7 @@ static void save_config__(FILE *config_file, const struct shash *remotes, const char *sync_from, const char *sync_exclude, bool is_backup); static void save_config(struct server_config *); -static void load_config(FILE *config_file, struct shash *remotes, +static bool load_config(FILE *config_file, struct shash *remotes, struct shash *db_conf, char **sync_from, char **sync_exclude, bool *is_backup); @@ -263,8 +270,9 @@ ovsdb_server_replication_run(struct server_config *config) } /* If one connection is broken, switch all databases to active, - * since they are configured via the same command line / appctl. */ - if (!all_alive && *config->is_backup) { + * if they are configured via the command line / appctl and so have + * shared configuration. */ + if (!config_file_path && !all_alive && *config->is_backup) { *config->is_backup = false; SHASH_FOR_EACH (node, config->all_dbs) { @@ -513,6 +521,196 @@ free_database_configs(struct shash *db_conf) shash_clear(db_conf); } +static bool +service_model_can_convert(enum service_model a, enum service_model b) +{ + ovs_assert(a != SM_UNDEFINED); + + if (a == b) { + return true; + } + + if (b == SM_UNDEFINED) { + return a == SM_STANDALONE || a == SM_CLUSTERED; + } + + /* Conversion can happen only between standalone and active-backup. */ + return (a == SM_STANDALONE && b == SM_ACTIVE_BACKUP) + || (a == SM_ACTIVE_BACKUP && b == SM_STANDALONE); +} + +static void +database_update_config(struct server_config *server_config, + struct db *db, const struct db_config *new_conf) +{ + struct db_config *conf = db->config; + enum service_model model = conf->model; + + /* Stop replicating when transitioning to active or standalone. */ + if (conf->model == SM_ACTIVE_BACKUP && conf->ab.backup + && (new_conf->model == SM_STANDALONE || !new_conf->ab.backup)) { + ovsdb_server_replication_remove_db(db); + } + + db_config_destroy(conf); + conf = db->config = db_config_clone(new_conf); + + if (conf->model == SM_UNDEFINED) { + /* We're operating on the same file, the model is the same. */ + conf->model = model; + } + + if (conf->model == SM_RELAY) { + ovsdb_relay_add_db(db->db, conf->source, update_schema, server_config, + &conf->options->rpc); + } + if (conf->model == SM_ACTIVE_BACKUP && conf->ab.backup) { + const struct uuid *server_uuid; + + server_uuid = ovsdb_jsonrpc_server_get_uuid(server_config->jsonrpc); + replication_set_db(db->db, conf->source, conf->ab.sync_exclude, + server_uuid, &conf->options->rpc); + } +} + +static bool +reconfigure_databases(struct server_config *server_config, + struct shash *db_conf) +{ + struct db_config *cur_conf, *new_conf; + struct shash_node *node, *conf_node; + bool res = true; + struct db *db; + + /* Remove databases that are no longer in the configuration or have + * incompatible configuration. Update compatible ones. */ + SHASH_FOR_EACH_SAFE (node, server_config->all_dbs) { + db = node->data; + + if (node->name[0] == '_') { + /* Skip internal databases. */ + continue; + } + + cur_conf = db->config; + conf_node = shash_find(db_conf, db->filename); + new_conf = conf_node ? conf_node->data : NULL; + + if (!new_conf) { + remove_db(server_config, node, + xasprintf("database %s removed from configuration", + node->name)); + continue; + } + if (!service_model_can_convert(cur_conf->model, new_conf->model)) { + remove_db(server_config, node, + xasprintf("service model changed for database %s", + node->name)); + continue; + } + database_update_config(server_config, db, new_conf); + + db_config_destroy(new_conf); + shash_delete(db_conf, conf_node); + } + + /* Create new databases. */ + SHASH_FOR_EACH (node, db_conf) { + struct ovsdb_error *error = open_db(server_config, + node->name, node->data); + if (error) { + char *s = ovsdb_error_to_string_free(error); + + VLOG_WARN("failed to open database '%s': %s", node->name, s); + free(s); + res = false; + } + db_config_destroy(node->data); + } + shash_clear(db_conf); + + return res; +} + +static bool +reconfigure_ovsdb_server(struct server_config *server_config) +{ + char *sync_from = NULL, *sync_exclude = NULL; + bool is_backup = false; + struct shash remotes; + struct shash db_conf; + bool res = true; + + FILE *file = NULL; + + if (config_file_path) { + file = fopen(config_file_path, "r+b"); + if (!file) { + VLOG_ERR("failed to open configuration file '%s': %s", + config_file_path, ovs_strerror(errno)); + return false; + } else { + VLOG_INFO("loading configuration from '%s'", config_file_path); + } + } else { + file = server_config->config_tmpfile; + } + ovs_assert(file); + + shash_init(&remotes); + shash_init(&db_conf); + + if (!load_config(file, &remotes, &db_conf, + &sync_from, &sync_exclude, &is_backup)) { + if (config_file_path) { + VLOG_WARN("failed to load configuration from %s", + config_file_path); + } else { + VLOG_FATAL("failed to load configuration from a temporary file"); + } + res = false; + goto exit_close; + } + + /* Parsing was successful. Update the server configuration. */ + shash_swap(server_config->remotes, &remotes); + free(*server_config->sync_from); + *server_config->sync_from = sync_from; + free(*server_config->sync_exclude); + *server_config->sync_exclude = sync_exclude; + *server_config->is_backup = is_backup; + + if (!reconfigure_databases(server_config, &db_conf)) { + VLOG_WARN("failed to configure databases"); + res = false; + } + + char *error = reconfigure_remotes(server_config->jsonrpc, + server_config->all_dbs, + server_config->remotes); + if (error) { + VLOG_WARN("failed to configure remotes: %s", error); + res = false; + } else { + error = reconfigure_ssl(server_config->all_dbs); + if (error) { + VLOG_WARN("failed to configure SSL: %s", error); + res = false; + } + } + free(error); + +exit_close: + if (config_file_path) { + fclose(file); + } + free_remotes(&remotes); + free_database_configs(&db_conf); + shash_destroy(&remotes); + shash_destroy(&db_conf); + return res; +} + int main(int argc, char *argv[]) { @@ -527,13 +725,22 @@ main(int argc, char *argv[]) struct process *run_process; bool exiting; int retval; - FILE *config_tmpfile; - struct server_config server_config; + FILE *config_tmpfile = NULL; struct shash all_dbs; struct shash_node *node; int replication_probe_interval = REPLICATION_DEFAULT_PROBE_INTERVAL; int relay_source_probe_interval = RELAY_SOURCE_DEFAULT_PROBE_INTERVAL; + struct server_config server_config = { + .remotes = &remotes, + .all_dbs = &all_dbs, + .sync_from = &sync_from, + .sync_exclude = &sync_exclude, + .is_backup = &is_backup, + .replication_probe_interval = &replication_probe_interval, + .relay_source_probe_interval = &relay_source_probe_interval, + }; + ovs_cmdl_proctitle_init(argc, argv); set_program_name(argv[0]); service_start(&argc, &argv); @@ -548,64 +755,39 @@ main(int argc, char *argv[]) daemon_become_new_user(false, false); - /* Create and initialize 'config_tmpfile' as a temporary file to hold - * ovsdb-server's most basic configuration, and then save our initial - * configuration to it. When --monitor is used, this preserves the effects - * of ovs-appctl commands such as ovsdb-server/add-remote (which saves the - * new configuration) across crashes. */ - config_tmpfile = tmpfile(); - if (!config_tmpfile) { - ovs_fatal(errno, "failed to create temporary file"); + if (!config_file_path) { + /* Create and initialize 'config_tmpfile' as a temporary file to hold + * ovsdb-server's most basic configuration, and then save our initial + * configuration to it. When --monitor is used, this preserves the + * effects of ovs-appctl commands such as ovsdb-server/add-remote + * (which saves the new configuration) across crashes. */ + config_tmpfile = tmpfile(); + if (!config_tmpfile) { + ovs_fatal(errno, "failed to create temporary file"); + } + server_config.config_tmpfile = config_tmpfile; + save_config__(config_tmpfile, &remotes, &db_conf, sync_from, + sync_exclude, is_backup); } - server_config.remotes = &remotes; - server_config.config_tmpfile = config_tmpfile; - - save_config__(config_tmpfile, &remotes, &db_conf, sync_from, - sync_exclude, is_backup); free_remotes(&remotes); free_database_configs(&db_conf); daemonize_start(false, false); - /* Load the saved config. */ - load_config(config_tmpfile, &remotes, &db_conf, &sync_from, - &sync_exclude, &is_backup); - - /* Start ovsdb jsonrpc server. When running as a backup server, - * jsonrpc connections are read only. Otherwise, both read - * and write transactions are allowed. */ - jsonrpc = ovsdb_jsonrpc_server_create(is_backup); + perf_counters_init(); - shash_init(&all_dbs); - server_config.all_dbs = &all_dbs; + /* Start ovsdb jsonrpc server. Both read and write transactions are + * allowed by default, individual remotes and databases will be configured + * as read-only, if necessary. */ + jsonrpc = ovsdb_jsonrpc_server_create(false); server_config.jsonrpc = jsonrpc; - server_config.sync_from = &sync_from; - server_config.sync_exclude = &sync_exclude; - server_config.is_backup = &is_backup; - server_config.replication_probe_interval = &replication_probe_interval; - server_config.relay_source_probe_interval = &relay_source_probe_interval; - - perf_counters_init(); - SHASH_FOR_EACH (node, &db_conf) { - struct ovsdb_error *error = open_db(&server_config, - node->name, node->data); - if (error) { - char *s = ovsdb_error_to_string_free(error); - ovs_fatal(0, "%s", s); - } - db_config_destroy(node->data); - } - shash_clear(&db_conf); + shash_init(&all_dbs); add_server_db(&server_config); - char *error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes); - if (!error) { - error = reconfigure_ssl(&all_dbs); - } - if (error) { - ovs_fatal(0, "%s", error); + if (!reconfigure_ovsdb_server(&server_config)) { + ovs_fatal(0, "server configuration failed"); } retval = unixctl_server_create(unixctl_path, &unixctl); @@ -2057,14 +2239,21 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED, * 'config_file_path', read it and sync the runtime configuration with it. */ static void ovsdb_server_reload(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *config_ OVS_UNUSED) + const char *argv[] OVS_UNUSED, void *config_) { + struct server_config *config = config_; + if (!config_file_path) { unixctl_command_reply_error(conn, "Configuration file was not specified on command line"); - } else { + return; + } + + if (!reconfigure_ovsdb_server(config)) { unixctl_command_reply_error(conn, - "Configuration file support is not implemented yet"); + "Configuration failed. See the log file for details."); + } else { + unixctl_command_reply(conn, NULL); } } @@ -2739,6 +2928,10 @@ save_config(struct server_config *config) struct shash_node *node; struct shash db_conf; + if (config_file_path) { + return; + } + shash_init(&db_conf); SHASH_FOR_EACH (node, config->all_dbs) { struct db *db = node->data; @@ -2755,7 +2948,7 @@ save_config(struct server_config *config) shash_destroy(&db_conf); } -static void +static bool remotes_from_json(struct shash *remotes, const struct json *json) { struct ovsdb_jsonrpc_options *options; @@ -2765,14 +2958,31 @@ remotes_from_json(struct shash *remotes, const struct json *json) free_remotes(remotes); ovs_assert(json); - ovs_assert(json->type == JSON_OBJECT); + if (json->type == JSON_NULL) { + return true; + } + if (json->type != JSON_OBJECT) { + VLOG_WARN("config: 'remotes' is not a JSON object"); + return false; + } object = json_object(json); SHASH_FOR_EACH (node, object) { options = ovsdb_jsonrpc_default_options(node->name); - ovsdb_jsonrpc_options_update_from_json(options, node->data, false); shash_add(remotes, node->name, options); + + json = node->data; + if (json->type == JSON_OBJECT) { + ovsdb_jsonrpc_options_update_from_json(options, node->data, false); + } else if (json->type != JSON_NULL) { + VLOG_WARN("%s: JSON-RPC options are not a JSON object or null", + node->name); + free_remotes(remotes); + return false; + } } + + return true; } static struct db_config * @@ -2783,6 +2993,12 @@ db_config_from_json(const char *name, const struct json *json) struct ovsdb_parser parser; struct ovsdb_error *error; + ovs_assert(json); + if (json->type == JSON_NULL) { + conf->model = SM_UNDEFINED; + return conf; + } + ovsdb_parser_init(&parser, json, "database %s", name); model = ovsdb_parser_member(&parser, "service-model", @@ -2859,7 +3075,7 @@ db_config_from_json(const char *name, const struct json *json) } -static void +static bool databases_from_json(struct shash *db_conf, const struct json *json) { const struct shash_node *node; @@ -2868,7 +3084,12 @@ databases_from_json(struct shash *db_conf, const struct json *json) free_database_configs(db_conf); ovs_assert(json); - ovs_assert(json->type == JSON_OBJECT); + if (json->type == JSON_NULL) { + return true; + } + if (json->type != JSON_OBJECT) { + VLOG_WARN("config: 'databases' is not a JSON object or null"); + } object = json_object(json); SHASH_FOR_EACH (node, object) { @@ -2876,13 +3097,19 @@ databases_from_json(struct shash *db_conf, const struct json *json) if (conf) { shash_add(db_conf, node->name, conf); + } else { + free_database_configs(db_conf); + return false; } } + return true; } -/* Clears and replaces 'remotes' and 'dbnames' by a configuration read from - * 'config_file', which must have been previously written by save_config(). */ -static void +/* Clears and replaces 'remotes' and 'db_conf' by a configuration read from + * 'config_file', which must have been previously written by save_config() + * or provided by the user with --config-file. + * Returns 'true', if parsing was successful, 'false' otherwise. */ +static bool load_config(FILE *config_file, struct shash *remotes, struct shash *db_conf, char **sync_from, char **sync_exclude, bool *is_backup) @@ -2890,17 +3117,34 @@ load_config(FILE *config_file, struct shash *remotes, struct json *json; if (fseek(config_file, 0, SEEK_SET) != 0) { - VLOG_FATAL("seek failed in temporary file (%s)", ovs_strerror(errno)); + VLOG_WARN("config: file seek failed (%s)", ovs_strerror(errno)); + return false; } json = json_from_stream(config_file); if (json->type == JSON_STRING) { - VLOG_FATAL("reading json failed (%s)", json_string(json)); + VLOG_WARN("config: reading JSON failed (%s)", json_string(json)); + json_destroy(json); + return false; + } + if (json->type != JSON_OBJECT) { + VLOG_WARN("configuration in a file must be a JSON object"); + json_destroy(json); + return false; } - ovs_assert(json->type == JSON_OBJECT); - remotes_from_json(remotes, shash_find_data(json_object(json), "remotes")); - databases_from_json(db_conf, - shash_find_data(json_object(json), "databases")); + if (!remotes_from_json(remotes, + shash_find_data(json_object(json), "remotes"))) { + VLOG_WARN("config: failed to parse 'remotes'"); + json_destroy(json); + return false; + } + if (!databases_from_json(db_conf, shash_find_data(json_object(json), + "databases"))) { + VLOG_WARN("config: failed to parse 'databases'"); + free_remotes(remotes); + json_destroy(json); + return false; + } struct json *string; string = shash_find_data(json_object(json), "sync_from"); @@ -2911,7 +3155,9 @@ load_config(FILE *config_file, struct shash *remotes, free(*sync_exclude); *sync_exclude = string ? xstrdup(json_string(string)) : NULL; - *is_backup = json_boolean(shash_find_data(json_object(json), "is_backup")); + struct json *boolean = shash_find_data(json_object(json), "is_backup"); + *is_backup = boolean ? json_boolean(boolean) : false; json_destroy(json); + return true; } From patchwork Thu Dec 14 01:04:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875936 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDjb6hZBz1ySd for ; Thu, 14 Dec 2023 12:07:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 98ECE42201; Thu, 14 Dec 2023 01:07:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 98ECE42201 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 vJIwu16HPEPA; Thu, 14 Dec 2023 01:07:42 +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 EF4B34220D; Thu, 14 Dec 2023 01:07:29 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org EF4B34220D Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BA0ABC0072; Thu, 14 Dec 2023 01:07:29 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 213D2C0072 for ; Thu, 14 Dec 2023 01:07:29 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 614B1436DC for ; Thu, 14 Dec 2023 01:05:45 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 614B1436DC 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 rf3JuXPG-BZN for ; Thu, 14 Dec 2023 01:05:42 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp2.osuosl.org (Postfix) with ESMTPS id 39C7F436E4 for ; Thu, 14 Dec 2023 01:05:42 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 39C7F436E4 Received: by mail.gandi.net (Postfix) with ESMTPSA id 10463240004; Thu, 14 Dec 2023 01:05:39 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:23 +0100 Message-ID: <20231214010431.1664005-22-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 21/22] tests: ovsdb: Add relay and replication execution with config file. 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" Basic relay and active-backup command execution tests extended to run some copies of ovsdb-server processes with --config-file. Signed-off-by: Ilya Maximets --- tests/ovsdb-server.at | 123 +++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 45aa80cd6..488dfc36f 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -1593,12 +1593,30 @@ m4_define([OVSDB_CHECK_EXECUTION_RELAY], ], [0], [ignore], [ignore]) for i in $(seq 2 ${n_servers}); do - AT_CHECK([ovsdb-server --detach --no-chdir dnl - --log-file=ovsdb-server$i.log dnl - --pidfile=${i}.pid --remote=punix:db${i}.sock dnl - --unixctl=unixctl${i} -vjsonrpc:file:dbg dnl - relay:${schema_name}:unix:db$((i-1)).sock - ], [0], [ignore], [ignore]) + dnl Run every second relay with a config file. + if test $(expr $i % 2) -eq 0; then + echo "{ + \"remotes\": { \"punix:db${i}.sock\": {} }, + \"databases\": { + \"${schema_name}\": { + \"service-model\": \"relay\", + \"source\": { \"unix:db$((i-1)).sock\": {} } + } + } + }" > config${i}.json + AT_CHECK([ovsdb-server --detach --no-chdir --pidfile=${i}.pid \ + --log-file=ovsdb-server$i.log \ + --unixctl=unixctl${i} -vjsonrpc:file:dbg \ + --config-file=config${i}.json + ], [0], [ignore], [ignore]) + else + AT_CHECK([ovsdb-server --detach --no-chdir \ + --log-file=ovsdb-server$i.log \ + --pidfile=${i}.pid --remote=punix:db${i}.sock \ + --unixctl=unixctl${i} -vjsonrpc:file:dbg \ + relay:${schema_name}:unix:db$((i-1)).sock + ], [0], [ignore], [ignore]) + fi done m4_foreach([txn], [$4], @@ -1645,13 +1663,14 @@ AT_BANNER([OVSDB -- ovsdb-server replication]) # OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS]) # -# Creates two databases with the given SCHEMA, and starts an ovsdb-server on +# Creates three databases with the given SCHEMA, and starts an ovsdb-server on # each database. # Runs each of the TRANSACTIONS (which should be a quoted list of # quoted strings) against one of the servers with ovsdb-client one at a -# time. The server replicates its database to the other ovsdb-server. +# time. The server replicates its database to the other two ovsdb-servers, +# one of which is configured via command line and the other via --config-file. # -# Checks that the dump of both databases are the same. +# Checks that the dump of all databases are the same. # # TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS. m4_define([OVSDB_CHECK_EXECUTION], @@ -1660,22 +1679,43 @@ m4_define([OVSDB_CHECK_EXECUTION], $2 > schema AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore]) AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore]) - - on_exit 'kill `cat *.pid`' - AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore]) - i - - AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=2.pid --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock db2], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-tool create db3 schema], [0], [stdout], [ignore]) + + on_exit 'kill $(cat *.pid)' + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server1.log \ + --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore]) + + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server2.log \ + --pidfile=2.pid --remote=punix:db2.sock --unixctl=unixctl2 \ + --sync-from=unix:db.sock db2], [0], [ignore], [ignore]) + + AT_DATA([config3.json], [ + { + "remotes": { "punix:db3.sock": {} }, + "databases": { + "db3": { + "service-model": "active-backup", + "backup": true, + "source": { "unix:db.sock": {} } + } + } + } +]) + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server3.log \ + --pidfile=3.pid --unixctl=unixctl3 --config-file=config3.json], + [0], [ignore], [ignore]) m4_foreach([txn], [$3], [AT_CHECK([ovsdb-client transact 'txn'], [0], [stdout], [ignore]) ]) AT_CHECK([ovsdb-client dump], [0], [stdout], [ignore]) - OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock > dump2; diff stdout dump2]) + OVS_WAIT_UNTIL([ ovsdb-client dump unix:db2.sock > dump2; diff -u stdout dump2]) + OVS_WAIT_UNTIL([ ovsdb-client dump unix:db3.sock > dump3; diff -u stdout dump3]) OVSDB_SERVER_SHUTDOWN OVSDB_SERVER_SHUTDOWN2 + OVSDB_SERVER_SHUTDOWN_N([3]) AT_CLEANUP]) EXECUTION_EXAMPLES @@ -1684,19 +1724,22 @@ AT_BANNER([OVSDB -- ovsdb-server replication table-exclusion]) # OVSDB_CHECK_REPLICATION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS]) # -# Creates two databases with the given SCHEMA, and starts an +# Creates three databases with the given SCHEMA, and starts an # ovsdb-server on each database. # Runs each of the TRANSACTIONS (which should be a quoted list of # quoted strings) against one of the servers with ovsdb-client one at a -# time. The server replicates its database to the other ovsdb-server. +# time. The server replicates its database to the other two ovsdb-servers, +# one of which is configured via command line and the other via --config-file. # -# Checks that the difference between the dump of the databases is -# OUTPUT, but UUIDs in the output are replaced by markers of the form -# where N is a number. The first unique UUID is replaced by <0>, +# Checks that the difference between the dump of the first and the other two +# databases is OUTPUT, but UUIDs in the output are replaced by markers of the +# form where N is a number. The first unique UUID is replaced by <0>, # the next by <1>, and so on. # If a given UUID appears more than once it is always replaced by the # same marker. # +# Also checks that the dumps of the second and third databases are the same. +# # TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS. m4_define([OVSDB_CHECK_REPLICATION], [AT_SETUP([$1]) @@ -1705,11 +1748,33 @@ m4_define([OVSDB_CHECK_REPLICATION], $2 > schema AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore]) AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore]) - - on_exit 'kill `cat *.pid`' - AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore]) - - AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile=2.pid --remote=punix:db2.sock --unixctl=unixctl2 --sync-from=unix:db.sock --sync-exclude-tables=mydb:b db2], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-tool create db3 schema], [0], [stdout], [ignore]) + + on_exit 'kill $(cat *.pid)' + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server1.log \ + --pidfile --remote=punix:db.sock db1], [0], [ignore], [ignore]) + + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server2.log \ + --pidfile=2.pid --remote=punix:db2.sock --unixctl=unixctl2 \ + --sync-from=unix:db.sock --sync-exclude-tables=mydb:b db2], + [0], [ignore], [ignore]) + + AT_DATA([config3.json], [ + { + "remotes": { "punix:db3.sock": {} }, + "databases": { + "db3": { + "service-model": "active-backup", + "backup": true, + "source": { "unix:db.sock": {} }, + "exclude-tables": [["b"]] + } + } + } +]) + AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server3.log \ + --pidfile=3.pid --unixctl=unixctl3 --config-file=config3.json], + [0], [ignore], [ignore]) m4_foreach([txn], [$3], [AT_CHECK([ ovsdb-client transact 'txn' ], [0], [stdout], [ignore]) @@ -1722,6 +1787,11 @@ m4_define([OVSDB_CHECK_REPLICATION], AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout], [ignore]) cat stdout > dump2 + OVS_WAIT_UNTIL([ ovsdb-client dump unix:db3.sock | grep one ]) + AT_CHECK([ovsdb-client dump unix:db3.sock], [0], [stdout], [ignore]) + cat stdout > dump3 + AT_CHECK([diff -u dump2 dump3]) + AT_CHECK([diff dump1 dump2], [1], [stdout], [ignore]) cat stdout > output @@ -1729,6 +1799,7 @@ m4_define([OVSDB_CHECK_REPLICATION], OVSDB_SERVER_SHUTDOWN OVSDB_SERVER_SHUTDOWN2 + OVSDB_SERVER_SHUTDOWN_N([3]) AT_CLEANUP]) REPLICATION_EXAMPLES From patchwork Thu Dec 14 01:04:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 1875937 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=patchwork.ozlabs.org) 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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SrDjd5m2Sz1ySd for ; Thu, 14 Dec 2023 12:07:49 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id AF83883D1B; Thu, 14 Dec 2023 01:07:47 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org AF83883D1B 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 K2rpfDA5afOL; Thu, 14 Dec 2023 01:07:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id D3BB083D09; Thu, 14 Dec 2023 01:07:41 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org D3BB083D09 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 87F24C0072; Thu, 14 Dec 2023 01:07:41 +0000 (UTC) X-Original-To: ovs-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 16DCFC0072 for ; Thu, 14 Dec 2023 01:07:40 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 2ABCA61ACA for ; Thu, 14 Dec 2023 01:05:48 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 2ABCA61ACA X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id cylDeWqG0USZ for ; Thu, 14 Dec 2023 01:05:46 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by smtp3.osuosl.org (Postfix) with ESMTPS id 5823761AF0 for ; Thu, 14 Dec 2023 01:05:46 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 5823761AF0 Received: by mail.gandi.net (Postfix) with ESMTPSA id 2D1F2240002; Thu, 14 Dec 2023 01:05:44 +0000 (UTC) From: Ilya Maximets To: ovs-dev@openvswitch.org Date: Thu, 14 Dec 2023 02:04:24 +0100 Message-ID: <20231214010431.1664005-23-i.maximets@ovn.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231214010431.1664005-1-i.maximets@ovn.org> References: <20231214010431.1664005-1-i.maximets@ovn.org> MIME-Version: 1.0 X-GND-Sasl: i.maximets@ovn.org Cc: Vladislav Odintsov , Dumitru Ceara , Ilya Maximets Subject: [ovs-dev] [PATCH 22/22] tests: ovsdb: Add configuration tests with config file. 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 more tests specific to --config-file. Signed-off-by: Ilya Maximets --- tests/ovsdb-server.at | 640 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 640 insertions(+) diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 488dfc36f..7085e72d4 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -183,6 +183,31 @@ AT_CHECK( OVSDB_SERVER_SHUTDOWN AT_CLEANUP +AT_SETUP([database multiplexing implementation with config file]) +AT_KEYWORDS([ovsdb server positive config-file]) +ordinal_schema > schema1 +constraint_schema > schema2 +AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore]) +on_exit 'kill $(cat *.pid)' + +AT_DATA([config.json], [ +{"remotes" : { "punix:db.sock": {} }, + "databases": { "db1": {}, "db2": { "service-model": "standalone" } } } +]) + +AT_CHECK([ovsdb-server --detach --no-chdir --log-file --pidfile \ + --config-file=config.json], [0], [ignore], [ignore]) +CHECK_DBS([constraints +ordinals +]) +AT_CHECK( + [[ovstest test-jsonrpc request unix:db.sock get_schema [\"nonexistent\"]]], [0], + [[{"error":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"},"id":0,"result":null} +]]) +OVSDB_SERVER_SHUTDOWN +AT_CLEANUP + AT_SETUP([ovsdb-server/add-db and remove-db]) AT_KEYWORDS([ovsdb server positive]) on_exit 'kill `cat *.pid`' @@ -298,6 +323,155 @@ AT_CHECK([uuidfilt db-change-unaware.stdout], [0], [dnl OVSDB_SERVER_SHUTDOWN(["/no database named ordinals/d"]) AT_CLEANUP +AT_SETUP([ovsdb-server/add-db and remove-db with a config file]) +AT_KEYWORDS([ovsdb server positive config-file]) +on_exit 'kill $(cat *.pid)' +ordinal_schema > schema1 +constraint_schema > schema2 +AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore]) + +dnl Start ovsdb-server with just a single database - db1. +AT_DATA([config.json], [ +{ + "remotes": { + "punix:db.sock": {} + }, + "databases": { + "db1": {} + } +} +]) +AT_CAPTURE_FILE([config.json]) +AT_CHECK([ovsdb-server -vfile -vvlog:off --log-file --detach --no-chdir \ + --pidfile --config-file=config.json], [0], [ignore], [ignore]) +CHECK_DBS([ordinals +]) + +dnl Remove the database. +AT_CHECK([sed -i'back' '/db1/d' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +CHECK_DBS([]) + +dnl Start monitoring processes. +AT_CHECK([ovsdb-client --detach --no-chdir --pidfile=ovsdb-client-1.pid \ + --no-db-change-aware --no-headings monitor _Server Database name \ + > db-change-unaware.stdout 2> db-change-unaware.stderr]) +AT_CHECK([ovsdb-client --detach --no-chdir --pidfile=ovsdb-client-2.pid \ + --db-change-aware --no-headings monitor _Server Database name \ + > db-change-aware.stdout 2> db-change-aware.stderr]) +AT_CAPTURE_FILE([db-change-unaware.stdout]) +AT_CAPTURE_FILE([db-change-unaware.stderr]) +AT_CAPTURE_FILE([db-change-aware.stdout]) +AT_CAPTURE_FILE([db-change-aware.stderr]) + +dnl Add the first database back. +AT_CHECK([sed -i'back' '/"databases"/a\ + "db1": {} + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +CHECK_DBS([ordinals +]) + +dnl Add the second database. +AT_CHECK([sed -i'back' '/"databases"/a\ + "db2": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +CHECK_DBS([constraints +ordinals +]) + +dnl The databases are responsive. +AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-client list-tables unix:db.sock ordinals], [0], [ignore], [ignore]) + +dnl Add an already added database. +AT_CHECK([sed -i'back' '/"databases"/a\ + "db2": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) + +dnl Fix the config back. +AT_CHECK([sed -i'back' '/db2/d' config.json]) +AT_CHECK([sed -i'back' '/"databases"/a\ + "db2": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) + +dnl Add a non-existing database. +AT_CHECK([sed -i'back' '/"databases"/a\ + "db3": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload], [2], [ignore], [ignore]) +OVS_WAIT_UNTIL([grep -q 'failed to configure databases' ovsdb-server.log]) +AT_CHECK([sed -i'back' '/db3/d' config.json]) + +dnl Add a remote through a db path in db1. +AT_CHECK([sed -i'back' '/"remotes"/a\ + "db:ordinals,ordinals,name": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [db:ordinals,ordinals,name +punix:db.sock +]) + +dnl Removing db1 has no effect on its remote. +AT_CHECK([sed -i'back' '/db1/d' config.json]) +AT_CHECK([sed -i'back' 's/"db2": {},/"db2": {}/' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload], [2], [ignore], [ignore]) +CHECK_DBS([constraints +]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [db:ordinals,ordinals,name +punix:db.sock +]) +AT_CHECK([ovsdb-client list-tables unix:db.sock ordinals], [1], [ignore], [ignore]) + +dnl Remove now missing remote. +AT_CHECK([sed -i'back' '/db:ordinals,ordinals,name/d' config.json]) + +dnl Remove db2. +AT_CHECK([sed -i'back' '/db2/d' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +CHECK_DBS() +AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [1], [ignore], [ignore]) + +dnl Add a removed database. +AT_CHECK([sed -i'back' '/"databases"/a\ + "db2": {} + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +CHECK_DBS([constraints +]) +AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore]) + +# Check the monitoring results. +AT_CHECK([uuidfilt db-change-aware.stdout], [0], [dnl +<0> initial _Server + +<1> insert ordinals + +<2> insert constraints + +<1> delete ordinals + +<2> delete constraints + +<3> insert constraints +]) +AT_CHECK([uuidfilt db-change-unaware.stdout], [0], [dnl +<0> initial _Server +]) + +OVSDB_SERVER_SHUTDOWN([" + /no database named ordinals/d + /failed to open database 'db3'/d + /failed to configure databases/d +"]) +AT_CLEANUP + AT_SETUP([ovsdb-server/add-db with --monitor]) AT_KEYWORDS([ovsdb server positive]) AT_SKIP_IF([test "$IS_WIN32" = "yes"]) @@ -499,6 +673,81 @@ AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes]) OVSDB_SERVER_SHUTDOWN AT_CLEANUP +AT_SETUP([ovsdb-server/add-remote and remove-remote with config file]) +AT_KEYWORDS([ovsdb server positive config-file]) +ordinal_schema > schema +AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore]) +on_exit 'kill $(cat *.pid)' + +AT_DATA([config.json], [ +{ + "remotes": { + }, + "databases": { "db": {} } +} +]) +AT_CAPTURE_FILE([config.json]) + +AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file --pidfile \ + --config-file=config.json], [0], [ignore], [ignore]) + +AT_CHECK([test ! -e socket1]) +AT_CHECK([sed -i'back' '/"remotes"/a\ + "punix:socket1": {} + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +if test "$IS_WIN32" = "yes"; then + OVS_WAIT_UNTIL([test -e socket1]) +else + OVS_WAIT_UNTIL([test -S socket1]) +fi +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [punix:socket1 +]) + +AT_CHECK([test ! -e socket2]) +AT_CHECK([sed -i'back' '/"remotes"/a\ + "punix:socket2": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +if test "$IS_WIN32" = "yes"; then + OVS_WAIT_UNTIL([test -e socket2]) +else + OVS_WAIT_UNTIL([test -S socket2]) +fi +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [punix:socket1 +punix:socket2 +]) + +AT_CHECK([sed -i'back' '/"remotes"/a\ + "db:x,y,z": {}, + ' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload], [2], [ignore], [ignore]) +OVS_WAIT_UNTIL([grep -q '"db:x,y,z": no database named x' ovsdb-server.log]) +AT_CHECK([sed -i'back' '/db:x,y,z/d' config.json]) + +AT_CHECK([sed -i'back' '/punix:socket1/d' config.json]) +AT_CHECK([sed -i'back' 's/"punix:socket2": {},/"punix:socket2": {}/' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +OVS_WAIT_UNTIL([test ! -e socket1]) +if test "$IS_WIN32" = "yes"; then + AT_CHECK([test -e socket2]) +else + AT_CHECK([test -S socket2]) +fi +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [punix:socket2 +]) + +AT_CHECK([sed -i'back' '/punix:socket2/d' config.json]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/reload]) +OVS_WAIT_UNTIL([test ! -e socket2]) +AT_CHECK([test ! -e socket1]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes]) +OVSDB_SERVER_SHUTDOWN(['/"db:x,y,z": no database named x/d']) +AT_CLEANUP + AT_SETUP([ovsdb-server/add-remote with --monitor]) AT_KEYWORDS([ovsdb server positive]) AT_SKIP_IF([test "$IS_WIN32" = "yes"]) @@ -2108,6 +2357,140 @@ dnl OVSDB_SERVER_SHUTDOWN dnl OVSDB_SERVER_SHUTDOWN2 AT_CLEANUP +AT_SETUP([ovsdb-server/active-backup-role-switching with config file]) +AT_KEYWORDS([ovsdb server replication active-backup-switching config-file]) +replication_schema > schema +AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore]) +AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore]) + +dnl Add some data to both DBs. +AT_CHECK([ovsdb-tool transact db1 \ +'[["mydb", + {"op": "insert", + "table": "a", + "row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore]) + +AT_CHECK([ovsdb-tool transact db2 \ +'[["mydb", + {"op": "insert", + "table": "a", + "row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore]) + +dnl Start both 'db1' and 'db2' in backup mode. Let them backup from each +dnl other. This is not a supported operation state, but to simulate a start +dnl up condition where an HA manger can select which one to be an active +dnl server soon after. +on_exit 'kill $(cat *.pid)' + +AT_DATA([config1.json], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "db1": { + "service-model": "active-backup", + "backup": true, + "source": { "unix:db2.sock": {} } + } + } +} +]) + +AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server1.log \ + --pidfile=1.pid --unixctl=unixctl1 --config-file=config1.json], + [0], [ignore], [ignore]) + +AT_DATA([config2.json], [ +{ + "remotes": { "punix:db2.sock": {} }, + "databases": { + "db2": { + "service-model": "active-backup", + "backup": true, + "source": { "unix:db.sock": {} } + } + } +} +]) +AT_CHECK([ovsdb-server -vfile --detach --no-chdir --log-file=ovsdb-server2.log \ + --pidfile=2.pid --unixctl=unixctl2 --config-file=config2.json], + [0], [ignore], [ignore]) + +dnl Make sure both servers reached the replication state. +OVS_WAIT_UNTIL([ovs-appctl -t $(pwd)/unixctl1 ovsdb-server/sync-status | grep replicating]) +OVS_WAIT_UNTIL([ovs-appctl -t $(pwd)/unixctl2 ovsdb-server/sync-status | grep replicating]) + +dnl Switch the 'db1' to active. +AT_CHECK([sed -i'back' 's/"backup": true/"backup": false/' config1.json]) +AT_CHECK([ovs-appctl -t $(pwd)/unixctl1 ovsdb-server/reload]) +AT_CHECK([ovs-appctl -t $(pwd)/unixctl1 ovsdb-server/sync-status], [0], [dnl +database: mydb +state: active +]) + +dnl Issue a transaction to 'db1'. +AT_CHECK([ovsdb-client transact unix:db.sock \ +'[["mydb", + {"op": "insert", + "table": "a", + "row": {"number": 0, "name": "zero"}}]]'], [0], [ignore]) + +dnl It should be replicated to 'db2'. +OVS_WAIT_UNTIL([ovsdb-client dump unix:db2.sock | grep zero]) + +dnl Issue a transaction to 'db2', it should fail. +AT_CHECK([ovsdb-client transact unix:db2.sock \ +'[["mydb", + {"op": "insert", + "table": "a", + "row": {"number": 1, "name": "one"}}]]'], [0], [dnl +[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]] +]) + +dnl Flip the role of 'db1' and 'db2'. 'db1' becomes backup, and 'db2' becomes active. +AT_CHECK([sed -i'back' 's/"backup": true/"backup": false/' config2.json]) +AT_CHECK([ovs-appctl -t $(pwd)/unixctl2 ovsdb-server/reload]) +AT_CHECK([sed -i'back' 's/"backup": false/"backup": true/' config1.json]) +AT_CHECK([ovs-appctl -t $(pwd)/unixctl1 ovsdb-server/reload]) + +dnl Verify the change happend. +OVS_WAIT_UNTIL([ovs-appctl -t $(pwd)/unixctl1 ovsdb-server/sync-status | grep replicating]) +AT_CHECK([ovs-appctl -t $(pwd)/unixctl2 ovsdb-server/sync-status], [0], [dnl +database: mydb +state: active +]) + +dnl Issue a transaction to 'db2' which is now active. +AT_CHECK([ovsdb-client transact unix:db2.sock \ +'[["mydb", + {"op": "insert", + "table": "b", + "row": {"number": 1, "name": "one"}}]]'], [0], [ignore]) + +dnl The transaction should be replicated to 'db1'. +OVS_WAIT_UNTIL([ovsdb-client dump unix:db.sock | grep one]) + +dnl Issue a transaction to 'db1', it should fail. +AT_CHECK([ovsdb-client transact unix:db.sock \ +'[["mydb", + {"op": "insert", + "table": "a", + "row": {"number": 2, "name": "two"}}]]'], [0], [dnl +[[{"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}]] +]) + +dnl Both servers should have the same content. +AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout]) +cat stdout > dump1 + +AT_CHECK([ovsdb-client dump unix:db2.sock], [0], [stdout]) +cat stdout > dump2 + +AT_CHECK([diff -u dump1 dump2]) + +OVSDB_SERVER_SHUTDOWN_N([1]) +OVSDB_SERVER_SHUTDOWN2 +AT_CLEANUP + #ovsdb-server prevent self replicating AT_SETUP([ovsdb-server prevent self replicating]) AT_KEYWORDS([ovsdb server replication]) @@ -2472,3 +2855,260 @@ AT_CHECK([diff db.clear ./replay_dir/db.copy.clear]) AT_CHECK([diff -u 1.log.clear 2.log.clear]) AT_CLEANUP + +AT_BANNER([OVSDB -- ovsdb-server configuration file]) + +dnl TEST_CONFIG_FILE([NAME], [config], [EXIT_CODE], [FAILURE_STRINGS]) +dnl +dnl Tries the config as a data for --config-file, checks the EXIT_CODE +dnl of the ovsdb-server and checks the stderr for FAILURE_STRINGS. +dnl NAME is added to the test name and keywords. +m4_define([TEST_CONFIG_FILE], +[ + AT_SETUP([ovsdb-server config-file - $1]) + AT_KEYWORDS([ovsdb server config-file $1]) + on_exit 'kill $(cat *.pid)' + echo '$2' > config.json + AT_CAPTURE_FILE([config.json]) + ordinal_schema > schema + constraint_schema > schema2 + AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-tool create db2 schema], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-tool create-cluster db_cluster schema2 unix:s1.raft], + [0], [ignore], [ignore]) + AT_CHECK([ovsdb-server -vfile -vPATTERN:console:'%p|%m' -vvlog:off \ + --log-file --detach --no-chdir --pidfile \ + --config-file=config.json], [$3], [ignore], [stderr]) + m4_if([$4], [], [], [ + AT_CHECK([cat stderr | grep -v -E 'INFO|DBG' \ + | grep -v 'failed to load configuration from' > warnings]) + AT_CHECK([cat warnings], [0], [m4_if([$3], [0], [$4], [$4 +ovsdb-server: server configuration failed +])])]) + m4_if([$3$4], [0], [OVSDB_SERVER_SHUTDOWN]) + AT_CLEANUP +]) + +TEST_CONFIG_FILE([simple], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db": null, "db_cluster": {} } +} +], [0]) + +TEST_CONFIG_FILE([standalone], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db": { "service-model": "standalone" } } +} +], [0]) + +TEST_CONFIG_FILE([clustered], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db_cluster": { "service-model": "clustered" } } +} +], [0]) + +TEST_CONFIG_FILE([same schema], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db": null, "db2": {} } +} +], [1], [dnl +WARN|failed to open database 'db2': ovsdb error: ordinals: duplicate database name +WARN|failed to configure databases]) + +TEST_CONFIG_FILE([model mismatch], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db": { "service-model": "clustered" } } +} +], [1], [dnl +WARN|failed to open database 'db': ovsdb error: db: database is standalone and not clustered +WARN|failed to configure databases]) + +TEST_CONFIG_FILE([model mismatch clustered], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { "db_cluster": { "service-model": "standalone" } } +} +], [1], [dnl +WARN|failed to open database 'db_cluster': ovsdb error: db_cluster: database is clustered and not standalone +WARN|failed to configure databases]) + +TEST_CONFIG_FILE([relay], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "RelaySchema": { + "service-model": "relay", + "source": { "unix:db2.sock": {} } + } + } +} +], [0]) + +TEST_CONFIG_FILE([relay without source], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "RelaySchema": { + "service-model": "relay" + } + } +} +], [1], [dnl +WARN|syntax "{"service-model":"relay"}": syntax error: Parsing database RelaySchema failed:dnl + Required 'source' member is missing. +WARN|config: failed to parse 'databases']) + +TEST_CONFIG_FILE([relay with options], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "RelaySchema": { + "service-model": "relay", + "source": { + "punix:db2.sock": { + "inactivity-probe": 10000, + "max-backoff": 8000, + "dscp": 42 + } + } + } + } +} +], [0]) + +TEST_CONFIG_FILE([relay with unrelated options], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "RelaySchema": { + "service-model": "relay", + "source": { + "punix:db2.sock": { + "inactivity-probe": 10000, + "max-backoff": 8000, + "dscp": 42, + "role": "My-RBAC-role" + } + } + } + } +} +], [0], [dnl +WARN|syntax "{"dscp":42,"inactivity-probe":10000,"max-backoff":8000,"role":"My-RBAC-role"}":dnl + syntax error: Parsing JSON-RPC options failed: Member 'role' is present but not allowed here. +]) + +TEST_CONFIG_FILE([unknown config], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "db": { "unknnown": "unknown" } + } +} +], [1], [dnl +WARN|syntax "{"unknnown":"unknown"}": syntax error: Parsing database db failed:dnl + Member 'unknnown' is present but not allowed here. +WARN|config: failed to parse 'databases']) + +TEST_CONFIG_FILE([active-backup active], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "db": { + "service-model": "active-backup", + "backup": false + } + } +} +], [0]) + +TEST_CONFIG_FILE([active-backup backup], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "db": { + "service-model": "active-backup", + "backup": true, + "source": { + "punix:db2.sock": { + "inactivity-probe": 100000, + "max-backoff": 16000, + "dscp": 42 + } + } + } + } +} +], [0]) + +TEST_CONFIG_FILE([active-backup backup without source], [ +{ + "remotes": { "punix:db.sock": {} }, + "databases": { + "db": { + "service-model": "active-backup", + "backup": true + } + } +} +], [1], [dnl +WARN|syntax "{"backup":true,"service-model":"active-backup"}": syntax error:dnl + Parsing database db failed: Required 'source' member is missing. +WARN|config: failed to parse 'databases']) + +TEST_CONFIG_FILE([syntax error], [ +{ + "remotes": { "punix:db.sock": {}, }, + "databases": { "db": {}, "db_cluster": {} } +} +], [1], [dnl +WARN|config: reading JSON failed (line 2, column 38, byte 41: syntax error parsing object expecting string)]) + +TEST_CONFIG_FILE([complex config], [ +{ + "remotes": { + "punix:db.sock": { + "inactivity-probe": 0, + "read-only": false + }, + "pssl:0:127.0.0.1": { + "inactivity-probe": 5000, + "max-backoff": 8000, + "read-only": true, + "role": "ovn-controller", + "dscp": 48 + }, + "db:ordinals,ordinals,name": null + }, + "databases": { + "db_cluster": { + "service-model": "clustered" + }, + "OVN_Northbound": { + "service-model": "relay", + "source": { + "unix:nb.sock": { + "max-backoff": 3000, + "inactivity-probe": 16000 + } + } + }, + "db": { + "service-model": "active-backup", + "backup": true, + "source": { + "unix:active.sock": { + "max-backoff": 16000, + "inactivity-probe": 180000 + } + }, + "exclude-tables": [["IC_SB_Global", "Availability_Zone"]] + } + } +} +], [0])