All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes
@ 2019-04-05 23:30 David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 01/18] ipv6: Add fib6_nh_init and release to stubs David Ahern
                   ` (18 more replies)
  0 siblings, 19 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Last set of three with the end goal of enabling IPv6 gateways with IPv4
routes.

This set adds fib6_nh_init and release to the IPv6 stubs, and adds neighbor
helpers that IPv4 code invokes to resolve an IPv6 address. When using
an IPv6 neighbor entry the hh_cache is bypassed as it contains the wrong
ethernet header for an IPv4 packet.

The nh_common nhc_has_gw was a temporary field used to convert existing
code from fib{6}_nh to fib_nh_common. That field is now converted to
nhc_gw_family to differentiate the address family of the gateway entry
as opposed to the address family of the container of fib_nh_common.

Existing code for rtable and fib_config is refactored to prepare
for a v6 address and then support is added. From there various
miscellaneous functions are updated to handle a v6 gateway - from
validating the v6 address to lookups in bpf code to verifying the
nexthop state.

Offload drivers - mlxsw and rocker - are modified to detect the v6
gateway and reject the route as 'unsupported'. e.g.,

    $ ip ro add 172.16.101.0/24 via inet6 fe80::202:ff:fe00:b dev swp1s0
    Error: mlxsw_spectrum: IPv6 gateway with IPv4 route is not supported.

This can be removed in time once support is added to each.

With the infrastructure changes in place, patch 17 enables it by adding
support for RTA_VIA to IPv4. RTA_VIA can be used for IPv4 addresses as
well. Only one of RTA_VIA and RTA_GATEWAY can be passed in a request.

Patch 18 adds a few test cases to fib_tests.sh.

v2
- comments from Ido - fixed typos as noted and updated messages
- add commit message to patch 1
- In patch 9, ipv4: Add fib_check_nh_v6_gw, moved the call to
  fib6_nh_release under the 'if (!err)' check as the intention is
  that release should not be called if init fails.

David Ahern (18):
  ipv6: Add fib6_nh_init and release to stubs
  ipv6: Add neighbor helpers that use the ipv6 stub
  net: Replace nhc_has_gw with nhc_gw_family
  ipv4: Prepare rtable for IPv6 gateway
  ipv4: Prepare fib_config for IPv6 gateway
  ipv4: Add support to rtable for ipv6 gateway
  ipv4: Add support to fib_config for IPv6 gateway
  ipv4: Refactor fib_check_nh
  ipv4: Add fib_check_nh_v6_gw
  neighbor: Add skip_cache argument to neigh_output
  ipv4: Add helpers for neigh lookup for nexthop
  bpf: Handle ipv6 gateway in bpf_ipv4_fib_lookup
  ipv4: Handle ipv6 gateway in ipv4_confirm_neigh
  ipv4: Handle ipv6 gateway in fib_detect_death
  ipv4: Handle ipv6 gateway in fib_good_nh
  ipv4: Flag fib_info with a fib_nh using IPv6 gateway
  ipv4: Allow ipv6 gateway with ipv4 routes
  selftests: fib_tests: Add tests for ipv6 gateway with ipv4 route

 drivers/infiniband/core/addr.c                     |   2 +-
 drivers/infiniband/hw/nes/nes_cm.c                 |   2 +-
 drivers/net/appletalk/ipddp.c                      |   6 +-
 .../net/ethernet/mellanox/mlx5/core/en/tc_tun.c    |   2 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_router.c  |  12 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_span.c    |   6 +-
 drivers/net/ethernet/rocker/rocker_main.c          |   9 +
 drivers/net/vrf.c                                  |  12 +-
 include/net/ip6_route.h                            |   2 +-
 include/net/ip_fib.h                               |  18 +-
 include/net/ipv6_stubs.h                           |   6 +
 include/net/ndisc.h                                |  40 ++
 include/net/neighbour.h                            |   5 +-
 include/net/route.h                                |  43 +-
 include/trace/events/fib.h                         |   4 +-
 net/atm/clip.c                                     |   4 +-
 net/core/filter.c                                  |  25 +-
 net/ipv4/fib_frontend.c                            |  68 +++-
 net/ipv4/fib_semantics.c                           | 432 ++++++++++++++-------
 net/ipv4/inet_connection_sock.c                    |   4 +-
 net/ipv4/ip_forward.c                              |   2 +-
 net/ipv4/ip_output.c                               |  13 +-
 net/ipv4/route.c                                   | 112 ++++--
 net/ipv4/xfrm4_policy.c                            |   7 +-
 net/ipv6/addrconf.c                                |   2 +-
 net/ipv6/addrconf_core.c                           |   9 +
 net/ipv6/af_inet6.c                                |   2 +
 net/ipv6/ip6_fib.c                                 |   2 +-
 net/ipv6/ip6_output.c                              |   2 +-
 net/ipv6/route.c                                   |  18 +-
 net/mpls/mpls_iptunnel.c                           |  12 +-
 tools/testing/selftests/net/fib_tests.sh           |  70 +++-
 32 files changed, 696 insertions(+), 257 deletions(-)

-- 
2.11.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 01/18] ipv6: Add fib6_nh_init and release to stubs
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 02/18] ipv6: Add neighbor helpers that use the ipv6 stub David Ahern
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add fib6_nh_init and fib6_nh_release to ipv6_stubs. If fib6_nh_init fails,
callers should not invoke fib6_nh_release, so there is no reason to have
a dummy stub for the IPv6 is not enabled case.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 include/net/ipv6_stubs.h | 6 ++++++
 net/ipv6/addrconf_core.c | 9 +++++++++
 net/ipv6/af_inet6.c      | 2 ++
 3 files changed, 17 insertions(+)

diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h
index d8d9c0b0e8c0..453b55bf6723 100644
--- a/include/net/ipv6_stubs.h
+++ b/include/net/ipv6_stubs.h
@@ -12,6 +12,8 @@
 
 /* structs from net/ip6_fib.h */
 struct fib6_info;
+struct fib6_nh;
+struct fib6_config;
 
 /* This is ugly, ideally these symbols should be built
  * into the core kernel.
@@ -40,6 +42,10 @@ struct ipv6_stub {
 	u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i, struct in6_addr *daddr,
 				 struct in6_addr *saddr);
 
+	int (*fib6_nh_init)(struct net *net, struct fib6_nh *fib6_nh,
+			    struct fib6_config *cfg, gfp_t gfp_flags,
+			    struct netlink_ext_ack *extack);
+	void (*fib6_nh_release)(struct fib6_nh *fib6_nh);
 	void (*udpv6_encap_enable)(void);
 	void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr,
 			      const struct in6_addr *solicited_addr,
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index 945b66e3008f..e37e4c5871f7 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -173,6 +173,14 @@ eafnosupport_ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
 	return 0;
 }
 
+static int eafnosupport_fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
+				     struct fib6_config *cfg, gfp_t gfp_flags,
+				     struct netlink_ext_ack *extack)
+{
+	NL_SET_ERR_MSG(extack, "IPv6 support not enabled in kernel");
+	return -EAFNOSUPPORT;
+}
+
 const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
 	.ipv6_dst_lookup   = eafnosupport_ipv6_dst_lookup,
 	.ipv6_route_input  = eafnosupport_ipv6_route_input,
@@ -181,6 +189,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
 	.fib6_lookup       = eafnosupport_fib6_lookup,
 	.fib6_multipath_select = eafnosupport_fib6_multipath_select,
 	.ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6,
+	.fib6_nh_init	   = eafnosupport_fib6_nh_init,
 };
 EXPORT_SYMBOL_GPL(ipv6_stub);
 
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 1789bf99c419..1dac6ea6666a 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -919,6 +919,8 @@ static const struct ipv6_stub ipv6_stub_impl = {
 	.fib6_lookup       = fib6_lookup,
 	.fib6_multipath_select = fib6_multipath_select,
 	.ip6_mtu_from_fib6 = ip6_mtu_from_fib6,
+	.fib6_nh_init	   = fib6_nh_init,
+	.fib6_nh_release   = fib6_nh_release,
 	.udpv6_encap_enable = udpv6_encap_enable,
 	.ndisc_send_na = ndisc_send_na,
 	.nd_tbl	= &nd_tbl,
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 02/18] ipv6: Add neighbor helpers that use the ipv6 stub
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 01/18] ipv6: Add fib6_nh_init and release to stubs David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 03/18] net: Replace nhc_has_gw with nhc_gw_family David Ahern
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add ipv6 helpers to handle ndisc references via the stub. Update
bpf_ipv6_fib_lookup to use __ipv6_neigh_lookup_noref_stub instead of
the open code ___neigh_lookup_noref with the stub.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 include/net/ndisc.h | 40 ++++++++++++++++++++++++++++++++++++++++
 net/core/filter.c   |  6 ++----
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index ddfbb591e2c5..366150053043 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -2,6 +2,8 @@
 #ifndef _NDISC_H
 #define _NDISC_H
 
+#include <net/ipv6_stubs.h>
+
 /*
  *	ICMP codes for neighbour discovery messages
  */
@@ -379,6 +381,14 @@ static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev
 	return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev);
 }
 
+static inline
+struct neighbour *__ipv6_neigh_lookup_noref_stub(struct net_device *dev,
+						 const void *pkey)
+{
+	return ___neigh_lookup_noref(ipv6_stub->nd_tbl, neigh_key_eq128,
+				     ndisc_hashfn, pkey, dev);
+}
+
 static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
 {
 	struct neighbour *n;
@@ -409,6 +419,36 @@ static inline void __ipv6_confirm_neigh(struct net_device *dev,
 	rcu_read_unlock_bh();
 }
 
+static inline void __ipv6_confirm_neigh_stub(struct net_device *dev,
+					     const void *pkey)
+{
+	struct neighbour *n;
+
+	rcu_read_lock_bh();
+	n = __ipv6_neigh_lookup_noref_stub(dev, pkey);
+	if (n) {
+		unsigned long now = jiffies;
+
+		/* avoid dirtying neighbour */
+		if (n->confirmed != now)
+			n->confirmed = now;
+	}
+	rcu_read_unlock_bh();
+}
+
+/* uses ipv6_stub and is meant for use outside of IPv6 core */
+static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
+					     const void *addr)
+{
+	struct neighbour *neigh;
+
+	neigh = __ipv6_neigh_lookup_noref_stub(dev, addr);
+	if (unlikely(!neigh))
+		neigh = __neigh_create(ipv6_stub->nd_tbl, addr, dev, false);
+
+	return neigh;
+}
+
 int ndisc_init(void);
 int ndisc_late_init(void);
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 8904e3407163..26d9cd785ae2 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4759,11 +4759,9 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 	params->rt_metric = f6i->fib6_metric;
 
 	/* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
-	 * not needed here. Can not use __ipv6_neigh_lookup_noref here
-	 * because we need to get nd_tbl via the stub
+	 * not needed here.
 	 */
-	neigh = ___neigh_lookup_noref(ipv6_stub->nd_tbl, neigh_key_eq128,
-				      ndisc_hashfn, dst, dev);
+	neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
 	if (!neigh)
 		return BPF_FIB_LKUP_RET_NO_NEIGH;
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 03/18] net: Replace nhc_has_gw with nhc_gw_family
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 01/18] ipv6: Add fib6_nh_init and release to stubs David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 02/18] ipv6: Add neighbor helpers that use the ipv6 stub David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 04/18] ipv4: Prepare rtable for IPv6 gateway David Ahern
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Allow the gateway in a fib_nh_common to be from a different address
family than the outer fib{6}_nh. To that end, replace nhc_has_gw with
nhc_gw_family and update users of nhc_has_gw to check nhc_gw_family.
Now nhc_family is used to know if the nh_common is part of a fib_nh
or fib6_nh (used for container_of to get to route family specific data),
and nhc_gw_family represents the address family for the gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/spectrum_router.c  |  4 ++--
 include/net/ip6_route.h                            |  2 +-
 include/net/ip_fib.h                               |  7 +++---
 include/trace/events/fib.h                         |  4 ++--
 net/core/filter.c                                  |  4 ++--
 net/ipv4/fib_semantics.c                           | 25 ++++++++++------------
 net/ipv4/route.c                                   |  5 +++--
 net/ipv6/addrconf.c                                |  2 +-
 net/ipv6/ip6_fib.c                                 |  2 +-
 net/ipv6/route.c                                   | 18 ++++++++--------
 10 files changed, 35 insertions(+), 38 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 0ba9daa05a52..772aa78cab51 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -4915,7 +4915,7 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
 static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
 {
 	/* RTF_CACHE routes are ignored */
-	return !(rt->fib6_flags & RTF_ADDRCONF) && rt->fib6_nh.fib_nh_has_gw;
+	return !(rt->fib6_flags & RTF_ADDRCONF) && rt->fib6_nh.fib_nh_gw_family;
 }
 
 static struct fib6_info *
@@ -5055,7 +5055,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
 				    const struct fib6_info *rt)
 {
-	return rt->fib6_nh.fib_nh_has_gw ||
+	return rt->fib6_nh.fib_nh_gw_family ||
 	       mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
 }
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 342180a7285c..5909fc421305 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -69,7 +69,7 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr)
 static inline bool rt6_qualify_for_ecmp(const struct fib6_info *f6i)
 {
 	return !(f6i->fib6_flags & (RTF_ADDRCONF|RTF_DYNAMIC)) &&
-		f6i->fib6_nh.fib_nh_has_gw;
+		f6i->fib6_nh.fib_nh_gw_family;
 }
 
 void ip6_route_input(struct sk_buff *skb);
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 3ce07841dc3b..c68a40435ee0 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -83,8 +83,8 @@ struct fib_nh_common {
 	struct lwtunnel_state	*nhc_lwtstate;
 	unsigned char		nhc_scope;
 	u8			nhc_family;
-	u8			nhc_has_gw:1,
-				unused:7;
+	u8			nhc_gw_family;
+
 	union {
 		__be32          ipv4;
 		struct in6_addr ipv6;
@@ -112,8 +112,7 @@ struct fib_nh {
 #define fib_nh_flags		nh_common.nhc_flags
 #define fib_nh_lws		nh_common.nhc_lwtstate
 #define fib_nh_scope		nh_common.nhc_scope
-#define fib_nh_family		nh_common.nhc_family
-#define fib_nh_has_gw		nh_common.nhc_has_gw
+#define fib_nh_gw_family	nh_common.nhc_gw_family
 #define fib_nh_gw4		nh_common.nhc_gw.ipv4
 #define fib_nh_gw6		nh_common.nhc_gw.ipv6
 #define fib_nh_weight		nh_common.nhc_weight
diff --git a/include/trace/events/fib.h b/include/trace/events/fib.h
index 7f83b6eafc5c..6f2a4dc35e37 100644
--- a/include/trace/events/fib.h
+++ b/include/trace/events/fib.h
@@ -69,13 +69,13 @@ TRACE_EVENT(fib_table_lookup,
 		__assign_str(name, dev ? dev->name : "-");
 
 		if (nhc) {
-			if (nhc->nhc_family == AF_INET) {
+			if (nhc->nhc_gw_family == AF_INET) {
 				p32 = (__be32 *) __entry->gw4;
 				*p32 = nhc->nhc_gw.ipv4;
 
 				in6 = (struct in6_addr *)__entry->gw6;
 				*in6 = in6_zero;
-			} else if (nhc->nhc_family == AF_INET6) {
+			} else if (nhc->nhc_gw_family == AF_INET6) {
 				p32 = (__be32 *) __entry->gw4;
 				*p32 = 0;
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 26d9cd785ae2..abd5b6ce031a 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4639,7 +4639,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 		return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
 	dev = nhc->nhc_dev;
-	if (nhc->nhc_has_gw)
+	if (nhc->nhc_gw_family)
 		params->ipv4_dst = nhc->nhc_gw.ipv4;
 
 	params->rt_metric = res.fi->fib_priority;
@@ -4752,7 +4752,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 	if (f6i->fib6_nh.fib_nh_lws)
 		return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
-	if (f6i->fib6_nh.fib_nh_has_gw)
+	if (f6i->fib6_nh.fib_nh_gw_family)
 		*dst = f6i->fib6_nh.fib_nh_gw6;
 
 	dev = f6i->fib6_nh.fib_nh_dev;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 8e0cb1687a74..e11f78c6373f 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -513,7 +513,7 @@ int fib_nh_init(struct net *net, struct fib_nh *nh,
 	nh->fib_nh_oif = cfg->fc_oif;
 	if (cfg->fc_gw) {
 		nh->fib_nh_gw4 = cfg->fc_gw;
-		nh->fib_nh_has_gw = 1;
+		nh->fib_nh_gw_family = AF_INET;
 	}
 	nh->fib_nh_flags = cfg->fc_flags;
 
@@ -1238,7 +1238,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
 				       "Route with host scope can not have multiple nexthops");
 			goto err_inval;
 		}
-		if (nh->fib_nh_gw4) {
+		if (nh->fib_nh_gw_family) {
 			NL_SET_ERR_MSG(extack,
 				       "Route with host scope can not have a gateway");
 			goto err_inval;
@@ -1341,18 +1341,15 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
 		rcu_read_unlock();
 	}
 
-	if (nhc->nhc_has_gw) {
-		switch (nhc->nhc_family) {
-		case AF_INET:
-			if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4))
-				goto nla_put_failure;
-			break;
-		case AF_INET6:
-			if (nla_put_in6_addr(skb, RTA_GATEWAY,
-					     &nhc->nhc_gw.ipv6) < 0)
-				goto nla_put_failure;
-			break;
-		}
+	switch (nhc->nhc_gw_family) {
+	case AF_INET:
+		if (nla_put_in_addr(skb, RTA_GATEWAY, nhc->nhc_gw.ipv4))
+			goto nla_put_failure;
+		break;
+	case AF_INET6:
+		if (nla_put_in6_addr(skb, RTA_GATEWAY, &nhc->nhc_gw.ipv6) < 0)
+			goto nla_put_failure;
+		break;
 	}
 
 	*flags |= (nhc->nhc_flags & RTNH_F_ONLINK);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index f3f2adf630d4..e7338e421796 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1734,8 +1734,9 @@ static int __mkroute_input(struct sk_buff *skb,
 	do_cache = res->fi && !itag;
 	if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
 	    skb->protocol == htons(ETH_P_IP)) {
-		__be32 gw = nhc->nhc_family == AF_INET ? nhc->nhc_gw.ipv4 : 0;
+		__be32 gw;
 
+		gw = nhc->nhc_gw_family == AF_INET ? nhc->nhc_gw.ipv4 : 0;
 		if (IN_DEV_SHARED_MEDIA(out_dev) ||
 		    inet_addr_onlink(out_dev, saddr, gw))
 			IPCB(skb)->flags |= IPSKB_DOREDIRECT;
@@ -2284,7 +2285,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 		} else {
 			if (unlikely(fl4->flowi4_flags &
 				     FLOWI_FLAG_KNOWN_NH &&
-				     !(nhc->nhc_has_gw &&
+				     !(nhc->nhc_gw_family &&
 				       nhc->nhc_scope == RT_SCOPE_LINK))) {
 				do_cache = false;
 				goto add;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2e8d1d2d8d3d..340a0f06f974 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2421,7 +2421,7 @@ static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
 	for_each_fib6_node_rt_rcu(fn) {
 		if (rt->fib6_nh.fib_nh_dev->ifindex != dev->ifindex)
 			continue;
-		if (no_gw && rt->fib6_nh.fib_nh_has_gw)
+		if (no_gw && rt->fib6_nh.fib_nh_gw_family)
 			continue;
 		if ((rt->fib6_flags & flags) != flags)
 			continue;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 8c00609a1513..46f54a5bb1f0 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -2304,7 +2304,7 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
 #else
 	seq_puts(seq, "00000000000000000000000000000000 00 ");
 #endif
-	if (rt->fib6_nh.fib_nh_has_gw) {
+	if (rt->fib6_nh.fib_nh_gw_family) {
 		flags |= RTF_GATEWAY;
 		seq_printf(seq, "%pi6", &rt->fib6_nh.fib_nh_gw6);
 	} else {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6e89151693d0..69f92d2b780e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -533,7 +533,7 @@ static void rt6_probe(struct fib6_info *rt)
 	 * Router Reachability Probe MUST be rate-limited
 	 * to no more than one per minute.
 	 */
-	if (!rt || !rt->fib6_nh.fib_nh_has_gw)
+	if (!rt || !rt->fib6_nh.fib_nh_gw_family)
 		return;
 
 	nh_gw = &rt->fib6_nh.fib_nh_gw6;
@@ -595,7 +595,7 @@ static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
 	struct neighbour *neigh;
 
 	if (rt->fib6_flags & RTF_NONEXTHOP ||
-	    !rt->fib6_nh.fib_nh_has_gw)
+	    !rt->fib6_nh.fib_nh_gw_family)
 		return RT6_NUD_SUCCEED;
 
 	rcu_read_lock_bh();
@@ -769,7 +769,7 @@ static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
 
 static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
 {
-	return (rt->fib6_flags & RTF_NONEXTHOP) || rt->fib6_nh.fib_nh_has_gw;
+	return (rt->fib6_flags & RTF_NONEXTHOP) || rt->fib6_nh.fib_nh_gw_family;
 }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
@@ -975,7 +975,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
 	rt->rt6i_dst = ort->fib6_dst;
 	rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
 	rt->rt6i_flags = ort->fib6_flags;
-	if (ort->fib6_nh.fib_nh_has_gw) {
+	if (ort->fib6_nh.fib_nh_gw_family) {
 		rt->rt6i_gateway = ort->fib6_nh.fib_nh_gw6;
 		rt->rt6i_flags |= RTF_GATEWAY;
 	}
@@ -1860,7 +1860,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
 		rcu_read_unlock();
 		return rt;
 	} else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
-			    !f6i->fib6_nh.fib_nh_has_gw)) {
+			    !f6i->fib6_nh.fib_nh_gw_family)) {
 		/* Create a RTF_CACHE clone which will not be
 		 * owned by the fib6 tree.  It is for the special case where
 		 * the daddr in the skb during the neighbor look-up is different
@@ -2430,7 +2430,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
 			continue;
 		if (rt->fib6_flags & RTF_REJECT)
 			break;
-		if (!rt->fib6_nh.fib_nh_has_gw)
+		if (!rt->fib6_nh.fib_nh_gw_family)
 			continue;
 		if (fl6->flowi6_oif != rt->fib6_nh.fib_nh_dev->ifindex)
 			continue;
@@ -2964,7 +2964,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
 			goto out;
 
 		fib6_nh->fib_nh_gw6 = cfg->fc_gateway;
-		fib6_nh->fib_nh_has_gw = 1;
+		fib6_nh->fib_nh_gw_family = AF_INET6;
 	}
 
 	err = -ENODEV;
@@ -3476,7 +3476,7 @@ static struct fib6_info *rt6_get_route_info(struct net *net,
 		if (rt->fib6_nh.fib_nh_dev->ifindex != ifindex)
 			continue;
 		if (!(rt->fib6_flags & RTF_ROUTEINFO) ||
-		    !rt->fib6_nh.fib_nh_has_gw)
+		    !rt->fib6_nh.fib_nh_gw_family)
 			continue;
 		if (!ipv6_addr_equal(&rt->fib6_nh.fib_nh_gw6, gwaddr))
 			continue;
@@ -3807,7 +3807,7 @@ static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
 	struct in6_addr *gateway = (struct in6_addr *)arg;
 
 	if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
-	    rt->fib6_nh.fib_nh_has_gw &&
+	    rt->fib6_nh.fib_nh_gw_family &&
 	    ipv6_addr_equal(gateway, &rt->fib6_nh.fib_nh_gw6)) {
 		return -1;
 	}
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 04/18] ipv4: Prepare rtable for IPv6 gateway
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (2 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 03/18] net: Replace nhc_has_gw with nhc_gw_family David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 05/18] ipv4: Prepare fib_config " David Ahern
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

To allow the gateway to be either an IPv4 or IPv6 address, remove
rt_uses_gateway from rtable and replace with rt_gw_family. If
rt_gw_family is set it implies rt_uses_gateway. Rename rt_gateway
to rt_gw4 to represent the IPv4 version.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 drivers/infiniband/core/addr.c                     |  2 +-
 drivers/infiniband/hw/nes/nes_cm.c                 |  2 +-
 drivers/net/appletalk/ipddp.c                      |  6 ++-
 .../net/ethernet/mellanox/mlx5/core/en/tc_tun.c    |  2 +-
 .../net/ethernet/mellanox/mlxsw/spectrum_span.c    |  3 +-
 include/net/route.h                                |  8 ++--
 net/atm/clip.c                                     |  4 +-
 net/ipv4/inet_connection_sock.c                    |  4 +-
 net/ipv4/ip_forward.c                              |  2 +-
 net/ipv4/ip_output.c                               |  2 +-
 net/ipv4/route.c                                   | 51 ++++++++++++----------
 net/ipv4/xfrm4_policy.c                            |  5 ++-
 net/mpls/mpls_iptunnel.c                           | 11 +++--
 13 files changed, 57 insertions(+), 45 deletions(-)

diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 2649e0f2ff65..f5ecb660fe7d 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -351,7 +351,7 @@ static bool has_gateway(const struct dst_entry *dst, sa_family_t family)
 
 	if (family == AF_INET) {
 		rt = container_of(dst, struct rtable, dst);
-		return rt->rt_uses_gateway;
+		return rt->rt_gw_family == AF_INET;
 	}
 
 	rt6 = container_of(dst, struct rt6_info, dst);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 032883180f65..0010a3ed64f1 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1407,7 +1407,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
 		if (neigh->nud_state & NUD_VALID) {
 			nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
 				  " is %pM, Gateway is 0x%08X \n", dst_ip,
-				  neigh->ha, ntohl(rt->rt_gateway));
+				  neigh->ha, ntohl(rt->rt_gw4));
 
 			if (arpindex >= 0) {
 				if (ether_addr_equal(nesadapter->arp_table[arpindex].mac_addr, neigh->ha)) {
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 3d27616d9c85..51cf5eca9c7f 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -116,11 +116,15 @@ static struct net_device * __init ipddp_init(void)
  */
 static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	__be32 paddr = skb_rtable(skb)->rt_gateway;
+        struct rtable *rtable = skb_rtable(skb);
+        __be32 paddr = 0;
         struct ddpehdr *ddp;
         struct ipddp_route *rt;
         struct atalk_addr *our_addr;
 
+	if (rtable->rt_gw_family == AF_INET)
+		paddr = rtable->rt_gw4;
+
 	spin_lock(&ipddp_route_lock);
 
 	/*
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
index fa2a3c444cdc..ae8671d8badf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -70,7 +70,7 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
 	if (ret)
 		return ret;
 
-	if (mlx5_lag_is_multipath(mdev) && !rt->rt_gateway)
+	if (mlx5_lag_is_multipath(mdev) && rt->rt_gw_family != AF_INET)
 		return -ENETUNREACH;
 #else
 	return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 536c23c578c3..133a497e3457 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -316,7 +316,8 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
 
 	dev = rt->dst.dev;
 	*saddrp = fl4.saddr;
-	*daddrp = rt->rt_gateway;
+	if (rt->rt_gw_family == AF_INET)
+		*daddrp = rt->rt_gw4;
 
 out:
 	ip_rt_put(rt);
diff --git a/include/net/route.h b/include/net/route.h
index 9883dc82f723..96912b099c08 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -55,12 +55,12 @@ struct rtable {
 	unsigned int		rt_flags;
 	__u16			rt_type;
 	__u8			rt_is_input;
-	__u8			rt_uses_gateway;
+	u8			rt_gw_family;
 
 	int			rt_iif;
 
 	/* Info on neighbour */
-	__be32			rt_gateway;
+	__be32			rt_gw4;
 
 	/* Miscellaneous cached information */
 	u32			rt_mtu_locked:1,
@@ -82,8 +82,8 @@ static inline bool rt_is_output_route(const struct rtable *rt)
 
 static inline __be32 rt_nexthop(const struct rtable *rt, __be32 daddr)
 {
-	if (rt->rt_gateway)
-		return rt->rt_gateway;
+	if (rt->rt_gw_family == AF_INET)
+		return rt->rt_gw4;
 	return daddr;
 }
 
diff --git a/net/atm/clip.c b/net/atm/clip.c
index d795b9c5aea4..b9e67e589a7b 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -345,8 +345,8 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
 		return NETDEV_TX_OK;
 	}
 	rt = (struct rtable *) dst;
-	if (rt->rt_gateway)
-		daddr = &rt->rt_gateway;
+	if (rt->rt_gw_family == AF_INET)
+		daddr = &rt->rt_gw4;
 	else
 		daddr = &ip_hdr(skb)->daddr;
 	n = dst_neigh_lookup(dst, daddr);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 6ea523d71947..a175e3e7ae97 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -564,7 +564,7 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
 	rt = ip_route_output_flow(net, fl4, sk);
 	if (IS_ERR(rt))
 		goto no_route;
-	if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
+	if (opt && opt->opt.is_strictroute && rt->rt_gw_family)
 		goto route_err;
 	rcu_read_unlock();
 	return &rt->dst;
@@ -602,7 +602,7 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk,
 	rt = ip_route_output_flow(net, fl4, sk);
 	if (IS_ERR(rt))
 		goto no_route;
-	if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
+	if (opt && opt->opt.is_strictroute && rt->rt_gw_family)
 		goto route_err;
 	return &rt->dst;
 
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 00ec819f949b..06f6f280b9ff 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -123,7 +123,7 @@ int ip_forward(struct sk_buff *skb)
 
 	rt = skb_rtable(skb);
 
-	if (opt->is_strictroute && rt->rt_uses_gateway)
+	if (opt->is_strictroute && rt->rt_gw_family)
 		goto sr_failed;
 
 	IPCB(skb)->flags |= IPSKB_FORWARDED;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 10b35328cfbc..a2bd4a6d9e6b 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -472,7 +472,7 @@ int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 	skb_dst_set_noref(skb, &rt->dst);
 
 packet_routed:
-	if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_uses_gateway)
+	if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gw_family)
 		goto no_route;
 
 	/* OK, we know where to send it, allocate and build IP header. */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e7338e421796..b77b4950d0c7 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -434,14 +434,13 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 					   struct sk_buff *skb,
 					   const void *daddr)
 {
+	const struct rtable *rt = container_of(dst, struct rtable, dst);
 	struct net_device *dev = dst->dev;
 	const __be32 *pkey = daddr;
-	const struct rtable *rt;
 	struct neighbour *n;
 
-	rt = (const struct rtable *) dst;
-	if (rt->rt_gateway)
-		pkey = (const __be32 *) &rt->rt_gateway;
+	if (rt->rt_gw_family == AF_INET)
+		pkey = (const __be32 *) &rt->rt_gw4;
 	else if (skb)
 		pkey = &ip_hdr(skb)->daddr;
 
@@ -453,13 +452,12 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 
 static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 {
+	const struct rtable *rt = container_of(dst, struct rtable, dst);
 	struct net_device *dev = dst->dev;
 	const __be32 *pkey = daddr;
-	const struct rtable *rt;
 
-	rt = (const struct rtable *)dst;
-	if (rt->rt_gateway)
-		pkey = (const __be32 *)&rt->rt_gateway;
+	if (rt->rt_gw_family == AF_INET)
+		pkey = (const __be32 *)&rt->rt_gw4;
 	else if (!daddr ||
 		 (rt->rt_flags &
 		  (RTCF_MULTICAST | RTCF_BROADCAST | RTCF_LOCAL)))
@@ -629,8 +627,8 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh
 
 	if (fnhe->fnhe_gw) {
 		rt->rt_flags |= RTCF_REDIRECTED;
-		rt->rt_gateway = fnhe->fnhe_gw;
-		rt->rt_uses_gateway = 1;
+		rt->rt_gw_family = AF_INET;
+		rt->rt_gw4 = fnhe->fnhe_gw;
 	}
 }
 
@@ -747,7 +745,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
 		return;
 	}
 
-	if (rt->rt_gateway != old_gw)
+	if (rt->rt_gw_family != AF_INET || rt->rt_gw4 != old_gw)
 		return;
 
 	in_dev = __in_dev_get_rcu(dev);
@@ -1282,7 +1280,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 	mtu = READ_ONCE(dst->dev->mtu);
 
 	if (unlikely(ip_mtu_locked(dst))) {
-		if (rt->rt_uses_gateway && mtu > 576)
+		if (rt->rt_gw_family && mtu > 576)
 			mtu = 576;
 	}
 
@@ -1410,8 +1408,10 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
 			orig = NULL;
 		}
 		fill_route_from_fnhe(rt, fnhe);
-		if (!rt->rt_gateway)
-			rt->rt_gateway = daddr;
+		if (!rt->rt_gw4) {
+			rt->rt_gw4 = daddr;
+			rt->rt_gw_family = AF_INET;
+		}
 
 		if (do_cache) {
 			dst_hold(&rt->dst);
@@ -1538,8 +1538,8 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 		struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
 
 		if (nh->fib_nh_gw4 && nh->fib_nh_scope == RT_SCOPE_LINK) {
-			rt->rt_gateway = nh->fib_nh_gw4;
-			rt->rt_uses_gateway = 1;
+			rt->rt_gw4 = nh->fib_nh_gw4;
+			rt->rt_gw_family = AF_INET;
 		}
 		ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
 
@@ -1557,8 +1557,10 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 			 * However, if we are unsuccessful at storing this
 			 * route into the cache we really need to set it.
 			 */
-			if (!rt->rt_gateway)
-				rt->rt_gateway = daddr;
+			if (!rt->rt_gw4) {
+				rt->rt_gw_family = AF_INET;
+				rt->rt_gw4 = daddr;
+			}
 			rt_add_uncached_list(rt);
 		}
 	} else
@@ -1591,8 +1593,8 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
 		rt->rt_iif = 0;
 		rt->rt_pmtu = 0;
 		rt->rt_mtu_locked = 0;
-		rt->rt_gateway = 0;
-		rt->rt_uses_gateway = 0;
+		rt->rt_gw_family = 0;
+		rt->rt_gw4 = 0;
 		INIT_LIST_HEAD(&rt->rt_uncached);
 
 		rt->dst.output = ip_output;
@@ -2595,8 +2597,9 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
 		rt->rt_genid = rt_genid_ipv4(net);
 		rt->rt_flags = ort->rt_flags;
 		rt->rt_type = ort->rt_type;
-		rt->rt_gateway = ort->rt_gateway;
-		rt->rt_uses_gateway = ort->rt_uses_gateway;
+		rt->rt_gw_family = ort->rt_gw_family;
+		if (rt->rt_gw_family == AF_INET)
+			rt->rt_gw4 = ort->rt_gw4;
 
 		INIT_LIST_HEAD(&rt->rt_uncached);
 	}
@@ -2675,8 +2678,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
 		if (nla_put_in_addr(skb, RTA_PREFSRC, fl4->saddr))
 			goto nla_put_failure;
 	}
-	if (rt->rt_uses_gateway &&
-	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gateway))
+	if (rt->rt_gw_family == AF_INET &&
+	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gw4))
 		goto nla_put_failure;
 
 	expires = rt->dst.expires;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index d73a6d6652f6..ee53a91526e5 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -97,8 +97,9 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
 					      RTCF_LOCAL);
 	xdst->u.rt.rt_type = rt->rt_type;
-	xdst->u.rt.rt_gateway = rt->rt_gateway;
-	xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
+	xdst->u.rt.rt_gw_family = rt->rt_gw_family;
+	if (rt->rt_gw_family == AF_INET)
+		xdst->u.rt.rt_gw4 = rt->rt_gw4;
 	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
 	xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
 	INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index f3a8557494d6..1f61b4e53686 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -137,10 +137,13 @@ static int mpls_xmit(struct sk_buff *skb)
 
 	mpls_stats_inc_outucastpkts(out_dev, skb);
 
-	if (rt)
-		err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gateway,
-				 skb);
-	else if (rt6) {
+	if (rt) {
+		if (rt->rt_gw_family == AF_INET)
+			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
+					 skb);
+		else
+			err = -EAFNOSUPPORT;
+	} else if (rt6) {
 		if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
 			/* 6PE (RFC 4798) */
 			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt6->rt6i_gateway.s6_addr32[3],
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 05/18] ipv4: Prepare fib_config for IPv6 gateway
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (3 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 04/18] ipv4: Prepare rtable for IPv6 gateway David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 06/18] ipv4: Add support to rtable for ipv6 gateway David Ahern
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Similar to rtable, fib_config needs to allow the gateway to be either an
IPv4 or an IPv6 address. To that end, rename fc_gw to fc_gw4 to mean an
IPv4 address and add fc_gw_family. Checks on 'is a gateway set' are changed
to see if fc_gw_family is set. In the process prepare the code for a
fc_gw_family == AF_INET6.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 include/net/ip_fib.h     |  5 +++--
 net/ipv4/fib_frontend.c  |  8 +++++---
 net/ipv4/fib_semantics.c | 40 ++++++++++++++++++++++++++--------------
 3 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index c68a40435ee0..1f72ad553c31 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -32,10 +32,11 @@ struct fib_config {
 	u8			fc_protocol;
 	u8			fc_scope;
 	u8			fc_type;
-	/* 3 bytes unused */
+	u8			fc_gw_family;
+	/* 2 bytes unused */
 	u32			fc_table;
 	__be32			fc_dst;
-	__be32			fc_gw;
+	__be32			fc_gw4;
 	int			fc_oif;
 	u32			fc_flags;
 	u32			fc_priority;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 15f779bd26b3..f99a2ec32505 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -558,7 +558,8 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
 	if (rt->rt_gateway.sa_family == AF_INET && addr) {
 		unsigned int addr_type;
 
-		cfg->fc_gw = addr;
+		cfg->fc_gw4 = addr;
+		cfg->fc_gw_family = AF_INET;
 		addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
 		if (rt->rt_flags & RTF_GATEWAY &&
 		    addr_type == RTN_UNICAST)
@@ -568,7 +569,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
 	if (cmd == SIOCDELRT)
 		return 0;
 
-	if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw)
+	if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw_family)
 		return -EINVAL;
 
 	if (cfg->fc_scope == RT_SCOPE_NOWHERE)
@@ -708,7 +709,8 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
 			cfg->fc_oif = nla_get_u32(attr);
 			break;
 		case RTA_GATEWAY:
-			cfg->fc_gw = nla_get_be32(attr);
+			cfg->fc_gw_family = AF_INET;
+			cfg->fc_gw4 = nla_get_be32(attr);
 			break;
 		case RTA_VIA:
 			NL_SET_ERR_MSG(extack, "IPv4 does not support RTA_VIA attribute");
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e11f78c6373f..d3e26e55f2e1 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -511,8 +511,8 @@ int fib_nh_init(struct net *net, struct fib_nh *nh,
 		goto init_failure;
 
 	nh->fib_nh_oif = cfg->fc_oif;
-	if (cfg->fc_gw) {
-		nh->fib_nh_gw4 = cfg->fc_gw;
+	if (cfg->fc_gw_family == AF_INET) {
+		nh->fib_nh_gw4 = cfg->fc_gw4;
 		nh->fib_nh_gw_family = AF_INET;
 	}
 	nh->fib_nh_flags = cfg->fc_flags;
@@ -589,8 +589,10 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
 			struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
 
 			nla = nla_find(attrs, attrlen, RTA_GATEWAY);
-			if (nla)
-				fib_cfg.fc_gw = nla_get_in_addr(nla);
+			if (nla) {
+				fib_cfg.fc_gw_family = AF_INET;
+				fib_cfg.fc_gw4 = nla_get_in_addr(nla);
+			}
 
 			nla = nla_find(attrs, attrlen, RTA_FLOW);
 			if (nla)
@@ -616,10 +618,14 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
 			       "Nexthop device index does not match RTA_OIF");
 		goto errout;
 	}
-	if (cfg->fc_gw && fi->fib_nh->fib_nh_gw4 != cfg->fc_gw) {
-		NL_SET_ERR_MSG(extack,
-			       "Nexthop gateway does not match RTA_GATEWAY");
-		goto errout;
+	if (cfg->fc_gw_family) {
+		if (cfg->fc_gw_family != fi->fib_nh->fib_nh_gw_family ||
+		    (cfg->fc_gw_family == AF_INET &&
+		     fi->fib_nh->fib_nh_gw4 != cfg->fc_gw4)) {
+			NL_SET_ERR_MSG(extack,
+				       "Nexthop gateway does not match RTA_GATEWAY");
+			goto errout;
+		}
 	}
 #ifdef CONFIG_IP_ROUTE_CLASSID
 	if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) {
@@ -719,7 +725,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
 	if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority)
 		return 1;
 
-	if (cfg->fc_oif || cfg->fc_gw) {
+	if (cfg->fc_oif || cfg->fc_gw_family) {
 		if (cfg->fc_encap) {
 			if (fib_encap_match(cfg->fc_encap_type, cfg->fc_encap,
 					    fi->fib_nh, cfg, extack))
@@ -730,10 +736,16 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
 		    cfg->fc_flow != fi->fib_nh->nh_tclassid)
 			return 1;
 #endif
-		if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->fib_nh_oif) &&
-		    (!cfg->fc_gw  || cfg->fc_gw == fi->fib_nh->fib_nh_gw4))
-			return 0;
-		return 1;
+		if ((cfg->fc_oif && cfg->fc_oif != fi->fib_nh->fib_nh_oif) ||
+		    (cfg->fc_gw_family &&
+		     cfg->fc_gw_family != fi->fib_nh->fib_nh_gw_family))
+			return 1;
+
+		if (cfg->fc_gw_family == AF_INET &&
+		    cfg->fc_gw4 != fi->fib_nh->fib_nh_gw4)
+			return 1;
+
+		return 0;
 	}
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -1204,7 +1216,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
 		goto failure;
 
 	if (fib_props[cfg->fc_type].error) {
-		if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) {
+		if (cfg->fc_gw_family || cfg->fc_oif || cfg->fc_mp) {
 			NL_SET_ERR_MSG(extack,
 				       "Gateway, device and multipath can not be specified for this route type");
 			goto err_inval;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 06/18] ipv4: Add support to rtable for ipv6 gateway
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (4 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 05/18] ipv4: Prepare fib_config " David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 07/18] ipv4: Add support to fib_config for IPv6 gateway David Ahern
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add support for an IPv6 gateway to rtable. Since a gateway is either
IPv4 or IPv6, make it a union with rt_gw4 where rt_gw_family decides
which address is in use.

When dumping the route data, encode an ipv6 nexthop using RTA_VIA.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/spectrum_span.c    |  3 +++
 include/net/route.h                                |  5 +++-
 net/ipv4/route.c                                   | 31 ++++++++++++++++++----
 net/ipv4/xfrm4_policy.c                            |  2 ++
 net/mpls/mpls_iptunnel.c                           |  5 ++--
 5 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 133a497e3457..560a60e522f9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -318,6 +318,9 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
 	*saddrp = fl4.saddr;
 	if (rt->rt_gw_family == AF_INET)
 		*daddrp = rt->rt_gw4;
+	/* can not offload if route has an IPv6 gateway */
+	else if (rt->rt_gw_family == AF_INET6)
+		dev = NULL;
 
 out:
 	ip_rt_put(rt);
diff --git a/include/net/route.h b/include/net/route.h
index 96912b099c08..5d28a2509b58 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -60,7 +60,10 @@ struct rtable {
 	int			rt_iif;
 
 	/* Info on neighbour */
-	__be32			rt_gw4;
+	union {
+		__be32		rt_gw4;
+		struct in6_addr	rt_gw6;
+	};
 
 	/* Miscellaneous cached information */
 	u32			rt_mtu_locked:1,
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index b77b4950d0c7..6e58acf0a87b 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1535,14 +1535,20 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
 
 	if (fi) {
 		struct fib_nh_common *nhc = FIB_RES_NHC(*res);
-		struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
+		struct fib_nh *nh;
 
-		if (nh->fib_nh_gw4 && nh->fib_nh_scope == RT_SCOPE_LINK) {
-			rt->rt_gw4 = nh->fib_nh_gw4;
-			rt->rt_gw_family = AF_INET;
+		if (nhc->nhc_gw_family && nhc->nhc_scope == RT_SCOPE_LINK) {
+			rt->rt_gw_family = nhc->nhc_gw_family;
+			/* only INET and INET6 are supported */
+			if (likely(nhc->nhc_gw_family == AF_INET))
+				rt->rt_gw4 = nhc->nhc_gw.ipv4;
+			else
+				rt->rt_gw6 = nhc->nhc_gw.ipv6;
 		}
+
 		ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
 
+		nh = container_of(nhc, struct fib_nh, nh_common);
 #ifdef CONFIG_IP_ROUTE_CLASSID
 		rt->dst.tclassid = nh->nh_tclassid;
 #endif
@@ -2600,6 +2606,8 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
 		rt->rt_gw_family = ort->rt_gw_family;
 		if (rt->rt_gw_family == AF_INET)
 			rt->rt_gw4 = ort->rt_gw4;
+		else if (rt->rt_gw_family == AF_INET6)
+			rt->rt_gw6 = ort->rt_gw6;
 
 		INIT_LIST_HEAD(&rt->rt_uncached);
 	}
@@ -2679,8 +2687,21 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
 			goto nla_put_failure;
 	}
 	if (rt->rt_gw_family == AF_INET &&
-	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gw4))
+	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gw4)) {
 		goto nla_put_failure;
+	} else if (rt->rt_gw_family == AF_INET6) {
+		int alen = sizeof(struct in6_addr);
+		struct nlattr *nla;
+		struct rtvia *via;
+
+		nla = nla_reserve(skb, RTA_VIA, alen + 2);
+		if (!nla)
+			goto nla_put_failure;
+
+		via = nla_data(nla);
+		via->rtvia_family = AF_INET6;
+		memcpy(via->rtvia_addr, &rt->rt_gw6, alen);
+	}
 
 	expires = rt->dst.expires;
 	if (expires) {
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index ee53a91526e5..72d19b1838ed 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -100,6 +100,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	xdst->u.rt.rt_gw_family = rt->rt_gw_family;
 	if (rt->rt_gw_family == AF_INET)
 		xdst->u.rt.rt_gw4 = rt->rt_gw4;
+	else if (rt->rt_gw_family == AF_INET6)
+		xdst->u.rt.rt_gw6 = rt->rt_gw6;
 	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
 	xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
 	INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 1f61b4e53686..2619c2fbea93 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -141,8 +141,9 @@ static int mpls_xmit(struct sk_buff *skb)
 		if (rt->rt_gw_family == AF_INET)
 			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
 					 skb);
-		else
-			err = -EAFNOSUPPORT;
+		else if (rt->rt_gw_family == AF_INET6)
+			err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt->rt_gw6,
+					 skb);
 	} else if (rt6) {
 		if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
 			/* 6PE (RFC 4798) */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 07/18] ipv4: Add support to fib_config for IPv6 gateway
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (5 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 06/18] ipv4: Add support to rtable for ipv6 gateway David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh David Ahern
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add support for an IPv6 gateway to fib_config. Since a gateway is either
IPv4 or IPv6, make it a union with fc_gw4 where fc_gw_family decides
which address is in use. Update current checks on family and gw4 to
handle ipv6 as well.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 include/net/ip_fib.h     |  5 ++++-
 net/ipv4/fib_semantics.c | 29 +++++++++++++++++++++++------
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 1f72ad553c31..f1c452f618a9 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -36,7 +36,10 @@ struct fib_config {
 	/* 2 bytes unused */
 	u32			fc_table;
 	__be32			fc_dst;
-	__be32			fc_gw4;
+	union {
+		__be32		fc_gw4;
+		struct in6_addr	fc_gw6;
+	};
 	int			fc_oif;
 	u32			fc_flags;
 	u32			fc_priority;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index d3e26e55f2e1..680b5a9a911a 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -276,7 +276,7 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
 
 	for_nexthops(fi) {
 		if (nh->fib_nh_oif != onh->fib_nh_oif ||
-		    nh->fib_nh_gw4 != onh->fib_nh_gw4 ||
+		    nh->fib_nh_gw_family != onh->fib_nh_gw_family ||
 		    nh->fib_nh_scope != onh->fib_nh_scope ||
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 		    nh->fib_nh_weight != onh->fib_nh_weight ||
@@ -287,6 +287,15 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
 		    lwtunnel_cmp_encap(nh->fib_nh_lws, onh->fib_nh_lws) ||
 		    ((nh->fib_nh_flags ^ onh->fib_nh_flags) & ~RTNH_COMPARE_MASK))
 			return -1;
+
+		if (nh->fib_nh_gw_family == AF_INET &&
+		    nh->fib_nh_gw4 != onh->fib_nh_gw4)
+			return -1;
+
+		if (nh->fib_nh_gw_family == AF_INET6 &&
+		    ipv6_addr_cmp(&nh->fib_nh_gw6, &onh->fib_nh_gw6))
+			return -1;
+
 		onh++;
 	} endfor_nexthops(fi);
 	return 0;
@@ -511,10 +520,12 @@ int fib_nh_init(struct net *net, struct fib_nh *nh,
 		goto init_failure;
 
 	nh->fib_nh_oif = cfg->fc_oif;
-	if (cfg->fc_gw_family == AF_INET) {
+	nh->fib_nh_gw_family = cfg->fc_gw_family;
+	if (cfg->fc_gw_family == AF_INET)
 		nh->fib_nh_gw4 = cfg->fc_gw4;
-		nh->fib_nh_gw_family = AF_INET;
-	}
+	else if (cfg->fc_gw_family == AF_INET6)
+		nh->fib_nh_gw6 = cfg->fc_gw6;
+
 	nh->fib_nh_flags = cfg->fc_flags;
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
@@ -621,9 +632,11 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
 	if (cfg->fc_gw_family) {
 		if (cfg->fc_gw_family != fi->fib_nh->fib_nh_gw_family ||
 		    (cfg->fc_gw_family == AF_INET &&
-		     fi->fib_nh->fib_nh_gw4 != cfg->fc_gw4)) {
+		     fi->fib_nh->fib_nh_gw4 != cfg->fc_gw4) ||
+		    (cfg->fc_gw_family == AF_INET6 &&
+		     ipv6_addr_cmp(&fi->fib_nh->fib_nh_gw6, &cfg->fc_gw6))) {
 			NL_SET_ERR_MSG(extack,
-				       "Nexthop gateway does not match RTA_GATEWAY");
+				       "Nexthop gateway does not match RTA_GATEWAY or RTA_VIA");
 			goto errout;
 		}
 	}
@@ -745,6 +758,10 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
 		    cfg->fc_gw4 != fi->fib_nh->fib_nh_gw4)
 			return 1;
 
+		if (cfg->fc_gw_family == AF_INET6 &&
+		    ipv6_addr_cmp(&cfg->fc_gw6, &fi->fib_nh->fib_nh_gw6))
+			return 1;
+
 		return 0;
 	}
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (6 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 07/18] ipv4: Add support to fib_config for IPv6 gateway David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-10  0:08   ` Govindarajulu Varadarajan
  2019-04-05 23:30 ` [PATCH v2 net-next 09/18] ipv4: Add fib_check_nh_v6_gw David Ahern
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

fib_check_nh is currently huge covering multiple uses cases - device only,
device + gateway, and device + gateway with ONLINK. The next patch adds
validation checks for IPv6 which only further complicates it. So, break
fib_check_nh into 2 helpers - one for gateway validation and one for device
only.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 net/ipv4/fib_semantics.c | 234 +++++++++++++++++++++++++----------------------
 1 file changed, 125 insertions(+), 109 deletions(-)

diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 680b5a9a911a..32ce6e6202d2 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -885,134 +885,150 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
  *					|
  *					|-> {local prefix} (terminal node)
  */
-static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
-			struct netlink_ext_ack *extack)
+static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
+			      u8 scope, struct netlink_ext_ack *extack)
 {
-	int err = 0;
-	struct net *net;
 	struct net_device *dev;
+	struct fib_result res;
+	int err;
 
-	net = cfg->fc_nlinfo.nl_net;
-	if (nh->fib_nh_gw4) {
-		struct fib_result res;
-
-		if (nh->fib_nh_flags & RTNH_F_ONLINK) {
-			unsigned int addr_type;
+	if (nh->fib_nh_flags & RTNH_F_ONLINK) {
+		unsigned int addr_type;
 
-			if (cfg->fc_scope >= RT_SCOPE_LINK) {
-				NL_SET_ERR_MSG(extack,
-					       "Nexthop has invalid scope");
-				return -EINVAL;
-			}
-			dev = __dev_get_by_index(net, nh->fib_nh_oif);
-			if (!dev) {
-				NL_SET_ERR_MSG(extack, "Nexthop device required for onlink");
-				return -ENODEV;
-			}
-			if (!(dev->flags & IFF_UP)) {
-				NL_SET_ERR_MSG(extack,
-					       "Nexthop device is not up");
-				return -ENETDOWN;
-			}
-			addr_type = inet_addr_type_dev_table(net, dev,
-							     nh->fib_nh_gw4);
-			if (addr_type != RTN_UNICAST) {
-				NL_SET_ERR_MSG(extack,
-					       "Nexthop has invalid gateway");
-				return -EINVAL;
-			}
-			if (!netif_carrier_ok(dev))
-				nh->fib_nh_flags |= RTNH_F_LINKDOWN;
-			nh->fib_nh_dev = dev;
-			dev_hold(dev);
-			nh->fib_nh_scope = RT_SCOPE_LINK;
-			return 0;
+		if (scope >= RT_SCOPE_LINK) {
+			NL_SET_ERR_MSG(extack, "Nexthop has invalid scope");
+			return -EINVAL;
 		}
-		rcu_read_lock();
-		{
-			struct fib_table *tbl = NULL;
-			struct flowi4 fl4 = {
-				.daddr = nh->fib_nh_gw4,
-				.flowi4_scope = cfg->fc_scope + 1,
-				.flowi4_oif = nh->fib_nh_oif,
-				.flowi4_iif = LOOPBACK_IFINDEX,
-			};
-
-			/* It is not necessary, but requires a bit of thinking */
-			if (fl4.flowi4_scope < RT_SCOPE_LINK)
-				fl4.flowi4_scope = RT_SCOPE_LINK;
-
-			if (cfg->fc_table)
-				tbl = fib_get_table(net, cfg->fc_table);
-
-			if (tbl)
-				err = fib_table_lookup(tbl, &fl4, &res,
-						       FIB_LOOKUP_IGNORE_LINKSTATE |
-						       FIB_LOOKUP_NOREF);
-
-			/* on error or if no table given do full lookup. This
-			 * is needed for example when nexthops are in the local
-			 * table rather than the given table
-			 */
-			if (!tbl || err) {
-				err = fib_lookup(net, &fl4, &res,
-						 FIB_LOOKUP_IGNORE_LINKSTATE);
-			}
-
-			if (err) {
-				NL_SET_ERR_MSG(extack,
-					       "Nexthop has invalid gateway");
-				rcu_read_unlock();
-				return err;
-			}
+		dev = __dev_get_by_index(net, nh->fib_nh_oif);
+		if (!dev) {
+			NL_SET_ERR_MSG(extack, "Nexthop device required for onlink");
+			return -ENODEV;
 		}
-		err = -EINVAL;
-		if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
-			NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
-			goto out;
+		if (!(dev->flags & IFF_UP)) {
+			NL_SET_ERR_MSG(extack, "Nexthop device is not up");
+			return -ENETDOWN;
 		}
-		nh->fib_nh_scope = res.scope;
-		nh->fib_nh_oif = FIB_RES_OIF(res);
-		nh->fib_nh_dev = dev = FIB_RES_DEV(res);
-		if (!dev) {
-			NL_SET_ERR_MSG(extack,
-				       "No egress device for nexthop gateway");
-			goto out;
+		addr_type = inet_addr_type_dev_table(net, dev, nh->fib_nh_gw4);
+		if (addr_type != RTN_UNICAST) {
+			NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
+			return -EINVAL;
 		}
-		dev_hold(dev);
 		if (!netif_carrier_ok(dev))
 			nh->fib_nh_flags |= RTNH_F_LINKDOWN;
-		err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
-	} else {
-		struct in_device *in_dev;
-
-		if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) {
-			NL_SET_ERR_MSG(extack,
-				       "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set");
-			return -EINVAL;
+		nh->fib_nh_dev = dev;
+		dev_hold(dev);
+		nh->fib_nh_scope = RT_SCOPE_LINK;
+		return 0;
+	}
+	rcu_read_lock();
+	{
+		struct fib_table *tbl = NULL;
+		struct flowi4 fl4 = {
+			.daddr = nh->fib_nh_gw4,
+			.flowi4_scope = scope + 1,
+			.flowi4_oif = nh->fib_nh_oif,
+			.flowi4_iif = LOOPBACK_IFINDEX,
+		};
+
+		/* It is not necessary, but requires a bit of thinking */
+		if (fl4.flowi4_scope < RT_SCOPE_LINK)
+			fl4.flowi4_scope = RT_SCOPE_LINK;
+
+		if (table)
+			tbl = fib_get_table(net, table);
+
+		if (tbl)
+			err = fib_table_lookup(tbl, &fl4, &res,
+					       FIB_LOOKUP_IGNORE_LINKSTATE |
+					       FIB_LOOKUP_NOREF);
+
+		/* on error or if no table given do full lookup. This
+		 * is needed for example when nexthops are in the local
+		 * table rather than the given table
+		 */
+		if (!tbl || err) {
+			err = fib_lookup(net, &fl4, &res,
+					 FIB_LOOKUP_IGNORE_LINKSTATE);
 		}
-		rcu_read_lock();
-		err = -ENODEV;
-		in_dev = inetdev_by_index(net, nh->fib_nh_oif);
-		if (!in_dev)
-			goto out;
-		err = -ENETDOWN;
-		if (!(in_dev->dev->flags & IFF_UP)) {
-			NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
+
+		if (err) {
+			NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
 			goto out;
 		}
-		nh->fib_nh_dev = in_dev->dev;
-		dev_hold(nh->fib_nh_dev);
-		nh->fib_nh_scope = RT_SCOPE_HOST;
-		if (!netif_carrier_ok(nh->fib_nh_dev))
-			nh->fib_nh_flags |= RTNH_F_LINKDOWN;
-		err = 0;
 	}
+
+	err = -EINVAL;
+	if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
+		NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
+		goto out;
+	}
+	nh->fib_nh_scope = res.scope;
+	nh->fib_nh_oif = FIB_RES_OIF(res);
+	nh->fib_nh_dev = dev = FIB_RES_DEV(res);
+	if (!dev) {
+		NL_SET_ERR_MSG(extack,
+			       "No egress device for nexthop gateway");
+		goto out;
+	}
+	dev_hold(dev);
+	if (!netif_carrier_ok(dev))
+		nh->fib_nh_flags |= RTNH_F_LINKDOWN;
+	err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
 out:
 	rcu_read_unlock();
 	return err;
 }
 
+static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
+			      struct netlink_ext_ack *extack)
+{
+	struct in_device *in_dev;
+	int err;
+
+	if (nh->fib_nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) {
+		NL_SET_ERR_MSG(extack,
+			       "Invalid flags for nexthop - PERVASIVE and ONLINK can not be set");
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+
+	err = -ENODEV;
+	in_dev = inetdev_by_index(net, nh->fib_nh_oif);
+	if (!in_dev)
+		goto out;
+	err = -ENETDOWN;
+	if (!(in_dev->dev->flags & IFF_UP)) {
+		NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
+		goto out;
+	}
+
+	nh->fib_nh_dev = in_dev->dev;
+	dev_hold(nh->fib_nh_dev);
+	nh->fib_nh_scope = RT_SCOPE_HOST;
+	if (!netif_carrier_ok(nh->fib_nh_dev))
+		nh->fib_nh_flags |= RTNH_F_LINKDOWN;
+	err = 0;
+out:
+	rcu_read_unlock();
+	return err;
+}
+
+static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
+			struct netlink_ext_ack *extack)
+{
+	struct net *net = cfg->fc_nlinfo.nl_net;
+	u32 table = cfg->fc_table;
+	int err;
+
+	if (nh->fib_nh_gw_family == AF_INET)
+		err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
+	else
+		err = fib_check_nh_nongw(net, nh, extack);
+
+	return err;
+}
+
 static inline unsigned int fib_laddr_hashfn(__be32 val)
 {
 	unsigned int mask = (fib_info_hash_size - 1);
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 09/18] ipv4: Add fib_check_nh_v6_gw
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (7 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 10/18] neighbor: Add skip_cache argument to neigh_output David Ahern
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add helper to use fib6_nh_init to validate a nexthop spec with an IPv6
gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
---
 net/ipv4/fib_semantics.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 32ce6e6202d2..dd95725c318e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -41,6 +41,7 @@
 #include <net/tcp.h>
 #include <net/sock.h>
 #include <net/ip_fib.h>
+#include <net/ip6_fib.h>
 #include <net/netlink.h>
 #include <net/nexthop.h>
 #include <net/lwtunnel.h>
@@ -841,6 +842,30 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
 	return true;
 }
 
+static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh,
+			      u32 table, struct netlink_ext_ack *extack)
+{
+	struct fib6_config cfg = {
+		.fc_table = table,
+		.fc_flags = nh->fib_nh_flags | RTF_GATEWAY,
+		.fc_ifindex = nh->fib_nh_oif,
+		.fc_gateway = nh->fib_nh_gw6,
+	};
+	struct fib6_nh fib6_nh = {};
+	int err;
+
+	err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack);
+	if (!err) {
+		nh->fib_nh_dev = fib6_nh.fib_nh_dev;
+		dev_hold(nh->fib_nh_dev);
+		nh->fib_nh_oif = nh->fib_nh_dev->ifindex;
+		nh->fib_nh_scope = RT_SCOPE_LINK;
+
+		ipv6_stub->fib6_nh_release(&fib6_nh);
+	}
+
+	return err;
+}
 
 /*
  * Picture
@@ -1023,6 +1048,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
 
 	if (nh->fib_nh_gw_family == AF_INET)
 		err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
+	else if (nh->fib_nh_gw_family == AF_INET6)
+		err = fib_check_nh_v6_gw(net, nh, table, extack);
 	else
 		err = fib_check_nh_nongw(net, nh, extack);
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 10/18] neighbor: Add skip_cache argument to neigh_output
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (8 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 09/18] ipv4: Add fib_check_nh_v6_gw David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 11/18] ipv4: Add helpers for neigh lookup for nexthop David Ahern
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

A later patch allows an IPv6 gateway with an IPv4 route. The neighbor
entry will exist in the v6 ndisc table and the cached header will contain
the ipv6 protocol which is wrong for an IPv4 packet. For an IPv4 packet to
use the v6 neighbor entry, neigh_output needs to skip the cached header
and just use the output callback for the neigh entry.

A future patchset can look at expanding the hh_cache to handle 2
protocols. For now, IPv6 gateways with an IPv4 route will take the
extra overhead of generating the header.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 drivers/net/vrf.c       | 4 ++--
 include/net/neighbour.h | 5 +++--
 net/ipv4/ip_output.c    | 2 +-
 net/ipv6/ip6_output.c   | 2 +-
 4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 6d1a1abbed27..fd1337736aa0 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -370,7 +370,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
 		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
 	if (!IS_ERR(neigh)) {
 		sock_confirm_neigh(skb, neigh);
-		ret = neigh_output(neigh, skb);
+		ret = neigh_output(neigh, skb, false);
 		rcu_read_unlock_bh();
 		return ret;
 	}
@@ -578,7 +578,7 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
 		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
 	if (!IS_ERR(neigh)) {
 		sock_confirm_neigh(skb, neigh);
-		ret = neigh_output(neigh, skb);
+		ret = neigh_output(neigh, skb, false);
 		rcu_read_unlock_bh();
 		return ret;
 	}
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 7c1ab9edba03..3e5438bd0101 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -498,11 +498,12 @@ static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb
 	return dev_queue_xmit(skb);
 }
 
-static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
+static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
+			       bool skip_cache)
 {
 	const struct hh_cache *hh = &n->hh;
 
-	if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
+	if ((n->nud_state & NUD_CONNECTED) && hh->hh_len && !skip_cache)
 		return neigh_hh_output(hh, skb);
 	else
 		return n->output(n, skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index a2bd4a6d9e6b..cca4892b8cb2 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -226,7 +226,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
 		int res;
 
 		sock_confirm_neigh(skb, neigh);
-		res = neigh_output(neigh, skb);
+		res = neigh_output(neigh, skb, false);
 
 		rcu_read_unlock_bh();
 		return res;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e51f3c648b09..adef2236abe2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -117,7 +117,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
 		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
 	if (!IS_ERR(neigh)) {
 		sock_confirm_neigh(skb, neigh);
-		ret = neigh_output(neigh, skb);
+		ret = neigh_output(neigh, skb, false);
 		rcu_read_unlock_bh();
 		return ret;
 	}
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 11/18] ipv4: Add helpers for neigh lookup for nexthop
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (9 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 10/18] neighbor: Add skip_cache argument to neigh_output David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 12/18] bpf: Handle ipv6 gateway in bpf_ipv4_fib_lookup David Ahern
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

A common theme 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{4,6}_neigh_lookup_noref based
on it.

To make this simpler, add a ip_neigh_gw4 helper similar to ip_neigh_gw6
added in an earlier patch 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 <dsahern@gmail.com>
---
 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 fd1337736aa0..18d752ae554f 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 use 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 <net/flow.h>
 #include <net/inet_sock.h>
 #include <net/ip_fib.h>
+#include <net/arp.h>
+#include <net/ndisc.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/rcupdate.h>
@@ -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 cca4892b8cb2..4e42c1974ba2 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 use 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


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 12/18] bpf: Handle ipv6 gateway in bpf_ipv4_fib_lookup
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (10 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 11/18] ipv4: Add helpers for neigh lookup for nexthop David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 13/18] ipv4: Handle ipv6 gateway in ipv4_confirm_neigh David Ahern
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Update bpf_ipv4_fib_lookup to handle an ipv6 gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/core/filter.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/net/core/filter.c b/net/core/filter.c
index abd5b6ce031a..41f633cf4fc1 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4639,15 +4639,26 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
 		return BPF_FIB_LKUP_RET_UNSUPP_LWT;
 
 	dev = nhc->nhc_dev;
-	if (nhc->nhc_gw_family)
-		params->ipv4_dst = nhc->nhc_gw.ipv4;
 
 	params->rt_metric = res.fi->fib_priority;
 
 	/* xdp and cls_bpf programs are run in RCU-bh so
 	 * rcu_read_lock_bh is not needed here
 	 */
-	neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)params->ipv4_dst);
+	if (likely(nhc->nhc_gw_family != AF_INET6)) {
+		if (nhc->nhc_gw_family)
+			params->ipv4_dst = nhc->nhc_gw.ipv4;
+
+		neigh = __ipv4_neigh_lookup_noref(dev,
+						 (__force u32)params->ipv4_dst);
+	} else {
+		struct in6_addr *dst = (struct in6_addr *)params->ipv6_dst;
+
+		params->family = AF_INET6;
+		*dst = nhc->nhc_gw.ipv6;
+		neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
+	}
+
 	if (!neigh)
 		return BPF_FIB_LKUP_RET_NO_NEIGH;
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 13/18] ipv4: Handle ipv6 gateway in ipv4_confirm_neigh
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (11 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 12/18] bpf: Handle ipv6 gateway in bpf_ipv4_fib_lookup David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 14/18] ipv4: Handle ipv6 gateway in fib_detect_death David Ahern
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Update ipv4_confirm_neigh to handle an ipv6 gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/ipv4/route.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 32ecb4c1c7e3..efa6a36cbfff 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -465,13 +465,15 @@ static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 	struct net_device *dev = dst->dev;
 	const __be32 *pkey = daddr;
 
-	if (rt->rt_gw_family == AF_INET)
+	if (rt->rt_gw_family == AF_INET) {
 		pkey = (const __be32 *)&rt->rt_gw4;
-	else if (!daddr ||
+	} else if (rt->rt_gw_family == AF_INET6) {
+		return __ipv6_confirm_neigh_stub(dev, &rt->rt_gw6);
+	} else if (!daddr ||
 		 (rt->rt_flags &
-		  (RTCF_MULTICAST | RTCF_BROADCAST | RTCF_LOCAL)))
+		  (RTCF_MULTICAST | RTCF_BROADCAST | RTCF_LOCAL))) {
 		return;
-
+	}
 	__ipv4_confirm_neigh(dev, *(__force u32 *)pkey);
 }
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 14/18] ipv4: Handle ipv6 gateway in fib_detect_death
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (12 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 13/18] ipv4: Handle ipv6 gateway in ipv4_confirm_neigh David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 15/18] ipv4: Handle ipv6 gateway in fib_good_nh David Ahern
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Update fib_detect_death to handle an ipv6 gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/ipv4/fib_semantics.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index dd95725c318e..e5a6d431bfab 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -457,10 +457,18 @@ static int fib_detect_death(struct fib_info *fi, int order,
 			    struct fib_info **last_resort, int *last_idx,
 			    int dflt)
 {
+	const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
 	struct neighbour *n;
 	int state = NUD_NONE;
 
-	n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].fib_nh_gw4, fi->fib_dev);
+	if (likely(nhc->nhc_gw_family == AF_INET))
+		n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev);
+	else if (nhc->nhc_gw_family == AF_INET6)
+		n = neigh_lookup(ipv6_stub->nd_tbl, &nhc->nhc_gw.ipv6,
+				 nhc->nhc_dev);
+	else
+		n = NULL;
+
 	if (n) {
 		state = n->nud_state;
 		neigh_release(n);
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 15/18] ipv4: Handle ipv6 gateway in fib_good_nh
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (13 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 14/18] ipv4: Handle ipv6 gateway in fib_detect_death David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 16/18] ipv4: Flag fib_info with a fib_nh using IPv6 gateway David Ahern
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Update fib_good_nh to handle an ipv6 gateway.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/ipv4/fib_semantics.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e5a6d431bfab..c1ea138335a2 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1909,8 +1909,14 @@ static bool fib_good_nh(const struct fib_nh *nh)
 
 		rcu_read_lock_bh();
 
-		n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
-					      (__force u32)nh->fib_nh_gw4);
+		if (likely(nh->fib_nh_gw_family == AF_INET))
+			n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
+						   (__force u32)nh->fib_nh_gw4);
+		else if (nh->fib_nh_gw_family == AF_INET6)
+			n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev,
+							   &nh->fib_nh_gw6);
+		else
+			n = NULL;
 		if (n)
 			state = n->nud_state;
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 16/18] ipv4: Flag fib_info with a fib_nh using IPv6 gateway
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (14 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 15/18] ipv4: Handle ipv6 gateway in fib_good_nh David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 17/18] ipv4: Allow ipv6 gateway with ipv4 routes David Ahern
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Until support is added to the offload drivers, they need to be able to
reject routes with an IPv6 gateway. To that end add a flag to fib_info
that indicates if any fib_nh has a v6 gateway. The flag allows the drivers
to efficiently know the use of a v6 gateway without walking all fib_nh
tied to a fib_info each time a route is added.

Update mlxsw and rocker to reject the routes with extack message as to why.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 8 ++++++++
 drivers/net/ethernet/rocker/rocker_main.c             | 9 +++++++++
 include/net/ip_fib.h                                  | 1 +
 net/ipv4/fib_semantics.c                              | 2 ++
 4 files changed, 20 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 772aa78cab51..5f05723011b4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -6092,6 +6092,14 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
 			NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
 			return notifier_from_errno(-EINVAL);
 		}
+		if (info->family == AF_INET) {
+			struct fib_entry_notifier_info *fen_info = ptr;
+
+			if (fen_info->fi->fib_nh_is_v6) {
+				NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
+				return notifier_from_errno(-EINVAL);
+			}
+		}
 		break;
 	}
 
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index a71c900ca04f..7ae6c124bfe9 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -2207,6 +2207,15 @@ static int rocker_router_fib_event(struct notifier_block *nb,
 	switch (event) {
 	case FIB_EVENT_ENTRY_ADD: /* fall through */
 	case FIB_EVENT_ENTRY_DEL:
+		if (info->family == AF_INET) {
+			struct fib_entry_notifier_info *fen_info = ptr;
+
+			if (fen_info->fi->fib_nh_is_v6) {
+				NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
+				return notifier_from_errno(-EINVAL);
+			}
+		}
+
 		memcpy(&fib_work->fen_info, ptr, sizeof(fib_work->fen_info));
 		/* Take referece on fib_info to prevent it from being
 		 * freed while work is queued. Release it afterwards.
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index f1c452f618a9..337106469ec5 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -147,6 +147,7 @@ struct fib_info {
 #define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
 #define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
 	int			fib_nhs;
+	bool			fib_nh_is_v6;
 	struct rcu_head		rcu;
 	struct fib_nh		fib_nh[0];
 #define fib_dev		fib_nh[0].fib_nh_dev
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index c1ea138335a2..4a968e24507b 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1349,6 +1349,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
 
 	change_nexthops(fi) {
 		fib_info_update_nh_saddr(net, nexthop_nh);
+		if (nexthop_nh->fib_nh_gw_family == AF_INET6)
+			fi->fib_nh_is_v6 = true;
 	} endfor_nexthops(fi)
 
 	fib_rebalance(fi);
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 17/18] ipv4: Allow ipv6 gateway with ipv4 routes
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (15 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 16/18] ipv4: Flag fib_info with a fib_nh using IPv6 gateway David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-05 23:30 ` [PATCH v2 net-next 18/18] selftests: fib_tests: Add tests for ipv6 gateway with ipv4 route David Ahern
  2019-04-08 22:24 ` [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Miller
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add support for RTA_VIA and allow an IPv6 nexthop for v4 routes:
   $ ip ro add 172.16.1.0/24 via inet6 2001:db8::1 dev eth0
   $ ip ro ls
   ...
   172.16.1.0/24 via inet6 2001:db8::1 dev eth0

For convenience and simplicity, userspace can use RTA_VIA to specify
AF_INET or AF_INET6 gateway.

The common fib_nexthop_info dump function compares the gateway address
family to the nh_common family to know if the gateway should be encoded
as RTA_VIA or RTA_GATEWAY.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/ip_fib.h     |  2 ++
 net/ipv4/fib_frontend.c  | 60 ++++++++++++++++++++++++++++++++++++++---
 net/ipv4/fib_semantics.c | 69 ++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 123 insertions(+), 8 deletions(-)

diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 337106469ec5..d8195c77e247 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -401,6 +401,8 @@ static inline bool fib4_rules_early_flow_dissect(struct net *net,
 /* Exported by fib_frontend.c */
 extern const struct nla_policy rtm_ipv4_policy[];
 void ip_fib_init(void);
+int fib_gw_from_via(struct fib_config *cfg, struct nlattr *nla,
+		    struct netlink_ext_ack *extack);
 __be32 fib_compute_spec_dst(struct sk_buff *skb);
 bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev);
 int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index f99a2ec32505..310060e67790 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -665,10 +665,55 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
 	[RTA_DPORT]		= { .type = NLA_U16 },
 };
 
+int fib_gw_from_via(struct fib_config *cfg, struct nlattr *nla,
+		    struct netlink_ext_ack *extack)
+{
+	struct rtvia *via;
+	int alen;
+
+	if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
+		NL_SET_ERR_MSG(extack, "Invalid attribute length for RTA_VIA");
+		return -EINVAL;
+	}
+
+	via = nla_data(nla);
+	alen = nla_len(nla) - offsetof(struct rtvia, rtvia_addr);
+
+	switch (via->rtvia_family) {
+	case AF_INET:
+		if (alen != sizeof(__be32)) {
+			NL_SET_ERR_MSG(extack, "Invalid IPv4 address in RTA_VIA");
+			return -EINVAL;
+		}
+		cfg->fc_gw_family = AF_INET;
+		cfg->fc_gw4 = *((__be32 *)via->rtvia_addr);
+		break;
+	case AF_INET6:
+#ifdef CONFIG_IPV6
+		if (alen != sizeof(struct in6_addr)) {
+			NL_SET_ERR_MSG(extack, "Invalid IPv6 address in RTA_VIA");
+			return -EINVAL;
+		}
+		cfg->fc_gw_family = AF_INET6;
+		cfg->fc_gw6 = *((struct in6_addr *)via->rtvia_addr);
+#else
+		NL_SET_ERR_MSG(extack, "IPv6 support not enabled in kernel");
+		return -EINVAL;
+#endif
+		break;
+	default:
+		NL_SET_ERR_MSG(extack, "Unsupported address family in RTA_VIA");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
 			     struct nlmsghdr *nlh, struct fib_config *cfg,
 			     struct netlink_ext_ack *extack)
 {
+	bool has_gw = false, has_via = false;
 	struct nlattr *attr;
 	int err, remaining;
 	struct rtmsg *rtm;
@@ -709,13 +754,16 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
 			cfg->fc_oif = nla_get_u32(attr);
 			break;
 		case RTA_GATEWAY:
+			has_gw = true;
 			cfg->fc_gw_family = AF_INET;
 			cfg->fc_gw4 = nla_get_be32(attr);
 			break;
 		case RTA_VIA:
-			NL_SET_ERR_MSG(extack, "IPv4 does not support RTA_VIA attribute");
-			err = -EINVAL;
-			goto errout;
+			has_via = true;
+			err = fib_gw_from_via(cfg, attr, extack);
+			if (err)
+				goto errout;
+			break;
 		case RTA_PRIORITY:
 			cfg->fc_priority = nla_get_u32(attr);
 			break;
@@ -754,6 +802,12 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
 		}
 	}
 
+	if (has_gw && has_via) {
+		NL_SET_ERR_MSG(extack,
+			       "Nexthop configuration can not contain both GATEWAY and VIA");
+		goto errout;
+	}
+
 	return 0;
 errout:
 	return err;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4a968e24507b..017273885eee 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -606,12 +606,22 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
 
 		attrlen = rtnh_attrlen(rtnh);
 		if (attrlen > 0) {
-			struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
+			struct nlattr *nla, *nlav, *attrs = rtnh_attrs(rtnh);
 
 			nla = nla_find(attrs, attrlen, RTA_GATEWAY);
+			nlav = nla_find(attrs, attrlen, RTA_VIA);
+			if (nla && nlav) {
+				NL_SET_ERR_MSG(extack,
+					       "Nexthop configuration can not contain both GATEWAY and VIA");
+				return -EINVAL;
+			}
 			if (nla) {
 				fib_cfg.fc_gw_family = AF_INET;
 				fib_cfg.fc_gw4 = nla_get_in_addr(nla);
+			} else if (nlav) {
+				ret = fib_gw_from_via(&fib_cfg, nlav, extack);
+				if (ret)
+					goto errout;
 			}
 
 			nla = nla_find(attrs, attrlen, RTA_FLOW);
@@ -792,11 +802,43 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
 
 		attrlen = rtnh_attrlen(rtnh);
 		if (attrlen > 0) {
-			struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
+			struct nlattr *nla, *nlav, *attrs = rtnh_attrs(rtnh);
 
 			nla = nla_find(attrs, attrlen, RTA_GATEWAY);
-			if (nla && nla_get_in_addr(nla) != nh->fib_nh_gw4)
-				return 1;
+			nlav = nla_find(attrs, attrlen, RTA_VIA);
+			if (nla && nlav) {
+				NL_SET_ERR_MSG(extack,
+					       "Nexthop configuration can not contain both GATEWAY and VIA");
+				return -EINVAL;
+			}
+
+			if (nla) {
+				if (nh->fib_nh_gw_family != AF_INET ||
+				    nla_get_in_addr(nla) != nh->fib_nh_gw4)
+					return 1;
+			} else if (nlav) {
+				struct fib_config cfg2;
+				int err;
+
+				err = fib_gw_from_via(&cfg2, nlav, extack);
+				if (err)
+					return err;
+
+				switch (nh->fib_nh_gw_family) {
+				case AF_INET:
+					if (cfg2.fc_gw_family != AF_INET ||
+					    cfg2.fc_gw4 != nh->fib_nh_gw4)
+						return 1;
+					break;
+				case AF_INET6:
+					if (cfg2.fc_gw_family != AF_INET6 ||
+					    ipv6_addr_cmp(&cfg2.fc_gw6,
+							  &nh->fib_nh_gw6))
+						return 1;
+					break;
+				}
+			}
+
 #ifdef CONFIG_IP_ROUTE_CLASSID
 			nla = nla_find(attrs, attrlen, RTA_FLOW);
 			if (nla && nla_get_u32(nla) != nh->nh_tclassid)
@@ -1429,8 +1471,25 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
 			goto nla_put_failure;
 		break;
 	case AF_INET6:
-		if (nla_put_in6_addr(skb, RTA_GATEWAY, &nhc->nhc_gw.ipv6) < 0)
+		/* if gateway family does not match nexthop family
+		 * gateway is encoded as RTA_VIA
+		 */
+		if (nhc->nhc_gw_family != nhc->nhc_family) {
+			int alen = sizeof(struct in6_addr);
+			struct nlattr *nla;
+			struct rtvia *via;
+
+			nla = nla_reserve(skb, RTA_VIA, alen + 2);
+			if (!nla)
+				goto nla_put_failure;
+
+			via = nla_data(nla);
+			via->rtvia_family = AF_INET6;
+			memcpy(via->rtvia_addr, &nhc->nhc_gw.ipv6, alen);
+		} else if (nla_put_in6_addr(skb, RTA_GATEWAY,
+					    &nhc->nhc_gw.ipv6) < 0) {
 			goto nla_put_failure;
+		}
 		break;
 	}
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 net-next 18/18] selftests: fib_tests: Add tests for ipv6 gateway with ipv4 route
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (16 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 17/18] ipv4: Allow ipv6 gateway with ipv4 routes David Ahern
@ 2019-04-05 23:30 ` David Ahern
  2019-04-08 22:24 ` [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Miller
  18 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-05 23:30 UTC (permalink / raw)
  To: davem, netdev; +Cc: idosch, jiri, David Ahern

From: David Ahern <dsahern@gmail.com>

Add tests for ipv6 gateway with ipv4 route. Tests include basic
single path with ping to verify connectivity and multipath.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fib_tests.sh | 70 +++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index 1080ff55a788..e941024869ff 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -9,7 +9,8 @@ ret=0
 ksft_skip=4
 
 # all tests in this script. Can be overridden with -t option
-TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics"
+TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw"
+
 VERBOSE=0
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -48,6 +49,7 @@ setup()
 {
 	set -e
 	ip netns add ns1
+	ip netns set ns1 auto
 	$IP link set dev lo up
 	ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
 	ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
@@ -698,6 +700,7 @@ route_setup()
 	set -e
 
 	ip netns add ns2
+	ip netns set ns2 auto
 	ip -netns ns2 link set dev lo up
 	ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
 	ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
@@ -1442,6 +1445,70 @@ ipv4_route_metrics_test()
 	route_cleanup
 }
 
+ipv4_route_v6_gw_test()
+{
+	local rc
+
+	echo
+	echo "IPv4 route with IPv6 gateway tests"
+
+	route_setup
+	sleep 2
+
+	#
+	# single path route
+	#
+	run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
+	rc=$?
+	log_test $rc 0 "Single path route with IPv6 gateway"
+	if [ $rc -eq 0 ]; then
+		check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
+	fi
+
+	run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
+	log_test $rc 0 "Single path route with IPv6 gateway - ping"
+
+	run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
+	rc=$?
+	log_test $rc 0 "Single path route delete"
+	if [ $rc -eq 0 ]; then
+		check_route "172.16.112.0/24"
+	fi
+
+	#
+	# multipath - v6 then v4
+	#
+	run_cmd "$IP ro add 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
+	rc=$?
+	log_test $rc 0 "Multipath route add - v6 nexthop then v4"
+	if [ $rc -eq 0 ]; then
+		check_route "172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
+	fi
+
+	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
+	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
+
+	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
+	log_test $? 0 "    Multipath route delete exact match"
+
+	#
+	# multipath - v4 then v6
+	#
+	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
+	rc=$?
+	log_test $rc 0 "Multipath route add - v4 nexthop then v6"
+	if [ $rc -eq 0 ]; then
+		check_route "172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 weight 1 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1"
+	fi
+
+	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
+	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
+
+	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
+	log_test $? 0 "    Multipath route delete exact match"
+
+	route_cleanup
+}
 
 ################################################################################
 # usage
@@ -1511,6 +1578,7 @@ do
 	ipv4_addr_metric)		ipv4_addr_metric_test;;
 	ipv6_route_metrics)		ipv6_route_metrics_test;;
 	ipv4_route_metrics)		ipv4_route_metrics_test;;
+	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
 
 	help) echo "Test names: $TESTS"; exit 0;;
 	esac
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes
  2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
                   ` (17 preceding siblings ...)
  2019-04-05 23:30 ` [PATCH v2 net-next 18/18] selftests: fib_tests: Add tests for ipv6 gateway with ipv4 route David Ahern
@ 2019-04-08 22:24 ` David Miller
  18 siblings, 0 replies; 25+ messages in thread
