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

📄 route.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	Linux INET6 implementation *	FIB front-end. * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt>	 * *	$Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $ * *	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/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/route.h>#include <linux/netdevice.h>#include <linux/in6.h>#include <linux/init.h>#include <linux/netlink.h>#include <linux/if_arp.h>#ifdef 	CONFIG_PROC_FS#include <linux/proc_fs.h>#endif#include <net/snmp.h>#include <net/ipv6.h>#include <net/ip6_fib.h>#include <net/ip6_route.h>#include <net/ndisc.h>#include <net/addrconf.h>#include <net/tcp.h>#include <linux/rtnetlink.h>#include <asm/uaccess.h>#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>#endif#undef CONFIG_RT6_POLICY/* Set to 3 to get tracing. */#define RT6_DEBUG 2#if RT6_DEBUG >= 3#define RDBG(x) printk x#define RT6_TRACE(x...) printk(KERN_DEBUG x)#else#define RDBG(x)#define RT6_TRACE(x...) do { ; } while (0)#endifint ip6_rt_max_size = 4096;int ip6_rt_gc_min_interval = 5*HZ;int ip6_rt_gc_timeout = 60*HZ;int ip6_rt_gc_interval = 30*HZ;int ip6_rt_gc_elasticity = 9;int ip6_rt_mtu_expires = 10*60*HZ;int ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);static struct dst_entry	*ip6_dst_check(struct dst_entry *dst, u32 cookie);static struct dst_entry	*ip6_dst_reroute(struct dst_entry *dst,					 struct sk_buff *skb);static struct dst_entry *ip6_negative_advice(struct dst_entry *);static int		 ip6_dst_gc(void);static int		ip6_pkt_discard(struct sk_buff *skb);static void		ip6_link_failure(struct sk_buff *skb);struct dst_ops ip6_dst_ops = {	AF_INET6,	__constant_htons(ETH_P_IPV6),	1024,        ip6_dst_gc,	ip6_dst_check,	ip6_dst_reroute,	NULL,	ip6_negative_advice,	ip6_link_failure,	sizeof(struct rt6_info),};struct rt6_info ip6_null_entry = {	{{NULL, ATOMIC_INIT(1), 1, &loopback_dev,	  -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	  -ENETUNREACH, NULL, NULL,	  ip6_pkt_discard, ip6_pkt_discard,#ifdef CONFIG_NET_CLS_ROUTE	  0,#endif	  &ip6_dst_ops}},	NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U,	255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0}};struct fib6_node ip6_routing_table = {	NULL, NULL, NULL, NULL,	&ip6_null_entry,	0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0};#ifdef CONFIG_RT6_POLICYint	ip6_rt_policy = 0;struct pol_chain *rt6_pol_list = NULL;static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);static struct rt6_info	*rt6_flow_lookup(struct rt6_info *rt,					 struct in6_addr *daddr,					 struct in6_addr *saddr,					 struct fl_acc_args *args);#else#define ip6_rt_policy (0)#endif/* Protects all the ip6 fib */rwlock_t rt6_lock = RW_LOCK_UNLOCKED;/* *	Route lookup. Any rt6_lock is implied. */static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,						    int oif,						    int strict){	struct rt6_info *local = NULL;	struct rt6_info *sprt;	if (oif) {		for (sprt = rt; sprt; sprt = sprt->u.next) {			struct net_device *dev = sprt->rt6i_dev;			if (dev->ifindex == oif)				return sprt;			if (dev->flags&IFF_LOOPBACK)				local = sprt;		}		if (local)			return local;		if (strict)			return &ip6_null_entry;	}	return rt;}/* *	pointer to the last default router chosen. BH is disabled locally. */static struct rt6_info *rt6_dflt_pointer = NULL;static spinlock_t rt6_dflt_lock = SPIN_LOCK_UNLOCKED;static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif){	struct rt6_info *match = NULL;	struct rt6_info *sprt;	int mpri = 0;	for (sprt = rt; sprt; sprt = sprt->u.next) {		struct neighbour *neigh;		if ((neigh = sprt->rt6i_nexthop) != NULL) {			int m = -1;			switch (neigh->nud_state) {			case NUD_REACHABLE:				if (sprt != rt6_dflt_pointer) {					rt = sprt;					goto out;				}				m = 2;				break;			case NUD_DELAY:				m = 1;				break;			case NUD_STALE:				m = 1;				break;			};			if (oif && sprt->rt6i_dev->ifindex == oif) {				m += 2;			}			if (m >= mpri) {				mpri = m;				match = sprt;			}		}	}	if (match) {		rt = match;	} else {		/*		 *	No default routers are known to be reachable.		 *	SHOULD round robin		 */		spin_lock(&rt6_dflt_lock);		if (rt6_dflt_pointer) {			struct rt6_info *next;			if ((next = rt6_dflt_pointer->u.next) != NULL &&			    next->u.dst.obsolete <= 0 &&			    next->u.dst.error == 0)				rt = next;		}		spin_unlock(&rt6_dflt_lock);	}out:	spin_lock(&rt6_dflt_lock);	rt6_dflt_pointer = rt;	spin_unlock(&rt6_dflt_lock);	return rt;}struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,			    int oif, int strict){	struct fib6_node *fn;	struct rt6_info *rt;	read_lock_bh(&rt6_lock);	fn = fib6_lookup(&ip6_routing_table, daddr, saddr);	rt = rt6_device_match(fn->leaf, oif, strict);	dst_hold(&rt->u.dst);	rt->u.dst.__use++;	read_unlock_bh(&rt6_lock);	rt->u.dst.lastuse = jiffies;	if (rt->u.dst.error == 0)		return rt;	dst_release(&rt->u.dst);	return NULL;}/* rt6_ins is called with FREE rt6_lock.   It takes new route entry, the addition fails by any reason the   route is freed. In any case, if caller does not hold it, it may   be destroyed. */static int rt6_ins(struct rt6_info *rt){	int err;	write_lock_bh(&rt6_lock);	err = fib6_add(&ip6_routing_table, rt);	write_unlock_bh(&rt6_lock);	return err;}/* No rt6_lock! If COW faild, the function returns dead route entry   with dst->error set to errno value. */static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,				struct in6_addr *saddr){	int err;	struct rt6_info *rt;	/*	 *	Clone the route.	 */	rt = ip6_rt_copy(ort);	if (rt) {		ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);		if (!(rt->rt6i_flags&RTF_GATEWAY))			ipv6_addr_copy(&rt->rt6i_gateway, daddr);		rt->rt6i_dst.plen = 128;		rt->rt6i_flags |= RTF_CACHE;		rt->u.dst.flags |= DST_HOST;#ifdef CONFIG_IPV6_SUBTREES		if (rt->rt6i_src.plen && saddr) {			ipv6_addr_copy(&rt->rt6i_src.addr, saddr);			rt->rt6i_src.plen = 128;		}#endif		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);		dst_clone(&rt->u.dst);		err = rt6_ins(rt);		if (err == 0)			return rt;		rt->u.dst.error = err;		return rt;	}	dst_clone(&ip6_null_entry.u.dst);	return &ip6_null_entry;}#ifdef CONFIG_RT6_POLICYstatic __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt,						      struct sk_buff *skb){	struct in6_addr *daddr, *saddr;	struct fl_acc_args arg;	arg.type = FL_ARG_FORWARD;	arg.fl_u.skb = skb;	saddr = &skb->nh.ipv6h->saddr;	daddr = &skb->nh.ipv6h->daddr;	return rt6_flow_lookup(rt, daddr, saddr, &arg);}static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt,						       struct sock *sk,						       struct flowi *fl){	struct fl_acc_args arg;	arg.type = FL_ARG_ORIGIN;	arg.fl_u.fl_o.sk = sk;	arg.fl_u.fl_o.flow = fl;	return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr,			       &arg);}#endif#define BACKTRACK() \if (rt == &ip6_null_entry && strict) { \       while ((fn = fn->parent) != NULL) { \		if (fn->fn_flags & RTN_ROOT) { \			dst_clone(&rt->u.dst); \			goto out; \		} \		if (fn->fn_flags & RTN_RTINFO) \			goto restart; \	} \}void ip6_route_input(struct sk_buff *skb){	struct fib6_node *fn;	struct rt6_info *rt;	int strict;	int attempts = 3;	strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);relookup:	read_lock_bh(&rt6_lock);	fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,			 &skb->nh.ipv6h->saddr);restart:	rt = fn->leaf;	if ((rt->rt6i_flags & RTF_CACHE)) {		if (ip6_rt_policy == 0) {			rt = rt6_device_match(rt, skb->dev->ifindex, strict);			BACKTRACK();			dst_clone(&rt->u.dst);			goto out;		}#ifdef CONFIG_RT6_POLICY		if ((rt->rt6i_flags & RTF_FLOW)) {			struct rt6_info *sprt;			for (sprt = rt; sprt; sprt = sprt->u.next) {				if (rt6_flow_match_in(sprt, skb)) {					rt = sprt;					dst_clone(&rt->u.dst);					goto out;				}			}		}#endif	}	rt = rt6_device_match(rt, skb->dev->ifindex, 0);	BACKTRACK();	if (ip6_rt_policy == 0) {		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {			read_unlock_bh(&rt6_lock);			rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,				     &skb->nh.ipv6h->saddr);						if (rt->u.dst.error != -EEXIST || --attempts <= 0)				goto out2;			/* Race condition! In the gap, when rt6_lock was			   released someone could insert this route.  Relookup.			 */			goto relookup;		}		dst_clone(&rt->u.dst);	} else {#ifdef CONFIG_RT6_POLICY		rt = rt6_flow_lookup_in(rt, skb);#else		/* NEVER REACHED */#endif	}out:	read_unlock_bh(&rt6_lock);out2:	rt->u.dst.lastuse = jiffies;	rt->u.dst.__use++;	skb->dst = (struct dst_entry *) rt;}struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl){	struct fib6_node *fn;	struct rt6_info *rt;	int strict;	int attempts = 3;	strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);relookup:	read_lock_bh(&rt6_lock);	fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,			 fl->nl_u.ip6_u.saddr);restart:	rt = fn->leaf;	if ((rt->rt6i_flags & RTF_CACHE)) {		if (ip6_rt_policy == 0) {			rt = rt6_device_match(rt, fl->oif, strict);			BACKTRACK();			dst_clone(&rt->u.dst);			goto out;		}#ifdef CONFIG_RT6_POLICY		if ((rt->rt6i_flags & RTF_FLOW)) {			struct rt6_info *sprt;			for (sprt = rt; sprt; sprt = sprt->u.next) {				if (rt6_flow_match_out(sprt, sk)) {					rt = sprt;					dst_clone(&rt->u.dst);					goto out;				}			}		}#endif	}	if (rt->rt6i_flags & RTF_DEFAULT) {		if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)			rt = rt6_best_dflt(rt, fl->oif);	} else {		rt = rt6_device_match(rt, fl->oif, strict);		BACKTRACK();	}	if (ip6_rt_policy == 0) {		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {			read_unlock_bh(&rt6_lock);			rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,				     fl->nl_u.ip6_u.saddr);						if (rt->u.dst.error != -EEXIST || --attempts <= 0)				goto out2;			/* Race condition! In the gap, when rt6_lock was			   released someone could insert this route.  Relookup.			 */			goto relookup;		}		dst_clone(&rt->u.dst);	} else {#ifdef CONFIG_RT6_POLICY		rt = rt6_flow_lookup_out(rt, sk, fl);#else		/* NEVER REACHED */#endif	}out:	read_unlock_bh(&rt6_lock);out2:	rt->u.dst.lastuse = jiffies;	rt->u.dst.__use++;	return &rt->u.dst;}/* *	Destination cache support functions */static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie){	struct rt6_info *rt;	rt = (struct rt6_info *) dst;	if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))		return dst;	dst_release(dst);	return NULL;}static struct dst_entry *ip6_dst_reroute(struct dst_entry *dst, struct sk_buff *skb){	/*	 *	FIXME	 */	RDBG(("ip6_dst_reroute(%p,%p)[%p] (AIEEE)\n", dst, skb,	      __builtin_return_address(0)));	return NULL;}static struct dst_entry *ip6_negative_advice(struct dst_entry *dst){	struct rt6_info *rt = (struct rt6_info *) dst;	if (rt) {		if (rt->rt6i_flags & RTF_CACHE)			ip6_del_rt(rt);		else			dst_release(dst);	}	return NULL;}static void ip6_link_failure(struct sk_buff *skb){	struct rt6_info *rt;	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);	rt = (struct rt6_info *) skb->dst;	if (rt) {		if (rt->rt6i_flags&RTF_CACHE) {			dst_set_expires(&rt->u.dst, 0);			rt->rt6i_flags |= RTF_EXPIRES;		} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))			rt->rt6i_node->fn_sernum = -1;	}}static int ip6_dst_gc(){	static unsigned expire = 30*HZ;	static unsigned long last_gc;	unsigned long now = jiffies;	if ((long)(now - last_gc) < ip6_rt_gc_min_interval &&	    atomic_read(&ip6_dst_ops.entries) <= ip6_rt_max_size)		goto out;	expire++;	fib6_run_gc(expire);	last_gc = now;	if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)		expire = ip6_rt_gc_timeout>>1;out:	expire -= expire>>ip6_rt_gc_elasticity;	return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);}/* Clean host part of a prefix. Not necessary in radix tree,   but results in cleaner routing tables.   Remove it only when all the things will work! */static void ipv6_wash_prefix(struct in6_addr *pfx, int plen){	int b = plen&0x7;	int o = (plen + 7)>>3;	if (o < 16)		memset(pfx->s6_addr + o, 0, 16 - o);	if (b != 0)		pfx->s6_addr[plen>>3] &= (0xFF<<(8-b));}static int ipv6_get_mtu(struct net_device *dev){	int mtu = IPV6_MIN_MTU;	struct inet6_dev *idev;	idev = in6_dev_get(dev);	if (idev) {		mtu = idev->cnf.mtu6;		in6_dev_put(idev);	}	return mtu;}static int ipv6_get_hoplimit(struct net_device *dev){	int hoplimit = ipv6_devconf.hop_limit;	struct inet6_dev *idev;	idev = in6_dev_get(dev);	if (idev) {		hoplimit = idev->cnf.hop_limit;		in6_dev_put(idev);	}	return hoplimit;}/* * */

⌨️ 快捷键说明

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