cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum_dpipe.c (36122B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/kernel.h>
      5#include <linux/mutex.h>
      6#include <net/devlink.h>
      7
      8#include "spectrum.h"
      9#include "spectrum_dpipe.h"
     10#include "spectrum_router.h"
     11
     12enum mlxsw_sp_field_metadata_id {
     13	MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
     14	MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
     15	MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
     16	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
     17	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
     18	MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
     19};
     20
     21static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
     22	{
     23		.name = "erif_port",
     24		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
     25		.bitwidth = 32,
     26		.mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
     27	},
     28	{
     29		.name = "l3_forward",
     30		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
     31		.bitwidth = 1,
     32	},
     33	{
     34		.name = "l3_drop",
     35		.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
     36		.bitwidth = 1,
     37	},
     38	{
     39		.name = "adj_index",
     40		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
     41		.bitwidth = 32,
     42	},
     43	{
     44		.name = "adj_size",
     45		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
     46		.bitwidth = 32,
     47	},
     48	{
     49		.name = "adj_hash_index",
     50		.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
     51		.bitwidth = 32,
     52	},
     53};
     54
     55enum mlxsw_sp_dpipe_header_id {
     56	MLXSW_SP_DPIPE_HEADER_METADATA,
     57};
     58
     59static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
     60	.name = "mlxsw_meta",
     61	.id = MLXSW_SP_DPIPE_HEADER_METADATA,
     62	.fields = mlxsw_sp_dpipe_fields_metadata,
     63	.fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
     64};
     65
     66static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
     67	&mlxsw_sp_dpipe_header_metadata,
     68	&devlink_dpipe_header_ethernet,
     69	&devlink_dpipe_header_ipv4,
     70	&devlink_dpipe_header_ipv6,
     71};
     72
     73static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
     74	.headers = mlxsw_dpipe_headers,
     75	.headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
     76};
     77
     78static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
     79						  struct sk_buff *skb)
     80{
     81	struct devlink_dpipe_action action = {0};
     82	int err;
     83
     84	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
     85	action.header = &mlxsw_sp_dpipe_header_metadata;
     86	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
     87
     88	err = devlink_dpipe_action_put(skb, &action);
     89	if (err)
     90		return err;
     91
     92	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
     93	action.header = &mlxsw_sp_dpipe_header_metadata;
     94	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
     95
     96	return devlink_dpipe_action_put(skb, &action);
     97}
     98
     99static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
    100						  struct sk_buff *skb)
    101{
    102	struct devlink_dpipe_match match = {0};
    103
    104	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    105	match.header = &mlxsw_sp_dpipe_header_metadata;
    106	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    107
    108	return devlink_dpipe_match_put(skb, &match);
    109}
    110
    111static void
    112mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
    113				   struct devlink_dpipe_action *action)
    114{
    115	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    116	action->header = &mlxsw_sp_dpipe_header_metadata;
    117	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
    118
    119	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    120	match->header = &mlxsw_sp_dpipe_header_metadata;
    121	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    122}
    123
    124static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
    125				       struct devlink_dpipe_value *match_value,
    126				       struct devlink_dpipe_match *match,
    127				       struct devlink_dpipe_value *action_value,
    128				       struct devlink_dpipe_action *action)
    129{
    130	entry->match_values = match_value;
    131	entry->match_values_count = 1;
    132
    133	entry->action_values = action_value;
    134	entry->action_values_count = 1;
    135
    136	match_value->match = match;
    137	match_value->value_size = sizeof(u32);
    138	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
    139	if (!match_value->value)
    140		return -ENOMEM;
    141
    142	action_value->action = action;
    143	action_value->value_size = sizeof(u32);
    144	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
    145	if (!action_value->value)
    146		goto err_action_alloc;
    147	return 0;
    148
    149err_action_alloc:
    150	kfree(match_value->value);
    151	return -ENOMEM;
    152}
    153
    154static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
    155				   struct devlink_dpipe_entry *entry,
    156				   struct mlxsw_sp_rif *rif,
    157				   bool counters_enabled)
    158{
    159	u32 *action_value;
    160	u32 *rif_value;
    161	u64 cnt;
    162	int err;
    163
    164	/* Set Match RIF index */
    165	rif_value = entry->match_values->value;
    166	*rif_value = mlxsw_sp_rif_index(rif);
    167	entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
    168	entry->match_values->mapping_valid = true;
    169
    170	/* Set Action Forwarding */
    171	action_value = entry->action_values->value;
    172	*action_value = 1;
    173
    174	entry->counter_valid = false;
    175	entry->counter = 0;
    176	entry->index = mlxsw_sp_rif_index(rif);
    177
    178	if (!counters_enabled)
    179		return 0;
    180
    181	err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
    182					     MLXSW_SP_RIF_COUNTER_EGRESS,
    183					     &cnt);
    184	if (!err) {
    185		entry->counter = cnt;
    186		entry->counter_valid = true;
    187	}
    188	return 0;
    189}
    190
    191static int
    192mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
    193				       struct devlink_dpipe_dump_ctx *dump_ctx)
    194{
    195	struct devlink_dpipe_value match_value, action_value;
    196	struct devlink_dpipe_action action = {0};
    197	struct devlink_dpipe_match match = {0};
    198	struct devlink_dpipe_entry entry = {0};
    199	struct mlxsw_sp *mlxsw_sp = priv;
    200	unsigned int rif_count;
    201	int i, j;
    202	int err;
    203
    204	memset(&match_value, 0, sizeof(match_value));
    205	memset(&action_value, 0, sizeof(action_value));
    206
    207	mlxsw_sp_erif_match_action_prepare(&match, &action);
    208	err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
    209					  &action_value, &action);
    210	if (err)
    211		return err;
    212
    213	rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
    214	mutex_lock(&mlxsw_sp->router->lock);
    215	i = 0;
    216start_again:
    217	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
    218	if (err)
    219		goto err_ctx_prepare;
    220	j = 0;
    221	for (; i < rif_count; i++) {
    222		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
    223
    224		if (!rif || !mlxsw_sp_rif_dev(rif))
    225			continue;
    226		err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
    227					      counters_enabled);
    228		if (err)
    229			goto err_entry_get;
    230		err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
    231		if (err) {
    232			if (err == -EMSGSIZE) {
    233				if (!j)
    234					goto err_entry_append;
    235				break;
    236			}
    237			goto err_entry_append;
    238		}
    239		j++;
    240	}
    241
    242	devlink_dpipe_entry_ctx_close(dump_ctx);
    243	if (i != rif_count)
    244		goto start_again;
    245	mutex_unlock(&mlxsw_sp->router->lock);
    246
    247	devlink_dpipe_entry_clear(&entry);
    248	return 0;
    249err_entry_append:
    250err_entry_get:
    251err_ctx_prepare:
    252	mutex_unlock(&mlxsw_sp->router->lock);
    253	devlink_dpipe_entry_clear(&entry);
    254	return err;
    255}
    256
    257static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
    258{
    259	struct mlxsw_sp *mlxsw_sp = priv;
    260	int i;
    261
    262	mutex_lock(&mlxsw_sp->router->lock);
    263	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
    264		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
    265
    266		if (!rif)
    267			continue;
    268		if (enable)
    269			mlxsw_sp_rif_counter_alloc(rif,
    270						   MLXSW_SP_RIF_COUNTER_EGRESS);
    271		else
    272			mlxsw_sp_rif_counter_free(rif,
    273						  MLXSW_SP_RIF_COUNTER_EGRESS);
    274	}
    275	mutex_unlock(&mlxsw_sp->router->lock);
    276	return 0;
    277}
    278
    279static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
    280{
    281	struct mlxsw_sp *mlxsw_sp = priv;
    282
    283	return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
    284}
    285
    286static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
    287	.matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
    288	.actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
    289	.entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
    290	.counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
    291	.size_get = mlxsw_sp_dpipe_table_erif_size_get,
    292};
    293
    294static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
    295{
    296	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    297
    298	return devlink_dpipe_table_register(devlink,
    299					    MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
    300					    &mlxsw_sp_erif_ops,
    301					    mlxsw_sp, false);
    302}
    303
    304static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
    305{
    306	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    307
    308	devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
    309}
    310
    311static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
    312{
    313	struct devlink_dpipe_match match = {0};
    314	int err;
    315
    316	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    317	match.header = &mlxsw_sp_dpipe_header_metadata;
    318	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    319
    320	err = devlink_dpipe_match_put(skb, &match);
    321	if (err)
    322		return err;
    323
    324	switch (type) {
    325	case AF_INET:
    326		match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    327		match.header = &devlink_dpipe_header_ipv4;
    328		match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
    329		break;
    330	case AF_INET6:
    331		match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    332		match.header = &devlink_dpipe_header_ipv6;
    333		match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
    334		break;
    335	default:
    336		WARN_ON(1);
    337		return -EINVAL;
    338	}
    339
    340	return devlink_dpipe_match_put(skb, &match);
    341}
    342
    343static int
    344mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
    345{
    346	return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
    347}
    348
    349static int
    350mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
    351{
    352	struct devlink_dpipe_action action = {0};
    353
    354	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    355	action.header = &devlink_dpipe_header_ethernet;
    356	action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
    357
    358	return devlink_dpipe_action_put(skb, &action);
    359}
    360
    361enum mlxsw_sp_dpipe_table_host_match {
    362	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
    363	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
    364	MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
    365};
    366
    367static void
    368mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
    369					       struct devlink_dpipe_action *action,
    370					       int type)
    371{
    372	struct devlink_dpipe_match *match;
    373
    374	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
    375	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    376	match->header = &mlxsw_sp_dpipe_header_metadata;
    377	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    378
    379	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
    380	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    381	switch (type) {
    382	case AF_INET:
    383		match->header = &devlink_dpipe_header_ipv4;
    384		match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
    385		break;
    386	case AF_INET6:
    387		match->header = &devlink_dpipe_header_ipv6;
    388		match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
    389		break;
    390	default:
    391		WARN_ON(1);
    392		return;
    393	}
    394
    395	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    396	action->header = &devlink_dpipe_header_ethernet;
    397	action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
    398}
    399
    400static int
    401mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
    402					struct devlink_dpipe_value *match_values,
    403					struct devlink_dpipe_match *matches,
    404					struct devlink_dpipe_value *action_value,
    405					struct devlink_dpipe_action *action,
    406					int type)
    407{
    408	struct devlink_dpipe_value *match_value;
    409	struct devlink_dpipe_match *match;
    410
    411	entry->match_values = match_values;
    412	entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
    413
    414	entry->action_values = action_value;
    415	entry->action_values_count = 1;
    416
    417	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
    418	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
    419
    420	match_value->match = match;
    421	match_value->value_size = sizeof(u32);
    422	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
    423	if (!match_value->value)
    424		return -ENOMEM;
    425
    426	match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
    427	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
    428
    429	match_value->match = match;
    430	switch (type) {
    431	case AF_INET:
    432		match_value->value_size = sizeof(u32);
    433		break;
    434	case AF_INET6:
    435		match_value->value_size = sizeof(struct in6_addr);
    436		break;
    437	default:
    438		WARN_ON(1);
    439		return -EINVAL;
    440	}
    441
    442	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
    443	if (!match_value->value)
    444		return -ENOMEM;
    445
    446	action_value->action = action;
    447	action_value->value_size = sizeof(u64);
    448	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
    449	if (!action_value->value)
    450		return -ENOMEM;
    451
    452	return 0;
    453}
    454
    455static void
    456__mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
    457				       struct mlxsw_sp_rif *rif,
    458				       unsigned char *ha, void *dip)
    459{
    460	struct devlink_dpipe_value *value;
    461	u32 *rif_value;
    462	u8 *ha_value;
    463
    464	/* Set Match RIF index */
    465	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
    466
    467	rif_value = value->value;
    468	*rif_value = mlxsw_sp_rif_index(rif);
    469	value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
    470	value->mapping_valid = true;
    471
    472	/* Set Match DIP */
    473	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
    474	memcpy(value->value, dip, value->value_size);
    475
    476	/* Set Action DMAC */
    477	value = entry->action_values;
    478	ha_value = value->value;
    479	ether_addr_copy(ha_value, ha);
    480}
    481
    482static void
    483mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
    484				      struct mlxsw_sp_neigh_entry *neigh_entry,
    485				      struct mlxsw_sp_rif *rif)
    486{
    487	unsigned char *ha;
    488	u32 dip;
    489
    490	ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
    491	dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
    492	__mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
    493}
    494
    495static void
    496mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
    497				      struct mlxsw_sp_neigh_entry *neigh_entry,
    498				      struct mlxsw_sp_rif *rif)
    499{
    500	struct in6_addr *dip;
    501	unsigned char *ha;
    502
    503	ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
    504	dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
    505
    506	__mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
    507}
    508
    509static void
    510mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
    511				     struct devlink_dpipe_entry *entry,
    512				     struct mlxsw_sp_neigh_entry *neigh_entry,
    513				     struct mlxsw_sp_rif *rif,
    514				     int type)
    515{
    516	int err;
    517
    518	switch (type) {
    519	case AF_INET:
    520		mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
    521		break;
    522	case AF_INET6:
    523		mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
    524		break;
    525	default:
    526		WARN_ON(1);
    527		return;
    528	}
    529
    530	err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
    531					 &entry->counter);
    532	if (!err)
    533		entry->counter_valid = true;
    534}
    535
    536static int
    537mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
    538				      struct devlink_dpipe_entry *entry,
    539				      bool counters_enabled,
    540				      struct devlink_dpipe_dump_ctx *dump_ctx,
    541				      int type)
    542{
    543	int rif_neigh_count = 0;
    544	int rif_neigh_skip = 0;
    545	int neigh_count = 0;
    546	int rif_count;
    547	int i, j;
    548	int err;
    549
    550	mutex_lock(&mlxsw_sp->router->lock);
    551	i = 0;
    552	rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
    553start_again:
    554	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
    555	if (err)
    556		goto err_ctx_prepare;
    557	j = 0;
    558	rif_neigh_skip = rif_neigh_count;
    559	for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
    560		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
    561		struct mlxsw_sp_neigh_entry *neigh_entry;
    562
    563		if (!rif)
    564			continue;
    565
    566		rif_neigh_count = 0;
    567		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
    568			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
    569
    570			if (neigh_type != type)
    571				continue;
    572
    573			if (neigh_type == AF_INET6 &&
    574			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
    575				continue;
    576
    577			if (rif_neigh_count < rif_neigh_skip)
    578				goto skip;
    579
    580			mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
    581							     neigh_entry, rif,
    582							     type);
    583			entry->index = neigh_count;
    584			err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
    585			if (err) {
    586				if (err == -EMSGSIZE) {
    587					if (!j)
    588						goto err_entry_append;
    589					else
    590						goto out;
    591				}
    592				goto err_entry_append;
    593			}
    594			neigh_count++;
    595			j++;
    596skip:
    597			rif_neigh_count++;
    598		}
    599		rif_neigh_skip = 0;
    600	}
    601out:
    602	devlink_dpipe_entry_ctx_close(dump_ctx);
    603	if (i != rif_count)
    604		goto start_again;
    605
    606	mutex_unlock(&mlxsw_sp->router->lock);
    607	return 0;
    608
    609err_ctx_prepare:
    610err_entry_append:
    611	mutex_unlock(&mlxsw_sp->router->lock);
    612	return err;
    613}
    614
    615static int
    616mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
    617				       bool counters_enabled,
    618				       struct devlink_dpipe_dump_ctx *dump_ctx,
    619				       int type)
    620{
    621	struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
    622	struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
    623	struct devlink_dpipe_value action_value;
    624	struct devlink_dpipe_action action = {0};
    625	struct devlink_dpipe_entry entry = {0};
    626	int err;
    627
    628	memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
    629			   sizeof(matches[0]));
    630	memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
    631				sizeof(match_values[0]));
    632	memset(&action_value, 0, sizeof(action_value));
    633
    634	mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
    635	err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
    636						      matches, &action_value,
    637						      &action, type);
    638	if (err)
    639		goto out;
    640
    641	err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
    642						    counters_enabled, dump_ctx,
    643						    type);
    644out:
    645	devlink_dpipe_entry_clear(&entry);
    646	return err;
    647}
    648
    649static int
    650mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
    651					struct devlink_dpipe_dump_ctx *dump_ctx)
    652{
    653	struct mlxsw_sp *mlxsw_sp = priv;
    654
    655	return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
    656						      counters_enabled,
    657						      dump_ctx, AF_INET);
    658}
    659
    660static void
    661mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
    662					  bool enable, int type)
    663{
    664	int i;
    665
    666	mutex_lock(&mlxsw_sp->router->lock);
    667	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
    668		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
    669		struct mlxsw_sp_neigh_entry *neigh_entry;
    670
    671		if (!rif)
    672			continue;
    673		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
    674			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
    675
    676			if (neigh_type != type)
    677				continue;
    678
    679			if (neigh_type == AF_INET6 &&
    680			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
    681				continue;
    682
    683			mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
    684							    neigh_entry,
    685							    enable);
    686		}
    687	}
    688	mutex_unlock(&mlxsw_sp->router->lock);
    689}
    690
    691static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
    692{
    693	struct mlxsw_sp *mlxsw_sp = priv;
    694
    695	mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
    696	return 0;
    697}
    698
    699static u64
    700mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
    701{
    702	u64 size = 0;
    703	int i;
    704
    705	mutex_lock(&mlxsw_sp->router->lock);
    706	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
    707		struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
    708		struct mlxsw_sp_neigh_entry *neigh_entry;
    709
    710		if (!rif)
    711			continue;
    712		mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
    713			int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
    714
    715			if (neigh_type != type)
    716				continue;
    717
    718			if (neigh_type == AF_INET6 &&
    719			    mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
    720				continue;
    721
    722			size++;
    723		}
    724	}
    725	mutex_unlock(&mlxsw_sp->router->lock);
    726
    727	return size;
    728}
    729
    730static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
    731{
    732	struct mlxsw_sp *mlxsw_sp = priv;
    733
    734	return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
    735}
    736
    737static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
    738	.matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
    739	.actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
    740	.entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
    741	.counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
    742	.size_get = mlxsw_sp_dpipe_table_host4_size_get,
    743};
    744
    745#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
    746
    747static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
    748{
    749	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    750	int err;
    751
    752	err = devlink_dpipe_table_register(devlink,
    753					   MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
    754					   &mlxsw_sp_host4_ops,
    755					   mlxsw_sp, false);
    756	if (err)
    757		return err;
    758
    759	err = devlink_dpipe_table_resource_set(devlink,
    760					       MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
    761					       MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
    762					       MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
    763	if (err)
    764		goto err_resource_set;
    765
    766	return 0;
    767
    768err_resource_set:
    769	devlink_dpipe_table_unregister(devlink,
    770				       MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
    771	return err;
    772}
    773
    774static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
    775{
    776	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    777
    778	devlink_dpipe_table_unregister(devlink,
    779				       MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
    780}
    781
    782static int
    783mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
    784{
    785	return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
    786}
    787
    788static int
    789mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
    790					struct devlink_dpipe_dump_ctx *dump_ctx)
    791{
    792	struct mlxsw_sp *mlxsw_sp = priv;
    793
    794	return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
    795						      counters_enabled,
    796						      dump_ctx, AF_INET6);
    797}
    798
    799static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
    800{
    801	struct mlxsw_sp *mlxsw_sp = priv;
    802
    803	mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
    804	return 0;
    805}
    806
    807static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
    808{
    809	struct mlxsw_sp *mlxsw_sp = priv;
    810
    811	return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
    812}
    813
    814static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
    815	.matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
    816	.actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
    817	.entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
    818	.counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
    819	.size_get = mlxsw_sp_dpipe_table_host6_size_get,
    820};
    821
    822#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
    823
    824static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
    825{
    826	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    827	int err;
    828
    829	err = devlink_dpipe_table_register(devlink,
    830					   MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
    831					   &mlxsw_sp_host6_ops,
    832					   mlxsw_sp, false);
    833	if (err)
    834		return err;
    835
    836	err = devlink_dpipe_table_resource_set(devlink,
    837					       MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
    838					       MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
    839					       MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
    840	if (err)
    841		goto err_resource_set;
    842
    843	return 0;
    844
    845err_resource_set:
    846	devlink_dpipe_table_unregister(devlink,
    847				       MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
    848	return err;
    849}
    850
    851static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
    852{
    853	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    854
    855	devlink_dpipe_table_unregister(devlink,
    856				       MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
    857}
    858
    859static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
    860						 struct sk_buff *skb)
    861{
    862	struct devlink_dpipe_match match = {0};
    863	int err;
    864
    865	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    866	match.header = &mlxsw_sp_dpipe_header_metadata;
    867	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
    868
    869	err = devlink_dpipe_match_put(skb, &match);
    870	if (err)
    871		return err;
    872
    873	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    874	match.header = &mlxsw_sp_dpipe_header_metadata;
    875	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
    876
    877	err = devlink_dpipe_match_put(skb, &match);
    878	if (err)
    879		return err;
    880
    881	match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    882	match.header = &mlxsw_sp_dpipe_header_metadata;
    883	match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
    884
    885	return devlink_dpipe_match_put(skb, &match);
    886}
    887
    888static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
    889						 struct sk_buff *skb)
    890{
    891	struct devlink_dpipe_action action = {0};
    892	int err;
    893
    894	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    895	action.header = &devlink_dpipe_header_ethernet;
    896	action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
    897
    898	err = devlink_dpipe_action_put(skb, &action);
    899	if (err)
    900		return err;
    901
    902	action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    903	action.header = &mlxsw_sp_dpipe_header_metadata;
    904	action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    905
    906	return devlink_dpipe_action_put(skb, &action);
    907}
    908
    909static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
    910{
    911	struct mlxsw_sp_nexthop *nh;
    912	u64 size = 0;
    913
    914	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
    915		if (mlxsw_sp_nexthop_is_forward(nh) &&
    916		    !mlxsw_sp_nexthop_group_has_ipip(nh))
    917			size++;
    918	return size;
    919}
    920
    921enum mlxsw_sp_dpipe_table_adj_match {
    922	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
    923	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
    924	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
    925	MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
    926};
    927
    928enum mlxsw_sp_dpipe_table_adj_action {
    929	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
    930	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
    931	MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
    932};
    933
    934static void
    935mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
    936					      struct devlink_dpipe_action *actions)
    937{
    938	struct devlink_dpipe_action *action;
    939	struct devlink_dpipe_match *match;
    940
    941	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
    942	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    943	match->header = &mlxsw_sp_dpipe_header_metadata;
    944	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
    945
    946	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
    947	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    948	match->header = &mlxsw_sp_dpipe_header_metadata;
    949	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
    950
    951	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
    952	match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
    953	match->header = &mlxsw_sp_dpipe_header_metadata;
    954	match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
    955
    956	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
    957	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    958	action->header = &devlink_dpipe_header_ethernet;
    959	action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
    960
    961	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
    962	action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
    963	action->header = &mlxsw_sp_dpipe_header_metadata;
    964	action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
    965}
    966
    967static int
    968mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
    969				       struct devlink_dpipe_value *match_values,
    970				       struct devlink_dpipe_match *matches,
    971				       struct devlink_dpipe_value *action_values,
    972				       struct devlink_dpipe_action *actions)
    973{	struct devlink_dpipe_value *action_value;
    974	struct devlink_dpipe_value *match_value;
    975	struct devlink_dpipe_action *action;
    976	struct devlink_dpipe_match *match;
    977
    978	entry->match_values = match_values;
    979	entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
    980
    981	entry->action_values = action_values;
    982	entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
    983
    984	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
    985	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
    986
    987	match_value->match = match;
    988	match_value->value_size = sizeof(u32);
    989	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
    990	if (!match_value->value)
    991		return -ENOMEM;
    992
    993	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
    994	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
    995
    996	match_value->match = match;
    997	match_value->value_size = sizeof(u32);
    998	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
    999	if (!match_value->value)
   1000		return -ENOMEM;
   1001
   1002	match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
   1003	match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
   1004
   1005	match_value->match = match;
   1006	match_value->value_size = sizeof(u32);
   1007	match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
   1008	if (!match_value->value)
   1009		return -ENOMEM;
   1010
   1011	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
   1012	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
   1013
   1014	action_value->action = action;
   1015	action_value->value_size = sizeof(u64);
   1016	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
   1017	if (!action_value->value)
   1018		return -ENOMEM;
   1019
   1020	action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
   1021	action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
   1022
   1023	action_value->action = action;
   1024	action_value->value_size = sizeof(u32);
   1025	action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
   1026	if (!action_value->value)
   1027		return -ENOMEM;
   1028
   1029	return 0;
   1030}
   1031
   1032static void
   1033__mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
   1034				      u32 adj_index, u32 adj_size,
   1035				      u32 adj_hash_index, unsigned char *ha,
   1036				      struct mlxsw_sp_rif *rif)
   1037{
   1038	struct devlink_dpipe_value *value;
   1039	u32 *p_rif_value;
   1040	u32 *p_index;
   1041
   1042	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
   1043	p_index = value->value;
   1044	*p_index = adj_index;
   1045
   1046	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
   1047	p_index = value->value;
   1048	*p_index = adj_size;
   1049
   1050	value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
   1051	p_index = value->value;
   1052	*p_index = adj_hash_index;
   1053
   1054	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
   1055	ether_addr_copy(value->value, ha);
   1056
   1057	value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
   1058	p_rif_value = value->value;
   1059	*p_rif_value = mlxsw_sp_rif_index(rif);
   1060	value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
   1061	value->mapping_valid = true;
   1062}
   1063
   1064static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
   1065						struct mlxsw_sp_nexthop *nh,
   1066						struct devlink_dpipe_entry *entry)
   1067{
   1068	struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
   1069	unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
   1070	u32 adj_hash_index = 0;
   1071	u32 adj_index = 0;
   1072	u32 adj_size = 0;
   1073	int err;
   1074
   1075	mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
   1076	__mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
   1077					      adj_hash_index, ha, rif);
   1078	err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
   1079	if (!err)
   1080		entry->counter_valid = true;
   1081}
   1082
   1083static int
   1084mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
   1085				     struct devlink_dpipe_entry *entry,
   1086				     bool counters_enabled,
   1087				     struct devlink_dpipe_dump_ctx *dump_ctx)
   1088{
   1089	struct mlxsw_sp_nexthop *nh;
   1090	int entry_index = 0;
   1091	int nh_count_max;
   1092	int nh_count = 0;
   1093	int nh_skip;
   1094	int j;
   1095	int err;
   1096
   1097	mutex_lock(&mlxsw_sp->router->lock);
   1098	nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
   1099start_again:
   1100	err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
   1101	if (err)
   1102		goto err_ctx_prepare;
   1103	j = 0;
   1104	nh_skip = nh_count;
   1105	nh_count = 0;
   1106	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
   1107		if (!mlxsw_sp_nexthop_is_forward(nh) ||
   1108		    mlxsw_sp_nexthop_group_has_ipip(nh))
   1109			continue;
   1110
   1111		if (nh_count < nh_skip)
   1112			goto skip;
   1113
   1114		mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
   1115		entry->index = entry_index;
   1116		err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
   1117		if (err) {
   1118			if (err == -EMSGSIZE) {
   1119				if (!j)
   1120					goto err_entry_append;
   1121				break;
   1122			}
   1123			goto err_entry_append;
   1124		}
   1125		entry_index++;
   1126		j++;
   1127skip:
   1128		nh_count++;
   1129	}
   1130
   1131	devlink_dpipe_entry_ctx_close(dump_ctx);
   1132	if (nh_count != nh_count_max)
   1133		goto start_again;
   1134	mutex_unlock(&mlxsw_sp->router->lock);
   1135
   1136	return 0;
   1137
   1138err_ctx_prepare:
   1139err_entry_append:
   1140	mutex_unlock(&mlxsw_sp->router->lock);
   1141	return err;
   1142}
   1143
   1144static int
   1145mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
   1146				      struct devlink_dpipe_dump_ctx *dump_ctx)
   1147{
   1148	struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
   1149	struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
   1150	struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
   1151	struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
   1152	struct devlink_dpipe_entry entry = {0};
   1153	struct mlxsw_sp *mlxsw_sp = priv;
   1154	int err;
   1155
   1156	memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
   1157			   sizeof(matches[0]));
   1158	memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
   1159				sizeof(match_values[0]));
   1160	memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
   1161			   sizeof(actions[0]));
   1162	memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
   1163				 sizeof(action_values[0]));
   1164
   1165	mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
   1166	err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
   1167						     match_values, matches,
   1168						     action_values, actions);
   1169	if (err)
   1170		goto out;
   1171
   1172	err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
   1173						   counters_enabled, dump_ctx);
   1174out:
   1175	devlink_dpipe_entry_clear(&entry);
   1176	return err;
   1177}
   1178
   1179static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
   1180{
   1181	char ratr_pl[MLXSW_REG_RATR_LEN];
   1182	struct mlxsw_sp *mlxsw_sp = priv;
   1183	struct mlxsw_sp_nexthop *nh;
   1184	u32 adj_hash_index = 0;
   1185	u32 adj_index = 0;
   1186	u32 adj_size = 0;
   1187
   1188	mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
   1189		if (!mlxsw_sp_nexthop_is_forward(nh) ||
   1190		    mlxsw_sp_nexthop_group_has_ipip(nh))
   1191			continue;
   1192
   1193		mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
   1194					 &adj_hash_index);
   1195		if (enable)
   1196			mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
   1197		else
   1198			mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
   1199		mlxsw_sp_nexthop_eth_update(mlxsw_sp,
   1200					    adj_index + adj_hash_index, nh,
   1201					    true, ratr_pl);
   1202	}
   1203	return 0;
   1204}
   1205
   1206static u64
   1207mlxsw_sp_dpipe_table_adj_size_get(void *priv)
   1208{
   1209	struct mlxsw_sp *mlxsw_sp = priv;
   1210	u64 size;
   1211
   1212	mutex_lock(&mlxsw_sp->router->lock);
   1213	size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
   1214	mutex_unlock(&mlxsw_sp->router->lock);
   1215
   1216	return size;
   1217}
   1218
   1219static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
   1220	.matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
   1221	.actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
   1222	.entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
   1223	.counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
   1224	.size_get = mlxsw_sp_dpipe_table_adj_size_get,
   1225};
   1226
   1227#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
   1228
   1229static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
   1230{
   1231	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
   1232	int err;
   1233
   1234	err = devlink_dpipe_table_register(devlink,
   1235					   MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
   1236					   &mlxsw_sp_dpipe_table_adj_ops,
   1237					   mlxsw_sp, false);
   1238	if (err)
   1239		return err;
   1240
   1241	err = devlink_dpipe_table_resource_set(devlink,
   1242					       MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
   1243					       MLXSW_SP_RESOURCE_KVD_LINEAR,
   1244					       MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
   1245	if (err)
   1246		goto err_resource_set;
   1247
   1248	return 0;
   1249
   1250err_resource_set:
   1251	devlink_dpipe_table_unregister(devlink,
   1252				       MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
   1253	return err;
   1254}
   1255
   1256static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
   1257{
   1258	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
   1259
   1260	devlink_dpipe_table_unregister(devlink,
   1261				       MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
   1262}
   1263
   1264int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
   1265{
   1266	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
   1267	int err;
   1268
   1269	err = devlink_dpipe_headers_register(devlink,
   1270					     &mlxsw_sp_dpipe_headers);
   1271	if (err)
   1272		return err;
   1273	err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
   1274	if (err)
   1275		goto err_erif_table_init;
   1276
   1277	err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
   1278	if (err)
   1279		goto err_host4_table_init;
   1280
   1281	err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
   1282	if (err)
   1283		goto err_host6_table_init;
   1284
   1285	err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
   1286	if (err)
   1287		goto err_adj_table_init;
   1288
   1289	return 0;
   1290err_adj_table_init:
   1291	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
   1292err_host6_table_init:
   1293	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
   1294err_host4_table_init:
   1295	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
   1296err_erif_table_init:
   1297	devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
   1298	return err;
   1299}
   1300
   1301void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
   1302{
   1303	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
   1304
   1305	mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
   1306	mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
   1307	mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
   1308	mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
   1309	devlink_dpipe_headers_unregister(devlink);
   1310}