datapath/linux/compat/vxlan.c
/* Callback from net/ipv4/udp.c to receive packets */
Callback from net/ipv4/udp.c to receive packets
Callback from net / ipv4 / udp . c to receive packets
static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
{
	union {
		struct metadata_dst dst;
		char buf[sizeof(struct metadata_dst) + sizeof(struct vxlan_metadata)];
	} buf;
	struct pcpu_sw_netstats *stats;
	struct vxlan_dev *vxlan;
	struct vxlan_sock *vs;
	struct vxlanhdr unparsed;
	struct vxlan_metadata _md;
	struct vxlan_metadata *md = &_md;
	__be16 protocol = htons(ETH_P_TEB);
	bool raw_proto = false;
	void *oiph;
	if (!pskb_may_pull(skb, VXLAN_HLEN))
		goto drop;
	unparsed = *vxlan_hdr(skb);
	if (!(unparsed.vx_flags & VXLAN_HF_VNI)) {
		netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
			   ntohl(vxlan_hdr(skb)->vx_flags),
			   ntohl(vxlan_hdr(skb)->vx_vni));
		goto drop;
	}
	unparsed.vx_flags &= ~VXLAN_HF_VNI;
	unparsed.vx_vni &= ~VXLAN_VNI_MASK;
	vs = rcu_dereference_sk_user_data(sk);
	if (!vs)
		goto drop;
#if IS_ENABLED(CONFIG_IPV6)
#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
	if (vxlan_get_sk_family(vs) == AF_INET6 &&
	    !udp_hdr(skb)->check &&
	    !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
		udp6_csum_zero_error(skb);
		goto drop;
	}
#endif
#endif
	vxlan = vxlan_vs_find_vni(vs, vxlan_vni(vxlan_hdr(skb)->vx_vni));
	if (!vxlan)
		goto drop;
	if (vs->flags & VXLAN_F_GPE) {
		if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags))
			goto drop;
		raw_proto = true;
	}
	if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
				   !net_eq(vxlan->net, dev_net(vxlan->dev))))
			goto drop;
	if (vxlan_collect_metadata(vs)) {
		__be32 vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
		struct metadata_dst *tun_dst;
		tun_dst = &buf.dst;
		ovs_udp_tun_rx_dst(tun_dst, skb,
				   vxlan_get_sk_family(vs), TUNNEL_KEY,
				   vxlan_vni_to_tun_id(vni), sizeof(*md));
		if (!tun_dst)
			goto drop;
		md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
		ovs_skb_dst_set(skb, (struct dst_entry *)tun_dst);
	} else {
		memset(md, 0, sizeof(*md));
	}
	if (vs->flags & VXLAN_F_REMCSUM_RX)
		if (!vxlan_remcsum(&unparsed, skb, vs->flags))
			goto drop;
	if (vs->flags & VXLAN_F_GBP)
		vxlan_parse_gbp_hdr(&unparsed, skb, vs->flags, md);
	if (unparsed.vx_flags || unparsed.vx_vni) {
		goto drop;
	}
	if (!raw_proto) {
		if (!vxlan_set_mac(vxlan, vs, skb))
			goto drop;
		skb_reset_mac_header(skb);
		skb->protocol = eth_type_trans(skb, vxlan->dev);
		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
	} else {
		skb_reset_mac_header(skb);
		skb->dev = vxlan->dev;
		skb->pkt_type = PACKET_HOST;
	}
	oiph = skb_network_header(skb);
	skb_reset_network_header(skb);
	if (!vxlan_ecn_decapsulate(vs, oiph, skb)) {
		++vxlan->dev->stats.rx_frame_errors;
		++vxlan->dev->stats.rx_errors;
		goto drop;
	}
	stats = this_cpu_ptr(vxlan->dev->tstats);
	u64_stats_update_begin(&stats->syncp);
	stats->rx_packets++;
	stats->rx_bytes += skb->len;
	u64_stats_update_end(&stats->syncp);
	netdev_port_receive(skb, skb_tunnel_info(skb));
	return 0;
