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

Version: GnuPG v1
 
 iQEcBAABAgAGBQJdGr/CAAoJEO8Ells5jWIRJY4H/10pMuRX11WDSQqc/ejQMywj
 3v+CBFTaNnCvbPqEFKH6p/1Y1KV/G1+ODzuat71QVjHqzlX/tCcLtNVrzIsozal+
 R42PADVpBuOGYC9CBBKZxKpORm4YEOApwERKAmjoTDKJUbho1TOOt60Vz7ctlybb
 nlEDdNogSKZ7ZxSj/Nn5NvaZnQPpS3ZpFcqMwr1ofQtCuUsYi9DNREd+NLwaknZS
 O3ib6nAFxBH4dpA0bSKWJHZi8QU1GcIdvs0iDeSnzvlCgwjbv3pM6eYkse90jXq+
 Sq0ZxSMb+97CCu54b5wu8EqOhzBaasVcKApR3NRQc5vHBI/1WMNB5eFWmfSpzWM=
 =3+Zi
 -----END PGP SIGNATURE-----

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

# gpg: Signature made Tue 02 Jul 2019 03:21:54 BST
# 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:
  migration/colo.c: Add missed filter notify for Xen COLO.
  COLO-compare: Add colo-compare remote notify support
  COLO-compare: Make the compare_chr_send() can send notification message.
  COLO-compare: Add remote notification chardev handler frame
  COLO-compare: Add new parameter to communicate with remote colo-frame
  net/announce: Expand test for stopping self announce
  net/announce: Add HMP optional ID
  net/announce: Add optional ID
  net/announce: Add HMP optional interface list
  net/announce: Allow optional list of interfaces
  net: remove unused get_str_sep() function
  net: use g_strsplit() for parsing host address and port
  net: avoid using variable length array in net_client_init()
  net: fix assertion failure when ipv6-prefixlen is not a number
  ftgmac100: do not link to netdev
  qemu-bridge-helper: Document known shortcomings
  MAINTAINERS: Add qemu-bridge-helper.c to "Network device backends"

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2019-07-02 16:41:28 +01:00
commit 8ef53cdb50
15 changed files with 430 additions and 99 deletions

View File

@ -1944,6 +1944,7 @@ M: Jason Wang <jasowang@redhat.com>
S: Maintained
F: net/
F: include/net/
F: qemu-bridge-helper.c
T: git https://github.com/jasowang/qemu.git net
F: qapi/net.json

View File

@ -955,8 +955,8 @@ ETEXI
{
.name = "announce_self",
.args_type = "",
.params = "",
.args_type = "interfaces:s?,id:s?",
.params = "[interfaces] [id]",
.help = "Trigger GARP/RARP announcements",
.cmd = hmp_announce_self,
},
@ -967,6 +967,9 @@ STEXI
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.
An optional comma separated @var{interfaces} list restricts the announce to the
named set of interfaces. An optional @var{id} can be used to start a separate announce
timer and to change the parameters of it later.
ETEXI
{

View File

@ -1017,8 +1017,6 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->conf.peers.ncs[0] = nd_table[0].netdev;
s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf,
object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
s);

View File

@ -2360,7 +2360,7 @@ static int virtio_net_post_load_device(void *opaque, int version_id)
timer_mod(n->announce_timer.tm,
qemu_clock_get_ms(n->announce_timer.type));
} else {
qemu_announce_timer_del(&n->announce_timer);
qemu_announce_timer_del(&n->announce_timer, false);
}
}
@ -2784,7 +2784,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
virtio_net_del_queue(n, i);
}
qemu_announce_timer_del(&n->announce_timer);
qemu_announce_timer_del(&n->announce_timer, false);
g_free(n->vqs);
qemu_del_nic(n->nic);
virtio_net_rsc_cleanup(n);

View File

