Beispiel #1
0
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
    VirtIONet *n = to_virtio_net(vdev);
    if (!n->nic->nc.peer) {
        return;
    }
    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
        return;
    }

    if (!tap_get_vhost_net(n->nic->nc.peer)) {
        return;
    }
    if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
                               (n->status & VIRTIO_NET_S_LINK_UP) &&
                               n->vm_running)) {
        return;
    }
    if (!n->vhost_started) {
        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
        if (r < 0) {
            fprintf(stderr, "unable to start vhost net: %d: "
                    "falling back on userspace virtio\n", -r);
        } else {
            n->vhost_started = 1;
        }
    } else {
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
        n->vhost_started = 0;
    }
}
Beispiel #2
0
static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
{
    if (!n->nic->nc.peer) {
        return;
    }
    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
        return;
    }

    if (!tap_get_vhost_net(n->nic->nc.peer)) {
        return;
    }
    if (!!n->vhost_started == virtio_net_started(n, status) &&
                              !n->nic->nc.peer->link_down) {
        return;
    }
    if (!n->vhost_started) {
        int r;
        if (!vhost_net_query(tap_get_vhost_net(n->nic->nc.peer), &n->vdev)) {
            return;
        }
        r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
        if (r < 0) {
            error_report("unable to start vhost net: %d: "
                         "falling back on userspace virtio", -r);
        } else {
            n->vhost_started = 1;
        }
    } else {
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
        n->vhost_started = 0;
    }
}
Beispiel #3
0
static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
{
    VirtIONet *n = to_virtio_net(vdev);

    features |= (1 << VIRTIO_NET_F_MAC);

    if (peer_has_vnet_hdr(n)) {
        tap_using_vnet_hdr(n->nic->nc.peer, 1);
    } else {
        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
        features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);

        features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
        features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
    }

    if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
        features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
        features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
    }

    if (!n->nic->nc.peer ||
        n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
        return features;
    }
    if (!tap_get_vhost_net(n->nic->nc.peer)) {
        return features;
    }
    return vhost_net_get_features(tap_get_vhost_net(n->nic->nc.peer), features);
}
Beispiel #4
0
static void vhost_net_stop_one(struct vhost_net *net,
                               VirtIODevice *dev)
{
    struct vhost_vring_file file = { .fd = -1 };

    if (!net->dev.started) {
        return;
    }

    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
        assert(r >= 0);
    }
    net->nc->info->poll(net->nc, true);
    vhost_dev_stop(&net->dev, dev);
    vhost_dev_disable_notifiers(&net->dev, dev);
}

int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
                    int total_queues)
{
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
    VirtioBusState *vbus = VIRTIO_BUS(qbus);
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
    int r, i = 0;

    if (!k->set_guest_notifiers) {
        error_report("binding does not support guest notifiers");
        r = -ENOSYS;
        goto err;
    }

    for (i = 0; i < total_queues; i++) {
        r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2);

        if (r < 0) {
            goto err;
        }
    }

    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
    if (r < 0) {
        error_report("Error binding guest notifier: %d", -r);
        goto err;
    }

    return 0;

err:
    while (--i >= 0) {
        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
    }
    return r;
}
Beispiel #5
0
void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
                    int total_queues)
{
    int i, r;

    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
                                          total_queues * 2,
                                          false);
    if (r < 0) {
        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
        fflush(stderr);
    }
    assert(r >= 0);

    for (i = 0; i < total_queues; i++) {
        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
    }
}
Beispiel #6
0
void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
                    int total_queues)
{
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
    VirtioBusState *vbus = VIRTIO_BUS(qbus);
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
    int i, r;

    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
    if (r < 0) {
        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
        fflush(stderr);
    }
    assert(r >= 0);

    for (i = 0; i < total_queues; i++) {
        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
    }
}
Beispiel #7
0
VHostNetState *get_vhost_net(NetClientState *nc)
{
    VHostNetState *vhost_net = 0;

    if (!nc) {
        return 0;
    }

    switch (nc->info->type) {
    case NET_CLIENT_OPTIONS_KIND_TAP:
        vhost_net = tap_get_vhost_net(nc);
        break;
    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
        vhost_net = vhost_user_get_vhost_net(nc);
        break;
    default:
        break;
    }

    return vhost_net;
}
Beispiel #8
0
static void virtio_net_reset(VirtIODevice *vdev)
{
    VirtIONet *n = to_virtio_net(vdev);

    /* Reset back to compatibility mode */
    n->promisc = 1;
    n->allmulti = 0;
    n->alluni = 0;
    n->nomulti = 0;
    n->nouni = 0;
    n->nobcast = 0;
    if (n->vhost_started) {
        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
        n->vhost_started = 0;
    }

    /* Flush any MAC and VLAN filter table state */
    n->mac_table.in_use = 0;
    n->mac_table.first_multi = 0;
    n->mac_table.multi_overflow = 0;
    n->mac_table.uni_overflow = 0;
    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
    memset(n->vlans, 0, MAX_VLAN >> 3);
}