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

📄 dn_fib.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	fi->fib_treeref++;	atomic_inc(&fi->fib_clntref);	spin_lock(&dn_fib_info_lock);	fi->fib_next = dn_fib_info_list;	fi->fib_prev = NULL;	if (dn_fib_info_list)		dn_fib_info_list->fib_prev = fi;	dn_fib_info_list = fi;	spin_unlock(&dn_fib_info_lock);	return fi;err_inval:	err = -EINVAL;failure:	*errp = err;	if (fi) {		fi->fib_dead = 1;		dn_fib_free_info(fi);	}	return NULL;}int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *fl, struct dn_fib_res *res){	int err = dn_fib_props[type].error;	if (err == 0) {		if (fi->fib_flags & RTNH_F_DEAD)			return 1;		res->fi = fi;		switch(type) {			case RTN_NAT:				DN_FIB_RES_RESET(*res);				atomic_inc(&fi->fib_clntref);				return 0;			case RTN_UNICAST:			case RTN_LOCAL:				for_nexthops(fi) {					if (nh->nh_flags & RTNH_F_DEAD)						continue;					if (!fl->oif || fl->oif == nh->nh_oif)						break;				}				if (nhsel < fi->fib_nhs) {					res->nh_sel = nhsel;					atomic_inc(&fi->fib_clntref);					return 0;				}				endfor_nexthops(fi);				res->fi = NULL;				return 1;			default:				if (net_ratelimit())					 printk("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n", type);				res->fi = NULL;				return -EINVAL;		}	}	return err;}void dn_fib_select_multipath(const struct flowi *fl, struct dn_fib_res *res){	struct dn_fib_info *fi = res->fi;	int w;	spin_lock_bh(&dn_fib_multipath_lock);	if (fi->fib_power <= 0) {		int power = 0;		change_nexthops(fi) {			if (!(nh->nh_flags&RTNH_F_DEAD)) {				power += nh->nh_weight;				nh->nh_power = nh->nh_weight;			}		} endfor_nexthops(fi);		fi->fib_power = power;		if (power < 0) {			spin_unlock_bh(&dn_fib_multipath_lock);			res->nh_sel = 0;			return;		}	}	w = jiffies % fi->fib_power;	change_nexthops(fi) {		if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {			if ((w -= nh->nh_power) <= 0) {				nh->nh_power--;				fi->fib_power--;				res->nh_sel = nhsel;				spin_unlock_bh(&dn_fib_multipath_lock);				return;			}		}	} endfor_nexthops(fi);	res->nh_sel = 0;	spin_unlock_bh(&dn_fib_multipath_lock);}static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta){	int i;	for(i = 1; i <= RTA_MAX; i++) {		struct rtattr *attr = rta[i-1];		if (attr) {			if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)				return -EINVAL;			if (i != RTA_MULTIPATH && i != RTA_METRICS &&			    i != RTA_TABLE)				rta[i-1] = (struct rtattr *)RTA_DATA(attr);		}	}	return 0;}static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct dn_fib_table *tb;	struct rtattr **rta = arg;	struct rtmsg *r = NLMSG_DATA(nlh);	if (dn_fib_check_attr(r, rta))		return -EINVAL;	tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);	if (tb)		return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));	return -ESRCH;}static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct dn_fib_table *tb;	struct rtattr **rta = arg;	struct rtmsg *r = NLMSG_DATA(nlh);	if (dn_fib_check_attr(r, rta))		return -EINVAL;	tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);	if (tb)		return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));	return -ENOBUFS;}static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa){	struct dn_fib_table *tb;	struct {		struct nlmsghdr nlh;		struct rtmsg rtm;	} req;	struct dn_kern_rta rta;	memset(&req.rtm, 0, sizeof(req.rtm));	memset(&rta, 0, sizeof(rta));	if (type == RTN_UNICAST)		tb = dn_fib_get_table(RT_MIN_TABLE, 1);	else		tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);	if (tb == NULL)		return;	req.nlh.nlmsg_len = sizeof(req);	req.nlh.nlmsg_type = cmd;	req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;	req.nlh.nlmsg_pid = 0;	req.nlh.nlmsg_seq = 0;	req.rtm.rtm_dst_len = dst_len;	req.rtm.rtm_table = tb->n;	req.rtm.rtm_protocol = RTPROT_KERNEL;	req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);	req.rtm.rtm_type = type;	rta.rta_dst = &dst;	rta.rta_prefsrc = &ifa->ifa_local;	rta.rta_oif = &ifa->ifa_dev->dev->ifindex;	if (cmd == RTM_NEWROUTE)		tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);	else		tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);}static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa){	fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);#if 0	if (!(dev->flags&IFF_UP))		return;	/* In the future, we will want to add default routes here */#endif}static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa){	int found_it = 0;	struct net_device *dev;	struct dn_dev *dn_db;	struct dn_ifaddr *ifa2;	ASSERT_RTNL();	/* Scan device list */	read_lock(&dev_base_lock);	for_each_netdev(&init_net, dev) {		dn_db = dev->dn_ptr;		if (dn_db == NULL)			continue;		for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) {			if (ifa2->ifa_local == ifa->ifa_local) {				found_it = 1;				break;			}		}	}	read_unlock(&dev_base_lock);	if (found_it == 0) {		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);		if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {			if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))				dn_fib_flush();		}	}}static void dn_fib_disable_addr(struct net_device *dev, int force){	if (dn_fib_sync_down(0, dev, force))		dn_fib_flush();	dn_rt_cache_flush(0);	neigh_ifdown(&dn_neigh_table, dev);}static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr){	struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;	switch(event) {		case NETDEV_UP:			dn_fib_add_ifaddr(ifa);			dn_fib_sync_up(ifa->ifa_dev->dev);			dn_rt_cache_flush(-1);			break;		case NETDEV_DOWN:			dn_fib_del_ifaddr(ifa);			if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {				dn_fib_disable_addr(ifa->ifa_dev->dev, 1);			} else {				dn_rt_cache_flush(-1);			}			break;	}	return NOTIFY_DONE;}static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force){	int ret = 0;	int scope = RT_SCOPE_NOWHERE;	if (force)		scope = -1;	for_fib_info() {		/*		 * This makes no sense for DECnet.... we will almost		 * certainly have more than one local address the same		 * over all our interfaces. It needs thinking about		 * some more.		 */		if (local && fi->fib_prefsrc == local) {			fi->fib_flags |= RTNH_F_DEAD;			ret++;		} else if (dev && fi->fib_nhs) {			int dead = 0;			change_nexthops(fi) {				if (nh->nh_flags&RTNH_F_DEAD)					dead++;				else if (nh->nh_dev == dev &&						nh->nh_scope != scope) {					spin_lock_bh(&dn_fib_multipath_lock);					nh->nh_flags |= RTNH_F_DEAD;					fi->fib_power -= nh->nh_power;					nh->nh_power = 0;					spin_unlock_bh(&dn_fib_multipath_lock);					dead++;				}			} endfor_nexthops(fi)			if (dead == fi->fib_nhs) {				fi->fib_flags |= RTNH_F_DEAD;				ret++;			}		}	} endfor_fib_info();	return ret;}static int dn_fib_sync_up(struct net_device *dev){	int ret = 0;	if (!(dev->flags&IFF_UP))		return 0;	for_fib_info() {		int alive = 0;		change_nexthops(fi) {			if (!(nh->nh_flags&RTNH_F_DEAD)) {				alive++;				continue;			}			if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))				continue;			if (nh->nh_dev != dev || dev->dn_ptr == NULL)				continue;			alive++;			spin_lock_bh(&dn_fib_multipath_lock);			nh->nh_power = 0;			nh->nh_flags &= ~RTNH_F_DEAD;			spin_unlock_bh(&dn_fib_multipath_lock);		} endfor_nexthops(fi);		if (alive > 0) {			fi->fib_flags &= ~RTNH_F_DEAD;			ret++;		}	} endfor_fib_info();	return ret;}static struct notifier_block dn_fib_dnaddr_notifier = {	.notifier_call = dn_fib_dnaddr_event,};void __exit dn_fib_cleanup(void){	dn_fib_table_cleanup();	dn_fib_rules_cleanup();	unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);}void __init dn_fib_init(void){	dn_fib_table_init();	dn_fib_rules_init();	register_dnaddr_notifier(&dn_fib_dnaddr_notifier);	rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL);	rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL);}

⌨️ 快捷键说明

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