📄 route.c
字号:
else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) rtm->rtm_type = RTN_LOCAL; else rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_protocol = rt->rt6i_protocol; if (rt->rt6i_flags&RTF_DYNAMIC) rtm->rtm_protocol = RTPROT_REDIRECT; else if (rt->rt6i_flags&(RTF_ADDRCONF|RTF_ALLONLINK)) rtm->rtm_protocol = RTPROT_KERNEL; else if (rt->rt6i_flags&RTF_DEFAULT) rtm->rtm_protocol = RTPROT_RA; if (rt->rt6i_flags&RTF_CACHE) rtm->rtm_flags |= RTM_F_CLONED; if (dst) { RTA_PUT(skb, RTA_DST, 16, dst); rtm->rtm_dst_len = 128; } else if (rtm->rtm_dst_len) RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);#ifdef CONFIG_IPV6_SUBTREES if (src) { RTA_PUT(skb, RTA_SRC, 16, src); rtm->rtm_src_len = 128; } else if (rtm->rtm_src_len) RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);#endif if (iif) RTA_PUT(skb, RTA_IIF, 4, &iif); else if (dst) { struct in6_addr saddr_buf; if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; if (rt->u.dst.neighbour) RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); if (rt->u.dst.dev) RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex); RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric); ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); if (rt->rt6i_expires) ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); else ci.rta_expires = 0; ci.rta_used = rt->u.dst.__use; ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); ci.rta_error = rt->u.dst.error; ci.rta_id = 0; ci.rta_ts = 0; ci.rta_tsage = 0; RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}static int rt6_dump_route(struct rt6_info *rt, void *p_arg){ struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; int prefix; if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) { struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh); prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; } else prefix = 0; return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, NULL, prefix);}static int fib6_dump_node(struct fib6_walker_t *w){ int res; struct rt6_info *rt; for (rt = w->leaf; rt; rt = rt->u.next) { res = rt6_dump_route(rt, w->args); if (res < 0) { /* Frame is full, suspend walking */ w->leaf = rt; return 1; } BUG_TRAP(res!=0); } w->leaf = NULL; return 0;}static void fib6_dump_end(struct netlink_callback *cb){ struct fib6_walker_t *w = (void*)cb->args[0]; if (w) { cb->args[0] = 0; fib6_walker_unlink(w); kfree(w); } if (cb->args[1]) { cb->done = (void*)cb->args[1]; cb->args[1] = 0; }}static int fib6_dump_done(struct netlink_callback *cb){ fib6_dump_end(cb); return cb->done(cb);}int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb){ struct rt6_rtnl_dump_arg arg; struct fib6_walker_t *w; int res; arg.skb = skb; arg.cb = cb; w = (void*)cb->args[0]; if (w == NULL) { /* New dump: * * 1. hook callback destructor. */ cb->args[1] = (long)cb->done; cb->done = fib6_dump_done; /* * 2. allocate and initialize walker. */ w = kmalloc(sizeof(*w), GFP_ATOMIC); if (w == NULL) return -ENOMEM; RT6_TRACE("dump<%p", w); memset(w, 0, sizeof(*w)); w->root = &ip6_routing_table; w->func = fib6_dump_node; w->args = &arg; cb->args[0] = (long)w; read_lock_bh(&rt6_lock); res = fib6_walk(w); read_unlock_bh(&rt6_lock); } else { w->args = &arg; read_lock_bh(&rt6_lock); res = fib6_walk_continue(w); read_unlock_bh(&rt6_lock); }#if RT6_DEBUG >= 3 if (res <= 0 && skb->len == 0) RT6_TRACE("%p>dump end\n", w);#endif res = res < 0 ? res : skb->len; /* res < 0 is an error. (really, impossible) res == 0 means that dump is complete, but skb still can contain data. res > 0 dump is not complete, but frame is full. */ /* Destroy walker, if dump of this table is complete. */ if (res <= 0) fib6_dump_end(cb); return res;}int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg){ struct rtattr **rta = arg; int iif = 0; int err = -ENOBUFS; struct sk_buff *skb; struct flowi fl; struct rt6_info *rt; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) goto out; /* Reserve room for dummy headers, this skb can pass through good chunk of routing engine. */ skb->mac.raw = skb->data; skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); memset(&fl, 0, sizeof(fl)); if (rta[RTA_SRC-1]) ipv6_addr_copy(&fl.fl6_src, (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); if (rta[RTA_DST-1]) ipv6_addr_copy(&fl.fl6_dst, (struct in6_addr*)RTA_DATA(rta[RTA_DST-1])); if (rta[RTA_IIF-1]) memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); if (iif) { struct net_device *dev; dev = __dev_get_by_index(iif); if (!dev) { err = -ENODEV; goto out_free; } } fl.oif = 0; if (rta[RTA_OIF-1]) memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); rt = (struct rt6_info*)ip6_route_output(NULL, &fl); skb->dst = &rt->u.dst; NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, nlh, 0); if (err < 0) { err = -EMSGSIZE; goto out_free; } 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; }void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh){ struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); skb = alloc_skb(size, gfp_any()); if (!skb) { netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; } if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; } NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE; netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any());}/* * /proc */#ifdef CONFIG_PROC_FS#define RT6_INFO_LEN (32 + 4 + 32 + 4 + 32 + 40 + 5 + 1)struct rt6_proc_arg{ char *buffer; int offset; int length; int skip; int len;};static int rt6_info_route(struct rt6_info *rt, void *p_arg){ struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg; int i; if (arg->skip < arg->offset / RT6_INFO_LEN) { arg->skip++; return 0; } if (arg->len >= arg->length) return 0; for (i=0; i<16; i++) { sprintf(arg->buffer + arg->len, "%02x", rt->rt6i_dst.addr.s6_addr[i]); arg->len += 2; } arg->len += sprintf(arg->buffer + arg->len, " %02x ", rt->rt6i_dst.plen);#ifdef CONFIG_IPV6_SUBTREES for (i=0; i<16; i++) { sprintf(arg->buffer + arg->len, "%02x", rt->rt6i_src.addr.s6_addr[i]); arg->len += 2; } arg->len += sprintf(arg->buffer + arg->len, " %02x ", rt->rt6i_src.plen);#else sprintf(arg->buffer + arg->len, "00000000000000000000000000000000 00 "); arg->len += 36;#endif if (rt->rt6i_nexthop) { for (i=0; i<16; i++) { sprintf(arg->buffer + arg->len, "%02x", rt->rt6i_nexthop->primary_key[i]); arg->len += 2; } } else { sprintf(arg->buffer + arg->len, "00000000000000000000000000000000"); arg->len += 32; } arg->len += sprintf(arg->buffer + arg->len, " %08x %08x %08x %08x %8s\n", rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt), rt->u.dst.__use, rt->rt6i_flags, rt->rt6i_dev ? rt->rt6i_dev->name : ""); return 0;}static int rt6_proc_info(char *buffer, char **start, off_t offset, int length){ struct rt6_proc_arg arg; arg.buffer = buffer; arg.offset = offset; arg.length = length; arg.skip = 0; arg.len = 0; read_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg); read_unlock_bh(&rt6_lock); *start = buffer; if (offset) *start += offset % RT6_INFO_LEN; arg.len -= offset % RT6_INFO_LEN; if (arg.len > length) arg.len = length; if (arg.len < 0) arg.len = 0; return arg.len;}extern struct rt6_statistics rt6_stats;static int rt6_stats_seq_show(struct seq_file *seq, void *v){ seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", rt6_stats.fib_nodes, rt6_stats.fib_route_nodes, rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries, rt6_stats.fib_rt_cache, atomic_read(&ip6_dst_ops.entries), rt6_stats.fib_discarded_routes); return 0;}static int rt6_stats_seq_open(struct inode *inode, struct file *file){ return single_open(file, rt6_stats_seq_show, NULL);}static struct file_operations rt6_stats_seq_fops = { .owner = THIS_MODULE, .open = rt6_stats_seq_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};#endif /* CONFIG_PROC_FS */#ifdef CONFIG_SYSCTLstatic int flush_delay;staticint ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos){ if (write) { proc_dointvec(ctl, write, filp, buffer, lenp, ppos); if (flush_delay < 0) flush_delay = 0; fib6_run_gc((unsigned long)flush_delay); return 0; } else return -EINVAL;}ctl_table ipv6_route_table[] = { { .ctl_name = NET_IPV6_ROUTE_FLUSH, .procname = "flush", .data = &flush_delay, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &ipv6_sysctl_rtcache_flush }, { .ctl_name = NET_IPV6_ROUTE_GC_THRESH, .procname = "gc_thresh", .data = &ip6_dst_ops.gc_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV6_ROUTE_MAX_SIZE, .procname = "max_size", .data = &ip6_rt_max_size, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL, .procname = "gc_min_interval", .data = &ip6_rt_gc_min_interval, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_TIMEOUT, .procname = "gc_timeout", .data = &ip6_rt_gc_timeout, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_INTERVAL, .procname = "gc_interval", .data = &ip6_rt_gc_interval, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_ELASTICITY, .procname = "gc_elasticity", .data = &ip6_rt_gc_elasticity, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_MTU_EXPIRES, .procname = "mtu_expires", .data = &ip6_rt_mtu_expires, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_MIN_ADVMSS, .procname = "min_adv_mss", .data = &ip6_rt_min_advmss, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = 0 }};#endifvoid __init ip6_route_init(void){ struct proc_dir_entry *p; ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!ip6_dst_ops.kmem_cachep) panic("cannot create ip6_dst_cache"); fib6_init();#ifdef CONFIG_PROC_FS p = proc_net_create("ipv6_route", 0, rt6_proc_info); if (p) p->owner = THIS_MODULE; proc_net_fops_create("rt6_stats", S_IRUGO, &rt6_stats_seq_fops);#endif#ifdef CONFIG_XFRM xfrm6_init();#endif}void __exit ip6_route_cleanup(void){#ifdef CONFIG_PROC_FS proc_net_remove("ipv6_route"); proc_net_remove("rt6_stats");#endif#ifdef CONFIG_XFRM xfrm6_fini();#endif rt6_ifdown(NULL); fib6_gc_cleanup(); kmem_cache_destroy(ip6_dst_ops.kmem_cachep);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -