mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-27 07:29:32 +00:00
seamless migration: pre migration phase on the destination side
- handle SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS - reply with SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK/NACK - prepare the channels for migration according to the migration type (semi/seamless) see spice-protocol for more details: commit 3838ad140a046c4ddf42fef58c9727ecfdc09f9f
This commit is contained in:
parent
43e0897da5
commit
8e2576d5ab
@ -790,9 +790,9 @@ static void main_channel_release_pipe_item(RedChannelClient *rcc,
|
||||
free(base);
|
||||
}
|
||||
|
||||
void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
|
||||
int success,
|
||||
int seamless)
|
||||
static void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
|
||||
int success,
|
||||
int seamless)
|
||||
{
|
||||
spice_printerr("client %p connected: %d seamless %d", mcc->base.client, success, seamless);
|
||||
if (mcc->mig_wait_connect) {
|
||||
@ -813,6 +813,18 @@ void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
|
||||
}
|
||||
}
|
||||
|
||||
void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
|
||||
uint32_t src_version)
|
||||
{
|
||||
if (reds_on_migrate_dst_set_seamless(mcc, src_version)) {
|
||||
red_channel_client_pipe_add_type(&mcc->base,
|
||||
SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
|
||||
} else {
|
||||
red_channel_client_pipe_add_type(&mcc->base,
|
||||
SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK);
|
||||
}
|
||||
}
|
||||
|
||||
void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
|
||||
{
|
||||
if (!red_client_during_migrate_at_target(mcc->base.client)) {
|
||||
@ -882,6 +894,10 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
|
||||
case SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR:
|
||||
main_channel_client_handle_migrate_connected(mcc, FALSE, FALSE);
|
||||
break;
|
||||
case SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS:
|
||||
main_channel_client_handle_migrate_dst_do_seamless(mcc,
|
||||
((SpiceMsgcMainMigrateDstDoSeamless *)message)->src_version);
|
||||
break;
|
||||
case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
|
||||
reds_on_main_mouse_mode_request(message, size);
|
||||
break;
|
||||
@ -1125,6 +1141,7 @@ MainChannel* main_channel_init(void)
|
||||
&channel_cbs);
|
||||
spice_assert(channel);
|
||||
red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
|
||||
|
||||
return (MainChannel *)channel;
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@
|
||||
#include "stat.h"
|
||||
#include "demarshallers.h"
|
||||
#include "char_device.h"
|
||||
#include "migration_protocol.h"
|
||||
#ifdef USE_TUNNEL
|
||||
#include "red_tunnel_worker.h"
|
||||
#endif
|
||||
@ -242,6 +243,8 @@ typedef struct RedsState {
|
||||
int expect_migrate;
|
||||
int src_do_seamless_migrate; /* per migration. Updated after the migration handshake
|
||||
between the 2 servers */
|
||||
int dst_do_seamless_migrate; /* per migration. Updated after the migration handshake
|
||||
between the 2 servers */
|
||||
Ring mig_target_clients;
|
||||
int num_mig_target_clients;
|
||||
RedsMigSpice *mig_spice;
|
||||
@ -256,7 +259,7 @@ typedef struct RedsState {
|
||||
|
||||
int vm_running;
|
||||
Ring char_devs_states; /* list of SpiceCharDeviceStateItem */
|
||||
int seamless_migration_enabled;
|
||||
int seamless_migration_enabled; /* command line arg */
|
||||
|
||||
SSL_CTX *ctx;
|
||||
|
||||
@ -1548,26 +1551,28 @@ static void reds_channel_do_link(RedChannel *channel, RedClient *client,
|
||||
caps + link_msg->num_common_caps : NULL);
|
||||
}
|
||||
|
||||
void reds_on_client_migrate_complete(RedClient *client)
|
||||
/*
|
||||
* migration target side:
|
||||
* In semi-seamless migration, we activate the channels only
|
||||
* after migration is completed.
|
||||
* In seamless migration, in order to keep the continuousness, and
|
||||
* not lose any data, we activate the target channels before
|
||||
* migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS
|
||||
*/
|
||||
static int reds_link_mig_target_channels(RedClient *client)
|
||||
{
|
||||
RedsMigTargetClient *mig_client;
|
||||
MainChannelClient *mcc;
|
||||
RingItem *item;
|
||||
|
||||
spice_info("%p", client);
|
||||
mcc = red_client_get_main(client);
|
||||
mig_client = reds_mig_target_client_find(client);
|
||||
if (!mig_client) {
|
||||
spice_warning("mig target client was not found");
|
||||
return;
|
||||
spice_info("Error: mig target client was not found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO: not doing net test. consider doing it on client_migrate_info
|
||||
main_channel_push_init(mcc, red_dispatcher_count(),
|
||||
reds->mouse_mode, reds->is_client_mouse_allowed,
|
||||
reds_get_mm_time() - MM_TIME_DELTA,
|
||||
red_dispatcher_qxl_ram_size());
|
||||
|
||||
/* Each channel should check if we are during migration, and
|
||||
* act accordingly. */
|
||||
RING_FOREACH(item, &mig_client->pending_links) {
|
||||
RedsMigPendingLink *mig_link;
|
||||
RedChannel *channel;
|
||||
@ -1586,6 +1591,40 @@ void reds_on_client_migrate_complete(RedClient *client)
|
||||
}
|
||||
|
||||
reds_mig_target_client_free(mig_client);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version)
|
||||
{
|
||||
/* seamless migration is not supported with multiple clients*/
|
||||
if (reds->allow_multiple_clients || src_version > SPICE_MIGRATION_PROTOCOL_VERSION) {
|
||||
reds->dst_do_seamless_migrate = FALSE;
|
||||
} else {
|
||||
RedClient *client;
|
||||
|
||||
client = main_channel_client_get_base(mcc)->client;
|
||||
reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
|
||||
/* linking all the channels that have been connected before migration handshake */
|
||||
reds->dst_do_seamless_migrate = reds_link_mig_target_channels(client);
|
||||
}
|
||||
return reds->dst_do_seamless_migrate;
|
||||
}
|
||||
|
||||
/* semi seamless */
|
||||
void reds_on_client_migrate_complete(RedClient *client)
|
||||
{
|
||||
MainChannelClient *mcc;
|
||||
|
||||
spice_info("%p", client);
|
||||
mcc = red_client_get_main(client);
|
||||
|
||||
// TODO: not doing net test. consider doing it on client_migrate_info
|
||||
main_channel_push_init(mcc, red_dispatcher_count(),
|
||||
reds->mouse_mode, reds->is_client_mouse_allowed,
|
||||
reds_get_mm_time() - MM_TIME_DELTA,
|
||||
red_dispatcher_qxl_ram_size());
|
||||
reds_link_mig_target_channels(client);
|
||||
}
|
||||
|
||||
static void reds_handle_other_links(RedLinkInfo *link)
|
||||
@ -1623,7 +1662,17 @@ static void reds_handle_other_links(RedLinkInfo *link)
|
||||
reds_stream_remove_watch(link->stream);
|
||||
|
||||
mig_client = reds_mig_target_client_find(client);
|
||||
if (red_client_during_migrate_at_target(client)) {
|
||||
/*
|
||||
* In semi-seamless migration, we activate the channels only
|
||||
* after migration is completed. Since, the session starts almost from
|
||||
* scratch we don't mind if we skip some messages in between the src session end and
|
||||
* dst session start.
|
||||
* In seamless migration, in order to keep the continuousness of the session, and
|
||||
* in order not to lose any data, we activate the target channels before
|
||||
* migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS.
|
||||
* If a channel connects before receiving SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS,
|
||||
* reds_on_migrate_dst_set_seamless will take care of activating it */
|
||||
if (red_client_during_migrate_at_target(client) && !reds->dst_do_seamless_migrate) {
|
||||
spice_assert(mig_client);
|
||||
reds_mig_target_client_add_pending_link(mig_client, link_mess, link->stream);
|
||||
} else {
|
||||
|
||||
@ -154,6 +154,9 @@ void reds_on_main_migrate_connected(int seamless); //should be called when all t
|
||||
// are connected to the target
|
||||
void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end);
|
||||
void reds_on_main_mouse_mode_request(void *message, size_t size);
|
||||
/* migration dest side: returns whether it can support seamless migration
|
||||
* with the given src migration protocol version */
|
||||
int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version);
|
||||
void reds_on_client_migrate_complete(RedClient *client);
|
||||
void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user