From: David Miller @ 2019-04-08 22:24 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, idosch, jiri, dsahern

From: David Ahern <dsahern@kernel.org>
Date: Fri,  5 Apr 2019 16:30:23 -0700

> Last set of three with the end goal of enabling IPv6 gateways with IPv4
> routes.

Series applied, thanks David.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-05 23:30 ` [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh David Ahern
@ 2019-04-10  0:08   ` Govindarajulu Varadarajan
  2019-04-10  0:43     ` David Ahern
  2019-04-10  2:13     ` David Ahern
  0 siblings, 2 replies; 25+ messages in thread
From: Govindarajulu Varadarajan @ 2019-04-10  0:08 UTC (permalink / raw)
  To: David Ahern
  Cc: davem, netdev, idosch, jiri, David Ahern, govind.varadar, benve

On Fri, Apr 5, 2019 at 4:32 PM David Ahern <dsahern@kernel.org> wrote:
>
> From: David Ahern <dsahern@gmail.com>
>
> fib_check_nh is currently huge covering multiple uses cases - device only,
> device + gateway, and device + gateway with ONLINK. The next patch adds
> validation checks for IPv6 which only further complicates it. So, break
> fib_check_nh into 2 helpers - one for gateway validation and one for device
> only.
>
> Signed-off-by: David Ahern <dsahern@gmail.com>
> Reviewed-by: Ido Schimmel <idosch@mellanox.com>

