Commit ee5a0448 authored by Ido Schimmel's avatar Ido Schimmel Committed by David S. Miller

mlxsw: spectrum_router: Set hardware flags for routes

Previous patches added support for two hardware flags for IPv4 and IPv6
routes: 'RTM_F_OFFLOAD' and 'RTM_F_TRAP'. Both indicate the presence of
the route in hardware. The first indicates that traffic is actually
offloaded from the kernel, whereas the second indicates that packets
hitting such routes are trapped to the kernel for processing (e.g., host
routes).

Use these two flags in mlxsw. The flags are modified in two places.
Firstly, whenever a route is updated in the device's table. This
includes the addition, deletion or update of a route. For example, when
a host route is promoted to perform NVE decapsulation, its action in the
device is updated, the 'RTM_F_OFFLOAD' flag set and the 'RTM_F_TRAP'
flag cleared.

Secondly, when a route is replaced and overwritten by another route, its
flags are cleared.

v2:
* Convert to new fib_alias_hw_flags_set() interface
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8c5a5b9b
...@@ -4096,131 +4096,128 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp, ...@@ -4096,131 +4096,128 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
} }
static void static void
mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group);
int i; u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
int dst_len = fib_entry->fib_node->key.prefix_len;
if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || struct mlxsw_sp_fib4_entry *fib4_entry;
fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE || struct fib_rt_info fri;
fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP || bool should_offload;
fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) {
nh_grp->nexthops->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
return;
}
for (i = 0; i < nh_grp->count; i++) {
struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
if (nh->offloaded) should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
nh->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD; fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
else common);
nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; fri.fi = fi;
} fri.tb_id = fib4_entry->tb_id;
fri.dst = cpu_to_be32(*p_dst);
fri.dst_len = dst_len;
fri.tos = fib4_entry->tos;
fri.type = fib4_entry->type;
fri.offload = should_offload;
fri.trap = !should_offload;
fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
} }
static void static void
mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group);
int i; u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
int dst_len = fib_entry->fib_node->key.prefix_len;
if (!list_is_singular(&nh_grp->fib_list)) struct mlxsw_sp_fib4_entry *fib4_entry;
return; struct fib_rt_info fri;
for (i = 0; i < nh_grp->count; i++) {
struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
} common);
fri.fi = fi;
fri.tb_id = fib4_entry->tb_id;
fri.dst = cpu_to_be32(*p_dst);
fri.dst_len = dst_len;
fri.tos = fib4_entry->tos;
fri.type = fib4_entry->type;
fri.offload = false;
fri.trap = false;
fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
} }
static void static void
mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_rt6 *mlxsw_sp_rt6; struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
bool should_offload;
should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
/* In IPv6 a multipath route is represented using multiple routes, so
* we need to set the flags on all of them.
*/
fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
common); common);
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, should_offload,
fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE) { !should_offload);
list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
list)->rt->fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
return;
}
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
struct mlxsw_sp_nexthop *nh;
nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
if (nh && nh->offloaded)
fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
else
fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
}
} }
static void static void
mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_rt6 *mlxsw_sp_rt6; struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
common); common);
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
struct fib6_info *rt = mlxsw_sp_rt6->rt; fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, false, false);
rt->fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
}
} }
static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) static void
mlxsw_sp_fib_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
switch (fib_entry->fib_node->fib->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_sp_fib4_entry_offload_set(fib_entry); mlxsw_sp_fib4_entry_hw_flags_set(mlxsw_sp, fib_entry);
break; break;
case MLXSW_SP_L3_PROTO_IPV6: case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_sp_fib6_entry_offload_set(fib_entry); mlxsw_sp_fib6_entry_hw_flags_set(mlxsw_sp, fib_entry);
break; break;
} }
} }
static void static void
mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{ {
switch (fib_entry->fib_node->fib->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_sp_fib4_entry_offload_unset(fib_entry); mlxsw_sp_fib4_entry_hw_flags_clear(mlxsw_sp, fib_entry);
break; break;
case MLXSW_SP_L3_PROTO_IPV6: case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_sp_fib6_entry_offload_unset(fib_entry); mlxsw_sp_fib6_entry_hw_flags_clear(mlxsw_sp, fib_entry);
break; break;
} }
} }
static void static void
mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry, mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_reg_ralue_op op, int err) struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op)
{ {
switch (op) { switch (op) {
case MLXSW_REG_RALUE_OP_WRITE_DELETE:
return mlxsw_sp_fib_entry_offload_unset(fib_entry);
case MLXSW_REG_RALUE_OP_WRITE_WRITE: case MLXSW_REG_RALUE_OP_WRITE_WRITE:
if (err) mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry);
return; break;
if (mlxsw_sp_fib_entry_should_offload(fib_entry)) case MLXSW_REG_RALUE_OP_WRITE_DELETE:
mlxsw_sp_fib_entry_offload_set(fib_entry); mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry);
else break;
mlxsw_sp_fib_entry_offload_unset(fib_entry);
return;
default: default:
return; break;
} }
} }
...@@ -4447,7 +4444,10 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, ...@@ -4447,7 +4444,10 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
{ {
int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op); int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, err); if (err)
return err;
mlxsw_sp_fib_entry_hw_flags_refresh(mlxsw_sp, fib_entry, op);
return err; return err;
} }
...@@ -4883,7 +4883,7 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -4883,7 +4883,7 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
if (!replaced) if (!replaced)
return 0; return 0;
mlxsw_sp_fib_entry_offload_unset(replaced); mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
fib4_replaced = container_of(replaced, struct mlxsw_sp_fib4_entry, fib4_replaced = container_of(replaced, struct mlxsw_sp_fib4_entry,
common); common);
mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_replaced); mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_replaced);
...@@ -5451,7 +5451,7 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -5451,7 +5451,7 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
if (!replaced) if (!replaced)
return 0; return 0;
mlxsw_sp_fib_entry_offload_unset(replaced); mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
fib6_replaced = container_of(replaced, struct mlxsw_sp_fib6_entry, fib6_replaced = container_of(replaced, struct mlxsw_sp_fib6_entry,
common); common);
mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_replaced); mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_replaced);
......
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