master
c 526 lines 13.9 KB
Raw
1 /*
2 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
3 * Copyright (c) 2016 FUJITSU LIMITED
4 * Copyright (c) 2016 Intel Corporation
5 *
6 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or
9 * later. See the COPYING file in the top-level directory.
10 */
11
12 #include "qemu/osdep.h"
13 #include "net/filter.h"
14 #include "net/net.h"
15 #include "qapi/error.h"
16 #include "qom/object.h"
17 #include "qemu/main-loop.h"
18 #include "qemu/error-report.h"
19 #include "trace.h"
20 #include "chardev/char-fe.h"
21 #include "qemu/iov.h"
22 #include "qemu/sockets.h"
23 #include "qemu/aio-wait.h"
24
25 #define TYPE_FILTER_MIRROR "filter-mirror"
26 typedef struct MirrorState MirrorState;
27 DECLARE_INSTANCE_CHECKER(MirrorState, FILTER_MIRROR,
28 TYPE_FILTER_MIRROR)
29
30 #define TYPE_FILTER_REDIRECTOR "filter-redirector"
31 DECLARE_INSTANCE_CHECKER(MirrorState, FILTER_REDIRECTOR,
32 TYPE_FILTER_REDIRECTOR)
33
34 #define REDIRECTOR_MAX_LEN NET_BUFSIZE
35
36 struct MirrorState {
37 NetFilterState parent_obj;
38 char *indev;
39 char *outdev;
40 CharFrontend chr_in;
41 CharFrontend chr_out;
42 SocketReadState rs;
43 bool vnet_hdr;
44 };
45
46 typedef struct FilterSendCo {
47 MirrorState *s;
48 char *buf;
49 ssize_t size;
50 bool done;
51 int ret;
52 } FilterSendCo;
53
54 static int _filter_send(MirrorState *s,
55 char *buf,
56 ssize_t size)
57 {
58 NetFilterState *nf = NETFILTER(s);
59 int ret = 0;
60 uint32_t len = 0;
61
62 len = htonl(size);
63 ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
64 if (ret != sizeof(len)) {
65 goto err;
66 }
67
68 if (s->vnet_hdr) {
69 /*
70 * If vnet_hdr = on, we send vnet header len to make other
71 * module(like colo-compare) know how to parse net
72 * packet correctly.
73 */
74 ssize_t vnet_hdr_len;
75
76 vnet_hdr_len = nf->netdev->vnet_hdr_len;
77
78 len = htonl(vnet_hdr_len);
79 ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
80 if (ret != sizeof(len)) {
81 goto err;
82 }
83 }
84
85 ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
86 if (ret != size) {
87 goto err;
88 }
89
90 return size;
91
92 err:
93 return ret < 0 ? ret : -EIO;
94 }
95
96 static void coroutine_fn filter_send_co(void *opaque)
97 {
98 FilterSendCo *data = opaque;
99
100 data->ret = _filter_send(data->s, data->buf, data->size);
101 data->done = true;
102 g_free(data->buf);
103 aio_wait_kick();
104 }
105
106 static int filter_send(MirrorState *s,
107 const struct iovec *iov,
108 int iovcnt)
109 {
110 ssize_t size = iov_size(iov, iovcnt);
111 char *buf = NULL;
112
113 if (!size) {
114 return 0;
115 }
116
117 buf = g_malloc(size);
118 iov_to_buf(iov, iovcnt, 0, buf, size);
119
120 FilterSendCo data = {
121 .s = s,
122 .size = size,
123 .buf = buf,
124 .ret = 0,
125 };
126
127 Coroutine *co = qemu_coroutine_create(filter_send_co, &data);
128 qemu_coroutine_enter(co);
129
130 while (!data.done) {
131 aio_poll(qemu_get_aio_context(), true);
132 }
133
134 return data.ret;
135 }
136
137 static void redirector_to_filter(NetFilterState *nf,
138 const uint8_t *buf,
139 int len)
140 {
141 struct iovec iov = {
142 .iov_base = (void *)buf,
143 .iov_len = len,
144 };
145
146 if (nf->direction == NET_FILTER_DIRECTION_ALL ||
147 nf->direction == NET_FILTER_DIRECTION_TX) {
148 qemu_netfilter_pass_to_next(nf->netdev, 0, &iov, 1, nf);
149 }
150
151 if (nf->direction == NET_FILTER_DIRECTION_ALL ||
152 nf->direction == NET_FILTER_DIRECTION_RX) {
153 qemu_netfilter_pass_to_next(nf->netdev->peer, 0, &iov, 1, nf);
154 }
155 }
156
157 static int redirector_chr_can_read(void *opaque)
158 {
159 return REDIRECTOR_MAX_LEN;
160 }
161
162 static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
163 {
164 NetFilterState *nf = opaque;
165 MirrorState *s = FILTER_REDIRECTOR(nf);
166 int ret;
167
168 ret = net_fill_rstate(&s->rs, buf, size);
169
170 if (ret == -1) {
171 qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
172 NULL, NULL, NULL, true);
173 }
174 }
175
176 static void redirector_chr_event(void *opaque, QEMUChrEvent event)
177 {
178 NetFilterState *nf = opaque;
179 MirrorState *s = FILTER_REDIRECTOR(nf);
180
181 switch (event) {
182 case CHR_EVENT_OPENED:
183 if (nf->on) {
184 qemu_chr_fe_set_handlers_full(&s->chr_in, redirector_chr_can_read,
185 redirector_chr_read, redirector_chr_event,
186 NULL, nf, NULL, false, false);
187 }
188 break;
189 case CHR_EVENT_CLOSED:
190 qemu_chr_fe_set_handlers_full(&s->chr_in, NULL, NULL, redirector_chr_event,
191 NULL, nf, NULL, false, false);
192 break;
193 default:
194 break;
195 }
196 }
197
198 static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
199 NetClientState *sender,
200 unsigned flags,
201 const struct iovec *iov,
202 int iovcnt,
203 NetPacketSent *sent_cb)
204 {
205 MirrorState *s = FILTER_MIRROR(nf);
206 int ret;
207
208 ret = filter_send(s, iov, iovcnt);
209 if (ret < 0) {
210 error_report("filter mirror send failed(%s)", strerror(-ret));
211 }
212
213 /*
214 * we don't hope this error interrupt the normal
215 * path of net packet, so we always return zero.
216 */
217 return 0;
218 }
219
220 static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
221 NetClientState *sender,
222 unsigned flags,
223 const struct iovec *iov,
224 int iovcnt,
225 NetPacketSent *sent_cb)
226 {
227 MirrorState *s = FILTER_REDIRECTOR(nf);
228 int ret;
229
230 if (qemu_chr_fe_backend_connected(&s->chr_out)) {
231 ret = filter_send(s, iov, iovcnt);
232 if (ret < 0) {
233 error_report("filter redirector send failed(%s)", strerror(-ret));
234 }
235 return ret;
236 } else {
237 return 0;
238 }
239 }
240
241 static void filter_mirror_cleanup(NetFilterState *nf)
242 {
243 MirrorState *s = FILTER_MIRROR(nf);
244
245 qemu_chr_fe_deinit(&s->chr_out, false);
246 }
247
248 static void filter_redirector_cleanup(NetFilterState *nf)
249 {
250 MirrorState *s = FILTER_REDIRECTOR(nf);
251
252 qemu_chr_fe_deinit(&s->chr_in, false);
253 qemu_chr_fe_deinit(&s->chr_out, false);
254 }
255
256 static void filter_mirror_setup(NetFilterState *nf, Error **errp)
257 {
258 MirrorState *s = FILTER_MIRROR(nf);
259 Chardev *chr;
260
261 if (s->outdev == NULL) {
262 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "filter-mirror parameter"\
263 " 'outdev' cannot be empty");
264 return;
265 }
266
267 chr = qemu_chr_find(s->outdev);
268 if (chr == NULL) {
269 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
270 "Device '%s' not found", s->outdev);
271 return;
272 }
273
274 qemu_chr_fe_init(&s->chr_out, chr, errp);
275 }
276
277 static void redirector_rs_finalize(SocketReadState *rs)
278 {
279 MirrorState *s = container_of(rs, MirrorState, rs);
280 NetFilterState *nf = NETFILTER(s);
281
282 redirector_to_filter(nf, rs->buf, rs->packet_len);
283 }
284
285 static void filter_redirector_setup(NetFilterState *nf, Error **errp)
286 {
287 MirrorState *s = FILTER_REDIRECTOR(nf);
288 Chardev *chr;
289
290 if (!s->indev && !s->outdev) {
291 error_setg(errp, "filter redirector needs 'indev' or "
292 "'outdev' at least one property set");
293 return;
294 } else if (s->indev && s->outdev) {
295 if (!strcmp(s->indev, s->outdev)) {
296 error_setg(errp, "'indev' and 'outdev' could not be same "
297 "for filter redirector");
298 return;
299 }
300 }
301
302 net_socket_rs_init(&s->rs, redirector_rs_finalize, s->vnet_hdr);
303
304 if (s->indev) {
305 chr = qemu_chr_find(s->indev);
306 if (chr == NULL) {
307 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
308 "IN Device '%s' not found", s->indev);
309 return;
310 }
311
312 if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
313 return;
314 }
315
316 if (nf->on) {
317 qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
318 redirector_chr_read, redirector_chr_event,
319 NULL, nf, NULL, true);
320 }
321 }
322
323 if (s->outdev) {
324 chr = qemu_chr_find(s->outdev);
325 if (chr == NULL) {
326 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
327 "OUT Device '%s' not found", s->outdev);
328 return;
329 }
330 if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
331 return;
332 }
333 }
334 }
335
336 static void filter_redirector_status_changed(NetFilterState *nf, Error **errp)
337 {
338 MirrorState *s = FILTER_REDIRECTOR(nf);
339
340 if (!s->indev) {
341 return;
342 }
343
344 if (nf->on) {
345 qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
346 redirector_chr_read, redirector_chr_event,
347 NULL, nf, NULL, true);
348 } else {
349 qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
350 NULL, NULL, NULL, true);
351 }
352 }
353
354 static char *filter_redirector_get_indev(Object *obj, Error **errp)
355 {
356 MirrorState *s = FILTER_REDIRECTOR(obj);
357
358 return g_strdup(s->indev);
359 }
360
361 static void filter_redirector_set_indev(Object *obj,
362 const char *value,
363 Error **errp)
364 {
365 MirrorState *s = FILTER_REDIRECTOR(obj);
366
367 g_free(s->indev);
368 s->indev = g_strdup(value);
369 }
370
371 static char *filter_mirror_get_outdev(Object *obj, Error **errp)
372 {
373 MirrorState *s = FILTER_MIRROR(obj);
374
375 return g_strdup(s->outdev);
376 }
377
378 static void filter_mirror_set_outdev(Object *obj,
379 const char *value,
380 Error **errp)
381 {
382 MirrorState *s = FILTER_MIRROR(obj);
383
384 g_free(s->outdev);
385 s->outdev = g_strdup(value);
386 if (!s->outdev) {
387 error_setg(errp, "filter mirror needs 'outdev' "
388 "property set");
389 return;
390 }
391 }
392
393 static bool filter_mirror_get_vnet_hdr(Object *obj, Error **errp)
394 {
395 MirrorState *s = FILTER_MIRROR(obj);
396
397 return s->vnet_hdr;
398 }
399
400 static void filter_mirror_set_vnet_hdr(Object *obj, bool value, Error **errp)
401 {
402 MirrorState *s = FILTER_MIRROR(obj);
403
404 s->vnet_hdr = value;
405 }
406
407 static char *filter_redirector_get_outdev(Object *obj, Error **errp)
408 {
409 MirrorState *s = FILTER_REDIRECTOR(obj);
410
411 return g_strdup(s->outdev);
412 }
413
414 static void filter_redirector_set_outdev(Object *obj,
415 const char *value,
416 Error **errp)
417 {
418 MirrorState *s = FILTER_REDIRECTOR(obj);
419
420 g_free(s->outdev);
421 s->outdev = g_strdup(value);
422 }
423
424 static bool filter_redirector_get_vnet_hdr(Object *obj, Error **errp)
425 {
426 MirrorState *s = FILTER_REDIRECTOR(obj);
427
428 return s->vnet_hdr;
429 }
430
431 static void filter_redirector_set_vnet_hdr(Object *obj,
432 bool value,
433 Error **errp)
434 {
435 MirrorState *s = FILTER_REDIRECTOR(obj);
436
437 s->vnet_hdr = value;
438 }
439
440 static void filter_mirror_class_init(ObjectClass *oc, const void *data)
441 {
442 NetFilterClass *nfc = NETFILTER_CLASS(oc);
443
444 object_class_property_add_str(oc, "outdev", filter_mirror_get_outdev,
445 filter_mirror_set_outdev);
446 object_class_property_add_bool(oc, "vnet_hdr_support",
447 filter_mirror_get_vnet_hdr,
448 filter_mirror_set_vnet_hdr);
449
450 nfc->setup = filter_mirror_setup;
451 nfc->cleanup = filter_mirror_cleanup;
452 nfc->receive_iov = filter_mirror_receive_iov;
453 }
454
455 static void filter_redirector_class_init(ObjectClass *oc, const void *data)
456 {
457 NetFilterClass *nfc = NETFILTER_CLASS(oc);
458
459 object_class_property_add_str(oc, "indev", filter_redirector_get_indev,
460 filter_redirector_set_indev);
461 object_class_property_add_str(oc, "outdev", filter_redirector_get_outdev,
462 filter_redirector_set_outdev);
463 object_class_property_add_bool(oc, "vnet_hdr_support",
464 filter_redirector_get_vnet_hdr,
465 filter_redirector_set_vnet_hdr);
466
467 nfc->setup = filter_redirector_setup;
468 nfc->cleanup = filter_redirector_cleanup;
469 nfc->receive_iov = filter_redirector_receive_iov;
470 nfc->status_changed = filter_redirector_status_changed;
471 }
472
473 static void filter_mirror_init(Object *obj)
474 {
475 MirrorState *s = FILTER_MIRROR(obj);
476
477 s->vnet_hdr = false;
478 }
479
480 static void filter_redirector_init(Object *obj)
481 {
482 MirrorState *s = FILTER_REDIRECTOR(obj);
483
484 s->vnet_hdr = false;
485 }
486
487 static void filter_mirror_fini(Object *obj)
488 {
489 MirrorState *s = FILTER_MIRROR(obj);
490
491 g_free(s->outdev);
492 }
493
494 static void filter_redirector_fini(Object *obj)
495 {
496 MirrorState *s = FILTER_REDIRECTOR(obj);
497
498 g_free(s->indev);
499 g_free(s->outdev);
500 }
501
502 static const TypeInfo filter_redirector_info = {
503 .name = TYPE_FILTER_REDIRECTOR,
504 .parent = TYPE_NETFILTER,
505 .class_init = filter_redirector_class_init,
506 .instance_init = filter_redirector_init,
507 .instance_finalize = filter_redirector_fini,
508 .instance_size = sizeof(MirrorState),
509 };
510
511 static const TypeInfo filter_mirror_info = {
512 .name = TYPE_FILTER_MIRROR,
513 .parent = TYPE_NETFILTER,
514 .class_init = filter_mirror_class_init,
515 .instance_init = filter_mirror_init,
516 .instance_finalize = filter_mirror_fini,
517 .instance_size = sizeof(MirrorState),
518 };
519
520 static void register_types(void)
521 {
522 type_register_static(&filter_mirror_info);
523 type_register_static(&filter_redirector_info);
524 }
525
526 type_init(register_types);