--- linux-2.4.30.orig/net/core/dev.c	2005-04-04 03:42:20.000000000 +0200
+++ linux-2.4.30/net/core/dev.c	2005-04-14 11:30:39.690121872 +0200
@@ -162,6 +162,252 @@
  *		86DD	IPv6
  */
 
+#define FAST_DEV_LOOKUP_CODE
+
+#ifdef FAST_DEV_LOOKUP_CODE
+/* Fash Device Lookup code. Should give much better than
+ * linear speed when looking for devices by idx or name.
+ * Increases maximum number of network devices.
+ * --Ben (greearb@candelatech.com)
+ * ported to 2.4.30  by Torge Szczepanek (adamantix@szczepanek.de)
+ */
+
+#define FDL_HASH_LEN 256
+
+#define FDL_DEBUG
+#undef FDL_DEBUG
+
+struct dev_hash_node {
+    struct net_device* dev;
+    struct dev_hash_node* next;
+};
+
+struct dev_hash_node* fdl_name_base[FDL_HASH_LEN];/* hashed by name */
+struct dev_hash_node* fdl_idx_base[FDL_HASH_LEN]; /* hashed by index */
+
+int fdl_initialized_yet = 0;
+
+/* TODO: Make these inline methods */
+/* Nice cheesy little hash method to be used on device-names (eth0, ppp0, etc) */
+int fdl_calc_name_idx(const char* dev_name) {
+    int tmp = 0;
+    int i;
+#ifdef FDL_DEBUG
+    printk(KERN_ERR "fdl_calc_name_idx, name: %s\n", dev_name);
+#endif
+    for (i = 0; dev_name[i]; i++) {
+	tmp += (int)(dev_name[i]);
+    }
+    if (i > 3) {
+	tmp += (dev_name[i-2] * 10); /* might add a little spread to the hash */
+	tmp += (dev_name[i-3] * 100); /* might add a little spread to the hash */
+    }
+#ifdef FDL_DEBUG
+    printk(KERN_ERR "fdl_calc_name_idx, rslt: %i\n", (int)(tmp % FDL_HASH_LEN));
+#endif
+    return (tmp % FDL_HASH_LEN);
+}
+
+int fdl_calc_index_idx(const int ifindex) {
+    return (ifindex % FDL_HASH_LEN);
+}
+
+/* Better have a lock on the dev_base before calling this... */
+int __fdl_ensure_init(void) {
+#ifdef FDL_DEBUG
+    printk(KERN_ERR "__fdl_ensure_init, enter\n");
+#endif
+    if (! fdl_initialized_yet) {
+	/* only do this once.. */
+	int i;
+	int idx = 0; /* into the hash table */
+	struct net_device* dev = dev_base;
+	struct dev_hash_node* dhn;
+	
+#ifdef FDL_DEBUG
+	printk(KERN_ERR "__fdl_ensure_init, doing real work...");
+#endif
+	
+	fdl_initialized_yet = 1; /* it has been attempted at least... */
+	
+	for (i = 0; i<FDL_HASH_LEN; i++) {
+	    fdl_name_base[i] = NULL;
+ fdl_idx_base[i] = NULL;
+	}
+	
+	/* add any current devices to the hash tables at this time. Note that
+	 * this method must be called with locks on the dev_base acquired.
+ */
+	while (dev) {
+	    
+#ifdef FDL_DEBUG
+	    printk(KERN_ERR "__fdl_ensure_init, dev: %p dev: %s, idx: %i\n", dev, dev->name, idx);
+#endif
+	    /* first, take care of the hash-by-name */
+	    idx = fdl_calc_name_idx(dev->name);
+	    dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC);
+	    if (dhn) {
+		dhn->dev = dev;
+		dhn->next = fdl_name_base[idx];
+		fdl_name_base[idx] = dhn;
+	    }
+	    else {
+		/* Nasty..couldn't get memory... */
+		return -ENOMEM;
+	    }
+	    idx = fdl_calc_index_idx(dev->ifindex);
+	    dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC);
+	    if (dhn) {
+		dhn->dev = dev;
+		dhn->next = fdl_idx_base[idx];
+		fdl_idx_base[idx] = dhn;
+	    }
+	    else {
+		/* Nasty..couldn't get memory... */
+		return -ENOMEM;
+	    }
+	    
+	    dev = dev->next;
+	}
+	fdl_initialized_yet = 2; /* initialization actually worked */
+    }
+#ifdef FDL_DEBUG
+    printk(KERN_ERR "__fdl_ensure_init, end, fdl_initialized_yet: %i\n", fdl_initialized_yet);
+#endif
+    if (fdl_initialized_yet == 2) {
+	return 0;
+    }
+    else {
+	return -1;
+    }
+}/* fdl_ensure_init */
+
+
+/* called from register_netdevice, assumes dev is locked, and that no one
+ * will be calling __find_dev_by_name before this exits.. etc.
+ */
+int __fdl_register_netdevice(struct net_device* dev) {
+    if (__fdl_ensure_init() == 0) {
+	/* first, take care of the hash-by-name */
+	int idx = fdl_calc_name_idx(dev->name);
+	struct dev_hash_node* dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC);
+	
+#ifdef FDL_DEBUG
+	printk(KERN_ERR "__fdl_register_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx);
+#endif
+	
+	if (dhn) {
+	    dhn->dev = dev;
+	    dhn->next = fdl_name_base[idx];
+	    fdl_name_base[idx] = dhn;
+	}
+	else {
+	    /* Nasty..couldn't get memory... */
+ /* Don't try to use these hash tables any more... */
+	    fdl_initialized_yet = 1; /* tried, but failed */
+	    return -ENOMEM;
+	}
+	
+	/* now, do the hash-by-idx */
+	idx = fdl_calc_index_idx(dev->ifindex);
+	dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC);
+	
+#ifdef FDL_DEBUG
+	printk(KERN_ERR "__fdl_register_netdevice, ifindex: %i, idx: %i", dev->ifindex, idx);
+#endif
+	
+	if (dhn) {
+	    dhn->dev = dev;
+	    dhn->next = fdl_idx_base[idx];
+	    fdl_idx_base[idx] = dhn;
+	}
+	else {
+	    /* Nasty..couldn't get memory... */
+	    /* Don't try to use these hash tables any more... */
+	    fdl_initialized_yet = 1; /* tried, but failed */
+	    return -ENOMEM;
+	}
+    }
+ return 0;
+} /* fdl_register_netdevice */
+
+
+/* called from register_netdevice, assumes dev is locked, and that no one
+ * will be calling __find_dev_by_name, etc. Returns 0 if found & removed one,
+ * returns -1 otherwise.
+ */
+int __fdl_unregister_netdevice(struct net_device* dev) {
+    int retval = -1;
+    if (fdl_initialized_yet == 2) { /* If we've been initialized correctly... */
+	/* first, take care of the hash-by-name */
+	int idx = fdl_calc_name_idx(dev->name);
+	struct dev_hash_node* prev = fdl_name_base[idx];
+	struct dev_hash_node* cur = NULL;
+	
+#ifdef FDL_DEBUG
+	printk(KERN_ERR "__fdl_unregister_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx);
+#endif
+	
+	if (prev) {
+	    if (strcmp(dev->name, prev->dev->name) == 0) {
+		/* it's the first one... */
+		fdl_name_base[idx] = prev->next;
+		kfree(prev);
+		retval = 0;
+	    }
+	    else {
+		cur = prev->next;
+		while (cur) {
+		    if (strcmp(dev->name, cur->dev->name) == 0) {
+			prev->next = cur->next;
+			kfree(cur);
+			retval = 0;
+			break;
+		    }
+		    else {
+			prev = cur;
+			cur = cur->next;
+		    }
+		}
+	    }
+	}
+	
+	/* Now, the hash-by-index */
+	idx = fdl_calc_index_idx(dev->ifindex);
+	prev = fdl_idx_base[idx];
+	cur = NULL;
+	if (prev) {
+	    if (dev->ifindex == prev->dev->ifindex) {
+		/* it's the first one... */
+		fdl_idx_base[idx] = prev->next;
+		kfree(prev);
+		retval = 0;
+	    }
+	    else {
+		cur = prev->next;
+		while (cur) {
+		    if (dev->ifindex == cur->dev->ifindex) {
+			prev->next = cur->next;
+			kfree(cur);
+			retval = 0;
+			break;
+		    }
+		    else {
+			prev = cur;
+			cur = cur->next;
+		    }
+		}
+	    }
+	}
+    }/* if we ensured init OK */
+    return retval;
+} /* fdl_unregister_netdevice */
+
+#endif /* FAST_DEV_LOOKUP_CODE */
+
+/* end patch */
+
+
 static struct packet_type *ptype_base[16];		/* 16 way hashed list */
 static struct packet_type *ptype_all = NULL;		/* Taps */
 
@@ -408,16 +654,35 @@
  *	careful with locks.
  */
  
-
 struct net_device *__dev_get_by_name(const char *name)
 {
-	struct net_device *dev;
-
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (strncmp(dev->name, name, IFNAMSIZ) == 0)
-			return dev;
+    struct net_device *dev;
+#ifdef FAST_DEV_LOOKUP_CODE
+    
+    int idx = fdl_calc_name_idx(name);
+    struct dev_hash_node* dhn;
+    if (fdl_initialized_yet == 2) {
+#ifdef FDL_DEBUG
+	printk(KERN_ERR "__dev_get_by_name, name: %s idx: %i\n", name, idx);
+#endif
+	dhn = fdl_name_base[idx];
+	while (dhn) {
+	    if (strcmp(dhn->dev->name, name) == 0) {
+		/* printk(KERN_ERR "__dev_get_by_name, found it: %p\n", dhn->dev); */
+		return dhn->dev;
+	    }
+	    dhn = dhn->next;
 	}
+	/* printk(KERN_ERR "__dev_get_by_name, didn't find it for name: %s\n", name); */
 	return NULL;
+    }
+#endif
+    
+    for (dev = dev_base; dev != NULL; dev = dev->next) {
+	if (strncmp(dev->name, name, IFNAMSIZ) == 0)
+	    return dev;
+    }
+    return NULL;
 }
 
 /**
@@ -465,12 +730,12 @@
  
 int dev_get(const char *name)
 {
-	struct net_device *dev;
-
-	read_lock(&dev_base_lock);
-	dev = __dev_get_by_name(name);
-	read_unlock(&dev_base_lock);
-	return dev != NULL;
+    struct net_device *dev;
+    
+    read_lock(&dev_base_lock);
+    dev = __dev_get_by_name(name);
+    read_unlock(&dev_base_lock);
+    return dev != NULL;
 }
 
 /**
@@ -486,13 +751,26 @@
 
 struct net_device * __dev_get_by_index(int ifindex)
 {
-	struct net_device *dev;
-
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (dev->ifindex == ifindex)
-			return dev;
+    struct net_device *dev;
+#ifdef FAST_DEV_LOOKUP_CODE
+    int idx = fdl_calc_index_idx(ifindex);
+    struct dev_hash_node* dhn;
+    if (fdl_initialized_yet == 2) { /* have we gone through initialization before... */
+	dhn = fdl_idx_base[idx];
+	while (dhn) {
+	    if (dhn->dev->ifindex == ifindex)
+		return dhn->dev;
+	    dhn = dhn->next;
 	}
 	return NULL;
+    }
+#endif
+    
+    for (dev = dev_base; dev != NULL; dev = dev->next) {
+	if (dev->ifindex == ifindex)
+	    return dev;
+    }
+    return NULL;
 }
 
 
