Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/mutex.h>
0006 #include <net/devlink.h>
0007 
0008 #include "spectrum.h"
0009 #include "spectrum_dpipe.h"
0010 #include "spectrum_router.h"
0011 
0012 enum mlxsw_sp_field_metadata_id {
0013     MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
0014     MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
0015     MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
0016     MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
0017     MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
0018     MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
0019 };
0020 
0021 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
0022     {
0023         .name = "erif_port",
0024         .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
0025         .bitwidth = 32,
0026         .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
0027     },
0028     {
0029         .name = "l3_forward",
0030         .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
0031         .bitwidth = 1,
0032     },
0033     {
0034         .name = "l3_drop",
0035         .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
0036         .bitwidth = 1,
0037     },
0038     {
0039         .name = "adj_index",
0040         .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
0041         .bitwidth = 32,
0042     },
0043     {
0044         .name = "adj_size",
0045         .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE,
0046         .bitwidth = 32,
0047     },
0048     {
0049         .name = "adj_hash_index",
0050         .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
0051         .bitwidth = 32,
0052     },
0053 };
0054 
0055 enum mlxsw_sp_dpipe_header_id {
0056     MLXSW_SP_DPIPE_HEADER_METADATA,
0057 };
0058 
0059 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
0060     .name = "mlxsw_meta",
0061     .id = MLXSW_SP_DPIPE_HEADER_METADATA,
0062     .fields = mlxsw_sp_dpipe_fields_metadata,
0063     .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
0064 };
0065 
0066 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
0067     &mlxsw_sp_dpipe_header_metadata,
0068     &devlink_dpipe_header_ethernet,
0069     &devlink_dpipe_header_ipv4,
0070     &devlink_dpipe_header_ipv6,
0071 };
0072 
0073 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
0074     .headers = mlxsw_dpipe_headers,
0075     .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
0076 };
0077 
0078 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
0079                           struct sk_buff *skb)
0080 {
0081     struct devlink_dpipe_action action = {0};
0082     int err;
0083 
0084     action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0085     action.header = &mlxsw_sp_dpipe_header_metadata;
0086     action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
0087 
0088     err = devlink_dpipe_action_put(skb, &action);
0089     if (err)
0090         return err;
0091 
0092     action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0093     action.header = &mlxsw_sp_dpipe_header_metadata;
0094     action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
0095 
0096     return devlink_dpipe_action_put(skb, &action);
0097 }
0098 
0099 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
0100                           struct sk_buff *skb)
0101 {
0102     struct devlink_dpipe_match match = {0};
0103 
0104     match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0105     match.header = &mlxsw_sp_dpipe_header_metadata;
0106     match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0107 
0108     return devlink_dpipe_match_put(skb, &match);
0109 }
0110 
0111 static void
0112 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
0113                    struct devlink_dpipe_action *action)
0114 {
0115     action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0116     action->header = &mlxsw_sp_dpipe_header_metadata;
0117     action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
0118 
0119     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0120     match->header = &mlxsw_sp_dpipe_header_metadata;
0121     match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0122 }
0123 
0124 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
0125                        struct devlink_dpipe_value *match_value,
0126                        struct devlink_dpipe_match *match,
0127                        struct devlink_dpipe_value *action_value,
0128                        struct devlink_dpipe_action *action)
0129 {
0130     entry->match_values = match_value;
0131     entry->match_values_count = 1;
0132 
0133     entry->action_values = action_value;
0134     entry->action_values_count = 1;
0135 
0136     match_value->match = match;
0137     match_value->value_size = sizeof(u32);
0138     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
0139     if (!match_value->value)
0140         return -ENOMEM;
0141 
0142     action_value->action = action;
0143     action_value->value_size = sizeof(u32);
0144     action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
0145     if (!action_value->value)
0146         goto err_action_alloc;
0147     return 0;
0148 
0149 err_action_alloc:
0150     kfree(match_value->value);
0151     return -ENOMEM;
0152 }
0153 
0154 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
0155                    struct devlink_dpipe_entry *entry,
0156                    struct mlxsw_sp_rif *rif,
0157                    bool counters_enabled)
0158 {
0159     u32 *action_value;
0160     u32 *rif_value;
0161     u64 cnt;
0162     int err;
0163 
0164     /* Set Match RIF index */
0165     rif_value = entry->match_values->value;
0166     *rif_value = mlxsw_sp_rif_index(rif);
0167     entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
0168     entry->match_values->mapping_valid = true;
0169 
0170     /* Set Action Forwarding */
0171     action_value = entry->action_values->value;
0172     *action_value = 1;
0173 
0174     entry->counter_valid = false;
0175     entry->counter = 0;
0176     entry->index = mlxsw_sp_rif_index(rif);
0177 
0178     if (!counters_enabled)
0179         return 0;
0180 
0181     err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
0182                          MLXSW_SP_RIF_COUNTER_EGRESS,
0183                          &cnt);
0184     if (!err) {
0185         entry->counter = cnt;
0186         entry->counter_valid = true;
0187     }
0188     return 0;
0189 }
0190 
0191 static int
0192 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
0193                        struct devlink_dpipe_dump_ctx *dump_ctx)
0194 {
0195     struct devlink_dpipe_value match_value, action_value;
0196     struct devlink_dpipe_action action = {0};
0197     struct devlink_dpipe_match match = {0};
0198     struct devlink_dpipe_entry entry = {0};
0199     struct mlxsw_sp *mlxsw_sp = priv;
0200     unsigned int rif_count;
0201     int i, j;
0202     int err;
0203 
0204     memset(&match_value, 0, sizeof(match_value));
0205     memset(&action_value, 0, sizeof(action_value));
0206 
0207     mlxsw_sp_erif_match_action_prepare(&match, &action);
0208     err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
0209                       &action_value, &action);
0210     if (err)
0211         return err;
0212 
0213     rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
0214     mutex_lock(&mlxsw_sp->router->lock);
0215     i = 0;
0216 start_again:
0217     err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
0218     if (err)
0219         goto err_ctx_prepare;
0220     j = 0;
0221     for (; i < rif_count; i++) {
0222         struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
0223 
0224         if (!rif || !mlxsw_sp_rif_dev(rif))
0225             continue;
0226         err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif,
0227                           counters_enabled);
0228         if (err)
0229             goto err_entry_get;
0230         err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
0231         if (err) {
0232             if (err == -EMSGSIZE) {
0233                 if (!j)
0234                     goto err_entry_append;
0235                 break;
0236             }
0237             goto err_entry_append;
0238         }
0239         j++;
0240     }
0241 
0242     devlink_dpipe_entry_ctx_close(dump_ctx);
0243     if (i != rif_count)
0244         goto start_again;
0245     mutex_unlock(&mlxsw_sp->router->lock);
0246 
0247     devlink_dpipe_entry_clear(&entry);
0248     return 0;
0249 err_entry_append:
0250 err_entry_get:
0251 err_ctx_prepare:
0252     mutex_unlock(&mlxsw_sp->router->lock);
0253     devlink_dpipe_entry_clear(&entry);
0254     return err;
0255 }
0256 
0257 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable)
0258 {
0259     struct mlxsw_sp *mlxsw_sp = priv;
0260     int i;
0261 
0262     mutex_lock(&mlxsw_sp->router->lock);
0263     for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
0264         struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
0265 
0266         if (!rif)
0267             continue;
0268         if (enable)
0269             mlxsw_sp_rif_counter_alloc(rif,
0270                            MLXSW_SP_RIF_COUNTER_EGRESS);
0271         else
0272             mlxsw_sp_rif_counter_free(rif,
0273                           MLXSW_SP_RIF_COUNTER_EGRESS);
0274     }
0275     mutex_unlock(&mlxsw_sp->router->lock);
0276     return 0;
0277 }
0278 
0279 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv)
0280 {
0281     struct mlxsw_sp *mlxsw_sp = priv;
0282 
0283     return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
0284 }
0285 
0286 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
0287     .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
0288     .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
0289     .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump,
0290     .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update,
0291     .size_get = mlxsw_sp_dpipe_table_erif_size_get,
0292 };
0293 
0294 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
0295 {
0296     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0297 
0298     return devl_dpipe_table_register(devlink,
0299                      MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
0300                      &mlxsw_sp_erif_ops,
0301                      mlxsw_sp, false);
0302 }
0303 
0304 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
0305 {
0306     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0307 
0308     devl_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
0309 }
0310 
0311 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type)
0312 {
0313     struct devlink_dpipe_match match = {0};
0314     int err;
0315 
0316     match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0317     match.header = &mlxsw_sp_dpipe_header_metadata;
0318     match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0319 
0320     err = devlink_dpipe_match_put(skb, &match);
0321     if (err)
0322         return err;
0323 
0324     switch (type) {
0325     case AF_INET:
0326         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0327         match.header = &devlink_dpipe_header_ipv4;
0328         match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
0329         break;
0330     case AF_INET6:
0331         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0332         match.header = &devlink_dpipe_header_ipv6;
0333         match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
0334         break;
0335     default:
0336         WARN_ON(1);
0337         return -EINVAL;
0338     }
0339 
0340     return devlink_dpipe_match_put(skb, &match);
0341 }
0342 
0343 static int
0344 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb)
0345 {
0346     return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET);
0347 }
0348 
0349 static int
0350 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb)
0351 {
0352     struct devlink_dpipe_action action = {0};
0353 
0354     action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0355     action.header = &devlink_dpipe_header_ethernet;
0356     action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
0357 
0358     return devlink_dpipe_action_put(skb, &action);
0359 }
0360 
0361 enum mlxsw_sp_dpipe_table_host_match {
0362     MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF,
0363     MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP,
0364     MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT,
0365 };
0366 
0367 static void
0368 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches,
0369                            struct devlink_dpipe_action *action,
0370                            int type)
0371 {
0372     struct devlink_dpipe_match *match;
0373 
0374     match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
0375     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0376     match->header = &mlxsw_sp_dpipe_header_metadata;
0377     match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0378 
0379     match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
0380     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0381     switch (type) {
0382     case AF_INET:
0383         match->header = &devlink_dpipe_header_ipv4;
0384         match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP;
0385         break;
0386     case AF_INET6:
0387         match->header = &devlink_dpipe_header_ipv6;
0388         match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP;
0389         break;
0390     default:
0391         WARN_ON(1);
0392         return;
0393     }
0394 
0395     action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0396     action->header = &devlink_dpipe_header_ethernet;
0397     action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
0398 }
0399 
0400 static int
0401 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry,
0402                     struct devlink_dpipe_value *match_values,
0403                     struct devlink_dpipe_match *matches,
0404                     struct devlink_dpipe_value *action_value,
0405                     struct devlink_dpipe_action *action,
0406                     int type)
0407 {
0408     struct devlink_dpipe_value *match_value;
0409     struct devlink_dpipe_match *match;
0410 
0411     entry->match_values = match_values;
0412     entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT;
0413 
0414     entry->action_values = action_value;
0415     entry->action_values_count = 1;
0416 
0417     match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
0418     match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
0419 
0420     match_value->match = match;
0421     match_value->value_size = sizeof(u32);
0422     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
0423     if (!match_value->value)
0424         return -ENOMEM;
0425 
0426     match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
0427     match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
0428 
0429     match_value->match = match;
0430     switch (type) {
0431     case AF_INET:
0432         match_value->value_size = sizeof(u32);
0433         break;
0434     case AF_INET6:
0435         match_value->value_size = sizeof(struct in6_addr);
0436         break;
0437     default:
0438         WARN_ON(1);
0439         return -EINVAL;
0440     }
0441 
0442     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
0443     if (!match_value->value)
0444         return -ENOMEM;
0445 
0446     action_value->action = action;
0447     action_value->value_size = sizeof(u64);
0448     action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
0449     if (!action_value->value)
0450         return -ENOMEM;
0451 
0452     return 0;
0453 }
0454 
0455 static void
0456 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry,
0457                        struct mlxsw_sp_rif *rif,
0458                        unsigned char *ha, void *dip)
0459 {
0460     struct devlink_dpipe_value *value;
0461     u32 *rif_value;
0462     u8 *ha_value;
0463 
0464     /* Set Match RIF index */
0465     value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF];
0466 
0467     rif_value = value->value;
0468     *rif_value = mlxsw_sp_rif_index(rif);
0469     value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
0470     value->mapping_valid = true;
0471 
0472     /* Set Match DIP */
0473     value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
0474     memcpy(value->value, dip, value->value_size);
0475 
0476     /* Set Action DMAC */
0477     value = entry->action_values;
0478     ha_value = value->value;
0479     ether_addr_copy(ha_value, ha);
0480 }
0481 
0482 static void
0483 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry,
0484                       struct mlxsw_sp_neigh_entry *neigh_entry,
0485                       struct mlxsw_sp_rif *rif)
0486 {
0487     unsigned char *ha;
0488     u32 dip;
0489 
0490     ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
0491     dip = mlxsw_sp_neigh4_entry_dip(neigh_entry);
0492     __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip);
0493 }
0494 
0495 static void
0496 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry,
0497                       struct mlxsw_sp_neigh_entry *neigh_entry,
0498                       struct mlxsw_sp_rif *rif)
0499 {
0500     struct in6_addr *dip;
0501     unsigned char *ha;
0502 
0503     ha = mlxsw_sp_neigh_entry_ha(neigh_entry);
0504     dip = mlxsw_sp_neigh6_entry_dip(neigh_entry);
0505 
0506     __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip);
0507 }
0508 
0509 static void
0510 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp,
0511                      struct devlink_dpipe_entry *entry,
0512                      struct mlxsw_sp_neigh_entry *neigh_entry,
0513                      struct mlxsw_sp_rif *rif,
0514                      int type)
0515 {
0516     int err;
0517 
0518     switch (type) {
0519     case AF_INET:
0520         mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif);
0521         break;
0522     case AF_INET6:
0523         mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif);
0524         break;
0525     default:
0526         WARN_ON(1);
0527         return;
0528     }
0529 
0530     err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry,
0531                      &entry->counter);
0532     if (!err)
0533         entry->counter_valid = true;
0534 }
0535 
0536 static int
0537 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp,
0538                       struct devlink_dpipe_entry *entry,
0539                       bool counters_enabled,
0540                       struct devlink_dpipe_dump_ctx *dump_ctx,
0541                       int type)
0542 {
0543     int rif_neigh_count = 0;
0544     int rif_neigh_skip = 0;
0545     int neigh_count = 0;
0546     int rif_count;
0547     int i, j;
0548     int err;
0549 
0550     mutex_lock(&mlxsw_sp->router->lock);
0551     i = 0;
0552     rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
0553 start_again:
0554     err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
0555     if (err)
0556         goto err_ctx_prepare;
0557     j = 0;
0558     rif_neigh_skip = rif_neigh_count;
0559     for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
0560         struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
0561         struct mlxsw_sp_neigh_entry *neigh_entry;
0562 
0563         if (!rif)
0564             continue;
0565 
0566         rif_neigh_count = 0;
0567         mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
0568             int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
0569 
0570             if (neigh_type != type)
0571                 continue;
0572 
0573             if (neigh_type == AF_INET6 &&
0574                 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
0575                 continue;
0576 
0577             if (rif_neigh_count < rif_neigh_skip)
0578                 goto skip;
0579 
0580             mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry,
0581                                  neigh_entry, rif,
0582                                  type);
0583             entry->index = neigh_count;
0584             err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
0585             if (err) {
0586                 if (err == -EMSGSIZE) {
0587                     if (!j)
0588                         goto err_entry_append;
0589                     else
0590                         goto out;
0591                 }
0592                 goto err_entry_append;
0593             }
0594             neigh_count++;
0595             j++;
0596 skip:
0597             rif_neigh_count++;
0598         }
0599         rif_neigh_skip = 0;
0600     }
0601 out:
0602     devlink_dpipe_entry_ctx_close(dump_ctx);
0603     if (i != rif_count)
0604         goto start_again;
0605 
0606     mutex_unlock(&mlxsw_sp->router->lock);
0607     return 0;
0608 
0609 err_ctx_prepare:
0610 err_entry_append:
0611     mutex_unlock(&mlxsw_sp->router->lock);
0612     return err;
0613 }
0614 
0615 static int
0616 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp,
0617                        bool counters_enabled,
0618                        struct devlink_dpipe_dump_ctx *dump_ctx,
0619                        int type)
0620 {
0621     struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
0622     struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT];
0623     struct devlink_dpipe_value action_value;
0624     struct devlink_dpipe_action action = {0};
0625     struct devlink_dpipe_entry entry = {0};
0626     int err;
0627 
0628     memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
0629                sizeof(matches[0]));
0630     memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
0631                 sizeof(match_values[0]));
0632     memset(&action_value, 0, sizeof(action_value));
0633 
0634     mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type);
0635     err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values,
0636                               matches, &action_value,
0637                               &action, type);
0638     if (err)
0639         goto out;
0640 
0641     err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry,
0642                             counters_enabled, dump_ctx,
0643                             type);
0644 out:
0645     devlink_dpipe_entry_clear(&entry);
0646     return err;
0647 }
0648 
0649 static int
0650 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled,
0651                     struct devlink_dpipe_dump_ctx *dump_ctx)
0652 {
0653     struct mlxsw_sp *mlxsw_sp = priv;
0654 
0655     return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
0656                               counters_enabled,
0657                               dump_ctx, AF_INET);
0658 }
0659 
0660 static void
0661 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp,
0662                       bool enable, int type)
0663 {
0664     int i;
0665 
0666     mutex_lock(&mlxsw_sp->router->lock);
0667     for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
0668         struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
0669         struct mlxsw_sp_neigh_entry *neigh_entry;
0670 
0671         if (!rif)
0672             continue;
0673         mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
0674             int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
0675 
0676             if (neigh_type != type)
0677                 continue;
0678 
0679             if (neigh_type == AF_INET6 &&
0680                 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
0681                 continue;
0682 
0683             mlxsw_sp_neigh_entry_counter_update(mlxsw_sp,
0684                                 neigh_entry,
0685                                 enable);
0686         }
0687     }
0688     mutex_unlock(&mlxsw_sp->router->lock);
0689 }
0690 
0691 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable)
0692 {
0693     struct mlxsw_sp *mlxsw_sp = priv;
0694 
0695     mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET);
0696     return 0;
0697 }
0698 
0699 static u64
0700 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type)
0701 {
0702     u64 size = 0;
0703     int i;
0704 
0705     mutex_lock(&mlxsw_sp->router->lock);
0706     for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
0707         struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
0708         struct mlxsw_sp_neigh_entry *neigh_entry;
0709 
0710         if (!rif)
0711             continue;
0712         mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) {
0713             int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry);
0714 
0715             if (neigh_type != type)
0716                 continue;
0717 
0718             if (neigh_type == AF_INET6 &&
0719                 mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
0720                 continue;
0721 
0722             size++;
0723         }
0724     }
0725     mutex_unlock(&mlxsw_sp->router->lock);
0726 
0727     return size;
0728 }
0729 
0730 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv)
0731 {
0732     struct mlxsw_sp *mlxsw_sp = priv;
0733 
0734     return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET);
0735 }
0736 
0737 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
0738     .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump,
0739     .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
0740     .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump,
0741     .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update,
0742     .size_get = mlxsw_sp_dpipe_table_host4_size_get,
0743 };
0744 
0745 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
0746 
0747 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp)
0748 {
0749     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0750     int err;
0751 
0752     err = devl_dpipe_table_register(devlink,
0753                     MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
0754                     &mlxsw_sp_host4_ops,
0755                     mlxsw_sp, false);
0756     if (err)
0757         return err;
0758 
0759     err = devl_dpipe_table_resource_set(devlink,
0760                         MLXSW_SP_DPIPE_TABLE_NAME_HOST4,
0761                         MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
0762                         MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4);
0763     if (err)
0764         goto err_resource_set;
0765 
0766     return 0;
0767 
0768 err_resource_set:
0769     devl_dpipe_table_unregister(devlink,
0770                     MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
0771     return err;
0772 }
0773 
0774 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp)
0775 {
0776     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0777 
0778     devl_dpipe_table_unregister(devlink,
0779                     MLXSW_SP_DPIPE_TABLE_NAME_HOST4);
0780 }
0781 
0782 static int
0783 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb)
0784 {
0785     return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6);
0786 }
0787 
0788 static int
0789 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled,
0790                     struct devlink_dpipe_dump_ctx *dump_ctx)
0791 {
0792     struct mlxsw_sp *mlxsw_sp = priv;
0793 
0794     return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp,
0795                               counters_enabled,
0796                               dump_ctx, AF_INET6);
0797 }
0798 
0799 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable)
0800 {
0801     struct mlxsw_sp *mlxsw_sp = priv;
0802 
0803     mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6);
0804     return 0;
0805 }
0806 
0807 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv)
0808 {
0809     struct mlxsw_sp *mlxsw_sp = priv;
0810 
0811     return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6);
0812 }
0813 
0814 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
0815     .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump,
0816     .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump,
0817     .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump,
0818     .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update,
0819     .size_get = mlxsw_sp_dpipe_table_host6_size_get,
0820 };
0821 
0822 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
0823 
0824 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp)
0825 {
0826     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0827     int err;
0828 
0829     err = devl_dpipe_table_register(devlink,
0830                     MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
0831                     &mlxsw_sp_host6_ops,
0832                     mlxsw_sp, false);
0833     if (err)
0834         return err;
0835 
0836     err = devl_dpipe_table_resource_set(devlink,
0837                         MLXSW_SP_DPIPE_TABLE_NAME_HOST6,
0838                         MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
0839                         MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6);
0840     if (err)
0841         goto err_resource_set;
0842 
0843     return 0;
0844 
0845 err_resource_set:
0846     devl_dpipe_table_unregister(devlink,
0847                     MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
0848     return err;
0849 }
0850 
0851 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
0852 {
0853     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0854 
0855     devl_dpipe_table_unregister(devlink,
0856                     MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
0857 }
0858 
0859 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
0860                          struct sk_buff *skb)
0861 {
0862     struct devlink_dpipe_match match = {0};
0863     int err;
0864 
0865     match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0866     match.header = &mlxsw_sp_dpipe_header_metadata;
0867     match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
0868 
0869     err = devlink_dpipe_match_put(skb, &match);
0870     if (err)
0871         return err;
0872 
0873     match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0874     match.header = &mlxsw_sp_dpipe_header_metadata;
0875     match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
0876 
0877     err = devlink_dpipe_match_put(skb, &match);
0878     if (err)
0879         return err;
0880 
0881     match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0882     match.header = &mlxsw_sp_dpipe_header_metadata;
0883     match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
0884 
0885     return devlink_dpipe_match_put(skb, &match);
0886 }
0887 
0888 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
0889                          struct sk_buff *skb)
0890 {
0891     struct devlink_dpipe_action action = {0};
0892     int err;
0893 
0894     action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0895     action.header = &devlink_dpipe_header_ethernet;
0896     action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
0897 
0898     err = devlink_dpipe_action_put(skb, &action);
0899     if (err)
0900         return err;
0901 
0902     action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0903     action.header = &mlxsw_sp_dpipe_header_metadata;
0904     action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0905 
0906     return devlink_dpipe_action_put(skb, &action);
0907 }
0908 
0909 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
0910 {
0911     struct mlxsw_sp_nexthop *nh;
0912     u64 size = 0;
0913 
0914     mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
0915         if (mlxsw_sp_nexthop_is_forward(nh) &&
0916             !mlxsw_sp_nexthop_group_has_ipip(nh))
0917             size++;
0918     return size;
0919 }
0920 
0921 enum mlxsw_sp_dpipe_table_adj_match {
0922     MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
0923     MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE,
0924     MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
0925     MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
0926 };
0927 
0928 enum mlxsw_sp_dpipe_table_adj_action {
0929     MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
0930     MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
0931     MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
0932 };
0933 
0934 static void
0935 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
0936                           struct devlink_dpipe_action *actions)
0937 {
0938     struct devlink_dpipe_action *action;
0939     struct devlink_dpipe_match *match;
0940 
0941     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
0942     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0943     match->header = &mlxsw_sp_dpipe_header_metadata;
0944     match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
0945 
0946     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
0947     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0948     match->header = &mlxsw_sp_dpipe_header_metadata;
0949     match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE;
0950 
0951     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
0952     match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
0953     match->header = &mlxsw_sp_dpipe_header_metadata;
0954     match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
0955 
0956     action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
0957     action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0958     action->header = &devlink_dpipe_header_ethernet;
0959     action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
0960 
0961     action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
0962     action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
0963     action->header = &mlxsw_sp_dpipe_header_metadata;
0964     action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
0965 }
0966 
0967 static int
0968 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
0969                        struct devlink_dpipe_value *match_values,
0970                        struct devlink_dpipe_match *matches,
0971                        struct devlink_dpipe_value *action_values,
0972                        struct devlink_dpipe_action *actions)
0973 {   struct devlink_dpipe_value *action_value;
0974     struct devlink_dpipe_value *match_value;
0975     struct devlink_dpipe_action *action;
0976     struct devlink_dpipe_match *match;
0977 
0978     entry->match_values = match_values;
0979     entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
0980 
0981     entry->action_values = action_values;
0982     entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
0983 
0984     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
0985     match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
0986 
0987     match_value->match = match;
0988     match_value->value_size = sizeof(u32);
0989     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
0990     if (!match_value->value)
0991         return -ENOMEM;
0992 
0993     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
0994     match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
0995 
0996     match_value->match = match;
0997     match_value->value_size = sizeof(u32);
0998     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
0999     if (!match_value->value)
1000         return -ENOMEM;
1001 
1002     match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1003     match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1004 
1005     match_value->match = match;
1006     match_value->value_size = sizeof(u32);
1007     match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
1008     if (!match_value->value)
1009         return -ENOMEM;
1010 
1011     action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1012     action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1013 
1014     action_value->action = action;
1015     action_value->value_size = sizeof(u64);
1016     action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1017     if (!action_value->value)
1018         return -ENOMEM;
1019 
1020     action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1021     action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1022 
1023     action_value->action = action;
1024     action_value->value_size = sizeof(u32);
1025     action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
1026     if (!action_value->value)
1027         return -ENOMEM;
1028 
1029     return 0;
1030 }
1031 
1032 static void
1033 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
1034                       u32 adj_index, u32 adj_size,
1035                       u32 adj_hash_index, unsigned char *ha,
1036                       struct mlxsw_sp_rif *rif)
1037 {
1038     struct devlink_dpipe_value *value;
1039     u32 *p_rif_value;
1040     u32 *p_index;
1041 
1042     value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
1043     p_index = value->value;
1044     *p_index = adj_index;
1045 
1046     value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE];
1047     p_index = value->value;
1048     *p_index = adj_size;
1049 
1050     value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
1051     p_index = value->value;
1052     *p_index = adj_hash_index;
1053 
1054     value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
1055     ether_addr_copy(value->value, ha);
1056 
1057     value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
1058     p_rif_value = value->value;
1059     *p_rif_value = mlxsw_sp_rif_index(rif);
1060     value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
1061     value->mapping_valid = true;
1062 }
1063 
1064 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
1065                         struct mlxsw_sp_nexthop *nh,
1066                         struct devlink_dpipe_entry *entry)
1067 {
1068     struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
1069     unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
1070     u32 adj_hash_index = 0;
1071     u32 adj_index = 0;
1072     u32 adj_size = 0;
1073     int err;
1074 
1075     mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index);
1076     __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size,
1077                           adj_hash_index, ha, rif);
1078     err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
1079     if (!err)
1080         entry->counter_valid = true;
1081 }
1082 
1083 static int
1084 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
1085                      struct devlink_dpipe_entry *entry,
1086                      bool counters_enabled,
1087                      struct devlink_dpipe_dump_ctx *dump_ctx)
1088 {
1089     struct mlxsw_sp_nexthop *nh;
1090     int entry_index = 0;
1091     int nh_count_max;
1092     int nh_count = 0;
1093     int nh_skip;
1094     int j;
1095     int err;
1096 
1097     mutex_lock(&mlxsw_sp->router->lock);
1098     nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1099 start_again:
1100     err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
1101     if (err)
1102         goto err_ctx_prepare;
1103     j = 0;
1104     nh_skip = nh_count;
1105     nh_count = 0;
1106     mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1107         if (!mlxsw_sp_nexthop_is_forward(nh) ||
1108             mlxsw_sp_nexthop_group_has_ipip(nh))
1109             continue;
1110 
1111         if (nh_count < nh_skip)
1112             goto skip;
1113 
1114         mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
1115         entry->index = entry_index;
1116         err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
1117         if (err) {
1118             if (err == -EMSGSIZE) {
1119                 if (!j)
1120                     goto err_entry_append;
1121                 break;
1122             }
1123             goto err_entry_append;
1124         }
1125         entry_index++;
1126         j++;
1127 skip:
1128         nh_count++;
1129     }
1130 
1131     devlink_dpipe_entry_ctx_close(dump_ctx);
1132     if (nh_count != nh_count_max)
1133         goto start_again;
1134     mutex_unlock(&mlxsw_sp->router->lock);
1135 
1136     return 0;
1137 
1138 err_ctx_prepare:
1139 err_entry_append:
1140     mutex_unlock(&mlxsw_sp->router->lock);
1141     return err;
1142 }
1143 
1144 static int
1145 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
1146                       struct devlink_dpipe_dump_ctx *dump_ctx)
1147 {
1148     struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1149     struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1150     struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
1151     struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
1152     struct devlink_dpipe_entry entry = {0};
1153     struct mlxsw_sp *mlxsw_sp = priv;
1154     int err;
1155 
1156     memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1157                sizeof(matches[0]));
1158     memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
1159                 sizeof(match_values[0]));
1160     memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1161                sizeof(actions[0]));
1162     memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
1163                  sizeof(action_values[0]));
1164 
1165     mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
1166     err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
1167                              match_values, matches,
1168                              action_values, actions);
1169     if (err)
1170         goto out;
1171 
1172     err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
1173                            counters_enabled, dump_ctx);
1174 out:
1175     devlink_dpipe_entry_clear(&entry);
1176     return err;
1177 }
1178 
1179 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
1180 {
1181     char ratr_pl[MLXSW_REG_RATR_LEN];
1182     struct mlxsw_sp *mlxsw_sp = priv;
1183     struct mlxsw_sp_nexthop *nh;
1184     u32 adj_hash_index = 0;
1185     u32 adj_index = 0;
1186     u32 adj_size = 0;
1187 
1188     mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
1189         if (!mlxsw_sp_nexthop_is_forward(nh) ||
1190             mlxsw_sp_nexthop_group_has_ipip(nh))
1191             continue;
1192 
1193         mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size,
1194                      &adj_hash_index);
1195         if (enable)
1196             mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
1197         else
1198             mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
1199         mlxsw_sp_nexthop_eth_update(mlxsw_sp,
1200                         adj_index + adj_hash_index, nh,
1201                         true, ratr_pl);
1202     }
1203     return 0;
1204 }
1205 
1206 static u64
1207 mlxsw_sp_dpipe_table_adj_size_get(void *priv)
1208 {
1209     struct mlxsw_sp *mlxsw_sp = priv;
1210     u64 size;
1211 
1212     mutex_lock(&mlxsw_sp->router->lock);
1213     size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
1214     mutex_unlock(&mlxsw_sp->router->lock);
1215 
1216     return size;
1217 }
1218 
1219 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
1220     .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
1221     .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
1222     .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
1223     .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
1224     .size_get = mlxsw_sp_dpipe_table_adj_size_get,
1225 };
1226 
1227 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
1228 
1229 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
1230 {
1231     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1232     int err;
1233 
1234     err = devl_dpipe_table_register(devlink,
1235                     MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1236                     &mlxsw_sp_dpipe_table_adj_ops,
1237                     mlxsw_sp, false);
1238     if (err)
1239         return err;
1240 
1241     err = devl_dpipe_table_resource_set(devlink,
1242                         MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
1243                         MLXSW_SP_RESOURCE_KVD_LINEAR,
1244                         MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ);
1245     if (err)
1246         goto err_resource_set;
1247 
1248     return 0;
1249 
1250 err_resource_set:
1251     devl_dpipe_table_unregister(devlink,
1252                     MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1253     return err;
1254 }
1255 
1256 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
1257 {
1258     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1259 
1260     devl_dpipe_table_unregister(devlink,
1261                     MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
1262 }
1263 
1264 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
1265 {
1266     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1267     int err;
1268 
1269     devl_dpipe_headers_register(devlink, &mlxsw_sp_dpipe_headers);
1270 
1271     err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
1272     if (err)
1273         goto err_erif_table_init;
1274 
1275     err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp);
1276     if (err)
1277         goto err_host4_table_init;
1278 
1279     err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
1280     if (err)
1281         goto err_host6_table_init;
1282 
1283     err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
1284     if (err)
1285         goto err_adj_table_init;
1286 
1287     return 0;
1288 err_adj_table_init:
1289     mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1290 err_host6_table_init:
1291     mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1292 err_host4_table_init:
1293     mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1294 err_erif_table_init:
1295     devl_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
1296     return err;
1297 }
1298 
1299 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
1300 {
1301     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1302 
1303     mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
1304     mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
1305     mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
1306     mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
1307     devl_dpipe_headers_unregister(devlink);
1308 }