Recent changes (master)

Jens Axboe
2018-08-17T15:03:35Z

The following changes since commit 35e2d88fad2151f272af60babb5e6c98922d0bcd:

Fix compilation on centos 7 (2018-08-15 12:06:14 -0600)

are available in the git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to 9ee669faa39003c2317e5df892314bcfcee069e3:

configure: avoid pkg-config usage for http engine (2018-08-16 18:58:27 +0200)

----------------------------------------------------------------
David Disseldorp (3):
configure: use pkg-config to detect libcurl & openssl
engines/http: support openssl < 1.1.0
configure: avoid pkg-config usage for http engine

Jens Axboe (3):
Merge branch 'http_older_openssl' of https://github.com/ddiss/fio
engines/http: fix use of uninitialized variable
Merge branch 'wip-http-swift' of https://github.com/l-mb/fio

Lars Marowsky-Bree (1):
engines/http: Add support for Swift storage backend

HOWTO | 17 ++++--
configure | 35 ++++++++++--
engines/http.c | 135 +++++++++++++++++++++++++++++++++++++++++------
examples/http-s3.fio | 4 +-
examples/http-swift.fio | 32 +++++++++++
examples/http-webdav.fio | 4 +-
fio.1 | 16 ++++--
7 files changed, 209 insertions(+), 34 deletions(-)
create mode 100644 examples/http-swift.fio

---

Diff of recent changes:

diff --git a/HOWTO b/HOWTO
index c77dad1..743144f 100644
--- a/HOWTO
+++ b/HOWTO
@@ -2137,14 +2137,16 @@ with the caveat that when used on the command line, they must come after the

Password for HTTP authentication.

-.. option:: https=bool : [http]
+.. option:: https=str : [http]

- Enable HTTPS instead of http. Default is **0**
+ Enable HTTPS instead of http. *on* enables HTTPS; *insecure*
+ will enable HTTPS, but disable SSL peer verification (use with
+ caution!). Default is **off**

-.. option:: http_s3=bool : [http]
+.. option:: http_mode=str : [http]

- Enable S3 specific HTTP headers such as authenticating requests
- with AWS Signature Version 4. Default is **0**
+ Which HTTP access mode to use: *webdav*, *swift*, or *s3*.
+ Default is **webdav**

.. option:: http_s3_region=str : [http]

@@ -2159,6 +2161,11 @@ with the caveat that when used on the command line, they must come after the

The S3 key/access id.

+.. option:: http_swift_auth_token=str : [http]
+
+ The Swift auth token. See the example configuration file on how
+ to retrieve this.
+
.. option:: http_verbose=int : [http]

Enable verbose requests from libcurl. Useful for debugging. 1
diff --git a/configure b/configure
index 103ea94..a03f7fa 100755
--- a/configure
+++ b/configure
@@ -14,12 +14,13 @@ else
fi

TMPC="${TMPDIR1}/fio-conf-${RANDOM}-$$-${RANDOM}.c"
+TMPC2="${TMPDIR1}/fio-conf-${RANDOM}-$$-${RANDOM}-2.c"
TMPO="${TMPDIR1}/fio-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/fio-conf-${RANDOM}-$$-${RANDOM}.exe"

# NB: do not call "exit" in the trap handler; this is buggy with some shells;
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
-trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM
+trap "rm -f $TMPC $TMPC2 $TMPO $TMPE" EXIT INT QUIT TERM

rm -rf config.log

@@ -1573,6 +1574,7 @@ print_config "IPv6 helpers" "$ipv6"
if test "$http" != "yes" ; then
http="no"
fi
+# check for openssl >= 1.1.0, which uses an opaque HMAC_CTX pointer
cat > $TMPC << EOF
#include <curl/curl.h>
#include <openssl/hmac.h>
@@ -1591,9 +1593,34 @@ int main(int argc, char **argv)
return 0;
}
EOF
-if test "$disable_http" != "yes" && compile_prog "" "-lcurl -lssl -lcrypto" "curl"; then
- LIBS="-lcurl -lssl -lcrypto $LIBS"
- http="yes"
+# openssl < 1.1.0 uses the HMAC_CTX type directly
+cat > $TMPC2 << EOF
+#include <curl/curl.h>
+#include <openssl/hmac.h>
+
+int main(int argc, char **argv)
+{
+ CURL *curl;
+ HMAC_CTX ctx;
+
+ curl = curl_easy_init();
+ curl_easy_cleanup(curl);
+
+ HMAC_CTX_init(&ctx);
+ HMAC_CTX_cleanup(&ctx);
+ return 0;
+}
+EOF
+if test "$disable_http" != "yes"; then
+ HTTP_LIBS="-lcurl -lssl -lcrypto"
+ if compile_prog "" "$HTTP_LIBS" "curl-new-ssl"; then
+ output_sym "CONFIG_HAVE_OPAQUE_HMAC_CTX"
+ http="yes"
+ LIBS="$HTTP_LIBS $LIBS"
+ elif mv $TMPC2 $TMPC && compile_prog "" "$HTTP_LIBS" "curl-old-ssl"; then
+ http="yes"
+ LIBS="$HTTP_LIBS $LIBS"
+ fi
fi
print_config "http engine" "$http"

