root/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_dpipe_table_erif_actions_dump
  2. mlxsw_sp_dpipe_table_erif_matches_dump
  3. mlxsw_sp_erif_match_action_prepare
  4. mlxsw_sp_erif_entry_prepare
  5. mlxsw_sp_erif_entry_get
  6. mlxsw_sp_dpipe_table_erif_entries_dump
  7. mlxsw_sp_dpipe_table_erif_counters_update
  8. mlxsw_sp_dpipe_table_erif_size_get
  9. mlxsw_sp_dpipe_erif_table_init
  10. mlxsw_sp_dpipe_erif_table_fini
  11. mlxsw_sp_dpipe_table_host_matches_dump
  12. mlxsw_sp_dpipe_table_host4_matches_dump
  13. mlxsw_sp_dpipe_table_host_actions_dump
  14. mlxsw_sp_dpipe_table_host_match_action_prepare
  15. mlxsw_sp_dpipe_table_host_entry_prepare
  16. __mlxsw_sp_dpipe_table_host_entry_fill
  17. mlxsw_sp_dpipe_table_host4_entry_fill
  18. mlxsw_sp_dpipe_table_host6_entry_fill
  19. mlxsw_sp_dpipe_table_host_entry_fill
  20. mlxsw_sp_dpipe_table_host_entries_get
  21. mlxsw_sp_dpipe_table_host_entries_dump
  22. mlxsw_sp_dpipe_table_host4_entries_dump
  23. mlxsw_sp_dpipe_table_host_counters_update
  24. mlxsw_sp_dpipe_table_host4_counters_update
  25. mlxsw_sp_dpipe_table_host_size_get
  26. mlxsw_sp_dpipe_table_host4_size_get
  27. mlxsw_sp_dpipe_host4_table_init
  28. mlxsw_sp_dpipe_host4_table_fini
  29. mlxsw_sp_dpipe_table_host6_matches_dump
  30. mlxsw_sp_dpipe_table_host6_entries_dump
  31. mlxsw_sp_dpipe_table_host6_counters_update
  32. mlxsw_sp_dpipe_table_host6_size_get
  33. mlxsw_sp_dpipe_host6_table_init
  34. mlxsw_sp_dpipe_host6_table_fini
  35. mlxsw_sp_dpipe_table_adj_matches_dump
  36. mlxsw_sp_dpipe_table_adj_actions_dump
  37. mlxsw_sp_dpipe_table_adj_size
  38. mlxsw_sp_dpipe_table_adj_match_action_prepare
  39. mlxsw_sp_dpipe_table_adj_entry_prepare
  40. __mlxsw_sp_dpipe_table_adj_entry_fill
  41. mlxsw_sp_dpipe_table_adj_entry_fill
  42. mlxsw_sp_dpipe_table_adj_entries_get
  43. mlxsw_sp_dpipe_table_adj_entries_dump
  44. mlxsw_sp_dpipe_table_adj_counters_update
  45. mlxsw_sp_dpipe_table_adj_size_get
  46. mlxsw_sp_dpipe_adj_table_init
  47. mlxsw_sp_dpipe_adj_table_fini
  48. mlxsw_sp_dpipe_init
  49. mlxsw_sp_dpipe_fini

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

/* [<][>][^][v][top][bottom][index][help] */