diff options
| author | Sridhar Samudrala <sri@us.ibm.com> | 2013-04-02 12:31:52 +0000 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-04-07 16:58:13 -0400 | 
| commit | 9dcc71e1fdbb7aa10d92a3d35e8a201adc84abd0 (patch) | |
| tree | 1c91b81cc0bc359ffd87a896227395c3acee833d | |
| parent | c4637cdf4839938a1c87d8da8f55055d6e9ec206 (diff) | |
| download | olio-linux-3.10-9dcc71e1fdbb7aa10d92a3d35e8a201adc84abd0.tar.xz olio-linux-3.10-9dcc71e1fdbb7aa10d92a3d35e8a201adc84abd0.zip | |
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 62a4438c608..9a6471593ca 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -912,6 +912,36 @@ static int handle_offloads(struct sk_buff *skb)  	return 0;  } +/* Bypass encapsulation if the destination is local */ +static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, +			       struct vxlan_dev *dst_vxlan) +{ +	struct pcpu_tstats *tx_stats = this_cpu_ptr(src_vxlan->dev->tstats); +	struct pcpu_tstats *rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats); + +	skb->pkt_type = PACKET_HOST; +	skb->encapsulation = 0; +	skb->dev = dst_vxlan->dev; +	__skb_pull(skb, skb_network_offset(skb)); + +	if (dst_vxlan->flags & VXLAN_F_LEARN) +		vxlan_snoop(skb->dev, INADDR_LOOPBACK, eth_hdr(skb)->h_source); + +	u64_stats_update_begin(&tx_stats->syncp); +	tx_stats->tx_packets++; +	tx_stats->tx_bytes += skb->len; +	u64_stats_update_end(&tx_stats->syncp); + +	if (netif_rx(skb) == NET_RX_SUCCESS) { +		u64_stats_update_begin(&rx_stats->syncp); +		rx_stats->rx_packets++; +		rx_stats->rx_bytes += skb->len; +		u64_stats_update_end(&rx_stats->syncp); +	} else { +		skb->dev->stats.rx_dropped++; +	} +} +  static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  				  struct vxlan_rdst *rdst, bool did_rsc)  { @@ -922,7 +952,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  	struct vxlanhdr *vxh;  	struct udphdr *uh;  	struct flowi4 fl4; -	unsigned int pkt_len = skb->len;  	__be32 dst;  	__u16 src_port, dst_port;          u32 vni; @@ -935,22 +964,8 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  	if (!dst) {  		if (did_rsc) { -			__skb_pull(skb, skb_network_offset(skb)); -			skb->ip_summed = CHECKSUM_NONE; -			skb->pkt_type = PACKET_HOST; -  			/* short-circuited back to local bridge */ -			if (netif_rx(skb) == NET_RX_SUCCESS) { -				struct pcpu_tstats *stats = this_cpu_ptr(dev->tstats); - -				u64_stats_update_begin(&stats->syncp); -				stats->tx_packets++; -				stats->tx_bytes += pkt_len; -				u64_stats_update_end(&stats->syncp); -			} else { -				dev->stats.tx_errors++; -				dev->stats.tx_aborted_errors++; -			} +			vxlan_encap_bypass(skb, vxlan, vxlan);  			return NETDEV_TX_OK;  		}  		goto drop; @@ -997,6 +1012,18 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		goto tx_error;  	} +	/* Bypass encapsulation if the destination is local */ +	if (rt->rt_flags & RTCF_LOCAL) { +		struct vxlan_dev *dst_vxlan; + +		ip_rt_put(rt); +		dst_vxlan = vxlan_find_vni(dev_net(dev), vni); +		if (!dst_vxlan) +			goto tx_error; +		vxlan_encap_bypass(skb, vxlan, dst_vxlan); +		return NETDEV_TX_OK; +	} +  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));  	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |  			      IPSKB_REROUTED); |