diff options
Diffstat (limited to 'net/core/neighbour.c')
| -rw-r--r-- | net/core/neighbour.c | 112 | 
1 files changed, 56 insertions, 56 deletions
| diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 70fe9e10ac86..3de654256028 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -397,25 +397,15 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,  			       struct net_device *dev)  {  	struct neighbour *n; -	int key_len = tbl->key_len; -	u32 hash_val; -	struct neigh_hash_table *nht;  	NEIGH_CACHE_STAT_INC(tbl, lookups);  	rcu_read_lock_bh(); -	nht = rcu_dereference_bh(tbl->nht); -	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); - -	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); -	     n != NULL; -	     n = rcu_dereference_bh(n->next)) { -		if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { -			if (!atomic_inc_not_zero(&n->refcnt)) -				n = NULL; -			NEIGH_CACHE_STAT_INC(tbl, hits); -			break; -		} +	n = __neigh_lookup_noref(tbl, pkey, dev); +	if (n) { +		if (!atomic_inc_not_zero(&n->refcnt)) +			n = NULL; +		NEIGH_CACHE_STAT_INC(tbl, hits);  	}  	rcu_read_unlock_bh(); @@ -601,7 +591,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,  	if (!n)  		goto out; -	write_pnet(&n->net, hold_net(net)); +	write_pnet(&n->net, net);  	memcpy(n->key, pkey, key_len);  	n->dev = dev;  	if (dev) @@ -610,7 +600,6 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,  	if (tbl->pconstructor && tbl->pconstructor(n)) {  		if (dev)  			dev_put(dev); -		release_net(net);  		kfree(n);  		n = NULL;  		goto out; @@ -644,7 +633,6 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,  				tbl->pdestructor(n);  			if (n->dev)  				dev_put(n->dev); -			release_net(pneigh_net(n));  			kfree(n);  			return 0;  		} @@ -667,7 +655,6 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)  					tbl->pdestructor(n);  				if (n->dev)  					dev_put(n->dev); -				release_net(pneigh_net(n));  				kfree(n);  				continue;  			} @@ -830,10 +817,9 @@ out:  static __inline__ int neigh_max_probes(struct neighbour *n)  {  	struct neigh_parms *p = n->parms; -	int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES); -	if (!(n->nud_state & NUD_PROBE)) -		max_probes += NEIGH_VAR(p, MCAST_PROBES); -	return max_probes; +	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) + +	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) : +	        NEIGH_VAR(p, MCAST_PROBES));  }  static void neigh_invalidate(struct neighbour *neigh) @@ -1263,10 +1249,10 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,  EXPORT_SYMBOL(neigh_event_ns);  /* called with read_lock_bh(&n->lock); */ -static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst) +static void neigh_hh_init(struct neighbour *n)  { -	struct net_device *dev = dst->dev; -	__be16 prot = dst->ops->protocol; +	struct net_device *dev = n->dev; +	__be16 prot = n->tbl->protocol;  	struct hh_cache	*hh = &n->hh;  	write_lock_bh(&n->lock); @@ -1280,43 +1266,19 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)  	write_unlock_bh(&n->lock);  } -/* This function can be used in contexts, where only old dev_queue_xmit - * worked, f.e. if you want to override normal output path (eql, shaper), - * but resolution is not made yet. - */ - -int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb) -{ -	struct net_device *dev = skb->dev; - -	__skb_pull(skb, skb_network_offset(skb)); - -	if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, -			    skb->len) < 0 && -	    dev_rebuild_header(skb)) -		return 0; - -	return dev_queue_xmit(skb); -} -EXPORT_SYMBOL(neigh_compat_output); -  /* Slow and careful. */  int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)  { -	struct dst_entry *dst = skb_dst(skb);  	int rc = 0; -	if (!dst) -		goto discard; -  	if (!neigh_event_send(neigh, skb)) {  		int err;  		struct net_device *dev = neigh->dev;  		unsigned int seq;  		if (dev->header_ops->cache && !neigh->hh.hh_len) -			neigh_hh_init(neigh, dst); +			neigh_hh_init(neigh);  		do {  			__skb_pull(skb, skb_network_offset(skb)); @@ -1332,8 +1294,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)  	}  out:  	return rc; -discard: -	neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);  out_kfree_skb:  	rc = -EINVAL;  	kfree_skb(skb); @@ -1464,11 +1424,10 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,  				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));  		dev_hold(dev);  		p->dev = dev; -		write_pnet(&p->net, hold_net(net)); +		write_pnet(&p->net, net);  		p->sysctl_table = NULL;  		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { -			release_net(net);  			dev_put(dev);  			kfree(p);  			return NULL; @@ -1508,7 +1467,6 @@ EXPORT_SYMBOL(neigh_parms_release);  static void neigh_parms_destroy(struct neigh_parms *parms)  { -	release_net(neigh_parms_net(parms));  	kfree(parms);  } @@ -1783,6 +1741,8 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)  			NEIGH_VAR(parms, UCAST_PROBES)) ||  	    nla_put_u32(skb, NDTPA_MCAST_PROBES,  			NEIGH_VAR(parms, MCAST_PROBES)) || +	    nla_put_u32(skb, NDTPA_MCAST_REPROBES, +			NEIGH_VAR(parms, MCAST_REPROBES)) ||  	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||  	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,  			  NEIGH_VAR(parms, BASE_REACHABLE_TIME)) || @@ -1942,6 +1902,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {  	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },  	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },  	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 }, +	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },  	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },  	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },  	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 }, @@ -2042,6 +2003,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)  				NEIGH_VAR_SET(p, MCAST_PROBES,  					      nla_get_u32(tbp[i]));  				break; +			case NDTPA_MCAST_REPROBES: +				NEIGH_VAR_SET(p, MCAST_REPROBES, +					      nla_get_u32(tbp[i])); +				break;  			case NDTPA_BASE_REACHABLE_TIME:  				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,  					      nla_get_msecs(tbp[i])); @@ -2427,6 +2392,40 @@ void __neigh_for_each_release(struct neigh_table *tbl,  }  EXPORT_SYMBOL(__neigh_for_each_release); +int neigh_xmit(int index, struct net_device *dev, +	       const void *addr, struct sk_buff *skb) +{ +	int err = -EAFNOSUPPORT; +	if (likely(index < NEIGH_NR_TABLES)) { +		struct neigh_table *tbl; +		struct neighbour *neigh; + +		tbl = neigh_tables[index]; +		if (!tbl) +			goto out; +		neigh = __neigh_lookup_noref(tbl, addr, dev); +		if (!neigh) +			neigh = __neigh_create(tbl, addr, dev, false); +		err = PTR_ERR(neigh); +		if (IS_ERR(neigh)) +			goto out_kfree_skb; +		err = neigh->output(neigh, skb); +	} +	else if (index == NEIGH_LINK_TABLE) { +		err = dev_hard_header(skb, dev, ntohs(skb->protocol), +				      addr, NULL, skb->len); +		if (err < 0) +			goto out_kfree_skb; +		err = dev_queue_xmit(skb); +	} +out: +	return err; +out_kfree_skb: +	kfree_skb(skb); +	goto out; +} +EXPORT_SYMBOL(neigh_xmit); +  #ifdef CONFIG_PROC_FS  static struct neighbour *neigh_get_first(struct seq_file *seq) @@ -2994,6 +2993,7 @@ static struct neigh_sysctl_table {  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"), +		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),  		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),  		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),  		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"), |