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