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