net/mlx5e: In case of LAG, one switch parent id is used for all representors
authorRabie Loulou <rabiel@mellanox.com>
Wed, 6 Jun 2018 12:49:27 +0000 (15:49 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Fri, 14 Dec 2018 21:28:52 +0000 (13:28 -0800)
When the uplink representors are put into lag, set all the
representors (VFs and uplinks) of the same NIC to return the same
switchdev id.

Currently, the route lookup code on the encapsulation offload path
assumes that same switchdev id for the source and dest devices means
that the dest is also mlx5 HW netdev. This doesn't hold anymore when we
align the switchdev Id of the uplinks to be same, which in turn causes
the bond/team to return that id to the caller. As such, enhance the
relevant check to take into account the uplink lag case.

Signed-off-by: Rabie Loulou <rabiel@mellanox.com>
Signed-off-by: Aviv Heller <avivh@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c

index c1515f0135018558913e0f563f9f5d5bbec18eb4..d5d161ab0dbc4974c723aa8ca2277b15f8c84818 100644 (file)
@@ -14,7 +14,8 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
                                   u8 *out_ttl)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5e_rep_priv *uplink_rpriv;
+       struct net_device *uplink_dev, *uplink_upper;
+       bool dst_is_lag_dev;
        struct rtable *rt;
        struct neighbour *n = NULL;
 
@@ -28,10 +29,20 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
 #else
        return -EOPNOTSUPP;
 #endif
-       uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
-       /* if the egress device isn't on the same HW e-switch, we use the uplink */
-       if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
-               *out_dev = uplink_rpriv->netdev;
+
+       uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
+       uplink_upper = netdev_master_upper_dev_get(uplink_dev);
+       dst_is_lag_dev = (uplink_upper &&
+                         netif_is_lag_master(uplink_upper) &&
+                         rt->dst.dev == uplink_upper &&
+                         mlx5_lag_is_active(priv->mdev));
+
+       /* if the egress device isn't on the same HW e-switch or
+        * it's a LAG device, use the uplink
+        */
+       if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev) ||
+           dst_is_lag_dev)
+               *out_dev = uplink_dev;
        else
                *out_dev = rt->dst.dev;
 
@@ -65,8 +76,9 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
        struct dst_entry *dst;
 
 #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
-       struct mlx5e_rep_priv *uplink_rpriv;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct net_device *uplink_dev, *uplink_upper;
+       bool dst_is_lag_dev;
        int ret;
 
        ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
@@ -77,10 +89,19 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
        if (!(*out_ttl))
                *out_ttl = ip6_dst_hoplimit(dst);
 
-       uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
-       /* if the egress device isn't on the same HW e-switch, we use the uplink */
-       if (!switchdev_port_same_parent_id(priv->netdev, dst->dev))
-               *out_dev = uplink_rpriv->netdev;
+       uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
+       uplink_upper = netdev_master_upper_dev_get(uplink_dev);
+       dst_is_lag_dev = (uplink_upper &&
+                         netif_is_lag_master(uplink_upper) &&
+                         dst->dev == uplink_upper &&
+                         mlx5_lag_is_active(priv->mdev));
+
+       /* if the egress device isn't on the same HW e-switch or
+        * it's a LAG device, use the uplink
+        */
+       if (!switchdev_port_same_parent_id(priv->netdev, dst->dev) ||
+           dst_is_lag_dev)
+               *out_dev = uplink_dev;
        else
                *out_dev = dst->dev;
 #else
index e5230049612f727198291902f58fe3ed40b5fd31..17f24127a3ba20ff4a3395125aef164812663501 100644 (file)
@@ -297,17 +297,31 @@ static const struct ethtool_ops mlx5e_rep_ethtool_ops = {
 int mlx5e_attr_get(struct net_device *dev, struct switchdev_attr *attr)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
-       struct mlx5e_rep_priv *rpriv = priv->ppriv;
-       struct mlx5_eswitch_rep *rep = rpriv->rep;
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct net_device *uplink_upper = NULL;
+       struct mlx5e_priv *uplink_priv = NULL;
+       struct net_device *uplink_dev;
 
        if (esw->mode == SRIOV_NONE)
                return -EOPNOTSUPP;
 
+       uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
+       if (uplink_dev) {
+               uplink_upper = netdev_master_upper_dev_get(uplink_dev);
+               uplink_priv = netdev_priv(uplink_dev);
+       }
+
        switch (attr->id) {
        case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
                attr->u.ppid.id_len = ETH_ALEN;
-               ether_addr_copy(attr->u.ppid.id, rep->hw_id);
+               if (uplink_upper && mlx5_lag_is_active(uplink_priv->mdev)) {
+                       ether_addr_copy(attr->u.ppid.id, uplink_upper->dev_addr);
+               } else {
+                       struct mlx5e_rep_priv *rpriv = priv->ppriv;
+                       struct mlx5_eswitch_rep *rep = rpriv->rep;
+
+                       ether_addr_copy(attr->u.ppid.id, rep->hw_id);
+               }
                break;
        default:
                return -EOPNOTSUPP;