diff --git a/engines/http.c b/engines/http.c
index d3fdba8..cb66ebe 100644
--- a/engines/http.c
+++ b/engines/http.c
@@ -25,25 +25,37 @@
#include <curl/curl.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
+#include <openssl/md5.h>
#include "fio.h"
#include "../optgroup.h"

+enum {
+ FIO_HTTP_WEBDAV = 0,
+ FIO_HTTP_S3 = 1,
+ FIO_HTTP_SWIFT = 2,
+
+ FIO_HTTPS_OFF = 0,
+ FIO_HTTPS_ON = 1,
+ FIO_HTTPS_INSECURE = 2,
+};
+
struct http_data {
CURL *curl;
};

struct http_options {
void *pad;
- int https;
+ unsigned int https;
char *host;
char *user;
char *pass;
char *s3_key;
char *s3_keyid;
char *s3_region;
+ char *swift_auth_token;
int verbose;
- int s3;
+ unsigned int mode;
};

struct http_curl_stream {
@@ -56,10 +68,24 @@ static struct fio_option options[] = {
{
.name = "https",
.lname = "https",
- .type = FIO_OPT_BOOL,
+ .type = FIO_OPT_STR,
.help = "Enable https",
.off1 = offsetof(struct http_options, https),
- .def = "0",
+ .def = "off",
+ .posval = {
+ { .ival = "off",
+ .oval = FIO_HTTPS_OFF,
+ .help = "No HTTPS",
+ },
+ { .ival = "on",
+ .oval = FIO_HTTPS_ON,
+ .help = "Enable HTTPS",
+ },
+ { .ival = "insecure",
+ .oval = FIO_HTTPS_INSECURE,
+ .help = "Enable HTTPS, disable peer verification",
+ },
+ },
.category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_HTTP,
},
@@ -112,6 +138,16 @@ static struct fio_option options[] = {
.group = FIO_OPT_G_HTTP,
},
{
+ .name = "http_swift_auth_token",
+ .lname = "Swift auth token",
+ .type = FIO_OPT_STR_STORE,
+ .help = "OpenStack Swift auth token",
+ .off1 = offsetof(struct http_options, swift_auth_token),
+ .def = "",
+ .category = FIO_OPT_C_ENGINE,
+ .group = FIO_OPT_G_HTTP,
+ },
+ {
.name = "http_s3_region",
.lname = "S3 region",
.type = FIO_OPT_STR_STORE,
@@ -122,18 +158,32 @@ static struct fio_option options[] = {
.group = FIO_OPT_G_HTTP,
},
{
- .name = "http_s3",
- .lname = "S3 extensions",
- .type = FIO_OPT_BOOL,
- .help = "Whether to enable S3 specific headers",
- .off1 = offsetof(struct http_options, s3),
- .def = "0",
+ .name = "http_mode",
+ .lname = "Request mode to use",
+ .type = FIO_OPT_STR,
+ .help = "Whether to use WebDAV, Swift, or S3",
+ .off1 = offsetof(struct http_options, mode),
+ .def = "webdav",
+ .posval = {
+ { .ival = "webdav",
+ .oval = FIO_HTTP_WEBDAV,
+ .help = "WebDAV server",
+ },
+ { .ival = "s3",
+ .oval = FIO_HTTP_S3,
+ .help = "S3 storage backend",
+ },
+ { .ival = "swift",
+ .oval = FIO_HTTP_SWIFT,
+ .help = "OpenStack Swift storage",
+ },
+ },
.category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_HTTP,
},
{
.name = "http_verbose",
- .lname = "CURL verbosity",
+ .lname = "HTTP verbosity level",
.type = FIO_OPT_INT,
.help = "increase http engine verbosity",
.off1 = offsetof(struct http_options, verbose),
@@ -204,15 +254,34 @@ static char *_gen_hex_sha256(const char *p, size_t len)
return _conv_hex(hash, SHA256_DIGEST_LENGTH);
}

+static char *_gen_hex_md5(const char *p, size_t len)
+{
+ unsigned char hash[MD5_DIGEST_LENGTH];
+
+ MD5((unsigned char*)p, len, hash);
+ return _conv_hex(hash, MD5_DIGEST_LENGTH);
+}
+
static void _hmac(unsigned char *md, void *key, int key_len, char *data) {
+#ifndef CONFIG_HAVE_OPAQUE_HMAC_CTX
+ HMAC_CTX _ctx;
+#endif
HMAC_CTX *ctx;
unsigned int hmac_len;

+#ifdef CONFIG_HAVE_OPAQUE_HMAC_CTX
ctx = HMAC_CTX_new();
+#else
+ ctx = &_ctx;
+#endif
HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), NULL);
HMAC_Update(ctx, (unsigned char*)data, strlen(data));
HMAC_Final(ctx, md, &hmac_len);
+#ifdef CONFIG_HAVE_OPAQUE_HMAC_CTX
HMAC_CTX_free(ctx);
+#else
+ HMAC_CTX_cleanup(ctx);
+#endif
}

static int _curl_trace(CURL *handle, curl_infotype type,
@@ -338,6 +407,29 @@ static void _add_aws_auth_header(CURL *curl, struct curl_slist *slist, struct ht
free(signature);
}

+static void _add_swift_header(CURL *curl, struct curl_slist *slist, struct http_options *o,
+ int op, const char *uri, char *buf, size_t len)
+{
+ char *dsha = NULL;
+ char s[512];
+
+ if (op == DDIR_WRITE) {
+ dsha = _gen_hex_md5(buf, len);
+ }
+ /* Surpress automatic Accept: header */
+ slist = curl_slist_append(slist, "Accept:");
+
+ snprintf(s, sizeof(s), "etag: %s", dsha);
+ slist = curl_slist_append(slist, s);
+
+ snprintf(s, sizeof(s), "x-auth-token: %s", o->swift_auth_token);
+ slist = curl_slist_append(slist, s);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+
+ free(dsha);
+}
+
static void fio_http_cleanup(struct thread_data *td)
{
struct http_data *http = td->io_ops_data;
@@ -402,17 +494,24 @@ static enum fio_q_status fio_http_queue(struct thread_data *td,

fio_ro_check(td, io_u);
memset(&_curl_stream, 0, sizeof(_curl_stream));
- snprintf(object, sizeof(object), "%s_%llu_%llu", td->files[0]->file_name, io_u->offset, io_u->xfer_buflen);
- snprintf(url, sizeof(url), "%s://%s%s", o->https ? "https" : "http", o->host, object);
+ snprintf(object, sizeof(object), "%s_%llu_%llu", td->files[0]->file_name,
+ io_u->offset, io_u->xfer_buflen);
+ if (o->https == FIO_HTTPS_OFF)
+ snprintf(url, sizeof(url), "http://%s%s", o->host, object);
+ else
+ snprintf(url, sizeof(url), "https://%s%s", o->host, object);
curl_easy_setopt(http->curl, CURLOPT_URL, url);
_curl_stream.buf = io_u->xfer_buf;
_curl_stream.max = io_u->xfer_buflen;
curl_easy_setopt(http->curl, CURLOPT_SEEKDATA, &_curl_stream);
curl_easy_setopt(http->curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)io_u->xfer_buflen);

- if (o->s3)
+ if (o->mode == FIO_HTTP_S3)
_add_aws_auth_header(http->curl, slist, o, io_u->ddir, object,
io_u->xfer_buf, io_u->xfer_buflen);
+ else if (o->mode == FIO_HTTP_SWIFT)
+ _add_swift_header(http->curl, slist, o, io_u->ddir, object,
+ io_u->xfer_buf, io_u->xfer_buflen);

if (io_u->ddir == DDIR_WRITE) {
curl_easy_setopt(http->curl, CURLOPT_READDATA, &_curl_stream);
@@ -487,7 +586,7 @@ static int fio_http_setup(struct thread_data *td)
{
struct http_data *http = NULL;
struct http_options *o = td->eo;
- int r;
+
/* allocate engine specific structure to deal with libhttp. */
http = calloc(1, sizeof(*http));
if (!http) {
@@ -503,6 +602,10 @@ static int fio_http_setup(struct thread_data *td)
curl_easy_setopt(http->curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(http->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(http->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
+ if (o->https == FIO_HTTPS_INSECURE) {
+ curl_easy_setopt(http->curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ curl_easy_setopt(http->curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
curl_easy_setopt(http->curl, CURLOPT_READFUNCTION, _http_read);
curl_easy_setopt(http->curl, CURLOPT_WRITEFUNCTION, _http_write);
curl_easy_setopt(http->curl, CURLOPT_SEEKFUNCTION, _http_seek);
@@ -520,7 +623,7 @@ static int fio_http_setup(struct thread_data *td)
return 0;
cleanup:
fio_http_cleanup(td);
- return r;
+ return 1;
}

static int fio_http_open(struct thread_data *td, struct fio_file *f)
diff --git a/examples/http-s3.fio b/examples/http-s3.fio
index a9805da..2dcae36 100644
--- a/examples/http-s3.fio
+++ b/examples/http-s3.fio
@@ -9,8 +9,8 @@ name=test
direct=1
filename=/larsmb-fio-test/object
http_verbose=0
-https=1
-http_s3=1
+https=on
+http_mode=s3
http_s3_key=${S3_KEY}
http_s3_keyid=${S3_ID}
http_host=s3.eu-central-1.amazonaws.com
diff --git a/examples/http-swift.fio b/examples/http-swift.fio
new file mode 100644
index 0000000..b591adb
--- /dev/null
+++ b/examples/http-swift.fio
@@ -0,0 +1,32 @@
+[global]
+ioengine=http
+rw=randwrite
+name=test
+direct=1
+http_verbose=0
+http_mode=swift
+https=on
+# This is the hostname and port portion of the public access link for
+# the container:
+http_host=swift.srv.openstack.local:8081
+filename_format=/swift/v1/fio-test/bucket.$jobnum
+group_reporting
+bs=64k
+size=1M
+# Currently, fio cannot yet generate the Swift Auth-Token itself.
+# You need to set this prior to running fio via
+# eval $(openstack token issue -f shell --prefix SWIFT_) ; export SWIFT_id
+http_swift_auth_token=${SWIFT_id}
+
+[create]
+numjobs=1
+rw=randwrite
+io_size=256k
+verify=sha256
+
+# This will delete all created objects again
+[trim]
+stonewall
+numjobs=1
+rw=trim
+io_size=64k
diff --git a/examples/http-webdav.fio b/examples/http-webdav.fio
index c0624f8..2d1ca73 100644
--- a/examples/http-webdav.fio
+++ b/examples/http-webdav.fio
@@ -4,8 +4,8 @@ rw=randwrite
name=test
direct=1
http_verbose=0
-http_s3=0
-https=0
+http_mode=webdav
+https=off
http_host=localhost
filename_format=/dav/bucket.$jobnum
group_reporting
diff --git a/fio.1 b/fio.1
index 883a31b..73a0422 100644
--- a/fio.1
+++ b/fio.1
@@ -1829,12 +1829,14 @@ Username for HTTP authentication.
.BI (http)http_pass \fR=\fPstr
Password for HTTP authentication.
.TP
-.BI (http)https \fR=\fPbool
-Whether to use HTTPS instead of plain HTTP. Default is \fB0\fR.
+.BI (http)https \fR=\fPstr
+Whether to use HTTPS instead of plain HTTP. \fRon\fP enables HTTPS;
+\fRinsecure\fP will enable HTTPS, but disable SSL peer verification (use
+with caution!). Default is \fBoff\fR.
.TP
-.BI (http)http_s3 \fR=\fPbool
-Include S3 specific HTTP headers such as authenticating requests with
-AWS Signature Version 4. Default is \fB0\fR.
+.BI (http)http_mode \fR=\fPstr
+Which HTTP access mode to use: webdav, swift, or s3. Default is
+\fBwebdav\fR.
.TP
.BI (http)http_s3_region \fR=\fPstr
The S3 region/zone to include in the request. Default is \fBus-east-1\fR.
@@ -1845,6 +1847,10 @@ The S3 secret key.
.BI (http)http_s3_keyid \fR=\fPstr
The S3 key/access id.
.TP
+.BI (http)http_swift_auth_token \fR=\fPstr
+The Swift auth token. See the example configuration file on how to
+retrieve this.
+.TP
.BI (http)http_verbose \fR=\fPint
Enable verbose requests from libcurl. Useful for debugging. 1 turns on
verbose logging from libcurl, 2 additionally enables HTTP IO tracing.