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

📄 dn_route.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
{	struct dn_route *rt = NULL;	struct net_device *dev = decnet_default_device;	struct neighbour *neigh = NULL;	struct dn_dev *dn_db;	unsigned hash;#ifdef CONFIG_DECNET_ROUTER	struct dn_fib_key key;	struct dn_fib_res res;	int err;	key.src = src;	key.dst = dst;	key.iif = 0;	key.oif = 0;	key.fwmark = 0;	key.scope = RT_SCOPE_UNIVERSE;	if ((err = dn_fib_lookup(&key, &res)) == 0) {		switch(res.type) {			case RTN_UNICAST:				/*				 * This method of handling multipath				 * routes is a hack and will change.				 * It works for now though.				 */				if (res.fi->fib_nhs)					dn_fib_select_multipath(&key, &res);				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);				err = -ENOBUFS;				if (!neigh)					break;				err = 0;				break;			case RTN_UNREACHABLE:				err = -EHOSTUNREACH;				break;			default:				err = -EINVAL;		}		dn_fib_res_put(&res);		if (err < 0)			return err;		goto got_route;	}	if (err != -ESRCH)		return err;#endif 	/* Look in On-Ethernet cache first */	if (!(flags & MSG_TRYHARD)) {		if ((neigh = dn_neigh_lookup(&dn_neigh_table, &dst)) != NULL)			goto got_route;	}	if (dev == NULL)		return -EINVAL;	dn_db = dev->dn_ptr;	if (dn_db == NULL)		return -EINVAL;	/* Try default router */	if ((neigh = neigh_clone(dn_db->router)) != NULL)		goto got_route;	/* Send to default device (and hope for the best) if above fail */	if ((neigh = __neigh_lookup(&dn_neigh_table, &dst, dev, 1)) != NULL)		goto got_route;	return -EINVAL;got_route:	if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {		neigh_release(neigh);		return -EINVAL;	}	dn_db = (struct dn_dev *)neigh->dev->dn_ptr;		rt->key.saddr  = src;	rt->rt_saddr   = src;	rt->key.daddr  = dst;	rt->rt_daddr   = dst;	rt->key.oif    = neigh ? neigh->dev->ifindex : -1;	rt->key.iif    = 0;	rt->key.fwmark = 0;	rt->u.dst.neighbour = neigh;	rt->u.dst.dev = neigh ? neigh->dev : NULL;	rt->u.dst.lastuse = jiffies;	rt->u.dst.output = dn_output;	rt->u.dst.input  = dn_rt_bug;	if (dn_dev_islocal(neigh->dev, rt->rt_daddr))		rt->u.dst.input = dn_nsp_rx;	hash = dn_hash(rt->key.saddr, rt->key.daddr);	dn_insert_route(rt, hash);	*pprt = &rt->u.dst;	return 0;}int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags){	unsigned hash = dn_hash(src, dst);	struct dn_route *rt = NULL;	if (!(flags & MSG_TRYHARD)) {		read_lock_bh(&dn_rt_hash_table[hash].lock);		for(rt = dn_rt_hash_table[hash].chain; rt; rt = rt->u.rt_next) {			if ((dst == rt->key.daddr) &&					(src == rt->key.saddr) &&					(rt->key.iif == 0) &&					(rt->key.oif != 0)) {				rt->u.dst.lastuse = jiffies;				dst_hold(&rt->u.dst);				rt->u.dst.__use++;				read_unlock_bh(&dn_rt_hash_table[hash].lock);				*pprt = &rt->u.dst;				return 0;			}		}		read_unlock_bh(&dn_rt_hash_table[hash].lock);	}	return dn_route_output_slow(pprt, dst, src, flags);}static int dn_route_input_slow(struct sk_buff *skb){	struct dn_route *rt = NULL;	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	struct net_device *dev = skb->dev;	struct dn_dev *dn_db;	struct neighbour *neigh = NULL;	int (*dnrt_input)(struct sk_buff *skb);	int (*dnrt_output)(struct sk_buff *skb);	u32 fwmark = 0;	unsigned hash;	dn_address saddr = cb->src;	dn_address daddr = cb->dst;#ifdef CONFIG_DECNET_ROUTER	struct dn_fib_key key;	struct dn_fib_res res;	int err;#endif	if (dev == NULL)		return -EINVAL;	if ((dn_db = dev->dn_ptr) == NULL)		return -EINVAL;	/*	 * In this case we've just received a packet from a source	 * outside ourselves pretending to come from us. We don't	 * allow it any further to prevent routing loops, spoofing and	 * other nasties. Loopback packets already have the dst attached	 * so this only affects packets which have originated elsewhere.	 */	if (dn_dev_islocal(dev, cb->src))		return -ENOTUNIQ;	/*	 * Default is to create a drop everything entry	 */	dnrt_input  = dn_blackhole;	dnrt_output = dn_rt_bug;	/*	 * Is the destination us ?	 */	if (!dn_dev_islocal(dev, cb->dst))		goto non_local_input;	/*	 * Local input... find source of skb	 */	dnrt_input  = dn_nsp_rx;	dnrt_output = dn_output;	saddr = cb->dst;	daddr = cb->src;	if ((neigh = neigh_lookup(&dn_neigh_table, &cb->src, dev)) != NULL)		goto add_entry;	if (dn_db->router && ((neigh = neigh_clone(dn_db->router)) != NULL))		goto add_entry;	neigh = neigh_create(&dn_neigh_table, &cb->src, dev);	if (!IS_ERR(neigh)) {		if (dev->type == ARPHRD_ETHER)			memcpy(neigh->ha, skb->mac.ethernet->h_source, ETH_ALEN);		goto add_entry;	}	return PTR_ERR(neigh);non_local_input:#ifdef CONFIG_DECNET_ROUTER	/*	 * Destination is another node... find next hop in	 * routing table here.	 */	key.src = cb->src;	key.dst = cb->dst;	key.iif = dev->ifindex;	key.oif = 0;	key.scope = RT_SCOPE_UNIVERSE;#ifdef CONFIG_DECNET_ROUTE_FWMARK	key.fwmark = skb->nfmark;#else	key.fwmark = 0;#endif	if ((err = dn_fib_lookup(&key, &res)) == 0) {		switch(res.type) {			case RTN_UNICAST:				if (res.fi->fib_nhs)					dn_fib_select_multipath(&key, &res);				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);				err = -ENOBUFS;				if (!neigh)					break;				err = 0;				dnrt_input = dn_forward;				fwmark = key.fwmark;				break;			case RTN_UNREACHABLE:				dnrt_input = dn_blackhole;				fwmark = key.fwmark;				break;			default:				err = -EINVAL;		}		dn_fib_res_put(&res);		if (err < 0)			return err;		goto add_entry;	}	return err;#endif /* CONFIG_DECNET_ROUTER */add_entry:	if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {                neigh_release(neigh);                return -EINVAL;        }	rt->key.saddr  = cb->src;	rt->rt_saddr   = saddr;	rt->key.daddr  = cb->dst;	rt->rt_daddr   = daddr;	rt->key.oif    = 0;	rt->key.iif    = dev->ifindex;	rt->key.fwmark = fwmark;	rt->u.dst.neighbour = neigh;	rt->u.dst.dev = neigh ? neigh->dev : NULL;	rt->u.dst.lastuse = jiffies;	rt->u.dst.output = dnrt_output;	rt->u.dst.input = dnrt_input;	hash = dn_hash(rt->key.saddr, rt->key.daddr);	dn_insert_route(rt, hash);	skb->dst = (struct dst_entry *)rt;	return 0;}int dn_route_input(struct sk_buff *skb){	struct dn_route *rt;	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	unsigned hash = dn_hash(cb->src, cb->dst);	if (skb->dst)		return 0;	read_lock(&dn_rt_hash_table[hash].lock);	for(rt = dn_rt_hash_table[hash].chain; rt != NULL; rt = rt->u.rt_next) {		if ((rt->key.saddr == cb->src) &&				(rt->key.daddr == cb->dst) &&				(rt->key.oif == 0) &&#ifdef CONFIG_DECNET_ROUTE_FWMARK				(rt->key.fwmark == skb->nfmark) &&#endif				(rt->key.iif == cb->iif)) {			rt->u.dst.lastuse = jiffies;			dst_hold(&rt->u.dst);			rt->u.dst.__use++;			read_unlock(&dn_rt_hash_table[hash].lock);			skb->dst = (struct dst_entry *)rt;			return 0;		}	}	read_unlock(&dn_rt_hash_table[hash].lock);	return dn_route_input_slow(skb);}#ifdef CONFIG_RTNETLINKstatic int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait){	struct dn_route *rt = (struct dn_route *)skb->dst;	struct rtmsg *r;	struct nlmsghdr *nlh;	unsigned char *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r));	r = NLMSG_DATA(nlh);	nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;	r->rtm_family = AF_DECnet;	r->rtm_dst_len = 16;	r->rtm_src_len = 16;	r->rtm_tos = 0;	r->rtm_table = 0;	r->rtm_type = 0;	r->rtm_flags = 0;	r->rtm_scope = RT_SCOPE_UNIVERSE;	r->rtm_protocol = RTPROT_UNSPEC;	RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr);	RTA_PUT(skb, RTA_SRC, 2, &rt->rt_saddr);	if (rt->u.dst.dev)		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);	if (rt->u.dst.window)		RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window);	if (rt->u.dst.rtt)		RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:        skb_trim(skb, b - skb->data);        return -1;}/* * This is called by both endnodes and routers now. */int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct dn_route *rt = NULL;	struct dn_skb_cb *cb;	dn_address dst = 0;	dn_address src = 0;	int iif = 0;	int err;	struct sk_buff *skb;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (skb == NULL)		return -ENOBUFS;	skb->mac.raw = skb->data;	cb = (struct dn_skb_cb *)skb->cb;	if (rta[RTA_SRC-1])		memcpy(&src, RTA_DATA(rta[RTA_SRC-1]), 2);	if (rta[RTA_DST-1])		memcpy(&dst, RTA_DATA(rta[RTA_DST-1]), 2);	if (rta[RTA_IIF-1])		memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));	if (iif) {		struct net_device *dev;		if ((dev = dev_get_by_index(iif)) == NULL) {			kfree_skb(skb);			return -ENODEV;		}		if (!dev->dn_ptr) {			dev_put(dev);			kfree_skb(skb);			return -ENODEV;		}		skb->protocol = __constant_htons(ETH_P_DNA_RT);		skb->dev = dev;		cb->src = src;		cb->dst = dst;		local_bh_disable();		err = dn_route_input(skb);		local_bh_enable();		memset(cb, 0, sizeof(struct dn_skb_cb));		rt = (struct dn_route *)skb->dst;	} else {		err = dn_route_output((struct dst_entry **)&rt, dst, src, 0);	}	if (!err && rt->u.dst.error)		err = rt->u.dst.error;	if (skb->dev)		dev_put(skb->dev);	skb->dev = NULL;	if (err)		goto out_free;	skb->dst = &rt->u.dst;	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;	err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0);	if (err == 0)		goto out_free;	if (err < 0) {		err = -EMSGSIZE;		goto out_free;	}	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);	return err;out_free:	kfree_skb(skb);	return err;}/* * For routers, this is called from dn_fib_dump, but for endnodes its * called directly from the rtnetlink dispatch table. */int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb){	struct dn_route *rt;	int h, s_h;	int idx, s_idx;	if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg))		return -EINVAL;	if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED))		return 0;	s_h = cb->args[0];	s_idx = idx = cb->args[1];	for(h = 0; h <= dn_rt_hash_mask; h++) {		if (h < s_h)			continue;		if (h > s_h)			s_idx = 0;		read_lock_bh(&dn_rt_hash_table[h].lock);		for(rt = dn_rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) {			if (idx < s_idx)				continue;			skb->dst = dst_clone(&rt->u.dst);			if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,					cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {				dst_release(xchg(&skb->dst, NULL));				read_unlock_bh(&dn_rt_hash_table[h].lock);				goto done;			}			dst_release(xchg(&skb->dst, NULL));		}		read_unlock_bh(&dn_rt_hash_table[h].lock);	}done:	cb->args[0] = h;	cb->args[1] = idx;	return skb->len;}#endif /* CONFIG_RTNETLINK */#ifdef CONFIG_PROC_FSstatic int decnet_cache_get_info(char *buffer, char **start, off_t offset, int length){        int len = 0;        off_t pos = 0;        off_t begin = 0;	struct dn_route *rt;	int i;	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];	for(i = 0; i <= dn_rt_hash_mask; i++) {		read_lock_bh(&dn_rt_hash_table[i].lock);		rt = dn_rt_hash_table[i].chain;		for(; rt != NULL; rt = rt->u.rt_next) {			len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n",					rt->u.dst.dev ? rt->u.dst.dev->name : "*",					dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),					dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),					atomic_read(&rt->u.dst.__refcnt),					rt->u.dst.__use,					(int)rt->u.dst.rtt					);	                pos = begin + len;	        	        if (pos < offset) {                	        len   = 0;                        	begin = pos;                	}              		if (pos > offset + length)                	        break;		}		read_unlock_bh(&dn_rt_hash_table[i].lock);		if (pos > offset + length)			break;	}        *start = buffer + (offset - begin);        len   -= (offset - begin);        if (len > length) len = length;        return(len);} #endif /* CONFIG_PROC_FS */void __init dn_route_init(void){	int i, goal, order;	dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache",						   sizeof(struct dn_route),						   0, SLAB_HWCACHE_ALIGN,						   NULL, NULL);	if (!dn_dst_ops.kmem_cachep)		panic("DECnet: Failed to allocate dn_dst_cache\n");	dn_route_timer.function = dn_dst_check_expire;	dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;	add_timer(&dn_route_timer);	goal = num_physpages >> (26 - PAGE_SHIFT);	for(order = 0; (1UL << order) < goal; order++)		/* NOTHING */;        /*         * Only want 1024 entries max, since the table is very, very unlikely         * to be larger than that.         */        while(order && ((((1UL << order) * PAGE_SIZE) /                                 sizeof(struct dn_rt_hash_bucket)) >= 2048))                order--;        do {                dn_rt_hash_mask = (1UL << order) * PAGE_SIZE /                        sizeof(struct dn_rt_hash_bucket);                while(dn_rt_hash_mask & (dn_rt_hash_mask - 1))                        dn_rt_hash_mask--;                dn_rt_hash_table = (struct dn_rt_hash_bucket *)                        __get_free_pages(GFP_ATOMIC, order);        } while (dn_rt_hash_table == NULL && --order > 0);	if (!dn_rt_hash_table)                panic("Failed to allocate DECnet route cache hash table\n");	printk(KERN_INFO 		"DECnet: Routing cache hash table of %u buckets, %ldKbytes\n", 		dn_rt_hash_mask, 		(long)(dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024);	dn_rt_hash_mask--;        for(i = 0; i <= dn_rt_hash_mask; i++) {                dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED;                dn_rt_hash_table[i].chain = NULL;        }        dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);#ifdef CONFIG_PROC_FS	proc_net_create("decnet_cache",0,decnet_cache_get_info);#endif /* CONFIG_PROC_FS */}void __exit dn_route_cleanup(void){	del_timer(&dn_route_timer);	dn_run_flush(0);#ifdef CONFIG_PROC_FS	proc_net_remove("decnet_cache");#endif /* CONFIG_PROC_FS */}

⌨️ 快捷键说明

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