virtio 模式下不支持ethtool -G 命令分析

结论:

  1. E1000网卡支持 ethtool -g xxx 和 ethtool -G xxx rx 4096 tx 4096 命令
  2. rtl8139网卡仅支持 ethtool -g xxx 命令
  3. virtio 模式:
  • centos7 仅支持ethtool -g xxx 命令
  • centos 6.5 两个命令都不支持
  • virtio模式下执行ethtool -g xxx 命令获取的是vring队列Queue Size 的大小是256,是QEMU端代码写死的不能被修改。

分析原因:

       E1000和rtl8139 是全虚拟化ethtool -g xxx 命令实际查询的是虚拟网卡的接收和发送队列的长度,而且e1000支持修改队列长度,理论上网卡的队列越长,网卡处理性能越高。

而virtio是半虚拟化,它的实现原理和传统网卡不一样,virtio中的核心部分是vring队列,这个队列是用于virtio前段driver和后端vhost通信的桥梁,在centos 7中支持ethtool -g xxx 命令

最终调用的函数为:

static void virtnet_get_ringparam(struct net_device *dev,
    struct ethtool_ringparam *ring)
{
 struct virtnet_info *vi = netdev_priv(dev);
 ring->rx_max_pending = virtqueue_get_vring_size(vi->rq[0].vq);
 ring->tx_max_pending = virtqueue_get_vring_size(vi->sq[0].vq);
 ring->rx_pending = ring->rx_max_pending;
 ring->tx_pending = ring->tx_max_pending;
}

此函数中获取rx 和tx 队列长度时,实际读取的是vring 队列的size。
centos 6.5 之所以不支持ethtool -g xxx 命令 是因为 2.6.32 的linux内核没有相关操作接口,virtnet支持的ethtool操作接口如下:

static const struct ethtool_ops virtnet_ethtool_ops = {
 .set_tx_csum = virtnet_set_tx_csum,
 .set_sg = ethtool_op_set_sg,
 .set_tso = ethtool_op_set_tso,
 .set_ufo = ethtool_op_set_ufo,
 .get_link = ethtool_op_get_link,
 .get_ringparam = virtnet_get_ringparam, /*此接口是我打了patch之后才支持的,原本不支持*/
};

virittio设备的配置空间如下:

使用PCI设备的BAR0来对PCI设备进行配置,从上表中可以看出Queue Size 对于前段virtio driver 来说是只读的,没有写权限。Queue Size 的大小只能由设备指定。
所以在virtio模式下不支持ethtool -G xxx rx 4096 tx 4096 命令,因为没有写权限。

初始化 virtqueue如下

该部分代码的实现在 virtio-pci.c 里 setup_vq()里面,具体为:

1.选择 virtqueue 的索引,写入 Queue Select 寄存器

2.读取 queue size 寄存器获得 virtqueue 的可用数目

3.分配并清零 4096 字节对齐的连续物理内存用于存放 virtqueue(调用 alloc_pages_exact()).把内存地址除以 4096 写入 Queue Address 寄存器(VIRTIO_PCI_QUEUE_ADDR_SHIFT)

4.可选情况下,如果 MSI-X 中断机制启用,选择一个向量用于 virtqueue 请求的中断,把对应向量的 MSI-X 表格入口号写入 Queue Vector 寄存器域,然后再次读取该域以确认返回正确值。

对应代码如下:

static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index,
      void (*callback)(struct virtqueue *vq),
      const char *name,
      u16 msix_vec)
{
 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 struct virtio_pci_vq_info *info;
 struct virtqueue *vq;
 unsigned long flags, size;
 u16 num;
 int err;
 VIRTIO_PCI_QUEUE_ADDR_SHIFT
 /* Select the queue we're interested in */
 /*1.选择 virtqueue 的索引,写入 Queue Select 寄存器*/
 iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
 /* Check if queue is either not available or already active. */
 /*BAR0寄存器地址偏移12字节*/
 /*是只读的不能修改*/
 /*2.读取 queue size 寄存器获得 virtqueue 的可用数目*/
 num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
 if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
  return ERR_PTR(-ENOENT);
 /* allocate and fill out our structure the represents an active
  * queue */
 info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL);
 if (!info)
  return ERR_PTR(-ENOMEM);
 info->queue_index = index;
 info->num = num;
 info->msix_vector = msix_vec;
 size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
 info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
 if (info->queue == NULL) {
  err = -ENOMEM;
  goto out_info;
 }
 /* activate the queue */
 /*分配并清零 4096 字节对齐的连续物理内存用于存放 virtqueue(调用 alloc_pages_exact()).
 把内存地址除以 4096 写入 Queue Address 寄存器(VIRTIO_PCI_QUEUE_ADDR_SHIFT)*/
 iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
    vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 /* create the vring */
 vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
     vdev, info->queue, vp_notify, callback, name);
 if (!vq) {
  err = -ENOMEM;
  goto out_activate_queue;
 }
 vq->priv = info;
 info->vq = vq;
 if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
  iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
  msix_vec = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
  if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
   err = -EBUSY;
   goto out_assign;
  }
 }
 spin_lock_irqsave(&vp_dev->lock, flags);
 list_add(&info->node, &vp_dev->virtqueues);
 spin_unlock_irqrestore(&vp_dev->lock, flags);
 return vq;
out_assign:
 vring_del_virtqueue(vq);
out_activate_queue:
 iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 free_pages_exact(info->queue, size);
out_info:
 kfree(info);
 return ERR_PTR(err);
}



关于Queue Size 的初始化,在qemu初始化virtionet设备时进行了初始化,Queue Size 即kernel读取的num,被初始化为256。
相关代码如下:
static void virtio_net_device_realize(DeviceState *dev, Error **errp)会调用virtio_net_add_queue设置Queue Size 大小。
static void virtio_net_add_queue(VirtIONet *n, int index)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(n);
    n->vqs[index].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); /*收包队列默认256*/
    if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) {
        n->vqs[index].tx_vq =
            virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); /*发包队列默认256,定时器模式*/
        n->vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                              virtio_net_tx_timer,
                                              &n->vqs[index]);
    } else {
        n->vqs[index].tx_vq =
            virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);/*发包队列默认256,中断模式*/
        n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]);
    }
    n->vqs[index].tx_waiting = 0;
    n->vqs[index].n = n;
}

通过以分析得出结论virtio模式下Queue Size 的大小是256,是QEMU设备端指定的不支持修改,且virtio driver端只有读权限。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值