2 * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
3 * (a.k.a. Fault Tolerance or Continuous Replication)
5 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
6 * Copyright (c) 2016 FUJITSU LIMITED
7 * Copyright (c) 2016 Intel Corporation
9 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
11 * This work is licensed under the terms of the GNU GPL, version 2 or
12 * later. See the COPYING file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include "qemu/error-report.h"
18 #include "qemu-common.h"
19 #include "qapi/qmp/qerror.h"
20 #include "qapi/error.h"
22 #include "qom/object_interfaces.h"
24 #include "qom/object.h"
25 #include "qemu/typedefs.h"
26 #include "net/queue.h"
27 #include "sysemu/char.h"
28 #include "qemu/sockets.h"
29 #include "qapi-visit.h"
32 #define TYPE_COLO_COMPARE "colo-compare"
33 #define COLO_COMPARE(obj) \
34 OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE)
36 #define MAX_QUEUE_SIZE 1024
41 +---------------+ +---------------+ +---------------+
42 |conn list +--->conn +--------->conn |
43 +---------------+ +---------------+ +---------------+
45 +---------------+ +---v----+ +---v----+ +---v----+ +---v----+
46 |primary | |secondary |primary | |secondary
47 |packet | |packet + |packet | |packet +
48 +--------+ +--------+ +--------+ +--------+
50 +---v----+ +---v----+ +---v----+ +---v----+
51 |primary | |secondary |primary | |secondary
52 |packet | |packet + |packet | |packet +
53 +--------+ +--------+ +--------+ +--------+
55 +---v----+ +---v----+ +---v----+ +---v----+
56 |primary | |secondary |primary | |secondary
57 |packet | |packet + |packet | |packet +
58 +--------+ +--------+ +--------+ +--------+
60 typedef struct CompareState
{
66 CharDriverState
*chr_pri_in
;
67 CharDriverState
*chr_sec_in
;
68 CharDriverState
*chr_out
;
69 SocketReadState pri_rs
;
70 SocketReadState sec_rs
;
72 /* connection list: the connections belonged to this NIC could be found
74 * element type: Connection
77 /* hashtable to save connection */
78 GHashTable
*connection_track_table
;
81 typedef struct CompareClass
{
82 ObjectClass parent_class
;
85 typedef struct CompareChardevProps
{
87 } CompareChardevProps
;
94 static int compare_chr_send(CharDriverState
*out
,
99 * Return 0 on success, if return -1 means the pkt
100 * is unsupported(arp and ipv6) and will be sent later
102 static int packet_enqueue(CompareState
*s
, int mode
)
108 if (mode
== PRIMARY_IN
) {
109 pkt
= packet_new(s
->pri_rs
.buf
, s
->pri_rs
.packet_len
);
111 pkt
= packet_new(s
->sec_rs
.buf
, s
->sec_rs
.packet_len
);
114 if (parse_packet_early(pkt
)) {
115 packet_destroy(pkt
, NULL
);
119 fill_connection_key(pkt
, &key
);
121 conn
= connection_get(s
->connection_track_table
,
125 if (!conn
->processing
) {
126 g_queue_push_tail(&s
->conn_list
, conn
);
127 conn
->processing
= true;
130 if (mode
== PRIMARY_IN
) {
131 if (g_queue_get_length(&conn
->primary_list
) <=
133 g_queue_push_tail(&conn
->primary_list
, pkt
);
135 error_report("colo compare primary queue size too big,"
139 if (g_queue_get_length(&conn
->secondary_list
) <=
141 g_queue_push_tail(&conn
->secondary_list
, pkt
);
143 error_report("colo compare secondary queue size too big,"
151 static int compare_chr_send(CharDriverState
*out
,
156 uint32_t len
= htonl(size
);
162 ret
= qemu_chr_fe_write_all(out
, (uint8_t *)&len
, sizeof(len
));
163 if (ret
!= sizeof(len
)) {
167 ret
= qemu_chr_fe_write_all(out
, (uint8_t *)buf
, size
);
175 return ret
< 0 ? ret
: -EIO
;
178 static char *compare_get_pri_indev(Object
*obj
, Error
**errp
)
180 CompareState
*s
= COLO_COMPARE(obj
);
182 return g_strdup(s
->pri_indev
);
185 static void compare_set_pri_indev(Object
*obj
, const char *value
, Error
**errp
)
187 CompareState
*s
= COLO_COMPARE(obj
);
189 g_free(s
->pri_indev
);
190 s
->pri_indev
= g_strdup(value
);
193 static char *compare_get_sec_indev(Object
*obj
, Error
**errp
)
195 CompareState
*s
= COLO_COMPARE(obj
);
197 return g_strdup(s
->sec_indev
);
200 static void compare_set_sec_indev(Object
*obj
, const char *value
, Error
**errp
)
202 CompareState
*s
= COLO_COMPARE(obj
);
204 g_free(s
->sec_indev
);
205 s
->sec_indev
= g_strdup(value
);
208 static char *compare_get_outdev(Object
*obj
, Error
**errp
)
210 CompareState
*s
= COLO_COMPARE(obj
);
212 return g_strdup(s
->outdev
);
215 static void compare_set_outdev(Object
*obj
, const char *value
, Error
**errp
)
217 CompareState
*s
= COLO_COMPARE(obj
);
220 s
->outdev
= g_strdup(value
);
223 static void compare_pri_rs_finalize(SocketReadState
*pri_rs
)
225 CompareState
*s
= container_of(pri_rs
, CompareState
, pri_rs
);
227 if (packet_enqueue(s
, PRIMARY_IN
)) {
228 trace_colo_compare_main("primary: unsupported packet in");
229 compare_chr_send(s
->chr_out
, pri_rs
->buf
, pri_rs
->packet_len
);
233 static void compare_sec_rs_finalize(SocketReadState
*sec_rs
)
235 CompareState
*s
= container_of(sec_rs
, CompareState
, sec_rs
);
237 if (packet_enqueue(s
, SECONDARY_IN
)) {
238 trace_colo_compare_main("secondary: unsupported packet in");
242 static int compare_chardev_opts(void *opaque
,
243 const char *name
, const char *value
,
246 CompareChardevProps
*props
= opaque
;
248 if (strcmp(name
, "backend") == 0 &&
249 strcmp(value
, "socket") == 0) {
250 props
->is_socket
= true;
252 } else if (strcmp(name
, "host") == 0 ||
253 (strcmp(name
, "port") == 0) ||
254 (strcmp(name
, "server") == 0) ||
255 (strcmp(name
, "wait") == 0) ||
256 (strcmp(name
, "path") == 0)) {
260 "COLO-compare does not support a chardev with option %s=%s",
267 * Return 0 is success.
268 * Return 1 is failed.
270 static int find_and_check_chardev(CharDriverState
**chr
,
274 CompareChardevProps props
;
276 *chr
= qemu_chr_find(chr_name
);
278 error_setg(errp
, "Device '%s' not found",
283 memset(&props
, 0, sizeof(props
));
284 if (qemu_opt_foreach((*chr
)->opts
, compare_chardev_opts
, &props
, errp
)) {
288 if (!props
.is_socket
) {
289 error_setg(errp
, "chardev \"%s\" is not a tcp socket",
297 * Called from the main thread on the primary
298 * to setup colo-compare.
300 static void colo_compare_complete(UserCreatable
*uc
, Error
**errp
)
302 CompareState
*s
= COLO_COMPARE(uc
);
304 if (!s
->pri_indev
|| !s
->sec_indev
|| !s
->outdev
) {
305 error_setg(errp
, "colo compare needs 'primary_in' ,"
306 "'secondary_in','outdev' property set");
308 } else if (!strcmp(s
->pri_indev
, s
->outdev
) ||
309 !strcmp(s
->sec_indev
, s
->outdev
) ||
310 !strcmp(s
->pri_indev
, s
->sec_indev
)) {
311 error_setg(errp
, "'indev' and 'outdev' could not be same "
312 "for compare module");
316 if (find_and_check_chardev(&s
->chr_pri_in
, s
->pri_indev
, errp
)) {
320 if (find_and_check_chardev(&s
->chr_sec_in
, s
->sec_indev
, errp
)) {
324 if (find_and_check_chardev(&s
->chr_out
, s
->outdev
, errp
)) {
328 qemu_chr_fe_claim_no_fail(s
->chr_pri_in
);
330 qemu_chr_fe_claim_no_fail(s
->chr_sec_in
);
332 qemu_chr_fe_claim_no_fail(s
->chr_out
);
334 net_socket_rs_init(&s
->pri_rs
, compare_pri_rs_finalize
);
335 net_socket_rs_init(&s
->sec_rs
, compare_sec_rs_finalize
);
337 g_queue_init(&s
->conn_list
);
339 s
->connection_track_table
= g_hash_table_new_full(connection_key_hash
,
340 connection_key_equal
,
347 static void colo_compare_class_init(ObjectClass
*oc
, void *data
)
349 UserCreatableClass
*ucc
= USER_CREATABLE_CLASS(oc
);
351 ucc
->complete
= colo_compare_complete
;
354 static void colo_compare_init(Object
*obj
)
356 object_property_add_str(obj
, "primary_in",
357 compare_get_pri_indev
, compare_set_pri_indev
,
359 object_property_add_str(obj
, "secondary_in",
360 compare_get_sec_indev
, compare_set_sec_indev
,
362 object_property_add_str(obj
, "outdev",
363 compare_get_outdev
, compare_set_outdev
,
367 static void colo_compare_finalize(Object
*obj
)
369 CompareState
*s
= COLO_COMPARE(obj
);
372 qemu_chr_add_handlers(s
->chr_pri_in
, NULL
, NULL
, NULL
, NULL
);
373 qemu_chr_fe_release(s
->chr_pri_in
);
376 qemu_chr_add_handlers(s
->chr_sec_in
, NULL
, NULL
, NULL
, NULL
);
377 qemu_chr_fe_release(s
->chr_sec_in
);
380 qemu_chr_fe_release(s
->chr_out
);
383 g_queue_free(&s
->conn_list
);
385 g_free(s
->pri_indev
);
386 g_free(s
->sec_indev
);
390 static const TypeInfo colo_compare_info
= {
391 .name
= TYPE_COLO_COMPARE
,
392 .parent
= TYPE_OBJECT
,
393 .instance_size
= sizeof(CompareState
),
394 .instance_init
= colo_compare_init
,
395 .instance_finalize
= colo_compare_finalize
,
396 .class_size
= sizeof(CompareClass
),
397 .class_init
= colo_compare_class_init
,
398 .interfaces
= (InterfaceInfo
[]) {
399 { TYPE_USER_CREATABLE
},
404 static void register_types(void)
406 type_register_static(&colo_compare_info
);
409 type_init(register_types
);