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

📄 route.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
			rt = rt6_best_dflt(rt, fl->oif);	} else {		rt = rt6_device_match(rt, fl->oif, strict);		BACKTRACK();	}	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {		read_unlock_bh(&rt6_lock);		rt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src);		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.		*/		dst_release(&rt->u.dst);		goto relookup;	}	dst_hold(&rt->u.dst);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_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, NULL, NULL);		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 void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu){	struct rt6_info *rt6 = (struct rt6_info*)dst;	if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen == 128) {		rt6->rt6i_flags |= RTF_MODIFIED;		if (mtu < IPV6_MIN_MTU)			mtu = IPV6_MIN_MTU;		dst->metrics[RTAX_MTU-1] = mtu;	}}/* Protected by rt6_lock.  */static struct dst_entry *ndisc_dst_gc_list;static int ipv6_get_mtu(struct net_device *dev);static inline unsigned int ipv6_advmss(unsigned int mtu){	mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);	if (mtu < ip6_rt_min_advmss)		mtu = ip6_rt_min_advmss;	/*	 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and 	 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. 	 * IPV6_MAXPLEN is also valid and means: "any MSS, 	 * rely only on pmtu discovery"	 */	if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))		mtu = IPV6_MAXPLEN;	return mtu;}struct dst_entry *ndisc_dst_alloc(struct net_device *dev, 				  struct neighbour *neigh,				  struct in6_addr *addr,				  int (*output)(struct sk_buff **)){	struct rt6_info *rt;	struct inet6_dev *idev = in6_dev_get(dev);	if (unlikely(idev == NULL))		return NULL;	rt = ip6_dst_alloc();	if (unlikely(rt == NULL))		goto out;	dev_hold(dev);	if (neigh)		neigh_hold(neigh);	else		neigh = ndisc_get_neigh(dev, addr);	rt->rt6i_dev	  = dev;	rt->rt6i_idev     = idev;	rt->rt6i_nexthop  = neigh;	atomic_set(&rt->u.dst.__refcnt, 1);	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));	rt->u.dst.output  = output;#if 0	/* there's no chance to use these for ndisc */	rt->u.dst.flags   = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST 				? DST_HOST 				: 0;	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);	rt->rt6i_dst.plen = 128;#endif	write_lock_bh(&rt6_lock);	rt->u.dst.next = ndisc_dst_gc_list;	ndisc_dst_gc_list = &rt->u.dst;	write_unlock_bh(&rt6_lock);	fib6_force_start_gc();out:	return (struct dst_entry *)rt;}int ndisc_dst_gc(int *more){	struct dst_entry *dst, *next, **pprev;	int freed;	next = NULL;	pprev = &ndisc_dst_gc_list;	freed = 0;	while ((dst = *pprev) != NULL) {		if (!atomic_read(&dst->__refcnt)) {			*pprev = dst->next;			dst_free(dst);			freed++;		} else {			pprev = &dst->next;			(*more)++;		}	}	return freed;}static int ip6_dst_gc(void){	static unsigned expire = 30*HZ;	static unsigned long last_gc;	unsigned long now = jiffies;	if (time_after(last_gc + ip6_rt_gc_min_interval, now) &&	    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 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;}/* * */int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr){	int err;	struct rtmsg *r;	struct rtattr **rta;	struct rt6_info *rt = NULL;	struct net_device *dev = NULL;	struct inet6_dev *idev = NULL;	int addr_type;	rta = (struct rtattr **) _rtattr;	if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128)		return -EINVAL;#ifndef CONFIG_IPV6_SUBTREES	if (rtmsg->rtmsg_src_len)		return -EINVAL;#endif	if (rtmsg->rtmsg_ifindex) {		err = -ENODEV;		dev = dev_get_by_index(rtmsg->rtmsg_ifindex);		if (!dev)			goto out;		idev = in6_dev_get(dev);		if (!idev)			goto out;	}	if (rtmsg->rtmsg_metric == 0)		rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;	rt = ip6_dst_alloc();	if (rt == NULL)		return -ENOMEM;	rt->u.dst.obsolete = -1;	rt->rt6i_expires = clock_t_to_jiffies(rtmsg->rtmsg_info);	if (nlh && (r = NLMSG_DATA(nlh))) {		rt->rt6i_protocol = r->rtm_protocol;	} else {		rt->rt6i_protocol = RTPROT_BOOT;	}	addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);	if (addr_type & IPV6_ADDR_MULTICAST)		rt->u.dst.input = ip6_mc_input;	else		rt->u.dst.input = ip6_forward;	rt->u.dst.output = ip6_output;	ipv6_addr_prefix(&rt->rt6i_dst.addr, 			 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len);	rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;	if (rt->rt6i_dst.plen == 128)	       rt->u.dst.flags = DST_HOST;#ifdef CONFIG_IPV6_SUBTREES	ipv6_addr_prefix(&rt->rt6i_src.addr, 			 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);	rt->rt6i_src.plen = rtmsg->rtmsg_src_len;#endif	rt->rt6i_metric = rtmsg->rtmsg_metric;	/* We cannot add true routes via loopback here,	   they would result in kernel looping; promote them to reject routes	 */	if ((rtmsg->rtmsg_flags&RTF_REJECT) ||	    (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {		/* hold loopback dev/idev if we haven't done so. */		if (dev != &loopback_dev) {			if (dev) {				dev_put(dev);				in6_dev_put(idev);			}			dev = &loopback_dev;			dev_hold(dev);			idev = in6_dev_get(dev);			if (!idev) {				err = -ENODEV;				goto out;			}		}		rt->u.dst.output = ip6_pkt_discard_out;		rt->u.dst.input = ip6_pkt_discard;		rt->u.dst.error = -ENETUNREACH;		rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;		goto install_route;	}	if (rtmsg->rtmsg_flags & RTF_GATEWAY) {		struct in6_addr *gw_addr;		int gwa_type;		gw_addr = &rtmsg->rtmsg_gateway;		ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway);		gwa_type = ipv6_addr_type(gw_addr);		if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {			struct rt6_info *grt;			/* IPv6 strictly inhibits using not link-local			   addresses as nexthop address.			   Otherwise, router will not able to send redirects.			   It is very good, but in some (rare!) circumstances			   (SIT, PtP, NBMA NOARP links) it is handy to allow			   some exceptions. --ANK			 */			err = -EINVAL;			if (!(gwa_type&IPV6_ADDR_UNICAST))				goto out;			grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);			err = -EHOSTUNREACH;			if (grt == NULL)				goto out;			if (dev) {				if (dev != grt->rt6i_dev) {					dst_release(&grt->u.dst);					goto out;				}			} else {				dev = grt->rt6i_dev;				idev = grt->rt6i_idev;				dev_hold(dev);				in6_dev_hold(grt->rt6i_idev);			}			if (!(grt->rt6i_flags&RTF_GATEWAY))				err = 0;			dst_release(&grt->u.dst);			if (err)				goto out;		}		err = -EINVAL;		if (dev == NULL || (dev->flags&IFF_LOOPBACK))			goto out;	}	err = -ENODEV;	if (dev == NULL)		goto out;	if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) {		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);		if (IS_ERR(rt->rt6i_nexthop)) {			err = PTR_ERR(rt->rt6i_nexthop);			rt->rt6i_nexthop = NULL;			goto out;		}	}	rt->rt6i_flags = rtmsg->rtmsg_flags;install_route:	if (rta && rta[RTA_METRICS-1]) {		int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]);		struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]);		while (RTA_OK(attr, attrlen)) {			unsigned flavor = attr->rta_type;			if (flavor) {				if (flavor > RTAX_MAX) {					err = -EINVAL;					goto out;				}				rt->u.dst.metrics[flavor-1] =					*(u32 *)RTA_DATA(attr);			}			attr = RTA_NEXT(attr, attrlen);		}	}	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) {		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =				IPV6_DEFAULT_MCASTHOPS;		else			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =				ipv6_get_hoplimit(dev);	}	if (!rt->u.dst.metrics[RTAX_MTU-1])		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);	if (!rt->u.dst.metrics[RTAX_ADVMSS-1])		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));	rt->u.dst.dev = dev;	rt->rt6i_idev = idev;	return ip6_ins_rt(rt, nlh, _rtattr);out:	if (dev)		dev_put(dev);	dst_free((struct dst_entry *) rt);	return err;}int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr){	int err;	write_lock_bh(&rt6_lock);	rt6_reset_dflt_pointer(NULL);	dst_release(&rt->u.dst);	err = fib6_del(rt, nlh, _rtattr);	write_unlock_bh(&rt6_lock);	return err;}static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr){	struct fib6_node *fn;	struct rt6_info *rt;	int err = -ESRCH;	read_lock_bh(&rt6_lock);	fn = fib6_locate(&ip6_routing_table,			 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len,			 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);		if (fn) {		for (rt = fn->leaf; rt; rt = rt->u.next) {			if (rtmsg->rtmsg_ifindex &&			    (rt->rt6i_dev == NULL ||			     rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex))				continue;			if (rtmsg->rtmsg_flags&RTF_GATEWAY &&			    ipv6_addr_cmp(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))				continue;			if (rtmsg->rtmsg_metric &&			    rtmsg->rtmsg_metric != rt->rt6i_metric)				continue;			dst_hold(&rt->u.dst);			read_unlock_bh(&rt6_lock);			return ip6_del_rt(rt, nlh, _rtattr);		}	}	read_unlock_bh(&rt6_lock);	return err;}/* *	Handle redirects */void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,		  struct neighbour *neigh, u8 *lladdr, int on_link){	struct rt6_info *rt, *nrt;	/* Locate old route to this destination. */	rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);	if (rt == NULL)		return;	if (neigh->dev != rt->rt6i_dev)		goto out;	/*	 * Current route is on-link; redirect is always invalid.	 * 	 * Seems, previous statement is not true. It could	 * be node, which looks for us as on-link (f.e. proxy ndisc)	 * But then router serving it might decide, that we should	 * know truth 8)8) --ANK (980726).	 */	if (!(rt->rt6i_flags&RTF_GATEWAY))		goto out;	/*	 *	RFC 2461 specifies that redirects should only be	 *	accepted if they come from the nexthop to the target.	 *	Due to the way default routers are chosen, this notion	 *	is a bit fuzzy and one might need to check all default	 *	routers.	 */

⌨️ 快捷键说明

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