mlxsw: spectrum_router: Periodically dump active IPv6 neighbours
authorArkadi Sharshevsky <arkadis@mellanox.com>
Tue, 18 Jul 2017 08:10:17 +0000 (10:10 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 18 Jul 2017 18:57:33 +0000 (11:57 -0700)
In addition to IPv4, periodically dump IPv6 neighbours and update the
kernel about them.

Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

index a0de7365d57e5dc7b2bdbb1048090a7e25ba0eb9..312fb67277d74e5e65a3f5c2f54f7f32357b5a05 100644 (file)
@@ -968,6 +968,36 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
        neigh_release(n);
 }
 
+static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
+                                                  char *rauhtd_pl,
+                                                  int rec_index)
+{
+       struct net_device *dev;
+       struct neighbour *n;
+       struct in6_addr dip;
+       u16 rif;
+
+       mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl, rec_index, &rif,
+                                        (char *) &dip);
+
+       if (!mlxsw_sp->router->rifs[rif]) {
+               dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
+               return;
+       }
+
+       dev = mlxsw_sp->router->rifs[rif]->dev;
+       n = neigh_lookup(&nd_tbl, &dip, dev);
+       if (!n) {
+               netdev_err(dev, "Failed to find matching neighbour for IP=%pI6c\n",
+                          &dip);
+               return;
+       }
+
+       netdev_dbg(dev, "Updating neighbour with IP=%pI6c\n", &dip);
+       neigh_event_send(n, NULL);
+       neigh_release(n);
+}
+
 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
                                                   char *rauhtd_pl,
                                                   int rec_index)
@@ -991,6 +1021,15 @@ static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
 
 }
 
+static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp *mlxsw_sp,
+                                                  char *rauhtd_pl,
+                                                  int rec_index)
+{
+       /* One record contains one entry. */
+       mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp, rauhtd_pl,
+                                              rec_index);
+}
+
 static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
                                              char *rauhtd_pl, int rec_index)
 {
@@ -1000,7 +1039,8 @@ static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
                                                       rec_index);
                break;
        case MLXSW_REG_RAUHTD_TYPE_IPV6:
-               WARN_ON_ONCE(1);
+               mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp, rauhtd_pl,
+                                                      rec_index);
                break;
        }
 }
@@ -1025,22 +1065,20 @@ static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
        return false;
 }
 
-static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
+static int
+__mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp,
+                                      char *rauhtd_pl,
+                                      enum mlxsw_reg_rauhtd_type type)
 {
-       char *rauhtd_pl;
-       u8 num_rec;
-       int i, err;
-
-       rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
-       if (!rauhtd_pl)
-               return -ENOMEM;
+       int i, num_rec;
+       int err;
 
        /* Make sure the neighbour's netdev isn't removed in the
         * process.
         */
        rtnl_lock();
        do {
-               mlxsw_reg_rauhtd_pack(rauhtd_pl, MLXSW_REG_RAUHTD_TYPE_IPV4);
+               mlxsw_reg_rauhtd_pack(rauhtd_pl, type);
                err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
                                      rauhtd_pl);
                if (err) {
@@ -1054,6 +1092,27 @@ static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
        } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
        rtnl_unlock();
 
+       return err;
+}
+
+static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
+{
+       enum mlxsw_reg_rauhtd_type type;
+       char *rauhtd_pl;
+       int err;
+
+       rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
+       if (!rauhtd_pl)
+               return -ENOMEM;
+
+       type = MLXSW_REG_RAUHTD_TYPE_IPV4;
+       err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
+       if (err)
+               goto out;
+
+       type = MLXSW_REG_RAUHTD_TYPE_IPV6;
+       err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
+out:
        kfree(rauhtd_pl);
        return err;
 }