xref: /openbmc/qemu/net/colo-compare.c (revision 289ac098b627f69a9571ab076f0ce49aae29b781)
17dce4e6fSZhang Chen /*
27dce4e6fSZhang Chen  * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
37dce4e6fSZhang Chen  * (a.k.a. Fault Tolerance or Continuous Replication)
47dce4e6fSZhang Chen  *
57dce4e6fSZhang Chen  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
67dce4e6fSZhang Chen  * Copyright (c) 2016 FUJITSU LIMITED
77dce4e6fSZhang Chen  * Copyright (c) 2016 Intel Corporation
87dce4e6fSZhang Chen  *
97dce4e6fSZhang Chen  * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
107dce4e6fSZhang Chen  *
117dce4e6fSZhang Chen  * This work is licensed under the terms of the GNU GPL, version 2 or
127dce4e6fSZhang Chen  * later.  See the COPYING file in the top-level directory.
137dce4e6fSZhang Chen  */
147dce4e6fSZhang Chen 
157dce4e6fSZhang Chen #include "qemu/osdep.h"
167dce4e6fSZhang Chen #include "qemu/error-report.h"
1759509ec1SZhang Chen #include "trace.h"
187dce4e6fSZhang Chen #include "qapi/error.h"
197dce4e6fSZhang Chen #include "net/net.h"
20f4b61836SZhang Chen #include "net/eth.h"
217dce4e6fSZhang Chen #include "qom/object_interfaces.h"
227dce4e6fSZhang Chen #include "qemu/iov.h"
237dce4e6fSZhang Chen #include "qom/object.h"
247dce4e6fSZhang Chen #include "net/queue.h"
254d43a603SMarc-André Lureau #include "chardev/char-fe.h"
267dce4e6fSZhang Chen #include "qemu/sockets.h"
27f27f01dbSMichael S. Tsirkin #include "colo.h"
28dd321ecfSWang Yong #include "sysemu/iothread.h"
290ffcece3SZhang Chen #include "net/colo-compare.h"
300ffcece3SZhang Chen #include "migration/colo.h"
31e05ae1d9SMarc-André Lureau #include "util.h"
327dce4e6fSZhang Chen 
339c55fe94SLukas Straub #include "block/aio-wait.h"
349c55fe94SLukas Straub #include "qemu/coroutine.h"
359c55fe94SLukas Straub 
367dce4e6fSZhang Chen #define TYPE_COLO_COMPARE "colo-compare"
37db1015e9SEduardo Habkost typedef struct CompareState CompareState;
388110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(CompareState, COLO_COMPARE,
398110fa1dSEduardo Habkost                          TYPE_COLO_COMPARE)
407dce4e6fSZhang Chen 
410ffcece3SZhang Chen static QTAILQ_HEAD(, CompareState) net_compares =
420ffcece3SZhang Chen        QTAILQ_HEAD_INITIALIZER(net_compares);
430ffcece3SZhang Chen 
44dccd0313SZhang Chen static NotifierList colo_compare_notifiers =
45dccd0313SZhang Chen     NOTIFIER_LIST_INITIALIZER(colo_compare_notifiers);
46dccd0313SZhang Chen 
470682e15bSZhang Chen #define COMPARE_READ_LEN_MAX NET_BUFSIZE
48b6540d40SZhang Chen #define MAX_QUEUE_SIZE 1024
49b6540d40SZhang Chen 
50f449c9e5SMao Zhongyi #define COLO_COMPARE_FREE_PRIMARY     0x01
51f449c9e5SMao Zhongyi #define COLO_COMPARE_FREE_SECONDARY   0x02
52f449c9e5SMao Zhongyi 
532f2fcff3SZhang Chen #define REGULAR_PACKET_CHECK_MS 1000
549cc43c94SZhang Chen #define DEFAULT_TIME_OUT_MS 3000
550682e15bSZhang Chen 
568c8ed038SRoman Bolshakov /* #define DEBUG_COLO_PACKETS */
578c8ed038SRoman Bolshakov 
5845942b79SLukas Straub static QemuMutex colo_compare_mutex;
5945942b79SLukas Straub static bool colo_compare_active;
600ffcece3SZhang Chen static QemuMutex event_mtx;
610ffcece3SZhang Chen static QemuCond event_complete_cond;
620ffcece3SZhang Chen static int event_unhandled_count;
63a2e5cb7aSZhang Chen static uint32_t max_queue_size;
640ffcece3SZhang Chen 
6559509ec1SZhang Chen /*
6661c5f469SZhang Chen  *  + CompareState ++
6761c5f469SZhang Chen  *  |               |
6861c5f469SZhang Chen  *  +---------------+   +---------------+         +---------------+
6961c5f469SZhang Chen  *  |   conn list   + - >      conn     + ------- >      conn     + -- > ......
7061c5f469SZhang Chen  *  +---------------+   +---------------+         +---------------+
7161c5f469SZhang Chen  *  |               |     |           |             |          |
7261c5f469SZhang Chen  *  +---------------+ +---v----+  +---v----+    +---v----+ +---v----+
7361c5f469SZhang Chen  *                    |primary |  |secondary    |primary | |secondary
7461c5f469SZhang Chen  *                    |packet  |  |packet  +    |packet  | |packet  +
7561c5f469SZhang Chen  *                    +--------+  +--------+    +--------+ +--------+
7661c5f469SZhang Chen  *                        |           |             |          |
7761c5f469SZhang Chen  *                    +---v----+  +---v----+    +---v----+ +---v----+
7861c5f469SZhang Chen  *                    |primary |  |secondary    |primary | |secondary
7961c5f469SZhang Chen  *                    |packet  |  |packet  +    |packet  | |packet  +
8061c5f469SZhang Chen  *                    +--------+  +--------+    +--------+ +--------+
8161c5f469SZhang Chen  *                        |           |             |          |
8261c5f469SZhang Chen  *                    +---v----+  +---v----+    +---v----+ +---v----+
8361c5f469SZhang Chen  *                    |primary |  |secondary    |primary | |secondary
8461c5f469SZhang Chen  *                    |packet  |  |packet  +    |packet  | |packet  +
8561c5f469SZhang Chen  *                    +--------+  +--------+    +--------+ +--------+
8659509ec1SZhang Chen  */
879c55fe94SLukas Straub 
889c55fe94SLukas Straub typedef struct SendCo {
899c55fe94SLukas Straub     Coroutine *co;
909c55fe94SLukas Straub     struct CompareState *s;
919c55fe94SLukas Straub     CharBackend *chr;
929c55fe94SLukas Straub     GQueue send_list;
939c55fe94SLukas Straub     bool notify_remote_frame;
949c55fe94SLukas Straub     bool done;
959c55fe94SLukas Straub     int ret;
969c55fe94SLukas Straub } SendCo;
979c55fe94SLukas Straub 
989c55fe94SLukas Straub typedef struct SendEntry {
999c55fe94SLukas Straub     uint32_t size;
1009c55fe94SLukas Straub     uint32_t vnet_hdr_len;
1019c55fe94SLukas Straub     uint8_t *buf;
1029c55fe94SLukas Straub } SendEntry;
1039c55fe94SLukas Straub 
104db1015e9SEduardo Habkost struct CompareState {
1057dce4e6fSZhang Chen     Object parent;
1067dce4e6fSZhang Chen 
1077dce4e6fSZhang Chen     char *pri_indev;
1087dce4e6fSZhang Chen     char *sec_indev;
1097dce4e6fSZhang Chen     char *outdev;
110cf6af766SZhang Chen     char *notify_dev;
11132a6ebecSMarc-André Lureau     CharBackend chr_pri_in;
11232a6ebecSMarc-André Lureau     CharBackend chr_sec_in;
11332a6ebecSMarc-André Lureau     CharBackend chr_out;
11413025feeSZhang Chen     CharBackend chr_notify_dev;
1157dce4e6fSZhang Chen     SocketReadState pri_rs;
1167dce4e6fSZhang Chen     SocketReadState sec_rs;
11713025feeSZhang Chen     SocketReadState notify_rs;
1189c55fe94SLukas Straub     SendCo out_sendco;
1199c55fe94SLukas Straub     SendCo notify_sendco;
120aa3a7032SZhang Chen     bool vnet_hdr;
1210c4266efSZhang Chen     uint64_t compare_timeout;
122cca35ac4SZhang Chen     uint32_t expired_scan_cycle;
12359509ec1SZhang Chen 
12461c5f469SZhang Chen     /*
12561c5f469SZhang Chen      * Record the connection that through the NIC
12661c5f469SZhang Chen      * Element type: Connection
127b6540d40SZhang Chen      */
128b6540d40SZhang Chen     GQueue conn_list;
12961c5f469SZhang Chen     /* Record the connection without repetition */
13059509ec1SZhang Chen     GHashTable *connection_track_table;
131dfd917a9Szhanghailiang 
132dd321ecfSWang Yong     IOThread *iothread;
133b43decb0Szhanghailiang     GMainContext *worker_context;
134dd321ecfSWang Yong     QEMUTimer *packet_check_timer;
1350ffcece3SZhang Chen 
1360ffcece3SZhang Chen     QEMUBH *event_bh;
1370ffcece3SZhang Chen     enum colo_event event;
1380ffcece3SZhang Chen 
1390ffcece3SZhang Chen     QTAILQ_ENTRY(CompareState) next;
140db1015e9SEduardo Habkost };
1417dce4e6fSZhang Chen 
1427dce4e6fSZhang Chen typedef struct CompareClass {
1437dce4e6fSZhang Chen     ObjectClass parent_class;
1447dce4e6fSZhang Chen } CompareClass;
1457dce4e6fSZhang Chen 
14659509ec1SZhang Chen enum {
14759509ec1SZhang Chen     PRIMARY_IN = 0,
14859509ec1SZhang Chen     SECONDARY_IN,
14959509ec1SZhang Chen };
15059509ec1SZhang Chen 
151bdadbb0fSDerek Su static const char *colo_mode[] = {
152bdadbb0fSDerek Su     [PRIMARY_IN] = "primary",
153bdadbb0fSDerek Su     [SECONDARY_IN] = "secondary",
154bdadbb0fSDerek Su };
15524525e93SZhang Chen 
1563037e7a5SZhang Chen static int compare_chr_send(CompareState *s,
1579c55fe94SLukas Straub                             uint8_t *buf,
158aa3a7032SZhang Chen                             uint32_t size,
15930685c00SZhang Chen                             uint32_t vnet_hdr_len,
1609c55fe94SLukas Straub                             bool notify_remote_frame,
1619c55fe94SLukas Straub                             bool zero_copy);
16259509ec1SZhang Chen 
packet_matches_str(const char * str,const uint8_t * buf,uint32_t packet_len)163f77bed14SZhang Chen static bool packet_matches_str(const char *str,
164f77bed14SZhang Chen                                const uint8_t *buf,
165f77bed14SZhang Chen                                uint32_t packet_len)
166f77bed14SZhang Chen {
167f77bed14SZhang Chen     if (packet_len != strlen(str)) {
168f77bed14SZhang Chen         return false;
169f77bed14SZhang Chen     }
170f77bed14SZhang Chen 
171ae4c2099SRao, Lei     return !memcmp(str, buf, packet_len);
172f77bed14SZhang Chen }
173f77bed14SZhang Chen 
notify_remote_frame(CompareState * s)1741d09f700SZhang Chen static void notify_remote_frame(CompareState *s)
1751d09f700SZhang Chen {
1761d09f700SZhang Chen     char msg[] = "DO_CHECKPOINT";
1771d09f700SZhang Chen     int ret = 0;
1781d09f700SZhang Chen 
1799c55fe94SLukas Straub     ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
1801d09f700SZhang Chen     if (ret < 0) {
1811d09f700SZhang Chen         error_report("Notify Xen COLO-frame failed");
1821d09f700SZhang Chen     }
1831d09f700SZhang Chen }
1841d09f700SZhang Chen 
colo_compare_inconsistency_notify(CompareState * s)1851d09f700SZhang Chen static void colo_compare_inconsistency_notify(CompareState *s)
1861d09f700SZhang Chen {
1871d09f700SZhang Chen     if (s->notify_dev) {
1881d09f700SZhang Chen         notify_remote_frame(s);
1891d09f700SZhang Chen     } else {
1901d09f700SZhang Chen         notifier_list_notify(&colo_compare_notifiers,
1917395127fSSteve Sistare                              NULL);
1921d09f700SZhang Chen     }
1931d09f700SZhang Chen }
1941d09f700SZhang Chen 
19533609e95SRao, Lei /* Use restricted to colo_insert_packet() */
seq_sorter(Packet * a,Packet * b,gpointer data)196a935cc31SZhang Chen static gint seq_sorter(Packet *a, Packet *b, gpointer data)
197a935cc31SZhang Chen {
198a5f038e2SZhang Chen     return b->tcp_seq - a->tcp_seq;
199a935cc31SZhang Chen }
200a935cc31SZhang Chen 
fill_pkt_tcp_info(void * data,uint32_t * max_ack)201f449c9e5SMao Zhongyi static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
202f449c9e5SMao Zhongyi {
203f449c9e5SMao Zhongyi     Packet *pkt = data;
204e05ae1d9SMarc-André Lureau     struct tcp_hdr *tcphd;
205f449c9e5SMao Zhongyi 
206e05ae1d9SMarc-André Lureau     tcphd = (struct tcp_hdr *)pkt->transport_header;
207f449c9e5SMao Zhongyi 
208f449c9e5SMao Zhongyi     pkt->tcp_seq = ntohl(tcphd->th_seq);
209f449c9e5SMao Zhongyi     pkt->tcp_ack = ntohl(tcphd->th_ack);
210fb5eca4aSZhang Chen     /* Need to consider ACK will bigger than uint32_t MAX */
211fb5eca4aSZhang Chen     *max_ack = pkt->tcp_ack - *max_ack > 0 ? pkt->tcp_ack : *max_ack;
212f449c9e5SMao Zhongyi     pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
2135a2d9929SRao, Lei                        + (tcphd->th_off << 2);
214f449c9e5SMao Zhongyi     pkt->payload_size = pkt->size - pkt->header_size;
215f449c9e5SMao Zhongyi     pkt->seq_end = pkt->tcp_seq + pkt->payload_size;
216f449c9e5SMao Zhongyi     pkt->flags = tcphd->th_flags;
217f449c9e5SMao Zhongyi }
218f449c9e5SMao Zhongyi 
21959509ec1SZhang Chen /*
2208850d4caSMao Zhongyi  * Return 1 on success, if return 0 means the
2218850d4caSMao Zhongyi  * packet will be dropped
2228850d4caSMao Zhongyi  */
colo_insert_packet(GQueue * queue,Packet * pkt,uint32_t * max_ack)223f449c9e5SMao Zhongyi static int colo_insert_packet(GQueue *queue, Packet *pkt, uint32_t *max_ack)
2248850d4caSMao Zhongyi {
225a2e5cb7aSZhang Chen     if (g_queue_get_length(queue) <= max_queue_size) {
2268850d4caSMao Zhongyi         if (pkt->ip->ip_p == IPPROTO_TCP) {
227f449c9e5SMao Zhongyi             fill_pkt_tcp_info(pkt, max_ack);
2288850d4caSMao Zhongyi             g_queue_insert_sorted(queue,
2298850d4caSMao Zhongyi                                   pkt,
2308850d4caSMao Zhongyi                                   (GCompareDataFunc)seq_sorter,
2318850d4caSMao Zhongyi                                   NULL);
2328850d4caSMao Zhongyi         } else {
2338850d4caSMao Zhongyi             g_queue_push_tail(queue, pkt);
2348850d4caSMao Zhongyi         }
2358850d4caSMao Zhongyi         return 1;
2368850d4caSMao Zhongyi     }
2378850d4caSMao Zhongyi     return 0;
2388850d4caSMao Zhongyi }
2398850d4caSMao Zhongyi 
2408850d4caSMao Zhongyi /*
24159509ec1SZhang Chen  * Return 0 on success, if return -1 means the pkt
24259509ec1SZhang Chen  * is unsupported(arp and ipv6) and will be sent later
24359509ec1SZhang Chen  */
packet_enqueue(CompareState * s,int mode,Connection ** con)2448ec14402SMao Zhongyi static int packet_enqueue(CompareState *s, int mode, Connection **con)
24559509ec1SZhang Chen {
246b6540d40SZhang Chen     ConnectionKey key;
24759509ec1SZhang Chen     Packet *pkt = NULL;
248b6540d40SZhang Chen     Connection *conn;
249bdadbb0fSDerek Su     int ret;
25059509ec1SZhang Chen 
25159509ec1SZhang Chen     if (mode == PRIMARY_IN) {
252ada1a33fSZhang Chen         pkt = packet_new(s->pri_rs.buf,
253ada1a33fSZhang Chen                          s->pri_rs.packet_len,
254ada1a33fSZhang Chen                          s->pri_rs.vnet_hdr_len);
25559509ec1SZhang Chen     } else {
256ada1a33fSZhang Chen         pkt = packet_new(s->sec_rs.buf,
257ada1a33fSZhang Chen                          s->sec_rs.packet_len,
258ada1a33fSZhang Chen                          s->sec_rs.vnet_hdr_len);
25959509ec1SZhang Chen     }
26059509ec1SZhang Chen 
26159509ec1SZhang Chen     if (parse_packet_early(pkt)) {
26259509ec1SZhang Chen         packet_destroy(pkt, NULL);
26359509ec1SZhang Chen         pkt = NULL;
26459509ec1SZhang Chen         return -1;
26559509ec1SZhang Chen     }
26664153ca6SRao, Lei     fill_connection_key(pkt, &key, false);
26759509ec1SZhang Chen 
268b6540d40SZhang Chen     conn = connection_get(s->connection_track_table,
269b6540d40SZhang Chen                           &key,
270b6540d40SZhang Chen                           &s->conn_list);
27159509ec1SZhang Chen 
272b6540d40SZhang Chen     if (!conn->processing) {
273b6540d40SZhang Chen         g_queue_push_tail(&s->conn_list, conn);
274b6540d40SZhang Chen         conn->processing = true;
275b6540d40SZhang Chen     }
276b6540d40SZhang Chen 
277b6540d40SZhang Chen     if (mode == PRIMARY_IN) {
278bdadbb0fSDerek Su         ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack);
279b6540d40SZhang Chen     } else {
280bdadbb0fSDerek Su         ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack);
281b6540d40SZhang Chen     }
282bdadbb0fSDerek Su 
283bdadbb0fSDerek Su     if (!ret) {
284bdadbb0fSDerek Su         trace_colo_compare_drop_packet(colo_mode[mode],
285bdadbb0fSDerek Su             "queue size too big, drop packet");
286bdadbb0fSDerek Su         packet_destroy(pkt, NULL);
287bdadbb0fSDerek Su         pkt = NULL;
288b6540d40SZhang Chen     }
289bdadbb0fSDerek Su 
2904d366235SMao Zhongyi     *con = conn;
29159509ec1SZhang Chen 
29259509ec1SZhang Chen     return 0;
29359509ec1SZhang Chen }
29459509ec1SZhang Chen 
after(uint32_t seq1,uint32_t seq2)295f449c9e5SMao Zhongyi static inline bool after(uint32_t seq1, uint32_t seq2)
296f449c9e5SMao Zhongyi {
297f449c9e5SMao Zhongyi         return (int32_t)(seq1 - seq2) > 0;
298f449c9e5SMao Zhongyi }
299f449c9e5SMao Zhongyi 
colo_release_primary_pkt(CompareState * s,Packet * pkt)300f449c9e5SMao Zhongyi static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
301f449c9e5SMao Zhongyi {
302f449c9e5SMao Zhongyi     int ret;
303f449c9e5SMao Zhongyi     ret = compare_chr_send(s,
304f449c9e5SMao Zhongyi                            pkt->data,
305f449c9e5SMao Zhongyi                            pkt->size,
30630685c00SZhang Chen                            pkt->vnet_hdr_len,
3079c55fe94SLukas Straub                            false,
3089c55fe94SLukas Straub                            true);
309f449c9e5SMao Zhongyi     if (ret < 0) {
310f449c9e5SMao Zhongyi         error_report("colo send primary packet failed");
311f449c9e5SMao Zhongyi     }
312f449c9e5SMao Zhongyi     trace_colo_compare_main("packet same and release packet");
3139c55fe94SLukas Straub     packet_destroy_partial(pkt, NULL);
314f449c9e5SMao Zhongyi }
315f449c9e5SMao Zhongyi 
3160682e15bSZhang Chen /*
3170682e15bSZhang Chen  * The IP packets sent by primary and secondary
3180682e15bSZhang Chen  * will be compared in here
3190682e15bSZhang Chen  * TODO support ip fragment, Out-Of-Order
3200682e15bSZhang Chen  * return:    0  means packet same
3210682e15bSZhang Chen  *            > 0 || < 0 means packet different
3220682e15bSZhang Chen  */
colo_compare_packet_payload(Packet * ppkt,Packet * spkt,uint16_t poffset,uint16_t soffset,uint16_t len)3239394133fSMao Zhongyi static int colo_compare_packet_payload(Packet *ppkt,
3246f5009c3SZhang Chen                                        Packet *spkt,
3259394133fSMao Zhongyi                                        uint16_t poffset,
3269394133fSMao Zhongyi                                        uint16_t soffset,
3279394133fSMao Zhongyi                                        uint16_t len)
3289394133fSMao Zhongyi 
3290682e15bSZhang Chen {
3308c8ed038SRoman Bolshakov     if (trace_event_get_state_backends(TRACE_COLO_COMPARE_IP_INFO)) {
331e630b2bfSZhang Chen         char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
332e630b2bfSZhang Chen 
333e630b2bfSZhang Chen         strcpy(pri_ip_src, inet_ntoa(ppkt->ip->ip_src));
334e630b2bfSZhang Chen         strcpy(pri_ip_dst, inet_ntoa(ppkt->ip->ip_dst));
335e630b2bfSZhang Chen         strcpy(sec_ip_src, inet_ntoa(spkt->ip->ip_src));
336e630b2bfSZhang Chen         strcpy(sec_ip_dst, inet_ntoa(spkt->ip->ip_dst));
337e630b2bfSZhang Chen 
338e630b2bfSZhang Chen         trace_colo_compare_ip_info(ppkt->size, pri_ip_src,
339e630b2bfSZhang Chen                                    pri_ip_dst, spkt->size,
340e630b2bfSZhang Chen                                    sec_ip_src, sec_ip_dst);
341e630b2bfSZhang Chen     }
3420682e15bSZhang Chen 
3439394133fSMao Zhongyi     return memcmp(ppkt->data + poffset, spkt->data + soffset, len);
3440682e15bSZhang Chen }
3450682e15bSZhang Chen 
346f4b61836SZhang Chen /*
347f449c9e5SMao Zhongyi  * return true means that the payload is consist and
348f449c9e5SMao Zhongyi  * need to make the next comparison, false means do
349f449c9e5SMao Zhongyi  * the checkpoint
350f4b61836SZhang Chen */
colo_mark_tcp_pkt(Packet * ppkt,Packet * spkt,int8_t * mark,uint32_t max_ack)351f449c9e5SMao Zhongyi static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
352f449c9e5SMao Zhongyi                               int8_t *mark, uint32_t max_ack)
3530682e15bSZhang Chen {
354f449c9e5SMao Zhongyi     *mark = 0;
355f4b61836SZhang Chen 
356f449c9e5SMao Zhongyi     if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
3571e907a32SFan Yang         if (!colo_compare_packet_payload(ppkt, spkt,
358f449c9e5SMao Zhongyi                                         ppkt->header_size, spkt->header_size,
359f449c9e5SMao Zhongyi                                         ppkt->payload_size)) {
360f449c9e5SMao Zhongyi             *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
361f449c9e5SMao Zhongyi             return true;
362f449c9e5SMao Zhongyi         }
363f449c9e5SMao Zhongyi     }
364f4b61836SZhang Chen 
365f449c9e5SMao Zhongyi     /* one part of secondary packet payload still need to be compared */
366f449c9e5SMao Zhongyi     if (!after(ppkt->seq_end, spkt->seq_end)) {
3671e907a32SFan Yang         if (!colo_compare_packet_payload(ppkt, spkt,
368f449c9e5SMao Zhongyi                                         ppkt->header_size + ppkt->offset,
369f449c9e5SMao Zhongyi                                         spkt->header_size + spkt->offset,
370f449c9e5SMao Zhongyi                                         ppkt->payload_size - ppkt->offset)) {
371f449c9e5SMao Zhongyi             if (!after(ppkt->tcp_ack, max_ack)) {
372f449c9e5SMao Zhongyi                 *mark = COLO_COMPARE_FREE_PRIMARY;
373f449c9e5SMao Zhongyi                 spkt->offset += ppkt->payload_size - ppkt->offset;
374f449c9e5SMao Zhongyi                 return true;
3756efeb328SZhang Chen             } else {
376f449c9e5SMao Zhongyi                 /* secondary guest hasn't ack the data, don't send
377f449c9e5SMao Zhongyi                  * out this packet
378f449c9e5SMao Zhongyi                  */
379f449c9e5SMao Zhongyi                 return false;
380f449c9e5SMao Zhongyi             }
381f449c9e5SMao Zhongyi         }
382f449c9e5SMao Zhongyi     } else {
383f449c9e5SMao Zhongyi         /* primary packet is longer than secondary packet, compare
384f449c9e5SMao Zhongyi          * the same part and mark the primary packet offset
385f449c9e5SMao Zhongyi          */
3861e907a32SFan Yang         if (!colo_compare_packet_payload(ppkt, spkt,
387f449c9e5SMao Zhongyi                                         ppkt->header_size + ppkt->offset,
388f449c9e5SMao Zhongyi                                         spkt->header_size + spkt->offset,
389f449c9e5SMao Zhongyi                                         spkt->payload_size - spkt->offset)) {
390f449c9e5SMao Zhongyi             *mark = COLO_COMPARE_FREE_SECONDARY;
391f449c9e5SMao Zhongyi             ppkt->offset += spkt->payload_size - spkt->offset;
392f449c9e5SMao Zhongyi             return true;
393f449c9e5SMao Zhongyi         }
3946efeb328SZhang Chen     }
395f4b61836SZhang Chen 
396f449c9e5SMao Zhongyi     return false;
397f449c9e5SMao Zhongyi }
3982dfe5113SAlex Bennée 
colo_compare_tcp(CompareState * s,Connection * conn)399f449c9e5SMao Zhongyi static void colo_compare_tcp(CompareState *s, Connection *conn)
400f449c9e5SMao Zhongyi {
401f449c9e5SMao Zhongyi     Packet *ppkt = NULL, *spkt = NULL;
402f449c9e5SMao Zhongyi     int8_t mark;
403f583dca9SZhang Chen 
404f449c9e5SMao Zhongyi     /*
405f449c9e5SMao Zhongyi      * If ppkt and spkt have the same payload, but ppkt's ACK
406f449c9e5SMao Zhongyi      * is greater than spkt's ACK, in this case we can not
407f449c9e5SMao Zhongyi      * send the ppkt because it will cause the secondary guest
408f449c9e5SMao Zhongyi      * to miss sending some data in the next. Therefore, we
409f449c9e5SMao Zhongyi      * record the maximum ACK in the current queue at both
410f449c9e5SMao Zhongyi      * primary side and secondary side. Only when the ack is
411f449c9e5SMao Zhongyi      * less than the smaller of the two maximum ack, then we
412f449c9e5SMao Zhongyi      * can ensure that the packet's payload is acknowledged by
413f449c9e5SMao Zhongyi      * primary and secondary.
414f449c9e5SMao Zhongyi     */
415*289ac098SStefan Weil     uint32_t min_ack = MIN(conn->pack, conn->sack);
416f583dca9SZhang Chen 
417f449c9e5SMao Zhongyi pri:
418f449c9e5SMao Zhongyi     if (g_queue_is_empty(&conn->primary_list)) {
419f449c9e5SMao Zhongyi         return;
420f449c9e5SMao Zhongyi     }
421a5f038e2SZhang Chen     ppkt = g_queue_pop_tail(&conn->primary_list);
422f449c9e5SMao Zhongyi sec:
423f449c9e5SMao Zhongyi     if (g_queue_is_empty(&conn->secondary_list)) {
424a5f038e2SZhang Chen         g_queue_push_tail(&conn->primary_list, ppkt);
425f449c9e5SMao Zhongyi         return;
426f449c9e5SMao Zhongyi     }
427a5f038e2SZhang Chen     spkt = g_queue_pop_tail(&conn->secondary_list);
42851b9d495SPeter Maydell 
429f449c9e5SMao Zhongyi     if (ppkt->tcp_seq == ppkt->seq_end) {
430f449c9e5SMao Zhongyi         colo_release_primary_pkt(s, ppkt);
431f449c9e5SMao Zhongyi         ppkt = NULL;
432f449c9e5SMao Zhongyi     }
433f449c9e5SMao Zhongyi 
434f449c9e5SMao Zhongyi     if (ppkt && conn->compare_seq && !after(ppkt->seq_end, conn->compare_seq)) {
435f449c9e5SMao Zhongyi         trace_colo_compare_main("pri: this packet has compared");
436f449c9e5SMao Zhongyi         colo_release_primary_pkt(s, ppkt);
437f449c9e5SMao Zhongyi         ppkt = NULL;
438f449c9e5SMao Zhongyi     }
439f449c9e5SMao Zhongyi 
440f449c9e5SMao Zhongyi     if (spkt->tcp_seq == spkt->seq_end) {
441f449c9e5SMao Zhongyi         packet_destroy(spkt, NULL);
442f449c9e5SMao Zhongyi         if (!ppkt) {
443f449c9e5SMao Zhongyi             goto pri;
444f449c9e5SMao Zhongyi         } else {
445f449c9e5SMao Zhongyi             goto sec;
446f449c9e5SMao Zhongyi         }
447f449c9e5SMao Zhongyi     } else {
448f449c9e5SMao Zhongyi         if (conn->compare_seq && !after(spkt->seq_end, conn->compare_seq)) {
449f449c9e5SMao Zhongyi             trace_colo_compare_main("sec: this packet has compared");
450f449c9e5SMao Zhongyi             packet_destroy(spkt, NULL);
451f449c9e5SMao Zhongyi             if (!ppkt) {
452f449c9e5SMao Zhongyi                 goto pri;
453f449c9e5SMao Zhongyi             } else {
454f449c9e5SMao Zhongyi                 goto sec;
455f449c9e5SMao Zhongyi             }
456f449c9e5SMao Zhongyi         }
457f449c9e5SMao Zhongyi         if (!ppkt) {
458a5f038e2SZhang Chen             g_queue_push_tail(&conn->secondary_list, spkt);
459f449c9e5SMao Zhongyi             goto pri;
460f449c9e5SMao Zhongyi         }
461f449c9e5SMao Zhongyi     }
462f449c9e5SMao Zhongyi 
463f449c9e5SMao Zhongyi     if (colo_mark_tcp_pkt(ppkt, spkt, &mark, min_ack)) {
464f449c9e5SMao Zhongyi         trace_colo_compare_tcp_info("pri",
465f449c9e5SMao Zhongyi                                     ppkt->tcp_seq, ppkt->tcp_ack,
466f449c9e5SMao Zhongyi                                     ppkt->header_size, ppkt->payload_size,
467f449c9e5SMao Zhongyi                                     ppkt->offset, ppkt->flags);
468f449c9e5SMao Zhongyi 
469f449c9e5SMao Zhongyi         trace_colo_compare_tcp_info("sec",
470f449c9e5SMao Zhongyi                                     spkt->tcp_seq, spkt->tcp_ack,
471f449c9e5SMao Zhongyi                                     spkt->header_size, spkt->payload_size,
472f449c9e5SMao Zhongyi                                     spkt->offset, spkt->flags);
473f449c9e5SMao Zhongyi 
474f449c9e5SMao Zhongyi         if (mark == COLO_COMPARE_FREE_PRIMARY) {
475f449c9e5SMao Zhongyi             conn->compare_seq = ppkt->seq_end;
476f449c9e5SMao Zhongyi             colo_release_primary_pkt(s, ppkt);
477a5f038e2SZhang Chen             g_queue_push_tail(&conn->secondary_list, spkt);
478f449c9e5SMao Zhongyi             goto pri;
47945b9e8c3SLi Zhijian         } else if (mark == COLO_COMPARE_FREE_SECONDARY) {
480f449c9e5SMao Zhongyi             conn->compare_seq = spkt->seq_end;
481f449c9e5SMao Zhongyi             packet_destroy(spkt, NULL);
482f449c9e5SMao Zhongyi             goto sec;
48345b9e8c3SLi Zhijian         } else if (mark == (COLO_COMPARE_FREE_PRIMARY | COLO_COMPARE_FREE_SECONDARY)) {
484f449c9e5SMao Zhongyi             conn->compare_seq = ppkt->seq_end;
485f449c9e5SMao Zhongyi             colo_release_primary_pkt(s, ppkt);
486f449c9e5SMao Zhongyi             packet_destroy(spkt, NULL);
487f449c9e5SMao Zhongyi             goto pri;
488f449c9e5SMao Zhongyi         }
489f449c9e5SMao Zhongyi     } else {
490a5f038e2SZhang Chen         g_queue_push_tail(&conn->primary_list, ppkt);
491a5f038e2SZhang Chen         g_queue_push_tail(&conn->secondary_list, spkt);
492f583dca9SZhang Chen 
4938c8ed038SRoman Bolshakov #ifdef DEBUG_COLO_PACKETS
494842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare ppkt", ppkt->data, ppkt->size);
495842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare spkt", spkt->data, spkt->size);
4968c8ed038SRoman Bolshakov #endif
497f449c9e5SMao Zhongyi 
4981d09f700SZhang Chen         colo_compare_inconsistency_notify(s);
499f449c9e5SMao Zhongyi     }
500f4b61836SZhang Chen }
501f4b61836SZhang Chen 
502f4b61836SZhang Chen 
503f4b61836SZhang Chen /*
504f4b61836SZhang Chen  * Called from the compare thread on the primary
505f4b61836SZhang Chen  * for compare udp packet
506f4b61836SZhang Chen  */
colo_packet_compare_udp(Packet * spkt,Packet * ppkt)507f4b61836SZhang Chen static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
508f4b61836SZhang Chen {
5099394133fSMao Zhongyi     uint16_t network_header_length = ppkt->ip->ip_hl << 2;
5109394133fSMao Zhongyi     uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
511f4b61836SZhang Chen 
512f4b61836SZhang Chen     trace_colo_compare_main("compare udp");
5132ad7ca4cSZhang Chen 
5146efeb328SZhang Chen     /*
5156efeb328SZhang Chen      * Because of ppkt and spkt are both in the same connection,
5166efeb328SZhang Chen      * The ppkt's src ip, dst ip, src port, dst port, ip_proto all are
5176efeb328SZhang Chen      * same with spkt. In addition, IP header's Identification is a random
5186efeb328SZhang Chen      * field, we can handle it in IP fragmentation function later.
5196efeb328SZhang Chen      * COLO just concern the response net packet payload from primary guest
5206efeb328SZhang Chen      * and secondary guest are same or not, So we ignored all IP header include
5216efeb328SZhang Chen      * other field like TOS,TTL,IP Checksum. we only need to compare
5226efeb328SZhang Chen      * the ip payload here.
5236efeb328SZhang Chen      */
5249394133fSMao Zhongyi     if (ppkt->size != spkt->size) {
5259394133fSMao Zhongyi         trace_colo_compare_main("UDP: payload size of packets are different");
5269394133fSMao Zhongyi         return -1;
5279394133fSMao Zhongyi     }
5289394133fSMao Zhongyi     if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
5299394133fSMao Zhongyi                                     ppkt->size - offset)) {
530f4b61836SZhang Chen         trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size);
531f4b61836SZhang Chen         trace_colo_compare_udp_miscompare("Secondary pkt size", spkt->size);
5328c8ed038SRoman Bolshakov #ifdef DEBUG_COLO_PACKETS
533842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare pri pkt", ppkt->data, ppkt->size);
534842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare sec pkt", spkt->data, spkt->size);
5358c8ed038SRoman Bolshakov #endif
5369394133fSMao Zhongyi         return -1;
5379394133fSMao Zhongyi     } else {
5389394133fSMao Zhongyi         return 0;
539f4b61836SZhang Chen     }
540f4b61836SZhang Chen }
541f4b61836SZhang Chen 
542f4b61836SZhang Chen /*
543f4b61836SZhang Chen  * Called from the compare thread on the primary
544f4b61836SZhang Chen  * for compare icmp packet
545f4b61836SZhang Chen  */
colo_packet_compare_icmp(Packet * spkt,Packet * ppkt)546f4b61836SZhang Chen static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
547f4b61836SZhang Chen {
5489394133fSMao Zhongyi     uint16_t network_header_length = ppkt->ip->ip_hl << 2;
5499394133fSMao Zhongyi     uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
5506efeb328SZhang Chen 
551f4b61836SZhang Chen     trace_colo_compare_main("compare icmp");
552f4b61836SZhang Chen 
5536efeb328SZhang Chen     /*
5546efeb328SZhang Chen      * Because of ppkt and spkt are both in the same connection,
5556efeb328SZhang Chen      * The ppkt's src ip, dst ip, src port, dst port, ip_proto all are
5566efeb328SZhang Chen      * same with spkt. In addition, IP header's Identification is a random
5576efeb328SZhang Chen      * field, we can handle it in IP fragmentation function later.
5586efeb328SZhang Chen      * COLO just concern the response net packet payload from primary guest
5596efeb328SZhang Chen      * and secondary guest are same or not, So we ignored all IP header include
5606efeb328SZhang Chen      * other field like TOS,TTL,IP Checksum. we only need to compare
5616efeb328SZhang Chen      * the ip payload here.
5626efeb328SZhang Chen      */
5639394133fSMao Zhongyi     if (ppkt->size != spkt->size) {
5649394133fSMao Zhongyi         trace_colo_compare_main("ICMP: payload size of packets are different");
5659394133fSMao Zhongyi         return -1;
5669394133fSMao Zhongyi     }
5679394133fSMao Zhongyi     if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
5689394133fSMao Zhongyi                                     ppkt->size - offset)) {
569f4b61836SZhang Chen         trace_colo_compare_icmp_miscompare("primary pkt size",
570f4b61836SZhang Chen                                            ppkt->size);
571f4b61836SZhang Chen         trace_colo_compare_icmp_miscompare("Secondary pkt size",
572f4b61836SZhang Chen                                            spkt->size);
5738c8ed038SRoman Bolshakov #ifdef DEBUG_COLO_PACKETS
574842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare pri pkt", ppkt->data, ppkt->size);
575842038f5SPeter Maydell         qemu_hexdump(stderr, "colo-compare sec pkt", spkt->data, spkt->size);
5768c8ed038SRoman Bolshakov #endif
577f4b61836SZhang Chen         return -1;
578f4b61836SZhang Chen     } else {
579f4b61836SZhang Chen         return 0;
580f4b61836SZhang Chen     }
581f4b61836SZhang Chen }
582f4b61836SZhang Chen 
583f4b61836SZhang Chen /*
584f4b61836SZhang Chen  * Called from the compare thread on the primary
585f4b61836SZhang Chen  * for compare other packet
586f4b61836SZhang Chen  */
colo_packet_compare_other(Packet * spkt,Packet * ppkt)587f4b61836SZhang Chen static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
588f4b61836SZhang Chen {
5899394133fSMao Zhongyi     uint16_t offset = ppkt->vnet_hdr_len;
5909394133fSMao Zhongyi 
591f4b61836SZhang Chen     trace_colo_compare_main("compare other");
5929394133fSMao Zhongyi     if (ppkt->size != spkt->size) {
5939394133fSMao Zhongyi         trace_colo_compare_main("Other: payload size of packets are different");
5949394133fSMao Zhongyi         return -1;
5959394133fSMao Zhongyi     }
5969394133fSMao Zhongyi     return colo_compare_packet_payload(ppkt, spkt, offset, offset,
5979394133fSMao Zhongyi                                        ppkt->size - offset);
5980682e15bSZhang Chen }
5990682e15bSZhang Chen 
colo_old_packet_check_one(Packet * pkt,int64_t * check_time)6000682e15bSZhang Chen static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
6010682e15bSZhang Chen {
6020682e15bSZhang Chen     int64_t now = qemu_clock_get_ms(QEMU_CLOCK_HOST);
6030682e15bSZhang Chen 
6040682e15bSZhang Chen     if ((now - pkt->creation_ms) > (*check_time)) {
6050682e15bSZhang Chen         trace_colo_old_packet_check_found(pkt->creation_ms);
6060682e15bSZhang Chen         return 0;
6070682e15bSZhang Chen     } else {
6080682e15bSZhang Chen         return 1;
6090682e15bSZhang Chen     }
6100682e15bSZhang Chen }
6110682e15bSZhang Chen 
colo_compare_register_notifier(Notifier * notify)612dccd0313SZhang Chen void colo_compare_register_notifier(Notifier *notify)
613dccd0313SZhang Chen {
614dccd0313SZhang Chen     notifier_list_add(&colo_compare_notifiers, notify);
615dccd0313SZhang Chen }
616dccd0313SZhang Chen 
colo_compare_unregister_notifier(Notifier * notify)617dccd0313SZhang Chen void colo_compare_unregister_notifier(Notifier *notify)
618dccd0313SZhang Chen {
619dccd0313SZhang Chen     notifier_remove(notify);
620dccd0313SZhang Chen }
621dccd0313SZhang Chen 
colo_old_packet_check_one_conn(Connection * conn,CompareState * s)622d25a7dabSZhang Chen static int colo_old_packet_check_one_conn(Connection *conn,
6231d09f700SZhang Chen                                           CompareState *s)
6240682e15bSZhang Chen {
62517475df2SZhang Chen     if (!g_queue_is_empty(&conn->primary_list)) {
62617475df2SZhang Chen         if (g_queue_find_custom(&conn->primary_list,
6279cc43c94SZhang Chen                                 &s->compare_timeout,
62817475df2SZhang Chen                                 (GCompareFunc)colo_old_packet_check_one))
62917475df2SZhang Chen             goto out;
63017475df2SZhang Chen     }
6310682e15bSZhang Chen 
63217475df2SZhang Chen     if (!g_queue_is_empty(&conn->secondary_list)) {
63317475df2SZhang Chen         if (g_queue_find_custom(&conn->secondary_list,
63417475df2SZhang Chen                                 &s->compare_timeout,
63517475df2SZhang Chen                                 (GCompareFunc)colo_old_packet_check_one))
63617475df2SZhang Chen             goto out;
6370682e15bSZhang Chen     }
638d25a7dabSZhang Chen 
639d25a7dabSZhang Chen     return 1;
64017475df2SZhang Chen 
64117475df2SZhang Chen out:
64217475df2SZhang Chen     /* Do checkpoint will flush old packet */
64317475df2SZhang Chen     colo_compare_inconsistency_notify(s);
64417475df2SZhang Chen     return 0;
6450682e15bSZhang Chen }
6460682e15bSZhang Chen 
6470682e15bSZhang Chen /*
6480682e15bSZhang Chen  * Look for old packets that the secondary hasn't matched,
6490682e15bSZhang Chen  * if we have some then we have to checkpoint to wake
6500682e15bSZhang Chen  * the secondary up.
6510682e15bSZhang Chen  */
colo_old_packet_check(void * opaque)6520682e15bSZhang Chen static void colo_old_packet_check(void *opaque)
6530682e15bSZhang Chen {
6540682e15bSZhang Chen     CompareState *s = opaque;
6550682e15bSZhang Chen 
656d25a7dabSZhang Chen     /*
657d25a7dabSZhang Chen      * If we find one old packet, stop finding job and notify
658d25a7dabSZhang Chen      * COLO frame do checkpoint.
659d25a7dabSZhang Chen      */
6601d09f700SZhang Chen     g_queue_find_custom(&s->conn_list, s,
661d25a7dabSZhang Chen                         (GCompareFunc)colo_old_packet_check_one_conn);
6620682e15bSZhang Chen }
6630682e15bSZhang Chen 
colo_compare_packet(CompareState * s,Connection * conn,int (* HandlePacket)(Packet * spkt,Packet * ppkt))664f449c9e5SMao Zhongyi static void colo_compare_packet(CompareState *s, Connection *conn,
665f449c9e5SMao Zhongyi                                 int (*HandlePacket)(Packet *spkt,
666f449c9e5SMao Zhongyi                                 Packet *ppkt))
6670682e15bSZhang Chen {
6680682e15bSZhang Chen     Packet *pkt = NULL;
6690682e15bSZhang Chen     GList *result = NULL;
6700682e15bSZhang Chen 
6710682e15bSZhang Chen     while (!g_queue_is_empty(&conn->primary_list) &&
6720682e15bSZhang Chen            !g_queue_is_empty(&conn->secondary_list)) {
673a5f038e2SZhang Chen         pkt = g_queue_pop_tail(&conn->primary_list);
6740682e15bSZhang Chen         result = g_queue_find_custom(&conn->secondary_list,
675f449c9e5SMao Zhongyi                  pkt, (GCompareFunc)HandlePacket);
6760682e15bSZhang Chen 
6770682e15bSZhang Chen         if (result) {
678f449c9e5SMao Zhongyi             colo_release_primary_pkt(s, pkt);
6799162ed66SLukas Straub             packet_destroy(result->data, NULL);
680739128e4SLukas Straub             g_queue_delete_link(&conn->secondary_list, result);
6810682e15bSZhang Chen         } else {
6820682e15bSZhang Chen             /*
6830682e15bSZhang Chen              * If one packet arrive late, the secondary_list or
6840682e15bSZhang Chen              * primary_list will be empty, so we can't compare it
685dccd0313SZhang Chen              * until next comparison. If the packets in the list are
686dccd0313SZhang Chen              * timeout, it will trigger a checkpoint request.
6870682e15bSZhang Chen              */
6880682e15bSZhang Chen             trace_colo_compare_main("packet different");
689a5f038e2SZhang Chen             g_queue_push_tail(&conn->primary_list, pkt);
6901d09f700SZhang Chen 
6911d09f700SZhang Chen             colo_compare_inconsistency_notify(s);
6920682e15bSZhang Chen             break;
6930682e15bSZhang Chen         }
6940682e15bSZhang Chen     }
6950682e15bSZhang Chen }
6960682e15bSZhang Chen 
697f449c9e5SMao Zhongyi /*
698f449c9e5SMao Zhongyi  * Called from the compare thread on the primary
699f449c9e5SMao Zhongyi  * for compare packet with secondary list of the
700f449c9e5SMao Zhongyi  * specified connection when a new packet was
701f449c9e5SMao Zhongyi  * queued to it.
702f449c9e5SMao Zhongyi  */
colo_compare_connection(void * opaque,void * user_data)703f449c9e5SMao Zhongyi static void colo_compare_connection(void *opaque, void *user_data)
704f449c9e5SMao Zhongyi {
705f449c9e5SMao Zhongyi     CompareState *s = user_data;
706f449c9e5SMao Zhongyi     Connection *conn = opaque;
707f449c9e5SMao Zhongyi 
708f449c9e5SMao Zhongyi     switch (conn->ip_proto) {
709f449c9e5SMao Zhongyi     case IPPROTO_TCP:
710f449c9e5SMao Zhongyi         colo_compare_tcp(s, conn);
711f449c9e5SMao Zhongyi         break;
712f449c9e5SMao Zhongyi     case IPPROTO_UDP:
713f449c9e5SMao Zhongyi         colo_compare_packet(s, conn, colo_packet_compare_udp);
714f449c9e5SMao Zhongyi         break;
715f449c9e5SMao Zhongyi     case IPPROTO_ICMP:
716f449c9e5SMao Zhongyi         colo_compare_packet(s, conn, colo_packet_compare_icmp);
717f449c9e5SMao Zhongyi         break;
718f449c9e5SMao Zhongyi     default:
719f449c9e5SMao Zhongyi         colo_compare_packet(s, conn, colo_packet_compare_other);
720f449c9e5SMao Zhongyi         break;
721f449c9e5SMao Zhongyi     }
722f449c9e5SMao Zhongyi }
723f449c9e5SMao Zhongyi 
_compare_chr_send(void * opaque)7249c55fe94SLukas Straub static void coroutine_fn _compare_chr_send(void *opaque)
7259c55fe94SLukas Straub {
7269c55fe94SLukas Straub     SendCo *sendco = opaque;
7279c55fe94SLukas Straub     CompareState *s = sendco->s;
7289c55fe94SLukas Straub     int ret = 0;
7299c55fe94SLukas Straub 
7309c55fe94SLukas Straub     while (!g_queue_is_empty(&sendco->send_list)) {
7319c55fe94SLukas Straub         SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
7329c55fe94SLukas Straub         uint32_t len = htonl(entry->size);
7339c55fe94SLukas Straub 
7349c55fe94SLukas Straub         ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
7359c55fe94SLukas Straub 
7369c55fe94SLukas Straub         if (ret != sizeof(len)) {
7379c55fe94SLukas Straub             g_free(entry->buf);
7389c55fe94SLukas Straub             g_slice_free(SendEntry, entry);
7399c55fe94SLukas Straub             goto err;
7409c55fe94SLukas Straub         }
7419c55fe94SLukas Straub 
7429c55fe94SLukas Straub         if (!sendco->notify_remote_frame && s->vnet_hdr) {
7439c55fe94SLukas Straub             /*
7449c55fe94SLukas Straub              * We send vnet header len make other module(like filter-redirector)
7459c55fe94SLukas Straub              * know how to parse net packet correctly.
7469c55fe94SLukas Straub              */
7479c55fe94SLukas Straub             len = htonl(entry->vnet_hdr_len);
7489c55fe94SLukas Straub 
7499c55fe94SLukas Straub             ret = qemu_chr_fe_write_all(sendco->chr,
7509c55fe94SLukas Straub                                         (uint8_t *)&len,
7519c55fe94SLukas Straub                                         sizeof(len));
7529c55fe94SLukas Straub 
7539c55fe94SLukas Straub             if (ret != sizeof(len)) {
7549c55fe94SLukas Straub                 g_free(entry->buf);
7559c55fe94SLukas Straub                 g_slice_free(SendEntry, entry);
7569c55fe94SLukas Straub                 goto err;
7579c55fe94SLukas Straub             }
7589c55fe94SLukas Straub         }
7599c55fe94SLukas Straub 
7609c55fe94SLukas Straub         ret = qemu_chr_fe_write_all(sendco->chr,
7619c55fe94SLukas Straub                                     (uint8_t *)entry->buf,
7629c55fe94SLukas Straub                                     entry->size);
7639c55fe94SLukas Straub 
7649c55fe94SLukas Straub         if (ret != entry->size) {
7659c55fe94SLukas Straub             g_free(entry->buf);
7669c55fe94SLukas Straub             g_slice_free(SendEntry, entry);
7679c55fe94SLukas Straub             goto err;
7689c55fe94SLukas Straub         }
7699c55fe94SLukas Straub 
7709c55fe94SLukas Straub         g_free(entry->buf);
7719c55fe94SLukas Straub         g_slice_free(SendEntry, entry);
7729c55fe94SLukas Straub     }
7739c55fe94SLukas Straub 
7749c55fe94SLukas Straub     sendco->ret = 0;
7759c55fe94SLukas Straub     goto out;
7769c55fe94SLukas Straub 
7779c55fe94SLukas Straub err:
7789c55fe94SLukas Straub     while (!g_queue_is_empty(&sendco->send_list)) {
7799c55fe94SLukas Straub         SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
7809c55fe94SLukas Straub         g_free(entry->buf);
7819c55fe94SLukas Straub         g_slice_free(SendEntry, entry);
7829c55fe94SLukas Straub     }
7839c55fe94SLukas Straub     sendco->ret = ret < 0 ? ret : -EIO;
7849c55fe94SLukas Straub out:
7859c55fe94SLukas Straub     sendco->co = NULL;
7869c55fe94SLukas Straub     sendco->done = true;
7879c55fe94SLukas Straub     aio_wait_kick();
7889c55fe94SLukas Straub }
7899c55fe94SLukas Straub 
compare_chr_send(CompareState * s,uint8_t * buf,uint32_t size,uint32_t vnet_hdr_len,bool notify_remote_frame,bool zero_copy)7903037e7a5SZhang Chen static int compare_chr_send(CompareState *s,
7919c55fe94SLukas Straub                             uint8_t *buf,
792aa3a7032SZhang Chen                             uint32_t size,
79330685c00SZhang Chen                             uint32_t vnet_hdr_len,
7949c55fe94SLukas Straub                             bool notify_remote_frame,
7959c55fe94SLukas Straub                             bool zero_copy)
79659509ec1SZhang Chen {
7979c55fe94SLukas Straub     SendCo *sendco;
7989c55fe94SLukas Straub     SendEntry *entry;
7999c55fe94SLukas Straub 
8009c55fe94SLukas Straub     if (notify_remote_frame) {
8019c55fe94SLukas Straub         sendco = &s->notify_sendco;
8029c55fe94SLukas Straub     } else {
8039c55fe94SLukas Straub         sendco = &s->out_sendco;
8049c55fe94SLukas Straub     }
80559509ec1SZhang Chen 
80659509ec1SZhang Chen     if (!size) {
8070656fbc7SZhang Chen         return -1;
80859509ec1SZhang Chen     }
80959509ec1SZhang Chen 
8109c55fe94SLukas Straub     entry = g_slice_new(SendEntry);
8119c55fe94SLukas Straub     entry->size = size;
8129c55fe94SLukas Straub     entry->vnet_hdr_len = vnet_hdr_len;
8139c55fe94SLukas Straub     if (zero_copy) {
8149c55fe94SLukas Straub         entry->buf = buf;
81530685c00SZhang Chen     } else {
8169c55fe94SLukas Straub         entry->buf = g_malloc(size);
8179c55fe94SLukas Straub         memcpy(entry->buf, buf, size);
81830685c00SZhang Chen     }
819a5f038e2SZhang Chen     g_queue_push_tail(&sendco->send_list, entry);
82030685c00SZhang Chen 
8219c55fe94SLukas Straub     if (sendco->done) {
8229c55fe94SLukas Straub         sendco->co = qemu_coroutine_create(_compare_chr_send, sendco);
8239c55fe94SLukas Straub         sendco->done = false;
8249c55fe94SLukas Straub         qemu_coroutine_enter(sendco->co);
8259c55fe94SLukas Straub         if (sendco->done) {
8269c55fe94SLukas Straub             /* report early errors */
8279c55fe94SLukas Straub             return sendco->ret;
828aa3a7032SZhang Chen         }
829aa3a7032SZhang Chen     }
830aa3a7032SZhang Chen 
8319c55fe94SLukas Straub     /* assume success */
83259509ec1SZhang Chen     return 0;
83359509ec1SZhang Chen }
83459509ec1SZhang Chen 
compare_chr_can_read(void * opaque)8350682e15bSZhang Chen static int compare_chr_can_read(void *opaque)
8360682e15bSZhang Chen {
8370682e15bSZhang Chen     return COMPARE_READ_LEN_MAX;
8380682e15bSZhang Chen }
8390682e15bSZhang Chen 
8400682e15bSZhang Chen /*
8410682e15bSZhang Chen  * Called from the main thread on the primary for packets
8420682e15bSZhang Chen  * arriving over the socket from the primary.
8430682e15bSZhang Chen  */
compare_pri_chr_in(void * opaque,const uint8_t * buf,int size)8440682e15bSZhang Chen static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
8450682e15bSZhang Chen {
8460682e15bSZhang Chen     CompareState *s = COLO_COMPARE(opaque);
8470682e15bSZhang Chen     int ret;
8480682e15bSZhang Chen 
8490682e15bSZhang Chen     ret = net_fill_rstate(&s->pri_rs, buf, size);
8500682e15bSZhang Chen     if (ret == -1) {
85181517ba3SAnton Nefedov         qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL,
85239ab61c6SMarc-André Lureau                                  NULL, NULL, true);
8530682e15bSZhang Chen         error_report("colo-compare primary_in error");
8540682e15bSZhang Chen     }
8550682e15bSZhang Chen }
8560682e15bSZhang Chen 
8570682e15bSZhang Chen /*
8580682e15bSZhang Chen  * Called from the main thread on the primary for packets
8590682e15bSZhang Chen  * arriving over the socket from the secondary.
8600682e15bSZhang Chen  */
compare_sec_chr_in(void * opaque,const uint8_t * buf,int size)8610682e15bSZhang Chen static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
8620682e15bSZhang Chen {
8630682e15bSZhang Chen     CompareState *s = COLO_COMPARE(opaque);
8640682e15bSZhang Chen     int ret;
8650682e15bSZhang Chen 
8660682e15bSZhang Chen     ret = net_fill_rstate(&s->sec_rs, buf, size);
8670682e15bSZhang Chen     if (ret == -1) {
86881517ba3SAnton Nefedov         qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL,
86939ab61c6SMarc-André Lureau                                  NULL, NULL, true);
8700682e15bSZhang Chen         error_report("colo-compare secondary_in error");
8710682e15bSZhang Chen     }
8720682e15bSZhang Chen }
8730682e15bSZhang Chen 
compare_notify_chr(void * opaque,const uint8_t * buf,int size)87413025feeSZhang Chen static void compare_notify_chr(void *opaque, const uint8_t *buf, int size)
87513025feeSZhang Chen {
87613025feeSZhang Chen     CompareState *s = COLO_COMPARE(opaque);
87713025feeSZhang Chen     int ret;
87813025feeSZhang Chen 
87913025feeSZhang Chen     ret = net_fill_rstate(&s->notify_rs, buf, size);
88013025feeSZhang Chen     if (ret == -1) {
88113025feeSZhang Chen         qemu_chr_fe_set_handlers(&s->chr_notify_dev, NULL, NULL, NULL, NULL,
88213025feeSZhang Chen                                  NULL, NULL, true);
88313025feeSZhang Chen         error_report("colo-compare notify_dev error");
88413025feeSZhang Chen     }
88513025feeSZhang Chen }
88613025feeSZhang Chen 
88766d2a242Szhanghailiang /*
88866d2a242Szhanghailiang  * Check old packet regularly so it can watch for any packets
88966d2a242Szhanghailiang  * that the secondary hasn't produced equivalents of.
89066d2a242Szhanghailiang  */
check_old_packet_regular(void * opaque)891dd321ecfSWang Yong static void check_old_packet_regular(void *opaque)
89266d2a242Szhanghailiang {
89366d2a242Szhanghailiang     CompareState *s = opaque;
89466d2a242Szhanghailiang 
89566d2a242Szhanghailiang     /* if have old packet we will notify checkpoint */
89666d2a242Szhanghailiang     colo_old_packet_check(s);
897ec081984SZhang Chen     timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
898cca35ac4SZhang Chen               s->expired_scan_cycle);
89966d2a242Szhanghailiang }
90066d2a242Szhanghailiang 
9010ffcece3SZhang Chen /* Public API, Used for COLO frame to notify compare event */
colo_notify_compares_event(void * opaque,int event,Error ** errp)9020ffcece3SZhang Chen void colo_notify_compares_event(void *opaque, int event, Error **errp)
9030ffcece3SZhang Chen {
9040ffcece3SZhang Chen     CompareState *s;
90545942b79SLukas Straub     qemu_mutex_lock(&colo_compare_mutex);
90645942b79SLukas Straub 
90745942b79SLukas Straub     if (!colo_compare_active) {
90845942b79SLukas Straub         qemu_mutex_unlock(&colo_compare_mutex);
90945942b79SLukas Straub         return;
91045942b79SLukas Straub     }
9110ffcece3SZhang Chen 
9120ffcece3SZhang Chen     qemu_mutex_lock(&event_mtx);
9130ffcece3SZhang Chen     QTAILQ_FOREACH(s, &net_compares, next) {
9140ffcece3SZhang Chen         s->event = event;
9150ffcece3SZhang Chen         qemu_bh_schedule(s->event_bh);
9160ffcece3SZhang Chen         event_unhandled_count++;
9170ffcece3SZhang Chen     }
9180ffcece3SZhang Chen     /* Wait all compare threads to finish handling this event */
9190ffcece3SZhang Chen     while (event_unhandled_count > 0) {
9200ffcece3SZhang Chen         qemu_cond_wait(&event_complete_cond, &event_mtx);
9210ffcece3SZhang Chen     }
9220ffcece3SZhang Chen 
9230ffcece3SZhang Chen     qemu_mutex_unlock(&event_mtx);
92445942b79SLukas Straub     qemu_mutex_unlock(&colo_compare_mutex);
9250ffcece3SZhang Chen }
9260ffcece3SZhang Chen 
colo_compare_timer_init(CompareState * s)927dd321ecfSWang Yong static void colo_compare_timer_init(CompareState *s)
9280682e15bSZhang Chen {
929dd321ecfSWang Yong     AioContext *ctx = iothread_get_aio_context(s->iothread);
9300682e15bSZhang Chen 
931ec081984SZhang Chen     s->packet_check_timer = aio_timer_new(ctx, QEMU_CLOCK_HOST,
932dd321ecfSWang Yong                                 SCALE_MS, check_old_packet_regular,
933dd321ecfSWang Yong                                 s);
934ec081984SZhang Chen     timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
935cca35ac4SZhang Chen               s->expired_scan_cycle);
936dd321ecfSWang Yong }
937dd321ecfSWang Yong 
colo_compare_timer_del(CompareState * s)938dd321ecfSWang Yong static void colo_compare_timer_del(CompareState *s)
939dd321ecfSWang Yong {
940dd321ecfSWang Yong     if (s->packet_check_timer) {
941dd321ecfSWang Yong         timer_free(s->packet_check_timer);
942dd321ecfSWang Yong         s->packet_check_timer = NULL;
943dd321ecfSWang Yong     }
944dd321ecfSWang Yong  }
945dd321ecfSWang Yong 
9460ffcece3SZhang Chen static void colo_flush_packets(void *opaque, void *user_data);
9470ffcece3SZhang Chen 
colo_compare_handle_event(void * opaque)9480ffcece3SZhang Chen static void colo_compare_handle_event(void *opaque)
9490ffcece3SZhang Chen {
9500ffcece3SZhang Chen     CompareState *s = opaque;
9510ffcece3SZhang Chen 
9520ffcece3SZhang Chen     switch (s->event) {
9530ffcece3SZhang Chen     case COLO_EVENT_CHECKPOINT:
9540ffcece3SZhang Chen         g_queue_foreach(&s->conn_list, colo_flush_packets, s);
9550ffcece3SZhang Chen         break;
9560ffcece3SZhang Chen     case COLO_EVENT_FAILOVER:
9570ffcece3SZhang Chen         break;
9580ffcece3SZhang Chen     default:
9590ffcece3SZhang Chen         break;
9600ffcece3SZhang Chen     }
9610ffcece3SZhang Chen 
9620ffcece3SZhang Chen     qemu_mutex_lock(&event_mtx);
96378e4f446SLukas Straub     assert(event_unhandled_count > 0);
9640ffcece3SZhang Chen     event_unhandled_count--;
9650ffcece3SZhang Chen     qemu_cond_broadcast(&event_complete_cond);
9660ffcece3SZhang Chen     qemu_mutex_unlock(&event_mtx);
9670ffcece3SZhang Chen }
9680ffcece3SZhang Chen 
colo_compare_iothread(CompareState * s)969dd321ecfSWang Yong static void colo_compare_iothread(CompareState *s)
970dd321ecfSWang Yong {
9715893c738SLukas Straub     AioContext *ctx = iothread_get_aio_context(s->iothread);
972dd321ecfSWang Yong     object_ref(OBJECT(s->iothread));
973dd321ecfSWang Yong     s->worker_context = iothread_get_g_main_context(s->iothread);
9740682e15bSZhang Chen 
9755345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
97681517ba3SAnton Nefedov                              compare_pri_chr_in, NULL, NULL,
97781517ba3SAnton Nefedov                              s, s->worker_context, true);
9785345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
97981517ba3SAnton Nefedov                              compare_sec_chr_in, NULL, NULL,
98081517ba3SAnton Nefedov                              s, s->worker_context, true);
98113025feeSZhang Chen     if (s->notify_dev) {
98213025feeSZhang Chen         qemu_chr_fe_set_handlers(&s->chr_notify_dev, compare_chr_can_read,
98313025feeSZhang Chen                                  compare_notify_chr, NULL, NULL,
98413025feeSZhang Chen                                  s, s->worker_context, true);
98513025feeSZhang Chen     }
9860682e15bSZhang Chen 
987dd321ecfSWang Yong     colo_compare_timer_init(s);
9885893c738SLukas Straub     s->event_bh = aio_bh_new(ctx, colo_compare_handle_event, s);
9890682e15bSZhang Chen }
9900682e15bSZhang Chen 
compare_get_pri_indev(Object * obj,Error ** errp)9917dce4e6fSZhang Chen static char *compare_get_pri_indev(Object *obj, Error **errp)
9927dce4e6fSZhang Chen {
9937dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
9947dce4e6fSZhang Chen 
9957dce4e6fSZhang Chen     return g_strdup(s->pri_indev);
9967dce4e6fSZhang Chen }
9977dce4e6fSZhang Chen 
compare_set_pri_indev(Object * obj,const char * value,Error ** errp)9987dce4e6fSZhang Chen static void compare_set_pri_indev(Object *obj, const char *value, Error **errp)
9997dce4e6fSZhang Chen {
10007dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
10017dce4e6fSZhang Chen 
10027dce4e6fSZhang Chen     g_free(s->pri_indev);
10037dce4e6fSZhang Chen     s->pri_indev = g_strdup(value);
10047dce4e6fSZhang Chen }
10057dce4e6fSZhang Chen 
compare_get_sec_indev(Object * obj,Error ** errp)10067dce4e6fSZhang Chen static char *compare_get_sec_indev(Object *obj, Error **errp)
10077dce4e6fSZhang Chen {
10087dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
10097dce4e6fSZhang Chen 
10107dce4e6fSZhang Chen     return g_strdup(s->sec_indev);
10117dce4e6fSZhang Chen }
10127dce4e6fSZhang Chen 
compare_set_sec_indev(Object * obj,const char * value,Error ** errp)10137dce4e6fSZhang Chen static void compare_set_sec_indev(Object *obj, const char *value, Error **errp)
10147dce4e6fSZhang Chen {
10157dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
10167dce4e6fSZhang Chen 
10177dce4e6fSZhang Chen     g_free(s->sec_indev);
10187dce4e6fSZhang Chen     s->sec_indev = g_strdup(value);
10197dce4e6fSZhang Chen }
10207dce4e6fSZhang Chen 
compare_get_outdev(Object * obj,Error ** errp)10217dce4e6fSZhang Chen static char *compare_get_outdev(Object *obj, Error **errp)
10227dce4e6fSZhang Chen {
10237dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
10247dce4e6fSZhang Chen 
10257dce4e6fSZhang Chen     return g_strdup(s->outdev);
10267dce4e6fSZhang Chen }
10277dce4e6fSZhang Chen 
compare_set_outdev(Object * obj,const char * value,Error ** errp)10287dce4e6fSZhang Chen static void compare_set_outdev(Object *obj, const char *value, Error **errp)
10297dce4e6fSZhang Chen {
10307dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
10317dce4e6fSZhang Chen 
10327dce4e6fSZhang Chen     g_free(s->outdev);
10337dce4e6fSZhang Chen     s->outdev = g_strdup(value);
10347dce4e6fSZhang Chen }
10357dce4e6fSZhang Chen 
compare_get_vnet_hdr(Object * obj,Error ** errp)1036aa3a7032SZhang Chen static bool compare_get_vnet_hdr(Object *obj, Error **errp)
1037aa3a7032SZhang Chen {
1038aa3a7032SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1039aa3a7032SZhang Chen 
1040aa3a7032SZhang Chen     return s->vnet_hdr;
1041aa3a7032SZhang Chen }
1042aa3a7032SZhang Chen 
compare_set_vnet_hdr(Object * obj,bool value,Error ** errp)1043aa3a7032SZhang Chen static void compare_set_vnet_hdr(Object *obj,
1044aa3a7032SZhang Chen                                  bool value,
1045aa3a7032SZhang Chen                                  Error **errp)
1046aa3a7032SZhang Chen {
1047aa3a7032SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1048aa3a7032SZhang Chen 
1049aa3a7032SZhang Chen     s->vnet_hdr = value;
1050aa3a7032SZhang Chen }
1051aa3a7032SZhang Chen 
compare_get_notify_dev(Object * obj,Error ** errp)1052cf6af766SZhang Chen static char *compare_get_notify_dev(Object *obj, Error **errp)
1053cf6af766SZhang Chen {
1054cf6af766SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1055cf6af766SZhang Chen 
1056cf6af766SZhang Chen     return g_strdup(s->notify_dev);
1057cf6af766SZhang Chen }
1058cf6af766SZhang Chen 
compare_set_notify_dev(Object * obj,const char * value,Error ** errp)1059cf6af766SZhang Chen static void compare_set_notify_dev(Object *obj, const char *value, Error **errp)
1060cf6af766SZhang Chen {
1061cf6af766SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1062cf6af766SZhang Chen 
1063cf6af766SZhang Chen     g_free(s->notify_dev);
1064cf6af766SZhang Chen     s->notify_dev = g_strdup(value);
1065cf6af766SZhang Chen }
1066cf6af766SZhang Chen 
compare_get_timeout(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)10679cc43c94SZhang Chen static void compare_get_timeout(Object *obj, Visitor *v,
10689cc43c94SZhang Chen                                 const char *name, void *opaque,
10699cc43c94SZhang Chen                                 Error **errp)
10709cc43c94SZhang Chen {
10719cc43c94SZhang Chen     CompareState *s = COLO_COMPARE(obj);
10720c4266efSZhang Chen     uint64_t value = s->compare_timeout;
10739cc43c94SZhang Chen 
10740c4266efSZhang Chen     visit_type_uint64(v, name, &value, errp);
10759cc43c94SZhang Chen }
10769cc43c94SZhang Chen 
compare_set_timeout(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)10779cc43c94SZhang Chen static void compare_set_timeout(Object *obj, Visitor *v,
10789cc43c94SZhang Chen                                 const char *name, void *opaque,
10799cc43c94SZhang Chen                                 Error **errp)
10809cc43c94SZhang Chen {
10819cc43c94SZhang Chen     CompareState *s = COLO_COMPARE(obj);
10829cc43c94SZhang Chen     uint32_t value;
10839cc43c94SZhang Chen 
1084668f62ecSMarkus Armbruster     if (!visit_type_uint32(v, name, &value, errp)) {
1085dcfe4805SMarkus Armbruster         return;
10869cc43c94SZhang Chen     }
10879cc43c94SZhang Chen     if (!value) {
1088dcfe4805SMarkus Armbruster         error_setg(errp, "Property '%s.%s' requires a positive value",
10899cc43c94SZhang Chen                    object_get_typename(obj), name);
1090dcfe4805SMarkus Armbruster         return;
10919cc43c94SZhang Chen     }
10929cc43c94SZhang Chen     s->compare_timeout = value;
10939cc43c94SZhang Chen }
10949cc43c94SZhang Chen 
compare_get_expired_scan_cycle(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1095cca35ac4SZhang Chen static void compare_get_expired_scan_cycle(Object *obj, Visitor *v,
1096cca35ac4SZhang Chen                                            const char *name, void *opaque,
1097cca35ac4SZhang Chen                                            Error **errp)
1098cca35ac4SZhang Chen {
1099cca35ac4SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1100cca35ac4SZhang Chen     uint32_t value = s->expired_scan_cycle;
1101cca35ac4SZhang Chen 
1102cca35ac4SZhang Chen     visit_type_uint32(v, name, &value, errp);
1103cca35ac4SZhang Chen }
1104cca35ac4SZhang Chen 
compare_set_expired_scan_cycle(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1105cca35ac4SZhang Chen static void compare_set_expired_scan_cycle(Object *obj, Visitor *v,
1106cca35ac4SZhang Chen                                            const char *name, void *opaque,
1107cca35ac4SZhang Chen                                            Error **errp)
1108cca35ac4SZhang Chen {
1109cca35ac4SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1110cca35ac4SZhang Chen     uint32_t value;
1111cca35ac4SZhang Chen 
1112668f62ecSMarkus Armbruster     if (!visit_type_uint32(v, name, &value, errp)) {
1113dcfe4805SMarkus Armbruster         return;
1114cca35ac4SZhang Chen     }
1115cca35ac4SZhang Chen     if (!value) {
1116dcfe4805SMarkus Armbruster         error_setg(errp, "Property '%s.%s' requires a positive value",
1117cca35ac4SZhang Chen                    object_get_typename(obj), name);
1118dcfe4805SMarkus Armbruster         return;
1119cca35ac4SZhang Chen     }
1120cca35ac4SZhang Chen     s->expired_scan_cycle = value;
1121cca35ac4SZhang Chen }
1122cca35ac4SZhang Chen 
get_max_queue_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1123a2e5cb7aSZhang Chen static void get_max_queue_size(Object *obj, Visitor *v,
1124a2e5cb7aSZhang Chen                                const char *name, void *opaque,
1125a2e5cb7aSZhang Chen                                Error **errp)
1126a2e5cb7aSZhang Chen {
1127a2e5cb7aSZhang Chen     uint32_t value = max_queue_size;
1128a2e5cb7aSZhang Chen 
1129a2e5cb7aSZhang Chen     visit_type_uint32(v, name, &value, errp);
1130a2e5cb7aSZhang Chen }
1131a2e5cb7aSZhang Chen 
set_max_queue_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1132a2e5cb7aSZhang Chen static void set_max_queue_size(Object *obj, Visitor *v,
1133a2e5cb7aSZhang Chen                                const char *name, void *opaque,
1134a2e5cb7aSZhang Chen                                Error **errp)
1135a2e5cb7aSZhang Chen {
11360c4266efSZhang Chen     uint64_t value;
1137a2e5cb7aSZhang Chen 
1138d1c81c34SMarkus Armbruster     if (!visit_type_uint64(v, name, &value, errp)) {
1139d1c81c34SMarkus Armbruster         return;
1140a2e5cb7aSZhang Chen     }
1141a2e5cb7aSZhang Chen     if (!value) {
1142d1c81c34SMarkus Armbruster         error_setg(errp, "Property '%s.%s' requires a positive value",
1143a2e5cb7aSZhang Chen                    object_get_typename(obj), name);
1144d1c81c34SMarkus Armbruster         return;
1145a2e5cb7aSZhang Chen     }
1146a2e5cb7aSZhang Chen     max_queue_size = value;
1147a2e5cb7aSZhang Chen }
1148a2e5cb7aSZhang Chen 
compare_pri_rs_finalize(SocketReadState * pri_rs)11497dce4e6fSZhang Chen static void compare_pri_rs_finalize(SocketReadState *pri_rs)
11507dce4e6fSZhang Chen {
115159509ec1SZhang Chen     CompareState *s = container_of(pri_rs, CompareState, pri_rs);
11528ec14402SMao Zhongyi     Connection *conn = NULL;
115359509ec1SZhang Chen 
11548ec14402SMao Zhongyi     if (packet_enqueue(s, PRIMARY_IN, &conn)) {
115559509ec1SZhang Chen         trace_colo_compare_main("primary: unsupported packet in");
1156aa3a7032SZhang Chen         compare_chr_send(s,
1157aa3a7032SZhang Chen                          pri_rs->buf,
1158aa3a7032SZhang Chen                          pri_rs->packet_len,
115930685c00SZhang Chen                          pri_rs->vnet_hdr_len,
11609c55fe94SLukas Straub                          false,
116130685c00SZhang Chen                          false);
11620682e15bSZhang Chen     } else {
11633463218cSMao Zhongyi         /* compare packet in the specified connection */
11648ec14402SMao Zhongyi         colo_compare_connection(conn, s);
116559509ec1SZhang Chen     }
11667dce4e6fSZhang Chen }
11677dce4e6fSZhang Chen 
compare_sec_rs_finalize(SocketReadState * sec_rs)11687dce4e6fSZhang Chen static void compare_sec_rs_finalize(SocketReadState *sec_rs)
11697dce4e6fSZhang Chen {
117059509ec1SZhang Chen     CompareState *s = container_of(sec_rs, CompareState, sec_rs);
11718ec14402SMao Zhongyi     Connection *conn = NULL;
117259509ec1SZhang Chen 
11738ec14402SMao Zhongyi     if (packet_enqueue(s, SECONDARY_IN, &conn)) {
117459509ec1SZhang Chen         trace_colo_compare_main("secondary: unsupported packet in");
11750682e15bSZhang Chen     } else {
11763463218cSMao Zhongyi         /* compare packet in the specified connection */
11778ec14402SMao Zhongyi         colo_compare_connection(conn, s);
117859509ec1SZhang Chen     }
11797dce4e6fSZhang Chen }
11807dce4e6fSZhang Chen 
compare_notify_rs_finalize(SocketReadState * notify_rs)118113025feeSZhang Chen static void compare_notify_rs_finalize(SocketReadState *notify_rs)
118213025feeSZhang Chen {
11831d09f700SZhang Chen     CompareState *s = container_of(notify_rs, CompareState, notify_rs);
11841d09f700SZhang Chen 
1185f77bed14SZhang Chen     const char msg[] = "COLO_COMPARE_GET_XEN_INIT";
11861d09f700SZhang Chen     int ret;
11871d09f700SZhang Chen 
1188f77bed14SZhang Chen     if (packet_matches_str("COLO_USERSPACE_PROXY_INIT",
1189f77bed14SZhang Chen                            notify_rs->buf,
1190f77bed14SZhang Chen                            notify_rs->packet_len)) {
11919c55fe94SLukas Straub         ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
11921d09f700SZhang Chen         if (ret < 0) {
11931d09f700SZhang Chen             error_report("Notify Xen COLO-frame INIT failed");
11941d09f700SZhang Chen         }
1195f77bed14SZhang Chen     } else if (packet_matches_str("COLO_CHECKPOINT",
1196f77bed14SZhang Chen                                   notify_rs->buf,
1197f77bed14SZhang Chen                                   notify_rs->packet_len)) {
11981d09f700SZhang Chen         /* colo-compare do checkpoint, flush pri packet and remove sec packet */
11991d09f700SZhang Chen         g_queue_foreach(&s->conn_list, colo_flush_packets, s);
1200f77bed14SZhang Chen     } else {
1201f77bed14SZhang Chen         error_report("COLO compare got unsupported instruction");
12021d09f700SZhang Chen     }
120313025feeSZhang Chen }
12047dce4e6fSZhang Chen 
12057dce4e6fSZhang Chen /*
12067dce4e6fSZhang Chen  * Return 0 is success.
12077dce4e6fSZhang Chen  * Return 1 is failed.
12087dce4e6fSZhang Chen  */
find_and_check_chardev(Chardev ** chr,char * chr_name,Error ** errp)12090ec7b3e7SMarc-André Lureau static int find_and_check_chardev(Chardev **chr,
12107dce4e6fSZhang Chen                                   char *chr_name,
12117dce4e6fSZhang Chen                                   Error **errp)
12127dce4e6fSZhang Chen {
12137dce4e6fSZhang Chen     *chr = qemu_chr_find(chr_name);
12147dce4e6fSZhang Chen     if (*chr == NULL) {
12157dce4e6fSZhang Chen         error_setg(errp, "Device '%s' not found",
12167dce4e6fSZhang Chen                    chr_name);
12177dce4e6fSZhang Chen         return 1;
12187dce4e6fSZhang Chen     }
12197dce4e6fSZhang Chen 
12200a73336dSDaniel P. Berrange     if (!qemu_chr_has_feature(*chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) {
12210a73336dSDaniel P. Berrange         error_setg(errp, "chardev \"%s\" is not reconnectable",
12227dce4e6fSZhang Chen                    chr_name);
12237dce4e6fSZhang Chen         return 1;
12247dce4e6fSZhang Chen     }
1225fbf3cc3aSMarc-André Lureau 
1226269d25cdSMarc-André Lureau     if (!qemu_chr_has_feature(*chr, QEMU_CHAR_FEATURE_GCONTEXT)) {
1227269d25cdSMarc-André Lureau         error_setg(errp, "chardev \"%s\" cannot switch context",
1228269d25cdSMarc-André Lureau                    chr_name);
1229269d25cdSMarc-André Lureau         return 1;
1230269d25cdSMarc-André Lureau     }
1231269d25cdSMarc-André Lureau 
12327dce4e6fSZhang Chen     return 0;
12337dce4e6fSZhang Chen }
12347dce4e6fSZhang Chen 
12357dce4e6fSZhang Chen /*
12367dce4e6fSZhang Chen  * Called from the main thread on the primary
12377dce4e6fSZhang Chen  * to setup colo-compare.
12387dce4e6fSZhang Chen  */
colo_compare_complete(UserCreatable * uc,Error ** errp)12397dce4e6fSZhang Chen static void colo_compare_complete(UserCreatable *uc, Error **errp)
12407dce4e6fSZhang Chen {
12417dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(uc);
12420ec7b3e7SMarc-André Lureau     Chardev *chr;
12437dce4e6fSZhang Chen 
1244dd321ecfSWang Yong     if (!s->pri_indev || !s->sec_indev || !s->outdev || !s->iothread) {
12457dce4e6fSZhang Chen         error_setg(errp, "colo compare needs 'primary_in' ,"
1246dd321ecfSWang Yong                    "'secondary_in','outdev','iothread' property set");
12477dce4e6fSZhang Chen         return;
12487dce4e6fSZhang Chen     } else if (!strcmp(s->pri_indev, s->outdev) ||
12497dce4e6fSZhang Chen                !strcmp(s->sec_indev, s->outdev) ||
12507dce4e6fSZhang Chen                !strcmp(s->pri_indev, s->sec_indev)) {
12517dce4e6fSZhang Chen         error_setg(errp, "'indev' and 'outdev' could not be same "
12527dce4e6fSZhang Chen                    "for compare module");
12537dce4e6fSZhang Chen         return;
12547dce4e6fSZhang Chen     }
12557dce4e6fSZhang Chen 
12569cc43c94SZhang Chen     if (!s->compare_timeout) {
12579cc43c94SZhang Chen         /* Set default value to 3000 MS */
12589cc43c94SZhang Chen         s->compare_timeout = DEFAULT_TIME_OUT_MS;
12599cc43c94SZhang Chen     }
12609cc43c94SZhang Chen 
1261cca35ac4SZhang Chen     if (!s->expired_scan_cycle) {
126209313cdbSZhang Chen         /* Set default value to 1000 MS */
1263cca35ac4SZhang Chen         s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
1264cca35ac4SZhang Chen     }
1265cca35ac4SZhang Chen 
1266a2e5cb7aSZhang Chen     if (!max_queue_size) {
1267a2e5cb7aSZhang Chen         /* Set default queue size to 1024 */
1268a2e5cb7aSZhang Chen         max_queue_size = MAX_QUEUE_SIZE;
1269a2e5cb7aSZhang Chen     }
1270a2e5cb7aSZhang Chen 
12715345fdb4SMarc-André Lureau     if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
12725345fdb4SMarc-André Lureau         !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) {
12737dce4e6fSZhang Chen         return;
12747dce4e6fSZhang Chen     }
12757dce4e6fSZhang Chen 
12765345fdb4SMarc-André Lureau     if (find_and_check_chardev(&chr, s->sec_indev, errp) ||
12775345fdb4SMarc-André Lureau         !qemu_chr_fe_init(&s->chr_sec_in, chr, errp)) {
12787dce4e6fSZhang Chen         return;
12797dce4e6fSZhang Chen     }
12807dce4e6fSZhang Chen 
12815345fdb4SMarc-André Lureau     if (find_and_check_chardev(&chr, s->outdev, errp) ||
12825345fdb4SMarc-André Lureau         !qemu_chr_fe_init(&s->chr_out, chr, errp)) {
12837dce4e6fSZhang Chen         return;
12847dce4e6fSZhang Chen     }
12857dce4e6fSZhang Chen 
1286aa3a7032SZhang Chen     net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr);
1287aa3a7032SZhang Chen     net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr);
12887dce4e6fSZhang Chen 
128913025feeSZhang Chen     /* Try to enable remote notify chardev, currently just for Xen COLO */
129013025feeSZhang Chen     if (s->notify_dev) {
129113025feeSZhang Chen         if (find_and_check_chardev(&chr, s->notify_dev, errp) ||
129213025feeSZhang Chen             !qemu_chr_fe_init(&s->chr_notify_dev, chr, errp)) {
129313025feeSZhang Chen             return;
129413025feeSZhang Chen         }
129513025feeSZhang Chen 
129613025feeSZhang Chen         net_socket_rs_init(&s->notify_rs, compare_notify_rs_finalize,
129713025feeSZhang Chen                            s->vnet_hdr);
129813025feeSZhang Chen     }
129913025feeSZhang Chen 
13009c55fe94SLukas Straub     s->out_sendco.s = s;
13019c55fe94SLukas Straub     s->out_sendco.chr = &s->chr_out;
13029c55fe94SLukas Straub     s->out_sendco.notify_remote_frame = false;
13039c55fe94SLukas Straub     s->out_sendco.done = true;
13049c55fe94SLukas Straub     g_queue_init(&s->out_sendco.send_list);
13059c55fe94SLukas Straub 
13069c55fe94SLukas Straub     if (s->notify_dev) {
13079c55fe94SLukas Straub         s->notify_sendco.s = s;
13089c55fe94SLukas Straub         s->notify_sendco.chr = &s->chr_notify_dev;
13099c55fe94SLukas Straub         s->notify_sendco.notify_remote_frame = true;
13109c55fe94SLukas Straub         s->notify_sendco.done = true;
13119c55fe94SLukas Straub         g_queue_init(&s->notify_sendco.send_list);
13129c55fe94SLukas Straub     }
13139c55fe94SLukas Straub 
1314b6540d40SZhang Chen     g_queue_init(&s->conn_list);
1315b6540d40SZhang Chen 
1316b6540d40SZhang Chen     s->connection_track_table = g_hash_table_new_full(connection_key_hash,
1317b6540d40SZhang Chen                                                       connection_key_equal,
1318b6540d40SZhang Chen                                                       g_free,
1319a18d4369SZhang Chen                                                       NULL);
132059509ec1SZhang Chen 
1321dd321ecfSWang Yong     colo_compare_iothread(s);
13225bd57ebaSLukas Straub 
13235bd57ebaSLukas Straub     qemu_mutex_lock(&colo_compare_mutex);
13245bd57ebaSLukas Straub     if (!colo_compare_active) {
13255bd57ebaSLukas Straub         qemu_mutex_init(&event_mtx);
13265bd57ebaSLukas Straub         qemu_cond_init(&event_complete_cond);
13275bd57ebaSLukas Straub         colo_compare_active = true;
13285bd57ebaSLukas Straub     }
13295bd57ebaSLukas Straub     QTAILQ_INSERT_TAIL(&net_compares, s, next);
13305bd57ebaSLukas Straub     qemu_mutex_unlock(&colo_compare_mutex);
13315bd57ebaSLukas Straub 
13327dce4e6fSZhang Chen     return;
13337dce4e6fSZhang Chen }
13347dce4e6fSZhang Chen 
colo_flush_packets(void * opaque,void * user_data)1335dfd917a9Szhanghailiang static void colo_flush_packets(void *opaque, void *user_data)
1336dfd917a9Szhanghailiang {
1337dfd917a9Szhanghailiang     CompareState *s = user_data;
1338dfd917a9Szhanghailiang     Connection *conn = opaque;
1339dfd917a9Szhanghailiang     Packet *pkt = NULL;
1340dfd917a9Szhanghailiang 
1341dfd917a9Szhanghailiang     while (!g_queue_is_empty(&conn->primary_list)) {
1342a5f038e2SZhang Chen         pkt = g_queue_pop_tail(&conn->primary_list);
1343aa3a7032SZhang Chen         compare_chr_send(s,
1344aa3a7032SZhang Chen                          pkt->data,
1345aa3a7032SZhang Chen                          pkt->size,
134630685c00SZhang Chen                          pkt->vnet_hdr_len,
13479c55fe94SLukas Straub                          false,
13489c55fe94SLukas Straub                          true);
13499c55fe94SLukas Straub         packet_destroy_partial(pkt, NULL);
1350dfd917a9Szhanghailiang     }
1351dfd917a9Szhanghailiang     while (!g_queue_is_empty(&conn->secondary_list)) {
1352a5f038e2SZhang Chen         pkt = g_queue_pop_tail(&conn->secondary_list);
1353dfd917a9Szhanghailiang         packet_destroy(pkt, NULL);
1354dfd917a9Szhanghailiang     }
1355dfd917a9Szhanghailiang }
1356dfd917a9Szhanghailiang 
colo_compare_class_init(ObjectClass * oc,void * data)13577dce4e6fSZhang Chen static void colo_compare_class_init(ObjectClass *oc, void *data)
13587dce4e6fSZhang Chen {
13597dce4e6fSZhang Chen     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
13607dce4e6fSZhang Chen 
13617dce4e6fSZhang Chen     ucc->complete = colo_compare_complete;
13627dce4e6fSZhang Chen }
13637dce4e6fSZhang Chen 
colo_compare_init(Object * obj)13647dce4e6fSZhang Chen static void colo_compare_init(Object *obj)
13657dce4e6fSZhang Chen {
1366aa3a7032SZhang Chen     CompareState *s = COLO_COMPARE(obj);
1367aa3a7032SZhang Chen 
13687dce4e6fSZhang Chen     object_property_add_str(obj, "primary_in",
1369d2623129SMarkus Armbruster                             compare_get_pri_indev, compare_set_pri_indev);
13707dce4e6fSZhang Chen     object_property_add_str(obj, "secondary_in",
1371d2623129SMarkus Armbruster                             compare_get_sec_indev, compare_set_sec_indev);
13727dce4e6fSZhang Chen     object_property_add_str(obj, "outdev",
1373d2623129SMarkus Armbruster                             compare_get_outdev, compare_set_outdev);
1374dd321ecfSWang Yong     object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
1375dd321ecfSWang Yong                             (Object **)&s->iothread,
1376dd321ecfSWang Yong                             object_property_allow_set_link,
1377d2623129SMarkus Armbruster                             OBJ_PROP_LINK_STRONG);
1378cf6af766SZhang Chen     /* This parameter just for Xen COLO */
1379cf6af766SZhang Chen     object_property_add_str(obj, "notify_dev",
1380d2623129SMarkus Armbruster                             compare_get_notify_dev, compare_set_notify_dev);
1381aa3a7032SZhang Chen 
13820c4266efSZhang Chen     object_property_add(obj, "compare_timeout", "uint64",
13839cc43c94SZhang Chen                         compare_get_timeout,
1384d2623129SMarkus Armbruster                         compare_set_timeout, NULL, NULL);
13859cc43c94SZhang Chen 
1386cca35ac4SZhang Chen     object_property_add(obj, "expired_scan_cycle", "uint32",
1387cca35ac4SZhang Chen                         compare_get_expired_scan_cycle,
1388d2623129SMarkus Armbruster                         compare_set_expired_scan_cycle, NULL, NULL);
1389cca35ac4SZhang Chen 
1390a2e5cb7aSZhang Chen     object_property_add(obj, "max_queue_size", "uint32",
1391a2e5cb7aSZhang Chen                         get_max_queue_size,
1392a2e5cb7aSZhang Chen                         set_max_queue_size, NULL, NULL);
1393a2e5cb7aSZhang Chen 
1394aa3a7032SZhang Chen     s->vnet_hdr = false;
1395aa3a7032SZhang Chen     object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
1396d2623129SMarkus Armbruster                              compare_set_vnet_hdr);
13977dce4e6fSZhang Chen }
13987dce4e6fSZhang Chen 
colo_compare_cleanup(void)13990c7af1a7SRao, Lei void colo_compare_cleanup(void)
14000c7af1a7SRao, Lei {
14010c7af1a7SRao, Lei     CompareState *tmp = NULL;
14020c7af1a7SRao, Lei     CompareState *n = NULL;
14030c7af1a7SRao, Lei 
14040c7af1a7SRao, Lei     QTAILQ_FOREACH_SAFE(tmp, &net_compares, next, n) {
14050c7af1a7SRao, Lei         object_unparent(OBJECT(tmp));
14060c7af1a7SRao, Lei     }
14070c7af1a7SRao, Lei }
14080c7af1a7SRao, Lei 
colo_compare_finalize(Object * obj)14097dce4e6fSZhang Chen static void colo_compare_finalize(Object *obj)
14107dce4e6fSZhang Chen {
14117dce4e6fSZhang Chen     CompareState *s = COLO_COMPARE(obj);
14120ffcece3SZhang Chen     CompareState *tmp = NULL;
14137dce4e6fSZhang Chen 
141445942b79SLukas Straub     qemu_mutex_lock(&colo_compare_mutex);
14150ffcece3SZhang Chen     QTAILQ_FOREACH(tmp, &net_compares, next) {
14160ffcece3SZhang Chen         if (tmp == s) {
14170ffcece3SZhang Chen             QTAILQ_REMOVE(&net_compares, s, next);
14180ffcece3SZhang Chen             break;
14190ffcece3SZhang Chen         }
14200ffcece3SZhang Chen     }
142145942b79SLukas Straub     if (QTAILQ_EMPTY(&net_compares)) {
142245942b79SLukas Straub         colo_compare_active = false;
142345942b79SLukas Straub         qemu_mutex_destroy(&event_mtx);
142445942b79SLukas Straub         qemu_cond_destroy(&event_complete_cond);
142545942b79SLukas Straub     }
142645942b79SLukas Straub     qemu_mutex_unlock(&colo_compare_mutex);
14270ffcece3SZhang Chen 
14285bd57ebaSLukas Straub     qemu_chr_fe_deinit(&s->chr_pri_in, false);
14295bd57ebaSLukas Straub     qemu_chr_fe_deinit(&s->chr_sec_in, false);
14305bd57ebaSLukas Straub     qemu_chr_fe_deinit(&s->chr_out, false);
14315bd57ebaSLukas Straub     if (s->notify_dev) {
14325bd57ebaSLukas Straub         qemu_chr_fe_deinit(&s->chr_notify_dev, false);
14335bd57ebaSLukas Straub     }
14345bd57ebaSLukas Straub 
14355bd57ebaSLukas Straub     colo_compare_timer_del(s);
14365bd57ebaSLukas Straub 
14375bd57ebaSLukas Straub     qemu_bh_delete(s->event_bh);
14385bd57ebaSLukas Straub 
14399c55fe94SLukas Straub     AioContext *ctx = iothread_get_aio_context(s->iothread);
14409c55fe94SLukas Straub     AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
14419c55fe94SLukas Straub     if (s->notify_dev) {
14429c55fe94SLukas Straub         AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
14439c55fe94SLukas Straub     }
14449c55fe94SLukas Straub 
1445dfd917a9Szhanghailiang     /* Release all unhandled packets after compare thead exited */
1446dfd917a9Szhanghailiang     g_queue_foreach(&s->conn_list, colo_flush_packets, s);
14479c55fe94SLukas Straub     AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
1448dfd917a9Szhanghailiang 
1449727c2d76SZhang Chen     g_queue_clear(&s->conn_list);
14509c55fe94SLukas Straub     g_queue_clear(&s->out_sendco.send_list);
14519c55fe94SLukas Straub     if (s->notify_dev) {
14529c55fe94SLukas Straub         g_queue_clear(&s->notify_sendco.send_list);
14539c55fe94SLukas Straub     }
1454b6540d40SZhang Chen 
1455dd321ecfSWang Yong     if (s->connection_track_table) {
1456dfd917a9Szhanghailiang         g_hash_table_destroy(s->connection_track_table);
1457dd321ecfSWang Yong     }
1458dd321ecfSWang Yong 
1459dd321ecfSWang Yong     object_unref(OBJECT(s->iothread));
14600ffcece3SZhang Chen 
14617dce4e6fSZhang Chen     g_free(s->pri_indev);
14627dce4e6fSZhang Chen     g_free(s->sec_indev);
14637dce4e6fSZhang Chen     g_free(s->outdev);
1464cf6af766SZhang Chen     g_free(s->notify_dev);
14657dce4e6fSZhang Chen }
14667dce4e6fSZhang Chen 
colo_compare_init_globals(void)146745942b79SLukas Straub static void __attribute__((__constructor__)) colo_compare_init_globals(void)
146845942b79SLukas Straub {
146945942b79SLukas Straub     colo_compare_active = false;
147045942b79SLukas Straub     qemu_mutex_init(&colo_compare_mutex);
147145942b79SLukas Straub }
147245942b79SLukas Straub 
14737dce4e6fSZhang Chen static const TypeInfo colo_compare_info = {
14747dce4e6fSZhang Chen     .name = TYPE_COLO_COMPARE,
14757dce4e6fSZhang Chen     .parent = TYPE_OBJECT,
14767dce4e6fSZhang Chen     .instance_size = sizeof(CompareState),
14777dce4e6fSZhang Chen     .instance_init = colo_compare_init,
14787dce4e6fSZhang Chen     .instance_finalize = colo_compare_finalize,
14797dce4e6fSZhang Chen     .class_size = sizeof(CompareClass),
14807dce4e6fSZhang Chen     .class_init = colo_compare_class_init,
14817dce4e6fSZhang Chen     .interfaces = (InterfaceInfo[]) {
14827dce4e6fSZhang Chen         { TYPE_USER_CREATABLE },
14837dce4e6fSZhang Chen         { }
14847dce4e6fSZhang Chen     }
14857dce4e6fSZhang Chen };
14867dce4e6fSZhang Chen 
register_types(void)14877dce4e6fSZhang Chen static void register_types(void)
14887dce4e6fSZhang Chen {
14897dce4e6fSZhang Chen     type_register_static(&colo_compare_info);
14907dce4e6fSZhang Chen }
14917dce4e6fSZhang Chen 
14927dce4e6fSZhang Chen type_init(register_types);
1493