aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-02 05:02:15 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-05 04:02:12 -0400
commita263b3093641fb1ec377582c90986a7fd0625184 (patch)
tree691fdb4703bb88611272bf958d9de1a461f1492a /net
parent11604721a3c4bea60e2ddd9e4e30d741ecdba7b0 (diff)
ipv4: Make neigh lookups directly in output packet path.
Do not use the dst cached neigh, we'll be getting rid of that. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/neighbour.c12
-rw-r--r--net/ipv4/ip_output.c12
-rw-r--r--net/ipv4/route.c6
3 files changed, 16 insertions, 14 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index d81d026138f0..a793af9af150 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -474,8 +474,8 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
474} 474}
475EXPORT_SYMBOL(neigh_lookup_nodev); 475EXPORT_SYMBOL(neigh_lookup_nodev);
476 476
477struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, 477struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
478 struct net_device *dev) 478 struct net_device *dev, bool want_ref)
479{ 479{
480 u32 hash_val; 480 u32 hash_val;
481 int key_len = tbl->key_len; 481 int key_len = tbl->key_len;
@@ -535,14 +535,16 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
535 n1 = rcu_dereference_protected(n1->next, 535 n1 = rcu_dereference_protected(n1->next,
536 lockdep_is_held(&tbl->lock))) { 536 lockdep_is_held(&tbl->lock))) {
537 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { 537 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
538 neigh_hold(n1); 538 if (want_ref)
539 neigh_hold(n1);
539 rc = n1; 540 rc = n1;
540 goto out_tbl_unlock; 541 goto out_tbl_unlock;
541 } 542 }
542 } 543 }
543 544
544 n->dead = 0; 545 n->dead = 0;
545 neigh_hold(n); 546 if (want_ref)
547 neigh_hold(n);
546 rcu_assign_pointer(n->next, 548 rcu_assign_pointer(n->next,
547 rcu_dereference_protected(nht->hash_buckets[hash_val], 549 rcu_dereference_protected(nht->hash_buckets[hash_val],
548 lockdep_is_held(&tbl->lock))); 550 lockdep_is_held(&tbl->lock)));
@@ -558,7 +560,7 @@ out_neigh_release:
558 neigh_release(n); 560 neigh_release(n);
559 goto out; 561 goto out;
560} 562}
561EXPORT_SYMBOL(neigh_create); 563EXPORT_SYMBOL(__neigh_create);
562 564
563static u32 pneigh_hash(const void *pkey, int key_len) 565static u32 pneigh_hash(const void *pkey, int key_len)
564{ 566{
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2630900e480a..6e9a266a0535 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -170,6 +170,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
170 struct net_device *dev = dst->dev; 170 struct net_device *dev = dst->dev;
171 unsigned int hh_len = LL_RESERVED_SPACE(dev); 171 unsigned int hh_len = LL_RESERVED_SPACE(dev);
172 struct neighbour *neigh; 172 struct neighbour *neigh;
173 u32 nexthop;
173 174
174 if (rt->rt_type == RTN_MULTICAST) { 175 if (rt->rt_type == RTN_MULTICAST) {
175 IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); 176 IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
@@ -191,15 +192,18 @@ static inline int ip_finish_output2(struct sk_buff *skb)
191 skb = skb2; 192 skb = skb2;
192 } 193 }
193 194
194 rcu_read_lock(); 195 rcu_read_lock_bh();
195 neigh = dst_get_neighbour_noref(dst); 196 nexthop = rt->rt_gateway ? rt->rt_gateway : ip_hdr(skb)->daddr;
197 neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
198 if (unlikely(!neigh))
199 neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
196 if (neigh) { 200 if (neigh) {
197 int res = neigh_output(neigh, skb); 201 int res = neigh_output(neigh, skb);
198 202
199 rcu_read_unlock(); 203 rcu_read_unlock_bh();
200 return res; 204 return res;
201 } 205 }
202 rcu_read_unlock(); 206 rcu_read_unlock_bh();
203 207
204 net_dbg_ratelimited("%s: No header cache and no neighbour!\n", 208 net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
205 __func__); 209 __func__);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6a5afc715558..2f40363e2851 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1098,17 +1098,13 @@ static int slow_chain_length(const struct rtable *head)
1098 1098
1099static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr) 1099static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr)
1100{ 1100{
1101 static const __be32 inaddr_any = 0;
1102 struct net_device *dev = dst->dev; 1101 struct net_device *dev = dst->dev;
1103 const __be32 *pkey = daddr; 1102 const __be32 *pkey = daddr;
1104 const struct rtable *rt; 1103 const struct rtable *rt;
1105 struct neighbour *n; 1104 struct neighbour *n;
1106 1105
1107 rt = (const struct rtable *) dst; 1106 rt = (const struct rtable *) dst;
1108 1107 if (rt->rt_gateway)
1109 if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
1110 pkey = &inaddr_any;
1111 else if (rt->rt_gateway)
1112 pkey = (const __be32 *) &rt->rt_gateway; 1108 pkey = (const __be32 *) &rt->rt_gateway;
1113 1109
1114 n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); 1110 n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey);