4.1.12内核已经支持vxlan报文的gro功能,意味着vxlan报文交给协议栈之前,已经被聚合过了,而在早期的内核中聚合逻辑是在encap_rcv函数之后实现的。
之前分析的UDP报文处理中,可以知道如果udp_sock定义了encap_rcv函数,将会把报文交给该函数处理,而不是传统的保存到sock队列,唤醒进程收包。
udp_sock定义的encap_rcv函数是在vxlan_socket_create函数中设置的,实际是vxlan_udp_encap_recv函数。
vxlan_udp_encap_recv函数
/* Callback from net/ipv4/udp.c to receive packets */
static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct vxlan_sock *vs;
struct vxlanhdr *vxh;
u32 flags, vni;
struct vxlan_metadata md = {0};
/* Need Vxlan and inner Ethernet header to be present */
if (!pskb_may_pull(skb, VXLAN_HLEN)) //报文长度检测
goto error;
vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); //得到vxlan头指针,和UDP头长度相同,所以可以这么操作
flags = ntohl(vxh->vx_flags);
vni = ntohl(vxh->vx_vni);
if (flags & VXLAN_HF_VNI) { //发送的vxlan报文,该flag必须置1
flags &= ~VXLAN_HF_VNI;
} else {
/* VNI flag always required to be set */
goto bad_flags;
}
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) //报文移动到内层报文
goto drop;
vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
vs = rcu_de