1
v2:
2
3
Added the premature_ok logic;
4
Added compat property for QEMU <9.1;
5
Refactored the existing handshake code;
6
7
CI run:
8
https://gitlab.com/farosas/qemu/-/pipelines/1660800456
9
10
v1:
11
https://lore.kernel.org/r/20250206175824.22664-1-farosas@suse.de
12
1
Hi,
13
Hi,
2
14
3
We've been discussing a way to stop multifd recv threads from getting
15
We've been discussing a way to stop multifd recv threads from getting
4
an error at the end of migration when the source threads close the
16
an error at the end of migration when the source threads close the
5
iochannel without ending the TLS session.
17
iochannel without ending the TLS session.
...
...
17
Aside from stopping the recv thread from seeing an error, this also
29
Aside from stopping the recv thread from seeing an error, this also
18
creates a contract that all connections should be closed only after
30
creates a contract that all connections should be closed only after
19
the TLS session is ended. This helps to avoid masking a legitimate
31
the TLS session is ended. This helps to avoid masking a legitimate
20
issue where the connection is closed prematurely.
32
issue where the connection is closed prematurely.
21
33
22
Fabiano Rosas (4):
34
Fabiano Rosas (8):
23
crypto: Allow gracefully ending the TLS session
35
crypto: Allow gracefully ending the TLS session
24
io: tls: Add qio_channel_tls_bye
36
io: tls: Add qio_channel_tls_bye
25
migration/multifd: Terminate the TLS connection
37
migration/multifd: Terminate the TLS connection
26
migration: Check migration error after loadvm
38
migration: Check migration error after loadvm
39
crypto: Remove qcrypto_tls_session_get_handshake_status
40
io: Plumb read flags into qio_channel_read_all_eof
41
io: Add a read flag for relaxed EOF
42
migration/multifd: Add a compat property for TLS termination
27
43
28
crypto/tlssession.c | 40 ++++++++++++++++++
44
crypto/tlssession.c | 105 +++++++++++++++++-----------
29
include/crypto/tlssession.h | 22 ++++++++++
45
hw/remote/mpqemu-link.c | 2 +-
30
include/io/channel-tls.h | 12 ++++++
46
include/crypto/tlssession.h | 46 ++++++------
31
io/channel-tls.c | 84 +++++++++++++++++++++++++++++++++++++
47
include/io/channel-tls.h | 12 ++++
32
io/trace-events | 5 +++
48
include/io/channel.h | 7 ++
33
migration/multifd.c | 34 ++++++++++++++-
49
io/channel-tls.c | 92 +++++++++++++++++++++++-
34
migration/savevm.c | 6 ++-
50
io/channel.c | 13 ++--
35
migration/tls.c | 5 +++
51
io/trace-events | 5 ++
36
migration/tls.h | 2 +-
52
migration/migration.h | 33 +++++++++
37
9 files changed, 207 insertions(+), 3 deletions(-)
53
migration/multifd.c | 42 ++++++++++-
54
migration/multifd.h | 2 +
55
migration/options.c | 2 +
56
migration/savevm.c | 6 +-
57
migration/tls.c | 5 ++
58
migration/tls.h | 2 +-
59
tests/unit/test-crypto-tlssession.c | 12 ++--
60
tools/i386/qemu-vmsr-helper.c | 3 +-
61
util/vhost-user-server.c | 2 +-
62
18 files changed, 308 insertions(+), 83 deletions(-)
38
63
39
--
64
--
40
2.35.3
65
2.35.3
diff view generated by jsdifflib
...
...
13
13
14
1- 1d457daf86 ("migration/multifd: Further remove the SYNC on complete")
14
1- 1d457daf86 ("migration/multifd: Further remove the SYNC on complete")
15
15
16
Signed-off-by: Fabiano Rosas <farosas@suse.de>
16
Signed-off-by: Fabiano Rosas <farosas@suse.de>
17
---
17
---
18
crypto/tlssession.c | 40 +++++++++++++++++++++++++++++++++++++
18
crypto/tlssession.c | 41 +++++++++++++++++++++++++++++++++++++
19
include/crypto/tlssession.h | 22 ++++++++++++++++++++
19
include/crypto/tlssession.h | 22 ++++++++++++++++++++
20
2 files changed, 62 insertions(+)
20
2 files changed, 63 insertions(+)
21
21
22
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
22
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
23
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
24
--- a/crypto/tlssession.c
24
--- a/crypto/tlssession.c
25
+++ b/crypto/tlssession.c
25
+++ b/crypto/tlssession.c
...
...
71
+int
71
+int
72
+qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
72
+qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
73
+{
73
+{
74
+ return QCRYPTO_TLS_BYE_COMPLETE;
74
+ return QCRYPTO_TLS_BYE_COMPLETE;
75
+}
75
+}
76
+
76
+
77
+
77
int
78
int
78
qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
79
qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
79
Error **errp)
80
Error **errp)
80
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
81
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
...
...
diff view generated by jsdifflib
1
Add a task dispatcher for gnutls_bye similar to the
1
Add a task dispatcher for gnutls_bye similar to the
2
qio_channel_tls_handshake_task(). The gnutls_bye() call might be
2
qio_channel_tls_handshake_task(). The gnutls_bye() call might be
3
interrupted and so it needs to be rescheduled.
3
interrupted and so it needs to be rescheduled.
4
4
5
The migration code will make use of this to help the migration
5
The migration code will make use of this to help the migration
6
destination identify a premature EOF. Once the session termination is
6
destination identify a premature EOF. Once the session termination is
7
in place, any EOF that happens before the source issued gnutls_bye()
7
in place, any EOF that happens before the source issued gnutls_bye()
8
will be considered an error.
8
will be considered an error.
9
9
10
Signed-off-by: Fabiano Rosas <farosas@suse.de>
10
Signed-off-by: Fabiano Rosas <farosas@suse.de>
11
---
11
---
12
include/io/channel-tls.h | 12 ++++++
12
include/io/channel-tls.h | 12 ++++++
13
io/channel-tls.c | 84 ++++++++++++++++++++++++++++++++++++++++
13
io/channel-tls.c | 84 ++++++++++++++++++++++++++++++++++++++++
14
io/trace-events | 5 +++
14
io/trace-events | 5 +++
15
3 files changed, 101 insertions(+)
15
3 files changed, 101 insertions(+)
16
16
17
diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h
17
diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/io/channel-tls.h
19
--- a/include/io/channel-tls.h
20
+++ b/include/io/channel-tls.h
20
+++ b/include/io/channel-tls.h
21
@@ -XXX,XX +XXX,XX @@ struct QIOChannelTLS {
21
@@ -XXX,XX +XXX,XX @@ struct QIOChannelTLS {
22
QCryptoTLSSession *session;
22
QCryptoTLSSession *session;
23
QIOChannelShutdown shutdown;
23
QIOChannelShutdown shutdown;
24
guint hs_ioc_tag;
24
guint hs_ioc_tag;
25
+ guint bye_ioc_tag;
25
+ guint bye_ioc_tag;
26
};
26
};
27
27
28
+/**
28
+/**
29
+ * qio_channel_tls_bye:
29
+ * qio_channel_tls_bye:
30
+ * @ioc: the TLS channel object
30
+ * @ioc: the TLS channel object
31
+ * @errp: pointer to a NULL-initialized error object
31
+ * @errp: pointer to a NULL-initialized error object
32
+ *
32
+ *
33
+ * Perform the TLS session termination. This method will return
33
+ * Perform the TLS session termination. This method will return
34
+ * immediately and the termination will continue in the background,
34
+ * immediately and the termination will continue in the background,
35
+ * provided the main loop is running.
35
+ * provided the main loop is running.
36
+ */
36
+ */
37
+void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp);
37
+void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp);
38
+
38
+
39
/**
39
/**
40
* qio_channel_tls_new_server:
40
* qio_channel_tls_new_server:
41
* @master: the underlying channel object
41
* @master: the underlying channel object
42
diff --git a/io/channel-tls.c b/io/channel-tls.c
42
diff --git a/io/channel-tls.c b/io/channel-tls.c
43
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
44
--- a/io/channel-tls.c
44
--- a/io/channel-tls.c
45
+++ b/io/channel-tls.c
45
+++ b/io/channel-tls.c
46
@@ -XXX,XX +XXX,XX @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
46
@@ -XXX,XX +XXX,XX @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
47
qio_channel_tls_handshake_task(ioc, task, context);
47
qio_channel_tls_handshake_task(ioc, task, context);
48
}
48
}
49
49
50
+static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
50
+static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
51
+ gpointer user_data);
51
+ gpointer user_data);
52
+
52
+
53
+static void qio_channel_tls_bye_task(QIOChannelTLS *ioc, QIOTask *task,
53
+static void qio_channel_tls_bye_task(QIOChannelTLS *ioc, QIOTask *task,
54
+ GMainContext *context)
54
+ GMainContext *context)
55
+{
55
+{
56
+ GIOCondition condition;
56
+ GIOCondition condition;
57
+ QIOChannelTLSData *data;
57
+ QIOChannelTLSData *data;
58
+ int status;
58
+ int status;
59
+ Error *err = NULL;
59
+ Error *err = NULL;
60
+
60
+
61
+ status = qcrypto_tls_session_bye(ioc->session, &err);
61
+ status = qcrypto_tls_session_bye(ioc->session, &err);
62
+
62
+
63
+ if (status < 0) {
63
+ if (status < 0) {
64
+ trace_qio_channel_tls_bye_fail(ioc);
64
+ trace_qio_channel_tls_bye_fail(ioc);
65
+ qio_task_set_error(task, err);
65
+ qio_task_set_error(task, err);
66
+ qio_task_complete(task);
66
+ qio_task_complete(task);
67
+ return;
67
+ return;
68
+ }
68
+ }
69
+
69
+
70
+ if (status == QCRYPTO_TLS_BYE_COMPLETE) {
70
+ if (status == QCRYPTO_TLS_BYE_COMPLETE) {
71
+ qio_task_complete(task);
71
+ qio_task_complete(task);
72
+ return;
72
+ return;
73
+ }
73
+ }
74
+
74
+
75
+ data = g_new0(typeof(*data), 1);
75
+ data = g_new0(typeof(*data), 1);
76
+ data->task = task;
76
+ data->task = task;
77
+ data->context = context;
77
+ data->context = context;
78
+
78
+
79
+ if (context) {
79
+ if (context) {
80
+ g_main_context_ref(context);
80
+ g_main_context_ref(context);
81
+ }
81
+ }
82
+
82
+
83
+ if (status == QCRYPTO_TLS_BYE_SENDING) {
83
+ if (status == QCRYPTO_TLS_BYE_SENDING) {
84
+ condition = G_IO_OUT;
84
+ condition = G_IO_OUT;
85
+ } else {
85
+ } else {
86
+ condition = G_IO_IN;
86
+ condition = G_IO_IN;
87
+ }
87
+ }
88
+
88
+
89
+ trace_qio_channel_tls_bye_pending(ioc, status);
89
+ trace_qio_channel_tls_bye_pending(ioc, status);
90
+ ioc->bye_ioc_tag = qio_channel_add_watch_full(ioc->master, condition,
90
+ ioc->bye_ioc_tag = qio_channel_add_watch_full(ioc->master, condition,
91
+ qio_channel_tls_bye_io,
91
+ qio_channel_tls_bye_io,
92
+ data, NULL, context);
92
+ data, NULL, context);
93
+}
93
+}
94
+
94
+
95
+
95
+
96
+static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
96
+static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
97
+ gpointer user_data)
97
+ gpointer user_data)
98
+{
98
+{
99
+ QIOChannelTLSData *data = user_data;
99
+ QIOChannelTLSData *data = user_data;
100
+ QIOTask *task = data->task;
100
+ QIOTask *task = data->task;
101
+ GMainContext *context = data->context;
101
+ GMainContext *context = data->context;
102
+ QIOChannelTLS *tioc = QIO_CHANNEL_TLS(qio_task_get_source(task));
102
+ QIOChannelTLS *tioc = QIO_CHANNEL_TLS(qio_task_get_source(task));
103
+
103
+
104
+ tioc->bye_ioc_tag = 0;
104
+ tioc->bye_ioc_tag = 0;
105
+ g_free(data);
105
+ g_free(data);
106
+ qio_channel_tls_bye_task(tioc, task, context);
106
+ qio_channel_tls_bye_task(tioc, task, context);
107
+
107
+
108
+ if (context) {
108
+ if (context) {
109
+ g_main_context_unref(context);
109
+ g_main_context_unref(context);
110
+ }
110
+ }
111
+
111
+
112
+ return FALSE;
112
+ return FALSE;
113
+}
113
+}
114
+
114
+
115
+static void propagate_error(QIOTask *task, gpointer opaque)
115
+static void propagate_error(QIOTask *task, gpointer opaque)
116
+{
116
+{
117
+ qio_task_propagate_error(task, opaque);
117
+ qio_task_propagate_error(task, opaque);
118
+}
118
+}
119
+
119
+
120
+void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp)
120
+void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp)
121
+{
121
+{
122
+ QIOTask *task;
122
+ QIOTask *task;
123
+
123
+
124
+ task = qio_task_new(OBJECT(ioc), propagate_error, errp, NULL);
124
+ task = qio_task_new(OBJECT(ioc), propagate_error, errp, NULL);
125
+
125
+
126
+ trace_qio_channel_tls_bye_start(ioc);
126
+ trace_qio_channel_tls_bye_start(ioc);
127
+ qio_channel_tls_bye_task(ioc, task, NULL);
127
+ qio_channel_tls_bye_task(ioc, task, NULL);
128
+}
128
+}
129
129
130
static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
130
static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
131
{
131
{
132
@@ -XXX,XX +XXX,XX @@ static int qio_channel_tls_close(QIOChannel *ioc,
132
@@ -XXX,XX +XXX,XX @@ static int qio_channel_tls_close(QIOChannel *ioc,
133
g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
133
g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
134
}
134
}
135
135
136
+ if (tioc->bye_ioc_tag) {
136
+ if (tioc->bye_ioc_tag) {
137
+ trace_qio_channel_tls_bye_cancel(ioc);
137
+ trace_qio_channel_tls_bye_cancel(ioc);
138
+ g_clear_handle_id(&tioc->bye_ioc_tag, g_source_remove);
138
+ g_clear_handle_id(&tioc->bye_ioc_tag, g_source_remove);
139
+ }
139
+ }
140
+
140
+
141
return qio_channel_close(tioc->master, errp);
141
return qio_channel_close(tioc->master, errp);
142
}
142
}
143
143
144
diff --git a/io/trace-events b/io/trace-events
144
diff --git a/io/trace-events b/io/trace-events
145
index XXXXXXX..XXXXXXX 100644
145
index XXXXXXX..XXXXXXX 100644
146
--- a/io/trace-events
146
--- a/io/trace-events
147
+++ b/io/trace-events
147
+++ b/io/trace-events
148
@@ -XXX,XX +XXX,XX @@ qio_channel_tls_handshake_pending(void *ioc, int status) "TLS handshake pending
148
@@ -XXX,XX +XXX,XX @@ qio_channel_tls_handshake_pending(void *ioc, int status) "TLS handshake pending
149
qio_channel_tls_handshake_fail(void *ioc) "TLS handshake fail ioc=%p"
149
qio_channel_tls_handshake_fail(void *ioc) "TLS handshake fail ioc=%p"
150
qio_channel_tls_handshake_complete(void *ioc) "TLS handshake complete ioc=%p"
150
qio_channel_tls_handshake_complete(void *ioc) "TLS handshake complete ioc=%p"
151
qio_channel_tls_handshake_cancel(void *ioc) "TLS handshake cancel ioc=%p"
151
qio_channel_tls_handshake_cancel(void *ioc) "TLS handshake cancel ioc=%p"
152
+qio_channel_tls_bye_start(void *ioc) "TLS termination start ioc=%p"
152
+qio_channel_tls_bye_start(void *ioc) "TLS termination start ioc=%p"
153
+qio_channel_tls_bye_pending(void *ioc, int status) "TLS termination pending ioc=%p status=%d"
153
+qio_channel_tls_bye_pending(void *ioc, int status) "TLS termination pending ioc=%p status=%d"
154
+qio_channel_tls_bye_fail(void *ioc) "TLS termination fail ioc=%p"
154
+qio_channel_tls_bye_fail(void *ioc) "TLS termination fail ioc=%p"
155
+qio_channel_tls_bye_complete(void *ioc) "TLS termination complete ioc=%p"
155
+qio_channel_tls_bye_complete(void *ioc) "TLS termination complete ioc=%p"
156
+qio_channel_tls_bye_cancel(void *ioc) "TLS termination cancel ioc=%p"
156
+qio_channel_tls_bye_cancel(void *ioc) "TLS termination cancel ioc=%p"
157
qio_channel_tls_credentials_allow(void *ioc) "TLS credentials allow ioc=%p"
157
qio_channel_tls_credentials_allow(void *ioc) "TLS credentials allow ioc=%p"
158
qio_channel_tls_credentials_deny(void *ioc) "TLS credentials deny ioc=%p"
158
qio_channel_tls_credentials_deny(void *ioc) "TLS credentials deny ioc=%p"
159
159
160
--
160
--
161
2.35.3
161
2.35.3
diff view generated by jsdifflib
1
The multifd recv side has been getting a TLS error of
1
The multifd recv side has been getting a TLS error of
2
GNUTLS_E_PREMATURE_TERMINATION at the end of migration when the send
2
GNUTLS_E_PREMATURE_TERMINATION at the end of migration when the send
3
side closes the sockets without ending the TLS session. This has been
3
side closes the sockets without ending the TLS session. This has been
4
masked by the code not checking the migration error after loadvm.
4
masked by the code not checking the migration error after loadvm.
5
5
6
Start ending the TLS session at multifd_send_shutdown() so the recv
6
Start ending the TLS session at multifd_send_shutdown() so the recv
7
side always sees a clean termination (EOF) and we can start to
7
side always sees a clean termination (EOF) and we can start to
8
differentiate that from an actual premature termination that might
8
differentiate that from an actual premature termination that might
9
possibly happen in the middle of the migration.
9
possibly happen in the middle of the migration.
10
10
11
There's nothing to be done if a previous migration error has already
11
There's nothing to be done if a previous migration error has already
12
broken the connection, so add a comment explaining it and ignore any
12
broken the connection, so add a comment explaining it and ignore any
13
errors coming from gnutls_bye().
13
errors coming from gnutls_bye().
14
14
15
This doesn't break compat with older recv-side QEMUs because EOF has
15
This doesn't break compat with older recv-side QEMUs because EOF has
16
always caused the recv thread to exit cleanly.
16
always caused the recv thread to exit cleanly.
17
17
18
Signed-off-by: Fabiano Rosas <farosas@suse.de>
18
Signed-off-by: Fabiano Rosas <farosas@suse.de>
19
---
19
---
20
migration/multifd.c | 34 +++++++++++++++++++++++++++++++++-
20
migration/multifd.c | 34 +++++++++++++++++++++++++++++++++-
21
migration/tls.c | 5 +++++
21
migration/tls.c | 5 +++++
22
migration/tls.h | 2 +-
22
migration/tls.h | 2 +-
23
3 files changed, 39 insertions(+), 2 deletions(-)
23
3 files changed, 39 insertions(+), 2 deletions(-)
24
24
25
diff --git a/migration/multifd.c b/migration/multifd.c
25
diff --git a/migration/multifd.c b/migration/multifd.c
26
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
27
--- a/migration/multifd.c
27
--- a/migration/multifd.c
28
+++ b/migration/multifd.c
28
+++ b/migration/multifd.c
29
@@ -XXX,XX +XXX,XX @@ void multifd_send_shutdown(void)
29
@@ -XXX,XX +XXX,XX @@ void multifd_send_shutdown(void)
30
return;
30
return;
31
}
31
}
32
32
33
+ for (i = 0; i < migrate_multifd_channels(); i++) {
33
+ for (i = 0; i < migrate_multifd_channels(); i++) {
34
+ MultiFDSendParams *p = &multifd_send_state->params[i];
34
+ MultiFDSendParams *p = &multifd_send_state->params[i];
35
+
35
+
36
+ /* thread_created implies the TLS handshake has succeeded */
36
+ /* thread_created implies the TLS handshake has succeeded */
37
+ if (p->tls_thread_created && p->thread_created) {
37
+ if (p->tls_thread_created && p->thread_created) {
38
+ Error *local_err = NULL;
38
+ Error *local_err = NULL;
39
+ /*
39
+ /*
40
+ * The destination expects the TLS session to always be
40
+ * The destination expects the TLS session to always be
41
+ * properly terminated. This helps to detect a premature
41
+ * properly terminated. This helps to detect a premature
42
+ * termination in the middle of the stream. Note that
42
+ * termination in the middle of the stream. Note that
43
+ * older QEMUs always break the connection on the source
43
+ * older QEMUs always break the connection on the source
44
+ * and the destination always sees
44
+ * and the destination always sees
45
+ * GNUTLS_E_PREMATURE_TERMINATION.
45
+ * GNUTLS_E_PREMATURE_TERMINATION.
46
+ */
46
+ */
47
+ migration_tls_channel_end(p->c, &local_err);
47
+ migration_tls_channel_end(p->c, &local_err);
48
+
48
+
49
+ if (local_err) {
49
+ if (local_err) {
50
+ /*
50
+ /*
51
+ * The above can fail with broken pipe due to a
51
+ * The above can fail with broken pipe due to a
52
+ * previous migration error, ignore the error.
52
+ * previous migration error, ignore the error.
53
+ */
53
+ */
54
+ assert(migration_has_failed(migrate_get_current()));
54
+ assert(migration_has_failed(migrate_get_current()));
55
+ }
55
+ }
56
+ }
56
+ }
57
+ }
57
+ }
58
+
58
+
59
multifd_send_terminate_threads();
59
multifd_send_terminate_threads();
60
60
61
for (i = 0; i < migrate_multifd_channels(); i++) {
61
for (i = 0; i < migrate_multifd_channels(); i++) {
62
@@ -XXX,XX +XXX,XX @@ static void *multifd_recv_thread(void *opaque)
62
@@ -XXX,XX +XXX,XX @@ static void *multifd_recv_thread(void *opaque)
63
63
64
ret = qio_channel_read_all_eof(p->c, (void *)p->packet,
64
ret = qio_channel_read_all_eof(p->c, (void *)p->packet,
65
p->packet_len, &local_err);
65
p->packet_len, &local_err);
66
- if (ret == 0 || ret == -1) { /* 0: EOF -1: Error */
66
- if (ret == 0 || ret == -1) { /* 0: EOF -1: Error */
67
+ if (!ret) {
67
+ if (!ret) {
68
+ /* EOF */
68
+ /* EOF */
69
+ assert(!local_err);
69
+ assert(!local_err);
70
+ break;
70
+ break;
71
+ }
71
+ }
72
+
72
+
73
+ if (ret == -1) {
73
+ if (ret == -1) {
74
break;
74
break;
75
}
75
}
76
76
77
diff --git a/migration/tls.c b/migration/tls.c
77
diff --git a/migration/tls.c b/migration/tls.c
78
index XXXXXXX..XXXXXXX 100644
78
index XXXXXXX..XXXXXXX 100644
79
--- a/migration/tls.c
79
--- a/migration/tls.c
80
+++ b/migration/tls.c
80
+++ b/migration/tls.c
81
@@ -XXX,XX +XXX,XX @@ void migration_tls_channel_connect(MigrationState *s,
81
@@ -XXX,XX +XXX,XX @@ void migration_tls_channel_connect(MigrationState *s,
82
NULL);
82
NULL);
83
}
83
}
84
84
85
+void migration_tls_channel_end(QIOChannel *ioc, Error **errp)
85
+void migration_tls_channel_end(QIOChannel *ioc, Error **errp)
86
+{
86
+{
87
+ qio_channel_tls_bye(QIO_CHANNEL_TLS(ioc), errp);
87
+ qio_channel_tls_bye(QIO_CHANNEL_TLS(ioc), errp);
88
+}
88
+}
89
+
89
+
90
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc)
90
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc)
91
{
91
{
92
if (!migrate_tls()) {
92
if (!migrate_tls()) {
93
diff --git a/migration/tls.h b/migration/tls.h
93
diff --git a/migration/tls.h b/migration/tls.h
94
index XXXXXXX..XXXXXXX 100644
94
index XXXXXXX..XXXXXXX 100644
95
--- a/migration/tls.h
95
--- a/migration/tls.h
96
+++ b/migration/tls.h
96
+++ b/migration/tls.h
97
@@ -XXX,XX +XXX,XX @@ void migration_tls_channel_connect(MigrationState *s,
97
@@ -XXX,XX +XXX,XX @@ void migration_tls_channel_connect(MigrationState *s,
98
QIOChannel *ioc,
98
QIOChannel *ioc,
99
const char *hostname,
99
const char *hostname,
100
Error **errp);
100
Error **errp);
101
-
101
-
102
+void migration_tls_channel_end(QIOChannel *ioc, Error **errp);
102
+void migration_tls_channel_end(QIOChannel *ioc, Error **errp);
103
/* Whether the QIO channel requires further TLS handshake? */
103
/* Whether the QIO channel requires further TLS handshake? */
104
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc);
104
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc);
105
105
106
--
106
--
107
2.35.3
107
2.35.3
diff view generated by jsdifflib
1
We're currently only checking the QEMUFile error after
1
We're currently only checking the QEMUFile error after
2
qemu_loadvm_state(). Check the migration error as well to avoid
2
qemu_loadvm_state(). Check the migration error as well to avoid
3
missing errors that might be set by the multifd recv thread.
3
missing errors that might be set by the multifd recv thread.
4
4
5
This doesn't break compat between 9.2 and 10.0 because 9.2 still has
5
This doesn't break compat between 9.2 and 10.0 because 9.2 still has
6
the multifd recv threads stuck at sync when the source channel shuts
6
the multifd recv threads stuck at sync when the source channel shuts
7
down. I.e. it doesn't have commit 1d457daf86 ("migration/multifd:
7
down. I.e. it doesn't have commit 1d457daf86 ("migration/multifd:
8
Further remove the SYNC on complete"). QEMU versions with that commit
8
Further remove the SYNC on complete"). QEMU versions with that commit
9
will have compat broken with versions containing this commit. This is
9
will have compat broken with versions containing this commit. This is
10
not an issue because both will be present in 10.0, but development
10
not an issue because both will be present in 10.0, but development
11
trees might see a migration error.
11
trees might see a migration error.
12
12
13
Signed-off-by: Fabiano Rosas <farosas@suse.de>
13
Signed-off-by: Fabiano Rosas <farosas@suse.de>
14
---
14
---
15
migration/savevm.c | 6 +++++-
15
migration/savevm.c | 6 +++++-
16
1 file changed, 5 insertions(+), 1 deletion(-)
16
1 file changed, 5 insertions(+), 1 deletion(-)
17
17
18
diff --git a/migration/savevm.c b/migration/savevm.c
18
diff --git a/migration/savevm.c b/migration/savevm.c
19
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
20
--- a/migration/savevm.c
20
--- a/migration/savevm.c
21
+++ b/migration/savevm.c
21
+++ b/migration/savevm.c
22
@@ -XXX,XX +XXX,XX @@ int qemu_loadvm_state(QEMUFile *f)
22
@@ -XXX,XX +XXX,XX @@ int qemu_loadvm_state(QEMUFile *f)
23
23
24
/* When reaching here, it must be precopy */
24
/* When reaching here, it must be precopy */
25
if (ret == 0) {
25
if (ret == 0) {
26
- ret = qemu_file_get_error(f);
26
- ret = qemu_file_get_error(f);
27
+ if (migrate_has_error(migrate_get_current())) {
27
+ if (migrate_has_error(migrate_get_current())) {
28
+ ret = -EINVAL;
28
+ ret = -EINVAL;
29
+ } else {
29
+ } else {
30
+ ret = qemu_file_get_error(f);
30
+ ret = qemu_file_get_error(f);
31
+ }
31
+ }
32
}
32
}
33
33
34
/*
34
/*
35
--
35
--
36
2.35.3
36
2.35.3
diff view generated by jsdifflib
New patch
1
1
The correct way of calling qcrypto_tls_session_handshake() requires
2
calling qcrypto_tls_session_get_handshake_status() right after it so
3
there's no reason to have a separate method.
4
5
Refactor qcrypto_tls_session_handshake() to inform the status in its
6
own return value and alter the callers accordingly.
7
8
No functional change.
9
10
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
11
Signed-off-by: Fabiano Rosas <farosas@suse.de>
12
---
13
crypto/tlssession.c | 64 +++++++++++------------------
14
include/crypto/tlssession.h | 32 ++++-----------
15
io/channel-tls.c | 7 ++--
16
tests/unit/test-crypto-tlssession.c | 12 ++----
17
4 files changed, 39 insertions(+), 76 deletions(-)
18
19
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/crypto/tlssession.c
22
+++ b/crypto/tlssession.c
23
@@ -XXX,XX +XXX,XX @@ qcrypto_tls_session_handshake(QCryptoTLSSession *session,
24
Error **errp)
25
{
26
int ret = gnutls_handshake(session->handle);
27
- if (ret == 0) {
28
+ if (!ret) {
29
session->handshakeComplete = true;
30
- } else {
31
- if (ret == GNUTLS_E_INTERRUPTED ||
32
- ret == GNUTLS_E_AGAIN) {
33
- ret = 1;
34
- } else {
35
- if (session->rerr || session->werr) {
36
- error_setg(errp, "TLS handshake failed: %s: %s",
37
- gnutls_strerror(ret),
38
- error_get_pretty(session->rerr ?
39
- session->rerr : session->werr));
40
- } else {
41
- error_setg(errp, "TLS handshake failed: %s",
42
- gnutls_strerror(ret));
43
- }
44
- ret = -1;
45
- }
46
- }
47
- error_free(session->rerr);
48
- error_free(session->werr);
49
- session->rerr = session->werr = NULL;
50
-
51
- return ret;
52
-}
53
-
54
-
55
-QCryptoTLSSessionHandshakeStatus
56
-qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *session)
57
-{
58
- if (session->handshakeComplete) {
59
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
60
- } else if (gnutls_record_get_direction(session->handle) == 0) {
61
- return QCRYPTO_TLS_HANDSHAKE_RECVING;
62
+ }
63
+
64
+ if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
65
+ int direction = gnutls_record_get_direction(session->handle);
66
+ return direction ? QCRYPTO_TLS_HANDSHAKE_SENDING :
67
+ QCRYPTO_TLS_HANDSHAKE_RECVING;
68
+ }
69
+
70
+ if (session->rerr || session->werr) {
71
+ error_setg(errp, "TLS handshake failed: %s: %s",
72
+ gnutls_strerror(ret),
73
+ error_get_pretty(session->rerr ?
74
+ session->rerr : session->werr));
75
} else {
76
- return QCRYPTO_TLS_HANDSHAKE_SENDING;
77
+ error_setg(errp, "TLS handshake failed: %s",
78
+ gnutls_strerror(ret));
79
}
80
+
81
+ error_free(session->rerr);
82
+ error_free(session->werr);
83
+ session->rerr = session->werr = NULL;
84
+
85
+ return -1;
86
}
87
88
+
89
int
90
qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
91
{
92
@@ -XXX,XX +XXX,XX @@ qcrypto_tls_session_check_pending(QCryptoTLSSession *session)
93
int
94
qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
95
Error **errp)
96
-{
97
- error_setg(errp, "TLS requires GNUTLS support");
98
- return -1;
99
-}
100
-
101
-
102
-QCryptoTLSSessionHandshakeStatus
103
-qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess)
104
{
105
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
106
}
107
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
108
index XXXXXXX..XXXXXXX 100644
109
--- a/include/crypto/tlssession.h
110
+++ b/include/crypto/tlssession.h
111
@@ -XXX,XX +XXX,XX @@
112
* GINT_TO_POINTER(fd));
113
*
114
* while (1) {
115
- * if (qcrypto_tls_session_handshake(sess, errp) < 0) {
116
+ * int ret = qcrypto_tls_session_handshake(sess, errp);
117
+ *
118
+ * if (ret < 0) {
119
* qcrypto_tls_session_free(sess);
120
* return -1;
121
* }
122
*
123
- * switch(qcrypto_tls_session_get_handshake_status(sess)) {
124
+ * switch(ret) {
125
* case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
126
* if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
127
* qcrypto_tls_session_free(sess);
128
@@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
129
*
130
* Validate the peer's credentials after a successful
131
* TLS handshake. It is an error to call this before
132
- * qcrypto_tls_session_get_handshake_status() returns
133
+ * qcrypto_tls_session_handshake() returns
134
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
135
*
136
* Returns 0 if the credentials validated, -1 on error
137
@@ -XXX,XX +XXX,XX @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
138
* registered with qcrypto_tls_session_set_callbacks()
139
*
140
* It is an error to call this before
141
- * qcrypto_tls_session_get_handshake_status() returns
142
+ * qcrypto_tls_session_handshake() returns
143
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
144
*
145
* Returns: the number of bytes sent,
146
@@ -XXX,XX +XXX,XX @@ ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
147
* opposed to an error.
148
*
149
* It is an error to call this before
150
- * qcrypto_tls_session_get_handshake_status() returns
151
+ * qcrypto_tls_session_handshake() returns
152
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
153
*
154
* Returns: the number of bytes received,
155
@@ -XXX,XX +XXX,XX @@ size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess);
156
* the underlying data channel is non-blocking, then
157
* this method may return control before the handshake
158
* is complete. On non-blocking channels the
159
- * qcrypto_tls_session_get_handshake_status() method
160
- * should be used to determine whether the handshake
161
+ * return value determines whether the handshake
162
* has completed, or is waiting to send or receive
163
* data. In the latter cases, the caller should setup
164
* an event loop watch and call this method again
165
@@ -XXX,XX +XXX,XX @@ typedef enum {
166
QCRYPTO_TLS_HANDSHAKE_RECVING,
167
} QCryptoTLSSessionHandshakeStatus;
168
169
-/**
170
- * qcrypto_tls_session_get_handshake_status:
171
- * @sess: the TLS session object
172
- *
173
- * Check the status of the TLS handshake. This
174
- * is used with non-blocking data channels to
175
- * determine whether the handshake is waiting
176
- * to send or receive further data to/from the
177
- * remote peer.
178
- *
179
- * Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE
180
- * it is permitted to send/receive payload data on
181
- * the channel
182
- */
183
-QCryptoTLSSessionHandshakeStatus
184
-qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
185
-
186
typedef enum {
187
QCRYPTO_TLS_BYE_COMPLETE,
188
QCRYPTO_TLS_BYE_SENDING,
189
diff --git a/io/channel-tls.c b/io/channel-tls.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/io/channel-tls.c
192
+++ b/io/channel-tls.c
193
@@ -XXX,XX +XXX,XX @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
194
GMainContext *context)
195
{
196
Error *err = NULL;
197
- QCryptoTLSSessionHandshakeStatus status;
198
+ int status;
199
200
- if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
201
+ status = qcrypto_tls_session_handshake(ioc->session, &err);
202
+
203
+ if (status < 0) {
204
trace_qio_channel_tls_handshake_fail(ioc);
205
qio_task_set_error(task, err);
206
qio_task_complete(task);
207
return;
208
}
209
210
- status = qcrypto_tls_session_get_handshake_status(ioc->session);
211
if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
212
trace_qio_channel_tls_handshake_complete(ioc);
213
if (qcrypto_tls_session_check_credentials(ioc->session,
214
diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c
215
index XXXXXXX..XXXXXXX 100644
216
--- a/tests/unit/test-crypto-tlssession.c
217
+++ b/tests/unit/test-crypto-tlssession.c
218
@@ -XXX,XX +XXX,XX @@ static void test_crypto_tls_session_psk(void)
219
rv = qcrypto_tls_session_handshake(serverSess,
220
&error_abort);
221
g_assert(rv >= 0);
222
- if (qcrypto_tls_session_get_handshake_status(serverSess) ==
223
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
224
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
225
serverShake = true;
226
}
227
}
228
@@ -XXX,XX +XXX,XX @@ static void test_crypto_tls_session_psk(void)
229
rv = qcrypto_tls_session_handshake(clientSess,
230
&error_abort);
231
g_assert(rv >= 0);
232
- if (qcrypto_tls_session_get_handshake_status(clientSess) ==
233
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
234
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
235
clientShake = true;
236
}
237
}
238
@@ -XXX,XX +XXX,XX @@ static void test_crypto_tls_session_x509(const void *opaque)
239
rv = qcrypto_tls_session_handshake(serverSess,
240
&error_abort);
241
g_assert(rv >= 0);
242
- if (qcrypto_tls_session_get_handshake_status(serverSess) ==
243
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
244
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
245
serverShake = true;
246
}
247
}
248
@@ -XXX,XX +XXX,XX @@ static void test_crypto_tls_session_x509(const void *opaque)
249
rv = qcrypto_tls_session_handshake(clientSess,
250
&error_abort);
251
g_assert(rv >= 0);
252
- if (qcrypto_tls_session_get_handshake_status(clientSess) ==
253
- QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
254
+ if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
255
clientShake = true;
256
}
257
}
258
--
259
2.35.3
260
261
diff view generated by jsdifflib
New patch
1
We want to pass flags into qio_channel_tls_readv() but some functions
2
along the way don't take a flags argument. Plumb the flags through.
1
3
4
No functional change.
5
6
Signed-off-by: Fabiano Rosas <farosas@suse.de>
7
---
8
hw/remote/mpqemu-link.c | 2 +-
9
include/io/channel.h | 6 ++++++
10
io/channel.c | 13 +++++++++----
11
migration/multifd.c | 2 +-
12
tools/i386/qemu-vmsr-helper.c | 3 ++-
13
util/vhost-user-server.c | 2 +-
14
6 files changed, 20 insertions(+), 8 deletions(-)
15
16
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/remote/mpqemu-link.c
19
+++ b/hw/remote/mpqemu-link.c
20
@@ -XXX,XX +XXX,XX @@ static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
21
bql_unlock();
22
}
23
24
- ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
25
+ ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, 0, errp);
26
27
if (drop_bql && !iothread && !qemu_in_coroutine()) {
28
bql_lock();
29
diff --git a/include/io/channel.h b/include/io/channel.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/io/channel.h
32
+++ b/include/io/channel.h
33
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
34
* @ioc: the channel object
35
* @iov: the array of memory regions to read data into
36
* @niov: the length of the @iov array
37
+ * @flags: read flags (QIO_CHANNEL_READ_FLAG_*)
38
* @errp: pointer to a NULL-initialized error object
39
*
40
* Read data from the IO channel, storing it in the
41
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
42
int coroutine_mixed_fn qio_channel_readv_all_eof(QIOChannel *ioc,
43
const struct iovec *iov,
44
size_t niov,
45
+ int flags,
46
Error **errp);
47
48
/**
49
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_write(QIOChannel *ioc,
50
* @ioc: the channel object
51
* @buf: the memory region to read data into
52
* @buflen: the number of bytes to @buf
53
+ * @flags: read flags (QIO_CHANNEL_READ_FLAG_*)
54
* @errp: pointer to a NULL-initialized error object
55
*
56
* Reads @buflen bytes into @buf, possibly blocking or (if the
57
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_write(QIOChannel *ioc,
58
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
59
char *buf,
60
size_t buflen,
61
+ int flags,
62
Error **errp);
63
64
/**
65
@@ -XXX,XX +XXX,XX @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
66
* @niov: the length of the @iov array
67
* @fds: an array of file handles to read
68
* @nfds: number of file handles in @fds
69
+ * @flags: read flags (QIO_CHANNEL_READ_FLAG_*)
70
* @errp: pointer to a NULL-initialized error object
71
*
72
*
73
@@ -XXX,XX +XXX,XX @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
74
const struct iovec *iov,
75
size_t niov,
76
int **fds, size_t *nfds,
77
+ int flags,
78
Error **errp);
79
80
/**
81
diff --git a/io/channel.c b/io/channel.c
82
index XXXXXXX..XXXXXXX 100644
83
--- a/io/channel.c
84
+++ b/io/channel.c
85
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
86
int coroutine_mixed_fn qio_channel_readv_all_eof(QIOChannel *ioc,
87
const struct iovec *iov,
88
size_t niov,
89
+ int flags,
90
Error **errp)
91
{
92
- return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
93
+ return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, flags,
94
+ errp);
95
}
96
97
int coroutine_mixed_fn qio_channel_readv_all(QIOChannel *ioc,
98
@@ -XXX,XX +XXX,XX @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
99
const struct iovec *iov,
100
size_t niov,
101
int **fds, size_t *nfds,
102
+ int flags,
103
Error **errp)
104
{
105
int ret = -1;
106
@@ -XXX,XX +XXX,XX @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
107
while ((nlocal_iov > 0) || local_fds) {
108
ssize_t len;
109
len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
110
- local_nfds, 0, errp);
111
+ local_nfds, flags, errp);
112
if (len == QIO_CHANNEL_ERR_BLOCK) {
113
if (qemu_in_coroutine()) {
114
qio_channel_yield(ioc, G_IO_IN);
115
@@ -XXX,XX +XXX,XX @@ int coroutine_mixed_fn qio_channel_readv_full_all(QIOChannel *ioc,
116
int **fds, size_t *nfds,
117
Error **errp)
118
{
119
- int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
120
+ int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, 0,
121
+ errp);
122
123
if (ret == 0) {
124
error_setg(errp, "Unexpected end-of-file before all data were read");
125
@@ -XXX,XX +XXX,XX @@ ssize_t qio_channel_write(QIOChannel *ioc,
126
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
127
char *buf,
128
size_t buflen,
129
+ int flags,
130
Error **errp)
131
{
132
struct iovec iov = { .iov_base = buf, .iov_len = buflen };
133
- return qio_channel_readv_all_eof(ioc, &iov, 1, errp);
134
+ return qio_channel_readv_all_eof(ioc, &iov, 1, flags, errp);
135
}
136
137
138
diff --git a/migration/multifd.c b/migration/multifd.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/migration/multifd.c
141
+++ b/migration/multifd.c
142
@@ -XXX,XX +XXX,XX @@ static void *multifd_recv_thread(void *opaque)
143
}
144
145
ret = qio_channel_read_all_eof(p->c, (void *)p->packet,
146
- p->packet_len, &local_err);
147
+ p->packet_len, 0, &local_err);
148
if (!ret) {
149
/* EOF */
150
assert(!local_err);
151
diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/tools/i386/qemu-vmsr-helper.c
154
+++ b/tools/i386/qemu-vmsr-helper.c
155
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vh_co_entry(void *opaque)
156
* Only RAPL MSR in rapl-msr-index.h is allowed
157
*/
158
r = qio_channel_read_all_eof(QIO_CHANNEL(client->ioc),
159
- (char *) &request, sizeof(request), &local_err);
160
+ (char *) &request, sizeof(request), 0,
161
+ &local_err);
162
if (r <= 0) {
163
break;
164
}
165
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/util/vhost-user-server.c
168
+++ b/util/vhost-user-server.c
169
@@ -XXX,XX +XXX,XX @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
170
.iov_len = vmsg->size,
171
};
172
if (vmsg->size) {
173
- rc = qio_channel_readv_all_eof(ioc, &iov_payload, 1, &local_err);
174
+ rc = qio_channel_readv_all_eof(ioc, &iov_payload, 1, 0, &local_err);
175
if (rc != 1) {
176
if (local_err) {
177
error_report_err(local_err);
178
--
179
2.35.3
diff view generated by jsdifflib
New patch
1
Add a read flag that can inform a channel that it's ok to receive an
2
EOF at any moment. Channels that have some form of strict EOF
3
tracking, such as TLS session termination, may choose to ignore EOF
4
errors with the use of this flag.
1
5
6
This is being added for compatibility with older migration streams
7
that do not include a TLS termination step.
8
9
Signed-off-by: Fabiano Rosas <farosas@suse.de>
10
---
11
include/io/channel.h | 1 +
12
io/channel-tls.c | 1 +
13
2 files changed, 2 insertions(+)
14
15
diff --git a/include/io/channel.h b/include/io/channel.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/io/channel.h
18
+++ b/include/io/channel.h
19
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,
20
#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1
21
22
#define QIO_CHANNEL_READ_FLAG_MSG_PEEK 0x1
23
+#define QIO_CHANNEL_READ_FLAG_RELAXED_EOF 0x2
24
25
typedef enum QIOChannelFeature QIOChannelFeature;
26
27
diff --git a/io/channel-tls.c b/io/channel-tls.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/io/channel-tls.c
30
+++ b/io/channel-tls.c
31
@@ -XXX,XX +XXX,XX @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
32
tioc->session,
33
iov[i].iov_base,
34
iov[i].iov_len,
35
+ flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF ||
36
qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
37
errp);
38
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
39
--
40
2.35.3
diff view generated by jsdifflib
New patch
1
We're currently changing the way the source multifd migration handles
2
the shutdown of the multifd channels when TLS is in use to perform a
3
clean termination by calling gnutls_bye().
1
4
5
Older src QEMUs will always close the channel without terminating the
6
TLS session. New dst QEMUs treat an unclean termination as an
7
error. Due to synchronization conditions, src QEMUs 9.1 and 9.2 are an
8
exception and can put the destination in a condition where it ignores
9
the unclean termination. For src QEMUs older than 9.1, we'll need a
10
compat property on the destination to inform that the src does not
11
terminate the TLS session.
12
13
Add multifd_clean_tls_termination (default true) that can be switched
14
on the destination whenever a src QEMU <9.1 is in use.
15
16
Signed-off-by: Fabiano Rosas <farosas@suse.de>
17
---
18
migration/migration.h | 33 +++++++++++++++++++++++++++++++++
19
migration/multifd.c | 8 +++++++-
20
migration/multifd.h | 2 ++
21
migration/options.c | 2 ++
22
4 files changed, 44 insertions(+), 1 deletion(-)
23
24
diff --git a/migration/migration.h b/migration/migration.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/migration/migration.h
27
+++ b/migration/migration.h
28
@@ -XXX,XX +XXX,XX @@ struct MigrationState {
29
* Default value is false. (since 8.1)
30
*/
31
bool multifd_flush_after_each_section;
32
+
33
+ /*
34
+ * This variable only makes sense when set on the machine that is
35
+ * the destination of a multifd migration with TLS enabled. It
36
+ * affects the behavior of the last send->recv iteration with
37
+ * regards to termination of the TLS session.
38
+ *
39
+ * When set:
40
+ *
41
+ * - the destination QEMU instance can expect to never get a
42
+ * GNUTLS_E_PREMATURE_TERMINATION error. Manifested as the error
43
+ * message: "The TLS connection was non-properly terminated".
44
+ *
45
+ * When clear:
46
+ *
47
+ * - the destination QEMU instance can expect to see a
48
+ * GNUTLS_E_PREMATURE_TERMINATION error in any multifd channel
49
+ * whenever the last recv() call of that channel happens after
50
+ * the source QEMU instance has already issued shutdown() on the
51
+ * channel.
52
+ *
53
+ * Commit 637280aeb2 (since 9.1) introduced a side effect that
54
+ * causes the destination instance to not be affected by the
55
+ * premature termination, while commit 1d457daf86 (since 10.0)
56
+ * causes the premature termination condition to be once again
57
+ * reachable.
58
+ *
59
+ * NOTE: Regardless of the state of this option, a premature
60
+ * termination of the TLS connection might happen due to error at
61
+ * any moment prior to the last send->recv iteration.
62
+ */
63
+ bool multifd_clean_tls_termination;
64
+
65
/*
66
* This decides the size of guest memory chunk that will be used
67
* to track dirty bitmap clearing. The size of memory chunk will
68
diff --git a/migration/multifd.c b/migration/multifd.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/migration/multifd.c
71
+++ b/migration/multifd.c
72
@@ -XXX,XX +XXX,XX @@ void multifd_recv_sync_main(void)
73
74
static void *multifd_recv_thread(void *opaque)
75
{
76
+ MigrationState *s = migrate_get_current();
77
MultiFDRecvParams *p = opaque;
78
Error *local_err = NULL;
79
bool use_packets = multifd_use_packets();
80
@@ -XXX,XX +XXX,XX @@ static void *multifd_recv_thread(void *opaque)
81
trace_multifd_recv_thread_start(p->id);
82
rcu_register_thread();
83
84
+ if (!s->multifd_clean_tls_termination) {
85
+ p->read_flags = QIO_CHANNEL_READ_FLAG_RELAXED_EOF;
86
+ }
87
+
88
while (true) {
89
uint32_t flags = 0;
90
bool has_data = false;
91
@@ -XXX,XX +XXX,XX @@ static void *multifd_recv_thread(void *opaque)
92
}
93
94
ret = qio_channel_read_all_eof(p->c, (void *)p->packet,
95
- p->packet_len, 0, &local_err);
96
+ p->packet_len, p->read_flags,
97
+ &local_err);
98
if (!ret) {
99
/* EOF */
100
assert(!local_err);
101
diff --git a/migration/multifd.h b/migration/multifd.h
102
index XXXXXXX..XXXXXXX 100644
103
--- a/migration/multifd.h
104
+++ b/migration/multifd.h
105
@@ -XXX,XX +XXX,XX @@ typedef struct {
106
uint32_t zero_num;
107
/* used for de-compression methods */
108
void *compress_data;
109
+ /* Flags for the QIOChannel */
110
+ int read_flags;
111
} MultiFDRecvParams;
112
113
typedef struct {
114
diff --git a/migration/options.c b/migration/options.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/migration/options.c
117
+++ b/migration/options.c
118
@@ -XXX,XX +XXX,XX @@ const Property migration_properties[] = {
119
clear_bitmap_shift, CLEAR_BITMAP_SHIFT_DEFAULT),
120
DEFINE_PROP_BOOL("x-preempt-pre-7-2", MigrationState,
121
preempt_pre_7_2, false),
122
+ DEFINE_PROP_BOOL("multifd-clean-tls-termination", MigrationState,
123
+ multifd_clean_tls_termination, true),
124
125
/* Migration parameters */
126
DEFINE_PROP_UINT8("x-throttle-trigger-threshold", MigrationState,
127
--
128
2.35.3
diff view generated by jsdifflib