17dbb11c8SYang Hongyang /*
27dbb11c8SYang Hongyang * Copyright (c) 2015 FUJITSU LIMITED
37dbb11c8SYang Hongyang * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
47dbb11c8SYang Hongyang *
57dbb11c8SYang Hongyang * This work is licensed under the terms of the GNU GPL, version 2 or
67dbb11c8SYang Hongyang * later. See the COPYING file in the top-level directory.
77dbb11c8SYang Hongyang */
87dbb11c8SYang Hongyang
92744d920SPeter Maydell #include "qemu/osdep.h"
107dbb11c8SYang Hongyang #include "net/filter.h"
117dbb11c8SYang Hongyang #include "net/queue.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
137dbb11c8SYang Hongyang #include "qemu/timer.h"
147dbb11c8SYang Hongyang #include "qemu/iov.h"
15eb815e24SMarkus Armbruster #include "qapi/qapi-builtin-visit.h"
167dbb11c8SYang Hongyang #include "qapi/qmp/qerror.h"
177dbb11c8SYang Hongyang #include "qom/object.h"
187dbb11c8SYang Hongyang
197dbb11c8SYang Hongyang #define TYPE_FILTER_BUFFER "filter-buffer"
207dbb11c8SYang Hongyang
218063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(FilterBufferState, FILTER_BUFFER)
227dbb11c8SYang Hongyang
23db1015e9SEduardo Habkost struct FilterBufferState {
247dbb11c8SYang Hongyang NetFilterState parent_obj;
257dbb11c8SYang Hongyang
267dbb11c8SYang Hongyang NetQueue *incoming_queue;
277dbb11c8SYang Hongyang uint32_t interval;
287dbb11c8SYang Hongyang QEMUTimer release_timer;
29db1015e9SEduardo Habkost };
307dbb11c8SYang Hongyang
filter_buffer_flush(NetFilterState * nf)317dbb11c8SYang Hongyang static void filter_buffer_flush(NetFilterState *nf)
327dbb11c8SYang Hongyang {
337dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(nf);
347dbb11c8SYang Hongyang
357dbb11c8SYang Hongyang if (!qemu_net_queue_flush(s->incoming_queue)) {
367dbb11c8SYang Hongyang /* Unable to empty the queue, purge remaining packets */
377dbb11c8SYang Hongyang qemu_net_queue_purge(s->incoming_queue, nf->netdev);
387dbb11c8SYang Hongyang }
397dbb11c8SYang Hongyang }
407dbb11c8SYang Hongyang
filter_buffer_release_timer(void * opaque)417dbb11c8SYang Hongyang static void filter_buffer_release_timer(void *opaque)
427dbb11c8SYang Hongyang {
437dbb11c8SYang Hongyang NetFilterState *nf = opaque;
447dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(nf);
457dbb11c8SYang Hongyang
467dbb11c8SYang Hongyang /*
477dbb11c8SYang Hongyang * Note: filter_buffer_flush() drops packets that can't be sent
487dbb11c8SYang Hongyang * TODO: We should leave them queued. But currently there's no way
497dbb11c8SYang Hongyang * for the next filter or receiver to notify us that it can receive
507dbb11c8SYang Hongyang * more packets.
517dbb11c8SYang Hongyang */
527dbb11c8SYang Hongyang filter_buffer_flush(nf);
537dbb11c8SYang Hongyang /* Timer rearmed to fire again in s->interval microseconds. */
547dbb11c8SYang Hongyang timer_mod(&s->release_timer,
557dbb11c8SYang Hongyang qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
567dbb11c8SYang Hongyang }
577dbb11c8SYang Hongyang
587dbb11c8SYang Hongyang /* filter APIs */
filter_buffer_receive_iov(NetFilterState * nf,NetClientState * sender,unsigned flags,const struct iovec * iov,int iovcnt,NetPacketSent * sent_cb)597dbb11c8SYang Hongyang static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
607dbb11c8SYang Hongyang NetClientState *sender,
617dbb11c8SYang Hongyang unsigned flags,
627dbb11c8SYang Hongyang const struct iovec *iov,
637dbb11c8SYang Hongyang int iovcnt,
647dbb11c8SYang Hongyang NetPacketSent *sent_cb)
657dbb11c8SYang Hongyang {
667dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(nf);
677dbb11c8SYang Hongyang
687dbb11c8SYang Hongyang /*
697dbb11c8SYang Hongyang * We return size when buffer a packet, the sender will take it as
707dbb11c8SYang Hongyang * a already sent packet, so sent_cb should not be called later.
717dbb11c8SYang Hongyang *
727dbb11c8SYang Hongyang * FIXME: Even if the guest can't receive packets for some reasons,
737dbb11c8SYang Hongyang * the filter can still accept packets until its internal queue is full.
747dbb11c8SYang Hongyang * For example:
757dbb11c8SYang Hongyang * For some reason, receiver could not receive more packets
76b8c4b67eSPhilippe Mathieu-Daudé * (.can_receive() returns false). Without a filter, at most one packet
777dbb11c8SYang Hongyang * will be queued in incoming queue and sender's poll will be disabled
787dbb11c8SYang Hongyang * unit its sent_cb() was called. With a filter, it will keep receiving
797dbb11c8SYang Hongyang * the packets without caring about the receiver. This is suboptimal.
807dbb11c8SYang Hongyang * May need more thoughts (e.g keeping sent_cb).
817dbb11c8SYang Hongyang */
827dbb11c8SYang Hongyang qemu_net_queue_append_iov(s->incoming_queue, sender, flags,
837dbb11c8SYang Hongyang iov, iovcnt, NULL);
847dbb11c8SYang Hongyang return iov_size(iov, iovcnt);
857dbb11c8SYang Hongyang }
867dbb11c8SYang Hongyang
filter_buffer_cleanup(NetFilterState * nf)877dbb11c8SYang Hongyang static void filter_buffer_cleanup(NetFilterState *nf)
887dbb11c8SYang Hongyang {
897dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(nf);
907dbb11c8SYang Hongyang
917dbb11c8SYang Hongyang if (s->interval) {
927dbb11c8SYang Hongyang timer_del(&s->release_timer);
937dbb11c8SYang Hongyang }
947dbb11c8SYang Hongyang
957dbb11c8SYang Hongyang /* flush packets */
967dbb11c8SYang Hongyang if (s->incoming_queue) {
977dbb11c8SYang Hongyang filter_buffer_flush(nf);
987dbb11c8SYang Hongyang g_free(s->incoming_queue);
997dbb11c8SYang Hongyang }
1007dbb11c8SYang Hongyang }
1017dbb11c8SYang Hongyang
filter_buffer_setup_timer(NetFilterState * nf)102f1b2bc60Szhanghailiang static void filter_buffer_setup_timer(NetFilterState *nf)
103f1b2bc60Szhanghailiang {
104f1b2bc60Szhanghailiang FilterBufferState *s = FILTER_BUFFER(nf);
105f1b2bc60Szhanghailiang
106f1b2bc60Szhanghailiang if (s->interval) {
107f1b2bc60Szhanghailiang timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
108f1b2bc60Szhanghailiang filter_buffer_release_timer, nf);
109f1b2bc60Szhanghailiang /* Timer armed to fire in s->interval microseconds. */
110f1b2bc60Szhanghailiang timer_mod(&s->release_timer,
111f1b2bc60Szhanghailiang qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
112f1b2bc60Szhanghailiang }
113f1b2bc60Szhanghailiang }
114f1b2bc60Szhanghailiang
filter_buffer_setup(NetFilterState * nf,Error ** errp)1157dbb11c8SYang Hongyang static void filter_buffer_setup(NetFilterState *nf, Error **errp)
1167dbb11c8SYang Hongyang {
1177dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(nf);
1187dbb11c8SYang Hongyang
1197dbb11c8SYang Hongyang /*
1207dbb11c8SYang Hongyang * We may want to accept zero interval when VM FT solutions like MC
1217dbb11c8SYang Hongyang * or COLO use this filter to release packets on demand.
1227dbb11c8SYang Hongyang */
1237dbb11c8SYang Hongyang if (!s->interval) {
1247dbb11c8SYang Hongyang error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "interval",
1257dbb11c8SYang Hongyang "a non-zero interval");
1267dbb11c8SYang Hongyang return;
1277dbb11c8SYang Hongyang }
1287dbb11c8SYang Hongyang
1297dbb11c8SYang Hongyang s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
130f1b2bc60Szhanghailiang filter_buffer_setup_timer(nf);
131f1b2bc60Szhanghailiang }
132f1b2bc60Szhanghailiang
filter_buffer_status_changed(NetFilterState * nf,Error ** errp)133f1b2bc60Szhanghailiang static void filter_buffer_status_changed(NetFilterState *nf, Error **errp)
134f1b2bc60Szhanghailiang {
135f1b2bc60Szhanghailiang FilterBufferState *s = FILTER_BUFFER(nf);
136f1b2bc60Szhanghailiang
137f1b2bc60Szhanghailiang if (!nf->on) {
1387dbb11c8SYang Hongyang if (s->interval) {
139f1b2bc60Szhanghailiang timer_del(&s->release_timer);
140f1b2bc60Szhanghailiang }
141f1b2bc60Szhanghailiang filter_buffer_flush(nf);
142f1b2bc60Szhanghailiang } else {
143f1b2bc60Szhanghailiang filter_buffer_setup_timer(nf);
1447dbb11c8SYang Hongyang }
1457dbb11c8SYang Hongyang }
1467dbb11c8SYang Hongyang
filter_buffer_get_interval(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)147d7bce999SEric Blake static void filter_buffer_get_interval(Object *obj, Visitor *v,
148d7bce999SEric Blake const char *name, void *opaque,
149d7bce999SEric Blake Error **errp)
1507dbb11c8SYang Hongyang {
1517dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(obj);
1527dbb11c8SYang Hongyang uint32_t value = s->interval;
1537dbb11c8SYang Hongyang
15451e72bc1SEric Blake visit_type_uint32(v, name, &value, errp);
1557dbb11c8SYang Hongyang }
1567dbb11c8SYang Hongyang
filter_buffer_set_interval(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)157d7bce999SEric Blake static void filter_buffer_set_interval(Object *obj, Visitor *v,
158d7bce999SEric Blake const char *name, void *opaque,
159d7bce999SEric Blake Error **errp)
1607dbb11c8SYang Hongyang {
1617dbb11c8SYang Hongyang FilterBufferState *s = FILTER_BUFFER(obj);
1627dbb11c8SYang Hongyang uint32_t value;
1637dbb11c8SYang Hongyang
164668f62ecSMarkus Armbruster if (!visit_type_uint32(v, name, &value, errp)) {
165dcfe4805SMarkus Armbruster return;
1667dbb11c8SYang Hongyang }
1677dbb11c8SYang Hongyang if (!value) {
168dcfe4805SMarkus Armbruster error_setg(errp, "Property '%s.%s' requires a positive value",
1697dbb11c8SYang Hongyang object_get_typename(obj), name);
170dcfe4805SMarkus Armbruster return;
1717dbb11c8SYang Hongyang }
1727dbb11c8SYang Hongyang s->interval = value;
1737dbb11c8SYang Hongyang }
1747dbb11c8SYang Hongyang
filter_buffer_class_init(ObjectClass * oc,void * data)1756d11ea6dSEduardo Habkost static void filter_buffer_class_init(ObjectClass *oc, void *data)
1766d11ea6dSEduardo Habkost {
1776d11ea6dSEduardo Habkost NetFilterClass *nfc = NETFILTER_CLASS(oc);
1786d11ea6dSEduardo Habkost
179*f0e34a06SEduardo Habkost object_class_property_add(oc, "interval", "uint32",
180*f0e34a06SEduardo Habkost filter_buffer_get_interval,
181*f0e34a06SEduardo Habkost filter_buffer_set_interval, NULL, NULL);
182*f0e34a06SEduardo Habkost
1836d11ea6dSEduardo Habkost nfc->setup = filter_buffer_setup;
1846d11ea6dSEduardo Habkost nfc->cleanup = filter_buffer_cleanup;
1856d11ea6dSEduardo Habkost nfc->receive_iov = filter_buffer_receive_iov;
1866d11ea6dSEduardo Habkost nfc->status_changed = filter_buffer_status_changed;
1876d11ea6dSEduardo Habkost }
1886d11ea6dSEduardo Habkost
1897dbb11c8SYang Hongyang static const TypeInfo filter_buffer_info = {
1907dbb11c8SYang Hongyang .name = TYPE_FILTER_BUFFER,
1917dbb11c8SYang Hongyang .parent = TYPE_NETFILTER,
1927dbb11c8SYang Hongyang .class_init = filter_buffer_class_init,
1937dbb11c8SYang Hongyang .instance_size = sizeof(FilterBufferState),
1947dbb11c8SYang Hongyang };
1957dbb11c8SYang Hongyang
register_types(void)1967dbb11c8SYang Hongyang static void register_types(void)
1977dbb11c8SYang Hongyang {
1987dbb11c8SYang Hongyang type_register_static(&filter_buffer_info);
1997dbb11c8SYang Hongyang }
2007dbb11c8SYang Hongyang
2017dbb11c8SYang Hongyang type_init(register_types);
202