您的位置:首页 > 理论基础 > 计算机网络

网络子系统63_路由子系统处理netlink事件

2013-10-17 18:42 597 查看
//	路由子系统netlink控制块
//		在ip_rt_init->devinet_init中注册。
1.1 static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
[4] = { .doit	 = inet_rtm_newaddr,  },
[5] = { .doit	 = inet_rtm_deladdr,  },
[6] = { .dumpit = inet_dump_ifaddr,  },
[8] = { .doit	 = inet_rtm_newroute, },
[9] = { .doit	 = inet_rtm_delroute, },
[10] = { .doit	 = inet_rtm_getroute, .dumpit = inet_dump_fib, },
#ifdef CONFIG_IP_MULTIPLE_TABLES
[16] = { .doit	 = inet_rtm_newrule, },
[17] = { .doit	 = inet_rtm_delrule, },
[18] = { .dumpit = inet_dump_rules,  },
#endif
};

//	为设备配置ip地址
//	函数主要任务:
//		1.检查有效性
//			1.1 网络部分<=32,提供了ip地址
//		2.分配in_ifaddr并填充信息
//		3.将in_ifaddr插入到in_device中

1.2 static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct net_device *dev;
struct in_device *in_dev;
struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
struct in_ifaddr *ifa;
int rc = -EINVAL;
// 有效性检查
//	网路地址部分 <= 32
if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
goto out;

rc = -ENODEV;
//通过设备index获取设备描述符
if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
goto out;

rc = -ENOBUFS;
//获取设备配置信息
if ((in_dev = __in_dev_get(dev)) == NULL) {
//第一次配置设备,则创建配置信息
in_dev = inetdev_init(dev);
}
//分配ip地址
if ((ifa = inet_alloc_ifa()) == NULL)
goto out;
//如果地址指派给隧道接口:
//	ifa->ifa_local为隧道的本地地址,ifa->ifa_address为远程地址
//否则:
// ifa->ifa_local, ifa->ifa_address均为本地地址
if (!rta[IFA_ADDRESS - 1])
rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
//网络地址部分
ifa->ifa_prefixlen = ifm->ifa_prefixlen;
//掩码
ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
//广播地址
if (rta[IFA_BROADCAST - 1])
memcpy(&ifa->ifa_broadcast,
RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
//选播地址
if (rta[IFA_ANYCAST - 1])
memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
//ifa_flags标示主辅地址
ifa->ifa_flags = ifm->ifa_flags;
ifa->ifa_scope = ifm->ifa_scope;
in_dev_hold(in_dev);
ifa->ifa_dev   = in_dev;
//设备别名
if (rta[IFA_LABEL - 1])
rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
//将新地址插入到in_device中
rc = inet_insert_ifa(ifa);
out:
return rc;
}

//	删除设备ip地址
//	函数主要任务:
//		1.获取设备的配置描述符in_device
//		2.从配置描述符中删除ip信息
1.3 static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct in_device *in_dev;
struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
struct in_ifaddr *ifa, **ifap;
//获取设备描述
if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
goto out;
__in_dev_put(in_dev);

for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
if ((rta[IFA_LOCAL - 1] &&
memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
&ifa->ifa_local, 4)) ||
(rta[IFA_LABEL - 1] &&
rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) ||
(rta[IFA_ADDRESS - 1] &&
(ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
!inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
ifa))))
continue;
//从in_device 删除配置的ip地址
inet_del_ifa(in_dev, ifap, 1);
return 0;
}
out:
return -EADDRNOTAVAIL;
}

//	添加路由
//		通过id选择路由表,通过特定于路由表的回调函数添加路由项
1.4 int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct fib_table * tb;
struct rtattr **rta = arg;
struct rtmsg *r = NLMSG_DATA(nlh);

if (inet_check_attr(r, rta))
return -EINVAL;
//根据指定的id,选择路由表
tb = fib_new_table(r->rtm_table);
if (tb)	//有路由表的回调函数添加一条新路由
return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
return -ENOBUFS;
}

//	获取路由信息
//	函数主要任务:
//		1.指定了入口设备,通过ip_route_input路由数据包,获取路由信息
//		2.否则通过出口路由,获取路由信息
//		3.将获取的路由信息通过netlink应答
1.5 int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{
struct rtattr **rta = arg;
struct rtmsg *rtm = NLMSG_DATA(nlh);
struct rtable *rt = NULL;
u32 dst = 0;
u32 src = 0;
int iif = 0;
int err = -ENOBUFS;
struct sk_buff *skb;

skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb)
goto out;

skb->mac.raw = skb->data;
skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));

if (rta[RTA_SRC - 1])
memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4);
if (rta[RTA_DST - 1])
memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4);
if (rta[RTA_IIF - 1])
memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int));
//入口路由
if (iif) {
struct net_device *dev = __dev_get_by_index(iif);
err = -ENODEV;
if (!dev)
goto out_free;
skb->protocol	= htons(ETH_P_IP);
skb->dev	= dev;
local_bh_disable();
//路由此skb,获取路由信息
err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
local_bh_enable();
rt = (struct rtable*)skb->dst;
if (!err && rt->u.dst.error)
err = -rt->u.dst.error;
//出口路由
} else {
//构造查找关键字
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = rtm->rtm_tos } } };
int oif = 0;
//出口设备
if (rta[RTA_OIF - 1])
memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
fl.oif = oif;
//出口路由
err = ip_route_output_key(&rt, &fl);
}
if (err)
goto out_free;

skb->dst = &rt->u.dst;
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
//netlink控制块
NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;

err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
RTM_NEWROUTE, 0);
//通过netlink应答
err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
if (err > 0)
err = 0;
out:	return err;

out_free:
kfree_skb(skb);
goto out;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux kernel ip 路由
相关文章推荐