Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6fc5b49 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-Add-router-adjacency-dpipe-table'



Jiri Pirko says:

====================
mlxsw: Add router adjacency dpipe table

Arkadi says:

This patchset adds router adjacency dpipe table support. This will provide
the ability to observe the hardware offloaded IPv4/6 nexthops.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 390e96ec 427e652a
Loading
Loading
Loading
Loading
+35 −9
Original line number Diff line number Diff line
@@ -4549,6 +4549,27 @@ MLXSW_ITEM32(reg, ratr, ipip_ipv4_udip, 0x18, 0, 32);
 */
MLXSW_ITEM32(reg, ratr, ipip_ipv6_ptr, 0x1C, 0, 24);

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_ratr_counter_set_type
 * Counter set type for flow counters
 * Access: RW
 */
MLXSW_ITEM32(reg, ratr, counter_set_type, 0x28, 24, 8);

/* reg_ratr_counter_index
 * Counter index for flow counters
 * Access: RW
 */
MLXSW_ITEM32(reg, ratr, counter_index, 0x28, 0, 24);

static inline void
mlxsw_reg_ratr_pack(char *payload,
		    enum mlxsw_reg_ratr_op op, bool valid,
@@ -4576,6 +4597,20 @@ static inline void mlxsw_reg_ratr_ipip4_entry_pack(char *payload, u32 ipv4_udip)
	mlxsw_reg_ratr_ipip_ipv4_udip_set(payload, ipv4_udip);
}

static inline void mlxsw_reg_ratr_counter_pack(char *payload, u64 counter_index,
					       bool counter_enable)
{
	enum mlxsw_reg_flow_counter_set_type set_type;

	if (counter_enable)
		set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES;
	else
		set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT;

	mlxsw_reg_ratr_counter_index_set(payload, counter_index);
	mlxsw_reg_ratr_counter_set_type_set(payload, set_type);
}

/* RICNT - Router Interface Counter Register
 * -----------------------------------------
 * The RICNT register retrieves per port performance counters
@@ -5297,15 +5332,6 @@ 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
+386 −11
Original line number Diff line number Diff line
@@ -43,22 +43,37 @@ enum mlxsw_sp_field_metadata_id {
	MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
	MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
	MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
};

static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
	{ .name = "erif_port",
	{
		.name = "erif_port",
		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
		.bitwidth = 32,
		.mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
	},
	{ .name = "l3_forward",
	{
		.name = "l3_forward",
		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
		.bitwidth = 1,
	},
	{ .name = "l3_drop",
	{
		.name = "l3_drop",
		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
		.bitwidth = 1,
	},
	{
		.name = "adj_index",
		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
		.bitwidth = 32,
	},
	{
		.name = "adj_hash_index",
		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
		.bitwidth = 32,
	},
};

enum mlxsw_sp_dpipe_header_id {
@@ -826,6 +841,359 @@ static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
				       MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
}

static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
						 struct sk_buff *skb)
{
	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_ADJ_INDEX;

	err = devlink_dpipe_match_put(skb, &match);
	if (err)
		return err;

	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
	match.header = &mlxsw_sp_dpipe_header_metadata;
	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;

	return devlink_dpipe_match_put(skb, &match);
}

static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
						 struct sk_buff *skb)
{
	struct devlink_dpipe_action action = {0};
	int err;

	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
	action.header = &devlink_dpipe_header_ethernet;
	action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;

	err = devlink_dpipe_action_put(skb, &action);
	if (err)
		return err;

	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
	action.header = &mlxsw_sp_dpipe_header_metadata;
	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;

	return devlink_dpipe_action_put(skb, &action);
}

static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
{
	struct mlxsw_sp_nexthop *nh;
	u64 size = 0;

	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
		if (mlxsw_sp_nexthop_offload(nh) &&
		    !mlxsw_sp_nexthop_group_has_ipip(nh))
			size++;
	return size;
}

enum mlxsw_sp_dpipe_table_adj_match {
	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
};

enum mlxsw_sp_dpipe_table_adj_action {
	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
};

static void
mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
					      struct devlink_dpipe_action *actions)
{
	struct devlink_dpipe_action *action;
	struct devlink_dpipe_match *match;

	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
	match->header = &mlxsw_sp_dpipe_header_metadata;
	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;

	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
	match->header = &mlxsw_sp_dpipe_header_metadata;
	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;

	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
	action->header = &devlink_dpipe_header_ethernet;
	action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;

	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
	action->header = &mlxsw_sp_dpipe_header_metadata;
	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
}

static int
mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
				       struct devlink_dpipe_value *match_values,
				       struct devlink_dpipe_match *matches,
				       struct devlink_dpipe_value *action_values,
				       struct devlink_dpipe_action *actions)
{	struct devlink_dpipe_value *action_value;
	struct devlink_dpipe_value *match_value;
	struct devlink_dpipe_action *action;
	struct devlink_dpipe_match *match;

	entry->match_values = match_values;
	entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;

	entry->action_values = action_values;
	entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;

	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];

	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_ADJ_MATCH_HASH_INDEX];
	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];

	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 = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];

	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;

	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];

	action_value->action = action;
	action_value->value_size = sizeof(u32);
	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
	if (!action_value->value)
		return -ENOMEM;

	return 0;
}

static void
__mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
				      u32 adj_index, u32 adj_hash_index,
				      unsigned char *ha,
				      struct mlxsw_sp_rif *rif)
{
	struct devlink_dpipe_value *value;
	u32 *p_rif_value;
	u32 *p_index;

	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
	p_index = value->value;
	*p_index = adj_index;

	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
	p_index = value->value;
	*p_index = adj_hash_index;

	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
	ether_addr_copy(value->value, ha);

	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
	p_rif_value = value->value;
	*p_rif_value = mlxsw_sp_rif_index(rif);
	value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
	value->mapping_valid = true;
}

static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
						struct mlxsw_sp_nexthop *nh,
						struct devlink_dpipe_entry *entry)
{
	struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
	unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
	u32 adj_hash_index = 0;
	u32 adj_index = 0;
	int err;

	mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
	__mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index,
					      adj_hash_index, ha, rif);
	err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
	if (!err)
		entry->counter_valid = true;
}

static int
mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
				     struct devlink_dpipe_entry *entry,
				     bool counters_enabled,
				     struct devlink_dpipe_dump_ctx *dump_ctx)
{
	struct mlxsw_sp_nexthop *nh;
	int entry_index = 0;
	int nh_count_max;
	int nh_count = 0;
	int nh_skip;
	int j;
	int err;

	rtnl_lock();
	nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
start_again:
	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
	if (err)
		goto err_ctx_prepare;
	j = 0;
	nh_skip = nh_count;
	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
		if (!mlxsw_sp_nexthop_offload(nh) ||
		    mlxsw_sp_nexthop_group_has_ipip(nh))
			continue;

		if (nh_count < nh_skip)
			goto skip;

		mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
		entry->index = entry_index;
		err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
		if (err) {
			if (err == -EMSGSIZE) {
				if (!j)
					goto err_entry_append;
				break;
			}
			goto err_entry_append;
		}
		entry_index++;
		j++;
skip:
		nh_count++;
	}

	devlink_dpipe_entry_ctx_close(dump_ctx);
	if (nh_count != nh_count_max)
		goto start_again;
	rtnl_unlock();

	return 0;

err_ctx_prepare:
err_entry_append:
	rtnl_unlock();
	return err;
}

static int
mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
				      struct devlink_dpipe_dump_ctx *dump_ctx)
{
	struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
	struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
	struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
	struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
	struct devlink_dpipe_entry entry = {0};
	struct mlxsw_sp *mlxsw_sp = priv;
	int err;

	memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
			   sizeof(matches[0]));
	memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
				sizeof(match_values[0]));
	memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
			   sizeof(actions[0]));
	memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
				 sizeof(action_values[0]));

	mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
	err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
						     match_values, matches,
						     action_values, actions);
	if (err)
		goto out;

	err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
						   counters_enabled, dump_ctx);
out:
	devlink_dpipe_entry_clear(&entry);
	return err;
}

static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
{
	struct mlxsw_sp *mlxsw_sp = priv;
	struct mlxsw_sp_nexthop *nh;
	u32 adj_hash_index = 0;
	u32 adj_index = 0;

	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
		if (!mlxsw_sp_nexthop_offload(nh) ||
		    mlxsw_sp_nexthop_group_has_ipip(nh))
			continue;

		mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
		if (enable)
			mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
		else
			mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
		mlxsw_sp_nexthop_update(mlxsw_sp,
					adj_index + adj_hash_index, nh);
	}
	return 0;
}

static u64
mlxsw_sp_dpipe_table_adj_size_get(void *priv)
{
	struct mlxsw_sp *mlxsw_sp = priv;
	u64 size;

	rtnl_lock();
	size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
	rtnl_unlock();

	return size;
}

static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
	.matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
	.actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
	.entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
	.counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
	.size_get = mlxsw_sp_dpipe_table_adj_size_get,
};

static int mlxsw_sp_dpipe_adj_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_ADJ,
					    &mlxsw_sp_dpipe_table_adj_ops,
					    mlxsw_sp, false);
}

static void mlxsw_sp_dpipe_adj_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_ADJ);
}

int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
{
	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
@@ -846,8 +1214,14 @@ int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
	err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
	if (err)
		goto err_host6_table_init;
	return 0;

	err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
	if (err)
		goto err_adj_table_init;

	return 0;
err_adj_table_init:
	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
err_host6_table_init:
	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
err_host4_table_init:
@@ -861,6 +1235,7 @@ void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
{
	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);

	mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
+1 −0
Original line number Diff line number Diff line
@@ -56,5 +56,6 @@ static inline 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"
#define MLXSW_SP_DPIPE_TABLE_NAME_HOST6 "mlxsw_host6"
#define MLXSW_SP_DPIPE_TABLE_NAME_ADJ "mlxsw_adj"

#endif /* _MLXSW_PIPELINE_H_*/
+130 −4
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ struct mlxsw_sp_router {
	struct rhashtable neigh_ht;
	struct rhashtable nexthop_group_ht;
	struct rhashtable nexthop_ht;
	struct list_head nexthop_list;
	struct {
		struct mlxsw_sp_lpm_tree *trees;
		unsigned int tree_count;
@@ -1316,7 +1317,7 @@ mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
						typeof(*neigh_entry),
						rif_list_node);
	}
	if (neigh_entry->rif_list_node.next == &rif->neigh_list)
	if (list_is_last(&neigh_entry->rif_list_node, &rif->neigh_list))
		return NULL;
	return list_next_entry(neigh_entry, rif_list_node);
}
@@ -2028,6 +2029,7 @@ struct mlxsw_sp_nexthop_key {
struct mlxsw_sp_nexthop {
	struct list_head neigh_list_node; /* member of neigh entry list */
	struct list_head rif_list_node;
	struct list_head router_list_node;
	struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
						* this belongs to
						*/
@@ -2050,6 +2052,8 @@ struct mlxsw_sp_nexthop {
		struct mlxsw_sp_neigh_entry *neigh_entry;
		struct mlxsw_sp_ipip_entry *ipip_entry;
	};
	unsigned int counter_index;
	bool counter_valid;
};

struct mlxsw_sp_nexthop_group {
@@ -2066,6 +2070,112 @@ struct mlxsw_sp_nexthop_group {
#define nh_rif	nexthops[0].rif
};

void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
				    struct mlxsw_sp_nexthop *nh)
{
	struct devlink *devlink;

	devlink = priv_to_devlink(mlxsw_sp->core);
	if (!devlink_dpipe_table_counter_enabled(devlink,
						 MLXSW_SP_DPIPE_TABLE_NAME_ADJ))
		return;

	if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &nh->counter_index))
		return;

	nh->counter_valid = true;
}

