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

📄 route.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				rt->rt6i_flags |= RTF_ANYCAST;			ipv6_addr_copy(&rt->rt6i_gateway, daddr);		}		ipv6_addr_copy(&rt->rt6i_dst.addr, 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);	}	return rt;}static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr){	struct rt6_info *rt = ip6_rt_copy(ort);	if (rt) {		ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);		rt->rt6i_dst.plen = 128;		rt->rt6i_flags |= RTF_CACHE;		rt->u.dst.flags |= DST_HOST;		rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);	}	return rt;}static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,					    struct flowi *fl, int flags){	struct fib6_node *fn;	struct rt6_info *rt, *nrt;	int strict = 0;	int attempts = 3;	int err;	int reachable = ipv6_devconf.forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;	strict |= flags & RT6_LOOKUP_F_IFACE;relookup:	read_lock_bh(&table->tb6_lock);restart_2:	fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);restart:	rt = rt6_select(fn, oif, strict | reachable);	BACKTRACK(&fl->fl6_src);	if (rt == &ip6_null_entry ||	    rt->rt6i_flags & RTF_CACHE)		goto out;	dst_hold(&rt->u.dst);	read_unlock_bh(&table->tb6_lock);	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))		nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);	else {#if CLONE_OFFLINK_ROUTE		nrt = rt6_alloc_clone(rt, &fl->fl6_dst);#else		goto out2;#endif	}	dst_release(&rt->u.dst);	rt = nrt ? : &ip6_null_entry;	dst_hold(&rt->u.dst);	if (nrt) {		err = ip6_ins_rt(nrt);		if (!err)			goto out2;	}	if (--attempts <= 0)		goto out2;	/*	 * Race condition! In the gap, when table->tb6_lock was	 * released someone could insert this route.  Relookup.	 */	dst_release(&rt->u.dst);	goto relookup;out:	if (reachable) {		reachable = 0;		goto restart_2;	}	dst_hold(&rt->u.dst);	read_unlock_bh(&table->tb6_lock);out2:	rt->u.dst.lastuse = jiffies;	rt->u.dst.__use++;	return rt;}static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,					    struct flowi *fl, int flags){	return ip6_pol_route(table, fl->iif, fl, flags);}void ip6_route_input(struct sk_buff *skb){	struct ipv6hdr *iph = ipv6_hdr(skb);	int flags = RT6_LOOKUP_F_HAS_SADDR;	struct flowi fl = {		.iif = skb->dev->ifindex,		.nl_u = {			.ip6_u = {				.daddr = iph->daddr,				.saddr = iph->saddr,				.flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK,			},		},		.mark = skb->mark,		.proto = iph->nexthdr,	};	if (rt6_need_strict(&iph->daddr))		flags |= RT6_LOOKUP_F_IFACE;	skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);}static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,					     struct flowi *fl, int flags){	return ip6_pol_route(table, fl->oif, fl, flags);}struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl){	int flags = 0;	if (rt6_need_strict(&fl->fl6_dst))		flags |= RT6_LOOKUP_F_IFACE;	if (!ipv6_addr_any(&fl->fl6_src))		flags |= RT6_LOOKUP_F_HAS_SADDR;	return fib6_rule_lookup(fl, flags, ip6_pol_route_output);}EXPORT_SYMBOL(ip6_route_output);static int ip6_blackhole_output(struct sk_buff *skb){	kfree_skb(skb);	return 0;}int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl){	struct rt6_info *ort = (struct rt6_info *) *dstp;	struct rt6_info *rt = (struct rt6_info *)		dst_alloc(&ip6_dst_blackhole_ops);	struct dst_entry *new = NULL;	if (rt) {		new = &rt->u.dst;		atomic_set(&new->__refcnt, 1);		new->__use = 1;		new->input = ip6_blackhole_output;		new->output = ip6_blackhole_output;		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));		new->dev = ort->u.dst.dev;		if (new->dev)			dev_hold(new->dev);		rt->rt6i_idev = ort->rt6i_idev;		if (rt->rt6i_idev)			in6_dev_hold(rt->rt6i_idev);		rt->rt6i_expires = 0;		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;		rt->rt6i_metric = 0;		memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));#ifdef CONFIG_IPV6_SUBTREES		memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));#endif		dst_free(new);	}	dst_release(*dstp);	*dstp = new;	return (new ? 0 : -ENOMEM);}EXPORT_SYMBOL_GPL(ip6_dst_blackhole);/* *	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;	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 void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu){	struct rt6_info *rt6 = (struct rt6_info*)dst;	if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {		rt6->rt6i_flags |= RTF_MODIFIED;		if (mtu < IPV6_MIN_MTU) {			mtu = IPV6_MIN_MTU;			dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;		}		dst->metrics[RTAX_MTU-1] = mtu;		call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);	}}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;}static struct dst_entry *ndisc_dst_gc_list;static DEFINE_SPINLOCK(ndisc_lock);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)) {		in6_dev_put(idev);		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_mtu(&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	spin_lock_bh(&ndisc_lock);	rt->u.dst.next = ndisc_dst_gc_list;	ndisc_dst_gc_list = &rt->u.dst;	spin_unlock_bh(&ndisc_lock);	fib6_force_start_gc();out:	return &rt->u.dst;}int ndisc_dst_gc(int *more){	struct dst_entry *dst, *next, **pprev;	int freed;	next = NULL;	freed = 0;	spin_lock_bh(&ndisc_lock);	pprev = &ndisc_dst_gc_list;	while ((dst = *pprev) != NULL) {		if (!atomic_read(&dst->__refcnt)) {			*pprev = dst->next;			dst_free(dst);			freed++;		} else {			pprev = &dst->next;			(*more)++;		}	}	spin_unlock_bh(&ndisc_lock);	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;}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 fib6_config *cfg){	int err;	struct rt6_info *rt = NULL;	struct net_device *dev = NULL;	struct inet6_dev *idev = NULL;	struct fib6_table *table;	int addr_type;	if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)		return -EINVAL;#ifndef CONFIG_IPV6_SUBTREES	if (cfg->fc_src_len)		return -EINVAL;#endif	if (cfg->fc_ifindex) {		err = -ENODEV;		dev = dev_get_by_index(&init_net, cfg->fc_ifindex);		if (!dev)			goto out;		idev = in6_dev_get(dev);		if (!idev)			goto out;	}	if (cfg->fc_metric == 0)		cfg->fc_metric = IP6_RT_PRIO_USER;	table = fib6_new_table(cfg->fc_table);	if (table == NULL) {		err = -ENOBUFS;		goto out;	}	rt = ip6_dst_alloc();	if (rt == NULL) {		err = -ENOMEM;		goto out;	}	rt->u.dst.obsolete = -1;	rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires);	if (cfg->fc_protocol == RTPROT_UNSPEC)		cfg->fc_protocol = RTPROT_BOOT;	rt->rt6i_protocol = cfg->fc_protocol;	addr_type = ipv6_addr_type(&cfg->fc_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, &cfg->fc_dst, cfg->fc_dst_len);	rt->rt6i_dst.plen = cfg->fc_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, &cfg->fc_src, cfg->fc_src_len);	rt->rt6i_src.plen = cfg->fc_src_len;#endif	rt->rt6i_metric = cfg->fc_metric;	/* We cannot add true routes via loopback here,	   they would result in kernel looping; promote them to reject routes	 */	if ((cfg->fc_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 != init_net.loopback_dev) {			if (dev) {				dev_put(dev);				in6_dev_put(idev);			}			dev = init_net.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 (cfg->fc_flags & RTF_GATEWAY) {		struct in6_addr *gw_addr;		int gwa_type;		gw_addr = &cfg->fc_gateway;		ipv6_addr_copy(&rt->rt6i_gateway, gw_addr);		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, cfg->fc_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 (cfg->fc_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 = cfg->fc_flags;install_route:	if (cfg->fc_mx) {		struct nlattr *nla;		int remaining;		nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {			int type = nla_type(nla);			if (type) {				if (type > RTAX_MAX) {					err = -EINVAL;					goto out;				}				rt->u.dst.metrics[type - 1] = nla_get_u32(nla);			}		}	}	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)		rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;	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_mtu(&rt->u.dst));	rt->u.dst.dev = dev;	rt->rt6i_idev = idev;	rt->rt6i_table = table;	return __ip6_ins_rt(rt, &cfg->fc_nlinfo);out:	if (dev)		dev_put(dev);	if (idev)		in6_dev_put(idev);	if (rt)		dst_free(&rt->u.dst);	return err;}static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info){

⌨️ 快捷键说明

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