2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ovsdb: Prevent OVSDB server from replicating itself.

Replication OVSDB server from itself is usually caused by configuration
errors. Such configuration errors can lead to OVSDB server data loss.
See "reported-at" for more details.

This patch adds logics that prevent OVSDB server from replicating
itself.

Reported-by: Guishuai Li <ligs@dtdream.com>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2017-January/326963.html
Suggested-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Andy Zhou <azhou@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Andy Zhou 2017-02-06 14:00:22 -08:00
parent 64fada2601
commit 05ac209a5d
6 changed files with 138 additions and 17 deletions

View File

@ -944,6 +944,13 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
}
reply = jsonrpc_create_reply(json_array_create(dbs, n_dbs),
request->id);
} else if (!strcmp(request->method, "get_server_id")) {
const struct uuid *uuid = &s->up.server->uuid;
struct json *result;
result = json_string_create_nocopy(xasprintf(UUID_FMT,
UUID_ARGS(uuid)));
reply = jsonrpc_create_reply(result, request->id);
} else if (!strcmp(request->method, "lock")) {
reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT);
} else if (!strcmp(request->method, "steal")) {

View File

@ -577,6 +577,36 @@ Initial views of rows are not presented in update2 notifications,
but in the response object to the monitor_cond request. The formatting
of the <table-updates2> object, however, is the same in either case.
.
.IP "4.1.15. Get Server ID"
A new RPC method added in Open vSwitch version 2.7. The request contains
the following members:
.
.PP
.RS
.nf
"method": "get_server_id"
"params": null
"id": <nonnull-json-value>
.fi
.RE
.
.IP
The response object contains the following members:
.
.PP
.RS
.nf
"result": "<server_id>"
"error": null
"id": same "id" as request
.fi
.RE
.
.IP
<server_id> is JSON string that contains a UUID that uniquely identifies
the running OVSDB server process. A fresh UUID is generated when the
process restarts.
.
.IP "5.1. Notation"
For <condition>, RFC 7047 only allows the use of \fB!=\fR, \fB==\fR,
\fBincludes\fR, and \fBexcludes\fR operators with set types. Open

View File

@ -139,9 +139,9 @@ static void load_config(FILE *config_file, struct sset *remotes,
static void
ovsdb_replication_init(const char *sync_from, const char *exclude,
struct shash *all_dbs)
struct shash *all_dbs, const struct uuid *server_uuid)
{
replication_init(sync_from, exclude);
replication_init(sync_from, exclude, server_uuid);
struct shash_node *node;
SHASH_FOR_EACH (node, all_dbs) {
struct db *db = node->data;
@ -425,7 +425,9 @@ main(int argc, char *argv[])
ovsdb_server_disable_monitor_cond, jsonrpc);
if (is_backup) {
ovsdb_replication_init(sync_from, sync_exclude, &all_dbs);
const struct uuid *server_uuid;
server_uuid = ovsdb_jsonrpc_server_get_uuid(jsonrpc);
ovsdb_replication_init(sync_from, sync_exclude, &all_dbs, server_uuid);
}
main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting,
@ -1185,8 +1187,10 @@ ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn,
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);
config->all_dbs, server_uuid);
if (!*config->is_backup) {
*config->is_backup = true;
save_config(config);
@ -1223,8 +1227,10 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn,
*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);
config->all_dbs, server_uuid);
}
err = set_blacklist_tables(argv[1], false);
}
@ -1430,8 +1436,10 @@ ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
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);
config->all_dbs, server_uuid);
}
unixctl_command_reply(conn, NULL);
} else {
@ -1464,8 +1472,10 @@ ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
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);
config->all_dbs, server_uuid);
}
unixctl_command_reply(conn, NULL);
}

View File

