patch-2.0.31 linux/net/ipv4/route.c

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

diff -u --recursive --new-file v2.0.30/linux/net/ipv4/route.c linux/net/ipv4/route.c
@@ -42,7 +42,11 @@
  *		Bjorn Ekwall	:	Kerneld route support.
  *		Alan Cox	:	Multicast fixed (I hope)
  * 		Pavel Krauz	:	Limited broadcast fixed
+ *              Elliot Poger    :       Added support for SO_BINDTODEVICE.
+ *		Andi Kleen	:	Don't send multicast addresses to
+ *					kerneld.	
  *
+ *	Juan Jose Ciarlante     :	Added ip_rt_dev 
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
@@ -127,9 +131,9 @@
  * Backlogging.
  */
 
-#define RT_BH_REDIRECT		0
-#define RT_BH_GARBAGE_COLLECT 	1
-#define RT_BH_FREE	 	2
+#define RT_BH_REDIRECT		1
+#define RT_BH_GARBAGE_COLLECT 	2
+#define RT_BH_FREE	 	4
 
 struct rt_req
 {
@@ -203,6 +207,7 @@
 			fi->fib_prev->fib_next = fi->fib_next;
 		if (fi == fib_info_list)
 			fib_info_list = fi->fib_next;
+		kfree_s(fi, sizeof(struct fib_info));
 	}
 	kfree_s(f, sizeof(struct fib_node));
 }
@@ -225,10 +230,9 @@
 		
 		for ( ; f; f = f->fib_next)
 		{
-			if ((dst ^ f->fib_dst) & fz->fz_mask)
+			if (((dst ^ f->fib_dst) & fz->fz_mask) ||
+			    (f->fib_info->fib_flags & RTF_GATEWAY))
 				continue;
-			if (f->fib_info->fib_flags & RTF_GATEWAY)
-				return NULL;
 			return f;
 		}
 	}
@@ -247,9 +251,11 @@
  *	  Host 193.233.7.129 is locally unreachable,
  *	  but old (<=1.3.37) code will send packets destined for it to eth1.
  *
+ * Calling routine can specify a particular interface by setting dev.  If dev==NULL,
+ * any interface will do.
  */
 
-static struct fib_node * fib_lookup_local(__u32 dst)
+static struct fib_node * fib_lookup_local(__u32 dst, struct device *dev)
 {
 	struct fib_zone * fz;
 	struct fib_node * f;
@@ -267,6 +273,8 @@
 		{
 			if ((dst ^ f->fib_dst) & fz->fz_mask)
 				continue;
+			if ( (dev != NULL) && (dev != f->fib_info->fib_dev) )
+				continue;
 			if (!(f->fib_info->fib_flags & RTF_GATEWAY))
 				return f;
 			longest_match_found = 1;
@@ -289,7 +297,7 @@
  *		route add -host 193.233.7.255 eth0
  */
 
-static struct fib_node * fib_lookup(__u32 dst)
+static struct fib_node * fib_lookup(__u32 dst, struct device *dev)
 {
 	struct fib_zone * fz;
 	struct fib_node * f;
@@ -305,6 +313,8 @@
 		{
 			if ((dst ^ f->fib_dst) & fz->fz_mask)
 				continue;
+			if ( (dev != NULL) && (dev != f->fib_info->fib_dev) )
+				continue;
 			return f;
 		}
 	}
@@ -915,6 +925,8 @@
 {
 	struct rtable *rt, **rtp;
 
+	ip_rt_bh_mask &= ~RT_BH_FREE;
+
 	rtp = &rt_free_queue;
 
 	while ((rt = *rtp) != NULL)
@@ -1254,7 +1266,7 @@
 	struct rt_req * rtr;
 	struct rtable * rt;
 
-	rt = ip_rt_route(dst, 0);
+	rt = ip_rt_route(dst, 0, NULL);
 	if (!rt)
 		return;
 
@@ -1323,7 +1335,7 @@
 		if (rth->rt_gateway != daddr)
 		{
 			ip_rt_fast_unlock();
-			rtg = ip_rt_route(rth->rt_gateway, 0);
+			rtg = ip_rt_route(rth->rt_gateway, 0, NULL);
 			ip_rt_fast_lock();
 		}
 
@@ -1395,7 +1407,7 @@
    
  */
 
-struct rtable * ip_rt_slow_route (__u32 daddr, int local)
+struct rtable * ip_rt_slow_route (__u32 daddr, int local, struct device *dev)
 {
 	unsigned hash = ip_rt_hash_code(daddr)^local;
 	struct rtable * rth;
@@ -1415,9 +1427,9 @@
 	}
 
 	if (local)
-		f = fib_lookup_local(daddr);
+		f = fib_lookup_local(daddr, dev);
 	else
-		f = fib_lookup (daddr);
+		f = fib_lookup (daddr, dev);
 
 	if (f)
 	{
@@ -1436,6 +1448,8 @@
 		ip_rt_unlock();
 		kfree_s(rth, sizeof(struct rtable));
 #ifdef CONFIG_KERNELD		
+		if (MULTICAST(daddr)) 
+			return NULL; 
 		daddr=ntohl(daddr);
 		sprintf(wanted_route, "%d.%d.%d.%d",
 			(int)(daddr >> 24) & 0xff, (int)(daddr >> 16) & 0xff,
@@ -1490,7 +1504,15 @@
 		rth->rt_gateway = rth->rt_dst;
 
 	if (ip_rt_lock == 1)
-		rt_cache_add(hash, rth);
+	{
+		/* Don't add this to the rt_cache if a device was specified,
+		 * because we might have skipped better routes which didn't
+		 * point at the right device. */
+		if (dev != NULL)
+			rth->rt_flags |= RTF_NOTCACHED;
+		else
+			rt_cache_add(hash, rth);
+	}
 	else
 	{
 		rt_free(rth);
@@ -1507,9 +1529,28 @@
 {
 	if (rt)
 		atomic_dec(&rt->rt_refcnt);
+	
+	/* If this rtable entry is not in the cache, we'd better free it once the
+	 * refcnt goes to zero, because nobody else will... */
+	if ( rt && (rt->rt_flags & RTF_NOTCACHED) && (!rt->rt_refcnt) )
+		rt_free(rt);
+}
+
+/*
+ *	Return routing dev for given address.
+ *	Called by ip_alias module to avoid using ip_rt_route and
+ *	generating hhs.
+ */
+struct device * ip_rt_dev(__u32 addr)
+{
+	struct fib_node *f;
+	f = fib_lookup(addr, NULL);
+	if (f) 
+		return f->fib_info->fib_dev;
+	return NULL;
 }
 
-struct rtable * ip_rt_route(__u32 daddr, int local)
+struct rtable * ip_rt_route(__u32 daddr, int local, struct device *dev)
 {
 	struct rtable * rth;
 
@@ -1517,7 +1558,8 @@
 
 	for (rth=ip_rt_hash_table[ip_rt_hash_code(daddr)^local]; rth; rth=rth->rt_next)
 	{
-		if (rth->rt_dst == daddr)
+		/* If a network device is specified, make sure this route points to it. */
+		if ( (rth->rt_dst == daddr) && ((dev==NULL) || (dev==rth->rt_dev)) )
 		{
 			rth->rt_lastuse = jiffies;
 			atomic_inc(&rth->rt_use);
@@ -1526,7 +1568,7 @@
 			return rth;
 		}
 	}
-	return ip_rt_slow_route (daddr, local);
+	return ip_rt_slow_route (daddr, local, dev);
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov