📄 fib_trie.c
字号:
cb->args[4] = i; return -1; } i++; } cb->args[4] = i; return skb->len;}static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb){ int h, s_h; struct list_head *fa_head; struct leaf *l = NULL; s_h = cb->args[3]; for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { if (h < s_h) continue; if (h > s_h) memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0])); fa_head = get_fa_head(l, plen); if (!fa_head) continue; if (list_empty(fa_head)) continue; if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) { cb->args[3] = h; return -1; } } cb->args[3] = h; return skb->len;}static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb){ int m, s_m; struct trie *t = (struct trie *) tb->tb_data; s_m = cb->args[2]; rcu_read_lock(); for (m = 0; m <= 32; m++) { if (m < s_m) continue; if (m > s_m) memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) { cb->args[2] = m; goto out; } } rcu_read_unlock(); cb->args[2] = m; return skb->len;out: rcu_read_unlock(); return -1;}/* Fix more generic FIB names for init later */#ifdef CONFIG_IP_MULTIPLE_TABLESstruct fib_table * fib_hash_init(u32 id)#elsestruct fib_table * __init fib_hash_init(u32 id)#endif{ struct fib_table *tb; struct trie *t; if (fn_alias_kmem == NULL) fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias), 0, SLAB_HWCACHE_ALIGN, NULL); tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie), GFP_KERNEL); if (tb == NULL) return NULL; tb->tb_id = id; tb->tb_lookup = fn_trie_lookup; tb->tb_insert = fn_trie_insert; tb->tb_delete = fn_trie_delete; tb->tb_flush = fn_trie_flush; tb->tb_select_default = fn_trie_select_default; tb->tb_dump = fn_trie_dump; memset(tb->tb_data, 0, sizeof(struct trie)); t = (struct trie *) tb->tb_data; trie_init(t); if (id == RT_TABLE_LOCAL) trie_local = t; else if (id == RT_TABLE_MAIN) trie_main = t; if (id == RT_TABLE_LOCAL) printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION); return tb;}#ifdef CONFIG_PROC_FS/* Depth first Trie walk iterator */struct fib_trie_iter { struct tnode *tnode; struct trie *trie; unsigned index; unsigned depth;};static struct node *fib_trie_get_next(struct fib_trie_iter *iter){ struct tnode *tn = iter->tnode; unsigned cindex = iter->index; struct tnode *p; /* A single entry routing table */ if (!tn) return NULL; pr_debug("get_next iter={node=%p index=%d depth=%d}\n", iter->tnode, iter->index, iter->depth);rescan: while (cindex < (1<<tn->bits)) { struct node *n = tnode_get_child(tn, cindex); if (n) { if (IS_LEAF(n)) { iter->tnode = tn; iter->index = cindex + 1; } else { /* push down one level */ iter->tnode = (struct tnode *) n; iter->index = 0; ++iter->depth; } return n; } ++cindex; } /* Current node exhausted, pop back up */ p = node_parent((struct node *)tn); if (p) { cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; tn = p; --iter->depth; goto rescan; } /* got root? */ return NULL;}static struct node *fib_trie_get_first(struct fib_trie_iter *iter, struct trie *t){ struct node *n ; if (!t) return NULL; n = rcu_dereference(t->trie); if (!iter) return NULL; if (n) { if (IS_TNODE(n)) { iter->tnode = (struct tnode *) n; iter->trie = t; iter->index = 0; iter->depth = 1; } else { iter->tnode = NULL; iter->trie = t; iter->index = 0; iter->depth = 0; } return n; } return NULL;}static void trie_collect_stats(struct trie *t, struct trie_stat *s){ struct node *n; struct fib_trie_iter iter; memset(s, 0, sizeof(*s)); rcu_read_lock(); for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { if (IS_LEAF(n)) { s->leaves++; s->totdepth += iter.depth; if (iter.depth > s->maxdepth) s->maxdepth = iter.depth; } else { const struct tnode *tn = (const struct tnode *) n; int i; s->tnodes++; if (tn->bits < MAX_STAT_DEPTH) s->nodesizes[tn->bits]++; for (i = 0; i < (1<<tn->bits); i++) if (!tn->child[i]) s->nullpointers++; } } rcu_read_unlock();}/* * This outputs /proc/net/fib_triestats */static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat){ unsigned i, max, pointers, bytes, avdepth; if (stat->leaves) avdepth = stat->totdepth*100 / stat->leaves; else avdepth = 0; seq_printf(seq, "\tAver depth: %d.%02d\n", avdepth / 100, avdepth % 100 ); seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); seq_printf(seq, "\tLeaves: %u\n", stat->leaves); bytes = sizeof(struct leaf) * stat->leaves; seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes); bytes += sizeof(struct tnode) * stat->tnodes; max = MAX_STAT_DEPTH; while (max > 0 && stat->nodesizes[max-1] == 0) max--; pointers = 0; for (i = 1; i <= max; i++) if (stat->nodesizes[i] != 0) { seq_printf(seq, " %d: %d", i, stat->nodesizes[i]); pointers += (1<<i) * stat->nodesizes[i]; } seq_putc(seq, '\n'); seq_printf(seq, "\tPointers: %d\n", pointers); bytes += sizeof(struct node *) * pointers; seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers); seq_printf(seq, "Total size: %d kB\n", (bytes + 1023) / 1024);#ifdef CONFIG_IP_FIB_TRIE_STATS seq_printf(seq, "Counters:\n---------\n"); seq_printf(seq,"gets = %d\n", t->stats.gets); seq_printf(seq,"backtracks = %d\n", t->stats.backtrack); seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);#ifdef CLEAR_STATS memset(&(t->stats), 0, sizeof(t->stats));#endif#endif /* CONFIG_IP_FIB_TRIE_STATS */}static int fib_triestat_seq_show(struct seq_file *seq, void *v){ struct trie_stat *stat; stat = kmalloc(sizeof(*stat), GFP_KERNEL); if (!stat) return -ENOMEM; seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n", sizeof(struct leaf), sizeof(struct tnode)); if (trie_local) { seq_printf(seq, "Local:\n"); trie_collect_stats(trie_local, stat); trie_show_stats(seq, stat); } if (trie_main) { seq_printf(seq, "Main:\n"); trie_collect_stats(trie_main, stat); trie_show_stats(seq, stat); } kfree(stat); return 0;}static int fib_triestat_seq_open(struct inode *inode, struct file *file){ return single_open(file, fib_triestat_seq_show, NULL);}static const struct file_operations fib_triestat_fops = { .owner = THIS_MODULE, .open = fib_triestat_seq_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos){ loff_t idx = 0; struct node *n; for (n = fib_trie_get_first(iter, trie_local); n; ++idx, n = fib_trie_get_next(iter)) { if (pos == idx) return n; } for (n = fib_trie_get_first(iter, trie_main); n; ++idx, n = fib_trie_get_next(iter)) { if (pos == idx) return n; } return NULL;}static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos){ rcu_read_lock(); if (*pos == 0) return SEQ_START_TOKEN; return fib_trie_get_idx(seq->private, *pos - 1);}static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct fib_trie_iter *iter = seq->private; void *l = v; ++*pos; if (v == SEQ_START_TOKEN) return fib_trie_get_idx(iter, 0); v = fib_trie_get_next(iter); BUG_ON(v == l); if (v) return v; /* continue scan in next trie */ if (iter->trie == trie_local) return fib_trie_get_first(iter, trie_main); return NULL;}static void fib_trie_seq_stop(struct seq_file *seq, void *v){ rcu_read_unlock();}static void seq_indent(struct seq_file *seq, int n){ while (n-- > 0) seq_puts(seq, " ");}static inline const char *rtn_scope(enum rt_scope_t s){ static char buf[32]; switch (s) { case RT_SCOPE_UNIVERSE: return "universe"; case RT_SCOPE_SITE: return "site"; case RT_SCOPE_LINK: return "link"; case RT_SCOPE_HOST: return "host"; case RT_SCOPE_NOWHERE: return "nowhere"; default: snprintf(buf, sizeof(buf), "scope=%d", s); return buf; }}static const char *rtn_type_names[__RTN_MAX] = { [RTN_UNSPEC] = "UNSPEC", [RTN_UNICAST] = "UNICAST", [RTN_LOCAL] = "LOCAL", [RTN_BROADCAST] = "BROADCAST", [RTN_ANYCAST] = "ANYCAST", [RTN_MULTICAST] = "MULTICAST", [RTN_BLACKHOLE] = "BLACKHOLE", [RTN_UNREACHABLE] = "UNREACHABLE", [RTN_PROHIBIT] = "PROHIBIT", [RTN_THROW] = "THROW", [RTN_NAT] = "NAT", [RTN_XRESOLVE] = "XRESOLVE",};static inline const char *rtn_type(unsigned t){ static char buf[32]; if (t < __RTN_MAX && rtn_type_names[t]) return rtn_type_names[t]; snprintf(buf, sizeof(buf), "type %d", t); return buf;}/* Pretty print the trie */static int fib_trie_seq_show(struct seq_file *seq, void *v){ const struct fib_trie_iter *iter = seq->private; struct node *n = v; if (v == SEQ_START_TOKEN) return 0; if (!node_parent(n)) { if (iter->trie == trie_local) seq_puts(seq, "<local>:\n"); else seq_puts(seq, "<main>:\n"); } if (IS_TNODE(n)) { struct tnode *tn = (struct tnode *) n; __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); seq_indent(seq, iter->depth-1); seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, tn->empty_children); } else { struct leaf *l = (struct leaf *) n; int i; __be32 val = htonl(l->key); seq_indent(seq, iter->depth); seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); for (i = 32; i >= 0; i--) { struct leaf_info *li = find_leaf_info(l, i); if (li) { struct fib_alias *fa; list_for_each_entry_rcu(fa, &li->falh, fa_list) { seq_indent(seq, iter->depth+1); seq_printf(seq, " /%d %s %s", i, rtn_scope(fa->fa_scope), rtn_type(fa->fa_type)); if (fa->fa_tos) seq_printf(seq, "tos =%d\n", fa->fa_tos); seq_putc(seq, '\n'); } } } } return 0;}static const struct seq_operations fib_trie_seq_ops = { .start = fib_trie_seq_start, .next = fib_trie_seq_next, .stop = fib_trie_seq_stop, .show = fib_trie_seq_show,};static int fib_trie_seq_open(struct inode *inode, struct file *file){ return seq_open_private(file, &fib_trie_seq_ops, sizeof(struct fib_trie_iter));}static const struct file_operations fib_trie_fops = { .owner = THIS_MODULE, .open = fib_trie_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi){ static unsigned type2flags[RTN_MAX + 1] = { [7] = RTF_REJECT, [8] = RTF_REJECT, }; unsigned flags = type2flags[type]; if (fi && fi->fib_nh->nh_gw) flags |= RTF_GATEWAY; if (mask == htonl(0xFFFFFFFF)) flags |= RTF_HOST; flags |= RTF_UP; return flags;}/* * This outputs /proc/net/route. * The format of the file is not supposed to be changed * and needs to be same as fib_hash output to avoid breaking * legacy utilities */static int fib_route_seq_show(struct seq_file *seq, void *v){ const struct fib_trie_iter *iter = seq->private; struct leaf *l = v; int i; char bf[128]; if (v == SEQ_START_TOKEN) { seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway " "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" "\tWindow\tIRTT"); return 0; } if (iter->trie == trie_local) return 0; if (IS_TNODE(l)) return 0; for (i=32; i>=0; i--) { struct leaf_info *li = find_leaf_info(l, i); struct fib_alias *fa; __be32 mask, prefix; if (!li) continue; mask = inet_make_mask(li->plen); prefix = htonl(l->key); list_for_each_entry_rcu(fa, &li->falh, fa_list) { const struct fib_info *fi = fa->fa_info; unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); if (fa->fa_type == RTN_BROADCAST || fa->fa_type == RTN_MULTICAST) continue; if (fi) snprintf(bf, sizeof(bf), "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", fi->fib_dev ? fi->fib_dev->name : "*", prefix, fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, mask, (fi->fib_advmss ? fi->fib_advmss + 40 : 0), fi->fib_window, fi->fib_rtt >> 3); else snprintf(bf, sizeof(bf), "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0); seq_printf(seq, "%-127s\n", bf); } } return 0;}static const struct seq_operations fib_route_seq_ops = { .start = fib_trie_seq_start, .next = fib_trie_seq_next, .stop = fib_trie_seq_stop, .show = fib_route_seq_show,};static int fib_route_seq_open(struct inode *inode, struct file *file){ return seq_open_private(file, &fib_route_seq_ops, sizeof(struct fib_trie_iter));}static const struct file_operations fib_route_fops = { .owner = THIS_MODULE, .open = fib_route_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};int __init fib_proc_init(void){ if (!proc_net_fops_create(&init_net, "fib_trie", S_IRUGO, &fib_trie_fops)) goto out1; if (!proc_net_fops_create(&init_net, "fib_triestat", S_IRUGO, &fib_triestat_fops)) goto out2; if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_route_fops)) goto out3; return 0;out3: proc_net_remove(&init_net, "fib_triestat");out2: proc_net_remove(&init_net, "fib_trie");out1: return -ENOMEM;}void __init fib_proc_exit(void){ proc_net_remove(&init_net, "fib_trie"); proc_net_remove(&init_net, "fib_triestat"); proc_net_remove(&init_net, "route");}#endif /* CONFIG_PROC_FS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -