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    CharDriverState *chr_in;
  42    CharDriverState *chr_out;
  43    int state; /* 0 = getting length, 1 = getting data */
  44    unsigned int index;
  45    unsigned int packet_len;
  46    uint8_t buf[REDIRECTOR_MAX_LEN];
  47} MirrorState;
  48
  49static int filter_mirror_send(CharDriverState *chr_out,
  50                              const struct iovec *iov,
  51                              int iovcnt)
  52{
  53    int ret = 0;
  54    ssize_t size = 0;
  55    uint32_t len =  0;
  56    char *buf;
  57
  58    size = iov_size(iov, iovcnt);
  59    if (!size) {
  60        return 0;
  61    }
  62
  63    len = htonl(size);
  64    ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)&len, sizeof(len));
  65    if (ret != sizeof(len)) {
  66        goto err;
  67    }
  68
  69    buf = g_malloc(size);
  70    iov_to_buf(iov, iovcnt, 0, buf, size);
  71    ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)buf, size);
  72    g_free(buf);
  73    if (ret != size) {
  74        goto err;
  75    }
  76
  77    return 0;
  78
  79err:
  80    return ret < 0 ? ret : -EIO;
  81}
  82
  83static void
  84redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len)
  85{
  86    struct iovec iov = {
  87        .iov_base = (void *)buf,
  88        .iov_len = len,
  89    };
  90
  91    if (nf->direction == NET_FILTER_DIRECTION_ALL ||
  92        nf->direction == NET_FILTER_DIRECTION_TX) {
  93        qemu_netfilter_pass_to_next(nf->netdev, 0, &iov, 1, nf);
  94    }
  95
  96    if (nf->direction == NET_FILTER_DIRECTION_ALL ||
  97        nf->direction == NET_FILTER_DIRECTION_RX) {
  98        qemu_netfilter_pass_to_next(nf->netdev->peer, 0, &iov, 1, nf);
  99     }
 100}
 101
 102static int redirector_chr_can_read(void *opaque)
 103{
 104    return REDIRECTOR_MAX_LEN;
 105}
 106
 107static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
 108{
 109    NetFilterState *nf = opaque;
 110    MirrorState *s = FILTER_REDIRECTOR(nf);
 111    unsigned int l;
 112
 113    while (size > 0) {
 114        /* reassemble a packet from the network */
 115        switch (s->state) { /* 0 = getting length, 1 = getting data */
 116        case 0:
 117            l = 4 - s->index;
 118            if (l > size) {
 119                l = size;
 120            }
 121            memcpy(s->buf + s->index, buf, l);
 122            buf += l;
 123            size -= l;
 124            s->index += l;
 125            if (s->index == 4) {
 126                /* got length */
 127                s->packet_len = ntohl(*(uint32_t *)s->buf);
 128                s->index = 0;
 129                s->state = 1;
 130            }
 131            break;
 132        case 1:
 133            l = s->packet_len - s->index;
 134            if (l > size) {
 135                l = size;
 136            }
 137            if (s->index + l <= sizeof(s->buf)) {
 138                memcpy(s->buf + s->index, buf, l);
 139            } else {
 140                error_report("serious error: oversized packet received.");
 141                s->index = s->state = 0;
 142                qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
 143                return;
 144            }
 145
 146            s->index += l;
 147            buf += l;
 148            size -= l;
 149            if (s->index >= s->packet_len) {
 150                s->index = 0;
 151                s->state = 0;
 152                redirector_to_filter(nf, s->buf, s->packet_len);
 153            }
 154            break;
 155        }
 156    }
 157}
 158
 159static void redirector_chr_event(void *opaque, int event)
 160{
 161    NetFilterState *nf = opaque;
 162    MirrorState *s = FILTER_REDIRECTOR(nf);
 163
 164    switch (event) {
 165    case CHR_EVENT_CLOSED:
 166        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
 167        break;
 168    default:
 169        break;
 170    }
 171}
 172
 173static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
 174                                         NetClientState *sender,
 175                                         unsigned flags,
 176                                         const struct iovec *iov,
 177                                         int iovcnt,
 178                                         NetPacketSent *sent_cb)
 179{
 180    MirrorState *s = FILTER_MIRROR(nf);
 181    int ret;
 182
 183    ret = filter_mirror_send(s->chr_out, iov, iovcnt);
 184    if (ret) {
 185        error_report("filter_mirror_send failed(%s)", strerror(-ret));
 186    }
 187
 188    /*
 189     * we don't hope this error interrupt the normal
 190     * path of net packet, so we always return zero.
 191     */
 192    return 0;
 193}
 194
 195static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
 196                                             NetClientState *sender,
 197                                             unsigned flags,
 198                                             const struct iovec *iov,
 199                                             int iovcnt,
 200                                             NetPacketSent *sent_cb)
 201{
 202    MirrorState *s = FILTER_REDIRECTOR(nf);
 203    int ret;
 204
 205    if (s->chr_out) {
 206        ret = filter_mirror_send(s->chr_out, iov, iovcnt);
 207        if (ret) {
 208            error_report("filter_mirror_send failed(%s)", strerror(-ret));
 209        }
 210        return iov_size(iov, iovcnt);
 211    } else {
 212        return 0;
 213    }
 214}
 215
 216static void filter_mirror_cleanup(NetFilterState *nf)
 217{
 218    MirrorState *s = FILTER_MIRROR(nf);
 219
 220    if (s->chr_out) {
 221        qemu_chr_fe_release(s->chr_out);
 222    }
 223}
 224
 225static void filter_redirector_cleanup(NetFilterState *nf)
 226{
 227    MirrorState *s = FILTER_REDIRECTOR(nf);
 228
 229    if (s->chr_in) {
 230        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
 231        qemu_chr_fe_release(s->chr_in);
 232    }
 233    if (s->chr_out) {
 234        qemu_chr_fe_release(s->chr_out);
 235    }
 236}
 237
 238static void filter_mirror_setup(NetFilterState *nf, Error **errp)
 239{
 240    MirrorState *s = FILTER_MIRROR(nf);
 241
 242    if (!s->outdev) {
 243        error_setg(errp, "filter filter mirror needs 'outdev' "
 244                   "property set");
 245        return;
 246    }
 247
 248    s->chr_out = qemu_chr_find(s->outdev);
 249    if (s->chr_out == NULL) {
 250        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 251                  "Device '%s' not found", s->outdev);
 252        return;
 253    }
 254
 255    if (qemu_chr_fe_claim(s->chr_out) != 0) {
 256        error_setg(errp, QERR_DEVICE_IN_USE, s->outdev);
 257        return;
 258    }
 259}
 260
 261static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 262{
 263    MirrorState *s = FILTER_REDIRECTOR(nf);
 264
 265    if (!s->indev && !s->outdev) {
 266        error_setg(errp, "filter redirector needs 'indev' or "
 267                   "'outdev' at least one property set");
 268        return;
 269    } else if (s->indev && s->outdev) {
 270        if (!strcmp(s->indev, s->outdev)) {
 271            error_setg(errp, "'indev' and 'outdev' could not be same "
 272                       "for filter redirector");
 273            return;
 274        }
 275    }
 276
 277    s->state = s->index = 0;
 278
 279    if (s->indev) {
 280        s->chr_in = qemu_chr_find(s->indev);
 281        if (s->chr_in == NULL) {
 282            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 283                      "IN Device '%s' not found", s->indev);
 284            return;
 285        }
 286
 287        qemu_chr_fe_claim_no_fail(s->chr_in);
 288        qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read,
 289                              redirector_chr_read, redirector_chr_event, nf);
 290    }
 291
 292    if (s->outdev) {
 293        s->chr_out = qemu_chr_find(s->outdev);
 294        if (s->chr_out == NULL) {
 295            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 296                      "OUT Device '%s' not found", s->outdev);
 297            return;
 298        }
 299        qemu_chr_fe_claim_no_fail(s->chr_out);
 300    }
 301}
 302
 303static void filter_mirror_class_init(ObjectClass *oc, void *data)
 304{
 305    NetFilterClass *nfc = NETFILTER_CLASS(oc);
 306
 307    nfc->setup = filter_mirror_setup;
 308    nfc->cleanup = filter_mirror_cleanup;
 309    nfc->receive_iov = filter_mirror_receive_iov;
 310}
 311
 312static void filter_redirector_class_init(ObjectClass *oc, void *data)
 313{
 314    NetFilterClass *nfc = NETFILTER_CLASS(oc);
 315
 316    nfc->setup = filter_redirector_setup;
 317    nfc->cleanup = filter_redirector_cleanup;
 318    nfc->receive_iov = filter_redirector_receive_iov;
 319}
 320
 321static char *filter_redirector_get_indev(Object *obj, Error **errp)
 322{
 323    MirrorState *s = FILTER_REDIRECTOR(obj);
 324
 325    return g_strdup(s->indev);
 326}
 327
 328static void
 329filter_redirector_set_indev(Object *obj, const char *value, Error **errp)
 330{
 331    MirrorState *s = FILTER_REDIRECTOR(obj);
 332
 333    g_free(s->indev);
 334    s->indev = g_strdup(value);
 335}
 336
 337static char *filter_mirror_get_outdev(Object *obj, Error **errp)
 338{
 339    MirrorState *s = FILTER_MIRROR(obj);
 340
 341    return g_strdup(s->outdev);
 342}
 343
 344static void
 345filter_mirror_set_outdev(Object *obj, const char *value, Error **errp)
 346{
 347    MirrorState *s = FILTER_MIRROR(obj);
 348
 349    g_free(s->outdev);
 350    s->outdev = g_strdup(value);
 351    if (!s->outdev) {
 352        error_setg(errp, "filter filter mirror needs 'outdev' "
 353                   "property set");
 354        return;
 355    }
 356}
 357
 358static char *filter_redirector_get_outdev(Object *obj, Error **errp)
 359{
 360    MirrorState *s = FILTER_REDIRECTOR(obj);
 361
 362    return g_strdup(s->outdev);
 363}
 364
 365static void
 366filter_redirector_set_outdev(Object *obj, const char *value, Error **errp)
 367{
 368    MirrorState *s = FILTER_REDIRECTOR(obj);
 369
 370    g_free(s->outdev);
 371    s->outdev = g_strdup(value);
 372}
 373
 374static void filter_mirror_init(Object *obj)
 375{
 376    object_property_add_str(obj, "outdev", filter_mirror_get_outdev,
 377                            filter_mirror_set_outdev, NULL);
 378}
 379
 380static void filter_redirector_init(Object *obj)
 381{
 382    object_property_add_str(obj, "indev", filter_redirector_get_indev,
 383                            filter_redirector_set_indev, NULL);
 384    object_property_add_str(obj, "outdev", filter_redirector_get_outdev,
 385                            filter_redirector_set_outdev, NULL);
 386}
 387
 388static void filter_mirror_fini(Object *obj)
 389{
 390    MirrorState *s = FILTER_MIRROR(obj);
 391
 392    g_free(s->outdev);
 393}
 394
 395static void filter_redirector_fini(Object *obj)
 396{
 397    MirrorState *s = FILTER_REDIRECTOR(obj);
 398
 399    g_free(s->indev);
 400    g_free(s->outdev);
 401}
 402
 403static const TypeInfo filter_redirector_info = {
 404    .name = TYPE_FILTER_REDIRECTOR,
 405    .parent = TYPE_NETFILTER,
 406    .class_init = filter_redirector_class_init,
 407    .instance_init = filter_redirector_init,
 408    .instance_finalize = filter_redirector_fini,
 409    .instance_size = sizeof(MirrorState),
 410};
 411
 412static const TypeInfo filter_mirror_info = {
 413    .name = TYPE_FILTER_MIRROR,
 414    .parent = TYPE_NETFILTER,
 415    .class_init = filter_mirror_class_init,
 416    .instance_init = filter_mirror_init,
 417    .instance_finalize = filter_mirror_fini,
 418    .instance_size = sizeof(MirrorState),
 419};
 420
 421static void register_types(void)
 422{
 423    type_register_static(&filter_mirror_info);
 424    type_register_static(&filter_redirector_info);
 425}
 426
 427type_init(register_types);
 428