📄 neighbour.c
字号:
} 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\n"); return 0; } seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " "%08lx %08lx %08lx %08lx\n", atomic_read(&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 const 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 const 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 */static inline size_t neigh_nlmsg_size(void){ return NLMSG_ALIGN(sizeof(struct ndmsg)) + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ + nla_total_size(sizeof(struct nda_cacheinfo)) + nla_total_size(4); /* NDA_PROBES */}static void __neigh_notify(struct neighbour *n, int type, int flags){ struct sk_buff *skb; int err = -ENOBUFS; skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = neigh_fill_info(skb, n, 0, 0, type, flags); if (err < 0) { /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);errout: if (err < 0) rtnl_set_sk_err(RTNLGRP_NEIGH, err);}#ifdef CONFIG_ARPDvoid neigh_app_ns(struct neighbour *n){ __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);}#endif /* CONFIG_ARPD */#ifdef CONFIG_SYSCTLstatic struct neigh_sysctl_table { struct ctl_table_header *sysctl_header; ctl_table neigh_vars[__NET_NEIGH_MAX]; 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 __read_mostly = { .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, }, { .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, }, { .procname = "anycast_delay", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .procname = "proxy_delay", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .procname = "locktime", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_RETRANS_TIME_MS, .procname = "retrans_time_ms", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_ms_jiffies, .strategy = &sysctl_ms_jiffies, }, { .ctl_name = NET_NEIGH_REACHABLE_TIME_MS, .procname = "base_reachable_time_ms", .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_ms_jiffies, .strategy = &sysctl_ms_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, ctl_handler *strategy){ struct neigh_sysctl_table *t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); const char *dev_name_source = NULL; char *dev_name = NULL; int err = 0; if (!t) return -ENOBUFS; 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; 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; t->neigh_vars[12].data = &p->retrans_time; t->neigh_vars[13].data = &p->base_reachable_time; if (dev) { dev_name_source = dev->name; t->neigh_dev[0].ctl_name = dev->ifindex; /* Terminate the table early */ memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14])); } else { dev_name_source = t->neigh_dev[0].procname; t->neigh_vars[14].data = (int *)(p + 1); t->neigh_vars[15].data = (int *)(p + 1) + 1; t->neigh_vars[16].data = (int *)(p + 1) + 2; t->neigh_vars[17].data = (int *)(p + 1) + 3; } if (handler || strategy) { /* RetransTime */ t->neigh_vars[3].proc_handler = handler; t->neigh_vars[3].strategy = strategy; t->neigh_vars[3].extra1 = dev; if (!strategy) t->neigh_vars[3].ctl_name = CTL_UNNUMBERED; /* ReachableTime */ t->neigh_vars[4].proc_handler = handler; t->neigh_vars[4].strategy = strategy; t->neigh_vars[4].extra1 = dev; if (!strategy) t->neigh_vars[4].ctl_name = CTL_UNNUMBERED; /* RetransTime (in milliseconds)*/ t->neigh_vars[12].proc_handler = handler; t->neigh_vars[12].strategy = strategy; t->neigh_vars[12].extra1 = dev; if (!strategy) t->neigh_vars[12].ctl_name = CTL_UNNUMBERED; /* ReachableTime (in milliseconds) */ t->neigh_vars[13].proc_handler = handler; t->neigh_vars[13].strategy = strategy; t->neigh_vars[13].extra1 = dev; if (!strategy) t->neigh_vars[13].ctl_name = CTL_UNNUMBERED; } dev_name = kstrdup(dev_name_source, GFP_KERNEL); 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); 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 */static int __init neigh_init(void){ rtnl_register(PF_U
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -