virtio协议1.0--⽹络设备
引⼦
virtio network device 是⼀种虚拟以太⽹卡
迄今为⽌virtio⽀持的最复杂的设备(其他设备可挖掘的内容很多)
做数据分析
空缓冲区被提前放置在RX virtqueue中⽤于接收数据包,收包⼀个队列
发送的数据包被排队到TX virtqueue中以便按该顺序传输,发送⼀个队列快手陈山
控制队列⽤于控制和⾼级过滤功能
Device ID
1
Virtqueues
队列分布布局
如果 VIRTIO_NET_F_MQ 没有协商,N = 1
如果 VIRTIO_NET_F_MQ 协商了,N  = max_virtqueue_pairs
VIRTIO_NET_F_CTRL_VQ 协商了,才会有 control queue
Feature bits
feature bit 说明
VIRTIO_NET_F_CSUM (0)  设备进⾏部分校验数据包。“checksum offload”是现代⽹卡的常见功能。丁丁 好声音
VIRTIO_NET_F_GUEST_CSUM (1) 驱动进⾏部分校验数据包。
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS (2) 没有代码使⽤过,offload配置通道,好像和 XDP LRO/CSUM 相关。
Control channel offloads reconfiguration support.Dynamic offload configuration。
VIRTIO_NET_F_MAC (5) 设备有指定的MAC
VIRTIO_NET_F_GUEST_TSO4 (7) 驱动⽀持TSOv4
VIRTIO_NET_F_GUEST_TSO6 (8) 驱动⽀持 TSOv6
VIRTIO_NET_F_GUEST_ECN (9) 驱动⽀持带有ECN 的 TSO
VIRTIO_NET_F_GUEST_UFO (10) 驱动⽀持 UFO.
VIRTIO_NET_F_HOST_TSO4 (11) 设备⽀持 TSOv4.
VIRTIO_NET_F_HOST_TSO6 (12) 设备⽀持 TSOv6.
VIRTIO_NET_F_HOST_ECN (13) 设备⽀持有 ECN 的 TSO
VIRTIO_NET_F_HOST_UFO (14) 设备⽀持 UFO
VIRTIO_NET_F_MRG_RXBUF (15) 驱动⽀持 Merge Buffer
VIRTIO_NET_F_STATUS (16)  ⽀持Configuration status 域,config change有关
VIRTIO_NET_F_CTRL_VQ (17) ⽀持Control queue
VIRTIO_NET_F_CTRL_RX (18) ⽀持 通过Control queue 设置 RX mode,如混杂模式,组播,⼴播等
VIRTIO_NET_F_CTRL_VLAN (19) Control queue 设置vlan过滤表
VIRTIO_NET_F_GUEST_ANNOUNCE(21) 驱动⽀持发送 gratuitous packets(Gratuitous ARP)
VIRTIO_NET_F_MQ(22) 设备⽀持多队列,并且RR⽅式接收报⽂
VIRTIO_NET_F_CTRL_MAC_ADDR(23) ⽀持通过Control Queue设置MAC地址
feature bit 依赖关系
VIRTIO_NET_F_GUEST_TSO4 需要 VIRTIO_NET_F_GUEST_CSUM.
VIRTIO_NET_F_GUEST_TSO6 需要  VIRTIO_NET_F_GUEST_CSUM.
VIRTIO_NET_F_GUEST_ECN 需要  VIRTIO_NET_F_GUEST_TSO4 或者 VIRTIO_NET_F_GUEST_TSO6.
VIRTIO_NET_F_GUEST_UFO 需要 VIRTIO_NET_F_GUEST_CSUM.
VIRTIO_NET_F_HOST_TSO4 需要 VIRTIO_NET_F_CSUM.
VIRTIO_NET_F_HOST_TSO6 需要 VIRTIO_NET_F_CSUM.
VIRTIO_NET_F_HOST_ECN 需要 VIRTIO_NET_F_HOST_TSO4 或VIRTIO_NET_F_HOST_TSO6
VIRTIO_NET_F_HOST_UFO 需要 VIRTIO_NET_F_CSUM.世界杯决赛时间12月18日几点
VIRTIO_NET_F_CTRL_RX 需要 VIRTIO_NET_F_CTRL_VQ.
VIRTIO_NET_F_CTRL_VLAN 需要 VIRTIO_NET_F_CTRL_VQ.
VIRTIO_NET_F_GUEST_ANNOUNCE 需要 VIRTIO_NET_F_CTRL_VQ.
VIRTIO_NET_F_MQ 需要 VIRTIO_NET_F_CTRL_VQ.
VIRTIO_NET_F_CTRL_MAC_ADDR 需要 VIRTIO_NET_F_CTRL_VQ.
区别
VIRTIO_NET_F_GSO (6) 设备⽀持报⽂分⽚,但是在未来将会有多个bit描述这个功能,以便更加清晰
设备 configuration 布局
当前定义了三个driver-read-only 配置字段
mac地址字段始终存在(但仅当设置了VIRTIO_NET_F_mac时有效),
status仅当设置了VIRTIO_NET_F_status时才存在。
为状态字段定义了两个只读位(⽤于驱动程序):VIRTIO_NET_S_LINK_UP和VIRTIO_NET_S_ANNOUNCE
字段max_virtqueue_pairs仅在设置VIRTIO_NET_F_MQ时存在。此字段指定在协商VIRTIO_NET_F_MQ后可以配置的传输和接收VirtQueue(分别为receiveq1…receiveqN和transmitq1…transmitqN)的最⼤数量
驱动
如果设备有MAC,应该协商VIRTIO_NET_F_MAC
如果⽀持 VIRTIO_NET_F_MAC,驱动必须将NIC的指定的MAC到mac域。否则,它应该使⽤本地管理的MAC地址
如果驱动不⽀持VIRTIO_NET_F_STATUS,默认链路是活跃的,如果⽀持,需要从status域读取设备状态设备
如果⽀持 VIRTIO_NET_F_MQ,设备必须设置 max_virtqueue_pairs 为 1 到 0x8000的⼀个值
区别
当使⽤ legacy 接⼝,设备从 virtio_net_config 中读取 status 和 max_virtqueue_pairs的内容是客户机的native endian,⽽不⼀定是 little endian
legacy 接⼝ mac 域是驱动可写的,不⽤ VIRTIO_NET_F_CTRL_MAC_ADDR 就可以更新MAC地址
设备初始化
驱动初始化设备的典型流程
初始化收、发队列,每种都最多到N,如果⽀持 VIRTIO_NET_F_MQ,N=max_virtqueue_pairs, 否则为 N=1
⽀持 VIRTIO_NET_F_CTRL_VQ,初始化 control queue
为 RX队列填充预接收buffer
即使 有 VIRTIO_NET_F_MQ,默认也只有1 RXQ, 1TXQ, 1CQ,驱动通过发送 VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 命令来指定收、发队列数
⽀持 VIRTIO_NET_F_MAC,configuration space 的 mac 字段就是物理地址,否则驱动⽣成随机的MAC地址
如果⽀持 VIRTIO_NET_F_STATUS,从底层的status字段读取链路状态,否则驱动默认链路是active的
如果⽀持 VIRTIO_NET_F_CSUM,驱动不需要⽣成checksum,性能会更⾼
如果⽀持 VIRTIO_NET_F_HOST_TSO4 (IPv4 TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP)
沈佳妮59035>闫妮 毛门照片和 VIRTIO_NET_F_HOST_UFO (UDP fragmentation),那么驱动可以使⽤卸载到设备的TCP和UDP
相反的功能也可⽤:驱动程序可以通过协商这些功能为虚拟设备节省⼀些⼯作
设备操作
区别
使⽤ legacy 接⼝,设备必须格式化 struct virtio_net_hdr 的相关域为客户机 native endian,⽽不是 little-endian
当协商 VIRTIO_NET_F_MRG_RXBUF, legacy 驱动在struct virtio_net_hdr
中提供 num_buffers,没有协商,头会⼩于2个字节
当使⽤legacy接⼝,驱动应该忽略TXQ和CQ的used ring 中entry的 len 值(注意,真实情况下,CQ使⽤len值,为writeable buffer的总和)
注意:历史上,有的设备在即使没有数据的情况下,也会设置len为 total descriptor length
报⽂发送
发送⼀个报⽂很简单,但是根据不同的特性,会有很多发送过程的变化
驱动可以发送⼀个完整校验和的报⽂,在这种情况下,flag为0,gso_type为 VIRTIO_NET_HDR_GSO_NONE
如果驱动协商了 VIRTIO_NET_F_CSUM,驱动跳过checksum阶段
flag 为 VIRTIO_NET_HDR_F_NEEDS_CSUM
csum_start 设置为 packet内开始计算checksum位置的偏移量
csum_offset 表⽰在 csum_start 之后多少个字节出,设备放置计算好的 checksum结果值
数据包中的TCP校验和字段设置为TCP伪报头的和,因此⽤TCP报头和正⽂的补码校验和替换它将得到正确的结果