@ -22,8 +22,12 @@ struct AnnounceTimer {
/* 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);
/*
* Delete the underlying timer and other data
* If 'free_named' true and the timer is a named timer, then remove
* it from the list of named timers and free the AnnounceTimer itself.
*/
void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named);
/*
* Under BQL/main thread

View File

@ -259,6 +259,8 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
void qmp_xen_colo_do_checkpoint(Error **errp)
{
replication_do_checkpoint_all(errp);
/* Notify all filters of all NIC to do checkpoint */
colo_notify_filters_event(COLO_EVENT_CHECKPOINT, errp);
}
#endif

View File

@ -27,6 +27,7 @@
#include "monitor/monitor-internal.h"
#include "monitor/qdev.h"
#include "qapi/error.h"
#include "qapi/clone-visitor.h"
#include "qapi/opts-visitor.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-block.h"
@ -38,6 +39,7 @@
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-commands-tpm.h"
#include "qapi/qapi-commands-ui.h"
#include "qapi/qapi-visit-net.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/string-input-visitor.h"
@ -67,6 +69,32 @@ static void hmp_handle_error(Monitor *mon, Error **errp)
}
}
/*
* Produce a strList from a comma separated list.
* A NULL or empty input string return NULL.
*/
static strList *strList_from_comma_list(const char *in)
{
strList *res = NULL;
strList **hook = &res;
while (in && in[0]) {
char *comma = strchr(in, ',');
*hook = g_new0(strList, 1);
if (comma) {
(*hook)->value = g_strndup(in, comma - in);
in = comma + 1; /* skip the , */
} else {
(*hook)->value = g_strdup(in);
in = NULL;
}
hook = &(*hook)->next;
}
return res;
}
void hmp_info_name(Monitor *mon, const QDict *qdict)
{
NameInfo *info;
@ -1631,7 +1659,18 @@ 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);
const char *interfaces_str = qdict_get_try_str(qdict, "interfaces");
const char *id = qdict_get_try_str(qdict, "id");
AnnounceParameters *params = QAPI_CLONE(AnnounceParameters,
migrate_announce_params());
qapi_free_strList(params->interfaces);
params->interfaces = strList_from_comma_list(interfaces_str);
params->has_interfaces = params->interfaces != NULL;
params->id = g_strdup(id);
params->has_id = !!params->id;
qmp_announce_self(params, NULL);
qapi_free_AnnounceParameters(params);
}
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)

View File

@ -15,6 +15,8 @@
#include "qapi/qapi-commands-net.h"
#include "trace.h"
static GData *named_timers;
int64_t qemu_announce_timer_step(AnnounceTimer *timer)
{
int64_t step;
@ -31,13 +33,38 @@ int64_t qemu_announce_timer_step(AnnounceTimer *timer)
return step;
}
void qemu_announce_timer_del(AnnounceTimer *timer)
/*
* If 'free_named' is true, then remove the timer from the list
* and free the timer itself.
*/
void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
{
bool free_timer = false;
if (timer->tm) {
timer_del(timer->tm);
timer_free(timer->tm);
timer->tm = NULL;
}
qapi_free_strList(timer->params.interfaces);
timer->params.interfaces = NULL;
if (free_named && timer->params.has_id) {
AnnounceTimer *list_timer;
/*
* Sanity check: There should only be one timer on the list with
* the id.
*/
list_timer = g_datalist_get_data(&named_timers, timer->params.id);
assert(timer == list_timer);
free_timer = true;
g_datalist_remove_data(&named_timers, timer->params.id);
}
trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id);
g_free(timer->params.id);
timer->params.id = NULL;
if (free_timer) {
g_free(timer);
}
}
/*
@ -54,7 +81,7 @@ void qemu_announce_timer_reset(AnnounceTimer *timer,
* 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);
qemu_announce_timer_del(timer, false);
QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
timer->round = params->rounds;
@ -96,29 +123,53 @@ static int announce_self_create(uint8_t *buf,
static void qemu_announce_self_iter(NICState *nic, void *opaque)
{
AnnounceTimer *timer = opaque;
uint8_t buf[60];
int len;
bool skip;
trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
len = announce_self_create(buf, nic->conf->macaddr.a);
if (timer->params.has_interfaces) {
strList *entry = timer->params.interfaces;
/* Skip unless we find our name in the requested list */
skip = true;
qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
while (entry) {
if (!strcmp(entry->value, nic->ncs->name)) {
/* Found us */
skip = false;
break;
}
entry = entry->next;
}
} else {
skip = false;
}
/* if the NIC provides it's own announcement support, use it as well */
if (nic->ncs->info->announce) {
nic->ncs->info->announce(nic->ncs);
trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
nic->ncs->name,
qemu_ether_ntoa(&nic->conf->macaddr), skip);
if (!skip) {
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);
qemu_foreach_nic(qemu_announce_self_iter, timer);
if (--timer->round) {
qemu_announce_timer_step(timer);
} else {
qemu_announce_timer_del(timer);
qemu_announce_timer_del(timer, true);
}
}
@ -129,12 +180,24 @@ void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
if (params->rounds) {
qemu_announce_self_once(timer);
} else {
qemu_announce_timer_del(timer);
qemu_announce_timer_del(timer, true);
}
}
void qmp_announce_self(AnnounceParameters *params, Error **errp)
{
static AnnounceTimer announce_timer;
qemu_announce_self(&announce_timer, params);
AnnounceTimer *named_timer;
if (!params->has_id) {
params->id = g_strdup("");
params->has_id = true;
}
named_timer = g_datalist_get_data(&named_timers, params->id);
if (!named_timer) {
named_timer = g_new0(AnnounceTimer, 1);
g_datalist_set_data(&named_timers, params->id, named_timer);
}
qemu_announce_self(named_timer, params);
}

