virtio协议1.0 -- 网络设备

84 篇文章 6 订阅
40 篇文章 9 订阅

引子

  • 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)

    • 什么是Gratuitous ARP_weixin_33754065的博客-CSDN博客 

    • 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.
      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) 和 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报头和正文的补码校验和替换它将得到正确的结果
      • 如果驱动协商了 VIRTIO_NET_F_HOST_TSO4, TSO6 或 UFO,且报文需要TCP或UDP分片,那么 gso_type 设置为 VIRTIO_NET_HDR_GSO_TCPV4, TCPV6 或 UDP(相反,设置为VIRTIO_NET_HDR_GSO_NONE)。这样,大于1514字节的报文可以被发送,元数据指示如何复制数据包头以将其切割成更小的数据包。gso的设定为
        • hdr_len:提示设备分配后每个报文都要复制多少报文头的内容,通常设置为包括传输报头在内的报头长度
        • gso_size:除了报文头(即MSS)的每个数据包的最大尺寸
        • 如果支持 VIRTIO_NET_F_HOST_ECN,gso_type 中的 VIRTIO_NET_HDR_GSO_ECN 表示TCP报文有 ECN bit集
        • TCP的ECN机制(显式拥塞通告机制)

      • num_buffers 设置为0,发送报文中,不使用
      • header 和 packet 在发送时被放在一个desc里面发送,然后KICK设备(实际情况根据ANY LAYOUT,可以放在两个不同的desc中!!!
    • 驱动
      • 设备必须设置 num_buffers 为0
      • 如果未协商VIRTIO_NET_F_CSUM,则驱动必须将flags设为0,并应向设备提供完全校验和的数据包
      • 如果协商了VIRTIO_NET_F_HOST_TSO4,则驱动程序可以将gso_type设置为VIRTIO_NET_HDR_GSO_TCPV4 以请求TCPV4分片,否则驱动程序不能将gso_type设置为VIRTIO_NET_HDR_GSO_TCPV4
      • 如果协商了VIRTIO_NET_F_HOST_TSO6,则驱动程序可以将gso_type设置为VIRTIO_NET_HDR_GSO_TCPV6 以请求TCPV6分片,否则驱动程序不能将gso_type设置为VIRTIO_NET_HDR_GSO_TCPV6
      • 如果协商了VIRTIO_NET_F_HOST_UFO,则驱动程序可以将gso_type设置为VIRTIO_NET_HDR_GSO_UDP 以请求UDP分片,否则驱动程序不能将gso_type设置为VIRTIO_NET_HDR_GSO_UDP
      • 除非协商了 VIRTIO_NET_F_HOST_ECN,否则驱动不能发送带有Explicit Congestion Notification bit set 的需要分片的TCP报文,且gso_type 不能为VIRTIO_NET_HDR_GSO_UDP
      • 如果协商了 VIRTIO_NET_F_CSUM , 驱动可能在flag中设置 VIRTIO_NET_HDR_F_NEEDS_CSUM
        • 驱动必须验证从csum_start的偏移量csum_offset处的数据包校验和以及所有之前的偏移量

        • 驱动必须设置TCP/UDP伪头中的 checksum

        • 驱动必须设置 csum_start 和 csum_offset

      • 如果没有协商VIRTIO_NET_F_HOST_TSO4, TSO6 或 UFO,则驱动必须将gso_type 设置为VIRTIO_NET_HDR_GSO_NONE
      • 如果 gso_type 不是 VIRTIO_NET_HDR_GSO_NONE,驱动必须在flag中设置 VIRTIO_NET_HDR_F_NEEDS_CSUM位,并必须为MSS设置 gso_size
      • 如果已协商VIRTIO_NET_F_HOST_TSO4、TSO6或UFO,则驱动程序应将hdr_len设置为不小于标头(包括传输标头)长度的值
      • 驱动不能设置flag的 VIRTIO_NET_HDR_F_DATA_VALID位
    • 设备
      • 设备忽略flag中没有协商的标志位
      • 如果flag 中 VIRTIO_NET_HDR_F_NEEDS_CSUM 没有设置,设备不能使用csum_start 和 csum_offset
      • 如果 VIRTIO_NET_F_HOST_TSO4, TSO6 或UFO被协商了,设备可能使用 hdr_len 来计算传输包头大小,单设备不能依赖于 hdr_len 值是正确的
      • 如果 VIRTIO_NET_HDR_F_NEEDS_CSUM 没有被设置,设备不能假设checksum是正确的
    • 发送报文中断
      • 通常,驱动程序将使用VIRTQ_AVAIL_F_NO_INTERRUPT 标志抑制传输中断,检查传输路径中的used packets
      • 此中断处理程序中的行为是从used ring 中回收描述符,并释放报文的内容
  • 设定接收报文buffer
    • 一般在RXQ上预先分配接收内存,以便提高性能
    • 如果 VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6 或VIRTIO_NET_F_GUEST_UFO 被使用了,最大的报文长度可以是 65550 字节,否则是1514字节,virtio_net_hdr 加载报文最前面,所以长度可能是65562 或1526字节
    • 设备
      • 如果 VIRTIO_NET_F_MRG_RXBUF 没有协商
        • 如果 VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6 或 VIRTIO_NET_F_GUEST_UFO协商了,驱动填充的buffer最少是65562字节
        • 否则,驱动最小填充1526字节的buffer
      • 如果 VIRTIO_NET_F_MRG_RXBUF 协商了,每个buffer必须大于 struct virtio_net_hdr
      • 每个buffer可以被split为多个desc
      • 如果 VIRTIO_NET_F_MQ 协商了,receiveq1...receiveqN都应该被预填充
    • 驱动
      • 设备需要设置 num_buffers 为接收报文所使用的desc数量
      • 如果 VIRTIO_NET_F_MRG_RXBUF 没有协商,设备必须使用1个desc来接收报文,num_buffers 为1
  • 接收报文处理
    • 当数据包被复制到receiveq中的buffer时,最佳是禁用中断并处理所有数据包,直到处理完所有数据包,然后重启中断
    • 接收报文处理包括
      • num_buffers表示此packet使用了多少desc:如果未协 VIRTIO_NET_F_MRG_RXBUF,则始终为1。这允许接收大数据包,而无需分配大的buffer。在这种情况下,used ring
        中将至少有num_buffers个buffer,并且设备将这些desc链成一个链表形成单个数据包。非首buffer不会以struct virtio_net_hdr开头
      • 如果num_buffers是1,那么整个packet将包含在此buffer中,紧跟在结构virtio_net_hdr之后
      • 如果协商了 VIRTIO_NET_F_GUEST_CSUM,可以在 flag中设置 VIRTIO_NET_HDR_F_DATA_VALID 位;如果可以,设备校验packet checksum,如果有多层包头,那么只校验一层
    • 此外,VIRTIO_NET_F_GUEST_CSUM、TSO4、TSO6、UDP和ECN功能使能的话,支持校验和、大包分片卸载和ECN支持,这是传输校验和、传输分段卸载和ECN功能
    • 如果协商了VIRTIO_NET_F_GUEST_CSUM功能,则可以在flag中设置VIRTIO_NET_HDR_F_NEEDS_CSUM bit:如果设置了,将会校验报文的checksum。packet上的checksum不完整,csum_start和csum_offset指示如何计算checksum
    • 如果协商了VIRTIO_NET_F_GUEST_TSO4、TSO6或UFO,则gso_type
      可能是除VIRTIO_NET_HDR_GSO_NONE之外的值,gso_size指示所需的MSS
    • 设备
      • 如果未协商VIRTIO_NET_F_MRG_RXBUF,设备必须将num_buffers设置为1
      • 如果已协商VIRTIO_NET_F_MRG_RXBUF,设备必须设置num_buffers,以指示packet(包括报头)使用的desc数量
      • 设备如果使用多个desc接收一个报文,将used ring 中的idx原子地增加num_buffers值后,作为新的idx
      • 如果 VIRTIO_NET_F_GUEST_CSUM 没有协商,设备必须把flag设置为0,并且让驱动计算完整的checksum
      • 如果 VIRTIO_NET_F_GUEST_TSO4 没有协商,设备不能设置 gso_type 为 VIRTIO_NET_HDR_GSO_TCPV4
      • 如果 VIRTIO_NET_F_GUEST_UDP 没有协商,设备不能设置 gso_type 为 VIRTIO_NET_HDR_GSO_UDP
      • 如果 VIRTIO_NET_F_GUEST_TSO6 没有协商,设备不能设置 gso_type 为 VIRTIO_NET_HDR_GSO_TCPV6
      • 如果 VIRTIO_NET_F_GUEST_ECN 没有协商,不能发送需要分片的ECN的TCP报文,如果协商了,gso_type 应该为 VIRTIO_NET_HDR_GSO_ECN
      • 如果协商了 VIRTIO_NET_F_GUEST_CSUM,设备可能在flag中设置VIRTIO_NET_HDR_F_NEEDS_CSUM bit,如果设置了
        • 设备必须校验checksum
        • 设备必须将接收buffer中存储的packet checksum 设置为TCP/UDP伪报头
        • 设备必须设置csum_start和csum_offset,以便从csum_start直到数据包结束,计算一个1的补码checksum,,并将结果存储在csum_offset处,从csum_start将产生完全校验和的数据包;
      • 如果未协商任何VIRTIO_NET_F_GUEST_TSO4、TSO6或UFO选项,则设备必须将gso_type 设置为 VIRTIO_NET_HDR_GSO_NONE
      • 如果gso_type 不是 VIRTIO_NET_HDR_GSO_NONE,则设备还必须设置flag中的VIRTIO_NET_HDR_F_NEEDS_CSUM 位,并必须设置gso_size 以指示所需的MSS
      • 如果已协商 VIRTIO_NET_F_GUEST_TSO4、TSO6或UFO选项之一,则设备应将hdr_len设置为不小于所有包头(包括传输标头)长度的值
      • 如果已协商VIRTIO_NET_F_GUEST_CSUM功能,则设备可在flag中设置VIRTIO_NET_HDR_F_DATA_VALID 位,如果这样,设备必须验证数据包checksum(在多个封装协议的情况下,验证一级校验和)
    • 驱动
      • 驱动必须忽略无法识别的flag位
      • 如果flag中未设置VIRTIO_NET_HDR_F_NEEDS_CSUM bit,则驱动不得使用csum_start 和 csum_offset
      • 如果已协商VIRTIO_NET_F_GUEST_TSO4、TSO6或UFO选项之一,则驱动可能仅将 hdr_len 用作表示传输头大小的提示。驱动不得依赖 hdr_len 的正确性
      • 如果未设置VIRTIO_NET_HDR_F_NEEDS_CSUM或VIRTIO_NET_HDR_F_DATA_VALID,则驱动不能依赖数据包checksum是否正确
  • 控制队列
    • VIRTIO_NET_F_CTRL_VQ协商了,使用CQ来发送命令操作设备实现多种feature,这些feature不易在configuration space中实现
    • 命令模式
    • class, command 和 command-specific-data 被驱动设定,设备会写ACK字段,如果ack字段不是 VIRTIO_NET_OK,那么可以用来做一些排查工作

       
    • 报文接收过滤功能
      • 如果 VIRTIO_NET_F_CTRL_RX 和 VIRTIO_NET_F_CTRL_RX_EXTRA 协商了,驱动可以发送 promiscuous mode, multicast, unicast and broadcast 接收的控制命令
      • 通常,这些命令是 best-effort,不需要的报文有可能会到达
      • 设备
        • 如果已协商VIRTIO_NET_F_CTRL_RX功能,则设备必须支持以下VIRTIO_NET_CTRL_RX class 的命令
          • VIRTIO_NET_CTRL_RX_PROMISC:打开和关闭混杂模式。command-specific-data 是一个字节,包含0(关闭)或1(打开)。如果启用了混杂模式,则设备应接收所有传入的数据包。即使由VIRTIO_NET_CTRL_RX class命令设置的其他模式之一处于启用状态,该命令也应生效
          • VIRTIO_NET_CTRL_RX_ALLMULTI:打开和关闭所有多播接收。command-specific-data 是一个字节,包含0(关闭)或1(打开)。当开启是时,设备应允许所有传入的多播数据包
        • 如果已协商VIRTIO_NET_F_CTRL_RX_EXTRA 功能,则设备必须支持以下VIRTIO_NET_CTRL_RX class 命令
          • VIRTIO_NET_CTRL_RX_ALLUNI:打开和关闭所有单播接收。command-specific-data 是一个字节,包含0(关闭)或1(打开)。当开启时,设备应允许所有传入的单播数据包
          • VIRTIO_NET_CTRL_RX_NOMULTI:抑制多播接收。command-specific-data是一个字节,包含0(允许多播接收)或1(禁止多播接收)。当开启时,设备不应向驱动程序发送多播数据包。即使启用了VIRTIO_NET_CTRL_RX_ALLMULTI,此选项也应生效。filter
            不应用于broadcast数据包
          • VIRTIO_NET_CTRL_RX_NOUNI:抑制单播接收。command-specific-data 是一个字节,包含0(允许单播接收)或1(禁止单播接收)。当开启时,设备不应向驱动程序发送单播数据包。即使VIRTIO_NET_CTRL_RX_ALLUNI处于启用状态,此选项也应生效
          • VIRTIO_NET_CTRL_RX_NOBCAST:抑制广播接收。command-specific-data是一个字节,包含0(允许广播接收)或1(禁止广播接收)。当开启时,设备不应向驱动程序发送broadcast 数据包。即使启用了VIRTIO_NET_CTRL_RX_ALLMULTI,此选项也应生效
      • 驱动
        • 如果未协商VIRTIO_NET_F_CTRL_RX功能,则驱动不得发出VIRTIO_NET_CTRL_RX_PROMISC或VIRTIO_NET_CTRL_RX_ALLMULTI命令 
        • 如果未协商VIRTIO_NET_F_CTRL_RX_EXTRA 功能,驱动不得发出VIRTIO_NET_CTRL_RX_ALLUNI、VIRTIO_NET_CTRL_RX_NOMULTI、VIRTIO_NET_CTRL_RX_NOUNI或VIRTIO_NET_CTRL_RX_NOBCAST命令 
    • 设定MAC过滤表
      • 如果协商了VIRTIO_NET_F_CTRL_RX功能,则驱动可以发送用于MAC过滤的控制命令
      • 该设备可以通过任意数量的目的MAC过滤传入的数据包
      • MAC过滤表是使用VIRTIO_NET_CTRL_MAC class 和命令VIRTIO_NET_CTRL_MAC_table_set设置的
      • command-specific-data 是两个可变长度表(元素是 6字节MAC地址)(struct struct virtio_net_ctrl_mac)
      • 第一个表包含单播地址,第二个表包含多播地址
      • VIRTIO_NET_CTRL_MAC_ADDR_SET 命令用于设置RX默认接收的MAC地址(如果 VIRTIO_NET_F_MAC_ADDR 已协商,这将反映在config space 的 mac 域中)
      • VIRTIO_NET_CTRL_MAC_ADDR_SET 的 command-specific-data 是 6字节的 MAC 地址
      • 设备
        • reset 时,MAC过滤表必须清空
        • 在使用 VIRTIO_NET_CTRL_MAC_TABLE_SET 命令之前,设备必须更新MAC过滤表
        • 如果已协商VIRTIO_NET_F_MAC_ADDR,则设备必须在使用VIRTIO_NET_CTRL_MAC_ADDR_SET 命令之前在config space 中更新 mac域
        • 设备应丢弃目标MAC与config space 的 mac域 或 MAC过滤表不匹配的ingress数据包
      • 驱动
        • 如果尚未协商VIRTIO_NET_F_CTRL_RX,则驱动不得发出VIRTIO_NET_CTRL_MAC class命令
        • 如果已协商VIRTIO_NET_F_CTRL_RX,则驱动应发出VIRTIO_NET_CTRL_MAC_ADDR_SET 以设置默认MAC(如果它与config space 的 mac 不同)
        • 驱动必须在VIRTIO_NET_CTRL_MAC_TABLE_SET命令后面跟一个le32 number,后面是非多播MAC表,后面跟另一个le32 number,后面多播MAC地址表。任何一个number都可以是0
      • 区别
        • 使用legacy 接口时,设备和驱动必须根据客户机的endian而不是little endian格式化struct virtio_net_ctrl_mac中的entries
        • 未协商VIRTIO_NET_F_CTRL_MAC_ADDR的 legacy 驱动程序,在NIC接到数据包时更改了config space 中的 mac域。legacy 驱动总是将mac值从第一个字节写到最后一个字节,因此在probe到legacy 驱动后,设备可能会延迟mac更新,也可能会延迟处理传入的数据包,直到驱动将mac的最后一个字节写到config space
    • VLAN过滤表
      • 如果驱动协商VIRTION_NET_F_CTRL_VLAN 功能,驱动可以控制设备中的VLAN过滤表
      • VIRTIO_NET_CTRL_VLAN_ADD 和 VIRTIO_NET_CTRL_VLAN_DEL 命令都使用一个little-endian 的16位 VLAN id作为 command-specific-data
      • 区别
        • 当使用legacy 接口时,设备和驱动程序必须根据客户机的native endian
          而不是little-endian 来格式化VLAN id 
    • 发送 Gratuitous Packet
      • 如果驱动协商 VIRTIO_NET_F_GUEST_ANNOUNCE(取决于VIRTIO_NET_F_CTRL_VQ),设备可以要求驱动发送免费数据包(gratuitous packets)
      • 这通常在客户机物理迁移之后完成,并且需要在新的网络链接上宣布其存在。(由于hypervisor不了解客户网络配置(例如标记的vlan),因此以这种方式宣告客户是最简单的)
      • 当驱动注意到 device configuration 更改时,会检查device configuration status
        字段中的 VIRTIO_NET_S_ANNOUNCE bit
      • VIRTIO_NET_CTRL_ANNOUNCE_ACK 命令用于指示驱动已收到notification
        ,并且设备清除status域中的VIRTIO_NET_S_ANNOUNCE 位
      • notification 处理过程
        • 发送免费数据包(如ARP)或标记有待发送的免费数据包,并让延迟例程发送它们 
        • 通过 control vq 发送 VIRTIO_NET_CTRL_ANNOUNCE_ACK 命令 
      • 驱动
        • 如果驱动协商VIRTIO_NET_F_GUEST_ANNOUNCE
          ,驱动应该在发现status中的VIRTIO_NET_S_ANNOUNCE 位置位后,通知网络对等方它的新位置
        • 驱动程序必须在控制队列上发送一条命令,命令队列的class为IRTIO_NET_CTRL_ANNOUNCE 和命令为 VIRTIO_NET_CTRL_ANNOUNCE_ACK 
      • 设备
        • 如果协商了VIRTIO_NET_F_GUEST_ANNOUNCE,设备必须在收到VIRTIO_NET_CTRL_ANNOUNCE class 和 VIRTIO_NET_CTRL_ANNOUNCE_ACK 控制报文buffer后清除status域中的VIRTIO_NET_S_ANNOUNCE 位,才可以将控制报文buffer标记为used
    • MQ模式下,接收steering
      • 如果驱动协商VIRTIO_NET_F_MQ(取决于VIRTIO_NET_F_CTRL_VQ),它可能会在多个transmitq1…transmitqN中的一个上发送数据包
      • 要求设备根据数据包flow将传入数据包入队到多个receiveq1…receiveqN中的一个
      • 默认情况下禁用多队列
      • 驱动通过执行VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令启用多队列,指定要使用RXQ,TXQ queue pair 数(最大到 max_virtqueue_pairs)
      • 可以使用transmitq1…transmitqn和receiveq1…receiveqn收发报文,其中n=virtqueue_pairs
      • 启用多队列时,设备必须使用基于数据包flow的自动接收转向(receive steering)
      • 接收转向分类的编程是隐式的
      • 在驱动程序在transmitqX上传输flow的数据包后,设备应使该流的传入数据包转向receiveqX
      • 对于单向协议,或者在还没有发送报文的情况下,设备可以将分组引导到指定的receiveq1…receiveqn之外的随机队列
      • 通过将virtqueue_pairs设置为1(默认设置)并等待设备使用控制buffer(这在真实驱动情况下会死锁住内核!!),可以禁用多队列
      • 驱动
        • 在使用VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令启用virtqueue之前,驱动程序必须配置virtqueue
        • 驱动不得在设备配置空间中请求0或大于max_virtqueue_pairs的virtqueue_pairs
        • 在VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令之前,驱动必须仅在transmitq1上对报文入队
        • 一旦将VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令置于available ring.
          中,驱动就不能在大于virtqueue_pairs的传输队列上入队数据包
      • 设备
        • 在VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令之前,设备必须仅在receiveq1上对入队数据包 
        • 一旦将VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET命令放置在used ring中,设备就不能在大于virtqueue_pairs的RXQ上对入队数据包 
      • 区别
        • 在使用legacy接口时,设备和驱动必须根据客户机的native endian
          而不是little-endian 格式化virtqueue_pairs 
    • 卸载状态配置
      • 如果协商了VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 功能,则驱动可以发送用于dynamic offloads state configuration 的控制命令
      • 设置 Offloads State
      • VIRTIO_NET_CTRL_GUEST_OFFLOADS class 有一个命令:VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 应用新的卸载配置
      • 作为命令数据传递的le64值是位掩码,位集定义要启用哪些配置卸载,位清除表示对应的配置卸载要禁用
      • 每个卸载都有相应的设备功能
      • 在特性协商时,将启用相应的卸载以保持向后的兼容性。
      • 驱动
        • 驱动不得启用未协商功能的配置卸载
      • 区别
        • 在使用legacy 接口时,设备和驱动程序必须根据客户机的native endian
          而不是(不使用传统接口时)little endian格式化 offloads字段
  • 区别(数据帧)
    • 使用legacy 接口时,未协商VIRTIO_F_ANY_LAYOUT 的驱动程序必须在传输和接收上为struct virtio_net_hdr 单独使用一个desc,网络数据在下一个desc中
    • 此外,当使用control virtqueue时,未协商VIRTIO_F_ANY_LAYOUT 的驱动必须
      • 对于所有命令,使用一个单独的2字节desc,包括前两个字段:class和command
      • 对于除VIRTIO_NET_CTRL_MAC_TABLE_SET之外的所有命令,使用另一个单独的desc,该desc包含command-specific-data(不带任何填充)
      • 对于VIRTIO_NET_CTRL_MAC_TABLE_SET命令,只使用两个desc来完成commandspecific-data with no padding:
        • 第一个desc必须包括单播地址virtio_net_ctrl_mac 表结构(不带填充)
        • 第二个desc必须包括多播地址的virtio_net_ctrl_mac表结构(无填充)
      • 对于所有命令,ack字段单独使用一个desc
      • 以上内容参见VCP的实现代码

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值