⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 route.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		ROUTE - implementation of the IP router. * * Version:	$Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $ * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Alan Cox, <gw4pts@gw4pts.ampr.org> *		Linus Torvalds, <Linus.Torvalds@helsinki.fi> *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * Fixes: *		Alan Cox	:	Verify area fixes. *		Alan Cox	:	cli() protects routing changes *		Rui Oliveira	:	ICMP routing table updates *		(rco@di.uminho.pt)	Routing table insertion and update *		Linus Torvalds	:	Rewrote bits to be sensible *		Alan Cox	:	Added BSD route gw semantics *		Alan Cox	:	Super /proc >4K  *		Alan Cox	:	MTU in route table *		Alan Cox	: 	MSS actually. Also added the window *					clamper. *		Sam Lantinga	:	Fixed route matching in rt_del() *		Alan Cox	:	Routing cache support. *		Alan Cox	:	Removed compatibility cruft. *		Alan Cox	:	RTF_REJECT support. *		Alan Cox	:	TCP irtt support. *		Jonathan Naylor	:	Added Metric support. *	Miquel van Smoorenburg	:	BSD API fixes. *	Miquel van Smoorenburg	:	Metrics. *		Alan Cox	:	Use __u32 properly *		Alan Cox	:	Aligned routing errors more closely with BSD *					our system is still very different. *		Alan Cox	:	Faster /proc handling *	Alexey Kuznetsov	:	Massive rework to support tree based routing, *					routing caches and better behaviour. *		 *		Olaf Erb	:	irtt wasn't being copied right. *		Bjorn Ekwall	:	Kerneld route support. *		Alan Cox	:	Multicast fixed (I hope) * 		Pavel Krauz	:	Limited broadcast fixed *		Mike McLagan	:	Routing by source *	Alexey Kuznetsov	:	End of old history. Split to fib.c and *					route.c and rewritten from scratch. *		Andi Kleen	:	Load-limit warning messages. *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma. *	Vitaly E. Lavrov	:	Race condition in ip_route_input_slow. *	Tobias Ringstrom	:	Uninitialized res.type in ip_route_output_slow. *	Vladimir V. Ivanov	:	IP rule info (flowid) is really useful. *		Marc Boucher	:	routing by fwmark *	Robert Olsson		:	Added rt_cache statistics *	Arnaldo C. Melo		:	Convert proc stuff to seq_file * *		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 *		2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/module.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/inetdevice.h>#include <linux/igmp.h>#include <linux/pkt_sched.h>#include <linux/mroute.h>#include <linux/netfilter_ipv4.h>#include <linux/random.h>#include <linux/jhash.h>#include <linux/rcupdate.h>#include <linux/times.h>#include <net/protocol.h>#include <net/ip.h>#include <net/route.h>#include <net/inetpeer.h>#include <net/sock.h>#include <net/ip_fib.h>#include <net/arp.h>#include <net/tcp.h>#include <net/icmp.h>#include <net/xfrm.h>#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>#endif#define IP_MAX_MTU	0xFFF0#define RT_GC_TIMEOUT (300*HZ)int ip_rt_min_delay		= 2 * HZ;int ip_rt_max_delay		= 10 * HZ;int ip_rt_max_size;int ip_rt_gc_timeout		= RT_GC_TIMEOUT;int ip_rt_gc_interval		= 60 * HZ;int ip_rt_gc_min_interval	= HZ / 2;int ip_rt_redirect_number	= 9;int ip_rt_redirect_load		= HZ / 50;int ip_rt_redirect_silence	= ((HZ / 50) << (9 + 1));int ip_rt_error_cost		= HZ;int ip_rt_error_burst		= 5 * HZ;int ip_rt_gc_elasticity		= 8;int ip_rt_mtu_expires		= 10 * 60 * HZ;int ip_rt_min_pmtu		= 512 + 20 + 20;int ip_rt_min_advmss		= 256;int ip_rt_secret_interval	= 10 * 60 * HZ;static unsigned long rt_deadline;#define RTprint(a...)	printk(KERN_DEBUG a)static struct timer_list rt_flush_timer;static struct timer_list rt_periodic_timer;static struct timer_list rt_secret_timer;/* *	Interface to generic destination cache. */static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie);static void		 ipv4_dst_destroy(struct dst_entry *dst);static void		 ipv4_dst_ifdown(struct dst_entry *dst, int how);static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);static void		 ipv4_link_failure(struct sk_buff *skb);static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);static int rt_garbage_collect(void);static struct dst_ops ipv4_dst_ops = {	.family =		AF_INET,	.protocol =		__constant_htons(ETH_P_IP),	.gc =			rt_garbage_collect,	.check =		ipv4_dst_check,	.destroy =		ipv4_dst_destroy,	.ifdown =		ipv4_dst_ifdown,	.negative_advice =	ipv4_negative_advice,	.link_failure =		ipv4_link_failure,	.update_pmtu =		ip_rt_update_pmtu,	.entry_size =		sizeof(struct rtable),};#define ECN_OR_COST(class)	TC_PRIO_##class__u8 ip_tos2prio[16] = {	TC_PRIO_BESTEFFORT,	ECN_OR_COST(FILLER),	TC_PRIO_BESTEFFORT,	ECN_OR_COST(BESTEFFORT),	TC_PRIO_BULK,	ECN_OR_COST(BULK),	TC_PRIO_BULK,	ECN_OR_COST(BULK),	TC_PRIO_INTERACTIVE,	ECN_OR_COST(INTERACTIVE),	TC_PRIO_INTERACTIVE,	ECN_OR_COST(INTERACTIVE),	TC_PRIO_INTERACTIVE_BULK,	ECN_OR_COST(INTERACTIVE_BULK),	TC_PRIO_INTERACTIVE_BULK,	ECN_OR_COST(INTERACTIVE_BULK)};/* * Route cache. *//* The locking scheme is rather straight forward: * * 1) Read-Copy Update protects the buckets of the central route hash. * 2) Only writers remove entries, and they hold the lock *    as they look at rtable reference counts. * 3) Only readers acquire references to rtable entries, *    they do so with atomic increments and with the *    lock held. */struct rt_hash_bucket {	struct rtable	*chain;	spinlock_t	lock;} __attribute__((__aligned__(8)));static struct rt_hash_bucket 	*rt_hash_table;static unsigned			rt_hash_mask;static int			rt_hash_log;static unsigned int		rt_hash_rnd;struct rt_cache_stat *rt_cache_stat;static int rt_intern_hash(unsigned hash, struct rtable *rth,				struct rtable **res);static unsigned int rt_hash_code(u32 daddr, u32 saddr, u8 tos){	return (jhash_3words(daddr, saddr, (u32) tos, rt_hash_rnd)		& rt_hash_mask);}#ifdef CONFIG_PROC_FSstruct rt_cache_iter_state {	int bucket;};static struct rtable *rt_cache_get_first(struct seq_file *seq){	struct rtable *r = NULL;	struct rt_cache_iter_state *st = seq->private;	for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {		rcu_read_lock_bh();		r = rt_hash_table[st->bucket].chain;		if (r)			break;		rcu_read_unlock_bh();	}	return r;}static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r){	struct rt_cache_iter_state *st = rcu_dereference(seq->private);	r = r->u.rt_next;	while (!r) {		rcu_read_unlock_bh();		if (--st->bucket < 0)			break;		rcu_read_lock_bh();		r = rt_hash_table[st->bucket].chain;	}	return r;}static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos){	struct rtable *r = rt_cache_get_first(seq);	if (r)		while (pos && (r = rt_cache_get_next(seq, r)))			--pos;	return pos ? NULL : r;}static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos){	return *pos ? rt_cache_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct rtable *r = NULL;	if (v == SEQ_START_TOKEN)		r = rt_cache_get_first(seq);	else		r = rt_cache_get_next(seq, v);	++*pos;	return r;}static void rt_cache_seq_stop(struct seq_file *seq, void *v){	if (v && v != SEQ_START_TOKEN)		rcu_read_unlock_bh();}static int rt_cache_seq_show(struct seq_file *seq, void *v){	if (v == SEQ_START_TOKEN)		seq_printf(seq, "%-127s\n",			   "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\t"			   "Metric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\t"			   "HHUptod\tSpecDst");	else {		struct rtable *r = v;		char temp[256];		sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"			      "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X",			r->u.dst.dev ? r->u.dst.dev->name : "*",			(unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,			r->rt_flags, atomic_read(&r->u.dst.__refcnt),			r->u.dst.__use, 0, (unsigned long)r->rt_src,			(dst_metric(&r->u.dst, RTAX_ADVMSS) ?			     (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),			dst_metric(&r->u.dst, RTAX_WINDOW),			(int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) +			      dst_metric(&r->u.dst, RTAX_RTTVAR)),			r->fl.fl4_tos,			r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,			r->u.dst.hh ? (r->u.dst.hh->hh_output ==				       dev_queue_xmit) : 0,			r->rt_spec_dst);		seq_printf(seq, "%-127s\n", temp);        }  	return 0;}static struct seq_operations rt_cache_seq_ops = {	.start  = rt_cache_seq_start,	.next   = rt_cache_seq_next,	.stop   = rt_cache_seq_stop,	.show   = rt_cache_seq_show,};static int rt_cache_seq_open(struct inode *inode, struct file *file){	struct seq_file *seq;	int rc = -ENOMEM;	struct rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);	if (!s)		goto out;	rc = seq_open(file, &rt_cache_seq_ops);	if (rc)		goto out_kfree;	seq          = file->private_data;	seq->private = s;	memset(s, 0, sizeof(*s));out:	return rc;out_kfree:	kfree(s);	goto out;}static struct file_operations rt_cache_seq_fops = {	.owner	 = THIS_MODULE,	.open	 = rt_cache_seq_open,	.read	 = seq_read,	.llseek	 = seq_lseek,	.release = seq_release_private,};static void *rt_cpu_seq_start(struct seq_file *seq, loff_t *pos){	int cpu;	if (*pos == 0)		return SEQ_START_TOKEN;	for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {		if (!cpu_possible(cpu))			continue;		*pos = cpu+1;		return per_cpu_ptr(rt_cache_stat, cpu);	}	return NULL;}static void *rt_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos){	int cpu;	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {		if (!cpu_possible(cpu))			continue;		*pos = cpu+1;		return per_cpu_ptr(rt_cache_stat, cpu);	}	return NULL;	}static void rt_cpu_seq_stop(struct seq_file *seq, void *v){}static int rt_cpu_seq_show(struct seq_file *seq, void *v){	struct rt_cache_stat *st = v;	if (v == SEQ_START_TOKEN) {		seq_printf(seq, "entries  in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n");		return 0;	}		seq_printf(seq,"%08x  %08x %08x %08x %08x %08x %08x %08x "		   " %08x %08x %08x %08x %08x %08x %08x %08x %08x \n",		   atomic_read(&ipv4_dst_ops.entries),		   st->in_hit,		   st->in_slow_tot,		   st->in_slow_mc,		   st->in_no_route,		   st->in_brd,		   st->in_martian_dst,		   st->in_martian_src,		   st->out_hit,		   st->out_slow_tot,		   st->out_slow_mc, 		   st->gc_total,		   st->gc_ignored,		   st->gc_goal_miss,		   st->gc_dst_overflow,		   st->in_hlist_search,		   st->out_hlist_search		);	return 0;}static struct seq_operations rt_cpu_seq_ops = {	.start  = rt_cpu_seq_start,	.next   = rt_cpu_seq_next,	.stop   = rt_cpu_seq_stop,	.show   = rt_cpu_seq_show,};static int rt_cpu_seq_open(struct inode *inode, struct file *file){	return seq_open(file, &rt_cpu_seq_ops);}static struct file_operations rt_cpu_seq_fops = {	.owner	 = THIS_MODULE,	.open	 = rt_cpu_seq_open,	.read	 = seq_read,	.llseek	 = seq_lseek,	.release = seq_release,};#endif /* CONFIG_PROC_FS */  static __inline__ void rt_free(struct rtable *rt){	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);}static __inline__ void rt_drop(struct rtable *rt){	ip_rt_put(rt);	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);}static __inline__ int rt_fast_clean(struct rtable *rth){	/* Kill broadcast/multicast entries very aggresively, if they	   collide in hash table with more useful entries */	return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&		rth->fl.iif && rth->u.rt_next;}static __inline__ int rt_valuable(struct rtable *rth){	return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||		rth->u.dst.expires;}static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2){	unsigned long age;	int ret = 0;	if (atomic_read(&rth->u.dst.__refcnt))		goto out;	ret = 1;	if (rth->u.dst.expires &&	    time_after_eq(jiffies, rth->u.dst.expires))		goto out;	age = jiffies - rth->u.dst.lastuse;	ret = 0;	if ((age <= tmo1 && !rt_fast_clean(rth)) ||	    (age <= tmo2 && rt_valuable(rth)))		goto out;	ret = 1;out:	return ret;}/* Bits of score are: * 31: very valuable * 30: not quite useless * 29..0: usage counter */static inline u32 rt_score(struct rtable *rt){	u32 score = jiffies - rt->u.dst.lastuse;	score = ~score & ~(3<<30);	if (rt_valuable(rt))		score |= (1<<31);	if (!rt->fl.iif ||	    !(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL)))		score |= (1<<30);	return score;}/* This runs via a timer and thus is always in BH context. */static void rt_check_expire(unsigned long dummy){	static int rover;	int i = rover, t;	struct rtable *rth, **rthp;	unsigned long now = jiffies;	for (t = ip_rt_gc_interval << rt_hash_log; t >= 0;	     t -= ip_rt_gc_timeout) {		unsigned long tmo = ip_rt_gc_timeout;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -