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/qmp/qerror.h"
18 #include "qapi-visit.h"
19 #include "qom/object.h"
20 #include "qemu/main-loop.h"
21 #include "qemu/error-report.h"
23 #include "sysemu/char.h"
25 #include "qemu/sockets.h"
27 #define FILTER_MIRROR(obj) \
28 OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_MIRROR)
30 #define FILTER_REDIRECTOR(obj) \
31 OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_REDIRECTOR)
33 #define TYPE_FILTER_MIRROR "filter-mirror"
34 #define TYPE_FILTER_REDIRECTOR "filter-redirector"
35 #define REDIRECTOR_MAX_LEN NET_BUFSIZE
37 typedef struct MirrorState
{
38 NetFilterState parent_obj
;
41 CharDriverState
*chr_in
;
42 CharDriverState
*chr_out
;
46 static int filter_mirror_send(CharDriverState
*chr_out
,
47 const struct iovec
*iov
,
55 size
= iov_size(iov
, iovcnt
);
61 ret
= qemu_chr_fe_write_all(chr_out
, (uint8_t *)&len
, sizeof(len
));
62 if (ret
!= sizeof(len
)) {
67 iov_to_buf(iov
, iovcnt
, 0, buf
, size
);
68 ret
= qemu_chr_fe_write_all(chr_out
, (uint8_t *)buf
, size
);
77 return ret
< 0 ? ret
: -EIO
;
81 redirector_to_filter(NetFilterState
*nf
, const uint8_t *buf
, int len
)
84 .iov_base
= (void *)buf
,
88 if (nf
->direction
== NET_FILTER_DIRECTION_ALL
||
89 nf
->direction
== NET_FILTER_DIRECTION_TX
) {
90 qemu_netfilter_pass_to_next(nf
->netdev
, 0, &iov
, 1, nf
);
93 if (nf
->direction
== NET_FILTER_DIRECTION_ALL
||
94 nf
->direction
== NET_FILTER_DIRECTION_RX
) {
95 qemu_netfilter_pass_to_next(nf
->netdev
->peer
, 0, &iov
, 1, nf
);
99 static int redirector_chr_can_read(void *opaque
)
101 return REDIRECTOR_MAX_LEN
;
104 static void redirector_chr_read(void *opaque
, const uint8_t *buf
, int size
)
106 NetFilterState
*nf
= opaque
;
107 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
110 ret
= net_fill_rstate(&s
->rs
, buf
, size
);
113 qemu_chr_add_handlers(s
->chr_in
, NULL
, NULL
, NULL
, NULL
);
117 static void redirector_chr_event(void *opaque
, int event
)
119 NetFilterState
*nf
= opaque
;
120 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
123 case CHR_EVENT_CLOSED
:
124 qemu_chr_add_handlers(s
->chr_in
, NULL
, NULL
, NULL
, NULL
);
131 static ssize_t
filter_mirror_receive_iov(NetFilterState
*nf
,
132 NetClientState
*sender
,
134 const struct iovec
*iov
,
136 NetPacketSent
*sent_cb
)
138 MirrorState
*s
= FILTER_MIRROR(nf
);
141 ret
= filter_mirror_send(s
->chr_out
, iov
, iovcnt
);
143 error_report("filter_mirror_send failed(%s)", strerror(-ret
));
147 * we don't hope this error interrupt the normal
148 * path of net packet, so we always return zero.
153 static ssize_t
filter_redirector_receive_iov(NetFilterState
*nf
,
154 NetClientState
*sender
,
156 const struct iovec
*iov
,
158 NetPacketSent
*sent_cb
)
160 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
164 ret
= filter_mirror_send(s
->chr_out
, iov
, iovcnt
);
166 error_report("filter_mirror_send failed(%s)", strerror(-ret
));
168 return iov_size(iov
, iovcnt
);
174 static void filter_mirror_cleanup(NetFilterState
*nf
)
176 MirrorState
*s
= FILTER_MIRROR(nf
);
179 qemu_chr_fe_release(s
->chr_out
);
183 static void filter_redirector_cleanup(NetFilterState
*nf
)
185 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
188 qemu_chr_add_handlers(s
->chr_in
, NULL
, NULL
, NULL
, NULL
);
189 qemu_chr_fe_release(s
->chr_in
);
192 qemu_chr_fe_release(s
->chr_out
);
196 static void filter_mirror_setup(NetFilterState
*nf
, Error
**errp
)
198 MirrorState
*s
= FILTER_MIRROR(nf
);
201 error_setg(errp
, "filter filter mirror needs 'outdev' "
206 s
->chr_out
= qemu_chr_find(s
->outdev
);
207 if (s
->chr_out
== NULL
) {
208 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
209 "Device '%s' not found", s
->outdev
);
213 if (qemu_chr_fe_claim(s
->chr_out
) != 0) {
214 error_setg(errp
, QERR_DEVICE_IN_USE
, s
->outdev
);
219 static void redirector_rs_finalize(SocketReadState
*rs
)
221 MirrorState
*s
= container_of(rs
, MirrorState
, rs
);
222 NetFilterState
*nf
= NETFILTER(s
);
224 redirector_to_filter(nf
, rs
->buf
, rs
->packet_len
);
227 static void filter_redirector_setup(NetFilterState
*nf
, Error
**errp
)
229 MirrorState
*s
= FILTER_REDIRECTOR(nf
);
231 if (!s
->indev
&& !s
->outdev
) {
232 error_setg(errp
, "filter redirector needs 'indev' or "
233 "'outdev' at least one property set");
235 } else if (s
->indev
&& s
->outdev
) {
236 if (!strcmp(s
->indev
, s
->outdev
)) {
237 error_setg(errp
, "'indev' and 'outdev' could not be same "
238 "for filter redirector");
243 net_socket_rs_init(&s
->rs
, redirector_rs_finalize
);
246 s
->chr_in
= qemu_chr_find(s
->indev
);
247 if (s
->chr_in
== NULL
) {
248 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
249 "IN Device '%s' not found", s
->indev
);
253 qemu_chr_fe_claim_no_fail(s
->chr_in
);
254 qemu_chr_add_handlers(s
->chr_in
, redirector_chr_can_read
,
255 redirector_chr_read
, redirector_chr_event
, nf
);
259 s
->chr_out
= qemu_chr_find(s
->outdev
);
260 if (s
->chr_out
== NULL
) {
261 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
262 "OUT Device '%s' not found", s
->outdev
);
265 qemu_chr_fe_claim_no_fail(s
->chr_out
);
269 static void filter_mirror_class_init(ObjectClass
*oc
, void *data
)
271 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
273 nfc
->setup
= filter_mirror_setup
;
274 nfc
->cleanup
= filter_mirror_cleanup
;
275 nfc
->receive_iov
= filter_mirror_receive_iov
;
278 static void filter_redirector_class_init(ObjectClass
*oc
, void *data
)
280 NetFilterClass
*nfc
= NETFILTER_CLASS(oc
);
282 nfc
->setup
= filter_redirector_setup
;
283 nfc
->cleanup
= filter_redirector_cleanup
;
284 nfc
->receive_iov
= filter_redirector_receive_iov
;
287 static char *filter_redirector_get_indev(Object
*obj
, Error
**errp
)
289 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
291 return g_strdup(s
->indev
);
295 filter_redirector_set_indev(Object
*obj
, const char *value
, Error
**errp
)
297 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
300 s
->indev
= g_strdup(value
);
303 static char *filter_mirror_get_outdev(Object
*obj
, Error
**errp
)
305 MirrorState
*s
= FILTER_MIRROR(obj
);
307 return g_strdup(s
->outdev
);
311 filter_mirror_set_outdev(Object
*obj
, const char *value
, Error
**errp
)
313 MirrorState
*s
= FILTER_MIRROR(obj
);
316 s
->outdev
= g_strdup(value
);
318 error_setg(errp
, "filter filter mirror needs 'outdev' "
324 static char *filter_redirector_get_outdev(Object
*obj
, Error
**errp
)
326 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
328 return g_strdup(s
->outdev
);
332 filter_redirector_set_outdev(Object
*obj
, const char *value
, Error
**errp
)
334 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
337 s
->outdev
= g_strdup(value
);
340 static void filter_mirror_init(Object
*obj
)
342 object_property_add_str(obj
, "outdev", filter_mirror_get_outdev
,
343 filter_mirror_set_outdev
, NULL
);
346 static void filter_redirector_init(Object
*obj
)
348 object_property_add_str(obj
, "indev", filter_redirector_get_indev
,
349 filter_redirector_set_indev
, NULL
);
350 object_property_add_str(obj
, "outdev", filter_redirector_get_outdev
,
351 filter_redirector_set_outdev
, NULL
);
354 static void filter_mirror_fini(Object
*obj
)
356 MirrorState
*s
= FILTER_MIRROR(obj
);
361 static void filter_redirector_fini(Object
*obj
)
363 MirrorState
*s
= FILTER_REDIRECTOR(obj
);
369 static const TypeInfo filter_redirector_info
= {
370 .name
= TYPE_FILTER_REDIRECTOR
,
371 .parent
= TYPE_NETFILTER
,
372 .class_init
= filter_redirector_class_init
,
373 .instance_init
= filter_redirector_init
,
374 .instance_finalize
= filter_redirector_fini
,
375 .instance_size
= sizeof(MirrorState
),
378 static const TypeInfo filter_mirror_info
= {
379 .name
= TYPE_FILTER_MIRROR
,
380 .parent
= TYPE_NETFILTER
,
381 .class_init
= filter_mirror_class_init
,
382 .instance_init
= filter_mirror_init
,
383 .instance_finalize
= filter_mirror_fini
,
384 .instance_size
= sizeof(MirrorState
),
387 static void register_types(void)
389 type_register_static(&filter_mirror_info
);
390 type_register_static(&filter_redirector_info
);
393 type_init(register_types
);