-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJcfh/0AAoJEO8Ells5jWIRmqIH/RbXUBbnhqBq/X2lDfz8A5o2
 9PowtrMj7tT0ZDpFkDtz8UcQVLvMa4A5c6lgQ9kjiCuX3bISjqvkUc0w/TMjgQCX
 7AGObzdgoVY58OmLbmmKYduTWbVZf33qton+yee0g92F+O/mroH9PZIUmDOC+Mm9
 iU+CFiMHIjfFv9BogTvFk3nf9XD9zMMTJLbFe2iA64KYUNPy2ncURlltlMTSqRDz
 PDawd7bmuVwWBLekNpwe0vliJC2t5/Cd78Njc7HMuKJsivmZAcFqJQ2xA2XxzmLp
 bQrYAXiaC3N/gDqgDsNNp/Buuy4pBJKFVAPYveBIqw9LwGYFwkkMZqGb8/9kca0=
 =zAY7
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging

# gpg: Signature made Tue 05 Mar 2019 07:06:28 GMT
# gpg:                using RSA key EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* remotes/jasowang/tags/net-pull-request:
  tests: Add a test for qemu self announcements
  hmp: Add hmp_announce_self
  qmp: Add announce-self command
  virtio-net: Allow qemu_announce_self to trigger virtio announcements
  net: Add a network device specific self-announcement ability
  migration: Switch to using announce timer
  virtio-net: Switch to using announce timer
  migration: Add announce parameters
  net: Introduce announce timer
  net: netmap: improve netmap_receive_iov()
  net: netmap: simplify netmap_receive()
  net: netmap: small improvements netmap_send()
  net/colo-compare.c: Remove duplicated code

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-03-05 09:33:20 +00:00
commit 0984a157c1
25 changed files with 637 additions and 174 deletions

View File

@ -936,6 +936,22 @@ Bug: can screw up when the buffer contains invalid UTF-8 sequences,
NUL characters, after the ring buffer lost data, and when reading NUL characters, after the ring buffer lost data, and when reading
stops because the size limit is reached. stops because the size limit is reached.
ETEXI
{
.name = "announce_self",
.args_type = "",
.params = "",
.help = "Trigger GARP/RARP announcements",
.cmd = hmp_announce_self,
},
STEXI
@item announce_self
@findex announce_self
Trigger a round of GARP/RARP broadcasts; this is useful for explicitly updating the
network infrastructure after a reconfiguration or some forms of migration.
The timings of the round are set by the migration announce parameters.
ETEXI ETEXI
{ {

33
hmp.c
View File

@ -334,6 +334,18 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
params = qmp_query_migrate_parameters(NULL); params = qmp_query_migrate_parameters(NULL);
if (params) { if (params) {
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL),
params->announce_initial);
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX),
params->announce_max);
monitor_printf(mon, "%s: %" PRIu64 "\n",
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS),
params->announce_rounds);
monitor_printf(mon, "%s: %" PRIu64 " ms\n",
MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP),
params->announce_step);
assert(params->has_compress_level); assert(params->has_compress_level);
monitor_printf(mon, "%s: %u\n", monitor_printf(mon, "%s: %u\n",
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL), MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL),
@ -1558,6 +1570,11 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
} }
void hmp_announce_self(Monitor *mon, const QDict *qdict)
{
qmp_announce_self(migrate_announce_params(), NULL);
}
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
{ {
qmp_migrate_cancel(NULL); qmp_migrate_cancel(NULL);
@ -1757,6 +1774,22 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
p->has_max_postcopy_bandwidth = true; p->has_max_postcopy_bandwidth = true;
visit_type_size(v, param, &p->max_postcopy_bandwidth, &err); visit_type_size(v, param, &p->max_postcopy_bandwidth, &err);
break; break;
case MIGRATION_PARAMETER_ANNOUNCE_INITIAL:
p->has_announce_initial = true;
visit_type_size(v, param, &p->announce_initial, &err);
break;
case MIGRATION_PARAMETER_ANNOUNCE_MAX:
p->has_announce_max = true;
visit_type_size(v, param, &p->announce_max, &err);
break;
case MIGRATION_PARAMETER_ANNOUNCE_ROUNDS:
p->has_announce_rounds = true;
visit_type_size(v, param, &p->announce_rounds, &err);
break;
case MIGRATION_PARAMETER_ANNOUNCE_STEP:
p->has_announce_step = true;
visit_type_size(v, param, &p->announce_step, &err);
break;
default: default:
assert(0); assert(0);
} }

1
hmp.h
View File

@ -46,6 +46,7 @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict); void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict); void hmp_exit_preconfig(Monitor *mon, const QDict *qdict);
void hmp_announce_self(Monitor *mon, const QDict *qdict);
void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_cpu(Monitor *mon, const QDict *qdict);
void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict);
void hmp_pmemsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict);

View File

@ -359,3 +359,9 @@ sunhme_rx_filter_reject(void) "rejecting incoming frame"
sunhme_rx_filter_accept(void) "accepting incoming frame" sunhme_rx_filter_accept(void) "accepting incoming frame"
sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int nr) "addr 0x%"PRIx32"(+0x%x) status 0x%"PRIx32 " len %d (ring %d/%d)" sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int nr) "addr 0x%"PRIx32"(+0x%x) status 0x%"PRIx32 " len %d (ring %d/%d)"
sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x" sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x"
# hw/net/virtio-net.c
virtio_net_announce_notify(void) ""
virtio_net_announce_timer(int round) "%d"
virtio_net_handle_announce(int round) "%d"
virtio_net_post_load_device(void)

View File

