OSDN Git Service

mlxsw: spectrum_router: Replay neighbours when RIF is made
authorPetr Machata <petrm@nvidia.com>
Wed, 19 Jul 2023 11:01:29 +0000 (13:01 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Jul 2023 07:54:05 +0000 (08:54 +0100)
As neighbours are created, mlxsw is involved through the netevent
notifications. When at the time there is no RIF for a given neighbour, the
notification is not acted upon. When the RIF is later created, these
outstanding neighbours are left unoffloaded and cause traffic to go through
the SW datapath.

In order to fix this issue, as a RIF is created, walk the ARP and ND tables
and find neighbours for the netdevice that represents the RIF. Then
schedule neighbour work for them, allowing them to be offloaded.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

index 2322429..9263a91 100644 (file)
@@ -2983,6 +2983,52 @@ static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
        }
 }
 
+struct mlxsw_sp_neigh_rif_made_sync {
+       struct mlxsw_sp *mlxsw_sp;
+       struct mlxsw_sp_rif *rif;
+       int err;
+};
+
+static void mlxsw_sp_neigh_rif_made_sync_each(struct neighbour *n, void *data)
+{
+       struct mlxsw_sp_neigh_rif_made_sync *rms = data;
+       int rc;
+
+       if (rms->err)
+               return;
+       if (n->dev != mlxsw_sp_rif_dev(rms->rif))
+               return;
+       rc = mlxsw_sp_router_schedule_neigh_work(rms->mlxsw_sp->router, n);
+       if (rc != NOTIFY_DONE)
+               rms->err = -ENOMEM;
+}
+
+static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
+                                       struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp_neigh_rif_made_sync rms = {
+               .mlxsw_sp = mlxsw_sp,
+               .rif = rif,
+       };
+
+       neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
+       if (rms.err)
+               goto err_arp;
+
+#if IS_ENABLED(CONFIG_IPV6)
+       neigh_for_each(&nd_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
+#endif
+       if (rms.err)
+               goto err_nd;
+
+       return 0;
+
+err_nd:
+err_arp:
+       mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
+       return rms.err;
+}
+
 enum mlxsw_sp_nexthop_type {
        MLXSW_SP_NEXTHOP_TYPE_ETH,
        MLXSW_SP_NEXTHOP_TYPE_IPIP,
@@ -7937,7 +7983,21 @@ static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
 static int mlxsw_sp_router_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
                                         struct mlxsw_sp_rif *rif)
 {
-       return mlxsw_sp_nexthop_rif_made_sync(mlxsw_sp, rif);
+       int err;
+
+       err = mlxsw_sp_neigh_rif_made_sync(mlxsw_sp, rif);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_nexthop_rif_made_sync(mlxsw_sp, rif);
+       if (err)
+               goto err_nexthop;
+
+       return 0;
+
+err_nexthop:
+       mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
+       return err;
 }
 
 static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,