Merge branch 'mlxsw-ipv4-host-dpipe-table'

Jiri Pirko says:

====================
mlxsw: Add IPv4 host dpipe table

Arkadi says:

This patchset adds IPv4 host dpipe table support. This will provide the
ability to observe the hardware offloaded IPv4 neighbors.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-08-24 09:33:17 -07:00
commit fb3bbbda5f
9 changed files with 636 additions and 56 deletions

View File

@ -5000,6 +5000,15 @@ enum mlxsw_reg_rauht_trap_id {
*/
MLXSW_ITEM32(reg, rauht, trap_id, 0x60, 0, 9);
enum mlxsw_reg_flow_counter_set_type {
/* No count */
MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT = 0x00,
/* Count packets and bytes */
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
/* Count only packets */
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS = 0x05,
};
/* reg_rauht_counter_set_type
* Counter set type for flow counters
* Access: RW
@ -5045,6 +5054,14 @@ static inline void mlxsw_reg_rauht_pack6(char *payload,
mlxsw_reg_rauht_dip6_memcpy_to(payload, dip);
}
static inline void mlxsw_reg_rauht_pack_counter(char *payload,
u64 counter_index)
{
mlxsw_reg_rauht_counter_index_set(payload, counter_index);
mlxsw_reg_rauht_counter_set_type_set(payload,
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
}
/* RALEU - Router Algorithmic LPM ECMP Update Register
* ---------------------------------------------------
* The register enables updating the ECMP section in the action for multiple
@ -6041,15 +6058,6 @@ static inline void mlxsw_reg_mpsc_pack(char *payload, u8 local_port, bool e,
MLXSW_REG_DEFINE(mgpc, MLXSW_REG_MGPC_ID, MLXSW_REG_MGPC_LEN);
enum mlxsw_reg_mgpc_counter_set_type {
/* No count */
MLXSW_REG_MGPC_COUNTER_SET_TYPE_NO_COUT = 0x00,
/* Count packets and bytes */
MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
/* Count only packets */
MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS = 0x05,
};
/* reg_mgpc_counter_set_type
* Counter set type.
* Access: OP
@ -6089,7 +6097,7 @@ MLXSW_ITEM64(reg, mgpc, packet_counter, 0x10, 0, 64);
static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index,
enum mlxsw_reg_mgpc_opcode opcode,
enum mlxsw_reg_mgpc_counter_set_type set_type)
enum mlxsw_reg_flow_counter_set_type set_type)
{
MLXSW_REG_ZERO(mgpc, payload);
mlxsw_reg_mgpc_counter_index_set(payload, counter_index);

View File

@ -382,12 +382,14 @@ int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
int err;
mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP,
MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES);
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
if (err)
return err;
*packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);
*bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);
if (packets)
*packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);
if (bytes)
*bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);
return 0;
}
@ -397,7 +399,7 @@ static int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp,
char mgpc_pl[MLXSW_REG_MGPC_LEN];
mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR,
MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES);
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
}

View File

@ -74,6 +74,8 @@ static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
&mlxsw_sp_dpipe_header_metadata,
&devlink_dpipe_header_ethernet,
&devlink_dpipe_header_ipv4,
};
static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
@ -114,26 +116,6 @@ static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
return devlink_dpipe_match_put(skb, &match);
}
static void mlxsw_sp_erif_entry_clear(struct devlink_dpipe_entry *entry)
{
unsigned int value_count, value_index;
struct devlink_dpipe_value *value;
value = entry->action_values;
value_count = entry->action_values_count;
for (value_index = 0; value_index < value_count; value_index++) {
kfree(value[value_index].value);
kfree(value[value_index].mask);
}
value = entry->match_values;
value_count = entry->match_values_count;
for (value_index = 0; value_index < value_count; value_index++) {
kfree(value[value_index].value);
kfree(value[value_index].mask);
}
}
static void
mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
struct devlink_dpipe_action *action)
@ -215,8 +197,8 @@ static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
}
static int
mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx)
mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx)
{
struct devlink_dpipe_value match_value, action_value;
struct devlink_dpipe_action action = {0};
@ -270,16 +252,16 @@ mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled,
goto start_again;
rtnl_unlock();
mlxsw_sp_erif_entry_clear(&entry);
devlink_dpipe_entry_clear(&entry);
return 0;
err_entry_append:
err_entry_get:
rtnl_unlock();
mlxsw_sp_erif_entry_clear(&entry);
devlink_dpipe_entry_clear(&entry);
return err;
}
static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable)
static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
{
struct mlxsw_sp *mlxsw_sp = priv;
int i;
@ -301,24 +283,29 @@ static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable)
return 0;
}
static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
{
struct mlxsw_sp *mlxsw_sp = priv;
return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
}
static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
.matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
.actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
.entries_dump = mlxsw_sp_table_erif_entries_dump,
.counters_set_update = mlxsw_sp_table_erif_counters_update,
.entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
.counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
.size_get = mlxsw_sp_dpipe_table_erif_size_get,
};
static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
u64 table_size;
table_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
return devlink_dpipe_table_register(devlink,
MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
&mlxsw_sp_erif_ops,
mlxsw_sp, table_size,
false);
mlxsw_sp, false);
}
static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
@ -328,6 +315,379 @@ static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
}
static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
{
struct devlink_dpipe_match match = {0};
int err;
match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
match.header = &mlxsw_sp_dpipe_header_metadata;
match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
err = devlink_dpipe_match_put(skb, &match);
if (err)
return err;
match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
match.header = &devlink_dpipe_header_ipv4;
match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
return devlink_dpipe_match_put(skb, &match);
}
static int
mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
{
return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
}
static int
mlxsw_sp_dpipe_table_host4_actions_dump(void *priv, struct sk_buff *skb)
{
struct devlink_dpipe_action action = {0};
action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
action.header = &devlink_dpipe_header_ethernet;
action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
return devlink_dpipe_action_put(skb, &action);
}
enum mlxsw_sp_dpipe_table_host_match {
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
};
static void
mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
struct devlink_dpipe_action *action,
int type)
{
struct devlink_dpipe_match *match;
match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
match->header = &mlxsw_sp_dpipe_header_metadata;
match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
match->header = &devlink_dpipe_header_ipv4;
match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
action->header = &devlink_dpipe_header_ethernet;
action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
}
static int
mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
struct devlink_dpipe_value *match_values,
struct devlink_dpipe_match *matches,
struct devlink_dpipe_value *action_value,
struct devlink_dpipe_action *action,
int type)
{
struct devlink_dpipe_value *match_value;
struct devlink_dpipe_match *match;
entry->match_values = match_values;
entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
entry->action_values = action_value;
entry->action_values_count = 1;
match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
match_value->match = match;
match_value->value_size = sizeof(u32);
match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
if (!match_value->value)
return -ENOMEM;
match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
match_value->match = match;
match_value->value_size = sizeof(u32);
match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
if (!match_value->value)
return -ENOMEM;
action_value->action = action;
action_value->value_size = sizeof(u64);
action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
if (!action_value->value)
return -ENOMEM;
return 0;
}
static void
__mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
struct mlxsw_sp_rif *rif,
unsigned char *ha, u32 dip)
{
struct devlink_dpipe_value *value;
u32 *rif_value;
u32 *dip_value;
u8 *ha_value;
/* Set Match RIF index */
value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
rif_value = value->value;
*rif_value = mlxsw_sp_rif_index(rif);
value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
value->mapping_valid = true;
/* Set Match DIP */
value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
dip_value = value->value;
*dip_value = dip;
/* Set Action DMAC */
value = entry->action_values;
ha_value = value->value;
ether_addr_copy(ha_value, ha);
}
static void
mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
struct mlxsw_sp_neigh_entry *neigh_entry,
struct mlxsw_sp_rif *rif)
{
unsigned char *ha;
u32 dip;
ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
__mlxsw_sp_dpipe_table_host4_entry_fill(entry, rif, ha, dip);
}
static void
mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
struct devlink_dpipe_entry *entry,
struct mlxsw_sp_neigh_entry *neigh_entry,
struct mlxsw_sp_rif *rif,
int type)
{
int err;
mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
&entry->counter);
if (!err)
entry->counter_valid = true;
}
static int
mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
struct devlink_dpipe_entry *entry,
bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx,
int type)
{
int rif_neigh_count = 0;
int rif_neigh_skip = 0;
int neigh_count = 0;
int rif_count;
int i, j;
int err;
rtnl_lock();
i = 0;
rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
start_again:
err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
if (err)
goto err_ctx_prepare;
j = 0;
rif_neigh_skip = rif_neigh_count;
for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
struct mlxsw_sp_neigh_entry *neigh_entry;
if (!rif)
continue;
rif_neigh_count = 0;
mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
if (rif_neigh_count < rif_neigh_skip)
goto skip;
mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
neigh_entry, rif,
type);
entry->index = neigh_count;
err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
if (err) {
if (err == -EMSGSIZE) {
if (!j)
goto err_entry_append;
else
goto out;
}
goto err_entry_append;
}
neigh_count++;
j++;
skip:
rif_neigh_count++;
}
rif_neigh_skip = 0;
}
out:
devlink_dpipe_entry_ctx_close(dump_ctx);
if (i != rif_count)
goto start_again;
rtnl_unlock();
return 0;
err_ctx_prepare:
err_entry_append:
rtnl_unlock();
return err;
}
static int
mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx,
int type)
{
struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
struct devlink_dpipe_value action_value;
struct devlink_dpipe_action action = {0};
struct devlink_dpipe_entry entry = {0};
int err;
memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
sizeof(matches[0]));
memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
sizeof(match_values[0]));
memset(&action_value, 0, sizeof(action_value));
mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
matches, &action_value,
&action, type);
if (err)
goto out;
err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
counters_enabled, dump_ctx,
type);
out:
devlink_dpipe_entry_clear(&entry);
return err;
}
static int
mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx)
{
struct mlxsw_sp *mlxsw_sp = priv;
return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
counters_enabled,
dump_ctx, AF_INET);
}
static void
mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
bool enable, int type)
{
int i;
rtnl_lock();
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
struct mlxsw_sp_neigh_entry *neigh_entry;
if (!rif)
continue;
mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
if (mlxsw_sp_neigh_entry_type(neigh_entry) != type)
continue;
mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
neigh_entry,
enable);
}
}
rtnl_unlock();
}
static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
{
struct mlxsw_sp *mlxsw_sp = priv;
mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
return 0;
}
static u64
mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
{
u64 size = 0;
int i;
rtnl_lock();
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
struct mlxsw_sp_neigh_entry *neigh_entry;
if (!rif)
continue;
mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
if (mlxsw_sp_neigh_entry_type(neigh_entry) != type)
continue;
size++;
}
}
rtnl_unlock();
return size;
}
static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
{
struct mlxsw_sp *mlxsw_sp = priv;
return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
}
static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
.matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
.actions_dump = mlxsw_sp_dpipe_table_host4_actions_dump,
.entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
.counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
.size_get = mlxsw_sp_dpipe_table_host4_size_get,
};
static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
return devlink_dpipe_table_register(devlink,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
&mlxsw_sp_host4_ops,
mlxsw_sp, false);
}
static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
devlink_dpipe_table_unregister(devlink,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
}
int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
@ -339,10 +699,16 @@ int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
return err;
err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
if (err)
goto err_erif_register;
goto err_erif_table_init;
err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
if (err)
goto err_host4_table_init;
return 0;
err_erif_register:
err_host4_table_init:
mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
err_erif_table_init:
devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
return err;
}
@ -351,6 +717,7 @@ void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
devlink_dpipe_headers_unregister(devlink);
}

View File

@ -39,5 +39,6 @@ int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp);
#define MLXSW_SP_DPIPE_TABLE_NAME_ERIF "mlxsw_erif"
#define MLXSW_SP_DPIPE_TABLE_NAME_HOST4 "mlxsw_host4"
#endif /* _MLXSW_PIPELINE_H_*/

View File

@ -901,6 +901,8 @@ struct mlxsw_sp_neigh_entry {
* this neigh entry
*/
struct list_head nexthop_neighs_list_node;
unsigned int counter_index;
bool counter_valid;
};
static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
@ -909,6 +911,53 @@ static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
.key_len = sizeof(struct mlxsw_sp_neigh_key),
};
struct mlxsw_sp_neigh_entry *
mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
if (!neigh_entry) {
if (list_empty(&rif->neigh_list))
return NULL;
else
return list_first_entry(&rif->neigh_list,
typeof(*neigh_entry),
rif_list_node);
}
if (neigh_entry->rif_list_node.next == &rif->neigh_list)
return NULL;
return list_next_entry(neigh_entry, rif_list_node);
}
int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry *neigh_entry)
{
return neigh_entry->key.n->tbl->family;
}
unsigned char *
mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry *neigh_entry)
{
return neigh_entry->ha;
}
u32 mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
{
struct neighbour *n;
n = neigh_entry->key.n;
return ntohl(*((__be32 *) n->primary_key));
}
int mlxsw_sp_neigh_counter_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
u64 *p_counter)
{
if (!neigh_entry->counter_valid)
return -EINVAL;
return mlxsw_sp_flow_counter_get(mlxsw_sp, neigh_entry->counter_index,
p_counter, NULL);
}
static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n,
u16 rif)
@ -949,6 +998,41 @@ mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_neigh_ht_params);
}
static bool
mlxsw_sp_neigh4_counter_should_alloc(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink;
devlink = priv_to_devlink(mlxsw_sp->core);
return devlink_dpipe_table_counter_enabled(devlink,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
}
static void
mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
if (mlxsw_sp_neigh_entry_type(neigh_entry) != AF_INET ||
!mlxsw_sp_neigh4_counter_should_alloc(mlxsw_sp))
return;
if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &neigh_entry->counter_index))
return;
neigh_entry->counter_valid = true;
}
static void
mlxsw_sp_neigh_counter_free(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
if (!neigh_entry->counter_valid)
return;
mlxsw_sp_flow_counter_free(mlxsw_sp,
neigh_entry->counter_index);
neigh_entry->counter_valid = false;
}
static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_create(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
{
@ -968,6 +1052,7 @@ mlxsw_sp_neigh_entry_create(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
if (err)
goto err_neigh_entry_insert;
mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
list_add(&neigh_entry->rif_list_node, &rif->neigh_list);
return neigh_entry;
@ -982,6 +1067,7 @@ mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
list_del(&neigh_entry->rif_list_node);
mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
mlxsw_sp_neigh_entry_free(neigh_entry);
}
@ -1287,6 +1373,9 @@ mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_rauht_pack4(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
dip);
if (neigh_entry->counter_valid)
mlxsw_reg_rauht_pack_counter(rauht_pl,
neigh_entry->counter_index);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
}
@ -1301,6 +1390,9 @@ mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_rauht_pack6(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
dip);
if (neigh_entry->counter_valid)
mlxsw_reg_rauht_pack_counter(rauht_pl,
neigh_entry->counter_index);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
}
@ -1337,6 +1429,18 @@ mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
}
}
void
mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
bool adding)
{
if (adding)
mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
else
mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, true);
}
struct mlxsw_sp_neigh_event_work {
struct work_struct work;
struct mlxsw_sp *mlxsw_sp;

View File

@ -42,6 +42,8 @@ enum mlxsw_sp_rif_counter_dir {
MLXSW_SP_RIF_COUNTER_EGRESS,
};
struct mlxsw_sp_neigh_entry;
struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
u16 rif_index);
u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
@ -56,5 +58,23 @@ void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir);
struct mlxsw_sp_neigh_entry *
mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
struct mlxsw_sp_neigh_entry *neigh_entry);
int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry *neigh_entry);
unsigned char *
mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry *neigh_entry);
u32 mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry);
#define mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) \
for (neigh_entry = mlxsw_sp_rif_neigh_next(rif, NULL); neigh_entry; \
neigh_entry = mlxsw_sp_rif_neigh_next(rif, neigh_entry))
int mlxsw_sp_neigh_counter_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
u64 *p_counter);
void
mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
bool adding);
#endif /* _MLXSW_ROUTER_H_*/

