📄 neighbour.c
字号:
void *v = state->neigh_sub_iter(state, n, pos); if (v) return n; goto next; } if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) break; if (n->nud_state & ~NUD_NOARP) break; next: n = n->next; } if (n) break; if (++state->bucket > tbl->hash_mask) break; n = tbl->hash_buckets[state->bucket]; } if (n && pos) --(*pos); return n;}static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos){ struct neighbour *n = neigh_get_first(seq); if (n) { while (*pos) { n = neigh_get_next(seq, n, pos); if (!n) break; } } return *pos ? NULL : n;}static struct pneigh_entry *pneigh_get_first(struct seq_file *seq){ struct neigh_seq_state *state = seq->private; struct neigh_table *tbl = state->tbl; struct pneigh_entry *pn = NULL; int bucket = state->bucket; state->flags |= NEIGH_SEQ_IS_PNEIGH; for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { pn = tbl->phash_buckets[bucket]; if (pn) break; } state->bucket = bucket; return pn;}static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, struct pneigh_entry *pn, loff_t *pos){ struct neigh_seq_state *state = seq->private; struct neigh_table *tbl = state->tbl; pn = pn->next; while (!pn) { if (++state->bucket > PNEIGH_HASHMASK) break; pn = tbl->phash_buckets[state->bucket]; if (pn) break; } if (pn && pos) --(*pos); return pn;}static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos){ struct pneigh_entry *pn = pneigh_get_first(seq); if (pn) { while (*pos) { pn = pneigh_get_next(seq, pn, pos); if (!pn) break; } } return *pos ? NULL : pn;}static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos){ struct neigh_seq_state *state = seq->private; void *rc; rc = neigh_get_idx(seq, pos); if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY)) rc = pneigh_get_idx(seq, pos); return rc;}void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags){ struct neigh_seq_state *state = seq->private; loff_t pos_minus_one; state->tbl = tbl; state->bucket = 0; state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH); read_lock_bh(&tbl->lock); pos_minus_one = *pos - 1; return *pos ? neigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN;}EXPORT_SYMBOL(neigh_seq_start);void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct neigh_seq_state *state; void *rc; if (v == SEQ_START_TOKEN) { rc = neigh_get_idx(seq, pos); goto out; } state = seq->private; if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) { rc = neigh_get_next(seq, v, NULL); if (rc) goto out; if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY)) rc = pneigh_get_first(seq); } else { BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY); rc = pneigh_get_next(seq, v, NULL); }out: ++(*pos); return rc;}EXPORT_SYMBOL(neigh_seq_next);void neigh_seq_stop(struct seq_file *seq, void *v){ struct neigh_seq_state *state = seq->private; struct neigh_table *tbl = state->tbl; read_unlock_bh(&tbl->lock);}EXPORT_SYMBOL(neigh_seq_stop);/* statistics via seq_file */static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos){ struct proc_dir_entry *pde = seq->private; struct neigh_table *tbl = pde->data; int cpu; if (*pos == 0) return SEQ_START_TOKEN; for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; *pos = cpu+1; return per_cpu_ptr(tbl->stats, cpu); } return NULL;}static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct proc_dir_entry *pde = seq->private; struct neigh_table *tbl = pde->data; int cpu; for (cpu = *pos; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; *pos = cpu+1; return per_cpu_ptr(tbl->stats, cpu); } return NULL;}static void neigh_stat_seq_stop(struct seq_file *seq, void *v){}static int neigh_stat_seq_show(struct seq_file *seq, void *v){ struct proc_dir_entry *pde = seq->private; struct neigh_table *tbl = pde->data; struct neigh_statistics *st = v; if (v == SEQ_START_TOKEN) { seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); return 0; } seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " "%08lx %08lx %08lx %08lx\n", tbl->entries, st->allocs, st->destroys, st->hash_grows, st->lookups, st->hits, st->res_failed, st->rcv_probes_mcast, st->rcv_probes_ucast, st->periodic_gc_runs, st->forced_gc_runs ); return 0;}static struct seq_operations neigh_stat_seq_ops = { .start = neigh_stat_seq_start, .next = neigh_stat_seq_next, .stop = neigh_stat_seq_stop, .show = neigh_stat_seq_show,};static int neigh_stat_seq_open(struct inode *inode, struct file *file){ int ret = seq_open(file, &neigh_stat_seq_ops); if (!ret) { struct seq_file *sf = file->private_data; sf->private = PDE(inode); } return ret;};static struct file_operations neigh_stat_seq_fops = { .owner = THIS_MODULE, .open = neigh_stat_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#endif /* CONFIG_PROC_FS */#ifdef CONFIG_ARPDvoid neigh_app_ns(struct neighbour *n){ struct nlmsghdr *nlh; int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256); struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC); if (!skb) return; if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) { kfree_skb(skb); return; } nlh = (struct nlmsghdr *)skb->data; nlh->nlmsg_flags = NLM_F_REQUEST; NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH; netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);}static void neigh_app_notify(struct neighbour *n){ struct nlmsghdr *nlh; int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256); struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC); if (!skb) return; if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) { kfree_skb(skb); return; } nlh = (struct nlmsghdr *)skb->data; NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH; netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);}#endif /* CONFIG_ARPD */#ifdef CONFIG_SYSCTLstatic struct neigh_sysctl_table { struct ctl_table_header *sysctl_header; ctl_table neigh_vars[17]; ctl_table neigh_dev[2]; ctl_table neigh_neigh_dir[2]; ctl_table neigh_proto_dir[2]; ctl_table neigh_root_dir[2];} neigh_sysctl_template = { .neigh_vars = { { .ctl_name = NET_NEIGH_MCAST_SOLICIT, .procname = "mcast_solicit", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_UCAST_SOLICIT, .procname = "ucast_solicit", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_APP_SOLICIT, .procname = "app_solicit", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_RETRANS_TIME, .procname = "retrans_time", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_REACHABLE_TIME, .procname = "base_reachable_time", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_NEIGH_DELAY_PROBE_TIME, .procname = "delay_first_probe_time", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_NEIGH_GC_STALE_TIME, .procname = "gc_stale_time", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_NEIGH_UNRES_QLEN, .procname = "unres_qlen", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_PROXY_QLEN, .procname = "proxy_qlen", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_ANYCAST_DELAY, .procname = "anycast_delay", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_PROXY_DELAY, .procname = "proxy_delay", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_LOCKTIME, .procname = "locktime", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_GC_INTERVAL, .procname = "gc_interval", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, { .ctl_name = NET_NEIGH_GC_THRESH1, .procname = "gc_thresh1", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_GC_THRESH2, .procname = "gc_thresh2", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NEIGH_GC_THRESH3, .procname = "gc_thresh3", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, }, .neigh_dev = { { .ctl_name = NET_PROTO_CONF_DEFAULT, .procname = "default", .mode = 0555, }, }, .neigh_neigh_dir = { { .procname = "neigh", .mode = 0555, }, }, .neigh_proto_dir = { { .mode = 0555, }, }, .neigh_root_dir = { { .ctl_name = CTL_NET, .procname = "net", .mode = 0555, }, },};int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, int p_id, int pdev_id, char *p_name, proc_handler *handler){ struct neigh_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL); const char *dev_name_source = NULL; char *dev_name = NULL; int err = 0; if (!t) return -ENOBUFS; memcpy(t, &neigh_sysctl_template, sizeof(*t)); t->neigh_vars[0].data = &p->mcast_probes; t->neigh_vars[1].data = &p->ucast_probes; t->neigh_vars[2].data = &p->app_probes; t->neigh_vars[3].data = &p->retrans_time; if (handler) { t->neigh_vars[3].proc_handler = handler; t->neigh_vars[3].extra1 = dev; } t->neigh_vars[4].data = &p->base_reachable_time; t->neigh_vars[5].data = &p->delay_probe_time; t->neigh_vars[6].data = &p->gc_staletime; t->neigh_vars[7].data = &p->queue_len; t->neigh_vars[8].data = &p->proxy_qlen; t->neigh_vars[9].data = &p->anycast_delay; t->neigh_vars[10].data = &p->proxy_delay; t->neigh_vars[11].data = &p->locktime; dev_name_source = t->neigh_dev[0].procname; if (dev) { dev_name_source = dev->name; t->neigh_dev[0].ctl_name = dev->ifindex; memset(&t->neigh_vars[12], 0, sizeof(ctl_table)); } else { t->neigh_vars[12].data = (int *)(p + 1); t->neigh_vars[13].data = (int *)(p + 1) + 1; t->neigh_vars[14].data = (int *)(p + 1) + 2; t->neigh_vars[15].data = (int *)(p + 1) + 3; } dev_name = net_sysctl_strdup(dev_name_source); if (!dev_name) { err = -ENOBUFS; goto free; } t->neigh_dev[0].procname = dev_name; t->neigh_neigh_dir[0].ctl_name = pdev_id; t->neigh_proto_dir[0].procname = p_name; t->neigh_proto_dir[0].ctl_name = p_id; t->neigh_dev[0].child = t->neigh_vars; t->neigh_neigh_dir[0].child = t->neigh_dev; t->neigh_proto_dir[0].child = t->neigh_neigh_dir; t->neigh_root_dir[0].child = t->neigh_proto_dir; t->sysctl_header = register_sysctl_table(t->neigh_root_dir, 0); if (!t->sysctl_header) { err = -ENOBUFS; goto free_procname; } p->sysctl_table = t; return 0; /* error path */ free_procname: kfree(dev_name); free: kfree(t); return err;}void neigh_sysctl_unregister(struct neigh_parms *p){ if (p->sysctl_table) { struct neigh_sysctl_table *t = p->sysctl_table; p->sysctl_table = NULL; unregister_sysctl_table(t->sysctl_header); kfree(t->neigh_dev[0].procname); kfree(t); }}#endif /* CONFIG_SYSCTL */EXPORT_SYMBOL(__neigh_event_send);EXPORT_SYMBOL(neigh_add);EXPORT_SYMBOL(neigh_changeaddr);EXPORT_SYMBOL(neigh_compat_output);EXPORT_SYMBOL(neigh_connected_output);EXPORT_SYMBOL(neigh_create);EXPORT_SYMBOL(neigh_delete);EXPORT_SYMBOL(neigh_destroy);EXPORT_SYMBOL(neigh_dump_info);EXPORT_SYMBOL(neigh_event_ns);EXPORT_SYMBOL(neigh_ifdown);EXPORT_SYMBOL(neigh_lookup);EXPORT_SYMBOL(neigh_lookup_nodev);EXPORT_SYMBOL(neigh_parms_alloc);EXPORT_SYMBOL(neigh_parms_release);EXPORT_SYMBOL(neigh_rand_reach_time);EXPORT_SYMBOL(neigh_resolve_output);EXPORT_SYMBOL(neigh_table_clear);EXPORT_SYMBOL(neigh_table_init);EXPORT_SYMBOL(neigh_update);EXPORT_SYMBOL(neigh_update_hhs);EXPORT_SYMBOL(pneigh_enqueue);EXPORT_SYMBOL(pneigh_lookup);#ifdef CONFIG_ARPDEXPORT_SYMBOL(neigh_app_ns);#endif#ifdef CONFIG_SYSCTLEXPORT_SYMBOL(neigh_sysctl_register);EXPORT_SYMBOL(neigh_sysctl_unregister);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -