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

mlxsw: spectrum_router: Move multipath hash configuration to a bitmap

Currently, the multipath hash configuration is written directly to the
register payload. While this is OK for the two currently supported
policies, it is going to be hard to follow when more policies and more
packet fields are added.

Instead, set the required headers and fields in a bitmap and then dump
it to the register payload.
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Reviewed-by: default avatarPetr Machata <petrm@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7725c1c8
...@@ -8305,6 +8305,8 @@ enum { ...@@ -8305,6 +8305,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_EN_IPV4 = 7, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4 = 7,
/* Enable TCP/UDP header fields if packet is IPv6 */ /* Enable TCP/UDP header fields if packet is IPv6 */
MLXSW_REG_RECR2_TCP_UDP_EN_IPV6 = 8, MLXSW_REG_RECR2_TCP_UDP_EN_IPV6 = 8,
__MLXSW_REG_RECR2_HEADER_CNT,
}; };
/* reg_recr2_outer_header_enables /* reg_recr2_outer_header_enables
...@@ -8339,6 +8341,8 @@ enum { ...@@ -8339,6 +8341,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_SPORT = 74, MLXSW_REG_RECR2_TCP_UDP_SPORT = 74,
/* TCP/UDP Destination Port */ /* TCP/UDP Destination Port */
MLXSW_REG_RECR2_TCP_UDP_DPORT = 75, MLXSW_REG_RECR2_TCP_UDP_DPORT = 75,
__MLXSW_REG_RECR2_FIELD_CNT,
}; };
/* reg_recr2_outer_header_fields_enable /* reg_recr2_outer_header_fields_enable
...@@ -8347,48 +8351,6 @@ enum { ...@@ -8347,48 +8351,6 @@ enum {
*/ */
MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_fields_enable, 0x14, 0x14, 1); MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_fields_enable, 0x14, 0x14, 1);
static inline void mlxsw_reg_recr2_ipv4_sip_enable(char *payload)
{
int i;
for (i = MLXSW_REG_RECR2_IPV4_SIP0; i <= MLXSW_REG_RECR2_IPV4_SIP3; i++)
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
true);
}
static inline void mlxsw_reg_recr2_ipv4_dip_enable(char *payload)
{
int i;
for (i = MLXSW_REG_RECR2_IPV4_DIP0; i <= MLXSW_REG_RECR2_IPV4_DIP3; i++)
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
true);
}
static inline void mlxsw_reg_recr2_ipv6_sip_enable(char *payload)
{
int i = MLXSW_REG_RECR2_IPV6_SIP0_7;
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
i = MLXSW_REG_RECR2_IPV6_SIP8;
for (; i <= MLXSW_REG_RECR2_IPV6_SIP15; i++)
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
true);
}
static inline void mlxsw_reg_recr2_ipv6_dip_enable(char *payload)
{
int i = MLXSW_REG_RECR2_IPV6_DIP0_7;
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
i = MLXSW_REG_RECR2_IPV6_DIP8;
for (; i <= MLXSW_REG_RECR2_IPV6_DIP15; i++)
mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
true);
}
static inline void mlxsw_reg_recr2_pack(char *payload, u32 seed) static inline void mlxsw_reg_recr2_pack(char *payload, u32 seed)
{ {
MLXSW_REG_ZERO(recr2, payload); MLXSW_REG_ZERO(recr2, payload);
......
...@@ -9599,73 +9599,95 @@ static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) ...@@ -9599,73 +9599,95 @@ static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
} }
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
static void mlxsw_sp_mp_hash_header_set(char *recr2_pl, int header) struct mlxsw_sp_mp_hash_config {
{ DECLARE_BITMAP(headers, __MLXSW_REG_RECR2_HEADER_CNT);
mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, header, true); DECLARE_BITMAP(fields, __MLXSW_REG_RECR2_FIELD_CNT);
} };
static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field) #define MLXSW_SP_MP_HASH_HEADER_SET(_headers, _header) \
{ bitmap_set(_headers, MLXSW_REG_RECR2_##_header, 1)
mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
}
static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) #define MLXSW_SP_MP_HASH_FIELD_SET(_fields, _field) \
bitmap_set(_fields, MLXSW_REG_RECR2_##_field, 1)
#define MLXSW_SP_MP_HASH_FIELD_RANGE_SET(_fields, _field, _nr) \
bitmap_set(_fields, MLXSW_REG_RECR2_##_field, _nr)
static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mp_hash_config *config)
{ {
struct net *net = mlxsw_sp_net(mlxsw_sp); struct net *net = mlxsw_sp_net(mlxsw_sp);
unsigned long *headers = config->headers;
unsigned long *fields = config->fields;
switch (net->ipv4.sysctl_fib_multipath_hash_policy) { switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
case 0: case 0:
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
break; break;
case 1: case 1:
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4); MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV4_PROTOCOL); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT); MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT); MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
break; break;
} }
} }
static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mp_hash_config *config)
{ {
unsigned long *headers = config->headers;
unsigned long *fields = config->fields;
switch (ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp))) { switch (ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp))) {
case 0: case 0:
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_FLOW_LABEL); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
break; break;
case 1: case 1:
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP); MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV6); MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT); MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT); MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
break; break;
} }
} }
static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
{ {
struct mlxsw_sp_mp_hash_config config = {};
char recr2_pl[MLXSW_REG_RECR2_LEN]; char recr2_pl[MLXSW_REG_RECR2_LEN];
unsigned long bit;
u32 seed; u32 seed;
seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0); seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
mlxsw_reg_recr2_pack(recr2_pl, seed); mlxsw_reg_recr2_pack(recr2_pl, seed);
mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl); mlxsw_sp_mp4_hash_init(mlxsw_sp, &config);
mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl); mlxsw_sp_mp6_hash_init(mlxsw_sp, &config);
for_each_set_bit(bit, config.headers, __MLXSW_REG_RECR2_HEADER_CNT)
mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, bit, 1);
for_each_set_bit(bit, config.fields, __MLXSW_REG_RECR2_FIELD_CNT)
mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, bit, 1);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
} }
......
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