0001
0002
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
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
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
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
0473 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP];
0474 memcpy(value->value, dip, value->value_size);
0475
0476
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 }