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