diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 122 |
1 files changed, 65 insertions, 57 deletions
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 f8ee18b4da6f..6ed87534d314 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -77,8 +77,8 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, struct neighbour **out_n, u8 *out_ttl) { + struct neighbour *n; struct rtable *rt; - struct neighbour *n = NULL; #if IS_ENABLED(CONFIG_INET) struct mlx5_core_dev *mdev = priv->mdev; @@ -97,15 +97,19 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, if (ret) return ret; - if (mlx5_lag_is_multipath(mdev) && rt->rt_gw_family != AF_INET) + if (mlx5_lag_is_multipath(mdev) && rt->rt_gw_family != AF_INET) { + ip_rt_put(rt); return -ENETUNREACH; + } #else return -EOPNOTSUPP; #endif ret = get_route_and_out_devs(priv, rt->dst.dev, route_dev, out_dev); - if (ret < 0) + if (ret < 0) { + ip_rt_put(rt); return ret; + } if (!(*out_ttl)) *out_ttl = ip4_dst_hoplimit(&rt->dst); @@ -126,44 +130,6 @@ static const char *mlx5e_netdev_kind(struct net_device *dev) return "unknown"; } -static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, - struct net_device *mirred_dev, - struct net_device **out_dev, - struct net_device **route_dev, - struct flowi6 *fl6, - struct neighbour **out_n, - u8 *out_ttl) -{ - struct neighbour *n = NULL; - struct dst_entry *dst; - -#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; - - if (!(*out_ttl)) - *out_ttl = ip6_dst_hoplimit(dst); - - ret = get_route_and_out_devs(priv, dst->dev, route_dev, out_dev); - if (ret < 0) - return ret; -#else - return -EOPNOTSUPP; -#endif - - n = dst_neigh_lookup(dst, &fl6->daddr); - dst_release(dst); - if (!n) - return -ENOMEM; - - *out_n = n; - return 0; -} - static int mlx5e_gen_ip_tunnel_header(char buf[], __u8 *ip_proto, struct mlx5e_encap_entry *e) { @@ -206,8 +172,8 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi4 fl4 = {}; + struct neighbour *n; int ipv4_encap_size; char *encap_header; u8 nud_state, ttl; @@ -233,12 +199,15 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, if (max_encap_size < ipv4_encap_size) { mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv4_encap_size, max_encap_size); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto release_neigh; } encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); - if (!encap_header) - return -ENOMEM; + if (!encap_header) { + err = -ENOMEM; + goto release_neigh; + } /* used by mlx5e_detach_encap to lookup a neigh hash table * entry in the neigh hash table when a user deletes a rule @@ -289,7 +258,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, e->reformat_type, @@ -309,12 +278,48 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } +#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) +static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, + struct net_device *mirred_dev, + struct net_device **out_dev, + struct net_device **route_dev, + struct flowi6 *fl6, + struct neighbour **out_n, + u8 *out_ttl) +{ + struct dst_entry *dst; + struct neighbour *n; + + int ret; + + ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst, + fl6); + if (ret < 0) + return ret; + + if (!(*out_ttl)) + *out_ttl = ip6_dst_hoplimit(dst); + + ret = get_route_and_out_devs(priv, dst->dev, route_dev, out_dev); + if (ret < 0) { + dst_release(dst); + return ret; + } + + n = dst_neigh_lookup(dst, &fl6->daddr); + dst_release(dst); + if (!n) + return -ENOMEM; + + *out_n = n; + return 0; +} + int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, struct net_device *mirred_dev, struct mlx5e_encap_entry *e) @@ -322,9 +327,9 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi6 fl6 = {}; struct ipv6hdr *ip6h; + struct neighbour *n; int ipv6_encap_size; char *encap_header; u8 nud_state, ttl; @@ -349,12 +354,15 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, if (max_encap_size < ipv6_encap_size) { mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv6_encap_size, max_encap_size); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto release_neigh; } encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); - if (!encap_header) - return -ENOMEM; + if (!encap_header) { + err = -ENOMEM; + goto release_neigh; + } /* used by mlx5e_detach_encap to lookup a neigh hash table * entry in the neigh hash table when a user deletes a rule @@ -404,7 +412,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, @@ -425,11 +433,11 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } +#endif bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv, struct net_device *netdev) |