Compare commits

..
40 Commits
Author SHA1 Message Date
Vitaliy Filippov 6b28e10660 HTTP "hello, world!" 2026-04-09 12:14:56 +03:00
Vitaliy Filippov f5d19b657a WIP TLS 2026-04-09 11:42:18 +03:00
Vitaliy Filippov 82f9515bf1 Auto-select the only RDMA device/port if there is only one 2026-04-05 16:16:54 +03:00
Vitaliy Filippov dc13f2dd45 Allow to skip checksums for headers 2026-04-05 11:40:00 +03:00
Vitaliy Filippov d54f73195b Implement protocol-level checksums (xxhash3) 2026-04-04 19:03:27 +03:00
Vitaliy Filippov 6c584df3ca Include xxhash3 x86dispatch 2026-04-04 19:03:01 +03:00
Vitaliy Filippov b2effacbc1 Do not use scrap_buffer in the client (it would block protocol checksum support) 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 440a722827 Support TLS CN authentication and per-image permissions in vitastor-cli serve 2026-04-04 19:01:50 +03:00
Vitaliy Filippov e478139e4d Add VitastorAuthFilter 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 7d68443235 Implement vitastor-cli ls-user, modify-user, remove-user commands 2026-04-04 19:01:50 +03:00
Vitaliy Filippov ff6519a005 Add image owner/owner_group/reader_group support (for antietcd VitastorAuthFilter) 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 34a98e4dcc Add security parameter documentation 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 1ebac51110 Support inline (string PEM) certificates and pkeys 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 2e261ac2cf Show encryption keys (only IDs) in the listing 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 405a8c3f53 Support storing image encryption keys in Vault 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 8d4d49dad3 Prefer local etcd addresses and correctly cycle over them even when they need resolving
Seems slightly overcomplicated...
2026-04-04 19:01:50 +03:00
Vitaliy Filippov 6a646be234 Support DNS resolving via libc-ares 2026-04-04 19:01:50 +03:00
Vitaliy Filippov bc0aa48bc7 Batch handle_immediate_ops more 2026-04-04 19:01:50 +03:00
Vitaliy Filippov df08f4e4d2 Add vitastor-cli create & modify --enc-key parameter 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 2669ba96ad Support reading from snapshots encrypted with different keys 2026-04-04 19:01:50 +03:00
Vitaliy Filippov b5b3c95bfd Support decryption with multiple keys 2026-04-04 19:01:50 +03:00
Vitaliy Filippov 0d5530f89a Allow to return chain_info in response to reads 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 0b32d76f75 Add basic AES-XTS client-side encryption support 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 67132a29ae Rework msgr send/receive to allow encryption support 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 6d22ab77ec Move fromhexstr() to str_util 2026-04-04 19:01:49 +03:00
Vitaliy Filippov b2bcf2734c Add openapi description 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 04e4fcd14d Slightly fix API return and input types 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 2dbfc8548a Implement vitastor-cli serve command to serve simple HTTP API 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 74a826d0be Implement HTTP server support O_o 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 4aa9c8bf2b Rename http_response_t to http_message_t 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 5a51415d2c Extract common HTTP context 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 2be8dfbb48 Support xxhash 32-bit checksums (data_csum_type=xxh3_32) 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 49db218f73 Detect block checksums using csum_block_size, not data_csum_type 2026-04-04 19:01:49 +03:00
Vitaliy Filippov b04a2d62b2 Add client certificate support 2026-04-04 19:01:49 +03:00
Vitaliy Filippov dcd545a1a5 Do not re-initialize TLS context every connection 2026-04-04 19:01:49 +03:00
Vitaliy Filippov 553e153c16 Add https support to antietcd 2026-04-04 19:01:49 +03:00
Vitaliy Filippov cc420ca32d Implement etcd SSL support via OpenSSL
Maybe I should remove all of this and use libwebsockets :)
2026-04-04 19:01:49 +03:00
Vitaliy Filippov dd5941b9a4 Release 3.0.9
- Fix broken garbage collection in the new store leading to very high memory usage
- Make the new store do full garbage collection on OSD startup by default (can be turned off with a new gc_on_start parameter)
- Make startup logging with the new store more informative, allow to log amount of garbage with log_level > 1
- Fix clients reading from snapshots incorrectly on retries (for example when OSDs were restarted during read)
- Fix a possible "send-after-free" in OSD which could probably also affect snapshot reads
- Fix OSD crashing when handling a read_bitmap operation from a deleted object with the new store
2026-04-04 18:38:40 +03:00
Vitaliy Filippov 4005b88865 Do not use node_type 2026-04-04 17:37:47 +03:00
Vitaliy Filippov 280b5cd675 Add gc_on_start docs 2026-04-04 17:19:32 +03:00
35 changed files with 750 additions and 171 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8...3.30)
project(vitastor)
set(VITASTOR_VERSION "3.0.8")
set(VITASTOR_VERSION "3.0.9")
include(CTest)
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v3.0.8
VITASTOR_VERSION ?= v3.0.9
all: build push
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v3.0.8
image: vitalif/vitastor-csi:v3.0.9
args:
- "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -121,7 +121,7 @@ spec:
privileged: true
capabilities:
add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v3.0.8
image: vitalif/vitastor-csi:v3.0.9
args:
- "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -5,7 +5,7 @@ package vitastor
const (
vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "3.0.8"
vitastorCSIDriverVersion = "3.0.9"
)
// Config struct fills the parameters of request or user input
+1 -1
View File
@@ -1,4 +1,4 @@
vitastor (3.0.8-1) unstable; urgency=medium
vitastor (3.0.9-1) unstable; urgency=medium
* Bugfixes
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v3.0.8
VITASTOR_VERSION ?= v3.0.9
all: build push
+1 -1
View File
@@ -4,7 +4,7 @@
#
# Desired Vitastor version
VITASTOR_VERSION=v3.0.8
VITASTOR_VERSION=v3.0.9
# Additional arguments for all containers
# For example, you may want to specify a custom logging driver here
+7
View File
@@ -70,6 +70,7 @@ with an OSD restart or, for some of them, even without restarting by updating co
- [use_atomic_flag](#use_atomic_flag)
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
- [gc_on_start](#gc_on_start)
## bind_address
@@ -753,3 +754,9 @@ This option sets the maximum number of object is a chunk. Moving 100k objects us
- Default: 100
This option sets the interval between handling two PG count change chunks.
## gc_on_start
- Type: boolean
Forcibly clean all garbage entries in the new store on every OSD restart.
+7
View File
@@ -71,6 +71,7 @@
- [use_atomic_flag](#use_atomic_flag)
- [pg_reshard_chunk_size](#pg_reshard_chunk_size)
- [pg_reshard_chunk_pause_ms](#pg_reshard_chunk_pause_ms)
- [gc_on_start](#gc_on_start)
## bind_address
@@ -793,3 +794,9 @@ pg_minsize OSD во время переключений, что может по
- Значение по умолчанию: 100
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
## gc_on_start
- Тип: булево (да/нет)
Принудительно очищать все мусорные записи в новом хранилище при каждом запуске OSD.
+4
View File
@@ -938,3 +938,7 @@
This option sets the interval between handling two PG count change chunks.
info_ru: |
Данная опция задаёт интервал между обработкой двух порций изменения числа PG пулов.
- name: gc_on_start
type: bool
info: Forcibly clean all garbage entries in the new store on every OSD restart.
info_ru: Принудительно очищать все мусорные записи в новом хранилище при каждом запуске OSD.
+2 -2
View File
@@ -26,9 +26,9 @@ at Vitastor Kubernetes operator: https://github.com/Antilles7227/vitastor-operat
The instruction is very simple.
1. Download a Docker image of the desired version: \
`docker pull vitalif/vitastor:v3.0.8`
`docker pull vitalif/vitastor:v3.0.9`
2. Install scripts to the host system: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.8 install.sh`
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.9 install.sh`
3. Reload udev rules: \
`udevadm control --reload-rules`
4. Enable the vitastor-host service: \
+2 -2
View File
@@ -25,9 +25,9 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
Инструкция по установке максимально простая.
1. Скачайте Docker-образ желаемой версии: \
`docker pull vitalif/vitastor:v3.0.8`
`docker pull vitalif/vitastor:v3.0.9`
2. Установите скрипты в хост-систему командой: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.8 install.sh`
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.9 install.sh`
3. Перезагрузите правила udev: \
`udevadm control --reload-rules`
4. Включите сервис vitastor-host: \
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vitastor-mon",
"version": "3.0.8",
"version": "3.0.9",
"description": "Vitastor SDS monitor service",
"main": "mon-main.js",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vitastor",
"version": "3.0.8",
"version": "3.0.9",
"description": "Low-level native bindings to Vitastor client library",
"main": "index.js",
"keywords": [
+1 -1
View File
@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver
from cinder.volume import volume_utils
VITASTOR_VERSION = '3.0.8'
VITASTOR_VERSION = '3.0.9'
LOG = logging.getLogger(__name__)
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.8
Version: 3.0.9
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.8.el10.tar.gz
Source0: vitastor-3.0.9.el10.tar.gz
BuildRequires: gperftools-devel
BuildRequires: gcc-c++
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.8
Version: 3.0.9
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.8.el7.tar.gz
Source0: vitastor-3.0.9.el7.tar.gz
BuildRequires: gperftools-devel
BuildRequires: devtoolset-9-gcc-c++
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.8
Version: 3.0.9
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.8.el8.tar.gz
Source0: vitastor-3.0.9.el8.tar.gz
BuildRequires: gperftools-devel
BuildRequires: gcc-toolset-9-gcc-c++
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.8
Version: 3.0.9
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.8.el9.tar.gz
Source0: vitastor-3.0.9.el9.tar.gz
BuildRequires: gperftools-devel
BuildRequires: gcc-c++
+1 -1
View File
@@ -20,7 +20,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
endif()
set(ENABLE_COVERAGE false CACHE BOOL "Enable code coverage")
add_definitions(-DVITASTOR_VERSION="3.0.8")
add_definitions(-DVITASTOR_VERSION="3.0.9")
add_definitions(-D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -fvisibility=hidden -I ${CMAKE_SOURCE_DIR}/src)
add_link_options(-fno-omit-frame-pointer)
if (${WITH_ASAN})
+1 -1
View File
@@ -877,7 +877,7 @@ uint64_t blockstore_impl_t::get_garbage_entries()
uint64_t blockstore_impl_t::get_garbage_memory()
{
return sizeof(blockstore_dirty_db_t::node_type) * dirty_db.size();
return (sizeof(obj_ver_id) + sizeof(dirty_entry) + 32) * dirty_db.size();
}
} // namespace v1
+26 -14
View File
@@ -164,30 +164,42 @@ void http_ares_cb(void *data, ares_socket_t socket_fd, int readable, int writabl
}
#ifdef WITH_OPENSSL
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
{
BIO *bio = NULL;
if (file_or_pem.substr(0, 5) != "-----")
{
std::string pem = read_file(file_or_pem);
bio = BIO_new_mem_buf(pem.data(), pem.size());
}
else
bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
if (!bio)
return false;
X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
bool ok = !!x509;
if (x509)
{
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
X509_STORE_add_cert(store, x509);
X509_free(x509);
}
BIO_free(bio);
return ok;
}
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
{
if (file_or_pem.substr(0, 5) == "-----")
{
BIO *bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
if (!bio)
return false;
X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
bool ok = !!x509;
if (x509)
{
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
X509_STORE_add_cert(store, x509);
X509_free(x509);
}
BIO_free(bio);
return ok;
return openssl_ctx_add_ca(ssl_ctx, file_or_pem);
}
return file_or_pem.empty()
? !!SSL_CTX_set_default_verify_paths(ssl_ctx)
: !!SSL_CTX_load_verify_locations(ssl_ctx, file_or_pem.c_str(), NULL);
}
static std::string openssl_get_cn(X509 *x509)
std::string openssl_get_cn(X509 *x509)
{
X509_NAME* subj = X509_get_subject_name(x509);
int pos = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
+12
View File
@@ -8,6 +8,10 @@
#include <functional>
#include "json11/json11.hpp"
#ifdef WITH_OPENSSL
#include <openssl/types.h>
#endif
#define WS_CONTINUATION 0
#define WS_TEXT 1
#define WS_BINARY 2
@@ -69,3 +73,11 @@ void http_close(http_co_t *co);
void http_destroy(http_co_t *co);
#pragma GCC visibility pop
#ifdef WITH_OPENSSL
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
std::string openssl_get_cn(X509 *x509);
bool openssl_ctx_use_cert(SSL_CTX *ssl_ctx, const std::string & file_or_pem, std::string & common_name);
bool openssl_ctx_use_key(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
#endif
+107 -4
View File
@@ -14,6 +14,13 @@
#ifdef WITH_RDMA
#include "msgr_rdma.h"
#endif
#include "http_client.h"
#ifdef WITH_OPENSSL
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#endif
#include <sys/poll.h>
@@ -117,6 +124,43 @@ void msgr_iothread_t::run()
void osd_messenger_t::init()
{
if (!tls_cert.empty() || !tls_key.empty() || !osd_tls_ca.empty() || !client_tls_ca.empty())
{
// Initialize TLS context
// FIXME: require OpenSSL
#ifndef WITH_OPENSSL
fprintf(stderr, "Vitastor is built without OpenSSL support\n");
exit(1);
#else
if (tls_cert.empty() || tls_key.empty() || osd_tls_ca.empty() || osd_num && client_tls_ca.empty())
{
if (osd_num)
fprintf(stderr, "Vitastor OSD TLS requires osd_tls_cert, osd_tls_key, osd_tls_ca, client_tls_ca\n");
else
fprintf(stderr, "Vitastor client TLS requires tls_cert, tls_key and osd_tls_ca\n");
exit(1);
}
else
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
bool ok = SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
ok = ok && openssl_ctx_add_ca(ssl_ctx, osd_tls_ca);
if (osd_num)
{
// OSD uses 2 separate root certificates to distinguish between clients and peer OSDs
ok = ok && openssl_ctx_add_ca(ssl_ctx, client_tls_ca);
}
ok = ok && openssl_ctx_use_cert(ssl_ctx, tls_cert, tls_cn);
ok = ok && openssl_ctx_use_key(ssl_ctx, tls_key);
if (!ok)
{
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
}
#endif
}
#ifdef WITH_RDMACM
if (use_rdmacm)
{
@@ -303,6 +347,13 @@ osd_messenger_t::~osd_messenger_t()
{
destroy_aes_xts_decrypt(decrypt_ctx);
}
#ifdef WITH_OPENSSL
if (ssl_ctx)
{
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
#endif
}
void osd_messenger_t::parse_config(const json11::Json & config)
@@ -340,7 +391,27 @@ void osd_messenger_t::parse_config(const json11::Json & config)
this->max_aes_xts_pool_size = config["max_aes_xts_pool_size"].uint64_value();
if (!this->max_aes_xts_pool_size)
this->max_aes_xts_pool_size = 256;
this->use_proto_checksums = config["use_proto_checksums"].is_null() || config["use_proto_checksums"].bool_value();
if (config["proto_checksums"].is_null())
this->use_proto_checksums = MSGR_CSUM_PAYLOAD;
else if (config["proto_checksums"].is_bool())
this->use_proto_checksums = config["proto_checksums"].bool_value() ? MSGR_CSUM_FULL : 0;
else if (config["proto_checksums"].string_value() != "")
this->use_proto_checksums = config["proto_checksums"].string_value() == "full" ? MSGR_CSUM_FULL : MSGR_CSUM_PAYLOAD;
else
this->use_proto_checksums = 0;
if (!osd_num)
{
tls_cert = config["tls_cert"].string_value();
tls_key = config["tls_key"].string_value();
osd_tls_ca = config["osd_tls_ca"].string_value();
}
else
{
tls_cert = config["osd_tls_cert"].string_value();
tls_key = config["osd_tls_key"].string_value();
osd_tls_ca = config["osd_tls_ca"].string_value();
client_tls_ca = config["client_tls_ca"].string_value();
}
if (!osd_num)
this->iothread_count = (uint32_t)config["client_iothread_count"].uint64_value();
else
@@ -571,6 +642,10 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
handle_peer_epoll(peer_fd, epoll_events);
});
// Check OSD number
if (!tls_cert.empty())
{
ssl_init(cl, false);
}
check_peer_config(cl);
}
@@ -663,7 +738,7 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
auto features = json11::Json::object{ { "check_sequencing", true } };
if (use_proto_checksums)
{
features["proto_checksums"] = true;
features["proto_checksums"] = use_proto_checksums;
}
payload["features"] = features;
#ifdef WITH_RDMA
@@ -740,9 +815,13 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
delete op;
return;
}
if (use_proto_checksums && config["features"]["proto_checksums"].bool_value())
if (use_proto_checksums)
{
cl->proto_csum_status = MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT;
auto peer_csums = config["features"]["proto_checksums"].uint64_value();
if (peer_csums == MSGR_CSUM_FULL && use_proto_checksums == MSGR_CSUM_FULL)
cl->proto_csum_status = MSGR_CSUM_FULL;
else if (peer_csums && use_proto_checksums)
cl->proto_csum_status = MSGR_CSUM_PAYLOAD;
}
#ifdef WITH_RDMA
if (!use_rdmacm && cl->rdma_conn && config["rdma_address"].is_string())
@@ -808,6 +887,10 @@ void osd_messenger_t::accept_connections(int listen_fd)
cl->peer_fd = peer_fd;
cl->peer_state = PEER_CONNECTED;
cl->in_buf = (uint8_t*)malloc_or_die(receive_buffer_size);
if (!tls_cert.empty())
{
ssl_init(cl, true);
}
// Add FD to epoll
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
{
@@ -822,6 +905,26 @@ void osd_messenger_t::accept_connections(int listen_fd)
}
}
void osd_messenger_t::ssl_init(osd_client_t *cl, bool server_mode)
{
#ifdef WITH_OPENSSL
cl->write_to_ssl = BIO_new(BIO_s_mem());
cl->read_from_ssl = BIO_new(BIO_s_mem());
cl->ssl_cli = SSL_new(ssl_ctx);
if (server_mode)
{
SSL_set_accept_state(cl->ssl_cli);
}
else
{
SSL_set_connect_state(cl->ssl_cli);
}
SSL_set_bio(cl->ssl_cli, cl->write_to_ssl, cl->read_from_ssl);
bool ok = ssl_do_handshake(cl);
assert(ok);
#endif
}
#ifdef WITH_RDMA
msgr_rdma_context_t* osd_messenger_t::choose_rdma_context(osd_client_t *cl)
{
+46 -3
View File
@@ -12,6 +12,10 @@
#include <deque>
#include <vector>
#ifdef WITH_OPENSSL
#include <openssl/types.h>
#endif
#include "../util/xxh_x86dispatch.h"
#include "../util/robin_hood.h"
#include "malloc_or_die.h"
@@ -32,8 +36,9 @@
#define PEER_RDMA 4
#define PEER_STOPPED 5
#define MSGR_PEER_CSUM_IN 1
#define MSGR_PEER_CSUM_OUT 2
#define MSGR_CSUM_PAYLOAD 1
#define MSGR_CSUM_FULL 2
#define MSGR_CSUM_NEG 4
#define VITASTOR_CONFIG_PATH "/etc/vitastor/vitastor.conf"
@@ -55,6 +60,12 @@ struct op_aes_xts_decrypt_t;
void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx);
void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx);
struct __attribute__((__packed__)) msgr_tls_record_hdr_t
{
uint8_t encrypted;
uint32_t size;
};
struct osd_client_t
{
uint64_t client_id = 0;
@@ -77,6 +88,17 @@ struct osd_client_t
msgr_rdma_connection_t *rdma_conn = NULL;
#endif
#ifdef WITH_OPENSSL
SSL *ssl_cli = NULL;
BIO *write_to_ssl = NULL;
// FIXME: use custom bio to avoid 1 more memory copy?
BIO *read_from_ssl = NULL;
uint8_t *ssl_out_buf = NULL;
size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0;
bool ssl_handshake_done = false;
bool ssl_want_write = false;
#endif
// Read state
int read_ready = 0;
osd_op_t *read_op = NULL;
@@ -210,6 +232,11 @@ protected:
int iothread_count = 0;
int max_aes_xts_pool_size = 256;
std::string tls_cert;
std::string tls_key;
std::string osd_tls_ca;
std::string client_tls_ca;
#ifdef WITH_RDMA
bool use_rdma = true;
bool use_rdmacm = false;
@@ -226,6 +253,19 @@ protected:
robin_hood::unordered_flat_map<rdma_cm_id*, rdmacm_connecting_t*> rdmacm_connecting;
#endif
#ifdef WITH_OPENSSL
SSL_CTX *ssl_ctx = NULL;
std::string tls_cn;
void ssl_init(osd_client_t *cl, bool server_mode);
bool ssl_do_handshake(osd_client_t *cl);
bool ssl_do_encrypt(osd_client_t *cl);
size_t ssl_do_encrypt_to(osd_client_t *cl, uint8_t *buf, size_t size);
bool ssl_op_write_buf(osd_client_t *cl, uint8_t *src, size_t src_len, bool skip_csum, size_t & from, size_t & done);
size_t ssl_op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_len);
void ssl_op_get_write_buffers(osd_client_t *cl, std::vector<iovec> & lst);
#endif
std::vector<msgr_iothread_t*> iothreads;
std::vector<uint64_t> read_ready_clients;
std::vector<uint64_t> write_ready_clients;
@@ -252,7 +292,7 @@ public:
std::vector<addr_mask_t> osd_cluster_network_masks;
std::vector<std::string> all_osd_networks;
std::vector<addr_mask_t> all_osd_network_masks;
bool use_proto_checksums = true;
int use_proto_checksums = 0;
// op statistics
osd_op_stats_t stats, recovery_stats;
@@ -304,6 +344,9 @@ protected:
void handle_send(int result, bool prev, bool more, osd_client_t *cl);
size_t op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_len);
void op_get_write_buffers(osd_client_t *cl, std::vector<iovec> & lst);
void next_write_op(osd_client_t *cl);
bool op_write_buf(osd_client_t *cl, uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len, bool skip_csum, size_t & from, size_t & done);
bool op_copy_data_to(osd_client_t *cl, uint8_t *dst, size_t dst_len, size_t & from, size_t & done);
void handle_read(int result, osd_client_t *cl);
bool handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size_t bufsize);
+17 -7
View File
@@ -187,6 +187,8 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
ibv_device **raw_dev_list = NULL;
ibv_device **dev_list = NULL;
ibv_device *single_list[2] = {};
int up_ports = 0;
int single_port_num = 0;
raw_dev_list = dev_list = ibv_get_device_list(NULL);
if (!dev_list || !*dev_list)
@@ -221,6 +223,7 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
dev_list = single_list;
}
retry:
for (int i = 0; dev_list[i]; ++i)
{
auto dev = dev_list[i];
@@ -258,6 +261,9 @@ std::vector<msgr_rdma_context_t*> msgr_rdma_context_t::create_all(const std::vec
fprintf(stderr, "RDMA device %s port %d GID %d does not exist\n", ibv_get_device_name(dev), port_num, sel_gid_index);
continue;
}
up_ports++;
single_port_num = port_num;
single_list[0] = dev;
uint32_t port_mtu = sel_mtu ? sel_mtu : ibv_mtu_to_bytes(portinfo.active_mtu);
#ifdef IBV_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT
if (sel_gid_index < 0)
@@ -298,6 +304,14 @@ cleanup_dev:
ibv_close_device(context);
}
if (!ret.size() && up_ports == 1 && dev_list != single_list)
{
// Auto-select the only available device/port if there is only one
dev_list = single_list;
sel_port_num = single_port_num;
goto retry;
}
cleanup:
if (raw_dev_list)
ibv_free_device_list(raw_dev_list);
@@ -559,11 +573,7 @@ int osd_messenger_t::try_send_rdma_copy(osd_client_t *cl, uint8_t *dst, int dst_
int total_dst_len = dst_len;
while (dst_len > 0 && (cl->write_op || cl->write_ops.size()))
{
if (!cl->write_op)
{
cl->write_op = cl->write_ops.front();
cl->write_ops.pop_front();
}
next_write_op(cl);
osd_op_t *op = cl->write_op;
size_t copied = op_copy_to(cl, dst, dst_len);
if (!copied)
@@ -744,10 +754,10 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
cl->send_free_ops.pop_front();
}
cl->send_free_ops.pop_front();
if (cl->proto_csum_status == MSGR_PEER_CSUM_IN && !cl->write_op && !cl->write_ops.size())
if ((cl->proto_csum_status & MSGR_CSUM_NEG) && !cl->write_op && !cl->write_ops.size())
{
// Checksums negotiated, enable
cl->proto_csum_status = MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT;
cl->proto_csum_status = cl->proto_csum_status & (~MSGR_CSUM_NEG);
}
try_send_rdma(cl);
}
+15 -10
View File
@@ -203,7 +203,7 @@ bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size
cl->read_op_size = 0;
cl->read_op_inline_decrypt_in = 0;
cl->read_op_inline_decrypt_pos = (size_t)-1;
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL || cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
if (!cl->read_csum_state)
cl->read_csum_state = XXH3_createState();
@@ -236,6 +236,10 @@ bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size
bool osd_messenger_t::handle_hdr(osd_client_t *cl)
{
if (cl->proto_csum_status == MSGR_CSUM_FULL)
{
XXH3_64bits_update(cl->read_csum_state, cl->read_op->req.buf, OSD_PACKET_SIZE);
}
if (cl->read_op->req.hdr.magic == SECONDARY_OSD_REPLY_MAGIC)
{
auto req_it = cl->sent_ops.find(cl->read_op->req.hdr.id);
@@ -333,7 +337,8 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
}
cl->read_op_size = cur_op->req.show_conf.json_len;
}
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
cl->read_op_size += 8;
}
@@ -391,7 +396,8 @@ bool osd_messenger_t::allocate_reply_buffers(osd_client_t *cl, osd_op_t *op)
free(op->buf);
op->buf = malloc_or_die(op->reply.describe.result_bytes);
}
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
cl->read_op_size += 8;
}
@@ -429,10 +435,6 @@ bool osd_messenger_t::op_copy_from(osd_client_t *cl, uint8_t *src, size_t src_le
from -= dst_len;
return true;
};
if (cl->read_csum_state && !from)
{
XXH3_64bits_update(cl->read_csum_state, (op->op_type == OSD_OP_IN ? op->req.buf : op->reply.buf), OSD_PACKET_SIZE);
}
if (op->op_type == OSD_OP_IN)
{
if (op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
@@ -520,7 +522,8 @@ bool osd_messenger_t::op_copy_from(osd_client_t *cl, uint8_t *src, size_t src_le
return true;
}
}
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
if (!op_read_buf((uint8_t*)&op->csum, 8, true))
return true;
@@ -642,7 +645,8 @@ void osd_messenger_t::op_get_read_buffers(osd_client_t *cl, std::vector<iovec> &
return;
}
}
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
if (!op_read_buf((uint8_t*)&op->csum, 8))
return;
@@ -676,7 +680,8 @@ void osd_messenger_t::op_alloc_temp_buffers(osd_op_t *op, int i)
bool osd_messenger_t::handle_finished_op(osd_client_t *cl)
{
osd_op_t *op = cl->read_op;
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT))
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
uint64_t real_csum = XXH3_64bits_digest(cl->read_csum_state);
if (op->csum != real_csum)
+383 -64
View File
@@ -7,6 +7,13 @@
#include "messenger.h"
#ifdef WITH_OPENSSL
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#endif
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
{
assert(cur_op->client_id);
@@ -116,25 +123,103 @@ void osd_messenger_t::measure_exec(osd_op_t *cur_op)
}
}
bool osd_messenger_t::ssl_do_handshake(osd_client_t *cl)
{
int r = SSL_do_handshake(cl->ssl_cli);
if (r > 0)
{
cl->ssl_handshake_done = true;
}
else
{
r = SSL_get_error(cl->ssl_cli, r);
if (r != SSL_ERROR_WANT_WRITE && r != SSL_ERROR_WANT_READ)
{
fprintf(stderr, "Client %ju TLS handshake error: %s, stopping client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
stop_client(cl->client_id);
return false;
}
if (r == SSL_ERROR_WANT_WRITE)
{
cl->ssl_want_write = true;
}
}
return true;
}
bool osd_messenger_t::ssl_do_encrypt(osd_client_t *cl)
{
if (cl->send_list.size() >= IOV_MAX || !cl->ssl_want_write)
return false;
size_t prev_size = cl->ssl_out_buf_size;
while (true)
{
size_t min_cap = cl->ssl_out_buf_size*2;
if (min_cap < 16384)
min_cap = 16384;
if (cl->ssl_out_buf_cap < min_cap)
{
uint8_t *old_buf = cl->ssl_out_buf;
uint8_t *old_end = old_buf + cl->ssl_out_buf_cap;
cl->ssl_out_buf = (uint8_t*)realloc_or_die(cl->ssl_out_buf, min_cap);
cl->ssl_out_buf_cap = min_cap;
for (auto & iov: cl->send_list)
{
if (iov.iov_base >= old_buf && iov.iov_base < old_end)
iov.iov_base = cl->ssl_out_buf + ((uint8_t*)iov.iov_base - old_buf);
}
}
bool full_read = (ssl_do_encrypt_to(cl, cl->ssl_out_buf+cl->ssl_out_buf_size,
cl->ssl_out_buf_cap-cl->ssl_out_buf_size) == cl->ssl_out_buf_cap-cl->ssl_out_buf_size);
if (!full_read)
break;
}
if (cl->ssl_out_buf_size > prev_size)
cl->send_list.push_back((iovec){ .iov_base = cl->ssl_out_buf+prev_size, .iov_len = cl->ssl_out_buf_size-prev_size });
return true;
}
size_t osd_messenger_t::ssl_do_encrypt_to(osd_client_t *cl, uint8_t *buf, size_t size)
{
if (size < sizeof(msgr_tls_record_hdr_t))
return 0;
int r = BIO_read(cl->read_from_ssl, buf+sizeof(msgr_tls_record_hdr_t), size-sizeof(msgr_tls_record_hdr_t));
if (r > 0)
{
if (r < size-sizeof(msgr_tls_record_hdr_t))
cl->ssl_want_write = false;
msgr_tls_record_hdr_t *hdr = (msgr_tls_record_hdr_t*)buf;
hdr->encrypted = 1;
hdr->size = r;
return r+sizeof(msgr_tls_record_hdr_t);
}
return 0;
}
bool osd_messenger_t::try_send(osd_client_t *cl)
{
if (!cl->write_op && !cl->write_ops.size() || cl->write_msg.msg_iovlen > 0 || cl->peer_state == PEER_STOPPED || cl->peer_fd < 0)
if (!cl->write_op && !cl->write_ops.size() && !cl->ssl_want_write ||
cl->write_msg.msg_iovlen > 0 || cl->peer_state == PEER_STOPPED || cl->peer_fd < 0)
{
return true;
}
assert(cl->peer_state != PEER_RDMA);
while ((cl->write_op || cl->write_ops.size()) && cl->send_list.size() < IOV_MAX)
if (cl->ssl_cli && !cl->ssl_handshake_done)
{
if (!cl->write_op)
bool ok = ssl_do_encrypt(cl);
assert(ok && cl->send_list.size() > 0);
}
else
{
while ((cl->write_op || cl->write_ops.size()) && cl->send_list.size() < IOV_MAX)
{
cl->write_op = cl->write_ops.front();
cl->write_ops.pop_front();
}
osd_op_t *op = cl->write_op;
op_get_write_buffers(cl, cl->send_list);
if (!cl->write_op && op->op_type == OSD_OP_IN)
{
cl->send_free_ops.push_back(op);
next_write_op(cl);
osd_op_t *op = cl->write_op;
op_get_write_buffers(cl, cl->send_list);
if (!cl->write_op && op->op_type == OSD_OP_IN)
{
cl->send_free_ops.push_back(op);
}
}
}
if (ringloop && !use_sync_send_recv)
@@ -197,6 +282,21 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
return true;
}
void osd_messenger_t::next_write_op(osd_client_t *cl)
{
if (!cl->write_op)
{
cl->write_op = cl->write_ops.front();
cl->write_ops.pop_front();
if (cl->proto_csum_status == MSGR_CSUM_FULL || cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
{
if (!cl->write_csum_state)
cl->write_csum_state = XXH3_createState();
XXH3_64bits_reset(cl->write_csum_state);
}
}
}
void osd_messenger_t::send_replies()
{
for (int i = 0; i < write_ready_clients.size(); i++)
@@ -264,14 +364,15 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
else
delete op;
}
cl->ssl_out_buf_size = 0;
if (more)
cl->zc_free_list.push_back(NULL); // end marker
cl->send_free_ops.clear();
cl->write_state = cl->write_op || cl->write_ops.size() ? CL_WRITE_READY : 0;
if (cl->proto_csum_status == MSGR_PEER_CSUM_IN && !cl->write_op && !cl->write_ops.size())
if ((cl->proto_csum_status & MSGR_CSUM_NEG) && !cl->write_op && !cl->write_ops.size())
{
// Checksums negotiated, enable
cl->proto_csum_status = MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT;
cl->proto_csum_status = cl->proto_csum_status & (~MSGR_CSUM_NEG);
}
#ifdef WITH_RDMA
if (cl->rdma_conn && !cl->write_op && !cl->write_ops.size() && cl->peer_state == PEER_RDMA_CONNECTING)
@@ -293,36 +394,37 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
}
}
static inline bool op_write_headers(osd_op_t *op, std::function<bool(uint8_t*, size_t)> op_write_buf)
static inline bool op_write_headers(osd_op_t *op, std::function<bool(uint8_t*, size_t, bool)> op_write_buf, bool skip_hdr_csum)
{
// Header
if (!op_write_buf((op->op_type == OSD_OP_IN ? op->reply.buf : op->req.buf), OSD_PACKET_SIZE))
if (!op_write_buf((op->op_type == OSD_OP_IN ? op->reply.buf : op->req.buf), OSD_PACKET_SIZE, skip_hdr_csum))
{
return false;
}
// Bitmap
if (op->op_type == OSD_OP_IN &&
op->req.hdr.opcode == OSD_OP_SEC_READ &&
op->reply.sec_rw.attr_len > 0)
{
if (!op_write_buf((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len))
if (!op_write_buf((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len, false))
return false;
}
else if (op->op_type == OSD_OP_OUT &&
(op->req.hdr.opcode == OSD_OP_SEC_WRITE || op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) &&
op->req.sec_rw.attr_len > 0)
{
if (!op_write_buf((uint8_t*)op->bitmap, op->req.sec_rw.attr_len))
if (!op_write_buf((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, false))
return false;
}
if (op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
{
if (op->op_type == OSD_OP_IN && op->reply.hdr.retval > 0)
{
if (!op_write_buf((uint8_t*)op->buf, (size_t)op->reply.hdr.retval))
if (!op_write_buf((uint8_t*)op->buf, (size_t)op->reply.hdr.retval, false))
return false;
}
else if (op->op_type == OSD_OP_OUT && op->req.sec_read_bmp.len > 0)
{
if (!op_write_buf((uint8_t*)op->buf, (size_t)op->req.sec_read_bmp.len))
if (!op_write_buf((uint8_t*)op->buf, (size_t)op->req.sec_read_bmp.len, false))
return false;
}
}
@@ -345,20 +447,38 @@ static inline bool op_has_data(osd_op_t *op)
op->req.hdr.opcode == OSD_OP_SHOW_CONFIG)) && op->iov.count > 0;
}
size_t osd_messenger_t::op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_len)
static inline bool op_has_data_for_ssl(osd_op_t *op)
{
size_t done = 0;
size_t from = cl->write_op_pos;
auto op_write_buf = [&](uint8_t *src, size_t src_len, bool skip_csum = false)
return (op->op_type == OSD_OP_IN
? (op->req.hdr.opcode == OSD_OP_SEC_LIST ||
op->req.hdr.opcode == OSD_OP_SHOW_CONFIG ||
op->req.hdr.opcode == OSD_OP_DESCRIBE)
: (op->req.hdr.opcode == OSD_OP_SEC_STABILIZE ||
op->req.hdr.opcode == OSD_OP_SEC_ROLLBACK ||
op->req.hdr.opcode == OSD_OP_SHOW_CONFIG)) && op->iov.count > 0;
}
static inline bool op_has_data_for_nonssl(osd_op_t *op)
{
return (op->op_type == OSD_OP_IN
? (op->req.hdr.opcode == OSD_OP_READ ||
op->req.hdr.opcode == OSD_OP_SEC_READ)
: (op->req.hdr.opcode == OSD_OP_WRITE ||
op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)) && op->iov.count > 0;
}
bool osd_messenger_t::ssl_op_write_buf(osd_client_t *cl, uint8_t *src, size_t src_len, bool skip_csum, size_t & from, size_t & done)
{
if (from < src_len)
{
if (from < src_len)
size_t n = src_len-from;
int ok = SSL_write_ex(cl->ssl_cli, src+from, n, &n);
if (ok)
{
size_t n = src_len-from;
if (n > dst_len-done)
n = dst_len-done;
cl->ssl_want_write = true;
if (cl->write_csum_state && !skip_csum)
XXH3_64bits_update(cl->write_csum_state, src+from, n);
memcpy(dst+done, src+from, n);
done += n;
cl->write_op_pos += n;
from += n;
@@ -367,39 +487,135 @@ size_t osd_messenger_t::op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_le
from = 0;
}
else
from -= src_len;
return true;
};
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT) && !from)
{
if (!cl->write_csum_state)
cl->write_csum_state = XXH3_createState();
XXH3_64bits_reset(cl->write_csum_state);
{
int res = SSL_get_error(cl->ssl_cli, ok);
if (res == SSL_ERROR_WANT_WRITE || res == 0)
cl->ssl_want_write = true;
else if (res == SSL_ERROR_ZERO_RETURN)
{
fprintf(stderr, "Client %ju TLS disconnected\n", cl->client_id);
stop_client(cl->client_id);
}
else if (res != SSL_ERROR_WANT_READ)
{
fprintf(stderr, "Client %ju TLS write error: %s. Disconnecting client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
stop_client(cl->client_id);
}
return false;
}
}
if (!op_write_headers(cl->write_op, op_write_buf))
else
from -= src_len;
return true;
}
bool osd_messenger_t::op_write_buf(osd_client_t *cl, uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len, bool skip_csum, size_t & from, size_t & done)
{
if (from < src_len)
{
size_t n = src_len-from;
if (n > dst_len-done)
n = dst_len-done;
if (cl->write_csum_state && !skip_csum)
XXH3_64bits_update(cl->write_csum_state, src+from, n);
memcpy(dst+done, src+from, n);
done += n;
cl->write_op_pos += n;
from += n;
if (from < src_len)
return false;
from = 0;
}
else
from -= src_len;
return true;
}
size_t osd_messenger_t::ssl_op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_len)
{
size_t done = 0;
size_t from = cl->write_op_pos;
// Encrypt headers and data except read/write data
auto to_ssl = [&](uint8_t *src, size_t src_len, bool skip_csum)
{
return ssl_op_write_buf(cl, src, src_len, skip_csum, from, done);
};
int i = 0;
bool full_hdr = false;
bool full_op = false;
do
{
if (!full_hdr)
full_hdr = op_write_headers(cl->write_op, to_ssl, cl->proto_csum_status != MSGR_CSUM_FULL);
if (full_hdr && op_has_data_for_ssl(cl->write_op))
{
for (; i < cl->write_op->iov.count; i++)
if (!ssl_op_write_buf(cl, (uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len, false, from, done))
break;
full_op = true;
}
if (cl->peer_state == PEER_STOPPED)
return 0;
if (cl->ssl_want_write)
{
auto ssl_written = ssl_do_encrypt_to(cl, dst+done, dst_len-done);
if (!ssl_written)
return done;
done += ssl_written;
}
} while (!full_op);
// Non-TLS-encrypted operation data
if (op_has_data_for_nonssl(cl->write_op))
{
if (!op_copy_data_to(cl, dst, dst_len, from, done))
return done;
}
// TLS-encrypted checksum (uh oh...)
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->proto_csum_status == MSGR_CSUM_PAYLOAD && cl->write_op_pos > OSD_PACKET_SIZE)
{
if (!from)
cl->write_op->csum = XXH3_64bits_digest(cl->write_csum_state);
if (!ssl_op_write_buf(cl, (uint8_t*)&cl->write_op->csum, 8, true, from, done))
return done;
if (cl->ssl_want_write)
{
auto ssl_written = ssl_do_encrypt_to(cl, dst+done, dst_len-done);
if (!ssl_written)
return done;
done += ssl_written;
}
}
cl->write_op = NULL;
cl->write_op_pos = 0;
return done;
}
size_t osd_messenger_t::op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_len)
{
if (cl->ssl_cli)
{
return ssl_op_copy_to(cl, dst, dst_len);
}
size_t done = 0;
size_t from = cl->write_op_pos;
auto op_write_buf = [&](uint8_t *src, size_t src_len, bool skip_csum)
{
return this->op_write_buf(cl, src, src_len, dst, dst_len, skip_csum, from, done);
};
// Header
if (!op_write_headers(cl->write_op, op_write_buf, cl->proto_csum_status != MSGR_CSUM_FULL))
{
return done;
}
// Operation data
if (op_has_data(cl->write_op))
{
if (cl->write_op->enc)
{
if (!op_encrypted_copy_data_to(cl, dst, dst_len, from, done))
{
return done;
}
}
else
{
for (int i = 0; i < cl->write_op->iov.count; i++)
{
if (!op_write_buf((uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len))
return done;
}
}
if (!op_copy_data_to(cl, dst, dst_len, from, done))
return done;
}
if (cl->write_csum_state)
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->proto_csum_status == MSGR_CSUM_PAYLOAD && cl->write_op_pos > OSD_PACKET_SIZE)
{
if (!from)
cl->write_op->csum = XXH3_64bits_digest(cl->write_csum_state);
@@ -411,10 +627,31 @@ size_t osd_messenger_t::op_copy_to(osd_client_t *cl, uint8_t *dst, size_t dst_le
return done;
}
bool osd_messenger_t::op_copy_data_to(osd_client_t *cl, uint8_t *dst, size_t dst_len, size_t & from, size_t & done)
{
if (cl->write_op->enc)
{
if (!op_encrypted_copy_data_to(cl, dst, dst_len, from, done))
{
return false;
}
}
else
{
for (int i = 0; i < cl->write_op->iov.count; i++)
{
auto & iov = cl->write_op->iov.buf[i];
if (!op_write_buf(cl, (uint8_t*)iov.iov_base, iov.iov_len, dst, dst_len, false, from, done))
return false;
}
}
return true;
}
void osd_messenger_t::op_get_write_buffers(osd_client_t *cl, std::vector<iovec> & lst)
{
size_t from = cl->write_op_pos;
auto op_write_buf = [&](uint8_t *src, size_t src_len, bool skip_csum = false)
auto op_write_buf = [&](uint8_t *src, size_t src_len, bool skip_csum)
{
if (lst.size() >= IOV_MAX)
return false;
@@ -430,13 +667,8 @@ void osd_messenger_t::op_get_write_buffers(osd_client_t *cl, std::vector<iovec>
from -= src_len;
return true;
};
if (cl->proto_csum_status == (MSGR_PEER_CSUM_IN|MSGR_PEER_CSUM_OUT) && !from)
{
if (!cl->write_csum_state)
cl->write_csum_state = XXH3_createState();
XXH3_64bits_reset(cl->write_csum_state);
}
if (!op_write_headers(cl->write_op, op_write_buf))
// Header
if (!op_write_headers(cl->write_op, op_write_buf, cl->proto_csum_status != MSGR_CSUM_FULL))
{
return;
}
@@ -462,12 +694,13 @@ void osd_messenger_t::op_get_write_buffers(osd_client_t *cl, std::vector<iovec>
{
for (int i = 0; i < cl->write_op->iov.count; i++)
{
if (!op_write_buf((uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len))
if (!op_write_buf((uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len, false))
return;
}
}
}
if (cl->write_csum_state)
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->proto_csum_status == MSGR_CSUM_PAYLOAD && cl->write_op_pos > OSD_PACKET_SIZE)
{
if (!from)
cl->write_op->csum = XXH3_64bits_digest(cl->write_csum_state);
@@ -477,3 +710,89 @@ void osd_messenger_t::op_get_write_buffers(osd_client_t *cl, std::vector<iovec>
cl->write_op = NULL;
cl->write_op_pos = 0;
}
void osd_messenger_t::ssl_op_get_write_buffers(osd_client_t *cl, std::vector<iovec> & lst)
{
size_t done = 0;
size_t from = cl->write_op_pos;
auto op_write_buf = [&](uint8_t *src, size_t src_len, bool skip_csum)
{
if (lst.size() >= IOV_MAX)
return false;
if (from < src_len)
{
if (cl->write_csum_state && !skip_csum)
XXH3_64bits_update(cl->write_csum_state, src+from, src_len-from);
lst.push_back((iovec){ .iov_base = src+from, .iov_len = src_len-from });
cl->write_op_pos += src_len-from;
from = 0;
}
else
from -= src_len;
return true;
};
// Encrypt headers and data except read/write data
auto to_ssl = [&](uint8_t *src, size_t src_len, bool skip_csum)
{
return ssl_op_write_buf(cl, src, src_len, skip_csum, from, done);
};
int i = 0;
bool full_hdr = false;
bool full_op = false;
do
{
if (!full_hdr)
full_hdr = op_write_headers(cl->write_op, to_ssl, cl->proto_csum_status != MSGR_CSUM_FULL);
if (full_hdr && op_has_data_for_ssl(cl->write_op))
{
for (; i < cl->write_op->iov.count; i++)
if (!ssl_op_write_buf(cl, (uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len, false, from, done))
break;
full_op = true;
}
if (cl->peer_state == PEER_STOPPED)
return;
if (!ssl_do_encrypt(cl))
return;
} while (!full_op);
// Non-TLS-encrypted operation data
if (op_has_data_for_nonssl(cl->write_op))
{
if (cl->write_op->enc)
{
if (lst.size() >= IOV_MAX)
return;
// No way except to allocate a temporary buffer and encrypt data to it
assert(cl->write_op->req.hdr.opcode == OSD_OP_WRITE);
size_t remsize = cl->write_op->req.rw.len - from + (from % 16);
assert(remsize > 0);
assert(!cl->write_op->enc_buf);
cl->write_op->enc_buf = (uint8_t*)malloc_or_die(remsize);
size_t done = 0;
bool end = op_encrypted_copy_data_to(cl, cl->write_op->enc_buf, remsize, from, done);
assert(end);
lst.push_back((iovec){ .iov_base = cl->write_op->enc_buf, .iov_len = remsize });
}
else
{
for (int i = 0; i < cl->write_op->iov.count; i++)
{
if (!op_write_buf((uint8_t*)cl->write_op->iov.buf[i].iov_base, cl->write_op->iov.buf[i].iov_len, false))
return;
}
}
}
// TLS-encrypted checksum (uh oh...)
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
cl->proto_csum_status == MSGR_CSUM_PAYLOAD && cl->write_op_pos > OSD_PACKET_SIZE)
{
if (!from)
cl->write_op->csum = XXH3_64bits_digest(cl->write_csum_state);
if (!ssl_op_write_buf(cl, (uint8_t*)&cl->write_op->csum, 8, true, from, done))
return;
if (!ssl_do_encrypt(cl))
return;
}
cl->write_op = NULL;
cl->write_op_pos = 0;
}
+20
View File
@@ -9,6 +9,12 @@
#ifdef WITH_RDMA
#include "msgr_rdma.h"
#endif
#ifdef WITH_OPENSSL
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#endif
void osd_client_t::cancel_ops()
{
@@ -239,4 +245,18 @@ osd_client_t::~osd_client_t()
XXH3_freeState(write_csum_state);
write_csum_state = NULL;
}
#ifdef WITH_OPENSSL
if (ssl_cli)
{
SSL_free(ssl_cli);
ssl_cli = NULL;
write_to_ssl = NULL;
read_from_ssl = NULL;
}
if (ssl_out_buf)
{
free(ssl_out_buf);
ssl_out_buf = NULL;
}
#endif
}
+1 -1
View File
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor
Description: Vitastor client library
Version: 3.0.8
Version: 3.0.9
Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir}
-39
View File
@@ -8,7 +8,6 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include "xxhash.h"
#include "addr_util.h"
#include "osd_primary.h"
#include "osd.h"
@@ -16,46 +15,8 @@
#include "str_util.h"
#include "json_util.h"
void xxhash_run_test(XXH3_state_t *st, void *buf, size_t size)
{
timespec tv, tv1;
clock_gettime(CLOCK_REALTIME, &tv);
uint64_t res = 1;
uint64_t done = 0;
while (true)
{
XXH3_64bits_reset(st);
XXH3_64bits_update(st, buf, size);
res *= XXH3_64bits_digest(st);
done++;
if (!(done % 100000))
{
clock_gettime(CLOCK_REALTIME, &tv1);
if ((tv1.tv_sec-tv.tv_sec)*1000 + (tv1.tv_nsec-tv.tv_nsec)/1000000 > 1000)
break;
}
}
double sec = (tv1.tv_sec-tv.tv_sec) + (tv1.tv_nsec-tv.tv_nsec)/1000000000.0;
fprintf(stderr, "xxhash3: %lu %zu byte blocks in %.2f sec = %.1f MB/s\n",
done, size, sec, done*size/sec/1024/1024);
}
void xxhash_bench()
{
std::vector<uint8_t> buf;
buf.resize(128*1024);
for (size_t i = 0; i < buf.size(); i++)
buf[i] = ((i+37)*3) % 255;
XXH3_state_t *st = XXH3_createState();
xxhash_run_test(st, buf.data(), 4096);
xxhash_run_test(st, buf.data(), buf.size());
XXH3_freeState(st);
}
osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
{
xxhash_bench();
zero_buffer_size = 1<<20;
zero_buffer = malloc_or_die(zero_buffer_size);
memset(zero_buffer, 0, zero_buffer_size);
+10 -3
View File
@@ -348,10 +348,17 @@ void osd_t::exec_show_config(osd_op_t *cur_op)
cl->read_op_id = cur_op->req.hdr.id + 1;
}
auto features = json11::Json::object{ { "pg_locks", true } };
if (req_json["features"]["proto_checksums"].bool_value() && msgr.use_proto_checksums)
if (msgr.use_proto_checksums)
{
cl->proto_csum_status = MSGR_PEER_CSUM_IN;
features["proto_checksums"] = true;
auto peer_csums = req_json["features"]["proto_checksums"].uint64_value();
if (peer_csums == MSGR_CSUM_FULL || peer_csums == MSGR_CSUM_PAYLOAD)
{
if (msgr.use_proto_checksums == MSGR_CSUM_FULL && peer_csums == MSGR_CSUM_FULL)
cl->proto_csum_status = MSGR_CSUM_FULL|MSGR_CSUM_NEG;
else
cl->proto_csum_status = MSGR_CSUM_PAYLOAD|MSGR_CSUM_NEG;
features["proto_checksums"] = msgr.use_proto_checksums;
}
}
// Expose sensitive configuration values so peers can check them
json11::Json::object wire_config = json11::Json::object {
+9 -1
View File
@@ -41,7 +41,7 @@ add_executable(test_heap
../blockstore/multilist.cpp
../blockstore/blockstore_heap.cpp
../util/crc32c.c
../util/xxhash.c
../util/xxh_x86dispatch.c
../util/allocator.cpp
../blockstore/blockstore_disk.cpp
../util/str_util.cpp
@@ -62,6 +62,14 @@ target_link_libraries(test_cas
vitastor_client
)
# http_hello
add_executable(http_hello
http_hello.cpp
)
target_link_libraries(http_hello
vitastor_client
)
# test_crc32
add_executable(test_crc32
test_crc32.cpp
+61
View File
@@ -0,0 +1,61 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdexcept>
#include "http_client.h"
#include "ringloop.h"
#include "epoll_manager.h"
#include "addr_util.h"
int main(int narg, char *args[])
{
ring_consumer_t looper;
ring_loop_t *ringloop = new ring_loop_t(RINGLOOP_DEFAULT_SIZE);
epoll_manager_t *epmgr = new epoll_manager_t(ringloop);
// Accept new connections
int listen_fd = create_and_bind_socket("0.0.0.0", 8085, 128, NULL);
fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL, 0) | O_NONBLOCK);
std::string error;
auto http_ctx = http_context_init(epmgr->tfd, "", "", "", false, error);
epmgr->set_fd_handler(listen_fd, false, [http_ctx](int listen_fd, int events)
{
sockaddr_storage addr;
socklen_t peer_addr_size = sizeof(addr);
int peer_fd;
while ((peer_fd = accept(listen_fd, (sockaddr*)&addr, &peer_addr_size)) >= 0)
{
assert(peer_fd != 0);
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
int one = 1;
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
auto co = http_init(http_ctx);
http_serve(co, peer_fd, (http_options_t){}, [co](http_message_t *msg)
{
if (msg->eof)
{
http_destroy(co);
return;
}
http_reply(co, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: 13\r\n\r\nHello, world!");
});
}
});
while (true)
{
ringloop->loop();
ringloop->wait();
}
delete epmgr;
delete ringloop;
return 0;
}