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

📄 route.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	int err;	struct fib6_table *table;	if (rt == &ip6_null_entry)		return -ENOENT;	table = rt->rt6i_table;	write_lock_bh(&table->tb6_lock);	err = fib6_del(rt, info);	dst_release(&rt->u.dst);	write_unlock_bh(&table->tb6_lock);	return err;}int ip6_del_rt(struct rt6_info *rt){	return __ip6_del_rt(rt, NULL);}static int ip6_route_del(struct fib6_config *cfg){	struct fib6_table *table;	struct fib6_node *fn;	struct rt6_info *rt;	int err = -ESRCH;	table = fib6_get_table(cfg->fc_table);	if (table == NULL)		return err;	read_lock_bh(&table->tb6_lock);	fn = fib6_locate(&table->tb6_root,			 &cfg->fc_dst, cfg->fc_dst_len,			 &cfg->fc_src, cfg->fc_src_len);	if (fn) {		for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {			if (cfg->fc_ifindex &&			    (rt->rt6i_dev == NULL ||			     rt->rt6i_dev->ifindex != cfg->fc_ifindex))				continue;			if (cfg->fc_flags & RTF_GATEWAY &&			    !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))				continue;			if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)				continue;			dst_hold(&rt->u.dst);			read_unlock_bh(&table->tb6_lock);			return __ip6_del_rt(rt, &cfg->fc_nlinfo);		}	}	read_unlock_bh(&table->tb6_lock);	return err;}/* *	Handle redirects */struct ip6rd_flowi {	struct flowi fl;	struct in6_addr gateway;};static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,					     struct flowi *fl,					     int flags){	struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl;	struct rt6_info *rt;	struct fib6_node *fn;	/*	 * Get the "current" route for this destination and	 * check if the redirect has come from approriate router.	 *	 * RFC 2461 specifies that redirects should only be	 * accepted if they come from the nexthop to the target.	 * Due to the way the routes are chosen, this notion	 * is a bit fuzzy and one might need to check all possible	 * routes.	 */	read_lock_bh(&table->tb6_lock);	fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);restart:	for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {		/*		 * 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 (rt6_check_expired(rt))			continue;		if (!(rt->rt6i_flags & RTF_GATEWAY))			continue;		if (fl->oif != rt->rt6i_dev->ifindex)			continue;		if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))			continue;		break;	}	if (!rt)		rt = &ip6_null_entry;	BACKTRACK(&fl->fl6_src);out:	dst_hold(&rt->u.dst);	read_unlock_bh(&table->tb6_lock);	return rt;};static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,					   struct in6_addr *src,					   struct in6_addr *gateway,					   struct net_device *dev){	int flags = RT6_LOOKUP_F_HAS_SADDR;	struct ip6rd_flowi rdfl = {		.fl = {			.oif = dev->ifindex,			.nl_u = {				.ip6_u = {					.daddr = *dest,					.saddr = *src,				},			},		},		.gateway = *gateway,	};	if (rt6_need_strict(dest))		flags |= RT6_LOOKUP_F_IFACE;	return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);}void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,		  struct in6_addr *saddr,		  struct neighbour *neigh, u8 *lladdr, int on_link){	struct rt6_info *rt, *nrt = NULL;	struct netevent_redirect netevent;	rt = ip6_route_redirect(dest, src, saddr, neigh->dev);	if (rt == &ip6_null_entry) {		if (net_ratelimit())			printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "			       "for redirect target\n");		goto out;	}	/*	 *	We have finally decided to accept it.	 */	neigh_update(neigh, lladdr, NUD_STALE,		     NEIGH_UPDATE_F_WEAK_OVERRIDE|		     NEIGH_UPDATE_F_OVERRIDE|		     (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|				     NEIGH_UPDATE_F_ISROUTER))		     );	/*	 * Redirect received -> path was valid.	 * Look, redirects are sent only in response to data packets,	 * so that this nexthop apparently is reachable. --ANK	 */	dst_confirm(&rt->u.dst);	/* Duplicate redirect: silently ignore. */	if (neigh == rt->u.dst.neighbour)		goto out;	nrt = ip6_rt_copy(rt);	if (nrt == NULL)		goto out;	nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;	if (on_link)		nrt->rt6i_flags &= ~RTF_GATEWAY;	ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);	nrt->rt6i_dst.plen = 128;	nrt->u.dst.flags |= DST_HOST;	ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);	nrt->rt6i_nexthop = neigh_clone(neigh);	/* Reset pmtu, it may be better */	nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst));	if (ip6_ins_rt(nrt))		goto out;	netevent.old = &rt->u.dst;	netevent.new = &nrt->u.dst;	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);	if (rt->rt6i_flags&RTF_CACHE) {		ip6_del_rt(rt);		return;	}out:	dst_release(&rt->u.dst);	return;}/* *	Handle ICMP "packet too big" messages *	i.e. Path MTU discovery */void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,			struct net_device *dev, u32 pmtu){	struct rt6_info *rt, *nrt;	int allfrag = 0;	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);	if (rt == NULL)		return;	if (pmtu >= dst_mtu(&rt->u.dst))		goto out;	if (pmtu < IPV6_MIN_MTU) {		/*		 * According to RFC2460, PMTU is set to the IPv6 Minimum Link		 * MTU (1280) and a fragment header should always be included		 * after a node receiving Too Big message reporting PMTU is		 * less than the IPv6 Minimum Link MTU.		 */		pmtu = IPV6_MIN_MTU;		allfrag = 1;	}	/* New mtu received -> path was valid.	   They are sent only in response to data packets,	   so that this nexthop apparently is reachable. --ANK	 */	dst_confirm(&rt->u.dst);	/* Host route. If it is static, it would be better	   not to override it, but add new one, so that	   when cache entry will expire old pmtu	   would return automatically.	 */	if (rt->rt6i_flags & RTF_CACHE) {		rt->u.dst.metrics[RTAX_MTU-1] = pmtu;		if (allfrag)			rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;		goto out;	}	/* Network route.	   Two cases are possible:	   1. It is connected route. Action: COW	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.	 */	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))		nrt = rt6_alloc_cow(rt, daddr, saddr);	else		nrt = rt6_alloc_clone(rt, daddr);	if (nrt) {		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;		if (allfrag)			nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;		/* According to RFC 1981, detecting PMTU increase shouldn't be		 * happened within 5 mins, the recommended timer is 10 mins.		 * Here this route expiration time is set to ip6_rt_mtu_expires		 * which is 10 mins. After 10 mins the decreased pmtu is expired		 * and detecting PMTU increase will be automatically happened.		 */		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;		ip6_ins_rt(nrt);	}out:	dst_release(&rt->u.dst);}/* *	Misc support functions */static struct rt6_info * ip6_rt_copy(struct rt6_info *ort){	struct rt6_info *rt = ip6_dst_alloc();	if (rt) {		rt->u.dst.input = ort->u.dst.input;		rt->u.dst.output = ort->u.dst.output;		memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));		rt->u.dst.error = ort->u.dst.error;		rt->u.dst.dev = ort->u.dst.dev;		if (rt->u.dst.dev)			dev_hold(rt->u.dst.dev);		rt->rt6i_idev = ort->rt6i_idev;		if (rt->rt6i_idev)			in6_dev_hold(rt->rt6i_idev);		rt->u.dst.lastuse = jiffies;		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		rt->rt6i_table = ort->rt6i_table;	}	return rt;}#ifdef CONFIG_IPV6_ROUTE_INFOstatic struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,					   struct in6_addr *gwaddr, int ifindex){	struct fib6_node *fn;	struct rt6_info *rt = NULL;	struct fib6_table *table;	table = fib6_get_table(RT6_TABLE_INFO);	if (table == NULL)		return NULL;	write_lock_bh(&table->tb6_lock);	fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);	if (!fn)		goto out;	for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {		if (rt->rt6i_dev->ifindex != ifindex)			continue;		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))			continue;		if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))			continue;		dst_hold(&rt->u.dst);		break;	}out:	write_unlock_bh(&table->tb6_lock);	return rt;}static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,					   struct in6_addr *gwaddr, int ifindex,					   unsigned pref){	struct fib6_config cfg = {		.fc_table	= RT6_TABLE_INFO,		.fc_metric	= 1024,		.fc_ifindex	= ifindex,		.fc_dst_len	= prefixlen,		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |				  RTF_UP | RTF_PREF(pref),	};	ipv6_addr_copy(&cfg.fc_dst, prefix);	ipv6_addr_copy(&cfg.fc_gateway, gwaddr);	/* We should treat it as a default route if prefix length is 0. */	if (!prefixlen)		cfg.fc_flags |= RTF_DEFAULT;	ip6_route_add(&cfg);	return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);}#endifstruct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev){	struct rt6_info *rt;	struct fib6_table *table;	table = fib6_get_table(RT6_TABLE_DFLT);	if (table == NULL)		return NULL;	write_lock_bh(&table->tb6_lock);	for (rt = table->tb6_root.leaf; rt; rt=rt->u.dst.rt6_next) {		if (dev == rt->rt6i_dev &&		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&		    ipv6_addr_equal(&rt->rt6i_gateway, addr))			break;	}	if (rt)		dst_hold(&rt->u.dst);	write_unlock_bh(&table->tb6_lock);	return rt;}struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,				     struct net_device *dev,				     unsigned int pref){	struct fib6_config cfg = {		.fc_table	= RT6_TABLE_DFLT,		.fc_metric	= 1024,		.fc_ifindex	= dev->ifindex,		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |				  RTF_UP | RTF_EXPIRES | RTF_PREF(pref),	};	ipv6_addr_copy(&cfg.fc_gateway, gwaddr);	ip6_route_add(&cfg);	return rt6_get_dflt_router(gwaddr, dev);}void rt6_purge_dflt_routers(void){	struct rt6_info *rt;	struct fib6_table *table;	/* NOTE: Keep consistent with rt6_get_dflt_router */	table = fib6_get_table(RT6_TABLE_DFLT);	if (table == NULL)		return;restart:	read_lock_bh(&table->tb6_lock);	for (rt = table->tb6_root.leaf; rt; rt = rt->u.dst.rt6_next) {		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {			dst_hold(&rt->u.dst);			read_unlock_bh(&table->tb6_lock);			ip6_del_rt(rt);			goto restart;		}	}	read_unlock_bh(&table->tb6_lock);}static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg,				 struct fib6_config *cfg){	memset(cfg, 0, sizeof(*cfg));	cfg->fc_table = RT6_TABLE_MAIN;	cfg->fc_ifindex = rtmsg->rtmsg_ifindex;	cfg->fc_metric = rtmsg->rtmsg_metric;	cfg->fc_expires = rtmsg->rtmsg_info;	cfg->fc_dst_len = rtmsg->rtmsg_dst_len;	cfg->fc_src_len = rtmsg->rtmsg_src_len;	cfg->fc_flags = rtmsg->rtmsg_flags;	ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst);	ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src);	ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway);}int ipv6_route_ioctl(unsigned int cmd, void __user *arg){	struct fib6_config cfg;	struct in6_rtmsg rtmsg;	int err;	switch(cmd) {	case SIOCADDRT:		/* Add a route */	case SIOCDELRT:		/* Delete a route */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		err = copy_from_user(&rtmsg, arg,				     sizeof(struct in6_rtmsg));		if (err)			return -EFAULT;		rtmsg_to_fib6_config(&rtmsg, &cfg);		rtnl_lock();		switch (cmd) {		case SIOCADDRT:			err = ip6_route_add(&cfg);			break;		case SIOCDELRT:			err = ip6_route_del(&cfg);			break;		default:			err = -EINVAL;		}		rtnl_unlock();		return err;	}	return -EINVAL;}/* *	Drop the packet on the floor */static inline int ip6_pkt_drop(struct sk_buff *skb, int code,			       int ipstats_mib_noroutes){	int type;	switch (ipstats_mib_noroutes) {	case IPSTATS_MIB_INNOROUTES:		type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);		if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) {			IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS);			break;		}		/* FALLTHROUGH */	case IPSTATS_MIB_OUTNOROUTES:		IP6_INC_STATS(ip6_dst_idev(skb->dst), ipstats_mib_noroutes);		break;	}	icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);	kfree_skb(skb);	return 0;}static int ip6_pkt_discard(struct sk_buff *skb){	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);}static int ip6_pkt_discard_out(struct sk_buff *skb){	skb->dev = skb->dst->dev;	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);}#ifdef CONFIG_IPV6_MULTIPLE_TABLESstatic int ip6_pkt_prohibit(struct sk_buff *skb){	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);}static int ip6_pkt_prohibit_out(struct sk_buff *skb){	skb->dev = skb->dst->dev;	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);}static int ip6_pkt_blk_hole(struct sk_buff *skb){	kfree_skb(skb);	return 0;}#endif/* *	Allocate a dst for local (unicast / anycast) address. */struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,				    const struct in6_addr *addr,				    int anycast){	struct rt6_info *rt = ip6_dst_alloc();	if (rt == NULL)		return ERR_PTR(-ENOMEM);	dev_hold(init_net.loopback_dev);	in6_dev_hold(idev);	rt->u.dst.flags = DST_HOST;	rt->u.dst.input = ip6_input;	rt->u.dst.output = ip6_output;	rt->rt6i_dev = init_net.loopback_dev;	rt->rt6i_idev = idev;	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.metrics[RTAX_HOPLIMIT-1] = -1;	rt->u.dst.obsolete = -1;	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;	if (anycast)		rt->rt6i_flags |= RTF_ANYCAST;	else		rt->rt6i_flags |= RTF_LOCAL;	rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);	if (rt->rt6i_nexthop == NULL) {		dst_free(&rt->u.dst);		return ERR_PTR(-ENOMEM);	}	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);	rt->rt6i_dst.plen = 128;	rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);	atomic_set(&rt->u.dst.__refcnt, 1);	return rt;}static int fib6_ifdown(struct rt6_info *rt, void *arg){	if (((void*)rt->rt6i_dev == arg || arg == NULL) &&	    rt != &ip6_null_entry) {		RT6_TRACE("deleted by ifdown %p\n", rt);		return -1;	}	return 0;}void rt6_ifdown(struct net_device *dev)

⌨️ 快捷键说明

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