网络子系统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; }
相关文章推荐
- 网络子系统62_路由子系统处理设备事件
- 网络子系统67_路由表处理设备事件
- 网络子系统68_路由表处理设备ip配置事件
- input子系统四之事件处理过程分析
- 多个进程同时等待网络的连接事件,当这个事件发生时,这些进程被同时唤醒,我们知道进程被唤醒,需要进行内核重新调度,这样每个进程同时去响应这一个事件,而最终只有一个进程能处理事件成功,其他的进程在处理该事件失败后重新休眠或其他。
- Android系统之事件处理子系统启动过程的学习和分析
- input子系统事件处理层(evdev)的环形缓冲区
- 网络子系统59_策略路由、多路径路由
- 链路层GRO的处理 (linux网络子系统学习 第八节)
- Spice工作原理及代码剖析:02 Spice网络事件处理模型
- 网络子系统44_ip协议源路由选项处理
- input子系统四 input事件处理
- linux 输入子系统(3)----事件处理(input_handler层)
- 网络子系统60_路由子系统初始化蓝图
- jQuery 1.7 正式版已经可以下载使用。jQuery是一个JavaScript库,它简化了HTML文档遍历,事件处理,动画和为网络快速发展的Ajax交互。jQuery 1.7 版本加入了新的事件API .on() 和 .off(),提
- 网络子系统18_arp对代理的处理
- 【网络】select/poll/epoll事件处理图示
- Linux input子系统分析---4、事件处理层分析
- xutils3网络请求结合下拉刷新事件处理缓存
- 网络子系统45_ip协议tos处理