With the latest net-next I am having issue with network traffic.
git bisect points to this commit as the first bad commit.
(448d7248191706cbbd7761e3bc72c2985c4d38a7 ipv4: Refactor fib_check_nh)

I do not understand this part of kernel, from what I see, this patch
rejects the default route added by NetworkManager.
[gvaradar@240m5avmarch ~]$ sudo ip route add 192.168.0.0/24 via
0.0.0.0 dev bm0 proto kernel scope link src 192.168.0.1 metric 101
Error: Nexthop has invalid gateway.

Is this request valid or is this an issue with NetworkManager? This
used to work before,
[gvaradar@240m5avmarch linux]$ ip route
default via 10.193.164.254 dev e0 proto dhcp metric 100
10.193.164.0/24 via 0.0.0.0 dev e0 proto kernel scope link src
10.193.164.12 metric 100
192.168.0.0/24 via 0.0.0.0 dev bm0 proto kernel scope link src
192.168.0.1 metric 101

I do not know why NetworkManager is adding "via 0.0.0.0".
192.168.0.0/24 is a local subnet.

Either way, this seems to break odd behavior of NetworkManager.

--
Govind

Network details:
[NOT WORKING]: HEAD of net-next
[gvaradar@240m5avmarch ~]$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity
0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536
gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: e0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state
UP group default qlen 1000
    link/ether 52:54:00:64:86:b6 brd ff:ff:ff:ff:ff:ff promiscuity 0
minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536
gso_max_segs 65535
    inet 10.193.164.12/24 brd 10.193.164.255 scope global dynamic
noprefixroute e0
       valid_lft 21430sec preferred_lft 21430sec
    inet6 fe80::1f95:bfca:8e05:9448/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: bm0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP
group default qlen 1000
    link/ether 00:fc:ba:a2:9c:d5 brd ff:ff:ff:ff:ff:ff promiscuity 0
minmtu 68 maxmtu 9000 numtxqueues 8 numrxqueues 8 gso_max_size 65536
gso_max_segs 65535
    inet 192.168.0.1/24 brd 192.168.0.255 scope global noprefixroute bm0
       valid_lft forever preferred_lft forever
    inet6 fe80::5988:7d2:a671:6c7d/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
[gvaradar@240m5avmarch ~]$ ip route
[gvaradar@240m5avmarch ~]$ ping 192.168.0.2 -c2
connect: Network is unreachable
[gvaradar@240m5avmarch ~]$ sudo ip route add 192.168.0.0/24 dev bm0
[gvaradar@240m5avmarch ~]$ ip route
192.168.0.0/24 dev bm0 scope link
[gvaradar@240m5avmarch ~]$ ping 192.168.0.2 -c2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.121 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.065 ms
[gvaradar@240m5avmarch ~]$ sudo ip route add 192.168.0.0/24 via
0.0.0.0 dev bm0 proto kernel scope link src 192.168.0.1 metric 101
Error: Nexthop has invalid gateway.
[root@240m5avmarch ~]# systemctl stop NetworkManager
[root@240m5avmarch ~]# netctl start bm0
[root@240m5avmarch ~]# ip route
192.168.0.0/24 dev bm0 proto kernel scope link src 192.168.0.1
[root@240m5avmarch ~]# ping 192.168.0.2 -c2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.184 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.050 ms