drop:
	kfree_skb(skb);
	return 0;
}
static int vxlan_rcv ( struct sock * sk , struct sk_buff * skb ) { union { struct metadata_dst dst ; char buf [ sizeof ( struct metadata_dst ) + sizeof ( struct vxlan_metadata ) ] ; } buf ; struct pcpu_sw_netstats * stats ; struct vxlan_dev * vxlan ; struct vxlan_sock * vs ; struct vxlanhdr unparsed ; struct vxlan_metadata _md ; struct vxlan_metadata * md = & _md ; __be16 protocol = htons ( ETH_P_TEB ) ; bool raw_proto = false ; void * oiph ; if ( ! pskb_may_pull ( skb , VXLAN_HLEN ) ) goto drop ; unparsed = * vxlan_hdr ( skb ) ; if ( ! ( unparsed . vx_flags & VXLAN_HF_VNI ) ) { netdev_dbg ( skb -> dev , " \n " , ntohl ( vxlan_hdr ( skb ) -> vx_flags ) , ntohl ( vxlan_hdr ( skb ) -> vx_vni ) ) ; goto drop ; } unparsed . vx_flags &= ~ VXLAN_HF_VNI ; unparsed . vx_vni &= ~ VXLAN_VNI_MASK ; vs = rcu_dereference_sk_user_data ( sk ) ; if ( ! vs ) goto drop ; #if IS_ENABLED ( CONFIG_IPV6 ) #ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM if ( vxlan_get_sk_family ( vs ) == AF_INET6 && ! udp_hdr ( skb ) -> check && ! ( vs -> flags & VXLAN_F_UDP_ZERO_CSUM6_RX ) ) { udp6_csum_zero_error ( skb ) ; goto drop ; } #endif #endif vxlan = vxlan_vs_find_vni ( vs , vxlan_vni ( vxlan_hdr ( skb ) -> vx_vni ) ) ; if ( ! vxlan ) goto drop ; if ( vs -> flags & VXLAN_F_GPE ) { if ( ! vxlan_parse_gpe_hdr ( & unparsed , & protocol , skb , vs -> flags ) ) goto drop ; raw_proto = true ; } if ( __iptunnel_pull_header ( skb , VXLAN_HLEN , protocol , raw_proto , ! net_eq ( vxlan -> net , dev_net ( vxlan -> dev ) ) ) ) goto drop ; if ( vxlan_collect_metadata ( vs ) ) { __be32 vni = vxlan_vni ( vxlan_hdr ( skb ) -> vx_vni ) ; struct metadata_dst * tun_dst ; tun_dst = & buf . dst ; ovs_udp_tun_rx_dst ( tun_dst , skb , vxlan_get_sk_family ( vs ) , TUNNEL_KEY , vxlan_vni_to_tun_id ( vni ) , sizeof ( * md ) ) ; if ( ! tun_dst ) goto drop ; md = ip_tunnel_info_opts ( & tun_dst -> u . tun_info ) ; ovs_skb_dst_set ( skb , ( struct dst_entry * ) tun_dst ) ; } else { memset ( md , 0 , sizeof ( * md ) ) ; } if ( vs -> flags & VXLAN_F_REMCSUM_RX ) if ( ! vxlan_remcsum ( & unparsed , skb , vs -> flags ) ) goto drop ; if ( vs -> flags & VXLAN_F_GBP ) vxlan_parse_gbp_hdr ( & unparsed , skb , vs -> flags , md ) ; if ( unparsed . vx_flags || unparsed . vx_vni ) { goto drop ; } if ( ! raw_proto ) { if ( ! vxlan_set_mac ( vxlan , vs , skb ) ) goto drop ; skb_reset_mac_header ( skb ) ; skb -> protocol = eth_type_trans ( skb , vxlan -> dev ) ; skb_postpull_rcsum ( skb , eth_hdr ( skb ) , ETH_HLEN ) ; } else { skb_reset_mac_header ( skb ) ; skb -> dev = vxlan -> dev ; skb -> pkt_type = PACKET_HOST ; } oiph = skb_network_header ( skb ) ; skb_reset_network_header ( skb ) ; if ( ! vxlan_ecn_decapsulate ( vs , oiph , skb ) ) { ++ vxlan -> dev -> stats . rx_frame_errors ; ++ vxlan -> dev -> stats . rx_errors ; goto drop ; } stats = this_cpu_ptr ( vxlan -> dev -> tstats ) ; u64_stats_update_begin ( & stats -> syncp ) ; stats -> rx_packets ++ ; stats -> rx_bytes += skb -> len ; u64_stats_update_end ( & stats -> syncp ) ; netdev_port_receive ( skb , skb_tunnel_info ( skb ) ) ; return 0 ; drop : kfree_skb ( skb ) ; return 0 ; }
Callback from net/ipv4/udp.c to receive packets
Callback from net / ipv4 / udp . c to receive packets
/* Need UDP and VXLAN header to be present */ /* VNI flag always required to be set */ /* Return non vxlan pkt */ /* For backwards compatibility, only allow reserved fields to be
	 * used by VXLAN extensions if explicitly requested.
	 */ /* Note that GBP and GPE can never be active together. This is
	 * ensured in vxlan_dev_configure.
	 */ /* If there are any unprocessed flags remaining treat
		 * this as a malformed packet. This behavior diverges from
		 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
		 * in reserved fields are to be ignored. The approach here
		 * maintains compatibility with previous stack code, and also
		 * is more robust and provides a little more security in
		 * adding extensions to VXLAN.
		 */ /* Consume bad packet */