aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2013-04-02 08:31:52 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-07 16:58:13 -0400
commit9dcc71e1fdbb7aa10d92a3d35e8a201adc84abd0 (patch)
tree1c91b81cc0bc359ffd87a896227395c3acee833d
parentc4637cdf4839938a1c87d8da8f55055d6e9ec206 (diff)
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>
-rw-r--r--drivers/net/vxlan.c59
1 files changed, 43 insertions, 16 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 62a4438c6084..9a6471593ca3 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -912,6 +912,36 @@ static int handle_offloads(struct sk_buff *skb)
912 return 0; 912 return 0;
913} 913}
914 914
915/* Bypass encapsulation if the destination is local */
916static 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
915static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, 945static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
916 struct vxlan_rdst *rdst, bool did_rsc) 946 struct vxlan_rdst *rdst, bool did_rsc)
917{ 947{
@@ -922,7 +952,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
922 struct vxlanhdr *vxh; 952 struct vxlanhdr *vxh;
923 struct udphdr *uh; 953 struct udphdr *uh;
924 struct flowi4 fl4; 954 struct flowi4 fl4;
925 unsigned int pkt_len = skb->len;
926 __be32 dst; 955 __be32 dst;
927 __u16 src_port, dst_port; 956 __u16 src_port, dst_port;
928 u32 vni; 957 u32 vni;
@@ -935,22 +964,8 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
935 964
936 if (!dst) { 965 if (!dst) {
937 if (did_rsc) { 966 if (did_rsc) {
938 __skb_pull(skb, skb_network_offset(skb));
939 skb->ip_summed = CHECKSUM_NONE;
940 skb->pkt_type = PACKET_HOST;
941
942 /* short-circuited back to local bridge */ 967 /* short-circuited back to local bridge */
943 if (netif_rx(skb) == NET_RX_SUCCESS) { 968 vxlan_encap_bypass(skb, vxlan, vxlan);
944 struct pcpu_tstats *stats = this_cpu_ptr(dev->tstats);
945
946 u64_stats_update_begin(&stats->syncp);
947 stats->tx_packets++;
948 stats->tx_bytes += pkt_len;
949 u64_stats_update_end(&stats->syncp);
950 } else {
951 dev->stats.tx_errors++;
952 dev->stats.tx_aborted_errors++;
953 }
954 return NETDEV_TX_OK; 969 return NETDEV_TX_OK;
955 } 970 }
956 goto drop; 971 goto drop;
@@ -997,6 +1012,18 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
997 goto tx_error; 1012 goto tx_error;
998 } 1013 }
999 1014
1015 /* Bypass encapsulation if the destination is local */
1016 if (rt->rt_flags & RTCF_LOCAL) {
1017 struct vxlan_dev *dst_vxlan;
1018
1019 ip_rt_put(rt);
1020 dst_vxlan = vxlan_find_vni(dev_net(dev), vni);
1021 if (!dst_vxlan)
1022 goto tx_error;
1023 vxlan_encap_bypass(skb, vxlan, dst_vxlan);
1024 return NETDEV_TX_OK;
1025 }
1026
1000 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 1027 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1001 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | 1028 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
1002 IPSKB_REROUTED); 1029 IPSKB_REROUTED);