第一部分 硬件识别包类型
网卡,是可以识别包类型的。在dpdk的API中。识别完之后,存在这个结构里:
struct rte_mbuf { ...... union { uint32_t packet_type; /**< L2/L3/L4 and tunnel information. */ struct { uint32_t l2_type:4; /**< (Outer) L2 type. */ uint32_t l3_type:4; /**< (Outer) L3 type. */ uint32_t l4_type:4; /**< (Outer) L4 type. */ uint32_t tun_type:4; /**< Tunnel type. */ uint32_t inner_l2_type:4; /**< Inner L2 type. */ uint32_t inner_l3_type:4; /**< Inner L3 type. */ uint32_t inner_l4_type:4; /**< Inner L4 type. */ }; }; ... ... }
这非常厉害,利用硬件能力;但是遗憾的是,有一些硬件并不能这么干,因为他们比较low,然后我们就需要软件实现。参考例子l3fwd,加一个回调替代硬件功能,提高兼容性:
static uint16_t callback(uint8_t port, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t max_pkts, void *user_param) { } void* cb_handler; cb_handler = rte_eth_add_rx_callback(port_id, i, callback, NULL); if (!cb_handler) { perror("rte_eth_add_rx_callback: "); return -1; }
所以,在实现这个函数之前,必须要了解硬件的行为模式。
第二部分 硬件的行为是啥样的
一个包来了之后,硬件会为 l2_type l3_type l4_type 赋值,值都是宏,见源码。如果是tunnel或者IP in IP等,也有相应的值变量可以付。但是我比较关系vlan。
而且发现,在 l2_type 定义的值之中,并没有VLAN存在。然后我构建了一组vlan包(见下一节)来实验,发现vlan包也能被正确识别到各层协议,那么它如何将这个一个
vlan包的信息传递出来呢?经过测试,发现用到了下面这个变量:
/** * The generic rte_mbuf, containing a packet mbuf. */ struct rte_mbuf { uint64_t ol_flags; /**< Offload features. */ }
如果是vlan包,会设置标记:
/** * RX packet is a 802.1q VLAN packet. This flag was set by PMDs when * the packet is recognized as a VLAN, but the behavior between PMDs * was not the same. This flag is kept for some time to avoid breaking * applications and should be replaced by PKT_RX_VLAN_STRIPPED. */ #define PKT_RX_VLAN_PKT (1ULL << 0)
至此,硬件行为基本清晰,已经基本满足我当前的需求,可以进行软件模拟了。
第三部分 构造一个VLAN包
做前文的实验中,为了验证硬件行为,需要自行构建vlan包。是这么干的。
1. 开一个虚拟机。单独建立一个网卡,与本地tap设备链接。
2. 在两端安装vconfig工具,并加载 8021q 内核模块,使用vconfig工具网卡增加一个虚拟的vlan网卡。
/home/tong/Data [[email protected]] [14:38] > pkgfile vconfig community/vlan /home/tong/Data [[email protected]] [14:38] > pacman -Ss vlan community/vlan 1.9-4 Virtual LAN configuration utility /home/tong/Data [[email protected]] [14:38] > sudo pacman -S vlan /home/tong/Data [[email protected]] [14:40] > modprobe 8021q /home/tong/Data [[email protected]] [14:48] > sudo vconfig add tap-dpdk-1 3 Added VLAN with VID == 3 to IF -:tap-dpdk-1:-
这时候能看见多了一个网卡
/home/tong/Data [[email protected]] [14:49] > ip link 21: tap-dpdk-1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UNKNOWN mode DEFAULT group default qlen 1000 link/ether d2:75:44:af:2b:20 brd ff:ff:ff:ff:ff:ff 25: tap-dpdk-1.3@tap-dpdk-1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether d2:75:44:af:2b:20 brd ff:ff:ff:ff:ff:ff
3. 在虚拟机里同样操作,设成同样的vlan id = 3 ,也是会有两个网卡 eth1 和 eth1.3
4. 在host主机上,给 tap-dpdk-1.3 发包。 在 guest 主机上,eth1和eth1.3上,都会看见发来的包,区别是,eth1.3看见的包已经去除了vlan,而eth1上的包是带着vlan的。
所以,抓eth1,就把带着vlan的pcap,抓出来了。。。。
5. 我真是太聪明了,我这都是跟谁学的。。。。。
第四部分 补充
测以上内容,用来两个网卡
0000:03:00.0 ‘82599EB 10-Gigabit SFI/SFP+ Network Connection‘ drv=igb_uio unused=ixgbe 0000:09:00.0 ‘82583V Gigabit Network Connection‘ drv=igb_uio unused=e1000e
不用说,82599EB 肯定是支持硬件offload的。82583v 不仅不支持offload,连多队列都不支持。。。。
另:82599EB 配成一个队列的时候,竟然无法收到全部的包,发了51个,只收到30个,另外20个一定是跑去了别的队列??? 咋回事捏???