2 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
3 * Copyright (c) 2016 FUJITSU LIMITED
4 * Copyright (c) 2016 Intel Corporation
6 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
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.
12 #include "qemu/osdep.h"
13 #include "net/filter.h"
15 #include "qapi/error.h"
16 #include "qom/object.h"
17 #include "qemu/main-loop.h"
18 #include "qemu/error-report.h"
20 #include "chardev/char-fe.h"
22 #include "qemu/sockets.h"
23 #include "block/aio-wait.h"
25 #define TYPE_FILTER_MIRROR "filter-mirror"
26 typedef struct MirrorState MirrorState
;
27 DECLARE_INSTANCE_CHECKER(MirrorState
, FILTER_MIRROR
,
30 #define TYPE_FILTER_REDIRECTOR "filter-redirector"
31 DECLARE_INSTANCE_CHECKER(MirrorState
, FILTER_REDIRECTOR
,
32 TYPE_FILTER_REDIRECTOR
)
34 #define REDIRECTOR_MAX_LEN NET_BUFSIZE
37 NetFilterState parent_obj
;
46 typedef struct FilterSendCo
{
54 static int _filter_send(MirrorState
*s
,
58 NetFilterState
*nf
= NETFILTER(s
);
63 ret
= qemu_chr_fe_write_all(&s
->chr_out
, (uint8_t *)&len
, sizeof(len
));
64 if (ret
!= sizeof(len
)) {
70 * If vnet_hdr = on, we send vnet header len to make other
71 * module(like colo-compare) know how to parse net
76 vnet_hdr_len
= nf
->netdev
->vnet_hdr_len
;
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
)) {
85 ret
= qemu_chr_fe_write_all(&s
->chr_out
, (uint8_t *)buf
, size
);
93 return ret
< 0 ? ret
: -EIO
;
96 static void coroutine_fn
filter_send_co(void *opaque
)
98 FilterSendCo
*data
= opaque
;
100 data
->ret
= _filter_send(data
->s
, data
->buf
, data
->size
);
106 static int filter_send(MirrorState
*s
,
107 const struct iovec
*iov
,
110 ssize_t size
= iov_size(iov
, iovcnt
);
117 buf
= g_malloc(size
);
118 iov_to_buf(iov
, iovcnt
, 0, buf
, size
);
120 FilterSendCo data
= {
127 Coroutine
*co
= qemu_coroutine_create(filter_send_co
, &data
);
128 qemu_coroutine_enter(co
);
131 aio_poll(qemu_get_aio_context(), true);
137 static void redirector_to_filter(NetFilterState
*nf
,
142 .iov_base
= (void *)buf
,
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
);
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
);
157 static int redirector_chr_can_read(void *opaque
)
159 return REDIRECTOR_MAX_LEN
;
162 static void redirector_chr_read(void *opaque
, const uint8_t *buf
, int size
)
164 NetFilterState
*nf
= opaque
;
165 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
168 ret
= net_fill_rstate(&s
->rs
, buf
, size
);
171 qemu_chr_fe_set_handlers(&s
->chr_in
, NULL
, NULL
, NULL
,
172 NULL
, NULL
, NULL
, true);
176 static void redirector_chr_event(void *opaque
, QEMUChrEvent event
)
178 NetFilterState
*nf
= opaque
;
179 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
182 case CHR_EVENT_CLOSED
:
183 qemu_chr_fe_set_handlers(&s
->chr_in
, NULL
, NULL
, NULL
,
184 NULL
, NULL
, NULL
, true);
191 static ssize_t
filter_mirror_receive_iov(NetFilterState
*nf
,
192 NetClientState
*sender
,
194 const struct iovec
*iov
,
196 NetPacketSent
*sent_cb
)
198 MirrorState
*s
= FILTER_MIRROR(nf
);
201 ret
= filter_send(s
, iov
, iovcnt
);
203 error_report("filter mirror send failed(%s)", strerror(-ret
));
207 * we don't hope this error interrupt the normal
208 * path of net packet, so we always return zero.
213 static ssize_t
filter_redirector_receive_iov(NetFilterState
*nf
,
214 NetClientState
*sender
,
216 const struct iovec
*iov
,
218 NetPacketSent
*sent_cb
)
220 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
223 if (qemu_chr_fe_backend_connected(&s
->chr_out
)) {
224 ret
= filter_send(s
, iov
, iovcnt
);
226 error_report("filter redirector send failed(%s)", strerror(-ret
));
234 static void filter_mirror_cleanup(NetFilterState
*nf
)
236 MirrorState
*s
= FILTER_MIRROR(nf
);
238 qemu_chr_fe_deinit(&s
->chr_out
, false);
241 static void filter_redirector_cleanup(NetFilterState
*nf
)
243 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
245 qemu_chr_fe_deinit(&s
->chr_in
, false);
246 qemu_chr_fe_deinit(&s
->chr_out
, false);
249 static void filter_mirror_setup(NetFilterState
*nf
, Error
**errp
)
251 MirrorState
*s
= FILTER_MIRROR(nf
);
254 if (s
->outdev
== NULL
) {
255 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
, "filter-mirror parameter"\
256 " 'outdev' cannot be empty");
260 chr
= qemu_chr_find(s
->outdev
);
262 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
263 "Device '%s' not found", s
->outdev
);
267 qemu_chr_fe_init(&s
->chr_out
, chr
, errp
);
270 static void redirector_rs_finalize(SocketReadState
*rs
)
272 MirrorState
*s
= container_of(rs
, MirrorState
, rs
);
273 NetFilterState
*nf
= NETFILTER(s
);
275 redirector_to_filter(nf
, rs
->buf
, rs
->packet_len
);
278 static void filter_redirector_setup(NetFilterState
*nf
, Error
**errp
)
280 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
283 if (!s
->indev
&& !s
->outdev
) {
284 error_setg(errp
, "filter redirector needs 'indev' or "
285 "'outdev' at least one property set");
287 } else if (s
->indev
&& s
->outdev
) {
288 if (!strcmp(s
->indev
, s
->outdev
)) {
289 error_setg(errp
, "'indev' and 'outdev' could not be same "
290 "for filter redirector");
295 net_socket_rs_init(&s
->rs
, redirector_rs_finalize
, s
->vnet_hdr
);
298 chr
= qemu_chr_find(s
->indev
);
300 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
301 "IN Device '%s' not found", s
->indev
);
305 if (!qemu_chr_fe_init(&s
->chr_in
, chr
, errp
)) {
309 qemu_chr_fe_set_handlers(&s
->chr_in
, redirector_chr_can_read
,
310 redirector_chr_read
, redirector_chr_event
,
311 NULL
, nf
, NULL
, true);
315 chr
= qemu_chr_find(s
->outdev
);
317 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
318 "OUT Device '%s' not found", s
->outdev
);
321 if (!qemu_chr_fe_init(&s
->chr_out
, chr
, errp
)) {
327 static char *filter_redirector_get_indev(Object
*obj
, Error
**errp
)
329 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
331 return g_strdup(s
->indev
);
334 static void filter_redirector_set_indev(Object
*obj
,
338 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
341 s
->indev
= g_strdup(value
);
344 static char *filter_mirror_get_outdev(Object
*obj
, Error
**errp
)
346 MirrorState
*s
= FILTER_MIRROR(obj
);
348 return g_strdup(s
->outdev
);
351 static void filter_mirror_set_outdev(Object
*obj
,
355 MirrorState
*s
= FILTER_MIRROR(obj
);
358 s
->outdev
= g_strdup(value
);
360 error_setg(errp
, "filter mirror needs 'outdev' "
366 static bool filter_mirror_get_vnet_hdr(Object
*obj
, Error
**errp
)
368 MirrorState
*s
= FILTER_MIRROR(obj
);
373 static void filter_mirror_set_vnet_hdr(Object
*obj
, bool value
, Error
**errp
)
375 MirrorState
*s
= FILTER_MIRROR(obj
);
380 static char *filter_redirector_get_outdev(Object
*obj
, Error
**errp
)
382 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
384 return g_strdup(s
->outdev
);
387 static void filter_redirector_set_outdev(Object
*obj
,
391 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
394 s
->outdev
= g_strdup(value
);
397 static bool filter_redirector_get_vnet_hdr(Object
*obj
, Error
**errp
)
399 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
404 static void filter_redirector_set_vnet_hdr(Object
*obj
,
408 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
413 static void filter_mirror_class_init(ObjectClass
*oc
, void *data
)
415 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
417 object_class_property_add_str(oc
, "outdev", filter_mirror_get_outdev
,
418 filter_mirror_set_outdev
);
419 object_class_property_add_bool(oc
, "vnet_hdr_support",
420 filter_mirror_get_vnet_hdr
,
421 filter_mirror_set_vnet_hdr
);
423 nfc
->setup
= filter_mirror_setup
;
424 nfc
->cleanup
= filter_mirror_cleanup
;
425 nfc
->receive_iov
= filter_mirror_receive_iov
;
428 static void filter_redirector_class_init(ObjectClass
*oc
, void *data
)
430 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
432 object_class_property_add_str(oc
, "indev", filter_redirector_get_indev
,
433 filter_redirector_set_indev
);
434 object_class_property_add_str(oc
, "outdev", filter_redirector_get_outdev
,
435 filter_redirector_set_outdev
);
436 object_class_property_add_bool(oc
, "vnet_hdr_support",
437 filter_redirector_get_vnet_hdr
,
438 filter_redirector_set_vnet_hdr
);
440 nfc
->setup
= filter_redirector_setup
;
441 nfc
->cleanup
= filter_redirector_cleanup
;
442 nfc
->receive_iov
= filter_redirector_receive_iov
;
445 static void filter_mirror_init(Object
*obj
)
447 MirrorState
*s
= FILTER_MIRROR(obj
);
452 static void filter_redirector_init(Object
*obj
)
454 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
459 static void filter_mirror_fini(Object
*obj
)
461 MirrorState
*s
= FILTER_MIRROR(obj
);
466 static void filter_redirector_fini(Object
*obj
)
468 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
474 static const TypeInfo filter_redirector_info
= {
475 .name
= TYPE_FILTER_REDIRECTOR
,
476 .parent
= TYPE_NETFILTER
,
477 .class_init
= filter_redirector_class_init
,
478 .instance_init
= filter_redirector_init
,
479 .instance_finalize
= filter_redirector_fini
,
480 .instance_size
= sizeof(MirrorState
),
483 static const TypeInfo filter_mirror_info
= {
484 .name
= TYPE_FILTER_MIRROR
,
485 .parent
= TYPE_NETFILTER
,
486 .class_init
= filter_mirror_class_init
,
487 .instance_init
= filter_mirror_init
,
488 .instance_finalize
= filter_mirror_fini
,
489 .instance_size
= sizeof(MirrorState
),
492 static void register_types(void)
494 type_register_static(&filter_mirror_info
);
495 type_register_static(&filter_redirector_info
);
498 type_init(register_types
);