View File

@ -178,7 +178,6 @@ struct devlink_dpipe_table_ops;
* struct devlink_dpipe_table - table object
* @priv: private
* @name: table name
* @size: maximum number of entries
* @counters_enabled: indicates if counters are active
* @counter_control_extern: indicates if counter control is in dpipe or
* external tool
@ -189,7 +188,6 @@ struct devlink_dpipe_table {
void *priv;
struct list_head list;
const char *name;
u64 size;
bool counters_enabled;
bool counter_control_extern;
struct devlink_dpipe_table_ops *table_ops;
@ -204,6 +202,7 @@ struct devlink_dpipe_table {
* @counters_set_update - when changing the counter status hardware sync
* maybe needed to allocate/free counter related
* resources
* @size_get - get size
*/
struct devlink_dpipe_table_ops {
int (*actions_dump)(void *priv, struct sk_buff *skb);
@ -211,6 +210,7 @@ struct devlink_dpipe_table_ops {
int (*entries_dump)(void *priv, bool counters_enabled,
struct devlink_dpipe_dump_ctx *dump_ctx);
int (*counters_set_update)(void *priv, bool enable);
u64 (*size_get)(void *priv);
};
/**
@ -311,8 +311,7 @@ void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index);
int devlink_dpipe_table_register(struct devlink *devlink,
const char *table_name,
struct devlink_dpipe_table_ops *table_ops,
void *priv, u64 size,
bool counter_control_extern);
void *priv, bool counter_control_extern);
void devlink_dpipe_table_unregister(struct devlink *devlink,
const char *table_name);
int devlink_dpipe_headers_register(struct devlink *devlink,
@ -324,10 +323,13 @@ int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx);
int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
struct devlink_dpipe_entry *entry);
int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx);
void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry);
int devlink_dpipe_action_put(struct sk_buff *skb,
struct devlink_dpipe_action *action);
int devlink_dpipe_match_put(struct sk_buff *skb,
struct devlink_dpipe_match *match);
extern struct devlink_dpipe_header devlink_dpipe_header_ethernet;
extern struct devlink_dpipe_header devlink_dpipe_header_ipv4;
#else
@ -447,6 +449,11 @@ devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
return 0;
}
static inline void
devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
{
}
static inline int
devlink_dpipe_action_put(struct sk_buff *skb,
struct devlink_dpipe_action *action)

View File

@ -226,4 +226,17 @@ enum devlink_dpipe_action_type {
DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY,
};
enum devlink_dpipe_field_ethernet_id {
DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
};
enum devlink_dpipe_field_ipv4_id {
DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
};
enum devlink_dpipe_header_id {
DEVLINK_DPIPE_HEADER_ETHERNET,
DEVLINK_DPIPE_HEADER_IPV4,
};
#endif /* _UAPI_LINUX_DEVLINK_H_ */

View File

@ -29,6 +29,40 @@
#define CREATE_TRACE_POINTS
#include <trace/events/devlink.h>
static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
{
.name = "destination_mac",
.id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
.bitwidth = 48,
},
};
struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
.name = "ethernet",
.id = DEVLINK_DPIPE_HEADER_ETHERNET,
.fields = devlink_dpipe_fields_ethernet,
.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
.global = true,
};
EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
{
.name = "destination ip",
.id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
.bitwidth = 32,
},
};
struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
.name = "ipv4",
.id = DEVLINK_DPIPE_HEADER_IPV4,
.fields = devlink_dpipe_fields_ipv4,
.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
.global = true,
};
EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
static LIST_HEAD(devlink_list);
@ -1613,13 +1647,15 @@ static int devlink_dpipe_table_put(struct sk_buff *skb,
struct devlink_dpipe_table *table)
{
struct nlattr *table_attr;
u64 table_size;
table_size = table->table_ops->size_get(table->priv);
table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
if (!table_attr)
return -EMSGSIZE;
if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table->size,
nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
DEVLINK_ATTR_PAD))
goto nla_put_failure;
if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
@ -1960,6 +1996,28 @@ int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
}
EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
{
unsigned int value_count, value_index;
struct devlink_dpipe_value *value;
value = entry->action_values;
value_count = entry->action_values_count;
for (value_index = 0; value_index < value_count; value_index++) {
kfree(value[value_index].value);
kfree(value[value_index].mask);
}
value = entry->match_values;
value_count = entry->match_values_count;
for (value_index = 0; value_index < value_count; value_index++) {
kfree(value[value_index].value);
kfree(value[value_index].mask);
}
}
EXPORT_SYMBOL(devlink_dpipe_entry_clear);
static int devlink_dpipe_entries_fill(struct genl_info *info,
enum devlink_command cmd, int flags,
struct devlink_dpipe_table *table)
@ -2684,20 +2742,21 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
* @table_name: table name
* @table_ops: table ops
* @priv: priv
* @size: size
* @counter_control_extern: external control for counters
*/
int devlink_dpipe_table_register(struct devlink *devlink,
const char *table_name,
struct devlink_dpipe_table_ops *table_ops,
void *priv, u64 size,
bool counter_control_extern)
void *priv, bool counter_control_extern)
{
struct devlink_dpipe_table *table;
if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
return -EEXIST;
if (WARN_ON(!table_ops->size_get))
return -EINVAL;
table = kzalloc(sizeof(*table), GFP_KERNEL);
if (!table)
return -ENOMEM;
@ -2705,7 +2764,6 @@ int devlink_dpipe_table_register(struct devlink *devlink,
table->name = table_name;
table->table_ops = table_ops;
table->priv = priv;
table->size = size;
table->counter_control_extern = counter_control_extern;
mutex_lock(&devlink_mutex);