mirror of
https://github.com/openvswitch/ovs
synced 2025-08-29 13:27:59 +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),
|
reply = jsonrpc_create_reply(json_array_create(dbs, n_dbs),
|
||||||
request->id);
|
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")) {
|
} else if (!strcmp(request->method, "lock")) {
|
||||||
reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT);
|
reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT);
|
||||||
} else if (!strcmp(request->method, "steal")) {
|
} 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
|
but in the response object to the monitor_cond request. The formatting
|
||||||
of the <table-updates2> object, however, is the same in either case.
|
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"
|
.IP "5.1. Notation"
|
||||||
For <condition>, RFC 7047 only allows the use of \fB!=\fR, \fB==\fR,
|
For <condition>, RFC 7047 only allows the use of \fB!=\fR, \fB==\fR,
|
||||||
\fBincludes\fR, and \fBexcludes\fR operators with set types. Open
|
\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
|
static void
|
||||||
ovsdb_replication_init(const char *sync_from, const char *exclude,
|
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;
|
struct shash_node *node;
|
||||||
SHASH_FOR_EACH (node, all_dbs) {
|
SHASH_FOR_EACH (node, all_dbs) {
|
||||||
struct db *db = node->data;
|
struct db *db = node->data;
|
||||||
@ -425,7 +425,9 @@ main(int argc, char *argv[])
|
|||||||
ovsdb_server_disable_monitor_cond, jsonrpc);
|
ovsdb_server_disable_monitor_cond, jsonrpc);
|
||||||
|
|
||||||
if (is_backup) {
|
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,
|
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) {
|
if ( !*config->sync_from) {
|
||||||
msg = "Unable to connect: active server is not specified.\n";
|
msg = "Unable to connect: active server is not specified.\n";
|
||||||
} else {
|
} else {
|
||||||
|
const struct uuid *server_uuid;
|
||||||
|
server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc);
|
||||||
ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
|
ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
|
||||||
config->all_dbs);
|
config->all_dbs, server_uuid);
|
||||||
if (!*config->is_backup) {
|
if (!*config->is_backup) {
|
||||||
*config->is_backup = true;
|
*config->is_backup = true;
|
||||||
save_config(config);
|
save_config(config);
|
||||||
@ -1223,8 +1227,10 @@ ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn,
|
|||||||
*config->sync_exclude = xstrdup(argv[1]);
|
*config->sync_exclude = xstrdup(argv[1]);
|
||||||
save_config(config);
|
save_config(config);
|
||||||
if (*config->is_backup) {
|
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,
|
ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
|
||||||
config->all_dbs);
|
config->all_dbs, server_uuid);
|
||||||
}
|
}
|
||||||
err = set_blacklist_tables(argv[1], false);
|
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) {
|
if (!error) {
|
||||||
save_config(config);
|
save_config(config);
|
||||||
if (*config->is_backup) {
|
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,
|
ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
|
||||||
config->all_dbs);
|
config->all_dbs, server_uuid);
|
||||||
}
|
}
|
||||||
unixctl_command_reply(conn, NULL);
|
unixctl_command_reply(conn, NULL);
|
||||||
} else {
|
} else {
|
||||||
@ -1464,8 +1472,10 @@ ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|||||||
|
|
||||||
save_config(config);
|
save_config(config);
|
||||||
if (*config->is_backup) {
|
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,
|
ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
|
||||||
config->all_dbs);
|
config->all_dbs, server_uuid);
|
||||||
}
|
}
|
||||||
unixctl_command_reply(conn, NULL);
|
unixctl_command_reply(conn, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
* (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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -34,10 +34,12 @@
|
|||||||
#include "svec.h"
|
#include "svec.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
VLOG_DEFINE_THIS_MODULE(replication);
|
VLOG_DEFINE_THIS_MODULE(replication);
|
||||||
|
|
||||||
static char *sync_from;
|
static char *sync_from;
|
||||||
|
static struct uuid server_uuid;
|
||||||
static struct jsonrpc_session *session;
|
static struct jsonrpc_session *session;
|
||||||
static unsigned int session_seqno = UINT_MAX;
|
static unsigned int session_seqno = UINT_MAX;
|
||||||
|
|
||||||
@ -88,6 +90,7 @@ void request_ids_clear(void);
|
|||||||
|
|
||||||
enum ovsdb_replication_state {
|
enum ovsdb_replication_state {
|
||||||
RPL_S_INIT,
|
RPL_S_INIT,
|
||||||
|
RPL_S_SERVER_ID_REQUESTED,
|
||||||
RPL_S_DB_REQUESTED,
|
RPL_S_DB_REQUESTED,
|
||||||
RPL_S_SCHEMA_REQUESTED,
|
RPL_S_SCHEMA_REQUESTED,
|
||||||
RPL_S_MONITOR_REQUESTED,
|
RPL_S_MONITOR_REQUESTED,
|
||||||
@ -110,7 +113,8 @@ static struct ovsdb* find_db(const char *db_name);
|
|||||||
|
|
||||||
|
|
||||||
void
|
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);
|
free(sync_from);
|
||||||
sync_from = xstrdup(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 = jsonrpc_session_open(sync_from, true);
|
||||||
session_seqno = UINT_MAX;
|
session_seqno = UINT_MAX;
|
||||||
|
|
||||||
|
/* Keep a copy of local server uuid. */
|
||||||
|
server_uuid = *server;
|
||||||
|
|
||||||
state = RPL_S_INIT;
|
state = RPL_S_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,16 +163,13 @@ replication_run(void)
|
|||||||
session_seqno = seqno;
|
session_seqno = seqno;
|
||||||
request_ids_clear();
|
request_ids_clear();
|
||||||
struct jsonrpc_msg *request;
|
struct jsonrpc_msg *request;
|
||||||
request = jsonrpc_create_request("list_dbs",
|
request = jsonrpc_create_request("get_server_id",
|
||||||
json_array_create_empty(), NULL);
|
json_array_create_empty(), NULL);
|
||||||
request_ids_add(request->id, NULL);
|
request_ids_add(request->id, NULL);
|
||||||
jsonrpc_session_send(session, request);
|
jsonrpc_session_send(session, request);
|
||||||
|
|
||||||
replication_dbs_destroy();
|
state = RPL_S_SERVER_ID_REQUESTED;
|
||||||
replication_dbs = replication_db_clone(&local_dbs);
|
VLOG_DBG("send server ID request.");
|
||||||
|
|
||||||
state = RPL_S_DB_REQUESTED;
|
|
||||||
VLOG_DBG("Send list_dbs request");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = jsonrpc_session_recv(session);
|
msg = jsonrpc_session_recv(session);
|
||||||
@ -197,10 +202,45 @@ replication_run(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (state) {
|
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:
|
case RPL_S_DB_REQUESTED:
|
||||||
if (msg->result->type != JSON_ARRAY) {
|
if (msg->result->type != JSON_ARRAY) {
|
||||||
struct ovsdb_error *error;
|
struct ovsdb_error *error;
|
||||||
error = ovsdb_error("list-dbs failed",
|
error = ovsdb_error("list_dbs failed",
|
||||||
"list_dbs response is not array");
|
"list_dbs response is not array");
|
||||||
ovsdb_error_assert(error);
|
ovsdb_error_assert(error);
|
||||||
state = RPL_S_ERR;
|
state = RPL_S_ERR;
|
||||||
@ -802,6 +842,7 @@ replication_status(void)
|
|||||||
if (alive) {
|
if (alive) {
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case RPL_S_INIT:
|
case RPL_S_INIT:
|
||||||
|
case RPL_S_SERVER_ID_REQUESTED:
|
||||||
case RPL_S_DB_REQUESTED:
|
case RPL_S_DB_REQUESTED:
|
||||||
case RPL_S_SCHEMA_REQUESTED:
|
case RPL_S_SCHEMA_REQUESTED:
|
||||||
case RPL_S_MONITOR_REQUESTED:
|
case RPL_S_MONITOR_REQUESTED:
|
||||||
|
@ -44,7 +44,8 @@ struct ovsdb;
|
|||||||
* used mainly by uinxctl commands.
|
* 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_run(void);
|
||||||
void replication_wait(void);
|
void replication_wait(void);
|
||||||
void replication_destroy(void);
|
void replication_destroy(void);
|
||||||
|
@ -1440,6 +1440,38 @@ dnl OVSDB_SERVER_SHUTDOWN
|
|||||||
dnl OVSDB_SERVER_SHUTDOWN2
|
dnl OVSDB_SERVER_SHUTDOWN2
|
||||||
AT_CLEANUP
|
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_SETUP([ovsdb-server/read-only db:ptcp connection])
|
||||||
AT_KEYWORDS([ovsdb server read-only])
|
AT_KEYWORDS([ovsdb server read-only])
|
||||||
AT_DATA([schema],
|
AT_DATA([schema],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user