📄 route.c
字号:
{ struct flow_rule *frule; struct rt6_info *nrt = NULL; struct pol_chain *pol; for (pol = rt6_pol_list; pol; pol = pol->next) { struct fib6_node *fn; struct rt6_info *sprt; fn = fib6_lookup(pol->rules, daddr, saddr); do { for (sprt = fn->leaf; sprt; sprt=sprt->u.next) { int res; frule = sprt->rt6i_flowr;#if RT6_DEBUG >= 2 if (frule == NULL) { printk(KERN_DEBUG "NULL flowr\n"); goto error; }#endif res = frule->ops->accept(rt, sprt, args, &nrt); switch (res) { case FLOWR_SELECT: goto found; case FLOWR_CLEAR: goto next_policy; case FLOWR_NODECISION: break; default: goto error; }; } fn = fn->parent; } while ((fn->fn_flags & RTN_TL_ROOT) == 0); next_policy: }error: dst_clone(&ip6_null_entry.u.dst); return &ip6_null_entry;found: if (nrt == NULL) goto error; nrt->rt6i_flags |= RTF_CACHE; dst_clone(&nrt->u.dst); err = rt6_ins(nrt); if (err) nrt->u.dst.error = err; return nrt;}#endifstatic int fib6_ifdown(struct rt6_info *rt, void *arg){ if (((void*)rt->rt6i_dev == arg || arg == NULL) && rt != &ip6_null_entry) { RT6_TRACE("deleted by ifdown %p\n", rt); return -1; } return 0;}void rt6_ifdown(struct net_device *dev){ write_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); write_unlock_bh(&rt6_lock);}struct rt6_mtu_change_arg{ struct net_device *dev; unsigned mtu;};static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg){ struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; /* In IPv6 pmtu discovery is not optional, so that RTAX_MTU lock cannot disable it. We still use this lock to block changes caused by addrconf/ndisc. */ if (rt->rt6i_dev == arg->dev && rt->u.dst.pmtu > arg->mtu && !(rt->u.dst.mxlock&(1<<RTAX_MTU))) rt->u.dst.pmtu = arg->mtu; rt->u.dst.advmss = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss); if (rt->u.dst.advmss > 65535-20) rt->u.dst.advmss = 65535; return 0;}void rt6_mtu_change(struct net_device *dev, unsigned mtu){ struct rt6_mtu_change_arg arg; arg.dev = dev; arg.mtu = mtu; read_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg); read_unlock_bh(&rt6_lock);}static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, struct in6_rtmsg *rtmsg){ memset(rtmsg, 0, sizeof(*rtmsg)); rtmsg->rtmsg_dst_len = r->rtm_dst_len; rtmsg->rtmsg_src_len = r->rtm_src_len; rtmsg->rtmsg_flags = RTF_UP; if (r->rtm_type == RTN_UNREACHABLE) rtmsg->rtmsg_flags |= RTF_REJECT; if (rta[RTA_GATEWAY-1]) { if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) return -EINVAL; memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16); rtmsg->rtmsg_flags |= RTF_GATEWAY; } if (rta[RTA_DST-1]) { if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3)) return -EINVAL; memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3)); } if (rta[RTA_SRC-1]) { if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3)) return -EINVAL; memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3)); } if (rta[RTA_OIF-1]) { if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int))) return -EINVAL; memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); } if (rta[RTA_PRIORITY-1]) { if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4)) return -EINVAL; memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4); } return 0;}int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg){ struct rtmsg *r = NLMSG_DATA(nlh); struct in6_rtmsg rtmsg; if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; return ip6_route_del(&rtmsg);}int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg){ struct rtmsg *r = NLMSG_DATA(nlh); struct in6_rtmsg rtmsg; if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; return ip6_route_add(&rtmsg);}struct rt6_rtnl_dump_arg{ struct sk_buff *skb; struct netlink_callback *cb;};static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *dst, struct in6_addr *src, int iif, int type, u32 pid, u32 seq){ struct rtmsg *rtm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; struct rta_cacheinfo ci; nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm)); rtm = NLMSG_DATA(nlh); rtm->rtm_family = AF_INET6; rtm->rtm_dst_len = rt->rt6i_dst.plen; rtm->rtm_src_len = rt->rt6i_src.plen; rtm->rtm_tos = 0; rtm->rtm_table = RT_TABLE_MAIN; if (rt->rt6i_flags&RTF_REJECT) rtm->rtm_type = RTN_UNREACHABLE; 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 = RTPROT_BOOT; 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.mxlock) < 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 - rt->u.dst.lastuse; if (rt->rt6i_expires) ci.rta_expires = 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; return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq);}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; struct sk_buff *skb; struct flowi fl; struct rt6_info *rt; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) return -ENOBUFS; /* 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)); fl.proto = 0; fl.nl_u.ip6_u.daddr = NULL; fl.nl_u.ip6_u.saddr = NULL; fl.uli_u.icmpt.type = 0; fl.uli_u.icmpt.code = 0; if (rta[RTA_SRC-1]) fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]); if (rta[RTA_DST-1]) fl.nl_u.ip6_u.daddr = (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) return -ENODEV; } 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.nl_u.ip6_u.daddr, fl.nl_u.ip6_u.saddr, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq); if (err < 0) return -EMSGSIZE; err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); if (err < 0) return err; return 0;}void inet6_rt_notify(int event, struct rt6_info *rt){ 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) < 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_proc_stats(char *buffer, char **start, off_t offset, int length){ int len; len = sprintf(buffer, "%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)); len -= offset; if (len > length) len = length; if(len < 0) len = 0; *start = buffer + offset; return len;}#endif /* CONFIG_PROC_FS */#ifdef CONFIG_SYSCTLstatic int flush_delay;staticint ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ if (write) { proc_dointvec(ctl, write, filp, buffer, lenp); if (flush_delay < 0) flush_delay = 0; fib6_run_gc((unsigned long)flush_delay); return 0; } else return -EINVAL;}ctl_table ipv6_route_table[] = { {NET_IPV6_ROUTE_FLUSH, "flush", &flush_delay, sizeof(int), 0644, NULL, &ipv6_sysctl_rtcache_flush}, {NET_IPV6_ROUTE_GC_THRESH, "gc_thresh", &ip6_dst_ops.gc_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_ROUTE_MAX_SIZE, "max_size", &ip6_rt_max_size, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval", &ip6_rt_gc_min_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout", &ip6_rt_gc_timeout, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval", &ip6_rt_gc_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity", &ip6_rt_gc_elasticity, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires", &ip6_rt_mtu_expires, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss", &ip6_rt_min_advmss, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, {0}};#endifvoid __init ip6_route_init(void){ ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); fib6_init();#ifdef CONFIG_PROC_FS proc_net_create("ipv6_route", 0, rt6_proc_info); proc_net_create("rt6_stats", 0, rt6_proc_stats);#endif}#ifdef MODULEvoid ip6_route_cleanup(void){#ifdef CONFIG_PROC_FS proc_net_remove("ipv6_route"); proc_net_remove("rt6_stats");#endif rt6_ifdown(NULL); fib6_gc_cleanup();}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -