linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
<<
>>
Prefs
   1/*
   2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
   3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
   4 * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com>
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions are met:
   8 *
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. Neither the names of the copyright holders nor the names of its
  15 *    contributors may be used to endorse or promote products derived from
  16 *    this software without specific prior written permission.
  17 *
  18 * Alternatively, this software may be distributed under the terms of the
  19 * GNU General Public License ("GPL") version 2 as published by the Free
  20 * Software Foundation.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32 * POSSIBILITY OF SUCH DAMAGE.
  33 */
  34
  35#include <linux/kernel.h>
  36#include <net/devlink.h>
  37
  38#include "spectrum.h"
  39#include "spectrum_dpipe.h"
  40#include "spectrum_router.h"
  41
  42enum mlxsw_sp_field_metadata_id {
  43        MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
  44        MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
  45        MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
  46};
  47
  48static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
  49        { .name = "erif_port",
  50          .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
  51          .bitwidth = 32,
  52          .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
  53        },
  54        { .name = "l3_forward",
  55          .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
  56          .bitwidth = 1,
  57        },
  58        { .name = "l3_drop",
  59          .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
  60          .bitwidth = 1,
  61        },
  62};
  63
  64enum mlxsw_sp_dpipe_header_id {
  65        MLXSW_SP_DPIPE_HEADER_METADATA,
  66};
  67
  68static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
  69        .name = "mlxsw_meta",
  70        .id = MLXSW_SP_DPIPE_HEADER_METADATA,
  71        .fields = mlxsw_sp_dpipe_fields_metadata,
  72        .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
  73};
  74
  75static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
  76        &mlxsw_sp_dpipe_header_metadata,
  77        &devlink_dpipe_header_ethernet,
  78        &devlink_dpipe_header_ipv4,
  79        &devlink_dpipe_header_ipv6,
  80};
  81
  82static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
  83        .headers = mlxsw_dpipe_headers,
  84        .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
  85};
  86
  87static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
  88                                                  struct sk_buff *skb)
  89{
  90        struct devlink_dpipe_action action = {0};
  91        int err;
  92
  93        action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
  94        action.header = &mlxsw_sp_dpipe_header_metadata;
  95        action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
  96
  97        err = devlink_dpipe_action_put(skb, &action);
  98        if (err)
  99                return err;
 100
 101        action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 102        action.header = &mlxsw_sp_dpipe_header_metadata;
 103        action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
 104
 105        return devlink_dpipe_action_put(skb, &action);
 106}
 107
 108static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
 109                                                  struct sk_buff *skb)
 110{
 111        struct devlink_dpipe_match match = {0};
 112
 113        match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 114        match.header = &mlxsw_sp_dpipe_header_metadata;
 115        match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
 116
 117        return devlink_dpipe_match_put(skb, &match);
 118}
 119
 120static void
 121mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
 122                                   struct devlink_dpipe_action *action)
 123{
 124        action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 125        action->header = &mlxsw_sp_dpipe_header_metadata;
 126        action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
 127
 128        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 129        match->header = &mlxsw_sp_dpipe_header_metadata;
 130        match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
 131}
 132
 133static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
 134                                       struct devlink_dpipe_value *match_value,
 135                                       struct devlink_dpipe_match *match,
 136                                       struct devlink_dpipe_value *action_value,
 137                                       struct devlink_dpipe_action *action)
 138{
 139        entry->match_values = match_value;
 140        entry->match_values_count = 1;
 141
 142        entry->action_values = action_value;
 143        entry->action_values_count = 1;
 144
 145        match_value->match = match;
 146        match_value->value_size = sizeof(u32);
 147        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
 148        if (!match_value->value)
 149                return -ENOMEM;
 150
 151        action_value->action = action;
 152        action_value->value_size = sizeof(u32);
 153        action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
 154        if (!action_value->value)
 155                goto err_action_alloc;
 156        return 0;
 157
 158err_action_alloc:
 159        kfree(match_value->value);
 160        return -ENOMEM;
 161}
 162
 163static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
 164                                   struct devlink_dpipe_entry *entry,
 165                                   struct mlxsw_sp_rif *rif,
 166                                   bool counters_enabled)
 167{
 168        u32 *action_value;
 169        u32 *rif_value;
 170        u64 cnt;
 171        int err;
 172
 173        /* Set Match RIF index */
 174        rif_value = entry->match_values->value;
 175        *rif_value = mlxsw_sp_rif_index(rif);
 176        entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
 177        entry->match_values->mapping_valid = true;
 178
 179        /* Set Action Forwarding */
 180        action_value = entry->action_values->value;
 181        *action_value = 1;
 182
 183        entry->counter_valid = false;
 184        entry->counter = 0;
 185        entry->index = mlxsw_sp_rif_index(rif);
 186
 187        if (!counters_enabled)
 188                return 0;
 189
 190        err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
 191                                             MLXSW_SP_RIF_COUNTER_EGRESS,
 192                                             &cnt);
 193        if (!err) {
 194                entry->counter = cnt;
 195                entry->counter_valid = true;
 196        }
 197        return 0;
 198}
 199
 200static int
 201mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
 202                                       struct devlink_dpipe_dump_ctx *dump_ctx)
 203{
 204        struct devlink_dpipe_value match_value, action_value;
 205        struct devlink_dpipe_action action = {0};
 206        struct devlink_dpipe_match match = {0};
 207        struct devlink_dpipe_entry entry = {0};
 208        struct mlxsw_sp *mlxsw_sp = priv;
 209        unsigned int rif_count;
 210        int i, j;
 211        int err;
 212
 213        memset(&match_value, 0, sizeof(match_value));
 214        memset(&action_value, 0, sizeof(action_value));
 215
 216        mlxsw_sp_erif_match_action_prepare(&match, &action);
 217        err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
 218                                          &action_value, &action);
 219        if (err)
 220                return err;
 221
 222        rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
 223        rtnl_lock();
 224        i = 0;
 225start_again:
 226        err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
 227        if (err)
 228                return err;
 229        j = 0;
 230        for (; i < rif_count; i++) {
 231                struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
 232
 233                if (!rif)
 234                        continue;
 235                err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
 236                                              counters_enabled);
 237                if (err)
 238                        goto err_entry_get;
 239                err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
 240                if (err) {
 241                        if (err == -EMSGSIZE) {
 242                                if (!j)
 243                                        goto err_entry_append;
 244                                break;
 245                        }
 246                        goto err_entry_append;
 247                }
 248                j++;
 249        }
 250
 251        devlink_dpipe_entry_ctx_close(dump_ctx);
 252        if (i != rif_count)
 253                goto start_again;
 254        rtnl_unlock();
 255
 256        devlink_dpipe_entry_clear(&entry);
 257        return 0;
 258err_entry_append:
 259err_entry_get:
 260        rtnl_unlock();
 261        devlink_dpipe_entry_clear(&entry);
 262        return err;
 263}
 264
 265static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
 266{
 267        struct mlxsw_sp *mlxsw_sp = priv;
 268        int i;
 269
 270        rtnl_lock();
 271        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 272                struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
 273
 274                if (!rif)
 275                        continue;
 276                if (enable)
 277                        mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
 278                                                   MLXSW_SP_RIF_COUNTER_EGRESS);
 279                else
 280                        mlxsw_sp_rif_counter_free(mlxsw_sp, rif,
 281                                                  MLXSW_SP_RIF_COUNTER_EGRESS);
 282        }
 283        rtnl_unlock();
 284        return 0;
 285}
 286
 287static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
 288{
 289        struct mlxsw_sp *mlxsw_sp = priv;
 290
 291        return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
 292}
 293
 294static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
 295        .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
 296        .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
 297        .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
 298        .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
 299        .size_get = mlxsw_sp_dpipe_table_erif_size_get,
 300};
 301
 302static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
 303{
 304        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 305
 306        return devlink_dpipe_table_register(devlink,
 307                                            MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
 308                                            &mlxsw_sp_erif_ops,
 309                                            mlxsw_sp, false);
 310}
 311
 312static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
 313{
 314        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 315
 316        devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
 317}
 318
 319static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
 320{
 321        struct devlink_dpipe_match match = {0};
 322        int err;
 323
 324        match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 325        match.header = &mlxsw_sp_dpipe_header_metadata;
 326        match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
 327
 328        err = devlink_dpipe_match_put(skb, &match);
 329        if (err)
 330                return err;
 331
 332        switch (type) {
 333        case AF_INET:
 334                match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 335                match.header = &devlink_dpipe_header_ipv4;
 336                match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
 337                break;
 338        case AF_INET6:
 339                match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 340                match.header = &devlink_dpipe_header_ipv6;
 341                match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
 342                break;
 343        default:
 344                WARN_ON(1);
 345                return -EINVAL;
 346        }
 347
 348        return devlink_dpipe_match_put(skb, &match);
 349}
 350
 351static int
 352mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
 353{
 354        return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
 355}
 356
 357static int
 358mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
 359{
 360        struct devlink_dpipe_action action = {0};
 361
 362        action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 363        action.header = &devlink_dpipe_header_ethernet;
 364        action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
 365
 366        return devlink_dpipe_action_put(skb, &action);
 367}
 368
 369enum mlxsw_sp_dpipe_table_host_match {
 370        MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
 371        MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
 372        MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
 373};
 374
 375static void
 376mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
 377                                               struct devlink_dpipe_action *action,
 378                                               int type)
 379{
 380        struct devlink_dpipe_match *match;
 381
 382        match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
 383        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 384        match->header = &mlxsw_sp_dpipe_header_metadata;
 385        match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
 386
 387        match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
 388        match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
 389        switch (type) {
 390        case AF_INET:
 391                match->header = &devlink_dpipe_header_ipv4;
 392                match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
 393                break;
 394        case AF_INET6:
 395                match->header = &devlink_dpipe_header_ipv6;
 396                match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
 397                break;
 398        default:
 399                WARN_ON(1);
 400                return;
 401        }
 402
 403        action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
 404        action->header = &devlink_dpipe_header_ethernet;
 405        action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
 406}
 407
 408static int
 409mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
 410                                        struct devlink_dpipe_value *match_values,
 411                                        struct devlink_dpipe_match *matches,
 412                                        struct devlink_dpipe_value *action_value,
 413                                        struct devlink_dpipe_action *action,
 414                                        int type)
 415{
 416        struct devlink_dpipe_value *match_value;
 417        struct devlink_dpipe_match *match;
 418
 419        entry->match_values = match_values;
 420        entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
 421
 422        entry->action_values = action_value;
 423        entry->action_values_count = 1;
 424
 425        match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
 426        match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
 427
 428        match_value->match = match;
 429        match_value->value_size = sizeof(u32);
 430        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
 431        if (!match_value->value)
 432                return -ENOMEM;
 433
 434        match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
 435        match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
 436
 437        match_value->match = match;
 438        switch (type) {
 439        case AF_INET:
 440                match_value->value_size = sizeof(u32);
 441                break;
 442        case AF_INET6:
 443                match_value->value_size = sizeof(struct in6_addr);
 444                break;
 445        default:
 446                WARN_ON(1);
 447                return -EINVAL;
 448        }
 449
 450        match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
 451        if (!match_value->value)
 452                return -ENOMEM;
 453
 454        action_value->action = action;
 455        action_value->value_size = sizeof(u64);
 456        action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
 457        if (!action_value->value)
 458                return -ENOMEM;
 459
 460        return 0;
 461}
 462
 463static void
 464__mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
 465                                       struct mlxsw_sp_rif *rif,
 466                                       unsigned char *ha, void *dip)
 467{
 468        struct devlink_dpipe_value *value;
 469        u32 *rif_value;
 470        u8 *ha_value;
 471
 472        /* Set Match RIF index */
 473        value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
 474
 475        rif_value = value->value;
 476        *rif_value = mlxsw_sp_rif_index(rif);
 477        value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
 478        value->mapping_valid = true;
 479
 480        /* Set Match DIP */
 481        value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
 482        memcpy(value->value, dip, value->value_size);
 483
 484        /* Set Action DMAC */
 485        value = entry->action_values;
 486        ha_value = value->value;
 487        ether_addr_copy(ha_value, ha);
 488}
 489
 490static void
 491mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
 492                                      struct mlxsw_sp_neigh_entry *neigh_entry,
 493                                      struct mlxsw_sp_rif *rif)
 494{
 495        unsigned char *ha;
 496        u32 dip;
 497
 498        ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
 499        dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
 500        __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
 501}
 502
 503static void
 504mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
 505                                      struct mlxsw_sp_neigh_entry *neigh_entry,
 506                                      struct mlxsw_sp_rif *rif)
 507{
 508        struct in6_addr *dip;
 509        unsigned char *ha;
 510
 511        ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
 512        dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
 513
 514        __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
 515}
 516
 517static void
 518mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
 519                                     struct devlink_dpipe_entry *entry,
 520                                     struct mlxsw_sp_neigh_entry *neigh_entry,
 521                                     struct mlxsw_sp_rif *rif,
 522                                     int type)
 523{
 524        int err;
 525
 526        switch (type) {
 527        case AF_INET:
 528                mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
 529                break;
 530        case AF_INET6:
 531                mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
 532                break;
 533        default:
 534                WARN_ON(1);
 535                return;
 536        }
 537
 538        err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
 539                                         &entry->counter);
 540        if (!err)
 541                entry->counter_valid = true;
 542}
 543
 544static int
 545mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
 546                                      struct devlink_dpipe_entry *entry,
 547                                      bool counters_enabled,
 548                                      struct devlink_dpipe_dump_ctx *dump_ctx,
 549                                      int type)
 550{
 551        int rif_neigh_count = 0;
 552        int rif_neigh_skip = 0;
 553        int neigh_count = 0;
 554        int rif_count;
 555        int i, j;
 556        int err;
 557
 558        rtnl_lock();
 559        i = 0;
 560        rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
 561start_again:
 562        err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
 563        if (err)
 564                goto err_ctx_prepare;
 565        j = 0;
 566        rif_neigh_skip = rif_neigh_count;
 567        for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 568                struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
 569                struct mlxsw_sp_neigh_entry *neigh_entry;
 570
 571                if (!rif)
 572                        continue;
 573
 574                rif_neigh_count = 0;
 575                mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
 576                        int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
 577
 578                        if (neigh_type != type)
 579                                continue;
 580
 581                        if (neigh_type == AF_INET6 &&
 582                            mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
 583                                continue;
 584
 585                        if (rif_neigh_count < rif_neigh_skip)
 586                                goto skip;
 587
 588                        mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
 589                                                             neigh_entry, rif,
 590                                                             type);
 591                        entry->index = neigh_count;
 592                        err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
 593                        if (err) {
 594                                if (err == -EMSGSIZE) {
 595                                        if (!j)
 596                                                goto err_entry_append;
 597                                        else
 598                                                goto out;
 599                                }
 600                                goto err_entry_append;
 601                        }
 602                        neigh_count++;
 603                        j++;
 604skip:
 605                        rif_neigh_count++;
 606                }
 607                rif_neigh_skip = 0;
 608        }
 609out:
 610        devlink_dpipe_entry_ctx_close(dump_ctx);
 611        if (i != rif_count)
 612                goto start_again;
 613
 614        rtnl_unlock();
 615        return 0;
 616
 617err_ctx_prepare:
 618err_entry_append:
 619        rtnl_unlock();
 620        return err;
 621}
 622
 623static int
 624mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
 625                                       bool counters_enabled,
 626                                       struct devlink_dpipe_dump_ctx *dump_ctx,
 627                                       int type)
 628{
 629        struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
 630        struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
 631        struct devlink_dpipe_value action_value;
 632        struct devlink_dpipe_action action = {0};
 633        struct devlink_dpipe_entry entry = {0};
 634        int err;
 635
 636        memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
 637                           sizeof(matches[0]));
 638        memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
 639                                sizeof(match_values[0]));
 640        memset(&action_value, 0, sizeof(action_value));
 641
 642        mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
 643        err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
 644                                                      matches, &action_value,
 645                                                      &action, type);
 646        if (err)
 647                goto out;
 648
 649        err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
 650                                                    counters_enabled, dump_ctx,
 651                                                    type);
 652out:
 653        devlink_dpipe_entry_clear(&entry);
 654        return err;
 655}
 656
 657static int
 658mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
 659                                        struct devlink_dpipe_dump_ctx *dump_ctx)
 660{
 661        struct mlxsw_sp *mlxsw_sp = priv;
 662
 663        return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
 664                                                      counters_enabled,
 665                                                      dump_ctx, AF_INET);
 666}
 667
 668static void
 669mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
 670                                          bool enable, int type)
 671{
 672        int i;
 673
 674        rtnl_lock();
 675        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 676                struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
 677                struct mlxsw_sp_neigh_entry *neigh_entry;
 678
 679                if (!rif)
 680                        continue;
 681                mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
 682                        int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
 683
 684                        if (neigh_type != type)
 685                                continue;
 686
 687                        if (neigh_type == AF_INET6 &&
 688                            mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
 689                                continue;
 690
 691                        mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
 692                                                            neigh_entry,
 693                                                            enable);
 694                }
 695        }
 696        rtnl_unlock();
 697}
 698
 699static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
 700{
 701        struct mlxsw_sp *mlxsw_sp = priv;
 702
 703        mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
 704        return 0;
 705}
 706
 707static u64
 708mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
 709{
 710        u64 size = 0;
 711        int i;
 712
 713        rtnl_lock();
 714        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 715                struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
 716                struct mlxsw_sp_neigh_entry *neigh_entry;
 717
 718                if (!rif)
 719                        continue;
 720                mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
 721                        int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
 722
 723                        if (neigh_type != type)
 724                                continue;
 725
 726                        if (neigh_type == AF_INET6 &&
 727                            mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
 728                                continue;
 729
 730                        size++;
 731                }
 732        }
 733        rtnl_unlock();
 734
 735        return size;
 736}
 737
 738static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
 739{
 740        struct mlxsw_sp *mlxsw_sp = priv;
 741
 742        return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
 743}
 744
 745static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
 746        .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
 747        .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
 748        .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
 749        .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
 750        .size_get = mlxsw_sp_dpipe_table_host4_size_get,
 751};
 752
 753static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
 754{
 755        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 756
 757        return devlink_dpipe_table_register(devlink,
 758                                            MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
 759                                            &mlxsw_sp_host4_ops,
 760                                            mlxsw_sp, false);
 761}
 762
 763static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
 764{
 765        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 766
 767        devlink_dpipe_table_unregister(devlink,
 768                                       MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
 769}
 770
 771static int
 772mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
 773{
 774        return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
 775}
 776
 777static int
 778mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
 779                                        struct devlink_dpipe_dump_ctx *dump_ctx)
 780{
 781        struct mlxsw_sp *mlxsw_sp = priv;
 782
 783        return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
 784                                                      counters_enabled,
 785                                                      dump_ctx, AF_INET6);
 786}
 787
 788static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
 789{
 790        struct mlxsw_sp *mlxsw_sp = priv;
 791
 792        mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
 793        return 0;
 794}
 795
 796static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
 797{
 798        struct mlxsw_sp *mlxsw_sp = priv;
 799
 800        return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
 801}
 802
 803static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
 804        .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
 805        .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
 806        .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
 807        .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
 808        .size_get = mlxsw_sp_dpipe_table_host6_size_get,
 809};
 810
 811static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
 812{
 813        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 814
 815        return devlink_dpipe_table_register(devlink,
 816                                            MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
 817                                            &mlxsw_sp_host6_ops,
 818                                            mlxsw_sp, false);
 819}
 820
 821static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
 822{
 823        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 824
 825        devlink_dpipe_table_unregister(devlink,
 826                                       MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
 827}
 828
 829int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
 830{
 831        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 832        int err;
 833
 834        err = devlink_dpipe_headers_register(devlink,
 835                                             &mlxsw_sp_dpipe_headers);
 836        if (err)
 837                return err;
 838        err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
 839        if (err)
 840                goto err_erif_table_init;
 841
 842        err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
 843        if (err)
 844                goto err_host4_table_init;
 845
 846        err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
 847        if (err)
 848                goto err_host6_table_init;
 849        return 0;
 850
 851err_host6_table_init:
 852        mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
 853err_host4_table_init:
 854        mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
 855err_erif_table_init:
 856        devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
 857        return err;
 858}
 859
 860void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
 861{
 862        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 863
 864        mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
 865        mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
 866        mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
 867        devlink_dpipe_headers_unregister(devlink);
 868}
 869