zoukankan      html  css  js  c++  java
  • qemu和vhost-user前后端协商过程

    http://blog.chinaunix.net/uid-28541347-id-5786547.html

    https://zhaozhanxu.com/2017/02/16/QEMU/2017-02-16-qemu-reconnect/

    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: net_client_init_fun call  10
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_net_init call vhost_dev_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call hdev->vhost_ops->vhost_backend_init 、host_set_owne、 vhost_get_features
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: vhost_virtqueue_init vhost_set_vring_call : File descriptor in bad state (77)
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: vhost_virtqueue_init vhost_set_vring_call : File descriptor in bad state (77)
    qemu-system-aarch64: -object memory-backend-file,id=mem0,mem-path=/tmp/kata: can't create backend with size 0
    [root@localhost binary]# socat "stdin,raw,echo=0,escape=0x11" "unix-connect:console.sock"
    2020/11/10 04:04:26 socat[16280] E connect(5, AF=1 "console.sock", 14): Connection refused
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: net_client_init_fun call  10
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_net_init call vhost_dev_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call hdev->vhost_ops->vhost_backend_init 、host_set_owne、 vhost_get_features
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: vhost_virtqueue_init vhost_set_vring_call : File descriptor in bad state (77)
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev tap,ifname=tap1,id=network-0,vhost=on,script=no,downscript=no: vhost_virtqueue_init vhost_set_vring_call : File descriptor in bad state (77)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    ^Cqemu-system-aarch64: terminating on signal 2

    vhost_set_mem_table: No buffer space available

    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: info: vhost_net_start vhost_net_start_one
    qemu-system-aarch64: info: vhost.c vhost_dev_start
    qemu-system-aarch64: vhost_dev_start call vhost_set_mem_table: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_virtqueue_start: No buffer space available (105)
    qemu-system-aarch64: vhost_dev_start call vhost_virtqueue_start: Resource temporarily unavailable (11)
    qemu-system-aarch64: vhost_virtqueue_start: Resource temporarily unavailable (11)

     创建vhost nic没有加-object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge1,share=on

    tcp_chr_connect
    static void tcp_chr_connect(void *opaque)
    {
        Chardev *chr = CHARDEV(opaque);
        SocketChardev *s = SOCKET_CHARDEV(opaque);
    
        g_free(chr->filename);
        chr->filename = qemu_chr_compute_filename(s);
    
        tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTED);
        update_ioc_handlers(s);
        info_report("tcp_chr_connect call qemu_chr_be_event CHR_EVENT_OPENED");
        qemu_chr_be_event(chr, CHR_EVENT_OPENED);
    }
    qemu-system-aarch64: -chardev socket,id=char0,path=/tmp/vhost1,server: info: QEMU waiting for connection on: disconnected:unix:/tmp/vhost1,server
    qemu-system-aarch64: -chardev socket,id=char0,path=/tmp/vhost1,server: info: tcp_chr_connect call qemu_chr_be_event CHR_EVENT_OPENED
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: net_client_init_fun call  10
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: net_init_vhost_user call net_vhost_user_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: net_vhost_user_init call  vhost_user_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c in vhost_user_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info:  net_vhost_user_init call qemu_chr_fe_set_handlers
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: net_vhost_user_event process CHR_EVENT_OPENED and call vhost_user_start
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_user_start call vhost_net_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_net_init not backend_kernel
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_net_init call vhost_dev_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_dev_init call hdev->vhost_ops->vhost_backend_init 、host_set_owne、 vhost_get_features
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 1
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 0
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: vhost_virtqueue_init vhost_set_vring_call : Success (0)
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 1
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost_dev_init call vhost_virtqueue_init
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: vhost_virtqueue_init vhost_set_vring_call : Success (0)
    qemu-system-aarch64: -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce: info: vhost-user.c vhost_user_write 1
    net_client_init1
    static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
    {
        NetClientState *peer = NULL;
    
        if (is_netdev) {
            if (netdev->type == NET_CLIENT_DRIVER_NIC ||
                !net_client_init_fun[netdev->type]) {
                error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                           "a netdev backend type");
                return -1;
            }
        } else {
            if (netdev->type == NET_CLIENT_DRIVER_NONE) {
                return 0; /* nothing to do */
            }
            if (netdev->type == NET_CLIENT_DRIVER_HUBPORT ||
                !net_client_init_fun[netdev->type]) {
                error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                           "a net backend type (maybe it is not compiled "
                           "into this binary)");
                return -1;
            }
    
            /* Do not add to a hub if it's a nic with a netdev= parameter. */
            if (netdev->type != NET_CLIENT_DRIVER_NIC ||
                !netdev->u.nic.has_netdev) {
                peer = net_hub_add_port(0, NULL, NULL);
            }
        }
    
        info_report("net_client_init_fun call  %d", NET_CLIENT_DRIVER_VHOST_USER);
        if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) {
            /* FIXME drop when all init functions store an Error */
            if (errp && !*errp) {
                error_setg(errp, QERR_DEVICE_INIT_FAILED,
                           NetClientDriver_str(netdev->type));
            }
            return -1;
        }
    
        if (is_netdev) {
            NetClientState *nc;
    
            nc = qemu_find_netdev(netdev->id);
            assert(nc);
            nc->is_netdev = true;
        }
    
        return 0;
    }
            [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,

    net_init_vhost_user

    int net_init_vhost_user(const Netdev *netdev, const char *name,
                            NetClientState *peer, Error **errp)
    {
        int queues;
        const NetdevVhostUserOptions *vhost_user_opts;
        Chardev *chr;
    
        assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
        vhost_user_opts = &netdev->u.vhost_user;
    
        chr = net_vhost_claim_chardev(vhost_user_opts, errp);
        if (!chr) {
            return -1;
        }
    
        /* verify net frontend */
        if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
                              (char *)name, errp)) {
            return -1;
        }
    
        queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
        if (queues < 1 || queues > MAX_QUEUE_NUM) {
            error_setg(errp,
                       "vhost-user number of queues must be in range [1, %d]",
                       MAX_QUEUE_NUM);
            return -1;
        }
        info_report("net_init_vhost_user call net_vhost_user_init");
        return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
    }
    安装net_vhost_user_event沟子函数
    static int net_vhost_user_init(NetClientState *peer, const char *device,
                                   const char *name, Chardev *chr,
                                   int queues)
    {
        Error *err = NULL;
        NetClientState *nc, *nc0 = NULL;
        NetVhostUserState *s = NULL;
        VhostUserState *user;
        int i;
    
        assert(name);
        assert(queues > 0);
    
        user = g_new0(struct VhostUserState, 1);
        for (i = 0; i < queues; i++) {
            nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
            snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
                     i, chr->label);
            nc->queue_index = i;
            if (!nc0) {
                nc0 = nc;
                s = DO_UPCAST(NetVhostUserState, nc, nc);
                info_report("net_vhost_user_init call  vhost_user_init");
                if (!qemu_chr_fe_init(&s->chr, chr, &err) ||
                    !vhost_user_init(user, &s->chr, &err)) {
                    error_report_err(err);
                    goto err;
                }
            }
            s = DO_UPCAST(NetVhostUserState, nc, nc);
            s->vhost_user = user;
        }
    
        s = DO_UPCAST(NetVhostUserState, nc, nc0);
        do {
            if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
                error_report_err(err);
                goto err;
            }
            info_report(" net_vhost_user_init call qemu_chr_fe_set_handlers");
            qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
                                     net_vhost_user_event, NULL, nc0->name, NULL,
                                     true);
        } while (!s->started);
    
        assert(s->vhost_net);
    
        return 0;

    net/vhost-user.c:net_vhost_user_event

    static void net_vhost_user_event(void *opaque, QEMUChrEvent event)
    {
        const char *name = opaque;
        NetClientState *ncs[MAX_QUEUE_NUM];
        NetVhostUserState *s;
        Chardev *chr;
        Error *err = NULL;
        int queues;
    
        queues = qemu_find_net_clients_except(name, ncs,
                                              NET_CLIENT_DRIVER_NIC,
                                              MAX_QUEUE_NUM);
        assert(queues < MAX_QUEUE_NUM);
    
        s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
        chr = qemu_chr_fe_get_driver(&s->chr);
        trace_vhost_user_event(chr->label, event);
        switch (event) {
        case CHR_EVENT_OPENED:
            info_report("net_vhost_user_event process CHR_EVENT_OPENED and call vhost_user_start");
            if (vhost_user_start(queues, ncs, s->vhost_user) < 0) {
                qemu_chr_fe_disconnect(&s->chr);
                return;
            }
            s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
                                             net_vhost_user_watch, s);
            qmp_set_link(name, true, &err);
            s->started = true;
            break;

    net/vhost-user.c:vhost_user_start

    static int vhost_user_start(int queues, NetClientState *ncs[],
                                VhostUserState *be)
    {
        VhostNetOptions options;
        struct vhost_net *net = NULL;
        NetVhostUserState *s;
        int max_queues;
        int i;
    
        options.backend_type = VHOST_BACKEND_TYPE_USER;
    
        for (i = 0; i < queues; i++) {
            assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
    
            s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
    
            options.net_backend = ncs[i];
            options.opaque      = be;
            options.busyloop_timeout = 0;
            info_report("vhost_user_start call vhost_net_init");
            net = vhost_net_init(&options);
            if (!net) {
                error_report("failed to init vhost_net for queue %d", i);
                goto err;
            }
    
            if (i == 0) {
                max_queues = vhost_net_get_max_queues(net);
                if (queues > max_queues) {
                    error_report("you are asking more queues than supported: %d",
                                 max_queues);
                    goto err;
                }
            }
    
            if (s->vhost_net) {
                vhost_net_cleanup(s->vhost_net);
                g_free(s->vhost_net);
            }
            s->vhost_net = net;
        }
    
        return 0;
    
    err:
        if (net) {
            vhost_net_cleanup(net);
            g_free(net);
        }
        vhost_user_stop(i, ncs);
        return -1;
    }

    hw/net/vhost_net.c: vhost_net_init

    struct vhost_net *vhost_net_init(VhostNetOptions *options)
    {
        int r;
        bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
        struct vhost_net *net = g_new0(struct vhost_net, 1);
        uint64_t features = 0;
    
        if (!options->net_backend) {
            fprintf(stderr, "vhost-net requires net backend to be setup
    ");
            goto fail;
        }
        net->nc = options->net_backend;
    
        net->dev.max_queues = 1;
        net->dev.nvqs = 2;
        net->dev.vqs = net->vqs;
    
        if (backend_kernel) {
            r = vhost_net_get_fd(options->net_backend);
            if (r < 0) {
                goto fail;
            }
            net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
                ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
            net->backend = r;
            net->dev.protocol_features = 0;
        } else {
            info_report("vhost_net_init not backend_kernel");
            net->dev.backend_features = 0;
            net->dev.protocol_features = 0;
            net->backend = -1;
    
            /* vhost-user needs vq_index to initiate a specific queue pair */
            net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
        }
    
        info_report("vhost_net_init call vhost_dev_init");
        r = vhost_dev_init(&net->dev, options->opaque,
                           options->backend_type, options->busyloop_timeout);
        if (r < 0) {
            goto fail;
        }
        if (backend_kernel) {
            if (!qemu_has_vnet_hdr_len(options->net_backend,
                                   sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
                net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
            }
            if (~net->dev.features & net->dev.backend_features) {
                fprintf(stderr, "vhost lacks feature mask %" PRIu64
                       " for backend
    ",
                       (uint64_t)(~net->dev.features & net->dev.backend_features));
                goto fail;
            }
        }

    hw/virtio/vhost.c:vhost_dev_init

    int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
                       VhostBackendType backend_type, uint32_t busyloop_timeout)
    {
        uint64_t features;
        int i, r, n_initialized_vqs = 0;
        Error *local_err = NULL;
    
        hdev->vdev = NULL;
        hdev->migration_blocker = NULL;
    
       info_report("vhost_dev_init call hdev->vhost_ops->vhost_backend_init 、host_set_owne、 vhost_get_features");
        r = vhost_set_backend_type(hdev, backend_type);
        assert(r >= 0);
    
        r = hdev->vhost_ops->vhost_backend_init(hdev, opaque);
        if (r < 0) {
            goto fail;
        }
    
        r = hdev->vhost_ops->vhost_set_owner(hdev);
        if (r < 0) {
            VHOST_OPS_DEBUG("vhost_set_owner failed");
            goto fail;
        }
    
        r = hdev->vhost_ops->vhost_get_features(hdev, &features);
        if (r < 0) {
            VHOST_OPS_DEBUG("vhost_get_features failed");
            goto fail;
        }
    
        for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) {
            info_report("vhost_dev_init call vhost_virtqueue_init");
            r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i);
            if (r < 0) {
                goto fail;
            }
        }
    
        if (busyloop_timeout) {
            for (i = 0; i < hdev->nvqs; ++i) {
                r = vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i,
                                                         busyloop_timeout);
                if (r < 0) {
                    goto fail_busyloop;
                }
            }
        }
    const VhostOps user_ops = {
            .backend_type = VHOST_BACKEND_TYPE_USER,
            .vhost_backend_init = vhost_user_backend_init,
            .vhost_backend_cleanup = vhost_user_backend_cleanup,
            .vhost_backend_memslots_limit = vhost_user_memslots_limit,
            .vhost_set_log_base = vhost_user_set_log_base,
            .vhost_set_mem_table = vhost_user_set_mem_table,
            .vhost_set_vring_addr = vhost_user_set_vring_addr,
            .vhost_set_vring_endian = vhost_user_set_vring_endian,
            .vhost_set_vring_num = vhost_user_set_vring_num,
            .vhost_set_vring_base = vhost_user_set_vring_base,
            .vhost_get_vring_base = vhost_user_get_vring_base,
            .vhost_set_vring_kick = vhost_user_set_vring_kick,
            .vhost_set_vring_call = vhost_user_set_vring_call,
            .vhost_set_features = vhost_user_set_features,
            .vhost_get_features = vhost_user_get_features,
            .vhost_set_owner = vhost_user_set_owner,
            .vhost_reset_device = vhost_user_reset_device,
            .vhost_get_vq_index = vhost_user_get_vq_index,
            .vhost_set_vring_enable = vhost_user_set_vring_enable,
            .vhost_requires_shm_log = vhost_user_requires_shm_log,
            .vhost_migration_done = vhost_user_migration_done,
            .vhost_backend_can_merge = vhost_user_can_merge,
            .vhost_net_set_mtu = vhost_user_net_set_mtu,
            .vhost_set_iotlb_callback = vhost_user_set_iotlb_callback,
            .vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg,
            .vhost_get_config = vhost_user_get_config,
            .vhost_set_config = vhost_user_set_config,
            .vhost_crypto_create_session = vhost_user_crypto_create_session,
            .vhost_crypto_close_session = vhost_user_crypto_close_session,
            .vhost_backend_mem_section_filter = vhost_user_mem_section_filter,
            .vhost_get_inflight_fd = vhost_user_get_inflight_fd,
            .vhost_set_inflight_fd = vhost_user_set_inflight_fd,
    };

    hw/virtio/vhost-user.c:vhost_user_write

    /* most non-init callers ignore the error */
    static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
                                int *fds, int fd_num)
    {
        info_report("vhost-user.c vhost_user_write %d", fd_num);
        struct vhost_user *u = dev->opaque;
        CharBackend *chr = u->user->chr;
        int ret, size = VHOST_USER_HDR_SIZE + msg->hdr.size;
    
        /*
         * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
         * we just need send it once in the first time. For later such
         * request, we just ignore it.
         */
        if (vhost_user_one_time_request(msg->hdr.request) && dev->vq_index != 0) {
            msg->hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK;
            return 0;
        }
    
        if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
            error_report("Failed to set msg fds.");
            return -1;
        }
    
        ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
        if (ret != size) {
            error_report("Failed to write msg."
                         " Wrote %d instead of %d.", ret, size);
            return -1;
        }
    
        return 0;
    }
    vhost_virtqueue_init
    static int vhost_virtqueue_init(struct vhost_dev *dev,
                                    struct vhost_virtqueue *vq, int n)
    {
        int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n);
        struct vhost_vring_file file = {
            .index = vhost_vq_index,
        };
        int r = event_notifier_init(&vq->masked_notifier, 0);
        if (r < 0) {
            return r;
        }
    
        file.fd = event_notifier_get_fd(&vq->masked_notifier);
        VHOST_OPS_DEBUG("vhost_virtqueue_init vhost_set_vring_call ");
        r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
        if (r) {
            VHOST_OPS_DEBUG("vhost_set_vring_call failed");
            r = -errno;
            goto fail_call;
        }
    
        vq->dev = dev;
    
        return 0;
    fail_call:
        event_notifier_cleanup(&vq->masked_notifier);
        return r;
    }
    static int vhost_user_set_vring_call(struct vhost_dev *dev,
                                         struct vhost_vring_file *file)
    {
        return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
    }
    static int vhost_user_set_vring_call(struct vhost_dev *dev,
                                         struct vhost_vring_file *file)
    {
        return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
    }
    static int vhost_set_vring_file(struct vhost_dev *dev,
                                    VhostUserRequest request,
                                    struct vhost_vring_file *file)
    {
        int fds[VHOST_USER_MAX_RAM_SLOTS];
        size_t fd_num = 0;
        VhostUserMsg msg = {
            .hdr.request = request,
            .hdr.flags = VHOST_USER_VERSION,
            .payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
            .hdr.size = sizeof(msg.payload.u64),
        };
    
        if (ioeventfd_enabled() && file->fd > 0) {
            fds[fd_num++] = file->fd;
        } else {
            msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
        }
    
        if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
            return -1;
        }
    
        return 0;
    }
    /* most non-init callers ignore the error */
    static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
                                int *fds, int fd_num)
    {
        info_report("vhost-user.c vhost_user_write %d", fd_num);
        struct vhost_user *u = dev->opaque;
        CharBackend *chr = u->user->chr;
        int ret, size = VHOST_USER_HDR_SIZE + msg->hdr.size;
    
        /*
         * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
         * we just need send it once in the first time. For later such
         * request, we just ignore it.
         */
        if (vhost_user_one_time_request(msg->hdr.request) && dev->vq_index != 0) {
            msg->hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK;
            return 0;
        }
    
        if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
            error_report("Failed to set msg fds.");
            return -1;
        }
    
        ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
        if (ret != size) {
            error_report("Failed to write msg."
                         " Wrote %d instead of %d.", ret, size);
            return -1;
        }
    
        return 0;
    }

    guest驱动加载完成

        当guest中virtio-net加载完成后会写VIRTIO_PCI_STATUS寄存器,这个操作同样会被kvm捕获传递给qemu。qemu的相应处理逻辑如下。

     

    host网络设备就会从virtio_set_status中调用memory_region_add_eventfd,然后通过kvm_io_ioeventfd_add添加eventfd到KVM,一旦有PIO操作,就通过eventfd通知QEMU,和iothread没有关系
    一般virtio网络设备(非vhost)从virtio_set_status 进入到virtio_net_vhost_status 后,发现不是vhost这边就直接return了,也就不会有memory_region_add_eventfd添加eventfd的过程了
    
    
    
    VHOST调用栈如下
    #0  memory_region_add_eventfd (mr=0x55fe2ae56320, addr=16, size=2, match_data=true, data=0, e=0x55fe2cf729f0) at /home/liufeng/workspace/src/open/qemu/memory.c:1792
    #1  0x000055fe2976a299 in virtio_pci_set_host_notifier_internal (proxy=0x55fe2ae55aa0, n=0, assign=true, set_handler=false) at hw/virtio/virtio-pci.c:307
    #2  0x000055fe2976c15f in virtio_pci_set_host_notifier (d=0x55fe2ae55aa0, n=0, assign=true) at hw/virtio/virtio-pci.c:1130
    #3  0x000055fe2952fe97 in vhost_dev_enable_notifiers (hdev=0x55fe2adcfbc0, vdev=0x55fe2ae5ddc8) at /home/liufeng/workspace/src/open/qemu/hw/virtio/vhost.c:1124
    #4  0x000055fe2950b8c7 in vhost_net_start_one (net=0x55fe2adcfbc0, dev=0x55fe2ae5ddc8) at /home/liufeng/workspace/src/open/qemu/hw/net/vhost_net.c:208
    #5  0x000055fe2950bdef in vhost_net_start (dev=0x55fe2ae5ddc8, ncs=0x55fe2c1ab040, total_queues=1) at /home/liufeng/workspace/src/open/qemu/hw/net/vhost_net.c:308
    #6  0x000055fe2950647c in virtio_net_vhost_status (n=0x55fe2ae5ddc8, status=7 'a') at /home/liufeng/workspace/src/open/qemu/hw/net/virtio-net.c:151
    #7  0x000055fe29506711 in virtio_net_set_status (vdev=0x55fe2ae5ddc8, status=7 'a') at /home/liufeng/workspace/src/open/qemu/hw/net/virtio-net.c:224
    #8  0x000055fe29527b89 in virtio_set_status (vdev=0x55fe2ae5ddc8, val=7 'a') at /home/liufeng/workspace/src/open/qemu/hw/virtio/virtio.c:748
    #9  0x000055fe2976a6eb in virtio_ioport_write (opaque=0x55fe2ae55aa0, addr=18, val=7) at hw/virtio/virtio-pci.c:428
    #10 0x000055fe2976ab46 in virtio_pci_config_write (opaque=0x55fe2ae55aa0, addr=18, val=7, size=1) at hw/virtio/virtio-pci.c:553
    #11 0x000055fe294c67dd in memory_region_write_accessor (mr=0x55fe2ae56320, addr=18, value=0x7f6d3fd9a848, size=1, shift=0, mask=255, attrs=...) at /home/liufeng/workspace/src/open/qemu/memory.c:525
    #12 0x000055fe294c69e8 in access_with_adjusted_size (addr=18, value=0x7f6d3fd9a848, size=1, access_size_min=1, access_size_max=4, access=0x55fe294c66fc <memory_region_write_accessor>, mr=0x55fe2ae56320, attrs=...)
        at /home/liufeng/workspace/src/open/qemu/memory.c:591
    #13 0x000055fe294c962f in memory_region_dispatch_write (mr=0x55fe2ae56320, addr=18, data=7, size=1, attrs=...) at /home/liufeng/workspace/src/open/qemu/memory.c:1273
    #14 0x000055fe2947b724 in address_space_write_continue (as=0x55fe29e205c0 <address_space_io>, addr=49170, attrs=..., buf=0x7f6d4ba38000 "aE03", len=1, addr1=18, l=1, mr=0x55fe2ae56320)
        at /home/liufeng/workspace/src/open/qemu/exec.c:2619
    #15 0x000055fe2947b89a in address_space_write (as=0x55fe29e205c0 <address_space_io>, addr=49170, attrs=..., buf=0x7f6d4ba38000 "aE03", len=1) at /home/liufeng/workspace/src/open/qemu/exec.c:2665
    #16 0x000055fe2947bc51 in address_space_rw (as=0x55fe29e205c0 <address_space_io>, addr=49170, attrs=..., buf=0x7f6d4ba38000 "aE03", len=1, is_write=true) at /home/liufeng/workspace/src/open/qemu/exec.c:2768
    #17 0x000055fe294c2d64 in kvm_handle_io (port=49170, attrs=..., data=0x7f6d4ba38000, direction=1, size=1, count=1) at /home/liufeng/workspace/src/open/qemu/kvm-all.c:1699
    #18 0x000055fe294c3264 in kvm_cpu_exec (cpu=0x55fe2ae8ef50) at /home/liufeng/workspace/src/open/qemu/kvm-all.c:1863
    #19 0x000055fe294aa8b8 in qemu_kvm_cpu_thread_fn (arg=0x55fe2ae8ef50) at /home/liufeng/workspace/src/open/qemu/cpus.c:1064
    #20 0x00007f6d47187dc5 in start_thread () from /lib64/libpthread.so.0
    #21 0x00007f6d46eb4ced in clone () from /lib64/libc.so.6
    static int vhost_net_start_one(struct vhost_net *net,
                                   VirtIODevice *dev)
    {
        struct vhost_vring_file file = { };
        int r;
    
        net->dev.nvqs = 2;
        net->dev.vqs = net->vqs;
    
        r = vhost_dev_enable_notifiers(&net->dev, dev);
        if (r < 0) {
            goto fail_notifiers;
        }
    
        r = vhost_dev_start(&net->dev, dev);
        if (r < 0) {
            goto fail_start;
        }
  • 相关阅读:
    关于vue的npm run dev和npm run build
    移动端meta行大全
    浅谈前端三大框架Angular、react、vue
    Web Workers
    Meta(其他信息)
    页面
    页面
    日期和时间
    ECharts教程(未完)
    页面
  • 原文地址:https://www.cnblogs.com/dream397/p/13949167.html
Copyright © 2011-2022 走看看