View File

@ -83,11 +83,14 @@ typedef struct CompareState {
char *pri_indev;
char *sec_indev;
char *outdev;
char *notify_dev;
CharBackend chr_pri_in;
CharBackend chr_sec_in;
CharBackend chr_out;
CharBackend chr_notify_dev;
SocketReadState pri_rs;
SocketReadState sec_rs;
SocketReadState notify_rs;
bool vnet_hdr;
/*
@ -117,16 +120,33 @@ enum {
SECONDARY_IN,
};
static void colo_compare_inconsistency_notify(void)
{
notifier_list_notify(&colo_compare_notifiers,
migrate_get_current());
}
static int compare_chr_send(CompareState *s,
const uint8_t *buf,
uint32_t size,
uint32_t vnet_hdr_len);
uint32_t vnet_hdr_len,
bool notify_remote_frame);
static void notify_remote_frame(CompareState *s)
{
char msg[] = "DO_CHECKPOINT";
int ret = 0;
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
if (ret < 0) {
error_report("Notify Xen COLO-frame failed");
}
}
static void colo_compare_inconsistency_notify(CompareState *s)
{
if (s->notify_dev) {
notify_remote_frame(s);
} else {
notifier_list_notify(&colo_compare_notifiers,
migrate_get_current());
}
}
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
@ -238,7 +258,8 @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
ret = compare_chr_send(s,
pkt->data,
pkt->size,
pkt->vnet_hdr_len);
pkt->vnet_hdr_len,
false);
if (ret < 0) {
error_report("colo send primary packet failed");
}
@ -430,7 +451,7 @@ sec:
qemu_hexdump((char *)spkt->data, stderr,
"colo-compare spkt", spkt->size);
colo_compare_inconsistency_notify();
colo_compare_inconsistency_notify(s);
}
}
@ -572,7 +593,7 @@ void colo_compare_unregister_notifier(Notifier *notify)
}
static int colo_old_packet_check_one_conn(Connection *conn,
void *user_data)
CompareState *s)
{
GList *result = NULL;
int64_t check_time = REGULAR_PACKET_CHECK_MS;
@ -583,7 +604,7 @@ static int colo_old_packet_check_one_conn(Connection *conn,
if (result) {
/* Do checkpoint will flush old packet */
colo_compare_inconsistency_notify();
colo_compare_inconsistency_notify(s);
return 0;
}
@ -603,7 +624,7 @@ static void colo_old_packet_check(void *opaque)
* If we find one old packet, stop finding job and notify
* COLO frame do checkpoint.
*/
g_queue_find_custom(&s->conn_list, NULL,
g_queue_find_custom(&s->conn_list, s,
(GCompareFunc)colo_old_packet_check_one_conn);
}
@ -632,7 +653,8 @@ static void colo_compare_packet(CompareState *s, Connection *conn,
*/
trace_colo_compare_main("packet different");
g_queue_push_head(&conn->primary_list, pkt);
colo_compare_inconsistency_notify();
colo_compare_inconsistency_notify(s);
break;
}
}
@ -668,7 +690,8 @@ static void colo_compare_connection(void *opaque, void *user_data)
static int compare_chr_send(CompareState *s,
const uint8_t *buf,
uint32_t size,
uint32_t vnet_hdr_len)
uint32_t vnet_hdr_len,
bool notify_remote_frame)
{
int ret = 0;
uint32_t len = htonl(size);
@ -677,7 +700,14 @@ static int compare_chr_send(CompareState *s,
return 0;
}
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
if (notify_remote_frame) {
ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
(uint8_t *)&len,
sizeof(len));
} else {
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
}
if (ret != sizeof(len)) {
goto err;
}
@ -688,13 +718,26 @@ static int compare_chr_send(CompareState *s,
* know how to parse net packet correctly.
*/
len = htonl(vnet_hdr_len);
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
if (!notify_remote_frame) {
ret = qemu_chr_fe_write_all(&s->chr_out,
(uint8_t *)&len,
sizeof(len));
}
if (ret != sizeof(len)) {
goto err;
}
}
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
if (notify_remote_frame) {
ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
(uint8_t *)buf,
size);
} else {
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
}
if (ret != size) {
goto err;
}
@ -744,6 +787,19 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
}
}
static void compare_notify_chr(void *opaque, const uint8_t *buf, int size)
{
CompareState *s = COLO_COMPARE(opaque);
int ret;
ret = net_fill_rstate(&s->notify_rs, buf, size);
if (ret == -1) {
qemu_chr_fe_set_handlers(&s->chr_notify_dev, NULL, NULL, NULL, NULL,
NULL, NULL, true);
error_report("colo-compare notify_dev error");
}
}
/*
* Check old packet regularly so it can watch for any packets
* that the secondary hasn't produced equivalents of.
@ -831,6 +887,11 @@ static void colo_compare_iothread(CompareState *s)
qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
compare_sec_chr_in, NULL, NULL,
s, s->worker_context, true);
if (s->notify_dev) {
qemu_chr_fe_set_handlers(&s->chr_notify_dev, compare_chr_can_read,
compare_notify_chr, NULL, NULL,
s, s->worker_context, true);
}
colo_compare_timer_init(s);
s->event_bh = qemu_bh_new(colo_compare_handle_event, s);
@ -897,6 +958,21 @@ static void compare_set_vnet_hdr(Object *obj,
s->vnet_hdr = value;
}
static char *compare_get_notify_dev(Object *obj, Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
return g_strdup(s->notify_dev);
}
static void compare_set_notify_dev(Object *obj, const char *value, Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
g_free(s->notify_dev);
s->notify_dev = g_strdup(value);
}
static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{
CompareState *s = container_of(pri_rs, CompareState, pri_rs);
@ -907,7 +983,8 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
compare_chr_send(s,
pri_rs->buf,
pri_rs->packet_len,
pri_rs->vnet_hdr_len);
pri_rs->vnet_hdr_len,
false);
} else {
/* compare packet in the specified connection */
colo_compare_connection(conn, s);
@ -927,6 +1004,27 @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs)
}
}
static void compare_notify_rs_finalize(SocketReadState *notify_rs)
{
CompareState *s = container_of(notify_rs, CompareState, notify_rs);
/* Get Xen colo-frame's notify and handle the message */
char *data = g_memdup(notify_rs->buf, notify_rs->packet_len);
char msg[] = "COLO_COMPARE_GET_XEN_INIT";
int ret;
if (!strcmp(data, "COLO_USERSPACE_PROXY_INIT")) {
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
if (ret < 0) {
error_report("Notify Xen COLO-frame INIT failed");
}
}
if (!strcmp(data, "COLO_CHECKPOINT")) {
/* colo-compare do checkpoint, flush pri packet and remove sec packet */
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
}
}
/*
* Return 0 is success.
@ -997,6 +1095,17 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr);
net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr);
/* Try to enable remote notify chardev, currently just for Xen COLO */
if (s->notify_dev) {
if (find_and_check_chardev(&chr, s->notify_dev, errp) ||
!qemu_chr_fe_init(&s->chr_notify_dev, chr, errp)) {
return;
}
net_socket_rs_init(&s->notify_rs, compare_notify_rs_finalize,
s->vnet_hdr);
}
QTAILQ_INSERT_TAIL(&net_compares, s, next);
g_queue_init(&s->conn_list);
@ -1024,7 +1133,8 @@ static void colo_flush_packets(void *opaque, void *user_data)
compare_chr_send(s,
pkt->data,
pkt->size,
pkt->vnet_hdr_len);
pkt->vnet_hdr_len,
false);
packet_destroy(pkt, NULL);
}
while (!g_queue_is_empty(&conn->secondary_list)) {
@ -1057,6 +1167,10 @@ static void colo_compare_init(Object *obj)
(Object **)&s->iothread,
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG, NULL);
/* This parameter just for Xen COLO */
object_property_add_str(obj, "notify_dev",
compare_get_notify_dev, compare_set_notify_dev,
NULL);
s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
@ -1071,6 +1185,10 @@ static void colo_compare_finalize(Object *obj)
qemu_chr_fe_deinit(&s->chr_pri_in, false);
qemu_chr_fe_deinit(&s->chr_sec_in, false);
qemu_chr_fe_deinit(&s->chr_out, false);
if (s->notify_dev) {
qemu_chr_fe_deinit(&s->chr_notify_dev, false);
}
if (s->iothread) {
colo_compare_timer_del(s);
}
@ -1103,6 +1221,7 @@ static void colo_compare_finalize(Object *obj)
g_free(s->pri_indev);
g_free(s->sec_indev);
g_free(s->outdev);
g_free(s->notify_dev);
}
static const TypeInfo colo_compare_info = {

View File

@ -64,55 +64,42 @@ static QTAILQ_HEAD(, NetClientState) net_clients;
/***********************************************************/
/* network device redirectors */
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
{
const char *p, *p1;
int len;
p = *pp;
p1 = strchr(p, sep);
if (!p1)
return -1;
len = p1 - p;
p1++;
if (buf_size > 0) {
if (len > buf_size - 1)
len = buf_size - 1;
memcpy(buf, p, len);
buf[len] = '\0';
}
*pp = p1;
return 0;
}
int parse_host_port(struct sockaddr_in *saddr, const char *str,
Error **errp)
{
char buf[512];
gchar **substrings;
struct hostent *he;
const char *p, *r;
int port;
const char *addr, *p, *r;
int port, ret = 0;
p = str;
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
substrings = g_strsplit(str, ":", 2);
if (!substrings || !substrings[0] || !substrings[1]) {
error_setg(errp, "host address '%s' doesn't contain ':' "
"separating host from port", str);
return -1;
ret = -1;
goto out;
}
addr = substrings[0];
p = substrings[1];
saddr->sin_family = AF_INET;
if (buf[0] == '\0') {
if (addr[0] == '\0') {
saddr->sin_addr.s_addr = 0;
} else {
if (qemu_isdigit(buf[0])) {
if (!inet_aton(buf, &saddr->sin_addr)) {
if (qemu_isdigit(addr[0])) {
if (!inet_aton(addr, &saddr->sin_addr)) {
error_setg(errp, "host address '%s' is not a valid "
"IPv4 address", buf);
return -1;
"IPv4 address", addr);
ret = -1;
goto out;
}
} else {
he = gethostbyname(buf);
he = gethostbyname(addr);
if (he == NULL) {
error_setg(errp, "can't resolve host address '%s'", buf);
return - 1;
error_setg(errp, "can't resolve host address '%s'", addr);
ret = -1;
goto out;
}
saddr->sin_addr = *(struct in_addr *)he->h_addr;
}
@ -120,10 +107,14 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str,
port = strtol(p, (char **)&r, 0);
if (r == p) {
error_setg(errp, "port number '%s' is invalid", p);
return -1;
ret = -1;
goto out;
}
saddr->sin_port = htons(port);
return 0;
out:
g_strfreev(substrings);
return ret;
}
char *qemu_mac_strdup_printf(const uint8_t *macaddr)
@ -1105,6 +1096,7 @@ static void show_netdevs(void)
static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
{
gchar **substrings = NULL;
void *object = NULL;
Error *err = NULL;
int ret = -1;
@ -1120,28 +1112,33 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
if (ip6_net) {
char buf[strlen(ip6_net) + 1];
char *prefix_addr;
unsigned long prefix_len = 64; /* Default 64bit prefix length. */
if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
/* Default 64bit prefix length. */
qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort);
qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort);
} else {
substrings = g_strsplit(ip6_net, "/", 2);
if (!substrings || !substrings[0]) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
"a valid IPv6 prefix");
goto out;
}
prefix_addr = substrings[0];
if (substrings[1]) {
/* User-specified prefix length. */
unsigned long len;
int err;
qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort);
err = qemu_strtoul(ip6_net, NULL, 10, &len);
err = qemu_strtoul(substrings[1], NULL, 10, &prefix_len);
if (err) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"ipv6-prefix", "a number");
} else {
qemu_opt_set_number(opts, "ipv6-prefixlen", len,
&error_abort);
"ipv6-prefixlen", "a number");
goto out;
}
}
qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort);
qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len,
&error_abort);
qemu_opt_unset(opts, "ipv6-net");
}
}
@ -1162,7 +1159,9 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
qapi_free_NetLegacy(object);
}
out:
error_propagate(errp, err);
g_strfreev(substrings);
visit_free(v);
return ret;
}

