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

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

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: default avatarDavid S. Miller <davem@davemloft.net>
parents a5e2da6e a481d713
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -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);
+6 −4
Original line number Diff line number Diff line
@@ -382,11 +382,13 @@ 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;
	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);
}

+400 −33
Original line number Diff line number Diff line
@@ -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,7 +197,7 @@ 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,
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;
@@ -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);
}
+1 −0
Original line number Diff line number Diff line
@@ -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_*/
+104 −0
Original line number Diff line number Diff line
@@ -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;
Loading