qemu/net/filter-buffer.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 FUJITSU LIMITED
   3 * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
   4 *
   5 * This work is licensed under the terms of the GNU GPL, version 2 or
   6 * later.  See the COPYING file in the top-level directory.
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "net/filter.h"
  11#include "net/queue.h"
  12#include "qapi/error.h"
  13#include "qemu/timer.h"
  14#include "qemu/iov.h"
  15#include "qapi/qapi-builtin-visit.h"
  16#include "qapi/qmp/qerror.h"
  17#include "qom/object.h"
  18
  19#define TYPE_FILTER_BUFFER "filter-buffer"
  20
  21#define FILTER_BUFFER(obj) \
  22    OBJECT_CHECK(FilterBufferState, (obj), TYPE_FILTER_BUFFER)
  23
  24typedef struct FilterBufferState {
  25    NetFilterState parent_obj;
  26
  27    NetQueue *incoming_queue;
  28    uint32_t interval;
  29    QEMUTimer release_timer;
  30} FilterBufferState;
  31
  32static void filter_buffer_flush(NetFilterState *nf)
  33{
  34    FilterBufferState *s = FILTER_BUFFER(nf);
  35
  36    if (!qemu_net_queue_flush(s->incoming_queue)) {
  37        /* Unable to empty the queue, purge remaining packets */
  38        qemu_net_queue_purge(s->incoming_queue, nf->netdev);
  39    }
  40}
  41
  42static void filter_buffer_release_timer(void *opaque)
  43{
  44    NetFilterState *nf = opaque;
  45    FilterBufferState *s = FILTER_BUFFER(nf);
  46
  47    /*
  48     * Note: filter_buffer_flush() drops packets that can't be sent
  49     * TODO: We should leave them queued.  But currently there's no way
  50     * for the next filter or receiver to notify us that it can receive
  51     * more packets.
  52     */
  53    filter_buffer_flush(nf);
  54    /* Timer rearmed to fire again in s->interval microseconds. */
  55    timer_mod(&s->release_timer,
  56              qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
  57}
  58
  59/* filter APIs */
  60static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
  61                                         NetClientState *sender,
  62                                         unsigned flags,
  63                                         const struct iovec *iov,
  64                                         int iovcnt,
  65                                         NetPacketSent *sent_cb)
  66{
  67    FilterBufferState *s = FILTER_BUFFER(nf);
  68
  69    /*
  70     * We return size when buffer a packet, the sender will take it as
  71     * a already sent packet, so sent_cb should not be called later.
  72     *
  73     * FIXME: Even if the guest can't receive packets for some reasons,
  74     * the filter can still accept packets until its internal queue is full.
  75     * For example:
  76     *   For some reason, receiver could not receive more packets
  77     * (.can_receive() returns zero). Without a filter, at most one packet
  78     * will be queued in incoming queue and sender's poll will be disabled
  79     * unit its sent_cb() was called. With a filter, it will keep receiving
  80     * the packets without caring about the receiver. This is suboptimal.
  81     * May need more thoughts (e.g keeping sent_cb).
  82     */
  83    qemu_net_queue_append_iov(s->incoming_queue, sender, flags,
  84                              iov, iovcnt, NULL);
  85    return iov_size(iov, iovcnt);
  86}
  87
  88static void filter_buffer_cleanup(NetFilterState *nf)
  89{
  90    FilterBufferState *s = FILTER_BUFFER(nf);
  91
  92    if (s->interval) {
  93        timer_del(&s->release_timer);
  94    }
  95
  96    /* flush packets */
  97    if (s->incoming_queue) {
  98        filter_buffer_flush(nf);
  99        g_free(s->incoming_queue);
 100    }
 101}
 102
 103static void filter_buffer_setup_timer(NetFilterState *nf)
 104{
 105    FilterBufferState *s = FILTER_BUFFER(nf);
 106
 107    if (s->interval) {
 108        timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
 109                      filter_buffer_release_timer, nf);
 110        /* Timer armed to fire in s->interval microseconds. */
 111        timer_mod(&s->release_timer,
 112                  qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
 113    }
 114}
 115
 116static void filter_buffer_setup(NetFilterState *nf, Error **errp)
 117{
 118    FilterBufferState *s = FILTER_BUFFER(nf);
 119
 120    /*
 121     * We may want to accept zero interval when VM FT solutions like MC
 122     * or COLO use this filter to release packets on demand.
 123     */
 124    if (!s->interval) {
 125        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "interval",
 126                   "a non-zero interval");
 127        return;
 128    }
 129
 130    s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
 131    filter_buffer_setup_timer(nf);
 132}
 133
 134static void filter_buffer_status_changed(NetFilterState *nf, Error **errp)
 135{
 136    FilterBufferState *s = FILTER_BUFFER(nf);
 137
 138    if (!nf->on) {
 139        if (s->interval) {
 140            timer_del(&s->release_timer);
 141        }
 142        filter_buffer_flush(nf);
 143    } else {
 144        filter_buffer_setup_timer(nf);
 145    }
 146}
 147
 148static void filter_buffer_class_init(ObjectClass *oc, void *data)
 149{
 150    NetFilterClass *nfc = NETFILTER_CLASS(oc);
 151
 152    nfc->setup = filter_buffer_setup;
 153    nfc->cleanup = filter_buffer_cleanup;
 154    nfc->receive_iov = filter_buffer_receive_iov;
 155    nfc->status_changed = filter_buffer_status_changed;
 156}
 157
 158static void filter_buffer_get_interval(Object *obj, Visitor *v,
 159                                       const char *name, void *opaque,
 160                                       Error **errp)
 161{
 162    FilterBufferState *s = FILTER_BUFFER(obj);
 163    uint32_t value = s->interval;
 164
 165    visit_type_uint32(v, name, &value, errp);
 166}
 167
 168static void filter_buffer_set_interval(Object *obj, Visitor *v,
 169                                       const char *name, void *opaque,
 170                                       Error **errp)
 171{
 172    FilterBufferState *s = FILTER_BUFFER(obj);
 173    Error *local_err = NULL;
 174    uint32_t value;
 175
 176    visit_type_uint32(v, name, &value, &local_err);
 177    if (local_err) {
 178        goto out;
 179    }
 180    if (!value) {
 181        error_setg(&local_err, "Property '%s.%s' requires a positive value",
 182                   object_get_typename(obj), name);
 183        goto out;
 184    }
 185    s->interval = value;
 186
 187out:
 188    error_propagate(errp, local_err);
 189}
 190
 191static void filter_buffer_init(Object *obj)
 192{
 193    object_property_add(obj, "interval", "uint32",
 194                        filter_buffer_get_interval,
 195                        filter_buffer_set_interval, NULL, NULL, NULL);
 196}
 197
 198static const TypeInfo filter_buffer_info = {
 199    .name = TYPE_FILTER_BUFFER,
 200    .parent = TYPE_NETFILTER,
 201    .class_init = filter_buffer_class_init,
 202    .instance_init = filter_buffer_init,
 203    .instance_size = sizeof(FilterBufferState),
 204};
 205
 206static void register_types(void)
 207{
 208    type_register_static(&filter_buffer_info);
 209}
 210
 211type_init(register_types);
 212