// 路由子系统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; }
时间: 2024-08-02 21:06:25