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 34 typedef 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 44 static 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 92 err: 93 return ret < 0 ? ret : -EIO; 94 } 95 96 static 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 116 static int redirector_chr_can_read(void *opaque) 117 { 118 return REDIRECTOR_MAX_LEN; 119 } 120 121 static 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 135 static void redirector_chr_event(void *opaque, QEMUChrEvent 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 150 static 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 172 static 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 193 static 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 200 static 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 208 static 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 229 static 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 237 static 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 286 static 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 295 static 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 304 static 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 311 static 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 321 static 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 328 static 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 343 static 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 350 static 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 357 static 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 364 static 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 374 static 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 381 static 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 390 static 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); 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); 401 } 402 403 static 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); 409 object_property_add_str(obj, "outdev", filter_redirector_get_outdev, 410 filter_redirector_set_outdev); 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); 416 } 417 418 static void filter_mirror_fini(Object *obj) 419 { 420 MirrorState *s = FILTER_MIRROR(obj); 421 422 g_free(s->outdev); 423 } 424 425 static 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 433 static 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 442 static 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 451 static void register_types(void) 452 { 453 type_register_static(&filter_mirror_info); 454 type_register_static(&filter_redirector_info); 455 } 456 457 type_init(register_types); 458