📄 route.c
字号:
struct nlmsghdr *nlh; unsigned char *b = skb->tail; struct rta_cacheinfo ci;#ifdef CONFIG_IP_MROUTE struct rtattr *eptr;#endif nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r)); r = NLMSG_DATA(nlh); nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; r->rtm_family = AF_INET; r->rtm_dst_len = 32; r->rtm_src_len = 0; r->rtm_tos = rt->key.tos; r->rtm_table = RT_TABLE_MAIN; r->rtm_type = rt->rt_type; r->rtm_scope = RT_SCOPE_UNIVERSE; r->rtm_protocol = RTPROT_UNSPEC; r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; if (rt->rt_flags & RTCF_NOTIFY) r->rtm_flags |= RTM_F_NOTIFY; RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); if (rt->key.src) { r->rtm_src_len = 32; RTA_PUT(skb, RTA_SRC, 4, &rt->key.src); } if (rt->u.dst.dev) RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);#ifdef CONFIG_NET_CLS_ROUTE if (rt->u.dst.tclassid) RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);#endif if (rt->key.iif) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); else if (rt->rt_src != rt->key.src) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); if (rt->rt_dst != rt->rt_gateway) RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) goto rtattr_failure; ci.rta_lastuse = jiffies - rt->u.dst.lastuse; ci.rta_used = rt->u.dst.__use; ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); if (rt->u.dst.expires) ci.rta_expires = rt->u.dst.expires - jiffies; else ci.rta_expires = 0; ci.rta_error = rt->u.dst.error; ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; if (rt->peer) { ci.rta_id = rt->peer->ip_id_count; if (rt->peer->tcp_ts_stamp) { ci.rta_ts = rt->peer->tcp_ts; ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; } }#ifdef CONFIG_IP_MROUTE eptr = (struct rtattr*)skb->tail;#endif RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); if (rt->key.iif) {#ifdef CONFIG_IP_MROUTE u32 dst = rt->rt_dst; if (MULTICAST(dst) && !LOCAL_MCAST(dst) && ipv4_devconf.mc_forwarding) { int err = ipmr_get_route(skb, r, nowait); if (err <= 0) { if (!nowait) { if (err == 0) return 0; goto nlmsg_failure; } else { if (err == -EMSGSIZE) goto nlmsg_failure; ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err; } } } else#endif RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif); } nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}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; /* 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 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; skb->protocol = __constant_htons(ETH_P_IP); skb->dev = dev; local_bh_disable(); 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 { int oif = 0; if (rta[RTA_OIF - 1]) memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif); } if (err) { kfree_skb(skb); goto out; } skb->dst = &rt->u.dst; if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; 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); if (!err) goto out; if (err < 0) { err = -EMSGSIZE; goto out; } err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); if (err > 0) err = 0;out: return err;}int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb){ struct rtable *rt; int h, s_h; int idx, s_idx; s_h = cb->args[0]; s_idx = idx = cb->args[1]; for (h = 0; h <= rt_hash_mask; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; read_lock_bh(&rt_hash_table[h].lock); for (rt = rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) { if (idx < s_idx) continue; skb->dst = dst_clone(&rt->u.dst); if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) { dst_release(xchg(&skb->dst, NULL)); read_unlock_bh(&rt_hash_table[h].lock); goto done; } dst_release(xchg(&skb->dst, NULL)); } read_unlock_bh(&rt_hash_table[h].lock); }done: cb->args[0] = h; cb->args[1] = idx; return skb->len;}void ip_rt_multicast_event(struct in_device *in_dev){ rt_cache_flush(0);}#ifdef CONFIG_SYSCTLstatic int flush_delay;static int ipv4_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); rt_cache_flush(flush_delay); return 0; } return -EINVAL;}static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context){ int delay; if (newlen != sizeof(int)) return -EINVAL; if (get_user(delay, (int *)newval)) return -EFAULT; rt_cache_flush(delay); return 0;}ctl_table ipv4_route_table[] = { { ctl_name: NET_IPV4_ROUTE_FLUSH, procname: "flush", data: &flush_delay, maxlen: sizeof(int), mode: 0644, proc_handler: &ipv4_sysctl_rtcache_flush, strategy: &ipv4_sysctl_rtcache_flush_strategy, }, { ctl_name: NET_IPV4_ROUTE_MIN_DELAY, procname: "min_delay", data: &ip_rt_min_delay, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_MAX_DELAY, procname: "max_delay", data: &ip_rt_max_delay, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_GC_THRESH, procname: "gc_thresh", data: &ipv4_dst_ops.gc_thresh, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_MAX_SIZE, procname: "max_size", data: &ip_rt_max_size, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_GC_MIN_INTERVAL, procname: "gc_min_interval", data: &ip_rt_gc_min_interval, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_GC_TIMEOUT, procname: "gc_timeout", data: &ip_rt_gc_timeout, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_GC_INTERVAL, procname: "gc_interval", data: &ip_rt_gc_interval, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_REDIRECT_LOAD, procname: "redirect_load", data: &ip_rt_redirect_load, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_REDIRECT_NUMBER, procname: "redirect_number", data: &ip_rt_redirect_number, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_REDIRECT_SILENCE, procname: "redirect_silence", data: &ip_rt_redirect_silence, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_ERROR_COST, procname: "error_cost", data: &ip_rt_error_cost, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_ERROR_BURST, procname: "error_burst", data: &ip_rt_error_burst, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_GC_ELASTICITY, procname: "gc_elasticity", data: &ip_rt_gc_elasticity, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_MTU_EXPIRES, procname: "mtu_expires", data: &ip_rt_mtu_expires, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec_jiffies, strategy: &sysctl_jiffies, }, { ctl_name: NET_IPV4_ROUTE_MIN_PMTU, procname: "min_pmtu", data: &ip_rt_min_pmtu, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { ctl_name: NET_IPV4_ROUTE_MIN_ADVMSS, procname: "min_adv_mss", data: &ip_rt_min_advmss, maxlen: sizeof(int), mode: 0644, proc_handler: &proc_dointvec, }, { 0 }};#endif#ifdef CONFIG_NET_CLS_ROUTEstruct ip_rt_acct *ip_rt_acct;static int ip_rt_acct_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data){ *start = buffer; if ((offset & 3) || (length & 3)) return -EIO; if (offset + length >= sizeof(struct ip_rt_acct) * 256) { length = sizeof(struct ip_rt_acct) * 256 - offset; *eof = 1; } if (length > 0) { u32 *dst = (u32*)buffer; u32 *src = (u32*)(((u8*)ip_rt_acct) + offset); memcpy(dst, src, length);#ifdef CONFIG_SMP if (smp_num_cpus > 1 || cpu_logical_map(0) != 0) { int i; int cnt = length / 4; for (i = 0; i < smp_num_cpus; i++) { int cpu = cpu_logical_map(i); int k; if (cpu == 0) continue; src = (u32*)(((u8*)ip_rt_acct) + offset + cpu * 256 * sizeof(struct ip_rt_acct)); for (k = 0; k < cnt; k++) dst[k] += src[k]; } }#endif return length; } return 0;}#endifvoid __init ip_rt_init(void){ int i, order, goal;#ifdef CONFIG_NET_CLS_ROUTE for (order = 0; (PAGE_SIZE << order) < 256 * sizeof(ip_rt_acct) * NR_CPUS; order++) /* NOTHING */; ip_rt_acct = (struct ip_rt_acct *)__get_free_pages(GFP_KERNEL, order); if (!ip_rt_acct) panic("IP: failed to allocate ip_rt_acct\n"); memset(ip_rt_acct, 0, PAGE_SIZE << order);#endif ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!ipv4_dst_ops.kmem_cachep) panic("IP: failed to allocate ip_dst_cache\n"); goal = num_physpages >> (26 - PAGE_SHIFT); for (order = 0; (1UL << order) < goal; order++) /* NOTHING */; do { rt_hash_mask = (1UL << order) * PAGE_SIZE / sizeof(struct rt_hash_bucket); while (rt_hash_mask & (rt_hash_mask - 1)) rt_hash_mask--; rt_hash_table = (struct rt_hash_bucket *) __get_free_pages(GFP_ATOMIC, order); } while (rt_hash_table == NULL && --order > 0); if (!rt_hash_table) panic("Failed to allocate IP route cache hash table\n"); printk("IP: routing cache hash table of %u buckets, %ldKbytes\n", rt_hash_mask, (long) (rt_hash_mask * sizeof(struct rt_hash_bucket)) / 1024); for (rt_hash_log = 0; (1 << rt_hash_log) != rt_hash_mask; rt_hash_log++) /* NOTHING */; rt_hash_mask--; for (i = 0; i <= rt_hash_mask; i++) { rt_hash_table[i].lock = RW_LOCK_UNLOCKED; rt_hash_table[i].chain = NULL; } ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); ip_rt_max_size = (rt_hash_mask + 1) * 16; devinet_init(); ip_fib_init(); rt_flush_timer.function = rt_run_flush; rt_periodic_timer.function = rt_check_expire; /* All the timers, started at system startup tend to synchronize. Perturb it a bit. */ rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval + ip_rt_gc_interval; add_timer(&rt_periodic_timer); proc_net_create ("rt_cache", 0, rt_cache_get_info); proc_net_create ("rt_cache_stat", 0, rt_cache_stat_get_info);#ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read, NULL);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -