⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 neighbour.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	read_lock_bh(&tbl->lock);	ndtmsg->ndtm_family = tbl->family;	ndtmsg->ndtm_pad1   = 0;	ndtmsg->ndtm_pad2   = 0;	NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);	NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);	NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);	NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);	NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);	{		unsigned long now = jiffies;		unsigned int flush_delta = now - tbl->last_flush;		unsigned int rand_delta = now - tbl->last_rand;		struct ndt_config ndc = {			.ndtc_key_len		= tbl->key_len,			.ndtc_entry_size	= tbl->entry_size,			.ndtc_entries		= atomic_read(&tbl->entries),			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),			.ndtc_hash_rnd		= tbl->hash_rnd,			.ndtc_hash_mask		= tbl->hash_mask,			.ndtc_hash_chain_gc	= tbl->hash_chain_gc,			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,		};		NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);	}	{		int cpu;		struct ndt_stats ndst;		memset(&ndst, 0, sizeof(ndst));		for_each_possible_cpu(cpu) {			struct neigh_statistics	*st;			st = per_cpu_ptr(tbl->stats, cpu);			ndst.ndts_allocs		+= st->allocs;			ndst.ndts_destroys		+= st->destroys;			ndst.ndts_hash_grows		+= st->hash_grows;			ndst.ndts_res_failed		+= st->res_failed;			ndst.ndts_lookups		+= st->lookups;			ndst.ndts_hits			+= st->hits;			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;		}		NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);	}	BUG_ON(tbl->parms.dev);	if (neightbl_fill_parms(skb, &tbl->parms) < 0)		goto nla_put_failure;	read_unlock_bh(&tbl->lock);	return nlmsg_end(skb, nlh);nla_put_failure:	read_unlock_bh(&tbl->lock);	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int neightbl_fill_param_info(struct sk_buff *skb,				    struct neigh_table *tbl,				    struct neigh_parms *parms,				    u32 pid, u32 seq, int type,				    unsigned int flags){	struct ndtmsg *ndtmsg;	struct nlmsghdr *nlh;	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);	if (nlh == NULL)		return -EMSGSIZE;	ndtmsg = nlmsg_data(nlh);	read_lock_bh(&tbl->lock);	ndtmsg->ndtm_family = tbl->family;	ndtmsg->ndtm_pad1   = 0;	ndtmsg->ndtm_pad2   = 0;	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||	    neightbl_fill_parms(skb, parms) < 0)		goto errout;	read_unlock_bh(&tbl->lock);	return nlmsg_end(skb, nlh);errout:	read_unlock_bh(&tbl->lock);	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,						      int ifindex){	struct neigh_parms *p;	for (p = &tbl->parms; p; p = p->next)		if ((p->dev && p->dev->ifindex == ifindex) ||		    (!p->dev && !ifindex))			return p;	return NULL;}static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {	[NDTA_NAME]		= { .type = NLA_STRING },	[NDTA_THRESH1]		= { .type = NLA_U32 },	[NDTA_THRESH2]		= { .type = NLA_U32 },	[NDTA_THRESH3]		= { .type = NLA_U32 },	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },	[NDTA_PARMS]		= { .type = NLA_NESTED },};static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {	[NDTPA_IFINDEX]			= { .type = NLA_U32 },	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },};static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct neigh_table *tbl;	struct ndtmsg *ndtmsg;	struct nlattr *tb[NDTA_MAX+1];	int err;	err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,			  nl_neightbl_policy);	if (err < 0)		goto errout;	if (tb[NDTA_NAME] == NULL) {		err = -EINVAL;		goto errout;	}	ndtmsg = nlmsg_data(nlh);	read_lock(&neigh_tbl_lock);	for (tbl = neigh_tables; tbl; tbl = tbl->next) {		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)			continue;		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)			break;	}	if (tbl == NULL) {		err = -ENOENT;		goto errout_locked;	}	/*	 * We acquire tbl->lock to be nice to the periodic timers and	 * make sure they always see a consistent set of values.	 */	write_lock_bh(&tbl->lock);	if (tb[NDTA_PARMS]) {		struct nlattr *tbp[NDTPA_MAX+1];		struct neigh_parms *p;		int i, ifindex = 0;		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],				       nl_ntbl_parm_policy);		if (err < 0)			goto errout_tbl_lock;		if (tbp[NDTPA_IFINDEX])			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);		p = lookup_neigh_params(tbl, ifindex);		if (p == NULL) {			err = -ENOENT;			goto errout_tbl_lock;		}		for (i = 1; i <= NDTPA_MAX; i++) {			if (tbp[i] == NULL)				continue;			switch (i) {			case NDTPA_QUEUE_LEN:				p->queue_len = nla_get_u32(tbp[i]);				break;			case NDTPA_PROXY_QLEN:				p->proxy_qlen = nla_get_u32(tbp[i]);				break;			case NDTPA_APP_PROBES:				p->app_probes = nla_get_u32(tbp[i]);				break;			case NDTPA_UCAST_PROBES:				p->ucast_probes = nla_get_u32(tbp[i]);				break;			case NDTPA_MCAST_PROBES:				p->mcast_probes = nla_get_u32(tbp[i]);				break;			case NDTPA_BASE_REACHABLE_TIME:				p->base_reachable_time = nla_get_msecs(tbp[i]);				break;			case NDTPA_GC_STALETIME:				p->gc_staletime = nla_get_msecs(tbp[i]);				break;			case NDTPA_DELAY_PROBE_TIME:				p->delay_probe_time = nla_get_msecs(tbp[i]);				break;			case NDTPA_RETRANS_TIME:				p->retrans_time = nla_get_msecs(tbp[i]);				break;			case NDTPA_ANYCAST_DELAY:				p->anycast_delay = nla_get_msecs(tbp[i]);				break;			case NDTPA_PROXY_DELAY:				p->proxy_delay = nla_get_msecs(tbp[i]);				break;			case NDTPA_LOCKTIME:				p->locktime = nla_get_msecs(tbp[i]);				break;			}		}	}	if (tb[NDTA_THRESH1])		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);	if (tb[NDTA_THRESH2])		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);	if (tb[NDTA_THRESH3])		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);	if (tb[NDTA_GC_INTERVAL])		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);	err = 0;errout_tbl_lock:	write_unlock_bh(&tbl->lock);errout_locked:	read_unlock(&neigh_tbl_lock);errout:	return err;}static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb){	int family, tidx, nidx = 0;	int tbl_skip = cb->args[0];	int neigh_skip = cb->args[1];	struct neigh_table *tbl;	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;	read_lock(&neigh_tbl_lock);	for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {		struct neigh_parms *p;		if (tidx < tbl_skip || (family && tbl->family != family))			continue;		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,				       NLM_F_MULTI) <= 0)			break;		for (nidx = 0, p = tbl->parms.next; p; p = p->next, nidx++) {			if (nidx < neigh_skip)				continue;			if (neightbl_fill_param_info(skb, tbl, p,						     NETLINK_CB(cb->skb).pid,						     cb->nlh->nlmsg_seq,						     RTM_NEWNEIGHTBL,						     NLM_F_MULTI) <= 0)				goto out;		}		neigh_skip = 0;	}out:	read_unlock(&neigh_tbl_lock);	cb->args[0] = tidx;	cb->args[1] = nidx;	return skb->len;}static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,			   u32 pid, u32 seq, int type, unsigned int flags){	unsigned long now = jiffies;	struct nda_cacheinfo ci;	struct nlmsghdr *nlh;	struct ndmsg *ndm;	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);	if (nlh == NULL)		return -EMSGSIZE;	ndm = nlmsg_data(nlh);	ndm->ndm_family	 = neigh->ops->family;	ndm->ndm_pad1    = 0;	ndm->ndm_pad2    = 0;	ndm->ndm_flags	 = neigh->flags;	ndm->ndm_type	 = neigh->type;	ndm->ndm_ifindex = neigh->dev->ifindex;	NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);	read_lock_bh(&neigh->lock);	ndm->ndm_state	 = neigh->nud_state;	if ((neigh->nud_state & NUD_VALID) &&	    nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) {		read_unlock_bh(&neigh->lock);		goto nla_put_failure;	}	ci.ndm_used	 = now - neigh->used;	ci.ndm_confirmed = now - neigh->confirmed;	ci.ndm_updated	 = now - neigh->updated;	ci.ndm_refcnt	 = atomic_read(&neigh->refcnt) - 1;	read_unlock_bh(&neigh->lock);	NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));	NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);	return nlmsg_end(skb, nlh);nla_put_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static void neigh_update_notify(struct neighbour *neigh){	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);	__neigh_notify(neigh, RTM_NEWNEIGH, 0);}static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,			    struct netlink_callback *cb){	struct neighbour *n;	int rc, h, s_h = cb->args[1];	int idx, s_idx = idx = cb->args[2];	read_lock_bh(&tbl->lock);	for (h = 0; h <= tbl->hash_mask; h++) {		if (h < s_h)			continue;		if (h > s_h)			s_idx = 0;		for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {			if (idx < s_idx)				continue;			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,					    cb->nlh->nlmsg_seq,					    RTM_NEWNEIGH,					    NLM_F_MULTI) <= 0) {				read_unlock_bh(&tbl->lock);				rc = -1;				goto out;			}		}	}	read_unlock_bh(&tbl->lock);	rc = skb->len;out:	cb->args[1] = h;	cb->args[2] = idx;	return rc;}static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb){	struct neigh_table *tbl;	int t, family, s_t;	read_lock(&neigh_tbl_lock);	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;	s_t = cb->args[0];	for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {		if (t < s_t || (family && tbl->family != family))			continue;		if (t > s_t)			memset(&cb->args[1], 0, sizeof(cb->args) -						sizeof(cb->args[0]));		if (neigh_dump_table(tbl, skb, cb) < 0)			break;	}	read_unlock(&neigh_tbl_lock);	cb->args[0] = t;	return skb->len;}void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie){	int chain;	read_lock_bh(&tbl->lock);	for (chain = 0; chain <= tbl->hash_mask; chain++) {		struct neighbour *n;		for (n = tbl->hash_buckets[chain]; n; n = n->next)			cb(n, cookie);	}	read_unlock_bh(&tbl->lock);}EXPORT_SYMBOL(neigh_for_each);/* The tbl->lock must be held as a writer and BH disabled. */void __neigh_for_each_release(struct neigh_table *tbl,			      int (*cb)(struct neighbour *)){	int chain;	for (chain = 0; chain <= tbl->hash_mask; chain++) {		struct neighbour *n, **np;		np = &tbl->hash_buckets[chain];		while ((n = *np) != NULL) {			int release;			write_lock(&n->lock);			release = cb(n);			if (release) {				*np = n->next;				n->dead = 1;			} else				np = &n->next;			write_unlock(&n->lock);			if (release)				neigh_cleanup_and_release(n);		}	}}EXPORT_SYMBOL(__neigh_for_each_release);#ifdef CONFIG_PROC_FSstatic struct neighbour *neigh_get_first(struct seq_file *seq){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	struct neighbour *n = NULL;	int bucket = state->bucket;	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;	for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {		n = tbl->hash_buckets[bucket];		while (n) {			if (state->neigh_sub_iter) {				loff_t fakep = 0;				void *v;				v = state->neigh_sub_iter(state, n, &fakep);				if (!v)					goto next;			}			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))				break;			if (n->nud_state & ~NUD_NOARP)				break;		next:			n = n->next;		}		if (n)			break;	}	state->bucket = bucket;	return n;}static struct neighbour *neigh_get_next(struct seq_file *seq,					struct neighbour *n,					loff_t *pos){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	if (state->neigh_sub_iter) {		void *v = state->neigh_sub_iter(state, n, pos);		if (v)			return n;	}	n = n->next;	while (1) {		while (n) {			if (state->neigh_sub_iter) {				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;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -