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 "qemu-common.h"
16 #include "qapi/error.h"
17 #include "qapi-visit.h"
18 #include "qom/object.h"
19 #include "qemu/main-loop.h"
20 #include "qemu/error-report.h"
22 #include "chardev/char-fe.h"
24 #include "qemu/sockets.h"
26 #define FILTER_MIRROR(obj) \
27 OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_MIRROR)
29 #define FILTER_REDIRECTOR(obj) \
30 OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_REDIRECTOR)
32 #define TYPE_FILTER_MIRROR "filter-mirror"
33 #define TYPE_FILTER_REDIRECTOR "filter-redirector"
34 #define REDIRECTOR_MAX_LEN NET_BUFSIZE
36 typedef struct MirrorState
{
37 NetFilterState parent_obj
;
46 static int filter_send(MirrorState
*s
,
47 const struct iovec
*iov
,
50 NetFilterState
*nf
= NETFILTER(s
);
56 size
= iov_size(iov
, iovcnt
);
62 ret
= qemu_chr_fe_write_all(&s
->chr_out
, (uint8_t *)&len
, sizeof(len
));
63 if (ret
!= sizeof(len
)) {
69 * If vnet_hdr = on, we send vnet header len to make other
70 * module(like colo-compare) know how to parse net
75 vnet_hdr_len
= nf
->netdev
->vnet_hdr_len
;
77 len
= htonl(vnet_hdr_len
);
78 ret
= qemu_chr_fe_write_all(&s
->chr_out
, (uint8_t *)&len
, sizeof(len
));
79 if (ret
!= sizeof(len
)) {
85 iov_to_buf(iov
, iovcnt
, 0, buf
, size
);
86 ret
= qemu_chr_fe_write_all(&s
->chr_out
, (uint8_t *)buf
, size
);
95 return ret
< 0 ? ret
: -EIO
;
98 static void redirector_to_filter(NetFilterState
*nf
,
103 .iov_base
= (void *)buf
,
107 if (nf
->direction
== NET_FILTER_DIRECTION_ALL
||
108 nf
->direction
== NET_FILTER_DIRECTION_TX
) {
109 qemu_netfilter_pass_to_next(nf
->netdev
, 0, &iov
, 1, nf
);
112 if (nf
->direction
== NET_FILTER_DIRECTION_ALL
||
113 nf
->direction
== NET_FILTER_DIRECTION_RX
) {
114 qemu_netfilter_pass_to_next(nf
->netdev
->peer
, 0, &iov
, 1, nf
);
118 static int redirector_chr_can_read(void *opaque
)
120 return REDIRECTOR_MAX_LEN
;
123 static void redirector_chr_read(void *opaque
, const uint8_t *buf
, int size
)
125 NetFilterState
*nf
= opaque
;
126 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
129 ret
= net_fill_rstate(&s
->rs
, buf
, size
);
132 qemu_chr_fe_set_handlers(&s
->chr_in
, NULL
, NULL
, NULL
,
133 NULL
, NULL
, NULL
, true);
137 static void redirector_chr_event(void *opaque
, int event
)
139 NetFilterState
*nf
= opaque
;
140 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
143 case CHR_EVENT_CLOSED
:
144 qemu_chr_fe_set_handlers(&s
->chr_in
, NULL
, NULL
, NULL
,
145 NULL
, NULL
, NULL
, true);
152 static ssize_t
filter_mirror_receive_iov(NetFilterState
*nf
,
153 NetClientState
*sender
,
155 const struct iovec
*iov
,
157 NetPacketSent
*sent_cb
)
159 MirrorState
*s
= FILTER_MIRROR(nf
);
162 ret
= filter_send(s
, iov
, iovcnt
);
164 error_report("filter mirror send failed(%s)", strerror(-ret
));
168 * we don't hope this error interrupt the normal
169 * path of net packet, so we always return zero.
174 static ssize_t
filter_redirector_receive_iov(NetFilterState
*nf
,
175 NetClientState
*sender
,
177 const struct iovec
*iov
,
179 NetPacketSent
*sent_cb
)
181 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
184 if (qemu_chr_fe_backend_connected(&s
->chr_out
)) {
185 ret
= filter_send(s
, iov
, iovcnt
);
187 error_report("filter redirector send failed(%s)", strerror(-ret
));
189 return iov_size(iov
, iovcnt
);
195 static void filter_mirror_cleanup(NetFilterState
*nf
)
197 MirrorState
*s
= FILTER_MIRROR(nf
);
199 qemu_chr_fe_deinit(&s
->chr_out
, false);
202 static void filter_redirector_cleanup(NetFilterState
*nf
)
204 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
206 qemu_chr_fe_deinit(&s
->chr_in
, false);
207 qemu_chr_fe_deinit(&s
->chr_out
, false);
210 static void filter_mirror_setup(NetFilterState
*nf
, Error
**errp
)
212 MirrorState
*s
= FILTER_MIRROR(nf
);
215 if (s
->outdev
== NULL
) {
216 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
, "filter-mirror parameter"\
217 " 'outdev' cannot be empty");
221 chr
= qemu_chr_find(s
->outdev
);
223 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
224 "Device '%s' not found", s
->outdev
);
228 qemu_chr_fe_init(&s
->chr_out
, chr
, errp
);
231 static void redirector_rs_finalize(SocketReadState
*rs
)
233 MirrorState
*s
= container_of(rs
, MirrorState
, rs
);
234 NetFilterState
*nf
= NETFILTER(s
);
236 redirector_to_filter(nf
, rs
->buf
, rs
->packet_len
);
239 static void filter_redirector_setup(NetFilterState
*nf
, Error
**errp
)
241 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
244 if (!s
->indev
&& !s
->outdev
) {
245 error_setg(errp
, "filter redirector needs 'indev' or "
246 "'outdev' at least one property set");
248 } else if (s
->indev
&& s
->outdev
) {
249 if (!strcmp(s
->indev
, s
->outdev
)) {
250 error_setg(errp
, "'indev' and 'outdev' could not be same "
251 "for filter redirector");
256 net_socket_rs_init(&s
->rs
, redirector_rs_finalize
, s
->vnet_hdr
);
259 chr
= qemu_chr_find(s
->indev
);
261 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
262 "IN Device '%s' not found", s
->indev
);
266 if (!qemu_chr_fe_init(&s
->chr_in
, chr
, errp
)) {
270 qemu_chr_fe_set_handlers(&s
->chr_in
, redirector_chr_can_read
,
271 redirector_chr_read
, redirector_chr_event
,
272 NULL
, nf
, NULL
, true);
276 chr
= qemu_chr_find(s
->outdev
);
278 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
279 "OUT Device '%s' not found", s
->outdev
);
282 if (!qemu_chr_fe_init(&s
->chr_out
, chr
, errp
)) {
288 static void filter_mirror_class_init(ObjectClass
*oc
, void *data
)
290 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
292 nfc
->setup
= filter_mirror_setup
;
293 nfc
->cleanup
= filter_mirror_cleanup
;
294 nfc
->receive_iov
= filter_mirror_receive_iov
;
297 static void filter_redirector_class_init(ObjectClass
*oc
, void *data
)
299 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
301 nfc
->setup
= filter_redirector_setup
;
302 nfc
->cleanup
= filter_redirector_cleanup
;
303 nfc
->receive_iov
= filter_redirector_receive_iov
;
306 static char *filter_redirector_get_indev(Object
*obj
, Error
**errp
)
308 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
310 return g_strdup(s
->indev
);
313 static void filter_redirector_set_indev(Object
*obj
,
317 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
320 s
->indev
= g_strdup(value
);
323 static char *filter_mirror_get_outdev(Object
*obj
, Error
**errp
)
325 MirrorState
*s
= FILTER_MIRROR(obj
);
327 return g_strdup(s
->outdev
);
330 static void filter_mirror_set_outdev(Object
*obj
,
334 MirrorState
*s
= FILTER_MIRROR(obj
);
337 s
->outdev
= g_strdup(value
);
339 error_setg(errp
, "filter mirror needs 'outdev' "
345 static bool filter_mirror_get_vnet_hdr(Object
*obj
, Error
**errp
)
347 MirrorState
*s
= FILTER_MIRROR(obj
);
352 static void filter_mirror_set_vnet_hdr(Object
*obj
, bool value
, Error
**errp
)
354 MirrorState
*s
= FILTER_MIRROR(obj
);
359 static char *filter_redirector_get_outdev(Object
*obj
, Error
**errp
)
361 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
363 return g_strdup(s
->outdev
);
366 static void filter_redirector_set_outdev(Object
*obj
,
370 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
373 s
->outdev
= g_strdup(value
);
376 static bool filter_redirector_get_vnet_hdr(Object
*obj
, Error
**errp
)
378 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
383 static void filter_redirector_set_vnet_hdr(Object
*obj
,
387 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
392 static void filter_mirror_init(Object
*obj
)
394 MirrorState
*s
= FILTER_MIRROR(obj
);
396 object_property_add_str(obj
, "outdev", filter_mirror_get_outdev
,
397 filter_mirror_set_outdev
, NULL
);
400 object_property_add_bool(obj
, "vnet_hdr_support",
401 filter_mirror_get_vnet_hdr
,
402 filter_mirror_set_vnet_hdr
, NULL
);
405 static void filter_redirector_init(Object
*obj
)
407 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
409 object_property_add_str(obj
, "indev", filter_redirector_get_indev
,
410 filter_redirector_set_indev
, NULL
);
411 object_property_add_str(obj
, "outdev", filter_redirector_get_outdev
,
412 filter_redirector_set_outdev
, NULL
);
415 object_property_add_bool(obj
, "vnet_hdr_support",
416 filter_redirector_get_vnet_hdr
,
417 filter_redirector_set_vnet_hdr
, NULL
);
420 static void filter_mirror_fini(Object
*obj
)
422 MirrorState
*s
= FILTER_MIRROR(obj
);
427 static void filter_redirector_fini(Object
*obj
)
429 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
435 static const TypeInfo filter_redirector_info
= {
436 .name
= TYPE_FILTER_REDIRECTOR
,
437 .parent
= TYPE_NETFILTER
,
438 .class_init
= filter_redirector_class_init
,
439 .instance_init
= filter_redirector_init
,
440 .instance_finalize
= filter_redirector_fini
,
441 .instance_size
= sizeof(MirrorState
),
444 static const TypeInfo filter_mirror_info
= {
445 .name
= TYPE_FILTER_MIRROR
,
446 .parent
= TYPE_NETFILTER
,
447 .class_init
= filter_mirror_class_init
,
448 .instance_init
= filter_mirror_init
,
449 .instance_finalize
= filter_mirror_fini
,
450 .instance_size
= sizeof(MirrorState
),
453 static void register_types(void)
455 type_register_static(&filter_mirror_info
);
456 type_register_static(&filter_redirector_info
);
459 type_init(register_types
);