void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
				   struct mlxsw_sp_nexthop *nh)
{
	if (!nh->counter_valid)
		return;
	mlxsw_sp_flow_counter_free(mlxsw_sp, nh->counter_index);
	nh->counter_valid = false;
}

int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_nexthop *nh, u64 *p_counter)
{
	if (!nh->counter_valid)
		return -EINVAL;

	return mlxsw_sp_flow_counter_get(mlxsw_sp, nh->counter_index,
					 p_counter, NULL);
}

struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
					       struct mlxsw_sp_nexthop *nh)
{
	if (!nh) {
		if (list_empty(&router->nexthop_list))
			return NULL;
		else
			return list_first_entry(&router->nexthop_list,
						typeof(*nh), router_list_node);
	}
	if (list_is_last(&nh->router_list_node, &router->nexthop_list))
		return NULL;
	return list_next_entry(nh, router_list_node);
}

bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh)
{
	return nh->offloaded;
}

unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh)
{
	if (!nh->offloaded)
		return NULL;
	return nh->neigh_entry->ha;
}

int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
			     u32 *p_adj_hash_index)
{
	struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
	u32 adj_hash_index = 0;
	int i;

	if (!nh->offloaded || !nh_grp->adj_index_valid)
		return -EINVAL;

	*p_adj_index = nh_grp->adj_index;

	for (i = 0; i < nh_grp->count; i++) {
		struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];

		if (nh_iter == nh)
			break;
		if (nh_iter->offloaded)
			adj_hash_index++;
	}

	*p_adj_hash_index = adj_hash_index;
	return 0;
}

struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh)
{
	return nh->rif;
}

bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh)
{
	struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
	int i;

	for (i = 0; i < nh_grp->count; i++) {
		struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];

		if (nh_iter->type == MLXSW_SP_NEXTHOP_TYPE_IPIP)
			return true;
	}
	return false;
}

static struct fib_info *
mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group *nh_grp)
{
@@ -2323,7 +2433,7 @@ static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
	return 0;
}

static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
			    struct mlxsw_sp_nexthop *nh)
{
	struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
@@ -2333,6 +2443,11 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
			    true, MLXSW_REG_RATR_TYPE_ETHERNET,
			    adj_index, neigh_entry->rif);
	mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
	if (nh->counter_valid)
		mlxsw_reg_ratr_counter_pack(ratr_pl, nh->counter_index, true);
	else
		mlxsw_reg_ratr_counter_pack(ratr_pl, 0, false);

	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
}

@@ -2367,7 +2482,7 @@ mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
		if (nh->update || reallocate) {
			switch (nh->type) {
			case MLXSW_SP_NEXTHOP_TYPE_ETH:
				err = mlxsw_sp_nexthop_mac_update
				err = mlxsw_sp_nexthop_update
					    (mlxsw_sp, adj_index, nh);
				break;
			case MLXSW_SP_NEXTHOP_TYPE_IPIP:
@@ -2784,6 +2899,9 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
	if (err)
		return err;

	mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
	list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);

	if (!dev)
		return 0;

@@ -2807,6 +2925,8 @@ static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp *mlxsw_sp,
				   struct mlxsw_sp_nexthop *nh)
{
	mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
	list_del(&nh->router_list_node);
	mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
	mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
}

@@ -4044,6 +4164,9 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,

	nh->nh_grp = nh_grp;
	memcpy(&nh->gw_addr, &rt->rt6i_gateway, sizeof(nh->gw_addr));
	mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);

	list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);

	if (!dev)
		return 0;
@@ -4056,6 +4179,8 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
				   struct mlxsw_sp_nexthop *nh)
{
	mlxsw_sp_nexthop6_type_fini(mlxsw_sp, nh);
	list_del(&nh->router_list_node);
	mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
}

static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
@@ -5990,6 +6115,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
	if (err)
		goto err_nexthop_group_ht_init;

	INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_list);
	err = mlxsw_sp_lpm_init(mlxsw_sp);
	if (err)
		goto err_lpm_init;
+20 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ enum mlxsw_sp_rif_counter_dir {
};

struct mlxsw_sp_neigh_entry;
struct mlxsw_sp_nexthop;

struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
					   u16 rif_index);
@@ -108,5 +109,24 @@ union mlxsw_sp_l3addr
mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
			   const struct net_device *ol_dev);
__be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev);
struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
					       struct mlxsw_sp_nexthop *nh);
bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh);
unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh);
int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
			     u32 *p_adj_hash_index);
struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh);
bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh);
#define mlxsw_sp_nexthop_for_each(nh, router)				\
	for (nh = mlxsw_sp_nexthop_next(router, NULL); nh;		\
	     nh = mlxsw_sp_nexthop_next(router, nh))
int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_nexthop *nh, u64 *p_counter);
int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
			    struct mlxsw_sp_nexthop *nh);
void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
				    struct mlxsw_sp_nexthop *nh);
void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
				   struct mlxsw_sp_nexthop *nh);

#endif /* _MLXSW_ROUTER_H_*/