@@ -617,17 +895,14 @@
 	if (p && (p[1] != 'd' || strchr(p+2, '%')))
 		return -EINVAL;
 
-	/*
-	 * If you need over 100 please also fix the algorithm...
-	 */
-	for (i = 0; i < 100; i++) {
+	for (i = 0; i < 2048; i++) {
 		snprintf(buf,sizeof(buf),name,i);
 		if (__dev_get_by_name(buf) == NULL) {
 			strcpy(dev->name, buf);
 			return i;
 		}
 	}
-	return -ENFILE;	/* Over 100 of the things .. bail out! */
+	return -ENFILE;	/* Over 2048 of the things .. bail out! */
 }
 
 /**
@@ -790,7 +1065,7 @@
 
 static void dev_do_clear_fastroute(struct net_device *dev)
 {
-	if (dev->accept_fastpath) {
+    if (dev->accept_fastpath) {
 		int i;
 
 		for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++) {
@@ -2197,8 +2472,17 @@
 			} else {
 				if (__dev_get_by_name(ifr->ifr_newname))
 					return -EEXIST;
+				#ifdef FAST_DEV_LOOKUP_CODE
+				write_lock_bh(&dev_base_lock); /* gotta lock it to remove stuff */
+				__fdl_unregister_netdevice(dev); /* remove it from the hash.. */
+				#endif
+
 				memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
 				dev->name[IFNAMSIZ-1] = 0;
+				#ifdef FAST_DEV_LOOKUP_CODE
+				__fdl_register_netdevice(dev);
+				write_unlock_bh(&dev_base_lock); /* gotta lock it to add stuff too */
+				#endif
 			}
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
 			return 0;
@@ -2553,6 +2837,12 @@
 	dev->next = NULL;
 	dev_init_scheduler(dev);
 	write_lock_bh(&dev_base_lock);
+#ifdef FAST_DEV_LOOKUP_CODE
+ /* Must do this before dp is set to dev, or it could be added twice, once
+ * on initialization based on dev_base, and once again after that...
+ */
+ __fdl_register_netdevice(dev);
+#endif
 	*dp = dev;
 	dev_hold(dev);
 	dev->deadbeaf = 0;
@@ -2625,6 +2915,9 @@
 		if (d == dev) {
 			write_lock_bh(&dev_base_lock);
 			*dp = d->next;
+#ifdef FAST_DEV_LOOKUP_CODE
+ __fdl_unregister_netdevice(dev);
+#endif
 			write_unlock_bh(&dev_base_lock);
 			break;
 		}
