]> git.proxmox.com Git - mirror_qemu.git/blame - net/colo-compare.c
Jhash: add linux kernel jhashtable in qemu
[mirror_qemu.git] / net / colo-compare.c
CommitLineData
7dce4e6f
ZC
1/*
2 * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
3 * (a.k.a. Fault Tolerance or Continuous Replication)
4 *
5 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
6 * Copyright (c) 2016 FUJITSU LIMITED
7 * Copyright (c) 2016 Intel Corporation
8 *
9 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
10 *
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.
13 */
14
15#include "qemu/osdep.h"
16#include "qemu/error-report.h"
59509ec1 17#include "trace.h"
7dce4e6f
ZC
18#include "qemu-common.h"
19#include "qapi/qmp/qerror.h"
20#include "qapi/error.h"
21#include "net/net.h"
22#include "qom/object_interfaces.h"
23#include "qemu/iov.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"
59509ec1 30#include "net/colo.h"
7dce4e6f
ZC
31
32#define TYPE_COLO_COMPARE "colo-compare"
33#define COLO_COMPARE(obj) \
34 OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE)
35
59509ec1
ZC
36/*
37 + CompareState ++
38 | |
39 +---------------+ +---------------+ +---------------+
40 |conn list +--->conn +--------->conn |
41 +---------------+ +---------------+ +---------------+
42 | | | | | |
43 +---------------+ +---v----+ +---v----+ +---v----+ +---v----+
44 |primary | |secondary |primary | |secondary
45 |packet | |packet + |packet | |packet +
46 +--------+ +--------+ +--------+ +--------+
47 | | | |
48 +---v----+ +---v----+ +---v----+ +---v----+
49 |primary | |secondary |primary | |secondary
50 |packet | |packet + |packet | |packet +
51 +--------+ +--------+ +--------+ +--------+
52 | | | |
53 +---v----+ +---v----+ +---v----+ +---v----+
54 |primary | |secondary |primary | |secondary
55 |packet | |packet + |packet | |packet +
56 +--------+ +--------+ +--------+ +--------+
57*/
7dce4e6f
ZC
58typedef struct CompareState {
59 Object parent;
60
61 char *pri_indev;
62 char *sec_indev;
63 char *outdev;
64 CharDriverState *chr_pri_in;
65 CharDriverState *chr_sec_in;
66 CharDriverState *chr_out;
67 SocketReadState pri_rs;
68 SocketReadState sec_rs;
59509ec1
ZC
69
70 /* hashtable to save connection */
71 GHashTable *connection_track_table;
7dce4e6f
ZC
72} CompareState;
73
74typedef struct CompareClass {
75 ObjectClass parent_class;
76} CompareClass;
77
78typedef struct CompareChardevProps {
79 bool is_socket;
80} CompareChardevProps;
81
59509ec1
ZC
82enum {
83 PRIMARY_IN = 0,
84 SECONDARY_IN,
85};
86
87static int compare_chr_send(CharDriverState *out,
88 const uint8_t *buf,
89 uint32_t size);
90
91/*
92 * Return 0 on success, if return -1 means the pkt
93 * is unsupported(arp and ipv6) and will be sent later
94 */
95static int packet_enqueue(CompareState *s, int mode)
96{
97 Packet *pkt = NULL;
98
99 if (mode == PRIMARY_IN) {
100 pkt = packet_new(s->pri_rs.buf, s->pri_rs.packet_len);
101 } else {
102 pkt = packet_new(s->sec_rs.buf, s->sec_rs.packet_len);
103 }
104
105 if (parse_packet_early(pkt)) {
106 packet_destroy(pkt, NULL);
107 pkt = NULL;
108 return -1;
109 }
110 /* TODO: get connection key from pkt */
111
112 /*
113 * TODO: use connection key get conn from
114 * connection_track_table
115 */
116
117 /*
118 * TODO: insert pkt to it's conn->primary_list
119 * or conn->secondary_list
120 */
121
122 return 0;
123}
124
125static int compare_chr_send(CharDriverState *out,
126 const uint8_t *buf,
127 uint32_t size)
128{
129 int ret = 0;
130 uint32_t len = htonl(size);
131
132 if (!size) {
133 return 0;
134 }
135
136 ret = qemu_chr_fe_write_all(out, (uint8_t *)&len, sizeof(len));
137 if (ret != sizeof(len)) {
138 goto err;
139 }
140
141 ret = qemu_chr_fe_write_all(out, (uint8_t *)buf, size);
142 if (ret != size) {
143 goto err;
144 }
145
146 return 0;
147
148err:
149 return ret < 0 ? ret : -EIO;
150}
151
7dce4e6f
ZC
152static char *compare_get_pri_indev(Object *obj, Error **errp)
153{
154 CompareState *s = COLO_COMPARE(obj);
155
156 return g_strdup(s->pri_indev);
157}
158
159static void compare_set_pri_indev(Object *obj, const char *value, Error **errp)
160{
161 CompareState *s = COLO_COMPARE(obj);
162
163 g_free(s->pri_indev);
164 s->pri_indev = g_strdup(value);
165}
166
167static char *compare_get_sec_indev(Object *obj, Error **errp)
168{
169 CompareState *s = COLO_COMPARE(obj);
170
171 return g_strdup(s->sec_indev);
172}
173
174static void compare_set_sec_indev(Object *obj, const char *value, Error **errp)
175{
176 CompareState *s = COLO_COMPARE(obj);
177
178 g_free(s->sec_indev);
179 s->sec_indev = g_strdup(value);
180}
181
182static char *compare_get_outdev(Object *obj, Error **errp)
183{
184 CompareState *s = COLO_COMPARE(obj);
185
186 return g_strdup(s->outdev);
187}
188
189static void compare_set_outdev(Object *obj, const char *value, Error **errp)
190{
191 CompareState *s = COLO_COMPARE(obj);
192
193 g_free(s->outdev);
194 s->outdev = g_strdup(value);
195}
196
197static void compare_pri_rs_finalize(SocketReadState *pri_rs)
198{
59509ec1
ZC
199 CompareState *s = container_of(pri_rs, CompareState, pri_rs);
200
201 if (packet_enqueue(s, PRIMARY_IN)) {
202 trace_colo_compare_main("primary: unsupported packet in");
203 compare_chr_send(s->chr_out, pri_rs->buf, pri_rs->packet_len);
204 }
7dce4e6f
ZC
205}
206
207static void compare_sec_rs_finalize(SocketReadState *sec_rs)
208{
59509ec1
ZC
209 CompareState *s = container_of(sec_rs, CompareState, sec_rs);
210
211 if (packet_enqueue(s, SECONDARY_IN)) {
212 trace_colo_compare_main("secondary: unsupported packet in");
213 }
7dce4e6f
ZC
214}
215
216static int compare_chardev_opts(void *opaque,
217 const char *name, const char *value,
218 Error **errp)
219{
220 CompareChardevProps *props = opaque;
221
222 if (strcmp(name, "backend") == 0 &&
223 strcmp(value, "socket") == 0) {
224 props->is_socket = true;
225 return 0;
226 } else if (strcmp(name, "host") == 0 ||
227 (strcmp(name, "port") == 0) ||
228 (strcmp(name, "server") == 0) ||
229 (strcmp(name, "wait") == 0) ||
230 (strcmp(name, "path") == 0)) {
231 return 0;
232 } else {
233 error_setg(errp,
234 "COLO-compare does not support a chardev with option %s=%s",
235 name, value);
236 return -1;
237 }
238}
239
240/*
241 * Return 0 is success.
242 * Return 1 is failed.
243 */
244static int find_and_check_chardev(CharDriverState **chr,
245 char *chr_name,
246 Error **errp)
247{
248 CompareChardevProps props;
249
250 *chr = qemu_chr_find(chr_name);
251 if (*chr == NULL) {
252 error_setg(errp, "Device '%s' not found",
253 chr_name);
254 return 1;
255 }
256
257 memset(&props, 0, sizeof(props));
258 if (qemu_opt_foreach((*chr)->opts, compare_chardev_opts, &props, errp)) {
259 return 1;
260 }
261
262 if (!props.is_socket) {
263 error_setg(errp, "chardev \"%s\" is not a tcp socket",
264 chr_name);
265 return 1;
266 }
267 return 0;
268}
269
270/*
271 * Called from the main thread on the primary
272 * to setup colo-compare.
273 */
274static void colo_compare_complete(UserCreatable *uc, Error **errp)
275{
276 CompareState *s = COLO_COMPARE(uc);
277
278 if (!s->pri_indev || !s->sec_indev || !s->outdev) {
279 error_setg(errp, "colo compare needs 'primary_in' ,"
280 "'secondary_in','outdev' property set");
281 return;
282 } else if (!strcmp(s->pri_indev, s->outdev) ||
283 !strcmp(s->sec_indev, s->outdev) ||
284 !strcmp(s->pri_indev, s->sec_indev)) {
285 error_setg(errp, "'indev' and 'outdev' could not be same "
286 "for compare module");
287 return;
288 }
289
290 if (find_and_check_chardev(&s->chr_pri_in, s->pri_indev, errp)) {
291 return;
292 }
293
294 if (find_and_check_chardev(&s->chr_sec_in, s->sec_indev, errp)) {
295 return;
296 }
297
298 if (find_and_check_chardev(&s->chr_out, s->outdev, errp)) {
299 return;
300 }
301
302 qemu_chr_fe_claim_no_fail(s->chr_pri_in);
303
304 qemu_chr_fe_claim_no_fail(s->chr_sec_in);
305
306 qemu_chr_fe_claim_no_fail(s->chr_out);
307
308 net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize);
309 net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
310
59509ec1
ZC
311 /* use g_hash_table_new_full() to new a hashtable */
312
7dce4e6f
ZC
313 return;
314}
315
316static void colo_compare_class_init(ObjectClass *oc, void *data)
317{
318 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
319
320 ucc->complete = colo_compare_complete;
321}
322
323static void colo_compare_init(Object *obj)
324{
325 object_property_add_str(obj, "primary_in",
326 compare_get_pri_indev, compare_set_pri_indev,
327 NULL);
328 object_property_add_str(obj, "secondary_in",
329 compare_get_sec_indev, compare_set_sec_indev,
330 NULL);
331 object_property_add_str(obj, "outdev",
332 compare_get_outdev, compare_set_outdev,
333 NULL);
334}
335
336static void colo_compare_finalize(Object *obj)
337{
338 CompareState *s = COLO_COMPARE(obj);
339
340 if (s->chr_pri_in) {
341 qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL);
342 qemu_chr_fe_release(s->chr_pri_in);
343 }
344 if (s->chr_sec_in) {
345 qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
346 qemu_chr_fe_release(s->chr_sec_in);
347 }
348 if (s->chr_out) {
349 qemu_chr_fe_release(s->chr_out);
350 }
351
352 g_free(s->pri_indev);
353 g_free(s->sec_indev);
354 g_free(s->outdev);
355}
356
357static const TypeInfo colo_compare_info = {
358 .name = TYPE_COLO_COMPARE,
359 .parent = TYPE_OBJECT,
360 .instance_size = sizeof(CompareState),
361 .instance_init = colo_compare_init,
362 .instance_finalize = colo_compare_finalize,
363 .class_size = sizeof(CompareClass),
364 .class_init = colo_compare_class_init,
365 .interfaces = (InterfaceInfo[]) {
366 { TYPE_USER_CREATABLE },
367 { }
368 }
369};
370
371static void register_types(void)
372{
373 type_register_static(&colo_compare_info);
374}
375
376type_init(register_types);