linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
<<
>>
Prefs
   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(mlxsw_sp, rif,
 270                                                   MLXSW_SP_RIF_COUNTER_EGRESS);
 271                else
 272                        mlxsw_sp_rif_counter_free(mlxsw_sp, 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_offload(nh) &&
 916                    !mlxsw_sp_nexthop_group_has_ipip(nh) &&
 917                    !mlxsw_sp_nexthop_is_discard(nh))
 918                        size++;
 919        return size;
 920}
 921
 922enum mlxsw_sp_dpipe_table_adj_match {
 923        MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
 924        MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
 925        MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
 926        MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
 927};
 928
 929enum mlxsw_sp_dpipe_table_adj_action {
 930        MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
 931        MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
 932        MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
 933};
 934
 935static void
 936mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
 937                                              struct devlink_dpipe_action *actions)
 938{
 939        struct devlink_dpipe_action *action;
 940        struct devlink_dpipe_match *match;
 941
 942        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
 943        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 944        match->header = &mlxsw_sp_dpipe_header_metadata;
 945        match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
 946
 947        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
 948        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 949        match->header = &mlxsw_sp_dpipe_header_metadata;
 950        match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
 951
 952        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
 953        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 954        match->header = &mlxsw_sp_dpipe_header_metadata;
 955        match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
 956
 957        action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
 958        action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 959        action->header = &devlink_dpipe_header_ethernet;
 960        action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
 961
 962        action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
 963        action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 964        action->header = &mlxsw_sp_dpipe_header_metadata;
 965        action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
 966}
 967
 968static int
 969mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
 970                                       struct devlink_dpipe_value *match_values,
 971                                       struct devlink_dpipe_match *matches,
 972                                       struct devlink_dpipe_value *action_values,
 973                                       struct devlink_dpipe_action *actions)
 974{       struct devlink_dpipe_value *action_value;
 975        struct devlink_dpipe_value *match_value;
 976        struct devlink_dpipe_action *action;
 977        struct devlink_dpipe_match *match;
 978
 979        entry->match_values = match_values;
 980        entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
 981
 982        entry->action_values = action_values;
 983        entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
 984
 985        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
 986        match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
 987
 988        match_value->match = match;
 989        match_value->value_size = sizeof(u32);
 990        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
 991        if (!match_value->value)
 992                return -ENOMEM;
 993
 994        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
 995        match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
 996
 997        match_value->match = match;
 998        match_value->value_size = sizeof(u32);
 999        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1000        if (!match_value->value)
1001                return -ENOMEM;
1002
1003        match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1004        match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1005
1006        match_value->match = match;
1007        match_value->value_size = sizeof(u32);
1008        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1009        if (!match_value->value)
1010                return -ENOMEM;
1011
1012        action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1013        action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1014
1015        action_value->action = action;
1016        action_value->value_size = sizeof(u64);
1017        action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1018        if (!action_value->value)
1019                return -ENOMEM;
1020
1021        action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1022        action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1023
1024        action_value->action = action;
1025        action_value->value_size = sizeof(u32);
1026        action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1027        if (!action_value->value)
1028                return -ENOMEM;
1029
1030        return 0;
1031}
1032
1033static void
1034__mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1035                                      u32 adj_index, u32 adj_size,
1036                                      u32 adj_hash_index, unsigned char *ha,
1037                                      struct mlxsw_sp_rif *rif)
1038{
1039        struct devlink_dpipe_value *value;
1040        u32 *p_rif_value;
1041        u32 *p_index;
1042
1043        value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1044        p_index = value->value;
1045        *p_index = adj_index;
1046
1047        value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1048        p_index = value->value;
1049        *p_index = adj_size;
1050
1051        value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1052        p_index = value->value;
1053        *p_index = adj_hash_index;
1054
1055        value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1056        ether_addr_copy(value->value, ha);
1057
1058        value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1059        p_rif_value = value->value;
1060        *p_rif_value = mlxsw_sp_rif_index(rif);
1061        value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1062        value->mapping_valid = true;
1063}
1064
1065static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1066                                                struct mlxsw_sp_nexthop *nh,
1067                                                struct devlink_dpipe_entry *entry)
1068{
1069        struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1070        unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1071        u32 adj_hash_index = 0;
1072        u32 adj_index = 0;
1073        u32 adj_size = 0;
1074        int err;
1075
1076        mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1077        __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1078                                              adj_hash_index, ha, rif);
1079        err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1080        if (!err)
1081                entry->counter_valid = true;
1082}
1083
1084static int
1085mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1086                                     struct devlink_dpipe_entry *entry,
1087                                     bool counters_enabled,
1088                                     struct devlink_dpipe_dump_ctx *dump_ctx)
1089{
1090        struct mlxsw_sp_nexthop *nh;
1091        int entry_index = 0;
1092        int nh_count_max;
1093        int nh_count = 0;
1094        int nh_skip;
1095        int j;
1096        int err;
1097
1098        mutex_lock(&mlxsw_sp->router->lock);
1099        nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1100start_again:
1101        err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1102        if (err)
1103                goto err_ctx_prepare;
1104        j = 0;
1105        nh_skip = nh_count;
1106        nh_count = 0;
1107        mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1108                if (!mlxsw_sp_nexthop_offload(nh) ||
1109                    mlxsw_sp_nexthop_group_has_ipip(nh) ||
1110                    mlxsw_sp_nexthop_is_discard(nh))
1111                        continue;
1112
1113                if (nh_count < nh_skip)
1114                        goto skip;
1115
1116                mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1117                entry->index = entry_index;
1118                err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1119                if (err) {
1120                        if (err == -EMSGSIZE) {
1121                                if (!j)
1122                                        goto err_entry_append;
1123                                break;
1124                        }
1125                        goto err_entry_append;
1126                }
1127                entry_index++;
1128                j++;
1129skip:
1130                nh_count++;
1131        }
1132
1133        devlink_dpipe_entry_ctx_close(dump_ctx);
1134        if (nh_count != nh_count_max)
1135                goto start_again;
1136        mutex_unlock(&mlxsw_sp->router->lock);
1137
1138        return 0;
1139
1140err_ctx_prepare:
1141err_entry_append:
1142        mutex_unlock(&mlxsw_sp->router->lock);
1143        return err;
1144}
1145
1146static int
1147mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1148                                      struct devlink_dpipe_dump_ctx *dump_ctx)
1149{
1150        struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1151        struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1152        struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1153        struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1154        struct devlink_dpipe_entry entry = {0};
1155        struct mlxsw_sp *mlxsw_sp = priv;
1156        int err;
1157
1158        memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1159                           sizeof(matches[0]));
1160        memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1161                                sizeof(match_values[0]));
1162        memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1163                           sizeof(actions[0]));
1164        memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1165                                 sizeof(action_values[0]));
1166
1167        mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1168        err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1169                                                     match_values, matches,
1170                                                     action_values, actions);
1171        if (err)
1172                goto out;
1173
1174        err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1175                                                   counters_enabled, dump_ctx);
1176out:
1177        devlink_dpipe_entry_clear(&entry);
1178        return err;
1179}
1180
1181static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1182{
1183        struct mlxsw_sp *mlxsw_sp = priv;
1184        struct mlxsw_sp_nexthop *nh;
1185        u32 adj_hash_index = 0;
1186        u32 adj_index = 0;
1187        u32 adj_size = 0;
1188
1189        mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1190                if (!mlxsw_sp_nexthop_offload(nh) ||
1191                    mlxsw_sp_nexthop_group_has_ipip(nh) ||
1192                    mlxsw_sp_nexthop_is_discard(nh))
1193                        continue;
1194
1195                mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1196                                         &adj_hash_index);
1197                if (enable)
1198                        mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1199                else
1200                        mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1201                mlxsw_sp_nexthop_update(mlxsw_sp,
1202                                        adj_index + adj_hash_index, nh);
1203        }
1204        return 0;
1205}
1206
1207static u64
1208mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1209{
1210        struct mlxsw_sp *mlxsw_sp = priv;
1211        u64 size;
1212
1213        mutex_lock(&mlxsw_sp->router->lock);
1214        size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1215        mutex_unlock(&mlxsw_sp->router->lock);
1216
1217        return size;
1218}
1219
1220static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1221        .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1222        .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1223        .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1224        .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1225        .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1226};
1227
1228#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1229
1230static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1231{
1232        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1233        int err;
1234
1235        err = devlink_dpipe_table_register(devlink,
1236                                           MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1237                                           &mlxsw_sp_dpipe_table_adj_ops,
1238                                           mlxsw_sp, false);
1239        if (err)
1240                return err;
1241
1242        err = devlink_dpipe_table_resource_set(devlink,
1243                                               MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1244                                               MLXSW_SP_RESOURCE_KVD_LINEAR,
1245                                               MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1246        if (err)
1247                goto err_resource_set;
1248
1249        return 0;
1250
1251err_resource_set:
1252        devlink_dpipe_table_unregister(devlink,
1253                                       MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1254        return err;
1255}
1256
1257static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1258{
1259        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1260
1261        devlink_dpipe_table_unregister(devlink,
1262                                       MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1263}
1264
1265int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1266{
1267        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1268        int err;
1269
1270        err = devlink_dpipe_headers_register(devlink,
1271                                             &mlxsw_sp_dpipe_headers);
1272        if (err)
1273                return err;
1274        err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1275        if (err)
1276                goto err_erif_table_init;
1277
1278        err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1279        if (err)
1280                goto err_host4_table_init;
1281
1282        err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1283        if (err)
1284                goto err_host6_table_init;
1285
1286        err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1287        if (err)
1288                goto err_adj_table_init;
1289
1290        return 0;
1291err_adj_table_init:
1292        mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1293err_host6_table_init:
1294        mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1295err_host4_table_init:
1296        mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1297err_erif_table_init:
1298        devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1299        return err;
1300}
1301
1302void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1303{
1304        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1305
1306        mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1307        mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1308        mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1309        mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1310        devlink_dpipe_headers_unregister(devlink);
1311}
1312