forked from mirrors/linux
		
	ip_tunnel: push generic protocol handling to ip_tunnel module.
Process skb tunnel header before sending packet to protocol handler. this allows code sharing between gre and ovs gre modules. Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0e6fbc5b6c
								
							
						
					
					
						commit
						3d7b46cd20
					
				
					 6 changed files with 54 additions and 27 deletions
				
			
		| 
						 | 
					@ -155,6 +155,7 @@ static inline void tunnel_ip_select_ident(struct sk_buff *skb,
 | 
				
			||||||
				  (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 | 
									  (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto);
 | 
				
			||||||
int iptunnel_xmit(struct net *net, struct rtable *rt,
 | 
					int iptunnel_xmit(struct net *net, struct rtable *rt,
 | 
				
			||||||
		  struct sk_buff *skb,
 | 
							  struct sk_buff *skb,
 | 
				
			||||||
		  __be32 src, __be32 dst, __u8 proto,
 | 
							  __be32 src, __be32 dst, __u8 proto,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -201,7 +201,8 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
					
 | 
				
			||||||
 | 
						return iptunnel_pull_header(skb, hdr_len, tpi->proto);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int gre_cisco_rcv(struct sk_buff *skb)
 | 
					static int gre_cisco_rcv(struct sk_buff *skb)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -408,13 +408,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
 | 
				
			||||||
	const struct iphdr *iph = ip_hdr(skb);
 | 
						const struct iphdr *iph = ip_hdr(skb);
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	secpath_reset(skb);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb->protocol = tpi->proto;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb->mac_header = skb->network_header;
 | 
					 | 
				
			||||||
	__pskb_pull(skb, tunnel->hlen);
 | 
					 | 
				
			||||||
	skb_postpull_rcsum(skb, skb_transport_header(skb), tunnel->hlen);
 | 
					 | 
				
			||||||
#ifdef CONFIG_NET_IPGRE_BROADCAST
 | 
					#ifdef CONFIG_NET_IPGRE_BROADCAST
 | 
				
			||||||
	if (ipv4_is_multicast(iph->daddr)) {
 | 
						if (ipv4_is_multicast(iph->daddr)) {
 | 
				
			||||||
		/* Looped back packet, drop it! */
 | 
							/* Looped back packet, drop it! */
 | 
				
			||||||
| 
						 | 
					@ -442,23 +435,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
 | 
				
			||||||
		tunnel->i_seqno = ntohl(tpi->seq) + 1;
 | 
							tunnel->i_seqno = ntohl(tpi->seq) + 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Warning: All skb pointers will be invalidated! */
 | 
					 | 
				
			||||||
	if (tunnel->dev->type == ARPHRD_ETHER) {
 | 
					 | 
				
			||||||
		if (!pskb_may_pull(skb, ETH_HLEN)) {
 | 
					 | 
				
			||||||
			tunnel->dev->stats.rx_length_errors++;
 | 
					 | 
				
			||||||
			tunnel->dev->stats.rx_errors++;
 | 
					 | 
				
			||||||
			goto drop;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		iph = ip_hdr(skb);
 | 
					 | 
				
			||||||
		skb->protocol = eth_type_trans(skb, tunnel->dev);
 | 
					 | 
				
			||||||
		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb->pkt_type = PACKET_HOST;
 | 
					 | 
				
			||||||
	__skb_tunnel_rx(skb, tunnel->dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb_reset_network_header(skb);
 | 
					 | 
				
			||||||
	err = IP_ECN_decapsulate(iph, skb);
 | 
						err = IP_ECN_decapsulate(iph, skb);
 | 
				
			||||||
	if (unlikely(err)) {
 | 
						if (unlikely(err)) {
 | 
				
			||||||
		if (log_ecn_error)
 | 
							if (log_ecn_error)
 | 
				
			||||||
| 
						 | 
					@ -477,6 +453,12 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
 | 
				
			||||||
	tstats->rx_bytes += skb->len;
 | 
						tstats->rx_bytes += skb->len;
 | 
				
			||||||
	u64_stats_update_end(&tstats->syncp);
 | 
						u64_stats_update_end(&tstats->syncp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tunnel->dev->type == ARPHRD_ETHER) {
 | 
				
			||||||
 | 
							skb->protocol = eth_type_trans(skb, tunnel->dev);
 | 
				
			||||||
 | 
							skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							skb->dev = tunnel->dev;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	gro_cells_receive(&tunnel->gro_cells, skb);
 | 
						gro_cells_receive(&tunnel->gro_cells, skb);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,3 +86,37 @@ int iptunnel_xmit(struct net *net, struct rtable *rt,
 | 
				
			||||||
	return pkt_len;
 | 
						return pkt_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(iptunnel_xmit);
 | 
					EXPORT_SYMBOL_GPL(iptunnel_xmit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (unlikely(!pskb_may_pull(skb, hdr_len)))
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb_pull_rcsum(skb, hdr_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (inner_proto == htons(ETH_P_TEB)) {
 | 
				
			||||||
 | 
							struct ethhdr *eh = (struct ethhdr *)skb->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (likely(ntohs(eh->h_proto) >= ETH_P_802_3_MIN))
 | 
				
			||||||
 | 
								skb->protocol = eh->h_proto;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								skb->protocol = htons(ETH_P_802_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							skb->protocol = inner_proto;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nf_reset(skb);
 | 
				
			||||||
 | 
						secpath_reset(skb);
 | 
				
			||||||
 | 
						if (!skb->l4_rxhash)
 | 
				
			||||||
 | 
							skb->rxhash = 0;
 | 
				
			||||||
 | 
						skb_dst_drop(skb);
 | 
				
			||||||
 | 
						skb->vlan_tci = 0;
 | 
				
			||||||
 | 
						skb_set_queue_mapping(skb, 0);
 | 
				
			||||||
 | 
						skb->pkt_type = PACKET_HOST;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(iptunnel_pull_header);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,8 +188,12 @@ static int ipip_rcv(struct sk_buff *skb)
 | 
				
			||||||
	struct net *net = dev_net(skb->dev);
 | 
						struct net *net = dev_net(skb->dev);
 | 
				
			||||||
	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
 | 
						struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
 | 
				
			||||||
	struct ip_tunnel *tunnel;
 | 
						struct ip_tunnel *tunnel;
 | 
				
			||||||
	const struct iphdr *iph = ip_hdr(skb);
 | 
						const struct iphdr *iph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (iptunnel_pull_header(skb, 0, tpi.proto))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
 | 
						tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
 | 
				
			||||||
			iph->saddr, iph->daddr, 0);
 | 
								iph->saddr, iph->daddr, 0);
 | 
				
			||||||
	if (tunnel) {
 | 
						if (tunnel) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -640,9 +640,14 @@ static const struct tnl_ptk_info tpi = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ipip_rcv(struct sk_buff *skb)
 | 
					static int ipip_rcv(struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct iphdr *iph = ip_hdr(skb);
 | 
						const struct iphdr *iph;
 | 
				
			||||||
	struct ip_tunnel *tunnel;
 | 
						struct ip_tunnel *tunnel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (iptunnel_pull_header(skb, 0, tpi.proto))
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
 | 
						tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
 | 
				
			||||||
				     iph->saddr, iph->daddr);
 | 
									     iph->saddr, iph->daddr);
 | 
				
			||||||
	if (tunnel != NULL) {
 | 
						if (tunnel != NULL) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue