diff options
author | David S. Miller <davem@davemloft.net> | 2012-07-02 05:02:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-05 04:02:12 -0400 |
commit | a263b3093641fb1ec377582c90986a7fd0625184 (patch) | |
tree | 691fdb4703bb88611272bf958d9de1a461f1492a /net | |
parent | 11604721a3c4bea60e2ddd9e4e30d741ecdba7b0 (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.c | 12 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 12 | ||||
-rw-r--r-- | net/ipv4/route.c | 6 |
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 | } |
475 | EXPORT_SYMBOL(neigh_lookup_nodev); | 475 | EXPORT_SYMBOL(neigh_lookup_nodev); |
476 | 476 | ||
477 | struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, | 477 | struct 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 | } |
561 | EXPORT_SYMBOL(neigh_create); | 563 | EXPORT_SYMBOL(__neigh_create); |
562 | 564 | ||
563 | static u32 pneigh_hash(const void *pkey, int key_len) | 565 | static 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 | ||
1099 | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr) | 1099 | static 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); |