diff mbox series

[v2,net] neighbor: Call __ipv4_neigh_lookup_noref in neigh_xmit

Message ID 20190503155501.28182-1-dsahern@kernel.org
State Changes Requested
Delegated to: David Miller
Headers show
Series [v2,net] neighbor: Call __ipv4_neigh_lookup_noref in neigh_xmit | expand

Commit Message

David Ahern May 3, 2019, 3:55 p.m. UTC
From: David Ahern <dsahern@gmail.com>

Commit cd9ff4de0107 changed the key for IFF_POINTOPOINT devices to
INADDR_ANY, but neigh_xmit which is used for MPLS encapsulations was not
updated to use the altered key. The result is that every packet Tx does
a lookup on the gateway address which does not find an entry, a new one
is created only to find the existing one in the table right before the
insert since arp_constructor was updated to reset the primary key. This
is seen in the allocs and destroys counters:
    ip -s -4 ntable show | head -10 | grep alloc

which increase for each packet showing the unnecessary overhread.

Fix by having neigh_xmit use __ipv4_neigh_lookup_noref for NEIGH_ARP_TABLE.
Define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set.

v2
- define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set as
  reported by kbuild test robot

Fixes: cd9ff4de0107 ("ipv4: Make neigh lookup keys for loopback/point-to-point devices be INADDR_ANY")
Reported-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: David Ahern <dsahern@gmail.com>

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/arp.h    | 8 ++++++++
 net/core/neighbour.c | 9 ++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

Comments

David Miller May 5, 2019, 5:42 p.m. UTC | #1
From: David Ahern <dsahern@kernel.org>
Date: Fri,  3 May 2019 08:55:01 -0700

> From: David Ahern <dsahern@gmail.com>
> 
> Commit cd9ff4de0107 changed the key for IFF_POINTOPOINT devices to
> INADDR_ANY, but neigh_xmit which is used for MPLS encapsulations was not
> updated to use the altered key. The result is that every packet Tx does
> a lookup on the gateway address which does not find an entry, a new one
> is created only to find the existing one in the table right before the
> insert since arp_constructor was updated to reset the primary key. This
> is seen in the allocs and destroys counters:
>     ip -s -4 ntable show | head -10 | grep alloc
> 
> which increase for each packet showing the unnecessary overhread.
> 
> Fix by having neigh_xmit use __ipv4_neigh_lookup_noref for NEIGH_ARP_TABLE.
> Define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set.
> 
> v2
> - define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set as
>   reported by kbuild test robot
> 
> Fixes: cd9ff4de0107 ("ipv4: Make neigh lookup keys for loopback/point-to-point devices be INADDR_ANY")
> Reported-by: Alan Maguire <alan.maguire@oracle.com>
> Signed-off-by: David Ahern <dsahern@gmail.com>
> 
> Signed-off-by: David Ahern <dsahern@gmail.com>

Double signoff and this patch doesn't apply to the net tree.
David Ahern May 5, 2019, 5:43 p.m. UTC | #2
On 5/5/19 11:42 AM, David Miller wrote:
> From: David Ahern <dsahern@kernel.org>
> Date: Fri,  3 May 2019 08:55:01 -0700
> 
>> From: David Ahern <dsahern@gmail.com>
>>
>> Commit cd9ff4de0107 changed the key for IFF_POINTOPOINT devices to
>> INADDR_ANY, but neigh_xmit which is used for MPLS encapsulations was not
>> updated to use the altered key. The result is that every packet Tx does
>> a lookup on the gateway address which does not find an entry, a new one
>> is created only to find the existing one in the table right before the
>> insert since arp_constructor was updated to reset the primary key. This
>> is seen in the allocs and destroys counters:
>>     ip -s -4 ntable show | head -10 | grep alloc
>>
>> which increase for each packet showing the unnecessary overhread.
>>
>> Fix by having neigh_xmit use __ipv4_neigh_lookup_noref for NEIGH_ARP_TABLE.
>> Define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set.
>>
>> v2
>> - define __ipv4_neigh_lookup_noref in case CONFIG_INET is not set as
>>   reported by kbuild test robot
>>
>> Fixes: cd9ff4de0107 ("ipv4: Make neigh lookup keys for loopback/point-to-point devices be INADDR_ANY")
>> Reported-by: Alan Maguire <alan.maguire@oracle.com>
>> Signed-off-by: David Ahern <dsahern@gmail.com>
>>
>> Signed-off-by: David Ahern <dsahern@gmail.com>
> 
> Double signoff and this patch doesn't apply to the net tree.
> 

oops on the double signoff; you actually took v1 so I need to send a delta.
David Miller May 5, 2019, 5:53 p.m. UTC | #3
From: David Ahern <dsahern@gmail.com>
Date: Sun, 5 May 2019 11:43:39 -0600

> oops on the double signoff; you actually took v1 so I need to send a delta.

Aha, I see, thanks for catching that.
diff mbox series

Patch

diff --git a/include/net/arp.h b/include/net/arp.h
index 977aabfcdc03..c8f580a0e6b1 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -18,6 +18,7 @@  static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32
 	return val * hash_rnd[0];
 }
 
+#ifdef CONFIG_INET
 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
 {
 	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
@@ -25,6 +26,13 @@  static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev
 
 	return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
 }
+#else
+static inline
+struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
+{
+	return NULL;
+}
+#endif
 
 static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
 {
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 30f6fd8f68e0..0ba5018ccb7f 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -31,6 +31,7 @@ 
 #include <linux/times.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
+#include <net/arp.h>
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/netevent.h>
@@ -2982,7 +2983,13 @@  int neigh_xmit(int index, struct net_device *dev,
 		if (!tbl)
 			goto out;
 		rcu_read_lock_bh();
-		neigh = __neigh_lookup_noref(tbl, addr, dev);
+		if (index == NEIGH_ARP_TABLE) {
+			u32 key = *((u32 *)addr);
+
+			neigh = __ipv4_neigh_lookup_noref(dev, key);
+		} else {
+			neigh = __neigh_lookup_noref(tbl, addr, dev);
+		}
 		if (!neigh)
 			neigh = __neigh_create(tbl, addr, dev, false);
 		err = PTR_ERR(neigh);