@ -21,12 +21,14 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-net.h"
#include "net/vhost_net.h" #include "net/vhost_net.h"
#include "net/announce.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qapi-events-net.h" #include "qapi/qapi-events-net.h"
#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-access.h"
#include "migration/misc.h" #include "migration/misc.h"
#include "standard-headers/linux/ethtool.h" #include "standard-headers/linux/ethtool.h"
#include "trace.h"
#define VIRTIO_NET_VM_VERSION 11 #define VIRTIO_NET_VM_VERSION 11
@ -148,14 +150,42 @@ static bool virtio_net_started(VirtIONet *n, uint8_t status)
(n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running; (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running;
} }
static void virtio_net_announce_notify(VirtIONet *net)
{
VirtIODevice *vdev = VIRTIO_DEVICE(net);
trace_virtio_net_announce_notify();
net->status |= VIRTIO_NET_S_ANNOUNCE;
virtio_notify_config(vdev);
}
static void virtio_net_announce_timer(void *opaque) static void virtio_net_announce_timer(void *opaque)
{ {
VirtIONet *n = opaque; VirtIONet *n = opaque;
trace_virtio_net_announce_timer(n->announce_timer.round);
n->announce_timer.round--;
virtio_net_announce_notify(n);
}
static void virtio_net_announce(NetClientState *nc)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
n->announce_counter--; /*
n->status |= VIRTIO_NET_S_ANNOUNCE; * Make sure the virtio migration announcement timer isn't running
virtio_notify_config(vdev); * If it is, let it trigger announcement so that we do not cause
* confusion.
*/
if (n->announce_timer.round) {
return;
}
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
virtio_net_announce_notify(n);
}
} }
static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
@ -467,8 +497,8 @@ static void virtio_net_reset(VirtIODevice *vdev)
n->nobcast = 0; n->nobcast = 0;
/* multiqueue is disabled by default */ /* multiqueue is disabled by default */
n->curr_queues = 1; n->curr_queues = 1;
timer_del(n->announce_timer); timer_del(n->announce_timer.tm);
n->announce_counter = 0; n->announce_timer.round = 0;
n->status &= ~VIRTIO_NET_S_ANNOUNCE; n->status &= ~VIRTIO_NET_S_ANNOUNCE;
/* Flush any MAC and VLAN filter table state */ /* Flush any MAC and VLAN filter table state */
@ -964,13 +994,12 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd, static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
struct iovec *iov, unsigned int iov_cnt) struct iovec *iov, unsigned int iov_cnt)
{ {
trace_virtio_net_handle_announce(n->announce_timer.round);
if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK && if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK &&
n->status & VIRTIO_NET_S_ANNOUNCE) { n->status & VIRTIO_NET_S_ANNOUNCE) {
n->status &= ~VIRTIO_NET_S_ANNOUNCE; n->status &= ~VIRTIO_NET_S_ANNOUNCE;
if (n->announce_counter) { if (n->announce_timer.round) {
timer_mod(n->announce_timer, qemu_announce_timer_step(&n->announce_timer);
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
self_announce_delay(n->announce_counter));
} }
return VIRTIO_NET_OK; return VIRTIO_NET_OK;
} else { } else {
@ -2286,6 +2315,7 @@ static int virtio_net_post_load_device(void *opaque, int version_id)
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
int i, link_down; int i, link_down;
trace_virtio_net_post_load_device();
virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs,
virtio_vdev_has_feature(vdev, virtio_vdev_has_feature(vdev,
VIRTIO_F_VERSION_1)); VIRTIO_F_VERSION_1));
@ -2322,8 +2352,15 @@ static int virtio_net_post_load_device(void *opaque, int version_id)
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
n->announce_counter = SELF_ANNOUNCE_ROUNDS; qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(),
timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); QEMU_CLOCK_VIRTUAL,
virtio_net_announce_timer, n);
if (n->announce_timer.round) {
timer_mod(n->announce_timer.tm,
qemu_clock_get_ms(n->announce_timer.type));
} else {
qemu_announce_timer_del(&n->announce_timer);
}
} }
return 0; return 0;
@ -2546,6 +2583,7 @@ static NetClientInfo net_virtio_info = {
.receive = virtio_net_receive, .receive = virtio_net_receive,
.link_status_changed = virtio_net_set_link_status, .link_status_changed = virtio_net_set_link_status,
.query_rx_filter = virtio_net_query_rxfilter, .query_rx_filter = virtio_net_query_rxfilter,
.announce = virtio_net_announce,
}; };
static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
@ -2679,8 +2717,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac));
n->status = VIRTIO_NET_S_LINK_UP; n->status = VIRTIO_NET_S_LINK_UP;
n->announce_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(),
virtio_net_announce_timer, n); QEMU_CLOCK_VIRTUAL,
virtio_net_announce_timer, n);
n->announce_timer.round = 0;
if (n->netclient_type) { if (n->netclient_type) {
/* /*
@ -2743,8 +2783,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
virtio_net_del_queue(n, i); virtio_net_del_queue(n, i);
} }
timer_del(n->announce_timer); qemu_announce_timer_del(&n->announce_timer);
timer_free(n->announce_timer);
g_free(n->vqs); g_free(n->vqs);
qemu_del_nic(n->nic); qemu_del_nic(n->nic);
virtio_net_rsc_cleanup(n); virtio_net_rsc_cleanup(n);

View File

@ -17,6 +17,7 @@
#include "qemu/units.h" #include "qemu/units.h"
#include "standard-headers/linux/virtio_net.h" #include "standard-headers/linux/virtio_net.h"
#include "hw/virtio/virtio.h" #include "hw/virtio/virtio.h"
#include "net/announce.h"
#define TYPE_VIRTIO_NET "virtio-net-device" #define TYPE_VIRTIO_NET "virtio-net-device"
#define VIRTIO_NET(obj) \ #define VIRTIO_NET(obj) \
@ -181,8 +182,7 @@ struct VirtIONet {
char *netclient_name; char *netclient_name;
char *netclient_type; char *netclient_type;
uint64_t curr_guest_offloads; uint64_t curr_guest_offloads;
QEMUTimer *announce_timer; AnnounceTimer announce_timer;
int announce_counter;
bool needs_vnet_hdr_swap; bool needs_vnet_hdr_swap;
bool mtu_bypass_backend; bool mtu_bypass_backend;
}; };

View File

@ -15,6 +15,7 @@
#define MIGRATION_MISC_H #define MIGRATION_MISC_H
#include "qemu/notify.h" #include "qemu/notify.h"
#include "qapi/qapi-types-net.h"
/* migration/ram.c */ /* migration/ram.c */
@ -28,16 +29,7 @@ void blk_mig_init(void);
static inline void blk_mig_init(void) {} static inline void blk_mig_init(void) {}
#endif #endif
#define SELF_ANNOUNCE_ROUNDS 5 AnnounceParameters *migrate_announce_params(void);
static inline
int64_t self_announce_delay(int round)
{
assert(round < SELF_ANNOUNCE_ROUNDS && round > 0);
/* delay 50ms, 150ms, 250ms, ... */
return 50 + (SELF_ANNOUNCE_ROUNDS - round - 1) * 100;
}
/* migration/savevm.c */ /* migration/savevm.c */
void dump_vmstate_json_to_file(FILE *out_fp); void dump_vmstate_json_to_file(FILE *out_fp);

41
include/net/announce.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Self-announce facility
* (c) 2017-2019 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_NET_ANNOUNCE_H
#define QEMU_NET_ANNOUNCE_H
#include "qemu-common.h"
#include "qapi/qapi-types-net.h"
#include "qemu/timer.h"
struct AnnounceTimer {
QEMUTimer *tm;
AnnounceParameters params;
QEMUClockType type;
int round;
};
/* Returns: update the timer to the next time point */
int64_t qemu_announce_timer_step(AnnounceTimer *timer);
/* Delete the underlying timer */
void qemu_announce_timer_del(AnnounceTimer *timer);
/*
* Under BQL/main thread
* Reset the timer to the given parameters/type/notifier.
*/
void qemu_announce_timer_reset(AnnounceTimer *timer,
AnnounceParameters *params,
QEMUClockType type,
QEMUTimerCB *cb,
void *opaque);
void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params);
#endif

View File

@ -60,6 +60,7 @@ typedef int (SetVnetLE)(NetClientState *, bool);
typedef int (SetVnetBE)(NetClientState *, bool); typedef int (SetVnetBE)(NetClientState *, bool);
typedef struct SocketReadState SocketReadState; typedef struct SocketReadState SocketReadState;
typedef void (SocketReadStateFinalize)(SocketReadState *rs); typedef void (SocketReadStateFinalize)(SocketReadState *rs);
typedef void (NetAnnounce)(NetClientState *);
typedef struct NetClientInfo { typedef struct NetClientInfo {
NetClientDriver type; NetClientDriver type;
@ -80,6 +81,7 @@ typedef struct NetClientInfo {
SetVnetHdrLen *set_vnet_hdr_len; SetVnetHdrLen *set_vnet_hdr_len;
SetVnetLE *set_vnet_le; SetVnetLE *set_vnet_le;
SetVnetBE *set_vnet_be; SetVnetBE *set_vnet_be;
NetAnnounce *announce;
} NetClientInfo; } NetClientInfo;
struct NetClientState { struct NetClientState {

View File

@ -8,6 +8,7 @@
typedef struct AdapterInfo AdapterInfo; typedef struct AdapterInfo AdapterInfo;
typedef struct AddressSpace AddressSpace; typedef struct AddressSpace AddressSpace;
typedef struct AioContext AioContext; typedef struct AioContext AioContext;
typedef struct AnnounceTimer AnnounceTimer;
typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter; typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
typedef struct BlockBackend BlockBackend; typedef struct BlockBackend BlockBackend;

View File

@ -81,8 +81,6 @@ extern bool machine_init_done;
void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_add_machine_init_done_notifier(Notifier *notify);
void qemu_remove_machine_init_done_notifier(Notifier *notify); void qemu_remove_machine_init_done_notifier(Notifier *notify);
void qemu_announce_self(void);
extern int autostart; extern int autostart;
typedef enum { typedef enum {

View File

@ -45,6 +45,7 @@
#include "migration/colo.h" #include "migration/colo.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "net/announce.h"
#define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */
@ -86,6 +87,15 @@
*/ */
#define DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH 0 #define DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH 0
/*
* Parameters for self_announce_delay giving a stream of RARP/ARP
* packets after migration.
*/
#define DEFAULT_MIGRATE_ANNOUNCE_INITIAL 50
#define DEFAULT_MIGRATE_ANNOUNCE_MAX 550
#define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS 5
#define DEFAULT_MIGRATE_ANNOUNCE_STEP 100
static NotifierList migration_state_notifiers = static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers); NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@ -364,7 +374,7 @@ static void process_incoming_migration_bh(void *opaque)
* This must happen after all error conditions are dealt with and * This must happen after all error conditions are dealt with and
* we're sure the VM is going to be running on this host. * we're sure the VM is going to be running on this host.
*/ */
qemu_announce_self(); qemu_announce_self(&mis->announce_timer, migrate_announce_params());
if (multifd_load_cleanup(&local_err) != 0) { if (multifd_load_cleanup(&local_err) != 0) {
error_report_err(local_err); error_report_err(local_err);
@ -739,10 +749,32 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth; params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
params->has_max_cpu_throttle = true; params->has_max_cpu_throttle = true;
params->max_cpu_throttle = s->parameters.max_cpu_throttle; params->max_cpu_throttle = s->parameters.max_cpu_throttle;
params->has_announce_initial = true;
params->announce_initial = s->parameters.announce_initial;
params->has_announce_max = true;
params->announce_max = s->parameters.announce_max;
params->has_announce_rounds = true;
params->announce_rounds = s->parameters.announce_rounds;
params->has_announce_step = true;
params->announce_step = s->parameters.announce_step;
return params; return params;
} }
AnnounceParameters *migrate_announce_params(void)
{
static AnnounceParameters ap;
MigrationState *s = migrate_get_current();
ap.initial = s->parameters.announce_initial;
ap.max = s->parameters.announce_max;
ap.rounds = s->parameters.announce_rounds;
ap.step = s->parameters.announce_step;
return &ap;
}
/* /*
* Return true if we're already in the middle of a migration * Return true if we're already in the middle of a migration
* (i.e. any of the active or setup states) * (i.e. any of the active or setup states)
@ -1116,6 +1148,35 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp)
return false; return false;
} }
if (params->has_announce_initial &&
params->announce_initial > 100000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_initial",
"is invalid, it must be less than 100000 ms");
return false;
}
if (params->has_announce_max &&
params->announce_max > 100000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_max",
"is invalid, it must be less than 100000 ms");
return false;
}
if (params->has_announce_rounds &&
params->announce_rounds > 1000) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_rounds",
"is invalid, it must be in the range of 0 to 1000");
return false;
}
if (params->has_announce_step &&
(params->announce_step < 1 ||
params->announce_step > 10000)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"announce_step",
"is invalid, it must be in the range of 1 to 10000 ms");
return false;
}
return true; return true;
} }
@ -1190,6 +1251,18 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
if (params->has_max_cpu_throttle) { if (params->has_max_cpu_throttle) {
dest->max_cpu_throttle = params->max_cpu_throttle; dest->max_cpu_throttle = params->max_cpu_throttle;
} }
if (params->has_announce_initial) {
dest->announce_initial = params->announce_initial;
}
if (params->has_announce_max) {
dest->announce_max = params->announce_max;
}
if (params->has_announce_rounds) {
dest->announce_rounds = params->announce_rounds;
}
if (params->has_announce_step) {
dest->announce_step = params->announce_step;
}
} }
static void migrate_params_apply(MigrateSetParameters *params, Error **errp) static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@ -1272,6 +1345,18 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_max_cpu_throttle) { if (params->has_max_cpu_throttle) {
s->parameters.max_cpu_throttle = params->max_cpu_throttle; s->parameters.max_cpu_throttle = params->max_cpu_throttle;
} }
if (params->has_announce_initial) {
s->parameters.announce_initial = params->announce_initial;
}
if (params->has_announce_max) {
s->parameters.announce_max = params->announce_max;
}
if (params->has_announce_rounds) {
s->parameters.announce_rounds = params->announce_rounds;
}
if (params->has_announce_step) {
s->parameters.announce_step = params->announce_step;
}
} }
void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
@ -3274,6 +3359,18 @@ static Property migration_properties[] = {
DEFINE_PROP_UINT8("max-cpu-throttle", MigrationState, DEFINE_PROP_UINT8("max-cpu-throttle", MigrationState,
parameters.max_cpu_throttle, parameters.max_cpu_throttle,
DEFAULT_MIGRATE_MAX_CPU_THROTTLE), DEFAULT_MIGRATE_MAX_CPU_THROTTLE),
DEFINE_PROP_SIZE("announce-initial", MigrationState,
parameters.announce_initial,
DEFAULT_MIGRATE_ANNOUNCE_INITIAL),
DEFINE_PROP_SIZE("announce-max", MigrationState,
parameters.announce_max,
DEFAULT_MIGRATE_ANNOUNCE_MAX),
DEFINE_PROP_SIZE("announce-rounds", MigrationState,
parameters.announce_rounds,
DEFAULT_MIGRATE_ANNOUNCE_ROUNDS),
DEFINE_PROP_SIZE("announce-step", MigrationState,
parameters.announce_step,
DEFAULT_MIGRATE_ANNOUNCE_STEP),
/* Migration capabilities */ /* Migration capabilities */
DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
@ -3346,6 +3443,10 @@ static void migration_instance_init(Object *obj)
params->has_xbzrle_cache_size = true; params->has_xbzrle_cache_size = true;
params->has_max_postcopy_bandwidth = true; params->has_max_postcopy_bandwidth = true;
params->has_max_cpu_throttle = true; params->has_max_cpu_throttle = true;
params->has_announce_initial = true;
params->has_announce_max = true;
params->has_announce_rounds = true;
params->has_announce_step = true;
qemu_sem_init(&ms->postcopy_pause_sem, 0); qemu_sem_init(&ms->postcopy_pause_sem, 0);
qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); qemu_sem_init(&ms->postcopy_pause_rp_sem, 0);

View File

@ -21,6 +21,7 @@
#include "qemu/coroutine_int.h" #include "qemu/coroutine_int.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "io/channel.h" #include "io/channel.h"
#include "net/announce.h"
struct PostcopyBlocktimeContext; struct PostcopyBlocktimeContext;
@ -36,6 +37,9 @@ struct MigrationIncomingState {
*/ */
QemuEvent main_thread_load_event; QemuEvent main_thread_load_event;
/* For network announces */
AnnounceTimer announce_timer;
size_t largest_page_size; size_t largest_page_size;
bool have_fault_thread; bool have_fault_thread;
QemuThread fault_thread; QemuThread fault_thread;

View File

@ -57,13 +57,7 @@
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "qjson.h" #include "qjson.h"
#include "migration/colo.h" #include "migration/colo.h"
#include "net/announce.h"
#ifndef ETH_P_RARP
#define ETH_P_RARP 0x8035
#endif
#define ARP_HTYPE_ETH 0x0001
#define ARP_PTYPE_IP 0x0800
#define ARP_OP_REQUEST_REV 0x3
const unsigned int postcopy_ram_discard_version = 0; const unsigned int postcopy_ram_discard_version = 0;
@ -125,67 +119,6 @@ static struct mig_cmd_args {
* generic extendable format with an exception for two old entities. * generic extendable format with an exception for two old entities.
*/ */
static int announce_self_create(uint8_t *buf,
uint8_t *mac_addr)
{
/* Ethernet header. */
memset(buf, 0xff, 6); /* destination MAC addr */
memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
*(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
/* RARP header. */
*(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
*(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
*(buf + 18) = 6; /* hardware addr length (ethernet) */
*(buf + 19) = 4; /* protocol addr length (IPv4) */
*(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
memcpy(buf + 22, mac_addr, 6); /* source hw addr */
memset(buf + 28, 0x00, 4); /* source protocol addr */
memcpy(buf + 32, mac_addr, 6); /* target hw addr */
memset(buf + 38, 0x00, 4); /* target protocol addr */
/* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
memset(buf + 42, 0x00, 18);
return 60; /* len (FCS will be added by hardware) */
}
static void qemu_announce_self_iter(NICState *nic, void *opaque)
{
uint8_t buf[60];
int len;
trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
len = announce_self_create(buf, nic->conf->macaddr.a);
qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
}
static void qemu_announce_self_once(void *opaque)
{
static int count = SELF_ANNOUNCE_ROUNDS;
QEMUTimer *timer = *(QEMUTimer **)opaque;
qemu_foreach_nic(qemu_announce_self_iter, NULL);
if (--count) {
/* delay 50ms, 150ms, 250ms, ... */
timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
self_announce_delay(count));
} else {
timer_del(timer);
timer_free(timer);
}
}
void qemu_announce_self(void)
{
static QEMUTimer *timer;
timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_announce_self_once, &timer);
qemu_announce_self_once(&timer);
}
/***********************************************************/ /***********************************************************/
/* savevm/loadvm support */ /* savevm/loadvm support */
@ -1765,13 +1698,14 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
{ {
Error *local_err = NULL; Error *local_err = NULL;
HandleRunBhData *data = opaque; HandleRunBhData *data = opaque;
MigrationIncomingState *mis = migration_incoming_get_current();
/* TODO we should move all of this lot into postcopy_ram.c or a shared code /* TODO we should move all of this lot into postcopy_ram.c or a shared code
* in migration.c * in migration.c
*/ */
cpu_synchronize_all_post_init(); cpu_synchronize_all_post_init();
qemu_announce_self(); qemu_announce_self(&mis->announce_timer, migrate_announce_params());
/* Make sure all file formats flush their mutable metadata. /* Make sure all file formats flush their mutable metadata.
* If we get an error here, just don't restart the VM yet. */ * If we get an error here, just don't restart the VM yet. */

View File

@ -52,7 +52,6 @@ vmstate_save_state_top(const char *idstr) "%s"
vmstate_subsection_save_loop(const char *name, const char *sub) "%s/%s" vmstate_subsection_save_loop(const char *name, const char *sub) "%s/%s"
vmstate_subsection_save_top(const char *idstr) "%s" vmstate_subsection_save_top(const char *idstr) "%s"
vmstate_load(const char *idstr, const char *vmsd_name) "%s, %s" vmstate_load(const char *idstr, const char *vmsd_name) "%s, %s"
qemu_announce_self_iter(const char *mac) "%s"
# migration/vmstate.c # migration/vmstate.c
vmstate_load_field_error(const char *field, int ret) "field \"%s\" load failed, ret = %d" vmstate_load_field_error(const char *field, int ret) "field \"%s\" load failed, ret = %d"

View File

@ -2,6 +2,7 @@ common-obj-y = net.o queue.o checksum.o util.o hub.o
common-obj-y += socket.o common-obj-y += socket.o
common-obj-y += dump.o common-obj-y += dump.o
common-obj-y += eth.o common-obj-y += eth.o
common-obj-y += announce.o
common-obj-$(CONFIG_L2TPV3) += l2tpv3.o common-obj-$(CONFIG_L2TPV3) += l2tpv3.o
common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o
common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o

140
net/announce.c Normal file
View File

@ -0,0 +1,140 @@
/*
* Self-announce
* (c) 2017-2019 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "net/announce.h"
#include "net/net.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-net.h"
#include "qapi/qapi-commands-net.h"
#include "trace.h"
int64_t qemu_announce_timer_step(AnnounceTimer *timer)
{
int64_t step;
step = timer->params.initial +
(timer->params.rounds - timer->round - 1) *
timer->params.step;
if (step < 0 || step > timer->params.max) {
step = timer->params.max;
}
timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
return step;
}
void qemu_announce_timer_del(AnnounceTimer *timer)
{
if (timer->tm) {
timer_del(timer->tm);
timer_free(timer->tm);
timer->tm = NULL;
}
}
/*
* Under BQL/main thread
* Reset the timer to the given parameters/type/notifier.
*/
void qemu_announce_timer_reset(AnnounceTimer *timer,
AnnounceParameters *params,
QEMUClockType type,
QEMUTimerCB *cb,
void *opaque)
{
/*
* We're under the BQL, so the current timer can't
* be firing, so we should be able to delete it.
*/
qemu_announce_timer_del(timer);
QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
timer->round = params->rounds;
timer->type = type;
timer->tm = timer_new_ms(type, cb, opaque);
}
#ifndef ETH_P_RARP
#define ETH_P_RARP 0x8035
#endif
#define ARP_HTYPE_ETH 0x0001
#define ARP_PTYPE_IP 0x0800
#define ARP_OP_REQUEST_REV 0x3
static int announce_self_create(uint8_t *buf,
uint8_t *mac_addr)
{
/* Ethernet header. */
memset(buf, 0xff, 6); /* destination MAC addr */
memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
*(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
/* RARP header. */
*(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
*(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
*(buf + 18) = 6; /* hardware addr length (ethernet) */
*(buf + 19) = 4; /* protocol addr length (IPv4) */
*(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
memcpy(buf + 22, mac_addr, 6); /* source hw addr */
memset(buf + 28, 0x00, 4); /* source protocol addr */
memcpy(buf + 32, mac_addr, 6); /* target hw addr */
memset(buf + 38, 0x00, 4); /* target protocol addr */
/* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
memset(buf + 42, 0x00, 18);
return 60; /* len (FCS will be added by hardware) */
}
static void qemu_announce_self_iter(NICState *nic, void *opaque)
{
uint8_t buf[60];
int len;
trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
len = announce_self_create(buf, nic->conf->macaddr.a);
qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
/* if the NIC provides it's own announcement support, use it as well */
if (nic->ncs->info->announce) {
nic->ncs->info->announce(nic->ncs);
}
}
static void qemu_announce_self_once(void *opaque)
{
AnnounceTimer *timer = (AnnounceTimer *)opaque;
qemu_foreach_nic(qemu_announce_self_iter, NULL);
if (--timer->round) {
qemu_announce_timer_step(timer);
} else {
qemu_announce_timer_del(timer);
}
}
void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
{
qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
qemu_announce_self_once, timer);
if (params->rounds) {
qemu_announce_self_once(timer);
} else {
qemu_announce_timer_del(timer);
}
}
void qmp_announce_self(AnnounceParameters *params, Error **errp)
{
static AnnounceTimer announce_timer;
qemu_announce_self(&announce_timer, params);
}

View File

@ -286,14 +286,6 @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
{ {
*mark = 0; *mark = 0;
if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
if (colo_compare_packet_payload(ppkt, spkt,
ppkt->header_size, spkt->header_size,
ppkt->payload_size)) {
*mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
return true;
}
}
if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) { if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
if (colo_compare_packet_payload(ppkt, spkt, if (colo_compare_packet_payload(ppkt, spkt,
ppkt->header_size, spkt->header_size, ppkt->header_size, spkt->header_size,

View File

@ -154,65 +154,27 @@ static void netmap_writable(void *opaque)
qemu_flush_queued_packets(&s->nc); qemu_flush_queued_packets(&s->nc);
} }
static ssize_t netmap_receive(NetClientState *nc,
const uint8_t *buf, size_t size)
{
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
struct netmap_ring *ring = s->tx;
uint32_t i;
uint32_t idx;
uint8_t *dst;
if (unlikely(!ring)) {
/* Drop. */
return size;
}
if (unlikely(size > ring->nr_buf_size)) {
RD(5, "[netmap_receive] drop packet of size %d > %d\n",
(int)size, ring->nr_buf_size);
return size;
}
if (nm_ring_empty(ring)) {
/* No available slots in the netmap TX ring. */
netmap_write_poll(s, true);
return 0;
}
i = ring->cur;
idx = ring->slot[i].buf_idx;
dst = (uint8_t *)NETMAP_BUF(ring, idx);
ring->slot[i].len = size;
ring->slot[i].flags = 0;
pkt_copy(buf, dst, size);
ring->cur = ring->head = nm_ring_next(ring, i);
ioctl(s->nmd->fd, NIOCTXSYNC, NULL);
return size;
}
static ssize_t netmap_receive_iov(NetClientState *nc, static ssize_t netmap_receive_iov(NetClientState *nc,
const struct iovec *iov, int iovcnt) const struct iovec *iov, int iovcnt)
{ {
NetmapState *s = DO_UPCAST(NetmapState, nc, nc); NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
struct netmap_ring *ring = s->tx; struct netmap_ring *ring = s->tx;
unsigned int tail = ring->tail;
ssize_t totlen = 0;
uint32_t last; uint32_t last;
uint32_t idx; uint32_t idx;
uint8_t *dst; uint8_t *dst;
int j; int j;
uint32_t i; uint32_t i;
if (unlikely(!ring)) { last = i = ring->head;
/* Drop the packet. */
return iov_size(iov, iovcnt);
}
last = i = ring->cur;
if (nm_ring_space(ring) < iovcnt) { if (nm_ring_space(ring) < iovcnt) {
/* Not enough netmap slots. */ /* Not enough netmap slots. Tell the kernel that we have seen the new
* available slots (so that it notifies us again when it has more
* ones), but without publishing any new slots to be processed
* (e.g., we don't advance ring->head). */
ring->cur = tail;
netmap_write_poll(s, true); netmap_write_poll(s, true);
return 0; return 0;
} }
@ -222,14 +184,17 @@ static ssize_t netmap_receive_iov(NetClientState *nc,
int offset = 0; int offset = 0;
int nm_frag_size; int nm_frag_size;
totlen += iov_frag_size;
/* Split each iovec fragment over more netmap slots, if /* Split each iovec fragment over more netmap slots, if
necessary. */ necessary. */
while (iov_frag_size) { while (iov_frag_size) {
nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size); nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size);
if (unlikely(nm_ring_empty(ring))) { if (unlikely(i == tail)) {
/* We run out of netmap slots while splitting the /* We ran out of netmap slots while splitting the
iovec fragments. */ iovec fragments. */
ring->cur = tail;
netmap_write_poll(s, true); netmap_write_poll(s, true);
return 0; return 0;
} }
@ -251,12 +216,24 @@ static ssize_t netmap_receive_iov(NetClientState *nc,
/* The last slot must not have NS_MOREFRAG set. */ /* The last slot must not have NS_MOREFRAG set. */
ring->slot[last].flags &= ~NS_MOREFRAG; ring->slot[last].flags &= ~NS_MOREFRAG;
/* Now update ring->cur and ring->head. */ /* Now update ring->head and ring->cur to publish the new slots and
ring->cur = ring->head = i; * the new wakeup point. */
ring->head = ring->cur = i;
ioctl(s->nmd->fd, NIOCTXSYNC, NULL); ioctl(s->nmd->fd, NIOCTXSYNC, NULL);
return iov_size(iov, iovcnt); return totlen;
}
static ssize_t netmap_receive(NetClientState *nc,
const uint8_t *buf, size_t size)
{
struct iovec iov;
iov.iov_base = (void *)buf;
iov.iov_len = size;
return netmap_receive_iov(nc, &iov, 1);
} }
/* Complete a previous send (backend --> guest) and enable the /* Complete a previous send (backend --> guest) and enable the
@ -272,39 +249,46 @@ static void netmap_send(void *opaque)
{ {
NetmapState *s = opaque; NetmapState *s = opaque;
struct netmap_ring *ring = s->rx; struct netmap_ring *ring = s->rx;
unsigned int tail = ring->tail;
/* Keep sending while there are available packets into the netmap /* Keep sending while there are available slots in the netmap
RX ring and the forwarding path towards the peer is open. */ RX ring and the forwarding path towards the peer is open. */
while (!nm_ring_empty(ring)) { while (ring->head != tail) {
uint32_t i; uint32_t i = ring->head;
uint32_t idx; uint32_t idx;
bool morefrag; bool morefrag;
int iovcnt = 0; int iovcnt = 0;
int iovsize; int iovsize;
/* Get a (possibly multi-slot) packet. */
do { do {
i = ring->cur;
idx = ring->slot[i].buf_idx; idx = ring->slot[i].buf_idx;
morefrag = (ring->slot[i].flags & NS_MOREFRAG); morefrag = (ring->slot[i].flags & NS_MOREFRAG);
s->iov[iovcnt].iov_base = (u_char *)NETMAP_BUF(ring, idx); s->iov[iovcnt].iov_base = (void *)NETMAP_BUF(ring, idx);
s->iov[iovcnt].iov_len = ring->slot[i].len; s->iov[iovcnt].iov_len = ring->slot[i].len;
iovcnt++; iovcnt++;
i = nm_ring_next(ring, i);
} while (i != tail && morefrag);
ring->cur = ring->head = nm_ring_next(ring, i); /* Advance ring->cur to tell the kernel that we have seen the slots. */
} while (!nm_ring_empty(ring) && morefrag); ring->cur = i;
if (unlikely(nm_ring_empty(ring) && morefrag)) { if (unlikely(morefrag)) {
RD(5, "[netmap_send] ran out of slots, with a pending" /* This is a truncated packet, so we can stop without releasing the
"incomplete packet\n"); * incomplete slots by updating ring->head. We will hopefully
* re-read the complete packet the next time we are called. */
break;
} }
iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt,
netmap_send_completed); netmap_send_completed);
/* Release the slots to the kernel. */
ring->head = i;
if (iovsize == 0) { if (iovsize == 0) {
/* The peer does not receive anymore. Packet is queued, stop /* The peer does not receive anymore. Packet is queued, stop
* reading from the backend until netmap_send_completed() * reading from the backend until netmap_send_completed(). */
*/
netmap_read_poll(s, false); netmap_read_poll(s, false);
break; break;
} }

View File

@ -1,5 +1,8 @@
# See docs/devel/tracing.txt for syntax documentation. # See docs/devel/tracing.txt for syntax documentation.
# net/announce.c
qemu_announce_self_iter(const char *mac) "%s"
# net/vhost-user.c # net/vhost-user.c
vhost_user_event(const char *chr, int event) "chr: %s got event: %d" vhost_user_event(const char *chr, int event) "chr: %s got event: %d"

View File

@ -480,6 +480,18 @@
# #
# Migration parameters enumeration # Migration parameters enumeration
# #
# @announce-initial: Initial delay (in milliseconds) before sending the first
# announce (Since 4.0)
#
# @announce-max: Maximum delay (in milliseconds) between packets in the
# announcement (Since 4.0)
#
# @announce-rounds: Number of self-announce packets sent after migration
# (Since 4.0)
#
# @announce-step: Increase in delay (in milliseconds) between subsequent
# packets in the announcement (Since 4.0)
#
# @compress-level: Set the compression level to be used in live migration, # @compress-level: Set the compression level to be used in live migration,
# the compression level is an integer between 0 and 9, where 0 means # the compression level is an integer between 0 and 9, where 0 means
# no compression, 1 means the best compression speed, and 9 means best # no compression, 1 means the best compression speed, and 9 means best
@ -557,10 +569,13 @@
# #
# @max-cpu-throttle: maximum cpu throttle percentage. # @max-cpu-throttle: maximum cpu throttle percentage.
# Defaults to 99. (Since 3.1) # Defaults to 99. (Since 3.1)
#
# Since: 2.4 # Since: 2.4
## ##
{ 'enum': 'MigrationParameter', { 'enum': 'MigrationParameter',
'data': ['compress-level', 'compress-threads', 'decompress-threads', 'data': ['announce-initial', 'announce-max',
'announce-rounds', 'announce-step',
'compress-level', 'compress-threads', 'decompress-threads',
'compress-wait-thread', 'compress-wait-thread',
'cpu-throttle-initial', 'cpu-throttle-increment', 'cpu-throttle-initial', 'cpu-throttle-increment',
'tls-creds', 'tls-hostname', 'max-bandwidth', 'tls-creds', 'tls-hostname', 'max-bandwidth',
@ -572,6 +587,18 @@
## ##
# @MigrateSetParameters: # @MigrateSetParameters:
# #
# @announce-initial: Initial delay (in milliseconds) before sending the first
# announce (Since 4.0)
#
# @announce-max: Maximum delay (in milliseconds) between packets in the
# announcement (Since 4.0)
#
# @announce-rounds: Number of self-announce packets sent after migration
# (Since 4.0)
#
# @announce-step: Increase in delay (in milliseconds) between subsequent
# packets in the announcement (Since 4.0)
#
# @compress-level: compression level # @compress-level: compression level
# #
# @compress-threads: compression thread count # @compress-threads: compression thread count
@ -653,7 +680,11 @@
# TODO either fuse back into MigrationParameters, or make # TODO either fuse back into MigrationParameters, or make
# MigrationParameters members mandatory # MigrationParameters members mandatory
{ 'struct': 'MigrateSetParameters', { 'struct': 'MigrateSetParameters',
'data': { '*compress-level': 'int', 'data': { '*announce-initial': 'size',
'*announce-max': 'size',
'*announce-rounds': 'size',
'*announce-step': 'size',
'*compress-level': 'int',
'*compress-threads': 'int', '*compress-threads': 'int',
'*compress-wait-thread': 'bool', '*compress-wait-thread': 'bool',
'*decompress-threads': 'int', '*decompress-threads': 'int',
@ -692,6 +723,18 @@
# #
# The optional members aren't actually optional. # The optional members aren't actually optional.
# #
# @announce-initial: Initial delay (in milliseconds) before sending the
# first announce (Since 4.0)
#
# @announce-max: Maximum delay (in milliseconds) between packets in the
# announcement (Since 4.0)
#
# @announce-rounds: Number of self-announce packets sent after migration
# (Since 4.0)
#
# @announce-step: Increase in delay (in milliseconds) between subsequent
# packets in the announcement (Since 4.0)
#
# @compress-level: compression level # @compress-level: compression level
# #
# @compress-threads: compression thread count # @compress-threads: compression thread count
@ -769,7 +812,11 @@
# Since: 2.4 # Since: 2.4
## ##
{ 'struct': 'MigrationParameters', { 'struct': 'MigrationParameters',
'data': { '*compress-level': 'uint8', 'data': { '*announce-initial': 'size',
'*announce-max': 'size',
'*announce-rounds': 'size',
'*announce-step': 'size',
'*compress-level': 'uint8',
'*compress-threads': 'uint8', '*compress-threads': 'uint8',
'*compress-wait-thread': 'bool', '*compress-wait-thread': 'bool',
'*decompress-threads': 'uint8', '*decompress-threads': 'uint8',

View File

@ -684,3 +684,46 @@
## ##
{ 'event': 'NIC_RX_FILTER_CHANGED', { 'event': 'NIC_RX_FILTER_CHANGED',
'data': { '*name': 'str', 'path': 'str' } } 'data': { '*name': 'str', 'path': 'str' } }
##
# @AnnounceParameters:
#
# Parameters for self-announce timers
#
# @initial: Initial delay (in ms) before sending the first GARP/RARP
# announcement
#
# @max: Maximum delay (in ms) between GARP/RARP announcement packets
#
# @rounds: Number of self-announcement attempts
#
# @step: Delay increase (in ms) after each self-announcement attempt
#
# Since: 4.0
##
{ 'struct': 'AnnounceParameters',
'data': { 'initial': 'int',
'max': 'int',
'rounds': 'int',
'step': 'int' } }
##
# @announce-self:
#
# Trigger generation of broadcast RARP frames to update network switches.
# This can be useful when network bonds fail-over the active slave.
#
# @params: AnnounceParameters giving timing and repetition count of announce
#
# Example:
#
# -> { "execute": "announce-self"
# "arguments": {
# "initial": 50, "max": 550, "rounds": 10, "step": 50 } }
# <- { "return": {} }
#
# Since: 4.0
##
{ 'command': 'announce-self', 'boxed': true,
'data' : 'AnnounceParameters'}

View File

@ -225,6 +225,7 @@ check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF)
check-qtest-i386-y += tests/migration-test$(EXESUF) check-qtest-i386-y += tests/migration-test$(EXESUF)
check-qtest-i386-y += tests/test-announce-self$(EXESUF)
check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF)
check-qtest-i386-y += tests/numa-test$(EXESUF) check-qtest-i386-y += tests/numa-test$(EXESUF)
check-qtest-x86_64-y += $(check-qtest-i386-y) check-qtest-x86_64-y += $(check-qtest-i386-y)
@ -263,6 +264,7 @@ check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF)
check-qtest-ppc64-y += tests/migration-test$(EXESUF) check-qtest-ppc64-y += tests/migration-test$(EXESUF)
check-qtest-ppc64-y += tests/test-announce-self$(EXESUF)
check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF) check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
@ -779,6 +781,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o
tests/migration-test$(EXESUF): tests/migration-test.o tests/migration-test$(EXESUF): tests/migration-test.o
tests/test-announce-self$(EXESUF): tests/test-announce-self.o
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \
$(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) \ $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) \
$(chardev-obj-y) $(chardev-obj-y)

View File

@ -0,0 +1,82 @@
/*
* QTest testcase for qemu_announce_self
*
* Copyright (c) 2017 Red hat, Inc.
* Copyright (c) 2014 SUSE LINUX Products GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#include "qapi/qmp/qdict.h"
#include "qemu-common.h"
#include "qemu/sockets.h"
#include "qemu/iov.h"
#include "libqos/libqos-pc.h"
#include "libqos/libqos-spapr.h"
#ifndef ETH_P_RARP
#define ETH_P_RARP 0x8035
#endif
static QTestState *test_init(int socket)
{
char *args;
args = g_strdup_printf("-netdev socket,fd=%d,id=hs0 -device "
"virtio-net-pci,netdev=hs0", socket);
return qtest_start(args);
}
static void test_announce(int socket)
{
char buffer[60];
int len;
QDict *rsp;
int ret;
uint16_t *proto = (uint16_t *)&buffer[12];
rsp = qmp("{ 'execute' : 'announce-self', "
" 'arguments': {"
" 'initial': 50, 'max': 550,"
" 'rounds': 10, 'step': 50 } }");
assert(!qdict_haskey(rsp, "error"));
qobject_unref(rsp);
/* Catch the packet and make sure it's a RARP */
ret = qemu_recv(socket, &len, sizeof(len), 0);
g_assert_cmpint(ret, ==, sizeof(len));
len = ntohl(len);
ret = qemu_recv(socket, buffer, len, 0);
g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
}
static void setup(gconstpointer data)
{
QTestState *qs;
void (*func) (int socket) = data;
int sv[2], ret;
ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
g_assert_cmpint(ret, !=, -1);
qs = test_init(sv[1]);
func(sv[0]);
/* End test */
close(sv[0]);
qtest_quit(qs);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/virtio/net/test_announce_self", test_announce, setup);
return g_test_run();
}

View File

@ -20,6 +20,7 @@
static int verbose; static int verbose;
static const char *hmp_cmds[] = { static const char *hmp_cmds[] = {
"announce_self",
"boot_set ndc", "boot_set ndc",
"chardev-add null,id=testchardev1", "chardev-add null,id=testchardev1",
"chardev-send-break testchardev1", "chardev-send-break testchardev1",