| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *              Random policy for multipath. | 
 | 3 |  * | 
 | 4 |  * | 
 | 5 |  * Version:	$Id: multipath_random.c,v 1.1.2.3 2004/09/21 08:42:11 elueck Exp $ | 
 | 6 |  * | 
 | 7 |  * Authors:	Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.de> | 
 | 8 |  * | 
 | 9 |  *		This program is free software; you can redistribute it and/or | 
 | 10 |  *		modify it under the terms of the GNU General Public License | 
 | 11 |  *		as published by the Free Software Foundation; either version | 
 | 12 |  *		2 of the License, or (at your option) any later version. | 
 | 13 |  */ | 
 | 14 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <asm/system.h> | 
 | 16 | #include <asm/uaccess.h> | 
 | 17 | #include <linux/types.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <linux/errno.h> | 
 | 19 | #include <linux/timer.h> | 
 | 20 | #include <linux/mm.h> | 
 | 21 | #include <linux/kernel.h> | 
 | 22 | #include <linux/fcntl.h> | 
 | 23 | #include <linux/stat.h> | 
 | 24 | #include <linux/socket.h> | 
 | 25 | #include <linux/in.h> | 
 | 26 | #include <linux/inet.h> | 
 | 27 | #include <linux/netdevice.h> | 
 | 28 | #include <linux/inetdevice.h> | 
 | 29 | #include <linux/igmp.h> | 
 | 30 | #include <linux/proc_fs.h> | 
 | 31 | #include <linux/seq_file.h> | 
| Randy Dunlap | 6efd845 | 2005-06-13 14:29:06 -0700 | [diff] [blame] | 32 | #include <linux/module.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | #include <linux/mroute.h> | 
 | 34 | #include <linux/init.h> | 
| Joe Perches | 4c3ae4d | 2007-02-22 01:26:32 -0800 | [diff] [blame] | 35 | #include <linux/random.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | #include <net/ip.h> | 
 | 37 | #include <net/protocol.h> | 
 | 38 | #include <linux/skbuff.h> | 
 | 39 | #include <net/sock.h> | 
 | 40 | #include <net/icmp.h> | 
 | 41 | #include <net/udp.h> | 
 | 42 | #include <net/raw.h> | 
 | 43 | #include <linux/notifier.h> | 
 | 44 | #include <linux/if_arp.h> | 
 | 45 | #include <linux/netfilter_ipv4.h> | 
 | 46 | #include <net/ipip.h> | 
 | 47 | #include <net/checksum.h> | 
 | 48 | #include <net/ip_mp_alg.h> | 
 | 49 |  | 
 | 50 | #define MULTIPATH_MAX_CANDIDATES 40 | 
 | 51 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | static void random_select_route(const struct flowi *flp, | 
 | 53 | 				struct rtable *first, | 
 | 54 | 				struct rtable **rp) | 
 | 55 | { | 
 | 56 | 	struct rtable *rt; | 
 | 57 | 	struct rtable *decision; | 
 | 58 | 	unsigned char candidate_count = 0; | 
 | 59 |  | 
 | 60 | 	/* count all candidate */ | 
 | 61 | 	for (rt = rcu_dereference(first); rt; | 
| Eric Dumazet | 5ef213f | 2007-02-10 16:57:03 -0800 | [diff] [blame] | 62 | 	     rt = rcu_dereference(rt->u.dst.rt_next)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | 		if ((rt->u.dst.flags & DST_BALANCED) != 0 && | 
 | 64 | 		    multipath_comparekeys(&rt->fl, flp)) | 
 | 65 | 			++candidate_count; | 
 | 66 | 	} | 
 | 67 |  | 
 | 68 | 	/* choose a random candidate */ | 
 | 69 | 	decision = first; | 
 | 70 | 	if (candidate_count > 1) { | 
 | 71 | 		unsigned char i = 0; | 
 | 72 | 		unsigned char candidate_no = (unsigned char) | 
| Joe Perches | 4c3ae4d | 2007-02-22 01:26:32 -0800 | [diff] [blame] | 73 | 			(random32() % candidate_count); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 |  | 
 | 75 | 		/* find chosen candidate and adjust GC data for all candidates | 
 | 76 | 		 * to ensure they stay in cache | 
 | 77 | 		 */ | 
| Eric Dumazet | 5ef213f | 2007-02-10 16:57:03 -0800 | [diff] [blame] | 78 | 		for (rt = first; rt; rt = rt->u.dst.rt_next) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 | 			if ((rt->u.dst.flags & DST_BALANCED) != 0 && | 
 | 80 | 			    multipath_comparekeys(&rt->fl, flp)) { | 
 | 81 | 				rt->u.dst.lastuse = jiffies; | 
 | 82 |  | 
 | 83 | 				if (i == candidate_no) | 
 | 84 | 					decision = rt; | 
 | 85 |  | 
 | 86 | 				if (i >= candidate_count) | 
 | 87 | 					break; | 
 | 88 |  | 
 | 89 | 				i++; | 
 | 90 | 			} | 
 | 91 | 		} | 
 | 92 | 	} | 
 | 93 |  | 
 | 94 | 	decision->u.dst.__use++; | 
 | 95 | 	*rp = decision; | 
 | 96 | } | 
 | 97 |  | 
 | 98 | static struct ip_mp_alg_ops random_ops = { | 
 | 99 | 	.mp_alg_select_route	=	random_select_route, | 
 | 100 | }; | 
 | 101 |  | 
 | 102 | static int __init random_init(void) | 
 | 103 | { | 
 | 104 | 	return multipath_alg_register(&random_ops, IP_MP_ALG_RANDOM); | 
 | 105 | } | 
 | 106 |  | 
 | 107 | static void __exit random_exit(void) | 
 | 108 | { | 
 | 109 | 	multipath_alg_unregister(&random_ops, IP_MP_ALG_RANDOM); | 
 | 110 | } | 
 | 111 |  | 
 | 112 | module_init(random_init); | 
 | 113 | module_exit(random_exit); | 
| Randy Dunlap | 6efd845 | 2005-06-13 14:29:06 -0700 | [diff] [blame] | 114 | MODULE_LICENSE("GPL"); |