qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 457 lines 12 kB view raw
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, 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 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); 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 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); 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 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);