cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

filter-mirror.c (12416B)


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