Commit d5eb89cf authored by Arkadi Sharshevsky's avatar Arkadi Sharshevsky Committed by David S. Miller

mlxsw: spectrum_router: Reflect IPv6 neighbours to the device

As with IPv4, listen to NEIGH_UPDATE events from the ndisc table and
program relevant neighbours to the device's neighbour table.

Note that neighbours with a link-local IP address aren't programmed, as
packets with a link-local destination IP are trapped after LPM lookup
and never reach the neighbour table.
Signed-off-by: default avatarArkadi Sharshevsky <arkadis@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6929e507
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#include <net/fib_rules.h> #include <net/fib_rules.h>
#include <net/l3mdev.h> #include <net/l3mdev.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/ndisc.h>
#include <net/ipv6.h>
#include "spectrum.h" #include "spectrum.h"
#include "core.h" #include "core.h"
...@@ -1147,6 +1149,32 @@ mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp, ...@@ -1147,6 +1149,32 @@ mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
} }
static void
mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
enum mlxsw_reg_rauht_op op)
{
struct neighbour *n = neigh_entry->key.n;
char rauht_pl[MLXSW_REG_RAUHT_LEN];
const char *dip = n->primary_key;
mlxsw_reg_rauht_pack6(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
dip);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
}
static bool mlxsw_sp_neigh_ipv6_ignore(struct neighbour *n)
{
/* Packets with a link-local destination address are trapped
* after LPM lookup and never reach the neighbour table, so
* there is no need to program such neighbours to the device.
*/
if (ipv6_addr_type((struct in6_addr *) &n->primary_key) &
IPV6_ADDR_LINKLOCAL)
return true;
return false;
}
static void static void
mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry, struct mlxsw_sp_neigh_entry *neigh_entry,
...@@ -1155,11 +1183,17 @@ mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp, ...@@ -1155,11 +1183,17 @@ mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
if (!adding && !neigh_entry->connected) if (!adding && !neigh_entry->connected)
return; return;
neigh_entry->connected = adding; neigh_entry->connected = adding;
if (neigh_entry->key.n->tbl == &arp_tbl) if (neigh_entry->key.n->tbl == &arp_tbl) {
mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry, mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
mlxsw_sp_rauht_op(adding)); mlxsw_sp_rauht_op(adding));
else } else if (neigh_entry->key.n->tbl == &nd_tbl) {
if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry->key.n))
return;
mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
mlxsw_sp_rauht_op(adding));
} else {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
}
} }
struct mlxsw_sp_neigh_event_work { struct mlxsw_sp_neigh_event_work {
...@@ -1247,7 +1281,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, ...@@ -1247,7 +1281,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
case NETEVENT_NEIGH_UPDATE: case NETEVENT_NEIGH_UPDATE:
n = ptr; n = ptr;
if (n->tbl != &arp_tbl) if (n->tbl != &arp_tbl && n->tbl != &nd_tbl)
return NOTIFY_DONE; return NOTIFY_DONE;
mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev); mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment