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); 499