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:
parent
64fada2601
commit
05ac209a5d
@ -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")) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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],
|
||||
|
Loading…
x
Reference in New Issue
Block a user