View File

@ -1,7 +1,8 @@
# See docs/devel/tracing.txt for syntax documentation.
# announce.c
qemu_announce_self_iter(const char *mac) "%s"
qemu_announce_self_iter(const char *id, const char *name, const char *mac, int skip) "%s:%s:%s skip: %d"
qemu_announce_timer_del(bool free_named, bool free_timer, char *id) "free named: %d free timer: %d id: %s"
# vhost-user.c
vhost_user_event(const char *chr, int event) "chr: %s got event: %d"

View File

@ -699,6 +699,13 @@
#
# @step: Delay increase (in ms) after each self-announcement attempt
#
# @interfaces: An optional list of interface names, which restricts the
# announcement to the listed interfaces. (Since 4.1)
#
# @id: A name to be used to identify an instance of announce-timers
# and to allow it to modified later. Not for use as
# part of the migration parameters. (Since 4.1)
#
# Since: 4.0
##
@ -706,7 +713,9 @@
'data': { 'initial': 'int',
'max': 'int',
'rounds': 'int',
'step': 'int' } }
'step': 'int',
'*interfaces': ['str'],
'*id' : 'str' } }
##
# @announce-self:
@ -718,9 +727,10 @@
#
# Example:
#
# -> { "execute": "announce-self"
# -> { "execute": "announce-self",
# "arguments": {
# "initial": 50, "max": 550, "rounds": 10, "step": 50 } }
# "initial": 50, "max": 550, "rounds": 10, "step": 50,
# "interfaces": ["vn2", "vn3"], "id": "bob" } }
# <- { "return": {} }
#
# Since: 4.0

