Linux Audio

Check our new training course

Linux kernel drivers training

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