| From 34613f26a8aec61daba60448f5c621446e1fc1cb Mon Sep 17 00:00:00 2001 |
| From: Sabrina Dubroca <sd@queasysnail.net> |
| Date: Wed, 4 Dec 2019 15:35:53 +0100 |
| Subject: [PATCH] net: ipv6_stub: use ip6_dst_lookup_flow instead of |
| ip6_dst_lookup |
| |
| commit 6c8991f41546c3c472503dff1ea9daaddf9331c2 upstream. |
| |
| ipv6_stub uses the ip6_dst_lookup function to allow other modules to |
| perform IPv6 lookups. However, this function skips the XFRM layer |
| entirely. |
| |
| All users of ipv6_stub->ip6_dst_lookup use ip_route_output_flow (via the |
| ip_route_output_key and ip_route_output helpers) for their IPv4 lookups, |
| which calls xfrm_lookup_route(). This patch fixes this inconsistent |
| behavior by switching the stub to ip6_dst_lookup_flow, which also calls |
| xfrm_lookup_route(). |
| |
| This requires some changes in all the callers, as these two functions |
| take different arguments and have different return types. |
| |
| Fixes: 5f81bd2e5d80 ("ipv6: export a stub for IPv6 symbols used by vxlan") |
| Reported-by: Xiumei Mu <xmu@redhat.com> |
| Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c |
| index bf539c34ccd3..fca5025d5a1a 100644 |
| --- a/drivers/infiniband/core/addr.c |
| +++ b/drivers/infiniband/core/addr.c |
| @@ -421,16 +421,15 @@ static int addr6_resolve(struct sockaddr *src_sock, |
| (const struct sockaddr_in6 *)dst_sock; |
| struct flowi6 fl6; |
| struct dst_entry *dst; |
| - int ret; |
| |
| memset(&fl6, 0, sizeof fl6); |
| fl6.daddr = dst_in->sin6_addr; |
| fl6.saddr = src_in->sin6_addr; |
| fl6.flowi6_oif = addr->bound_dev_if; |
| |
| - ret = ipv6_stub->ipv6_dst_lookup(addr->net, NULL, &dst, &fl6); |
| - if (ret < 0) |
| - return ret; |
| + dst = ipv6_stub->ipv6_dst_lookup_flow(addr->net, NULL, &fl6, NULL); |
| + if (IS_ERR(dst)) |
| + return PTR_ERR(dst); |
| |
| if (ipv6_addr_any(&src_in->sin6_addr)) |
| src_in->sin6_addr = fl6.saddr; |
| diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c |
| index 5a3474f9351b..312c2fc961c0 100644 |
| --- a/drivers/infiniband/sw/rxe/rxe_net.c |
| +++ b/drivers/infiniband/sw/rxe/rxe_net.c |
| @@ -117,10 +117,12 @@ static struct dst_entry *rxe_find_route6(struct net_device *ndev, |
| memcpy(&fl6.daddr, daddr, sizeof(*daddr)); |
| fl6.flowi6_proto = IPPROTO_UDP; |
| |
| - if (unlikely(ipv6_stub->ipv6_dst_lookup(sock_net(recv_sockets.sk6->sk), |
| - recv_sockets.sk6->sk, &ndst, &fl6))) { |
| + ndst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(recv_sockets.sk6->sk), |
| + recv_sockets.sk6->sk, &fl6, |
| + NULL); |
| + if (unlikely(IS_ERR(ndst))) { |
| pr_err_ratelimited("no route to %pI6\n", daddr); |
| - goto put; |
| + return NULL; |
| } |
| |
| if (unlikely(ndst->error)) { |
| 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 e24ed34093fc..0b6d2b49c644 100644 |
| --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c |
| +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c |
| @@ -122,10 +122,10 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, |
| #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) |
| int ret; |
| |
| - ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst, |
| - fl6); |
| - if (ret < 0) |
| - return ret; |
| + dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(mirred_dev), NULL, fl6, |
| + NULL); |
| + if (IS_ERR(dst)) |
| + return PTR_ERR(dst); |
| |
| if (!(*out_ttl)) |
| *out_ttl = ip6_dst_hoplimit(dst); |
| diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c |
| index cb2ea8facd8d..ac1470a6c64f 100644 |
| --- a/drivers/net/geneve.c |
| +++ b/drivers/net/geneve.c |
| @@ -853,7 +853,9 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, |
| if (dst) |
| return dst; |
| } |
| - if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) { |
| + dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6, |
| + NULL); |
| + if (IS_ERR(dst)) { |
| netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr); |
| return ERR_PTR(-ENETUNREACH); |
| } |
| diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c |
| index 48d3002e2775..ef55df321129 100644 |
| --- a/drivers/net/vxlan.c |
| +++ b/drivers/net/vxlan.c |
| @@ -2262,7 +2262,6 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, |
| bool use_cache = ip_tunnel_dst_cache_usable(skb, info); |
| struct dst_entry *ndst; |
| struct flowi6 fl6; |
| - int err; |
| |
| if (!sock6) |
| return ERR_PTR(-EIO); |
| @@ -2285,10 +2284,9 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, |
| fl6.fl6_dport = dport; |
| fl6.fl6_sport = sport; |
| |
| - err = ipv6_stub->ipv6_dst_lookup(vxlan->net, |
| - sock6->sock->sk, |
| - &ndst, &fl6); |
| - if (unlikely(err < 0)) { |
| + ndst = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net, sock6->sock->sk, |
| + &fl6, NULL); |
| + if (unlikely(IS_ERR(ndst))) { |
| netdev_dbg(dev, "no route to %pI6\n", daddr); |
| return ERR_PTR(-ENETUNREACH); |
| } |
| diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h |
| index 6c0c4fde16f8..174a5ae48889 100644 |
| --- a/include/net/ipv6_stubs.h |
| +++ b/include/net/ipv6_stubs.h |
| @@ -24,8 +24,10 @@ struct ipv6_stub { |
| const struct in6_addr *addr); |
| int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex, |
| const struct in6_addr *addr); |
| - int (*ipv6_dst_lookup)(struct net *net, struct sock *sk, |
| - struct dst_entry **dst, struct flowi6 *fl6); |
| + struct dst_entry *(*ipv6_dst_lookup_flow)(struct net *net, |
| + const struct sock *sk, |
| + struct flowi6 *fl6, |
| + const struct in6_addr *final_dst); |
| int (*ipv6_route_input)(struct sk_buff *skb); |
| |
| struct fib6_table *(*fib6_get_table)(struct net *net, u32 id); |
| diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c |
| index 74cfb8b5ab33..99a6de52b21d 100644 |
| --- a/net/core/lwt_bpf.c |
| +++ b/net/core/lwt_bpf.c |
| @@ -230,9 +230,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) |
| fl6.daddr = iph6->daddr; |
| fl6.saddr = iph6->saddr; |
| |
| - err = ipv6_stub->ipv6_dst_lookup(net, skb->sk, &dst, &fl6); |
| - if (unlikely(err)) |
| - goto err; |
| + dst = ipv6_stub->ipv6_dst_lookup_flow(net, skb->sk, &fl6, NULL); |
| if (IS_ERR(dst)) { |
| err = PTR_ERR(dst); |
| goto err; |
| diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c |
| index 5b1246635e02..0ceb8943d648 100644 |
| --- a/net/ipv6/addrconf_core.c |
| +++ b/net/ipv6/addrconf_core.c |
| @@ -128,11 +128,12 @@ int inet6addr_validator_notifier_call_chain(unsigned long val, void *v) |
| } |
| EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain); |
| |
| -static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1, |
| - struct dst_entry **u2, |
| - struct flowi6 *u3) |
| +static struct dst_entry *eafnosupport_ipv6_dst_lookup_flow(struct net *net, |
| + const struct sock *sk, |
| + struct flowi6 *fl6, |
| + const struct in6_addr *final_dst) |
| { |
| - return -EAFNOSUPPORT; |
| + return ERR_PTR(-EAFNOSUPPORT); |
| } |
| |
| static int eafnosupport_ipv6_route_input(struct sk_buff *skb) |
| @@ -184,7 +185,7 @@ static int eafnosupport_fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, |
| } |
| |
| const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { |
| - .ipv6_dst_lookup = eafnosupport_ipv6_dst_lookup, |
| + .ipv6_dst_lookup_flow = eafnosupport_ipv6_dst_lookup_flow, |
| .ipv6_route_input = eafnosupport_ipv6_route_input, |
| .fib6_get_table = eafnosupport_fib6_get_table, |
| .fib6_table_lookup = eafnosupport_fib6_table_lookup, |
| diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c |
| index d4b22c56aa8b..1c4bb0c73307 100644 |
| --- a/net/ipv6/af_inet6.c |
| +++ b/net/ipv6/af_inet6.c |
| @@ -913,7 +913,7 @@ static int ipv6_route_input(struct sk_buff *skb) |
| static const struct ipv6_stub ipv6_stub_impl = { |
| .ipv6_sock_mc_join = ipv6_sock_mc_join, |
| .ipv6_sock_mc_drop = ipv6_sock_mc_drop, |
| - .ipv6_dst_lookup = ip6_dst_lookup, |
| + .ipv6_dst_lookup_flow = ip6_dst_lookup_flow, |
| .ipv6_route_input = ipv6_route_input, |
| .fib6_get_table = fib6_get_table, |
| .fib6_table_lookup = fib6_table_lookup, |
| diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c |
| index 198ec4fe4148..8ff1c6120b1e 100644 |
| --- a/net/mpls/af_mpls.c |
| +++ b/net/mpls/af_mpls.c |
| @@ -619,16 +619,15 @@ static struct net_device *inet6_fib_lookup_dev(struct net *net, |
| struct net_device *dev; |
| struct dst_entry *dst; |
| struct flowi6 fl6; |
| - int err; |
| |
| if (!ipv6_stub) |
| return ERR_PTR(-EAFNOSUPPORT); |
| |
| memset(&fl6, 0, sizeof(fl6)); |
| memcpy(&fl6.daddr, addr, sizeof(struct in6_addr)); |
| - err = ipv6_stub->ipv6_dst_lookup(net, NULL, &dst, &fl6); |
| - if (err) |
| - return ERR_PTR(err); |
| + dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &fl6, NULL); |
| + if (IS_ERR(dst)) |
| + return ERR_CAST(dst); |
| |
| dev = dst->dev; |
| dev_hold(dev); |
| diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c |
| index 1405ccc9101c..c879bb1ca01a 100644 |
| --- a/net/tipc/udp_media.c |
| +++ b/net/tipc/udp_media.c |
| @@ -189,10 +189,12 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, |
| .saddr = src->ipv6, |
| .flowi6_proto = IPPROTO_UDP |
| }; |
| - err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst, |
| - &fl6); |
| - if (err) |
| + ndst = ipv6_stub->ipv6_dst_lookup_flow(net, ub->ubsock->sk, |
| + &fl6, NULL); |
| + if (IS_ERR(ndst)) { |
| + err = PTR_ERR(ndst); |
| goto tx_error; |
| + } |
| ttl = ip6_dst_hoplimit(ndst); |
| err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, |
| &src->ipv6, &dst->ipv6, 0, ttl, 0, |
| -- |
| 2.7.4 |
| |