View File

@ -10,7 +10,17 @@
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
/*
* Known shortcomings:
* - There is no manual page
* - The syntax of the ACL file is not documented anywhere
* - parse_acl_file() doesn't report fopen() failure properly, fails
* to check ferror() after fgets() failure, arbitrarily truncates
* long lines, handles whitespace inconsistently, error messages
* don't point to the offending file and line, errors in included
* files are reported, but otherwise ignored, ...
*/
#include "qemu/osdep.h"

View File

@ -4477,7 +4477,7 @@ Dump the network traffic on netdev @var{dev} to the file specified by
The file format is libpcap, so it can be analyzed with tools such as tcpdump
or Wireshark.
@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support]
@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support][,notify_dev=@var{id}]
Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with
secondary packet. If the packets are same, we will output primary
@ -4486,11 +4486,15 @@ do checkpoint and send primary packet to outdev@var{chardevid}.
In order to improve efficiency, we need to put the task of comparison
in another thread. If it has the vnet_hdr_support flag, colo compare
will send/recv packet with vnet_hdr_len.
If you want to use Xen COLO, will need the notify_dev to notify Xen
colo-frame to do checkpoint.
we must use it with the help of filter-mirror and filter-redirector.
@example
KVM COLO
primary:
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
@ -4514,6 +4518,33 @@ secondary:
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
Xen COLO
primary:
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait
-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait
-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait
-chardev socket,id=compare0-0,host=3.3.3.3,port=9001
-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait
-chardev socket,id=compare_out0,host=3.3.3.3,port=9005
-chardev socket,id=notify_way,host=3.3.3.3,port=9009,server,nowait
-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0
-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out
-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0
-object iothread,id=iothread1
-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,notify_dev=nofity_way,iothread=iothread1
secondary:
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown
-device e1000,netdev=hn0,mac=52:a4:00:12:78:66
-chardev socket,id=red0,host=3.3.3.3,port=9003
-chardev socket,id=red1,host=3.3.3.3,port=9004
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
@end example
If you want to know the detail of above command line, you can read

