From: Jiri Pirko <redacted>
Ido says:
When the kernel forwards IPv4 packets via multipath routes it doesn't
consider nexthops that are dead or linkdown. For example, if the nexthop
netdev is administratively down or doesn't have a carrier.
Devices capable of offloading such multipath routes need to be made
aware of changes in the reflected nexthops' status. Otherwise, the
device might forward packets via non-functional nexthops, resulting in
packet loss. This patchset aims to fix that.
The first 11 patches deal with the necessary restructuring in the
mlxsw driver, so that it's able to correctly add and remove nexthops
from the device's adjacency table.
The 12th patch adds the NH_{ADD,DEL} events to the FIB notification
chain. These notifications are sent whenever the kernel decides to add
or remove a nexthop from the forwarding plane.
Finally, the last three patches add support for these events in the
mlxsw driver, which is currently the only driver capable of offloading
multipath routes.
Ido Schimmel (15):
mlxsw: spectrum_router: Nullify nexthop's neigh pointer
mlxsw: spectrum_router: Store nexthop groups in a hash table
mlxsw: spectrum_router: Store nexthops in a hash table
mlxsw: spectrum_router: Use nexthop's scope to set action type
mlxsw: spectrum_router: Add gateway indication to nexthop group
mlxsw: spectrum_router: Store routes in a more generic way
mlxsw: spectrum_router: Remove FIB info from FIB entry struct
mlxsw: spectrum_router: Refactor nexthop init routine
mlxsw: spectrum_router: More accurately set offload flag
mlxsw: spectrum_router: Determine offload status using generic
function
mlxsw: spectrum_router: Use trap action only for some route types
ipv4: fib: Notify about nexthop status changes
mlxsw: spectrum_router: Reflect nexthop status changes
mlxsw: spectrum_router: Don't reflect LINKDOWN nexthops
mlxsw: spectrum_router: Flush resources when RIF is deleted
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 +
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 7 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 534 ++++++++++++++++-----
include/net/ip_fib.h | 7 +
net/ipv4/fib_semantics.c | 33 ++
5 files changed, 457 insertions(+), 130 deletions(-)
--
2.7.4
From: Ido Schimmel <redacted>
When we invalidate a nexthop we should also invalidate its neighbour
entry pointer as it might be destroyed later on. This makes the nexthop
de-init function symmetric with its init and also ensures nobody will
try to access the neighbour entry.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
@@ -1398,12 +1398,13 @@ static void mlxsw_sp_nexthop_fini(struct mlxsw_sp *mlxsw_sp,__mlxsw_sp_nexthop_neigh_update(nh,true);list_del(&nh->neigh_list_node);+nh->neigh_entry=NULL;/* If that is the last nexthop connected to that neigh, remove from*nexthop_neighs_list*/-if(list_empty(&nh->neigh_entry->nexthop_list))-list_del(&nh->neigh_entry->nexthop_neighs_list_node);+if(list_empty(&neigh_entry->nexthop_list))+list_del(&neigh_entry->nexthop_neighs_list_node);if(!neigh_entry->connected&&list_empty(&neigh_entry->nexthop_list))mlxsw_sp_neigh_entry_destroy(mlxsw_sp,neigh_entry);
From: Ido Schimmel <redacted>
Currently, when we're notified about a new RTN_UNICAST route we perform
a lookup on the nexthop group list looking for a group with a matching
configuration to that found in the FIB info. This is quite inefficient.
Instead, we can simply rely on the kernel to consolidate several FIB
configurations into the same FIB info and use the FIB info as the key
for our private nexthop group struct.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 104 +++++++++++----------
2 files changed, 54 insertions(+), 52 deletions(-)
@@ -1107,9 +1107,14 @@ struct mlxsw_sp_nexthop {structmlxsw_sp_neigh_entry*neigh_entry;};+structmlxsw_sp_nexthop_group_key{+structfib_info*fi;+};+structmlxsw_sp_nexthop_group{-structlist_headlist;/* node in mlxsw->router.nexthop_group_list */+structrhash_headht_node;structlist_headfib_list;/* list of fib entries that use this group */+structmlxsw_sp_nexthop_group_keykey;u8adj_index_valid:1;u32adj_index;u16ecmp_size;
From: Ido Schimmel <redacted>
Later in the patchset we'll add the NH_{ADD,DEL} events which will let
us know when a nexthop is considered to be dead. Based on these events
we need to be able to add or remove the nexthop from the device's
tables.
Therefore, store the private nexthop structs in a hash table and use the
kernel's fib_nh struct as the key, so that we'll be able to easily find
them when the events are received.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 +
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 58 ++++++++++++++++++++--
2 files changed, 55 insertions(+), 4 deletions(-)
@@ -1090,11 +1090,17 @@ static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)rhashtable_destroy(&mlxsw_sp->router.neigh_ht);}+structmlxsw_sp_nexthop_key{+structfib_nh*fib_nh;+};+structmlxsw_sp_nexthop{structlist_headneigh_list_node;/* member of neigh entry list */structmlxsw_sp_nexthop_group*nh_grp;/* pointer back to the group*thisbelongsto*/+structrhash_headht_node;+structmlxsw_sp_nexthop_keykey;u8should_offload:1,/* set indicates this neigh is connected and*shouldbeputtoKVDlinearareaofthisgroup.*/
@@ -1384,6 +1410,12 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,structnet_device*dev=fib_nh->nh_dev;structneighbour*n;u8nud_state,dead;+interr;++nh->key.fib_nh=fib_nh;+err=mlxsw_sp_nexthop_insert(mlxsw_sp,nh);+if(err)+returnerr;/* Take a reference of neigh here ensuring that neigh would*notbedetructedbeforethenexthopentryisfinished.
@@ -1393,16 +1425,18 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,n=neigh_lookup(&arp_tbl,&fib_nh->nh_gw,dev);if(!n){n=neigh_create(&arp_tbl,&fib_nh->nh_gw,dev);-if(IS_ERR(n))-returnPTR_ERR(n);+if(IS_ERR(n)){+err=PTR_ERR(n);+gotoerr_neigh_create;+}neigh_event_send(n,NULL);}neigh_entry=mlxsw_sp_neigh_entry_lookup(mlxsw_sp,n);if(!neigh_entry){neigh_entry=mlxsw_sp_neigh_entry_create(mlxsw_sp,n);if(IS_ERR(neigh_entry)){-neigh_release(n);-return-EINVAL;+err=-EINVAL;+gotoerr_neigh_entry_create;}}
@@ -1423,6 +1457,12 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,__mlxsw_sp_nexthop_neigh_update(nh,!(nud_state&NUD_VALID&&!dead));return0;++err_neigh_entry_create:+neigh_release(n);+err_neigh_create:+mlxsw_sp_nexthop_remove(mlxsw_sp,nh);+returnerr;}staticvoidmlxsw_sp_nexthop_fini(structmlxsw_sp*mlxsw_sp,
From: Ido Schimmel <redacted>
We currently use the scope of the FIB info to distinguish between a
direct unicast route and a gatewayed one. However, the kernel is
perfectly happy to configure a route with scope UNIVERSE to a directly
connected network.
Instead, we can rely on the first nexthop's scope to check if the route
is gatewayed or not.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Ido Schimmel <redacted>
The next patch is going to generalize the way in which we store routes.
Instead of attaching a nexthop group only to gatewayed routes, one will
be attached to each route, in a similar way to the way the FIB code
stores its routes.
The above means that any function operating on a nexthop group cannot
assume the group represents only gatewayed nexthops. One such function
is the one that refreshes a nexthop group and updates the adjacency
table following nexthop changes.
For a nexthop group that doesn't represent any gateways this function
would essentially be a NOP, but it would be useful if it did update the
action associated with any route using it. This will allow us to later
consolidate code paths when a nexthop changes following NH_{ADD,DEL}
events.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
@@ -1121,7 +1121,8 @@ struct mlxsw_sp_nexthop_group {structrhash_headht_node;structlist_headfib_list;/* list of fib entries that use this group */structmlxsw_sp_nexthop_group_keykey;-u8adj_index_valid:1;+u8adj_index_valid:1,+gateway:1;/* routes using the group use a gateway */u32adj_index;u16ecmp_size;u16count;
From: Ido Schimmel <redacted>
Up until now, the only FIB entries that were associated with a nexthop
group were routes to remote networks where all the nexthop devices had a
valid router interface (RIF). This is in contrast to the FIB code,
where all the routes are associated with a FIB info. The same design
choice needs to be applied to the driver's cache.
Based on the NH_{ADD,DEL} events which will be added later in the
patchset, we need to be able to change the action (forward / trap)
associated with all the routes using the nexthop group. However, if we
can't link between the nexthop and the routes using it, then the above
is impossible.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 40 +++++++++++++++-------
1 file changed, 27 insertions(+), 13 deletions(-)
@@ -127,7 +127,6 @@ struct mlxsw_sp_fib_entry {structmlxsw_sp_fib_keykey;enummlxsw_sp_fib_entry_typetype;unsignedintref_count;-u16rif;/* used for action local */structmlxsw_sp_vr*vr;structfib_info*fi;structlist_headnexthop_group_node;
@@ -1101,6 +1100,7 @@ struct mlxsw_sp_nexthop {*/structrhash_headht_node;structmlxsw_sp_nexthop_keykey;+structmlxsw_sp_rif*r;u8should_offload:1,/* set indicates this neigh is connected and*shouldbeputtoKVDlinearareaofthisgroup.*/
@@ -1414,15 +1415,25 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,{structmlxsw_sp_neigh_entry*neigh_entry;structnet_device*dev=fib_nh->nh_dev;+structmlxsw_sp_rif*r;structneighbour*n;u8nud_state,dead;interr;+nh->nh_grp=nh_grp;nh->key.fib_nh=fib_nh;err=mlxsw_sp_nexthop_insert(mlxsw_sp,nh);if(err)returnerr;+r=mlxsw_sp_rif_find_by_dev(mlxsw_sp,dev);+if(!r)+return0;+nh->r=r;++if(!nh_grp->gateway)+return0;+/* Take a reference of neigh here ensuring that neigh would*notbedetructedbeforethenexthopentryisfinished.*Thereferenceistakeneitherinneigh_lookup()or
@@ -1453,7 +1464,6 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,list_add_tail(&neigh_entry->nexthop_neighs_list_node,&mlxsw_sp->router.nexthop_neighs_list);-nh->nh_grp=nh_grp;nh->neigh_entry=neigh_entry;list_add_tail(&nh->neigh_list_node,&neigh_entry->nexthop_list);read_lock_bh(&n->lock);
From: Ido Schimmel <redacted>
After the previous changes, the FIB info is embedded in every nexthop
group struct, which in turn is embedded in every FIB entry struct.
We can therefore safely remove the FIB info from the entry struct. This
has the added advantage of making the router-related structs more
generic and suitable for use with IPv6 offloads.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
From: Ido Schimmel <redacted>
The nexthop init and de-init functions both have symmetric parts
concerned with the reflection of the neighbour entry into the device's
adjacency table, in case it's used by a gatewayed route.
These sections of code also need to be called when a nexthop is marked
as valid / invalid following NH_{ADD,DEL} events. Break these out into
appropriate functions, so that they could be invoked following the
reception of above events.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 80 +++++++++++++---------
1 file changed, 49 insertions(+), 31 deletions(-)
@@ -1407,30 +1407,16 @@ mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,}}-staticintmlxsw_sp_nexthop_init(structmlxsw_sp*mlxsw_sp,-structmlxsw_sp_nexthop_group*nh_grp,-structmlxsw_sp_nexthop*nh,-structfib_nh*fib_nh)+staticintmlxsw_sp_nexthop_neigh_init(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_nexthop*nh){structmlxsw_sp_neigh_entry*neigh_entry;-structnet_device*dev=fib_nh->nh_dev;-structmlxsw_sp_rif*r;+structfib_nh*fib_nh=nh->key.fib_nh;structneighbour*n;u8nud_state,dead;interr;-nh->nh_grp=nh_grp;-nh->key.fib_nh=fib_nh;-err=mlxsw_sp_nexthop_insert(mlxsw_sp,nh);-if(err)-returnerr;--r=mlxsw_sp_rif_find_by_dev(mlxsw_sp,dev);-if(!r)-return0;-nh->r=r;--if(!nh_grp->gateway)+if(!nh->nh_grp->gateway)return0;/* Take a reference of neigh here ensuring that neigh would
@@ -1438,13 +1424,11 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,*Thereferenceistakeneitherinneigh_lookup()or*inneigh_create()incasenisnotfound.*/-n=neigh_lookup(&arp_tbl,&fib_nh->nh_gw,dev);+n=neigh_lookup(&arp_tbl,&fib_nh->nh_gw,fib_nh->nh_dev);if(!n){-n=neigh_create(&arp_tbl,&fib_nh->nh_gw,dev);-if(IS_ERR(n)){-err=PTR_ERR(n);-gotoerr_neigh_create;-}+n=neigh_create(&arp_tbl,&fib_nh->nh_gw,fib_nh->nh_dev);+if(IS_ERR(n))+returnPTR_ERR(n);neigh_event_send(n,NULL);}neigh_entry=mlxsw_sp_neigh_entry_lookup(mlxsw_sp,n);
@@ -1475,19 +1459,18 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,err_neigh_entry_create:neigh_release(n);-err_neigh_create:-mlxsw_sp_nexthop_remove(mlxsw_sp,nh);returnerr;}-staticvoidmlxsw_sp_nexthop_fini(structmlxsw_sp*mlxsw_sp,-structmlxsw_sp_nexthop*nh)+staticvoidmlxsw_sp_nexthop_neigh_fini(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_nexthop*nh){structmlxsw_sp_neigh_entry*neigh_entry=nh->neigh_entry;-structneighbour*n=neigh_entry->key.n;+structneighbour*n;if(!neigh_entry)-gotoout;+return;+n=neigh_entry->key.n;__mlxsw_sp_nexthop_neigh_update(nh,true);list_del(&nh->neigh_list_node);
From: Ido Schimmel <redacted>
We currently set the RTNH_F_OFFLOAD flag for all routes using remote
action, but this isn't always correct. If none of the nexthops
associated with a gatewayed route can be offloaded into the device, then
any packet hitting it would be trapped to the CPU and forwarded by the
kernel.
Solve this by pushing the setting of the offload flag to after the route
was programmed into the device, thereby allowing us to take all the
parameters into account.
This change will also help us further in the patchset, when we refresh
routes following the reception of NH_{ADD,DEL} events.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 100 ++++++++++++++++-----
1 file changed, 80 insertions(+), 20 deletions(-)
From: Ido Schimmel <redacted>
The previous patch introduced a generic function to determine whether a
route should be offloaded or not. Make use of it here.
In the future we're going to add more conditions to this test (e.g.,
whether TOS is non-zero), so it makes sense to centralize it instead of
open coding it in a few places.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Ido Schimmel <redacted>
The device can have one of three actions associated with a route:
1) Remote - packets continue to the adjacency table
2) Local - packets continue to the neighbour table
3) Trap - packets continue to the CPU
The first two actions can also trap packets to the CPU, but they do so
using a different trap ID, which has a lower traffic class and less
allotted bandwidth.
We currently use the third action for both RTN_{LOCAL,BROADCAST} routes
and RTN_UNICAST routes not pointing to the switch ports.
However, packets that merely need to be forwarded by the switch are
likely not control packets and can be therefore scheduled towards the
CPU using a lower traffic class.
Achieve the above by assigning the third action only to local and
broadcast routes and have any other route use either of the first two
actions, based on whether the route is gatewayed or not.
This will also allow us to refresh routes using the local action and
have them trap packets when their RIF is no longer valid following a
NH_DEL event.
One side effect of this patch is that we no longer give special
treatment to multipath routes using both switch and non-switch ports
towards their nexthops. If at least one of the nexthops can be resolved,
then the device will forward the packets instead of trapping them.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 42 +++++++---------------
1 file changed, 13 insertions(+), 29 deletions(-)
@@ -1807,29 +1814,6 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,}if(fen_info->type!=RTN_UNICAST)return-EINVAL;--for(nhsel=0;nhsel<fi->fib_nhs;nhsel++){-conststructfib_nh*nh=&fi->fib_nh[nhsel];--if(!nh->nh_dev)-continue;-r=mlxsw_sp_rif_find_by_dev(mlxsw_sp,nh->nh_dev);-if(!r){-/* In case router interface is not found for-*atleastoneofthenexthops,thatmeans-*thenexthoppointstosomedeviceunrelated-*tous.Settrapandpassthepacketsfor-*thisprefixtokernel.-*/-break;-}-}--if(!r){-fib_entry->type=MLXSW_SP_FIB_ENTRY_TYPE_TRAP;-return0;-}-if(fi->fib_nh->nh_scope!=RT_SCOPE_LINK)fib_entry->type=MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;else
From: Ido Schimmel <redacted>
When a multipath route is hit the kernel doesn't consider nexthops that
are DEAD or LINKDOWN when IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN is set.
Devices that offload multipath routes need to be made aware of nexthop
status changes. Otherwise, the device will keep forwarding packets to
non-functional nexthops.
Add the FIB_EVENT_NH_{ADD,DEL} events to the fib notification chain,
which notify capable devices when they should add or delete a nexthop
from their tables.
Cc: Roopa Prabhu <redacted>
Cc: David Ahern <redacted>
Cc: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
include/net/ip_fib.h | 7 +++++++
net/ipv4/fib_semantics.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
@@ -214,11 +214,18 @@ struct fib_entry_notifier_info {u32nlflags;};+structfib_nh_notifier_info{+structfib_notifier_infoinfo;/* must be first */+structfib_nh*fib_nh;+};+enumfib_event_type{FIB_EVENT_ENTRY_ADD,FIB_EVENT_ENTRY_DEL,FIB_EVENT_RULE_ADD,FIB_EVENT_RULE_DEL,+FIB_EVENT_NH_ADD,+FIB_EVENT_NH_DEL,};intregister_fib_notifier(structnotifier_block*nb,
From: Ido Schimmel <redacted>
When the last IP address is removed from a netdev, its RIF is deleted.
However, if user didn't first remove neighbours and nexthops using this
interface, then they would still be present in the device's tables.
Therefore, whenever a RIF is deleted, make sure all the neighbours and
nexthops (adjacency entries) using it are removed from the relevant
tables as well.
The action associated with any route using this RIF would be refreshed,
most likely to trap. If the kernel decides to remove the route (f.e.,
because all the nexthops are now DEAD), then an event would be sent,
causing the route to be removed from the device.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 ++
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 +
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 86 +++++++++++++++++++++-
3 files changed, 93 insertions(+), 3 deletions(-)
@@ -1090,12 +1094,34 @@ static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)rhashtable_destroy(&mlxsw_sp->router.neigh_ht);}+staticintmlxsw_sp_neigh_rif_flush(structmlxsw_sp*mlxsw_sp,+conststructmlxsw_sp_rif*r)+{+charrauht_pl[MLXSW_REG_RAUHT_LEN];++mlxsw_reg_rauht_pack(rauht_pl,MLXSW_REG_RAUHT_OP_WRITE_DELETE_ALL,+r->rif,r->addr);+returnmlxsw_reg_write(mlxsw_sp->core,MLXSW_REG(rauht),rauht_pl);+}++staticvoidmlxsw_sp_neigh_rif_gone_sync(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_rif*r)+{+structmlxsw_sp_neigh_entry*neigh_entry,*tmp;++mlxsw_sp_neigh_rif_flush(mlxsw_sp,r);+list_for_each_entry_safe(neigh_entry,tmp,&r->neigh_list,+rif_list_node)+mlxsw_sp_neigh_entry_destroy(mlxsw_sp,neigh_entry);+}+structmlxsw_sp_nexthop_key{structfib_nh*fib_nh;};structmlxsw_sp_nexthop{structlist_headneigh_list_node;/* member of neigh entry list */+structlist_headrif_list_node;structmlxsw_sp_nexthop_group*nh_grp;/* pointer back to the group*thisbelongsto*/
From: Ido Schimmel <redacted>
When a packet hits a multipath route in the device's routing table, a
hash is computed over its headers, which is then used to select the
appropriate nexthop from the device's adjacency table.
There are situations in which the kernel removes a nexthop from a
multipath route (e.g., no carrier) and the device should do the same.
Upon the reception of NH_{ADD,DEL} events, add or remove a nexthop from
the device's adjacency table and refresh all the routes using the
nexthop group. If all the nexthops of a multipath route are invalid,
then any packet hitting the route would be trapped to the CPU for
forwarding.
If all the nexthops are DEAD, then the kernel would remove the route
entirely. On the other hand, if all the nexthops are merely LINKDOWN,
then the kernel would keep the route and forward any incoming packet
using a different route.
While the last case might sound like a problem, it's expected that a
routing daemon running in user space would remove such a route from the
FIB as it's dumped with the DEAD flag set.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 59 +++++++++++++++++++++-
1 file changed, 57 insertions(+), 2 deletions(-)
@@ -1417,7 +1425,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,u8nud_state,dead;interr;-if(!nh->nh_grp->gateway)+if(!nh->nh_grp->gateway||nh->neigh_entry)return0;/* Take a reference of neigh here ensuring that neigh would
@@ -2114,6 +2158,12 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work)caseFIB_EVENT_RULE_DEL:mlxsw_sp_router_fib4_abort(mlxsw_sp);break;+caseFIB_EVENT_NH_ADD:/* fall through */+caseFIB_EVENT_NH_DEL:+mlxsw_sp_nexthop_event(mlxsw_sp,fib_work->event,+fib_work->fnh_info.fib_nh);+fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);+break;}rtnl_unlock();kfree(fib_work);
@@ -2147,6 +2197,11 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,*/fib_info_hold(fib_work->fen_info.fi);break;+caseFIB_EVENT_NH_ADD:/* fall through */+caseFIB_EVENT_NH_DEL:+memcpy(&fib_work->fnh_info,ptr,sizeof(fib_work->fnh_info));+fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent);+break;}mlxsw_core_schedule_work(&fib_work->work);
From: Ido Schimmel <redacted>
The kernel resolves the nexthops for a given route using
FIB_LOOKUP_IGNORE_LINKSTATE which means a notification can be sent for a
route with one of its nexthops being LINKDOWN.
In case IGNORE_ROUTES_WITH_LINKDOWN is set for the nexthop netdev, then
we shouldn't reflect the nexthop to the device's table.
Once the nexthop netdev's carrier goes up we'll be notified using NH_ADD
and reflect it to the device.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 7 +++++++
1 file changed, 7 insertions(+)
From: Andy Gospodarek <andy@greyhouse.net> Date: 2017-02-08 15:25:37
On Wed, Feb 08, 2017 at 11:16:39AM +0100, Jiri Pirko wrote:
From: Ido Schimmel <redacted>
When a multipath route is hit the kernel doesn't consider nexthops that
are DEAD or LINKDOWN when IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN is set.
Devices that offload multipath routes need to be made aware of nexthop
status changes. Otherwise, the device will keep forwarding packets to
non-functional nexthops.
Add the FIB_EVENT_NH_{ADD,DEL} events to the fib notification chain,
which notify capable devices when they should add or delete a nexthop
from their tables.
This looks good -- thanks for doing this.
IIUC the hardware forwarding use case for your hardware covered by David
Ahern's patch[1] to the ipv4 software path selection is already covered,
so this is probably the last known link/neighbor forwarding issue for
ipv4 that needs coverage.
1. a6db449 net: ipv4: Consider failed nexthops in multipath routes
Cc: Roopa Prabhu <redacted>
Cc: David Ahern <redacted>
Cc: Andy Gospodarek <andy@greyhouse.net>
@@ -214,11 +214,18 @@ struct fib_entry_notifier_info {u32nlflags;};+structfib_nh_notifier_info{+structfib_notifier_infoinfo;/* must be first */+structfib_nh*fib_nh;+};+enumfib_event_type{FIB_EVENT_ENTRY_ADD,FIB_EVENT_ENTRY_DEL,FIB_EVENT_RULE_ADD,FIB_EVENT_RULE_DEL,+FIB_EVENT_NH_ADD,+FIB_EVENT_NH_DEL,};intregister_fib_notifier(structnotifier_block*nb,
From: Andy Gospodarek <andy@greyhouse.net> Date: 2017-02-08 15:38:13
On Wed, Feb 8, 2017 at 5:16 AM, Jiri Pirko [off-list ref] wrote:
From: Ido Schimmel <redacted>
When a multipath route is hit the kernel doesn't consider nexthops that
are DEAD or LINKDOWN when IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN is set.
Devices that offload multipath routes need to be made aware of nexthop
status changes. Otherwise, the device will keep forwarding packets to
non-functional nexthops.
Add the FIB_EVENT_NH_{ADD,DEL} events to the fib notification chain,
which notify capable devices when they should add or delete a nexthop
from their tables.
This looks good -- thanks for doing this.
IIUC the hardware forwarding use case for your hardware covered by David
Ahern's patch[1] to the ipv4 software path selection is already covered,
so this is probably the last known link/neighbor forwarding issue for
ipv4 that needs coverage.
1. a6db449 net: ipv4: Consider failed nexthops in multipath routes
Cc: Roopa Prabhu <redacted>
Cc: David Ahern <redacted>
Cc: Andy Gospodarek <andy@greyhouse.net>
@@ -214,11 +214,18 @@ struct fib_entry_notifier_info {u32nlflags;};+structfib_nh_notifier_info{+structfib_notifier_infoinfo;/* must be first */+structfib_nh*fib_nh;+};+enumfib_event_type{FIB_EVENT_ENTRY_ADD,FIB_EVENT_ENTRY_DEL,FIB_EVENT_RULE_ADD,FIB_EVENT_RULE_DEL,+FIB_EVENT_NH_ADD,+FIB_EVENT_NH_DEL,};intregister_fib_notifier(structnotifier_block*nb,
On Wed, Feb 08, 2017 at 09:56:00AM -0500, Andy Gospodarek wrote:
On Wed, Feb 08, 2017 at 11:16:39AM +0100, Jiri Pirko wrote:
quoted
From: Ido Schimmel <redacted>
When a multipath route is hit the kernel doesn't consider nexthops that
are DEAD or LINKDOWN when IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN is set.
Devices that offload multipath routes need to be made aware of nexthop
status changes. Otherwise, the device will keep forwarding packets to
non-functional nexthops.
Add the FIB_EVENT_NH_{ADD,DEL} events to the fib notification chain,
which notify capable devices when they should add or delete a nexthop
from their tables.
This looks good -- thanks for doing this.
IIUC the hardware forwarding use case for your hardware covered by David
Ahern's patch[1] to the ipv4 software path selection is already covered,
so this is probably the last known link/neighbor forwarding issue for
ipv4 that needs coverage.
1. a6db449 net: ipv4: Consider failed nexthops in multipath routes
Yep, it aligns the kernel's datapath with what we already implemented in
mlxsw. In case the neighbour can't be resolve, then the nexthop isn't
reflected to the device (we need the MAC...).
In the case of multipath routes, if some of the nexthops can be
reflected, then we do so, but periodically ask the kernel to try and
resolve the others. Otherwise, these nexthops will never be resolved, as
the kernel doesn't see the packets hitting the multipath route and
therefore lacks the motivation to resolve its nexthops.
quoted
Cc: Roopa Prabhu <redacted>
Cc: David Ahern <redacted>
Cc: Andy Gospodarek <andy@greyhouse.net>
From: David Ahern <hidden> Date: 2017-02-08 18:11:19
On 2/8/17 8:32 AM, Ido Schimmel wrote:
In the case of multipath routes, if some of the nexthops can be
reflected, then we do so, but periodically ask the kernel to try and
resolve the others. Otherwise, these nexthops will never be resolved, as
the kernel doesn't see the packets hitting the multipath route and
therefore lacks the motivation to resolve its nexthops.
It should get the motivation once the neigh entry is cleaned up. That
can take a long time based on gc settings, but it can also happen from
the remote side if it sends an arp message.
On Wed, Feb 08, 2017 at 11:05:54AM -0700, David Ahern wrote:
On 2/8/17 8:32 AM, Ido Schimmel wrote:
quoted
In the case of multipath routes, if some of the nexthops can be
reflected, then we do so, but periodically ask the kernel to try and
resolve the others. Otherwise, these nexthops will never be resolved, as
the kernel doesn't see the packets hitting the multipath route and
therefore lacks the motivation to resolve its nexthops.
It should get the motivation once the neigh entry is cleaned up. That
can take a long time based on gc settings, but it can also happen from
the remote side if it sends an arp message.
And when the remote side does that and the neighbour becomes valid we no
longer try to actively resolve it.
From: David Miller <davem@davemloft.net> Date: 2017-02-08 20:45:16
From: David Miller <davem@davemloft.net>
Date: Wed, 08 Feb 2017 15:28:48 -0500 (EST)
Looks really nice, series applied, thanks!
Jiri, just FYI, I bungled up merging this. And I am trying to fix
that up.
I forgot to include patch #14, but I'll apply that now in the
mainline.
I get a warning, in mlxsw_sp_nexthop_group_create() because the
compiler thinks that 'nh' can be use uninitialized. And I think
the compiler is pointing out something legitimate.
This cleanup loop in err_nexthop_group_insert and err_nexthop_init
needs to take the 'nh' from &nh_grp->nexthops[i] instead of using
whatever is left in 'nh' for all mlxsw_sp_nexthop_fini() calls.
So I'm going to augment the commit of patch #14 to make it go:
@@ -1667,8 +1667,10 @@ mlxsw_sp_nexthop_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi) err_nexthop_group_insert: err_nexthop_init:- for (i--; i >= 0; i--)+ for (i--; i >= 0; i--) {+ nh = &nh_grp->nexthops[i]; mlxsw_sp_nexthop_fini(mlxsw_sp, nh);+ } kfree(nh_grp); return ERR_PTR(err); }
Wed, Feb 08, 2017 at 09:43:45PM CET, davem@davemloft.net wrote:
From: David Miller <davem@davemloft.net>
Date: Wed, 08 Feb 2017 15:28:48 -0500 (EST)
quoted
Looks really nice, series applied, thanks!
Jiri, just FYI, I bungled up merging this. And I am trying to fix
that up.
I forgot to include patch #14, but I'll apply that now in the
mainline.
Yeah, the lost patch #14. I had to resend it to get it to patchwork.
That's probably what confused your tools.
quoted hunk
I get a warning, in mlxsw_sp_nexthop_group_create() because the
compiler thinks that 'nh' can be use uninitialized. And I think
the compiler is pointing out something legitimate.
This cleanup loop in err_nexthop_group_insert and err_nexthop_init
needs to take the 'nh' from &nh_grp->nexthops[i] instead of using
whatever is left in 'nh' for all mlxsw_sp_nexthop_fini() calls.
So I'm going to augment the commit of patch #14 to make it go:
err_nexthop_group_insert:
err_nexthop_init:
- for (i--; i >= 0; i--)
+ for (i--; i >= 0; i--) {
+ nh = &nh_grp->nexthops[i];
mlxsw_sp_nexthop_fini(mlxsw_sp, nh);
+ }
kfree(nh_grp);
return ERR_PTR(err);
}
Oh. I did not catch is. But this is totally unrelated to this patchset.
Please send it as a separate fix. Or I can do it if yo want.
Fixes: a7ff87acd995 ("mlxsw: spectrum_router: Implement next-hop routing")
Acked-by: Jiri Pirko <redacted>
On Wed, Feb 08, 2017 at 03:43:45PM -0500, David Miller wrote:
quoted hunk
From: David Miller <davem@davemloft.net>
Date: Wed, 08 Feb 2017 15:28:48 -0500 (EST)
quoted
Looks really nice, series applied, thanks!
Jiri, just FYI, I bungled up merging this. And I am trying to fix
that up.
I forgot to include patch #14, but I'll apply that now in the
mainline.
I get a warning, in mlxsw_sp_nexthop_group_create() because the
compiler thinks that 'nh' can be use uninitialized. And I think
the compiler is pointing out something legitimate.
This cleanup loop in err_nexthop_group_insert and err_nexthop_init
needs to take the 'nh' from &nh_grp->nexthops[i] instead of using
whatever is left in 'nh' for all mlxsw_sp_nexthop_fini() calls.
So I'm going to augment the commit of patch #14 to make it go:
@@ -1667,8 +1667,10 @@ mlxsw_sp_nexthop_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi) err_nexthop_group_insert: err_nexthop_init:- for (i--; i >= 0; i--)+ for (i--; i >= 0; i--) {+ nh = &nh_grp->nexthops[i]; mlxsw_sp_nexthop_fini(mlxsw_sp, nh);+ }
Looks good to me. Thanks for fixing that up!
This is now consistent with mlxsw_sp_nexthop_group_destroy().
From: Jiri Pirko <redacted>
Ido says:
When the kernel forwards IPv4 packets via multipath routes it doesn't
consider nexthops that are dead or linkdown. For example, if the nexthop
netdev is administratively down or doesn't have a carrier.
Devices capable of offloading such multipath routes need to be made
aware of changes in the reflected nexthops' status. Otherwise, the
device might forward packets via non-functional nexthops, resulting in
packet loss. This patchset aims to fix that.
The first 11 patches deal with the necessary restructuring in the
mlxsw driver, so that it's able to correctly add and remove nexthops
from the device's adjacency table.
The 12th patch adds the NH_{ADD,DEL} events to the FIB notification
chain. These notifications are sent whenever the kernel decides to add
or remove a nexthop from the forwarding plane.
Finally, the last three patches add support for these events in the
mlxsw driver, which is currently the only driver capable of offloading
multipath routes.
Wed, Feb 08, 2017 at 09:43:45PM CET, davem@davemloft.net wrote:
quoted
From: David Miller <davem@davemloft.net>
Date: Wed, 08 Feb 2017 15:28:48 -0500 (EST)
quoted
Looks really nice, series applied, thanks!
Jiri, just FYI, I bungled up merging this. And I am trying to fix
that up.
I forgot to include patch #14, but I'll apply that now in the
mainline.
Yeah, the lost patch #14. I had to resend it to get it to patchwork.
That's probably what confused your tools.
quoted
I get a warning, in mlxsw_sp_nexthop_group_create() because the
compiler thinks that 'nh' can be use uninitialized. And I think
the compiler is pointing out something legitimate.
This cleanup loop in err_nexthop_group_insert and err_nexthop_init
needs to take the 'nh' from &nh_grp->nexthops[i] instead of using
whatever is left in 'nh' for all mlxsw_sp_nexthop_fini() calls.
So I'm going to augment the commit of patch #14 to make it go:
err_nexthop_group_insert:
err_nexthop_init:
- for (i--; i >= 0; i--)
+ for (i--; i >= 0; i--) {
+ nh = &nh_grp->nexthops[i];
mlxsw_sp_nexthop_fini(mlxsw_sp, nh);
+ }
kfree(nh_grp);
return ERR_PTR(err);
}
Oh. I did not catch is. But this is totally unrelated to this patchset.
Please send it as a separate fix. Or I can do it if yo want.
Fixes: a7ff87acd995 ("mlxsw: spectrum_router: Implement next-hop routing")
Acked-by: Jiri Pirko <redacted>
Sorry, I integrated it into the patch #14 commit, and it's already pushed
out.
From: Ido Schimmel <redacted>
The kernel resolves the nexthops for a given route using
FIB_LOOKUP_IGNORE_LINKSTATE which means a notification can be sent for a
route with one of its nexthops being LINKDOWN.
In case IGNORE_ROUTES_WITH_LINKDOWN is set for the nexthop netdev, then
we shouldn't reflect the nexthop to the device's table.
Once the nexthop netdev's carrier goes up we'll be notified using NH_ADD
and reflect it to the device.
Signed-off-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 7 +++++++
1 file changed, 7 insertions(+)