qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

filter-mirror.c (13196B)


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