View File

@ -184,21 +184,72 @@ static void announce_self(void *obj, void *data, QGuestAllocator *t_alloc)
QDict *rsp;
int ret;
uint16_t *proto = (uint16_t *)&buffer[12];
size_t total_received = 0;
uint64_t start, now, last_rxt, deadline;
/* Send a set of packets over a few second period */
rsp = qmp("{ 'execute' : 'announce-self', "
" 'arguments': {"
" 'initial': 50, 'max': 550,"
" 'rounds': 10, 'step': 50 } }");
" 'initial': 20, 'max': 100,"
" 'rounds': 300, 'step': 10, 'id': 'bob' } }");
assert(!qdict_haskey(rsp, "error"));
qobject_unref(rsp);
/* Catch the packet and make sure it's a RARP */
/* Catch the first packet and make sure it's a RARP */
ret = qemu_recv(sv[0], &len, sizeof(len), 0);
g_assert_cmpint(ret, ==, sizeof(len));
len = ntohl(len);
ret = qemu_recv(sv[0], buffer, len, 0);
g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
/*
* Stop the announcment by settings rounds to 0 on the
* existing timer.
*/
rsp = qmp("{ 'execute' : 'announce-self', "
" 'arguments': {"
" 'initial': 20, 'max': 100,"
" 'rounds': 0, 'step': 10, 'id': 'bob' } }");
assert(!qdict_haskey(rsp, "error"));
qobject_unref(rsp);
/* Now make sure the packets stop */
/* Times are in us */
start = g_get_monotonic_time();
/* 30 packets, max gap 100ms, * 4 for wiggle */
deadline = start + 1000 * (100 * 30 * 4);
last_rxt = start;
while (true) {
int saved_err;
ret = qemu_recv(sv[0], buffer, 60, MSG_DONTWAIT);
saved_err = errno;
now = g_get_monotonic_time();
g_assert_cmpint(now, <, deadline);
if (ret >= 0) {
if (ret) {
last_rxt = now;
}
total_received += ret;
/* Check it's not spewing loads */
g_assert_cmpint(total_received, <, 60 * 30 * 2);
} else {
g_assert_cmpint(saved_err, ==, EAGAIN);
/* 400ms, i.e. 4 worst case gaps */
if ((now - last_rxt) > (1000 * 100 * 4)) {
/* Nothings arrived for a while - must have stopped */
break;
};
/* 100ms */
g_usleep(1000 * 100);
}
};
}
static void virtio_net_test_cleanup(void *sockets)