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