[Working]: #First working commit
[gvaradar@240m5avmarch linux]$ git log -1
commit a4ea5d43c807be28545625c1e0641905022fa0d1 (HEAD,
refs/bisect/good-a4ea5d43c807be28545625c1e0641905022fa0d1)
Author: David Ahern <dsahern@gmail.com>
Date:   Fri Apr 5 16:30:30 2019 -0700

    ipv4: Add support to fib_config for IPv6 gateway

    Add support for an IPv6 gateway to fib_config. Since a gateway is either
    IPv4 or IPv6, make it a union with fc_gw4 where fc_gw_family decides
    which address is in use. Update current checks on family and gw4 to
    handle ipv6 as well.

    Signed-off-by: David Ahern <dsahern@gmail.com>
    Reviewed-by: Ido Schimmel <idosch@mellanox.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

[gvaradar@240m5avmarch linux]$ ip route
default via 10.193.164.254 dev e0 proto dhcp metric 100
10.193.164.0/24 via 0.0.0.0 dev e0 proto kernel scope link src
10.193.164.12 metric 100
192.168.0.0/24 via 0.0.0.0 dev bm0 proto kernel scope link src
192.168.0.1 metric 101
[gvaradar@240m5avmarch linux]$ ping 192.168.0.2 -c4
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from 192.168.0.2: icmp_seq=4 ttl=64 time=0.071 ms
...
[gvaradar@240m5avmarch linux]$ sudo ip route del 192.168.0.0/24
[gvaradar@240m5avmarch linux]$ ip route
default via 10.193.164.254 dev e0 proto dhcp metric 100
10.193.164.0/24 via 0.0.0.0 dev e0 proto kernel scope link src
10.193.164.12 metric 100
[gvaradar@240m5avmarch linux]$ sudo ip route add 192.168.0.0/24 via
0.0.0.0 dev bm0 proto kernel scope link src 192.168.0.1 metric 101
[gvaradar@240m5avmarch linux]$ ip route
default via 10.193.164.254 dev e0 proto dhcp metric 100
10.193.164.0/24 via 0.0.0.0 dev e0 proto kernel scope link src
10.193.164.12 metric 100
192.168.0.0/24 via 0.0.0.0 dev bm0 proto kernel scope link src
192.168.0.1 metric 101

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-10  0:08   ` Govindarajulu Varadarajan
@ 2019-04-10  0:43     ` David Ahern
  2019-04-10  2:13     ` David Ahern
  1 sibling, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-10  0:43 UTC (permalink / raw)
  To: Govindarajulu Varadarajan, David Ahern; +Cc: davem, netdev, idosch, jiri, benve

On 4/9/19 5:08 PM, Govindarajulu Varadarajan wrote:
> On Fri, Apr 5, 2019 at 4:32 PM David Ahern <dsahern@kernel.org> wrote:
>>
>> From: David Ahern <dsahern@gmail.com>
>>
>> fib_check_nh is currently huge covering multiple uses cases - device only,
>> device + gateway, and device + gateway with ONLINK. The next patch adds
>> validation checks for IPv6 which only further complicates it. So, break
>> fib_check_nh into 2 helpers - one for gateway validation and one for device
>> only.
>>
>> Signed-off-by: David Ahern <dsahern@gmail.com>
>> Reviewed-by: Ido Schimmel <idosch@mellanox.com>
> 
> With the latest net-next I am having issue with network traffic.
> git bisect points to this commit as the first bad commit.
> (448d7248191706cbbd7761e3bc72c2985c4d38a7 ipv4: Refactor fib_check_nh)
> 

Thanks for the report. I'll take a look tonight.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-10  0:08   ` Govindarajulu Varadarajan
  2019-04-10  0:43     ` David Ahern
@ 2019-04-10  2:13     ` David Ahern
  2019-04-10  5:31       ` Govindarajulu Varadarajan
  1 sibling, 1 reply; 25+ messages in thread
From: David Ahern @ 2019-04-10  2:13 UTC (permalink / raw)
  To: Govindarajulu Varadarajan, David Ahern; +Cc: davem, netdev, idosch, jiri, benve

On 4/9/19 5:08 PM, Govindarajulu Varadarajan wrote:
> On Fri, Apr 5, 2019 at 4:32 PM David Ahern <dsahern@kernel.org> wrote:
>>
>> From: David Ahern <dsahern@gmail.com>
>>
>> fib_check_nh is currently huge covering multiple uses cases - device only,
>> device + gateway, and device + gateway with ONLINK. The next patch adds
>> validation checks for IPv6 which only further complicates it. So, break
>> fib_check_nh into 2 helpers - one for gateway validation and one for device
>> only.
>>
>> Signed-off-by: David Ahern <dsahern@gmail.com>
>> Reviewed-by: Ido Schimmel <idosch@mellanox.com>
> 
> With the latest net-next I am having issue with network traffic.
> git bisect points to this commit as the first bad commit.
> (448d7248191706cbbd7761e3bc72c2985c4d38a7 ipv4: Refactor fib_check_nh)
> 

Can you see if this fixes it? whitespace damaged, but fairly simple to
apply manually:

diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 017273885eee..779d2be2b135 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -616,8 +616,9 @@ static int fib_get_nhs(struct fib_info *fi, struct
rtnexthop *rtnh,
                                return -EINVAL;
                        }
                        if (nla) {
-                               fib_cfg.fc_gw_family = AF_INET;
                                fib_cfg.fc_gw4 = nla_get_in_addr(nla);
+                               if (fib_cfg.fc_gw4)
+                                       fib_cfg.fc_gw_family = AF_INET;
                        } else if (nlav) {
                                ret = fib_gw_from_via(&fib_cfg, nlav,
extack);
                                if (ret)

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-10  2:13     ` David Ahern
@ 2019-04-10  5:31       ` Govindarajulu Varadarajan
  2019-04-10 15:44         ` David Ahern
  0 siblings, 1 reply; 25+ messages in thread
