patch-1.3.42 linux/net/ipv4/ip_output.c

Next file: linux/net/ipv4/ip_sockglue.c
Previous file: linux/net/ipv4/ip_options.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.41/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
@@ -86,7 +86,7 @@
 	/*
 	 *	Put a MAC header on the packet
 	 */
-	ip_send(newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr);
+	ip_send(NULL,newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr);
 	/*
 	 *	Add the rest of the data space.	
 	 */
@@ -110,7 +110,7 @@
  *	Take an skb, and fill in the MAC header.
  */
 
-int ip_send(struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
+int ip_send(struct rtable * rt, struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
 {
 	int mac = 0;
 
@@ -123,6 +123,18 @@
 		 *  	(rebuild header will sort this out)
 		 */
 		skb_reserve(skb,(dev->hard_header_len+15)&~15);	/* 16 byte aligned IP headers are good */
+		if (rt && dev == rt->rt_dev && rt->rt_hh)
+		{
+			memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len);
+			if (rt->rt_hh->hh_uptodate)
+				return dev->hard_header_len;
+#if RT_CACHE_DEBUG >= 2
+			printk("ip_send: hh miss %08x via %08x\n", daddr, rt->rt_gateway);
+#endif
+			skb->arp = 0;
+			skb->raddr = daddr;
+			return -dev->hard_header_len;
+		}
 		mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len);
 		if (mac < 0)
 		{
@@ -134,7 +146,7 @@
 	return mac;
 }
 
-static int ip_send_room(struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
+static int ip_send_room(struct rtable * rt, struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
 {
 	int mac = 0;
 
@@ -143,6 +155,18 @@
 	if (dev->hard_header)
 	{
 		skb_reserve(skb,MAX_HEADER);
+		if (rt && dev == rt->rt_dev && rt->rt_hh)
+		{
+			memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len);
+			if (rt->rt_hh->hh_uptodate)
+				return dev->hard_header_len;
+#if RT_CACHE_DEBUG >= 2
+			printk("ip_send_room: hh miss %08x via %08x\n", daddr, rt->rt_gateway);
+#endif
+			skb->arp = 0;
+			skb->raddr = daddr;
+			return -dev->hard_header_len;
+		}
 		mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len);
 		if (mac < 0)
 		{
@@ -163,15 +187,16 @@
  * routing/ARP tables to select a device struct.
  */
 int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr,
-		struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
+		struct device **dev, int type, struct options *opt,
+		int len, int tos, int ttl, struct rtable ** rp)
 {
 	struct rtable *rt;
 	__u32 raddr;
 	int tmp;
-	__u32 src;
 	struct iphdr *iph;
 	__u32 final_daddr = daddr;
 
+
 	if (opt && opt->srr)
 		daddr = opt->faddr;
 
@@ -183,12 +208,22 @@
 	if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
 		*dev=dev_get(skb->sk->ip_mc_name);
 #endif
+	if (rp)
+	{
+		rt = ip_check_route(rp, daddr, skb->localroute);
+		/*
+		 * If rp != NULL rt_put following below should not
+		 * release route, so that...
+		 */
+		if (rt)
+			ATOMIC_INCR(&rt->rt_refcnt);
+	}
+	else
+		rt = ip_rt_route(daddr, skb->localroute);
+
+
 	if (*dev == NULL)
 	{
-		if(skb->localroute)
-			rt = ip_rt_local(daddr, NULL, &src);
-		else
-			rt = ip_rt_route(daddr, NULL, &src);
 		if (rt == NULL)
 		{
 			ip_statistics.IpOutNoRoutes++;
@@ -196,43 +231,24 @@
 		}
 
 		*dev = rt->rt_dev;
-		/*
-		 *	If the frame is from us and going off machine it MUST MUST MUST
-		 *	have the output device ip address and never the loopback
-		 */
-		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
-			saddr = src;/*rt->rt_dev->pa_addr;*/
-		raddr = rt->rt_gateway;
-
 	}
-	else
-	{
-		/*
-		 *	We still need the address of the first hop.
-		 */
-		if(skb->localroute)
-			rt = ip_rt_local(daddr, NULL, &src);
-		else
-			rt = ip_rt_route(daddr, NULL, &src);
-		/*
-		 *	If the frame is from us and going off machine it MUST MUST MUST
-		 *	have the output device ip address and never the loopback
-		 */
-		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
-			saddr = src;/*rt->rt_dev->pa_addr;*/
 
-		raddr = (rt == NULL) ? 0 : rt->rt_gateway;
-	}
+	if ((LOOPBACK(saddr) && !LOOPBACK(daddr)) || !saddr)
+		saddr = rt ? rt->rt_src : (*dev)->pa_addr;
 
-	/*
-	 *	No source addr so make it our addr
-	 */
-	if (saddr == 0)
-		saddr = src;
+	raddr = rt ? rt->rt_gateway : 0;
+
+	if (opt && opt->is_strictroute && rt && (rt->rt_flags & RTF_GATEWAY))
+	{
+		ip_rt_put(rt);
+		ip_statistics.IpOutNoRoutes++;
+		return -ENETUNREACH;
+	}
 
 	/*
 	 *	No gateway so aim at the real destination
 	 */
+
 	if (raddr == 0)
 		raddr = daddr;
 
@@ -240,10 +256,12 @@
 	 *	Now build the MAC header.
 	 */
 
-	if(type==IPPROTO_TCP)
-		tmp = ip_send_room(skb, raddr, len, *dev, saddr);
+	if (type==IPPROTO_TCP)
+		tmp = ip_send_room(rt, skb, raddr, len, *dev, saddr);
 	else
-		tmp = ip_send(skb, raddr, len, *dev, saddr);
+		tmp = ip_send(rt, skb, raddr, len, *dev, saddr);
+
+	ip_rt_put(rt);
 
 	/*
 	 *	Book keeping
@@ -285,11 +303,6 @@
 
 	if (!opt || !opt->optlen)
 		return sizeof(struct iphdr) + tmp;
-	if (opt->is_strictroute && rt && rt->rt_gateway) 
-	{
-		ip_statistics.IpOutNoRoutes++;
-		return -ENETUNREACH;
-	}
 	iph->ihl += opt->optlen>>2;
 	ip_options_build(skb, opt, final_daddr, (*dev)->pa_addr, 0);
 	return iph->ihl*4 + tmp;
@@ -563,8 +576,9 @@
 	__u32 saddr;
 	unsigned short id;
 	struct iphdr *iph;
-	int local=0;
-	struct device *dev;
+	__u32 raddr;
+	struct device *dev = NULL;
+	struct hh_cache * hh=NULL;
 	int nfrags=0;
 	__u32 true_daddr = daddr;
 
@@ -588,60 +602,17 @@
 	else
 	{
 #endif	
-		/*
-		 *	Perform the IP routing decisions
-		 */
-	 
-		if(sk->localroute || flags&MSG_DONTROUTE)
-			local=1;
-	
-		rt = sk->ip_route_cache;
-		
-		/*
-		 *	See if the routing cache is outdated. We need to clean this up once we are happy it is reliable
-		 *	by doing the invalidation actively in the route change and header change.
-		 */
-	
-		saddr=sk->ip_route_saddr;	 
-		if(!rt || sk->ip_route_stamp != rt_stamp ||
-		   daddr!=sk->ip_route_daddr || sk->ip_route_local!=local ||
-		   (sk->saddr && sk->saddr != saddr))
-		{
-			if(local)
-				rt = ip_rt_local(daddr, NULL, &saddr);
-			else
-				rt = ip_rt_route(daddr, NULL, &saddr);
-			sk->ip_route_local=local;
-			sk->ip_route_daddr=daddr;
-			sk->ip_route_saddr=saddr;
-			sk->ip_route_stamp=rt_stamp;
-			sk->ip_route_cache=rt;
-			sk->ip_hcache_ver=NULL;
-			sk->ip_hcache_state= 0;
-		}
-		else if(rt)
-		{
-			/*
-			 *	Attempt header caches only if the cached route is being reused. Header cache
-			 *	is not ultra cheap to set up. This means we only set it up on the second packet,
-			 *	so one shot communications are not slowed. We assume (seems reasonable) that 2 is
-			 *	probably going to be a stream of data.
-			 */
-			if(rt->rt_dev->header_cache && sk->ip_hcache_state!= -1)
-			{
-				if(sk->ip_hcache_ver==NULL || sk->ip_hcache_stamp!=*sk->ip_hcache_ver)
-					rt->rt_dev->header_cache(rt->rt_dev,sk,saddr,daddr);
-				else
-					/* Can't cache. Remember this */
-					sk->ip_hcache_state= -1;
-			}
-		}
-		
+		rt = ip_check_route(&sk->ip_route_cache, daddr,
+				    sk->localroute || (flags&MSG_DONTROUTE) ||
+				    (opt && opt->is_strictroute));
 		if (rt == NULL) 
 		{
-	 		ip_statistics.IpOutNoRoutes++;
+			ip_statistics.IpOutNoRoutes++;
 			return(-ENETUNREACH);
 		}
+		saddr = rt->rt_src;
+
+		hh = rt->rt_hh;
 	
 		if (sk->saddr && (!LOOPBACK(sk->saddr) || LOOPBACK(daddr)))
 			saddr = sk->saddr;
@@ -649,10 +620,13 @@
 		dev=rt->rt_dev;
 #ifdef CONFIG_IP_MULTICAST
 	}
+	if (rt && !dev)
+		dev = rt->rt_dev;
 #endif		
 	if (user_saddr)
 		saddr = user_saddr;
 
+	raddr = rt ? rt->rt_gateway : daddr;
 	/*
 	 *	Now compute the buffer space we require
 	 */ 
@@ -662,16 +636,10 @@
 	 *	choice RAW frames within 20 bytes of maximum size(rare) to the long path
 	 */
 
-	length += 20;
+	length += sizeof(struct iphdr);
 	if (!sk->ip_hdrincl && opt) 
-	{
 		length += opt->optlen;
-		if (opt->is_strictroute && rt && rt->rt_gateway) 
-		{
-			ip_statistics.IpOutNoRoutes++;
-			return -ENETUNREACH;
-		}
-	}
+
 	if(length <= dev->mtu && !MULTICAST(daddr) && daddr!=0xFFFFFFFF && daddr!=dev->pa_brdaddr)
 	{	
 		int error;
@@ -687,12 +655,19 @@
 		skb->sk=sk;
 		skb->arp=0;
 		skb->saddr=saddr;
-		skb->raddr=(rt&&rt->rt_gateway)?rt->rt_gateway:daddr;
+		skb->raddr = raddr;
 		skb_reserve(skb,(dev->hard_header_len+15)&~15);
-		if(sk->ip_hcache_state>0)
+		if (hh)
 		{
-			memcpy(skb_push(skb,dev->hard_header_len),sk->ip_hcache_data,dev->hard_header_len);
 			skb->arp=1;
+			memcpy(skb_push(skb,dev->hard_header_len),hh->hh_data,dev->hard_header_len);
+			if (!hh->hh_uptodate)
+			{
+				skb->arp = 0;
+#if RT_CACHE_DEBUG >= 2
+				printk("ip_build_xmit: hh miss %08x via %08x\n", rt->rt_dst, rt->rt_gateway);
+#endif				
+			}
 		}
 		else if(dev->hard_header)
 		{
@@ -747,7 +722,7 @@
 		}
 		return 0;
 	}
-	length-=20;
+	length -= sizeof(struct iphdr);
 	if (sk && !sk->ip_hdrincl && opt) 
 	{
 		length -= opt->optlen;
@@ -847,7 +822,7 @@
 		skb->sk = sk;
 		skb->arp = 0;
 		skb->saddr = saddr;
-		skb->raddr = (rt&&rt->rt_gateway) ? rt->rt_gateway : daddr;
+		skb->raddr = raddr;
 		skb_reserve(skb,(dev->hard_header_len+15)&~15);
 		data = skb_put(skb, fraglen-dev->hard_header_len);
 
@@ -858,10 +833,17 @@
 		 *	pointer to speed header cache builds for identical targets.
 		 */
 		 
-		if(sk->ip_hcache_state>0)
+		if (hh)
 		{
-			memcpy(skb_push(skb,dev->hard_header_len),sk->ip_hcache_data, dev->hard_header_len);
 			skb->arp=1;
+			memcpy(skb_push(skb,dev->hard_header_len),hh->hh_data,dev->hard_header_len);
+			if (!hh->hh_uptodate)
+			{
+				skb->arp = 0;
+#if RT_CACHE_DEBUG >= 2
+				printk("ip_build_xmit: hh miss %08x via %08x\n", rt->rt_dst, rt->rt_gateway);
+#endif				
+			}
 		}
 		else if (dev->hard_header)
 		{
@@ -958,15 +940,15 @@
 			if(sk==NULL || sk->ip_mc_loop)
 			{
 				if(skb->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI))
-					ip_loopback(rt?rt->rt_dev:dev,skb);
+					ip_loopback(dev,skb);
 				else 
 				{
-					struct ip_mc_list *imc=rt?rt->rt_dev->ip_mc_list:dev->ip_mc_list;
+					struct ip_mc_list *imc=dev->ip_mc_list;
 					while(imc!=NULL) 
 					{
 						if(imc->multiaddr==daddr) 
 						{
-							ip_loopback(rt?rt->rt_dev:dev,skb);
+							ip_loopback(dev,skb);
 							break;
 						}
 						imc=imc->next;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this