@ -1,6 +1,6 @@
/*
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,10 +34,12 @@
#include "svec.h"
#include "table.h"
#include "transaction.h"
#include "uuid.h"
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;
@ -88,6 +90,7 @@ void request_ids_clear(void);
enum ovsdb_replication_state {
RPL_S_INIT,
RPL_S_SERVER_ID_REQUESTED,
RPL_S_DB_REQUESTED,
RPL_S_SCHEMA_REQUESTED,
RPL_S_MONITOR_REQUESTED,
@ -110,7 +113,8 @@ static struct ovsdb* find_db(const char *db_name);
void
replication_init(const char *sync_from_, const char *exclude_tables)
replication_init(const char *sync_from_, const char *exclude_tables,
const struct uuid *server)
{
free(sync_from);
sync_from = xstrdup(sync_from_);
@ -128,6 +132,10 @@ replication_init(const char *sync_from_, const char *exclude_tables)
session = jsonrpc_session_open(sync_from, true);
session_seqno = UINT_MAX;
/* Keep a copy of local server uuid. */
server_uuid = *server;
state = RPL_S_INIT;
}
@ -155,16 +163,13 @@ replication_run(void)
session_seqno = seqno;
request_ids_clear();
struct jsonrpc_msg *request;
request = jsonrpc_create_request("list_dbs",
request = jsonrpc_create_request("get_server_id",
json_array_create_empty(), NULL);
request_ids_add(request->id, NULL);
jsonrpc_session_send(session, request);
replication_dbs_destroy();
replication_dbs = replication_db_clone(&local_dbs);
state = RPL_S_DB_REQUESTED;
VLOG_DBG("Send list_dbs request");
state = RPL_S_SERVER_ID_REQUESTED;
VLOG_DBG("send server ID request.");
}
msg = jsonrpc_session_recv(session);
@ -197,10 +202,45 @@ replication_run(void)
}
switch (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");
ovsdb_error_assert(error);
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");
ovsdb_error_assert(error);
state = RPL_S_ERR;
break;
}
struct jsonrpc_msg *request;
request = jsonrpc_create_request("list_dbs",
json_array_create_empty(),
NULL);
request_ids_add(request->id, NULL);
jsonrpc_session_send(session, request);
replication_dbs_destroy();
replication_dbs = replication_db_clone(&local_dbs);
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",
error = ovsdb_error("list_dbs failed",
"list_dbs response is not array");
ovsdb_error_assert(error);
state = RPL_S_ERR;
@ -802,6 +842,7 @@ replication_status(void)
if (alive) {
switch(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:

View File

@ -44,7 +44,8 @@ struct ovsdb;
* used mainly by uinxctl commands.
*/
void replication_init(const char *sync_from, const char *exclude_tables);
void replication_init(const char *sync_from, const char *exclude_tables,
const struct uuid *server);
void replication_run(void);
void replication_wait(void);
void replication_destroy(void);

View File

@ -1440,6 +1440,38 @@ dnl OVSDB_SERVER_SHUTDOWN
dnl OVSDB_SERVER_SHUTDOWN2
AT_CLEANUP
#ovsdb-server prevent self replicating
AT_SETUP([ovsdb-server prevent self replicating])
AT_KEYWORDS([ovsdb server replication])
replication_schema > schema
AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
dnl Add some data to both DBs
AT_CHECK([ovsdb-tool transact db \
'[["mydb",
{"op": "insert",
"table": "a",
"row": {"number": 9, "name": "nine"}}]]'], [0], [ignore], [ignore])
dnl Start 'db', then try to be a back up server of itself.
AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server.log --pidfile="`pwd`"/pid --remote=punix:db.sock --unixctl="`pwd`"/unixctl db --sync-from=unix:db.sock --active ], [0], [ignore], [ignore])
on_exit 'test ! -e pid || kill `cat pid`'
dnl Save the current content
AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout])
cp stdout dump1
AT_CHECK([ovs-appctl -t "`pwd`"/unixctl ovsdb-server/connect-active-ovsdb-server])
dnl Check that self replicating is blocked.
AT_CHECK([grep "Self replicating is not allowed" ovsdb-server.log], [0], [stdout])
dnl Check current DB content is preserved.
AT_CHECK([ovsdb-client dump unix:db.sock], [0], [stdout])
cat stdout > dump2
AT_CHECK([diff dump1 dump2])
AT_CLEANUP
AT_SETUP([ovsdb-server/read-only db:ptcp connection])
AT_KEYWORDS([ovsdb server read-only])
AT_DATA([schema],