qemu/net/filter-mirror.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
   3 * Copyright (c) 2016 FUJITSU LIMITED
   4 * Copyright (c) 2016 Intel Corporation
   5 *
   6 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
   7 *
   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.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "net/filter.h"
  14#include "net/net.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"
  22#include "trace.h"
  23#include "sysemu/char.h"
  24#include "qemu/iov.h"
  25#include "qemu/sockets.h"
  26
  27#define FILTER_MIRROR(obj) \
  28    OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_MIRROR)
  29
  30#define FILTER_REDIRECTOR(obj) \
  31    OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_REDIRECTOR)
  32
  33#define TYPE_FILTER_MIRROR "filter-mirror"
  34#define TYPE_FILTER_REDIRECTOR "filter-redirector"
  35#define REDIRECTOR_MAX_LEN NET_BUFSIZE
  36
  37typedef struct MirrorState {
  38    NetFilterState parent_obj;
  39    char *indev;
  40    char *outdev;
  41    CharBackend chr_in;
  42    CharBackend chr_out;
  43    SocketReadState rs;
  44} MirrorState;
  45
  46static int filter_mirror_send(CharBackend *chr_out,
  47                              const struct iovec *iov,
  48                              int iovcnt)
  49{
  50    int ret = 0;
  51    ssize_t size = 0;
  52    uint32_t len =  0;
  53    char *buf;
  54
  55    size = iov_size(iov, iovcnt);
  56    if (!size) {
  57        return 0;
  58    }
  59
  60    len = htonl(size);
  61    ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)&len, sizeof(len));
  62    if (ret != sizeof(len)) {
  63        goto err;
  64    }
  65
  66    buf = g_malloc(size);
  67    iov_to_buf(iov, iovcnt, 0, buf, size);
  68    ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)buf, size);
  69    g_free(buf);
  70    if (ret != size) {
  71        goto err;
  72    }
  73
  74    return 0;
  75
  76err:
  77    return ret < 0 ? ret : -EIO;
  78}
  79
  80static void
  81redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len)
  82{
  83    struct iovec iov = {
  84        .iov_base = (void *)buf,
  85        .iov_len = len,
  86    };
  87
  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);
  91    }
  92
  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);
  96     }
  97}
  98
  99static int redirector_chr_can_read(void *opaque)
 100{
 101    return REDIRECTOR_MAX_LEN;
 102}
 103
 104static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
 105{
 106    NetFilterState *nf = opaque;
 107    MirrorState *s = FILTER_REDIRECTOR(nf);
 108    int ret;
 109
 110    ret = net_fill_rstate(&s->rs, buf, size);
 111
 112    if (ret == -1) {
 113        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
 114                                 NULL, NULL, true);
 115    }
 116}
 117
 118static void redirector_chr_event(void *opaque, int event)
 119{
 120    NetFilterState *nf = opaque;
 121    MirrorState *s = FILTER_REDIRECTOR(nf);
 122
 123    switch (event) {
 124    case CHR_EVENT_CLOSED:
 125        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
 126                                 NULL, NULL, true);
 127        break;
 128    default:
 129        break;
 130    }
 131}
 132
 133static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
 134                                         NetClientState *sender,
 135                                         unsigned flags,
 136                                         const struct iovec *iov,
 137                                         int iovcnt,
 138                                         NetPacketSent *sent_cb)
 139{
 140    MirrorState *s = FILTER_MIRROR(nf);
 141    int ret;
 142
 143    ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
 144    if (ret) {
 145        error_report("filter_mirror_send failed(%s)", strerror(-ret));
 146    }
 147
 148    /*
 149     * we don't hope this error interrupt the normal
 150     * path of net packet, so we always return zero.
 151     */
 152    return 0;
 153}
 154
 155static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
 156                                             NetClientState *sender,
 157                                             unsigned flags,
 158                                             const struct iovec *iov,
 159                                             int iovcnt,
 160                                             NetPacketSent *sent_cb)
 161{
 162    MirrorState *s = FILTER_REDIRECTOR(nf);
 163    int ret;
 164
 165    if (qemu_chr_fe_get_driver(&s->chr_out)) {
 166        ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
 167        if (ret) {
 168            error_report("filter_mirror_send failed(%s)", strerror(-ret));
 169        }
 170        return iov_size(iov, iovcnt);
 171    } else {
 172        return 0;
 173    }
 174}
 175
 176static void filter_mirror_cleanup(NetFilterState *nf)
 177{
 178    MirrorState *s = FILTER_MIRROR(nf);
 179
 180    qemu_chr_fe_deinit(&s->chr_out);
 181}
 182
 183static void filter_redirector_cleanup(NetFilterState *nf)
 184{
 185    MirrorState *s = FILTER_REDIRECTOR(nf);
 186
 187    qemu_chr_fe_deinit(&s->chr_in);
 188    qemu_chr_fe_deinit(&s->chr_out);
 189}
 190
 191static void filter_mirror_setup(NetFilterState *nf, Error **errp)
 192{
 193    MirrorState *s = FILTER_MIRROR(nf);
 194    CharDriverState *chr;
 195
 196    if (!s->outdev) {
 197        error_setg(errp, "filter mirror needs 'outdev' "
 198                   "property set");
 199        return;
 200    }
 201
 202    chr = qemu_chr_find(s->outdev);
 203    if (chr == NULL) {
 204        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 205                  "Device '%s' not found", s->outdev);
 206        return;
 207    }
 208
 209    qemu_chr_fe_init(&s->chr_out, chr, errp);
 210}
 211
 212static void redirector_rs_finalize(SocketReadState *rs)
 213{
 214    MirrorState *s = container_of(rs, MirrorState, rs);
 215    NetFilterState *nf = NETFILTER(s);
 216
 217    redirector_to_filter(nf, rs->buf, rs->packet_len);
 218}
 219
 220static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 221{
 222    MirrorState *s = FILTER_REDIRECTOR(nf);
 223    CharDriverState *chr;
 224
 225    if (!s->indev && !s->outdev) {
 226        error_setg(errp, "filter redirector needs 'indev' or "
 227                   "'outdev' at least one property set");
 228        return;
 229    } else if (s->indev && s->outdev) {
 230        if (!strcmp(s->indev, s->outdev)) {
 231            error_setg(errp, "'indev' and 'outdev' could not be same "
 232                       "for filter redirector");
 233            return;
 234        }
 235    }
 236
 237    net_socket_rs_init(&s->rs, redirector_rs_finalize);
 238
 239    if (s->indev) {
 240        chr = qemu_chr_find(s->indev);
 241        if (chr == NULL) {
 242            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 243                      "IN Device '%s' not found", s->indev);
 244            return;
 245        }
 246
 247        if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
 248            return;
 249        }
 250
 251        qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
 252                                 redirector_chr_read, redirector_chr_event,
 253                                 nf, NULL, true);
 254    }
 255
 256    if (s->outdev) {
 257        chr = qemu_chr_find(s->outdev);
 258        if (chr == NULL) {
 259            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 260                      "OUT Device '%s' not found", s->outdev);
 261            return;
 262        }
 263        if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
 264            return;
 265        }
 266    }
 267}
 268
 269static void filter_mirror_class_init(ObjectClass *oc, void *data)
 270{
 271    NetFilterClass *nfc = NETFILTER_CLASS(oc);
 272
 273    nfc->setup = filter_mirror_setup;
 274    nfc->cleanup = filter_mirror_cleanup;
 275    nfc->receive_iov = filter_mirror_receive_iov;
 276}
 277
 278static void filter_redirector_class_init(ObjectClass *oc, void *data)
 279{
 280    NetFilterClass *nfc = NETFILTER_CLASS(oc);
 281
 282    nfc->setup = filter_redirector_setup;
 283    nfc->cleanup = filter_redirector_cleanup;
 284    nfc->receive_iov = filter_redirector_receive_iov;
 285}
 286
 287static char *filter_redirector_get_indev(Object *obj, Error **errp)
 288{
 289    MirrorState *s = FILTER_REDIRECTOR(obj);
 290
 291    return g_strdup(s->indev);
 292}
 293
 294static void
 295filter_redirector_set_indev(Object *obj, const char *value, Error **errp)
 296{
 297    MirrorState *s = FILTER_REDIRECTOR(obj);
 298
 299    g_free(s->indev);
 300    s->indev = g_strdup(value);
 301}
 302
 303static char *filter_mirror_get_outdev(Object *obj, Error **errp)
 304{
 305    MirrorState *s = FILTER_MIRROR(obj);
 306
 307    return g_strdup(s->outdev);
 308}
 309
 310static void
 311filter_mirror_set_outdev(Object *obj, const char *value, Error **errp)
 312{
 313    MirrorState *s = FILTER_MIRROR(obj);
 314
 315    g_free(s->outdev);
 316    s->outdev = g_strdup(value);
 317    if (!s->outdev) {
 318        error_setg(errp, "filter mirror needs 'outdev' "
 319                   "property set");
 320        return;
 321    }
 322}
 323
 324static char *filter_redirector_get_outdev(Object *obj, Error **errp)
 325{
 326    MirrorState *s = FILTER_REDIRECTOR(obj);
 327
 328    return g_strdup(s->outdev);
 329}
 330
 331static void
 332filter_redirector_set_outdev(Object *obj, const char *value, Error **errp)
 333{
 334    MirrorState *s = FILTER_REDIRECTOR(obj);
 335
 336    g_free(s->outdev);
 337    s->outdev = g_strdup(value);
 338}
 339
 340static void filter_mirror_init(Object *obj)
 341{
 342    object_property_add_str(obj, "outdev", filter_mirror_get_outdev,
 343                            filter_mirror_set_outdev, NULL);
 344}
 345
 346static void filter_redirector_init(Object *obj)
 347{
 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);
 352}
 353
 354static void filter_mirror_fini(Object *obj)
 355{
 356    MirrorState *s = FILTER_MIRROR(obj);
 357
 358    g_free(s->outdev);
 359}
 360
 361static void filter_redirector_fini(Object *obj)
 362{
 363    MirrorState *s = FILTER_REDIRECTOR(obj);
 364
 365    g_free(s->indev);
 366    g_free(s->outdev);
 367}
 368
 369static 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),
 376};
 377
 378static 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),
 385};
 386
 387static void register_types(void)
 388{
 389    type_register_static(&filter_mirror_info);
 390    type_register_static(&filter_redirector_info);
 391}
 392
 393type_init(register_types);
 394