现代物理网卡为了提高网络并行处理性能,使用Packet Flow Hash 用于不同的目的,比如RSS(Receive Side Scaling)、RPS(Receive Packet Steering)、RFS(Receive Flow Steering)、ARFS(Accelerated Receive Flow Steering)以及接口bonding等等。网卡也可以提供包流哈希值作为元数据,它可以被应用程序使用,而不需要重新计算包流哈希值。
随着越来越多的服务部署在虚拟化环境中,利用虚拟接口来实现Packet Flow Hash的目的。比如可以在vpp中通过show hardware-interfaces命令行来查询虚拟机网卡队列支持情况及网卡卸载、rss能力(当前网卡默认并未开启RSS功能):
代码语言:javascript复制#下面可以查询接口GigabitEthernetb/0/01已经开启多队列模式
DBGvpp# show interface rx-placement
Thread 1 (vpp_wk_0):
node dpdk-input:
GigabitEthernetb/0/0 queue 0 (polling)
Thread 2 (vpp_wk_1):
GigabitEthernetb/0/0 queue 1 (polling)
#查询接口队列支持能力及网卡卸载及RSS配置情况。
DBGvpp# show hardware-interfaces
Name Idx Link Hardware
GigabitEthernetb/0/0 1 down GigabitEthernetb/0/0
Link speed: 10 Gbps
RX Queues:
queue thread mode
0 main (0) polling
TX Queues:
TX Hash: [name: hash-eth-l34 priority: 50 description: Hash ethernet L34 headers]
queue shared thread(s)
0 no 0
Ethernet address 00:50:56:33:cd:a8
VMware VMXNET3
carrier down
flags: maybe-multiseg tx-offload
Devargs:
rx: queues 1 (max 16), desc 1024 (min 128 max 4096 align 1)
tx: queues 1 (max 8), desc 1024 (min 512 max 4096 align 1)
pci: device 15ad:07b0 subsystem 15ad:07b0 address 0000:0b:00.00 numa 0
max rx packet len: 16384
promiscuous: unicast off all-multicast off
vlan offload: strip off filter off qinq off
rx offload avail: vlan-strip udp-cksum tcp-cksum tcp-lro vlan-filter
scatter rss-hash
rx offload active: scatter
tx offload avail: vlan-insert udp-cksum tcp-cksum tcp-tso multi-segs
tx offload active: udp-cksum tcp-cksum multi-segs
rss avail: ipv4-tcp ipv4 ipv6-tcp ipv6 #网卡支持rss能力
rss active: none #当前已生效的rss能力
tx burst function: (not available)
rx burst function: (not available)
VPP实现了基于软件的Packet Flow Hash ,可以用于不同的目的。还为用户提供了一种集中的方式来注册基于流量配置文件的自定义哈希函数,以用于不同的vpp功能,即Multi-TXQ,软件RSS或接口bonding驱动程序。
哈希架构提供了两种类型的哈希函数:VNET_HASH_FN_TYPE_ETHERNET和VNET_HASH_FN_TYPE_IP,分别用于以太网流量和IP流量。哈希架构提供了一个统一的函数函数接口:
代码语言:javascript复制typedef void (*vnet_hash_fn_t) (void **p, u32 *h, u32 n_packets);
参数说明:**p是指向数据包头(ethernet或ip)开头的指针数组。 *h是一个大小为n_packets的空数组。返回时计算后报文哈希值。 N_packets是传递给该函数的数据包数。
自定义哈希函数可以通过VNET_REGISTER_HASH_FUNCTION注册。用户需要提供名称、描述、优先级和哈希函数进行注册。默认哈希函数将根据注册的哈希函数中最高的优先级选择。
代码语言:javascript复制typedef struct vnet_hash_function_registration
{
const char *name;
const char *description;
int priority;
vnet_hash_fn_t function[VNET_HASH_FN_TYPE_N];
struct vnet_hash_function_registration *next;
} vnet_hash_function_registration_t;
例如,crc32c_5tuple提供了两个散列函数:用于IP通信流和用于以太网通信流。它使用流中的5个元组来计算其上的crc32哈希值。
代码语言:javascript复制void vnet_crc32c_5tuple_ip_func (void **p, u32 *hash, u32 n_packets);
void vnet_crc32c_5tuple_ethernet_func (void **p, u32 *hash, u32 n_packets);
VNET_REGISTER_HASH_FUNCTION (crc32c_5tuple, static) = {
.name = "crc32c-5tuple",
.description = "IPv4/IPv6 header and TCP/UDP ports",
.priority = 50,
.function[VNET_HASH_FN_TYPE_ETHERNET] = vnet_crc32c_5tuple_ethernet_func,
.function[VNET_HASH_FN_TYPE_IP] = vnet_crc32c_5tuple_ip_func,
};
我们可以通过命令行show hash来查询所有注册的哈希函数以及优先级和描述。
代码语言:javascript复制DBGvpp# show hash
Name Prio Description
hash-eth-l34 50 Hash ethernet L34 headers
hash-eth-l23 50 Hash ethernet L23 headers
hash-eth-l2 50 Hash ethernet L2 headers
handoff-eth-sym 1 Ethernet/IPv4/IPv6/MPLS headers Symmetric
handoff-eth 2 Ethernet/IPv4/IPv6/MPLS headers
crc32c-5tuple 50 IPv4/IPv6 header and TCP/UDP ports
在bonding接口创建时提供了负载分担的类型load-balance { l2 | l23 | l34 } 就是使用了上面的hash函数,通过API函数vnet_hash_function_from_name 来获取对应的hash函数指针,如下所示:
代码语言:javascript复制 if (bif->lb == BOND_LB_L2)
bif->hash_func =
vnet_hash_function_from_name ("hash-eth-l2", VNET_HASH_FN_TYPE_ETHERNET);
else if (bif->lb == BOND_LB_L34)
bif->hash_func = vnet_hash_function_from_name ("hash-eth-l34",
VNET_HASH_FN_TYPE_ETHERNET);
else if (bif->lb == BOND_LB_L23)
bif->hash_func = vnet_hash_function_from_name ("hash-eth-l23",
VNET_HASH_FN_TYPE_ETHERNET);
参考资料:
1、https://zhuanlan.zhihu.com/p/452848497
2、https://zhuanlan.zhihu.com/p/482772138