Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vxlan: Bypass encapsulation if the destination is local

This patch bypasses vxlan encapsulation if the destination vxlan
endpoint is a local device.

Changes since v1: added missing check for vxlan_find_vni() failure

Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Sridhar Samudrala and committed by
David S. Miller
9dcc71e1 c4637cdf

+43 -16
+43 -16
drivers/net/vxlan.c
··· 912 912 return 0; 913 913 } 914 914 915 + /* Bypass encapsulation if the destination is local */ 916 + static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, 917 + struct vxlan_dev *dst_vxlan) 918 + { 919 + struct pcpu_tstats *tx_stats = this_cpu_ptr(src_vxlan->dev->tstats); 920 + struct pcpu_tstats *rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats); 921 + 922 + skb->pkt_type = PACKET_HOST; 923 + skb->encapsulation = 0; 924 + skb->dev = dst_vxlan->dev; 925 + __skb_pull(skb, skb_network_offset(skb)); 926 + 927 + if (dst_vxlan->flags & VXLAN_F_LEARN) 928 + vxlan_snoop(skb->dev, INADDR_LOOPBACK, eth_hdr(skb)->h_source); 929 + 930 + u64_stats_update_begin(&tx_stats->syncp); 931 + tx_stats->tx_packets++; 932 + tx_stats->tx_bytes += skb->len; 933 + u64_stats_update_end(&tx_stats->syncp); 934 + 935 + if (netif_rx(skb) == NET_RX_SUCCESS) { 936 + u64_stats_update_begin(&rx_stats->syncp); 937 + rx_stats->rx_packets++; 938 + rx_stats->rx_bytes += skb->len; 939 + u64_stats_update_end(&rx_stats->syncp); 940 + } else { 941 + skb->dev->stats.rx_dropped++; 942 + } 943 + } 944 + 915 945 static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, 916 946 struct vxlan_rdst *rdst, bool did_rsc) 917 947 { ··· 952 922 struct vxlanhdr *vxh; 953 923 struct udphdr *uh; 954 924 struct flowi4 fl4; 955 - unsigned int pkt_len = skb->len; 956 925 __be32 dst; 957 926 __u16 src_port, dst_port; 958 927 u32 vni; ··· 964 935 965 936 if (!dst) { 966 937 if (did_rsc) { 967 - __skb_pull(skb, skb_network_offset(skb)); 968 - skb->ip_summed = CHECKSUM_NONE; 969 - skb->pkt_type = PACKET_HOST; 970 - 971 938 /* short-circuited back to local bridge */ 972 - if (netif_rx(skb) == NET_RX_SUCCESS) { 973 - struct pcpu_tstats *stats = this_cpu_ptr(dev->tstats); 974 - 975 - u64_stats_update_begin(&stats->syncp); 976 - stats->tx_packets++; 977 - stats->tx_bytes += pkt_len; 978 - u64_stats_update_end(&stats->syncp); 979 - } else { 980 - dev->stats.tx_errors++; 981 - dev->stats.tx_aborted_errors++; 982 - } 939 + vxlan_encap_bypass(skb, vxlan, vxlan); 983 940 return NETDEV_TX_OK; 984 941 } 985 942 goto drop; ··· 1010 995 ip_rt_put(rt); 1011 996 dev->stats.collisions++; 1012 997 goto tx_error; 998 + } 999 + 1000 + /* Bypass encapsulation if the destination is local */ 1001 + if (rt->rt_flags & RTCF_LOCAL) { 1002 + struct vxlan_dev *dst_vxlan; 1003 + 1004 + ip_rt_put(rt); 1005 + dst_vxlan = vxlan_find_vni(dev_net(dev), vni); 1006 + if (!dst_vxlan) 1007 + goto tx_error; 1008 + vxlan_encap_bypass(skb, vxlan, dst_vxlan); 1009 + return NETDEV_TX_OK; 1013 1010 } 1014 1011 1015 1012 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));