From: Govindarajulu Varadarajan @ 2019-04-10  5:31 UTC (permalink / raw)
  To: David Ahern
  Cc: David Ahern, davem, netdev, idosch, jiri, benve, govind.varadar

On Tue, Apr 9, 2019 at 7:13 PM David Ahern <dsahern@gmail.com> wrote:
>
> On 4/9/19 5:08 PM, Govindarajulu Varadarajan wrote:
> > On Fri, Apr 5, 2019 at 4:32 PM David Ahern <dsahern@kernel.org> wrote:
> >>
> >> From: David Ahern <dsahern@gmail.com>
> >>
> >> fib_check_nh is currently huge covering multiple uses cases - device only,
> >> device + gateway, and device + gateway with ONLINK. The next patch adds
> >> validation checks for IPv6 which only further complicates it. So, break
> >> fib_check_nh into 2 helpers - one for gateway validation and one for device
> >> only.
> >>
> >> Signed-off-by: David Ahern <dsahern@gmail.com>
> >> Reviewed-by: Ido Schimmel <idosch@mellanox.com>
> >
> > With the latest net-next I am having issue with network traffic.
> > git bisect points to this commit as the first bad commit.
> > (448d7248191706cbbd7761e3bc72c2985c4d38a7 ipv4: Refactor fib_check_nh)
> >
>
> Can you see if this fixes it? whitespace damaged, but fairly simple to
> apply manually:
>
> diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
> index 017273885eee..779d2be2b135 100644
> --- a/net/ipv4/fib_semantics.c
> +++ b/net/ipv4/fib_semantics.c
> @@ -616,8 +616,9 @@ static int fib_get_nhs(struct fib_info *fi, struct
> rtnexthop *rtnh,
>                                 return -EINVAL;
>                         }
>                         if (nla) {
> -                               fib_cfg.fc_gw_family = AF_INET;
>                                 fib_cfg.fc_gw4 = nla_get_in_addr(nla);
> +                               if (fib_cfg.fc_gw4)
> +                                       fib_cfg.fc_gw_family = AF_INET;
>                         } else if (nlav) {
>                                 ret = fib_gw_from_via(&fib_cfg, nlav,
> extack);
>                                 if (ret)
This did not work.

However this worked

@@ -1096,7 +1096,7 @@ static int fib_check_nh(struct fib_config *cfg,
struct fib_nh *nh,
        u32 table = cfg->fc_table;
        int err;

-       if (nh->fib_nh_gw_family == AF_INET)
+       if (nh->fib_nh_gw4)
                err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
        else if (nh->fib_nh_gw_family == AF_INET6)
                err = fib_check_nh_v6_gw(net, nh, table, extack);

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh
  2019-04-10  5:31       ` Govindarajulu Varadarajan
@ 2019-04-10 15:44         ` David Ahern
  0 siblings, 0 replies; 25+ messages in thread
From: David Ahern @ 2019-04-10 15:44 UTC (permalink / raw)
  To: Govindarajulu Varadarajan; +Cc: David Ahern, davem, netdev, idosch, jiri, benve

On 4/9/19 10:31 PM, Govindarajulu Varadarajan wrote:
> However this worked
> 
> @@ -1096,7 +1096,7 @@ static int fib_check_nh(struct fib_config *cfg,
> struct fib_nh *nh,
>         u32 table = cfg->fc_table;
>         int err;
> 
> -       if (nh->fib_nh_gw_family == AF_INET)
> +       if (nh->fib_nh_gw4)
>                 err = fib_check_nh_v4_gw(net, nh, table, cfg->fc_scope, extack);
>         else if (nh->fib_nh_gw_family == AF_INET6)
>                 err = fib_check_nh_v6_gw(net, nh, table, extack);
> 

since fib_nh_gw4 is a union that cannot be used without checking the
family first. You need this part as well (previous hunk was for mpath
routes):

diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 310060e67790..d4b63f94f7be 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -755,8 +755,9 @@ static int rtm_to_fib_config(struct net *net, struct
sk_buff *skb,
                        break;
                case RTA_GATEWAY:
                        has_gw = true;
-                       cfg->fc_gw_family = AF_INET;
                        cfg->fc_gw4 = nla_get_be32(attr);
+                       if (cfg->fc_gw4)
+                               cfg->fc_gw_family = AF_INET;
                        break;
                case RTA_VIA:
                        has_via = true;

^ permalink raw reply related	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2019-04-10 15:44 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-05 23:30 [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 01/18] ipv6: Add fib6_nh_init and release to stubs David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 02/18] ipv6: Add neighbor helpers that use the ipv6 stub David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 03/18] net: Replace nhc_has_gw with nhc_gw_family David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 04/18] ipv4: Prepare rtable for IPv6 gateway David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 05/18] ipv4: Prepare fib_config " David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 06/18] ipv4: Add support to rtable for ipv6 gateway David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 07/18] ipv4: Add support to fib_config for IPv6 gateway David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 08/18] ipv4: Refactor fib_check_nh David Ahern
2019-04-10  0:08   ` Govindarajulu Varadarajan
2019-04-10  0:43     ` David Ahern
2019-04-10  2:13     ` David Ahern
2019-04-10  5:31       ` Govindarajulu Varadarajan
2019-04-10 15:44         ` David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 09/18] ipv4: Add fib_check_nh_v6_gw David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 10/18] neighbor: Add skip_cache argument to neigh_output David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 11/18] ipv4: Add helpers for neigh lookup for nexthop David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 12/18] bpf: Handle ipv6 gateway in bpf_ipv4_fib_lookup David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 13/18] ipv4: Handle ipv6 gateway in ipv4_confirm_neigh David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 14/18] ipv4: Handle ipv6 gateway in fib_detect_death David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 15/18] ipv4: Handle ipv6 gateway in fib_good_nh David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 16/18] ipv4: Flag fib_info with a fib_nh using IPv6 gateway David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 17/18] ipv4: Allow ipv6 gateway with ipv4 routes David Ahern
2019-04-05 23:30 ` [PATCH v2 net-next 18/18] selftests: fib_tests: Add tests for ipv6 gateway with ipv4 route David Ahern
2019-04-08 22:24 ` [PATCH v2 net-next 00/18] ipv4: Enable support for IPv6 gateway with IPv4 routes David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.