From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.1 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 458D4C10F0E for ; Thu, 4 Apr 2019 17:50:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 158FC206DD for ; Thu, 4 Apr 2019 17:50:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1554400225; bh=jOAXDue7nNt/tQvDSyzA10/O1iRbgjbmNwAwIIOls2A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=2e0LwHIz9AD9E/QppTWqxMw5XeBk3URI8Km6ICUczSiyjIim5qpVn/ZOZDUJu8e3o vc6RXeQWB4Dv9dJoJiTTG8dV068tsuThPmm6tVG9hagFhM0gY5rCxWFDbqDJZ3LWD0 V7SZ/daA0Xooe17VS19VqKotQ8JzLzwgEif0KoJM= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729536AbfDDRuW (ORCPT ); Thu, 4 Apr 2019 13:50:22 -0400 Received: from mail.kernel.org ([198.145.29.99]:36342 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727152AbfDDRuB (ORCPT ); Thu, 4 Apr 2019 13:50:01 -0400 Received: from kenny.it.cumulusnetworks.com. (fw.cumulusnetworks.com [216.129.126.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 4000620820; Thu, 4 Apr 2019 17:50:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1554400201; bh=jOAXDue7nNt/tQvDSyzA10/O1iRbgjbmNwAwIIOls2A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=2qiqg8ZR/1LT4KhT/YCYBrL5UC8i4WgsALQZpc0/04eMObcmbDudOWBkSCChsWPGL aGsXwYL2mPpjBooLoXQl7f67jh2BSSMmP0TyQgXagBMnMG6IrkUfOkyiFD/Awg+Fgk Bxf2cHa9wORl7a0IChLbM5uOVBaVaZV2OvadFIUQ= From: David Ahern To: davem@davemloft.net, netdev@vger.kernel.org Cc: idosch@mellanox.com, jiri@mellanox.com, David Ahern Subject: [PATCH net-next 11/18] ipv4: Add helpers for neigh lookup for nexthop Date: Thu, 4 Apr 2019 10:50:00 -0700 Message-Id: <20190404175007.8150-12-dsahern@kernel.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190404175007.8150-1-dsahern@kernel.org> References: <20190404175007.8150-1-dsahern@kernel.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: David Ahern A common them in the output path is looking up a neigh entry for a nexthop, either the gateway in an rtable or a fallback to the daddr in the skb: nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr); neigh = __ipv4_neigh_lookup_noref(dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); To allow the nexthop to be an IPv6 address we need to consider the family of the nexthop and then call __ipv*_neigh_lookup_noref based on it. To make this simpler, add a ip_neigh_gw4 helper similar to ip_neigh_gw6 which handles: neigh = __ipv4_neigh_lookup_noref(dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); And then add a second one, ip_neigh_for_gw, that calls either ip_neigh_gw4 or ip_neigh_gw6 based on the address family of the gateway. Update the output paths in the VRF driver and core v4 code to use ip_neigh_for_gw simplifying the family based lookup and making both ready for a v6 nexthop. ipv4_neigh_lookup has a different need - the potential to resolve a passed in address in addition to any gateway in the rtable or skb. Since this is a one-off, add ip_neigh_gw4 and ip_neigh_gw6 diectly. The difference between __neigh_create used by the helpers and neigh_create called by ipv4_neigh_lookup is taking a refcount, so add rcu_read_lock_bh and bump the refcnt on the neigh entry. Signed-off-by: David Ahern --- drivers/net/vrf.c | 10 ++++------ include/net/route.h | 32 ++++++++++++++++++++++++++++++++ net/ipv4/ip_output.c | 11 ++++------- net/ipv4/route.c | 29 +++++++++++++++++++---------- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 60c36d06bb4f..abca05cb856a 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -549,7 +549,7 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); struct neighbour *neigh; - u32 nexthop; + bool is_v6gw = false; int ret = -EINVAL; nf_reset(skb); @@ -572,13 +572,11 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s rcu_read_lock_bh(); - nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr); - neigh = __ipv4_neigh_lookup_noref(dev, nexthop); - if (unlikely(!neigh)) - neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); + neigh = ip_neigh_for_gw(rt, skb, &is_v6gw); if (!IS_ERR(neigh)) { sock_confirm_neigh(skb, neigh); - ret = neigh_output(neigh, skb, false); + /* if crossing protocols, can not used the cached header */ + ret = neigh_output(neigh, skb, is_v6gw); rcu_read_unlock_bh(); return ret; } diff --git a/include/net/route.h b/include/net/route.h index 5d28a2509b58..96f6c9ae33c2 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -350,4 +352,34 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst) return hoplimit; } +static inline struct neighbour *ip_neigh_gw4(struct net_device *dev, + __be32 daddr) +{ + struct neighbour *neigh; + + neigh = __ipv4_neigh_lookup_noref(dev, daddr); + if (unlikely(!neigh)) + neigh = __neigh_create(&arp_tbl, &daddr, dev, false); + + return neigh; +} + +static inline struct neighbour *ip_neigh_for_gw(struct rtable *rt, + struct sk_buff *skb, + bool *is_v6gw) +{ + struct net_device *dev = rt->dst.dev; + struct neighbour *neigh; + + if (likely(rt->rt_gw_family == AF_INET)) { + neigh = ip_neigh_gw4(dev, rt->rt_gw4); + } else if (rt->rt_gw_family == AF_INET6) { + neigh = ip_neigh_gw6(dev, &rt->rt_gw6); + *is_v6gw = true; + } else { + neigh = ip_neigh_gw4(dev, ip_hdr(skb)->daddr); + } + return neigh; +} + #endif /* _ROUTE_H */ diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8cf8b0118f70..e5b8d7726737 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -188,7 +188,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); struct neighbour *neigh; - u32 nexthop; + bool is_v6gw = false; if (rt->rt_type == RTN_MULTICAST) { IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTMCAST, skb->len); @@ -218,16 +218,13 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s } rcu_read_lock_bh(); - nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr); - neigh = __ipv4_neigh_lookup_noref(dev, nexthop); - if (unlikely(!neigh)) - neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); + neigh = ip_neigh_for_gw(rt, skb, &is_v6gw); if (!IS_ERR(neigh)) { int res; sock_confirm_neigh(skb, neigh); - res = neigh_output(neigh, skb, false); - + /* if crossing protocols, can not used the cached header */ + res = neigh_output(neigh, skb, is_v6gw); rcu_read_unlock_bh(); return res; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6e58acf0a87b..32ecb4c1c7e3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -436,18 +436,27 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, { const struct rtable *rt = container_of(dst, struct rtable, dst); struct net_device *dev = dst->dev; - const __be32 *pkey = daddr; struct neighbour *n; - if (rt->rt_gw_family == AF_INET) - pkey = (const __be32 *) &rt->rt_gw4; - else if (skb) - pkey = &ip_hdr(skb)->daddr; - - n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); - if (n) - return n; - return neigh_create(&arp_tbl, pkey, dev); + rcu_read_lock_bh(); + + if (likely(rt->rt_gw_family == AF_INET)) { + n = ip_neigh_gw4(dev, rt->rt_gw4); + } else if (rt->rt_gw_family == AF_INET6) { + n = ip_neigh_gw6(dev, &rt->rt_gw6); + } else { + __be32 pkey; + + pkey = skb ? ip_hdr(skb)->daddr : *((__be32 *) daddr); + n = ip_neigh_gw4(dev, pkey); + } + + if (n && !refcount_inc_not_zero(&n->refcnt)) + n = NULL; + + rcu_read_unlock_bh(); + + return n; } static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr) -- 2.11.0