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