diff options
| author | Sridhar Samudrala <sri@us.ibm.com> | 2013-04-02 08:31:52 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-04-07 16:58:13 -0400 |
| commit | 9dcc71e1fdbb7aa10d92a3d35e8a201adc84abd0 (patch) | |
| tree | 1c91b81cc0bc359ffd87a896227395c3acee833d | |
| parent | c4637cdf4839938a1c87d8da8f55055d6e9ec206 (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.c | 59 |
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 */ | ||
| 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 | static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | 945 | static 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); |
