1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c 3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <linux/kernel.h> 36 #include <net/devlink.h> 37 38 #include "spectrum.h" 39 #include "spectrum_dpipe.h" 40 #include "spectrum_router.h" 41 42 enum mlxsw_sp_field_metadata_id { 43 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 44 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 45 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 46 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX, 47 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE, 48 MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX, 49 }; 50 51 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = { 52 { 53 .name = "erif_port", 54 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 55 .bitwidth = 32, 56 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX, 57 }, 58 { 59 .name = "l3_forward", 60 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 61 .bitwidth = 1, 62 }, 63 { 64 .name = "l3_drop", 65 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 66 .bitwidth = 1, 67 }, 68 { 69 .name = "adj_index", 70 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX, 71 .bitwidth = 32, 72 }, 73 { 74 .name = "adj_size", 75 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE, 76 .bitwidth = 32, 77 }, 78 { 79 .name = "adj_hash_index", 80 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX, 81 .bitwidth = 32, 82 }, 83 }; 84 85 enum mlxsw_sp_dpipe_header_id { 86 MLXSW_SP_DPIPE_HEADER_METADATA, 87 }; 88 89 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = { 90 .name = "mlxsw_meta", 91 .id = MLXSW_SP_DPIPE_HEADER_METADATA, 92 .fields = mlxsw_sp_dpipe_fields_metadata, 93 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata), 94 }; 95 96 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = { 97 &mlxsw_sp_dpipe_header_metadata, 98 &devlink_dpipe_header_ethernet, 99 &devlink_dpipe_header_ipv4, 100 &devlink_dpipe_header_ipv6, 101 }; 102 103 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = { 104 .headers = mlxsw_dpipe_headers, 105 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers), 106 }; 107 108 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv, 109 struct sk_buff *skb) 110 { 111 struct devlink_dpipe_action action = {0}; 112 int err; 113 114 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 115 action.header = &mlxsw_sp_dpipe_header_metadata; 116 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 117 118 err = devlink_dpipe_action_put(skb, &action); 119 if (err) 120 return err; 121 122 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 123 action.header = &mlxsw_sp_dpipe_header_metadata; 124 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP; 125 126 return devlink_dpipe_action_put(skb, &action); 127 } 128 129 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv, 130 struct sk_buff *skb) 131 { 132 struct devlink_dpipe_match match = {0}; 133 134 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 135 match.header = &mlxsw_sp_dpipe_header_metadata; 136 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 137 138 return devlink_dpipe_match_put(skb, &match); 139 } 140 141 static void 142 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match, 143 struct devlink_dpipe_action *action) 144 { 145 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 146 action->header = &mlxsw_sp_dpipe_header_metadata; 147 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 148 149 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 150 match->header = &mlxsw_sp_dpipe_header_metadata; 151 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 152 } 153 154 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry, 155 struct devlink_dpipe_value *match_value, 156 struct devlink_dpipe_match *match, 157 struct devlink_dpipe_value *action_value, 158 struct devlink_dpipe_action *action) 159 { 160 entry->match_values = match_value; 161 entry->match_values_count = 1; 162 163 entry->action_values = action_value; 164 entry->action_values_count = 1; 165 166 match_value->match = match; 167 match_value->value_size = sizeof(u32); 168 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 169 if (!match_value->value) 170 return -ENOMEM; 171 172 action_value->action = action; 173 action_value->value_size = sizeof(u32); 174 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 175 if (!action_value->value) 176 goto err_action_alloc; 177 return 0; 178 179 err_action_alloc: 180 kfree(match_value->value); 181 return -ENOMEM; 182 } 183 184 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp, 185 struct devlink_dpipe_entry *entry, 186 struct mlxsw_sp_rif *rif, 187 bool counters_enabled) 188 { 189 u32 *action_value; 190 u32 *rif_value; 191 u64 cnt; 192 int err; 193 194 /* Set Match RIF index */ 195 rif_value = entry->match_values->value; 196 *rif_value = mlxsw_sp_rif_index(rif); 197 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 198 entry->match_values->mapping_valid = true; 199 200 /* Set Action Forwarding */ 201 action_value = entry->action_values->value; 202 *action_value = 1; 203 204 entry->counter_valid = false; 205 entry->counter = 0; 206 entry->index = mlxsw_sp_rif_index(rif); 207 208 if (!counters_enabled) 209 return 0; 210 211 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif, 212 MLXSW_SP_RIF_COUNTER_EGRESS, 213 &cnt); 214 if (!err) { 215 entry->counter = cnt; 216 entry->counter_valid = true; 217 } 218 return 0; 219 } 220 221 static int 222 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, 223 struct devlink_dpipe_dump_ctx *dump_ctx) 224 { 225 struct devlink_dpipe_value match_value, action_value; 226 struct devlink_dpipe_action action = {0}; 227 struct devlink_dpipe_match match = {0}; 228 struct devlink_dpipe_entry entry = {0}; 229 struct mlxsw_sp *mlxsw_sp = priv; 230 unsigned int rif_count; 231 int i, j; 232 int err; 233 234 memset(&match_value, 0, sizeof(match_value)); 235 memset(&action_value, 0, sizeof(action_value)); 236 237 mlxsw_sp_erif_match_action_prepare(&match, &action); 238 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, 239 &action_value, &action); 240 if (err) 241 return err; 242 243 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 244 rtnl_lock(); 245 i = 0; 246 start_again: 247 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 248 if (err) 249 return err; 250 j = 0; 251 for (; i < rif_count; i++) { 252 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 253 254 if (!rif) 255 continue; 256 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, 257 counters_enabled); 258 if (err) 259 goto err_entry_get; 260 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry); 261 if (err) { 262 if (err == -EMSGSIZE) { 263 if (!j) 264 goto err_entry_append; 265 break; 266 } 267 goto err_entry_append; 268 } 269 j++; 270 } 271 272 devlink_dpipe_entry_ctx_close(dump_ctx); 273 if (i != rif_count) 274 goto start_again; 275 rtnl_unlock(); 276 277 devlink_dpipe_entry_clear(&entry); 278 return 0; 279 err_entry_append: 280 err_entry_get: 281 rtnl_unlock(); 282 devlink_dpipe_entry_clear(&entry); 283 return err; 284 } 285 286 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable) 287 { 288 struct mlxsw_sp *mlxsw_sp = priv; 289 int i; 290 291 rtnl_lock(); 292 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 293 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 294 295 if (!rif) 296 continue; 297 if (enable) 298 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, 299 MLXSW_SP_RIF_COUNTER_EGRESS); 300 else 301 mlxsw_sp_rif_counter_free(mlxsw_sp, rif, 302 MLXSW_SP_RIF_COUNTER_EGRESS); 303 } 304 rtnl_unlock(); 305 return 0; 306 } 307 308 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv) 309 { 310 struct mlxsw_sp *mlxsw_sp = priv; 311 312 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 313 } 314 315 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = { 316 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump, 317 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump, 318 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump, 319 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update, 320 .size_get = mlxsw_sp_dpipe_table_erif_size_get, 321 }; 322 323 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp) 324 { 325 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 326 327 return devlink_dpipe_table_register(devlink, 328 MLXSW_SP_DPIPE_TABLE_NAME_ERIF, 329 &mlxsw_sp_erif_ops, 330 mlxsw_sp, false); 331 } 332 333 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp) 334 { 335 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 336 337 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF); 338 } 339 340 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type) 341 { 342 struct devlink_dpipe_match match = {0}; 343 int err; 344 345 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 346 match.header = &mlxsw_sp_dpipe_header_metadata; 347 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 348 349 err = devlink_dpipe_match_put(skb, &match); 350 if (err) 351 return err; 352 353 switch (type) { 354 case AF_INET: 355 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 356 match.header = &devlink_dpipe_header_ipv4; 357 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 358 break; 359 case AF_INET6: 360 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 361 match.header = &devlink_dpipe_header_ipv6; 362 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 363 break; 364 default: 365 WARN_ON(1); 366 return -EINVAL; 367 } 368 369 return devlink_dpipe_match_put(skb, &match); 370 } 371 372 static int 373 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb) 374 { 375 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET); 376 } 377 378 static int 379 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb) 380 { 381 struct devlink_dpipe_action action = {0}; 382 383 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 384 action.header = &devlink_dpipe_header_ethernet; 385 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 386 387 return devlink_dpipe_action_put(skb, &action); 388 } 389 390 enum mlxsw_sp_dpipe_table_host_match { 391 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF, 392 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP, 393 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT, 394 }; 395 396 static void 397 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches, 398 struct devlink_dpipe_action *action, 399 int type) 400 { 401 struct devlink_dpipe_match *match; 402 403 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 404 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 405 match->header = &mlxsw_sp_dpipe_header_metadata; 406 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 407 408 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 409 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 410 switch (type) { 411 case AF_INET: 412 match->header = &devlink_dpipe_header_ipv4; 413 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 414 break; 415 case AF_INET6: 416 match->header = &devlink_dpipe_header_ipv6; 417 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 418 break; 419 default: 420 WARN_ON(1); 421 return; 422 } 423 424 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 425 action->header = &devlink_dpipe_header_ethernet; 426 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 427 } 428 429 static int 430 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry, 431 struct devlink_dpipe_value *match_values, 432 struct devlink_dpipe_match *matches, 433 struct devlink_dpipe_value *action_value, 434 struct devlink_dpipe_action *action, 435 int type) 436 { 437 struct devlink_dpipe_value *match_value; 438 struct devlink_dpipe_match *match; 439 440 entry->match_values = match_values; 441 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT; 442 443 entry->action_values = action_value; 444 entry->action_values_count = 1; 445 446 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 447 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 448 449 match_value->match = match; 450 match_value->value_size = sizeof(u32); 451 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 452 if (!match_value->value) 453 return -ENOMEM; 454 455 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 456 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 457 458 match_value->match = match; 459 switch (type) { 460 case AF_INET: 461 match_value->value_size = sizeof(u32); 462 break; 463 case AF_INET6: 464 match_value->value_size = sizeof(struct in6_addr); 465 break; 466 default: 467 WARN_ON(1); 468 return -EINVAL; 469 } 470 471 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 472 if (!match_value->value) 473 return -ENOMEM; 474 475 action_value->action = action; 476 action_value->value_size = sizeof(u64); 477 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 478 if (!action_value->value) 479 return -ENOMEM; 480 481 return 0; 482 } 483 484 static void 485 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry, 486 struct mlxsw_sp_rif *rif, 487 unsigned char *ha, void *dip) 488 { 489 struct devlink_dpipe_value *value; 490 u32 *rif_value; 491 u8 *ha_value; 492 493 /* Set Match RIF index */ 494 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 495 496 rif_value = value->value; 497 *rif_value = mlxsw_sp_rif_index(rif); 498 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 499 value->mapping_valid = true; 500 501 /* Set Match DIP */ 502 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 503 memcpy(value->value, dip, value->value_size); 504 505 /* Set Action DMAC */ 506 value = entry->action_values; 507 ha_value = value->value; 508 ether_addr_copy(ha_value, ha); 509 } 510 511 static void 512 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry, 513 struct mlxsw_sp_neigh_entry *neigh_entry, 514 struct mlxsw_sp_rif *rif) 515 { 516 unsigned char *ha; 517 u32 dip; 518 519 ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 520 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry); 521 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip); 522 } 523 524 static void 525 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry, 526 struct mlxsw_sp_neigh_entry *neigh_entry, 527 struct mlxsw_sp_rif *rif) 528 { 529 struct in6_addr *dip; 530 unsigned char *ha; 531 532 ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 533 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry); 534 535 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip); 536 } 537 538 static void 539 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp, 540 struct devlink_dpipe_entry *entry, 541 struct mlxsw_sp_neigh_entry *neigh_entry, 542 struct mlxsw_sp_rif *rif, 543 int type) 544 { 545 int err; 546 547 switch (type) { 548 case AF_INET: 549 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif); 550 break; 551 case AF_INET6: 552 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif); 553 break; 554 default: 555 WARN_ON(1); 556 return; 557 } 558 559 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry, 560 &entry->counter); 561 if (!err) 562 entry->counter_valid = true; 563 } 564 565 static int 566 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp, 567 struct devlink_dpipe_entry *entry, 568 bool counters_enabled, 569 struct devlink_dpipe_dump_ctx *dump_ctx, 570 int type) 571 { 572 int rif_neigh_count = 0; 573 int rif_neigh_skip = 0; 574 int neigh_count = 0; 575 int rif_count; 576 int i, j; 577 int err; 578 579 rtnl_lock(); 580 i = 0; 581 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 582 start_again: 583 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 584 if (err) 585 goto err_ctx_prepare; 586 j = 0; 587 rif_neigh_skip = rif_neigh_count; 588 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 589 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 590 struct mlxsw_sp_neigh_entry *neigh_entry; 591 592 if (!rif) 593 continue; 594 595 rif_neigh_count = 0; 596 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 597 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 598 599 if (neigh_type != type) 600 continue; 601 602 if (neigh_type == AF_INET6 && 603 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 604 continue; 605 606 if (rif_neigh_count < rif_neigh_skip) 607 goto skip; 608 609 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry, 610 neigh_entry, rif, 611 type); 612 entry->index = neigh_count; 613 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 614 if (err) { 615 if (err == -EMSGSIZE) { 616 if (!j) 617 goto err_entry_append; 618 else 619 goto out; 620 } 621 goto err_entry_append; 622 } 623 neigh_count++; 624 j++; 625 skip: 626 rif_neigh_count++; 627 } 628 rif_neigh_skip = 0; 629 } 630 out: 631 devlink_dpipe_entry_ctx_close(dump_ctx); 632 if (i != rif_count) 633 goto start_again; 634 635 rtnl_unlock(); 636 return 0; 637 638 err_ctx_prepare: 639 err_entry_append: 640 rtnl_unlock(); 641 return err; 642 } 643 644 static int 645 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp, 646 bool counters_enabled, 647 struct devlink_dpipe_dump_ctx *dump_ctx, 648 int type) 649 { 650 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 651 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 652 struct devlink_dpipe_value action_value; 653 struct devlink_dpipe_action action = {0}; 654 struct devlink_dpipe_entry entry = {0}; 655 int err; 656 657 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 658 sizeof(matches[0])); 659 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 660 sizeof(match_values[0])); 661 memset(&action_value, 0, sizeof(action_value)); 662 663 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type); 664 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values, 665 matches, &action_value, 666 &action, type); 667 if (err) 668 goto out; 669 670 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry, 671 counters_enabled, dump_ctx, 672 type); 673 out: 674 devlink_dpipe_entry_clear(&entry); 675 return err; 676 } 677 678 static int 679 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled, 680 struct devlink_dpipe_dump_ctx *dump_ctx) 681 { 682 struct mlxsw_sp *mlxsw_sp = priv; 683 684 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 685 counters_enabled, 686 dump_ctx, AF_INET); 687 } 688 689 static void 690 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp, 691 bool enable, int type) 692 { 693 int i; 694 695 rtnl_lock(); 696 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 697 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 698 struct mlxsw_sp_neigh_entry *neigh_entry; 699 700 if (!rif) 701 continue; 702 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 703 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 704 705 if (neigh_type != type) 706 continue; 707 708 if (neigh_type == AF_INET6 && 709 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 710 continue; 711 712 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp, 713 neigh_entry, 714 enable); 715 } 716 } 717 rtnl_unlock(); 718 } 719 720 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable) 721 { 722 struct mlxsw_sp *mlxsw_sp = priv; 723 724 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET); 725 return 0; 726 } 727 728 static u64 729 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type) 730 { 731 u64 size = 0; 732 int i; 733 734 rtnl_lock(); 735 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 736 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 737 struct mlxsw_sp_neigh_entry *neigh_entry; 738 739 if (!rif) 740 continue; 741 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 742 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 743 744 if (neigh_type != type) 745 continue; 746 747 if (neigh_type == AF_INET6 && 748 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 749 continue; 750 751 size++; 752 } 753 } 754 rtnl_unlock(); 755 756 return size; 757 } 758 759 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv) 760 { 761 struct mlxsw_sp *mlxsw_sp = priv; 762 763 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET); 764 } 765 766 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = { 767 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump, 768 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 769 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump, 770 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update, 771 .size_get = mlxsw_sp_dpipe_table_host4_size_get, 772 }; 773 774 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1 775 776 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp) 777 { 778 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 779 int err; 780 781 err = devlink_dpipe_table_register(devlink, 782 MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 783 &mlxsw_sp_host4_ops, 784 mlxsw_sp, false); 785 if (err) 786 return err; 787 788 err = devlink_dpipe_table_resource_set(devlink, 789 MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 790 MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 791 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4); 792 if (err) 793 goto err_resource_set; 794 795 return 0; 796 797 err_resource_set: 798 devlink_dpipe_table_unregister(devlink, 799 MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 800 return err; 801 } 802 803 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp) 804 { 805 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 806 807 devlink_dpipe_table_unregister(devlink, 808 MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 809 } 810 811 static int 812 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb) 813 { 814 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6); 815 } 816 817 static int 818 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled, 819 struct devlink_dpipe_dump_ctx *dump_ctx) 820 { 821 struct mlxsw_sp *mlxsw_sp = priv; 822 823 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 824 counters_enabled, 825 dump_ctx, AF_INET6); 826 } 827 828 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable) 829 { 830 struct mlxsw_sp *mlxsw_sp = priv; 831 832 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6); 833 return 0; 834 } 835 836 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv) 837 { 838 struct mlxsw_sp *mlxsw_sp = priv; 839 840 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6); 841 } 842 843 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = { 844 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump, 845 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 846 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump, 847 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update, 848 .size_get = mlxsw_sp_dpipe_table_host6_size_get, 849 }; 850 851 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2 852 853 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp) 854 { 855 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 856 int err; 857 858 err = devlink_dpipe_table_register(devlink, 859 MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 860 &mlxsw_sp_host6_ops, 861 mlxsw_sp, false); 862 if (err) 863 return err; 864 865 err = devlink_dpipe_table_resource_set(devlink, 866 MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 867 MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 868 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6); 869 if (err) 870 goto err_resource_set; 871 872 return 0; 873 874 err_resource_set: 875 devlink_dpipe_table_unregister(devlink, 876 MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 877 return err; 878 } 879 880 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp) 881 { 882 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 883 884 devlink_dpipe_table_unregister(devlink, 885 MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 886 } 887 888 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv, 889 struct sk_buff *skb) 890 { 891 struct devlink_dpipe_match match = {0}; 892 int err; 893 894 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 895 match.header = &mlxsw_sp_dpipe_header_metadata; 896 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 897 898 err = devlink_dpipe_match_put(skb, &match); 899 if (err) 900 return err; 901 902 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 903 match.header = &mlxsw_sp_dpipe_header_metadata; 904 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 905 906 err = devlink_dpipe_match_put(skb, &match); 907 if (err) 908 return err; 909 910 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 911 match.header = &mlxsw_sp_dpipe_header_metadata; 912 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 913 914 return devlink_dpipe_match_put(skb, &match); 915 } 916 917 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv, 918 struct sk_buff *skb) 919 { 920 struct devlink_dpipe_action action = {0}; 921 int err; 922 923 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 924 action.header = &devlink_dpipe_header_ethernet; 925 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 926 927 err = devlink_dpipe_action_put(skb, &action); 928 if (err) 929 return err; 930 931 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 932 action.header = &mlxsw_sp_dpipe_header_metadata; 933 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 934 935 return devlink_dpipe_action_put(skb, &action); 936 } 937 938 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp) 939 { 940 struct mlxsw_sp_nexthop *nh; 941 u64 size = 0; 942 943 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) 944 if (mlxsw_sp_nexthop_offload(nh) && 945 !mlxsw_sp_nexthop_group_has_ipip(nh)) 946 size++; 947 return size; 948 } 949 950 enum mlxsw_sp_dpipe_table_adj_match { 951 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX, 952 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE, 953 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX, 954 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT, 955 }; 956 957 enum mlxsw_sp_dpipe_table_adj_action { 958 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC, 959 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT, 960 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT, 961 }; 962 963 static void 964 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches, 965 struct devlink_dpipe_action *actions) 966 { 967 struct devlink_dpipe_action *action; 968 struct devlink_dpipe_match *match; 969 970 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 971 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 972 match->header = &mlxsw_sp_dpipe_header_metadata; 973 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 974 975 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 976 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 977 match->header = &mlxsw_sp_dpipe_header_metadata; 978 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 979 980 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 981 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 982 match->header = &mlxsw_sp_dpipe_header_metadata; 983 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 984 985 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 986 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 987 action->header = &devlink_dpipe_header_ethernet; 988 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 989 990 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 991 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 992 action->header = &mlxsw_sp_dpipe_header_metadata; 993 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 994 } 995 996 static int 997 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry, 998 struct devlink_dpipe_value *match_values, 999 struct devlink_dpipe_match *matches, 1000 struct devlink_dpipe_value *action_values, 1001 struct devlink_dpipe_action *actions) 1002 { struct devlink_dpipe_value *action_value; 1003 struct devlink_dpipe_value *match_value; 1004 struct devlink_dpipe_action *action; 1005 struct devlink_dpipe_match *match; 1006 1007 entry->match_values = match_values; 1008 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT; 1009 1010 entry->action_values = action_values; 1011 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT; 1012 1013 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 1014 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 1015 1016 match_value->match = match; 1017 match_value->value_size = sizeof(u32); 1018 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 1019 if (!match_value->value) 1020 return -ENOMEM; 1021 1022 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 1023 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 1024 1025 match_value->match = match; 1026 match_value->value_size = sizeof(u32); 1027 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 1028 if (!match_value->value) 1029 return -ENOMEM; 1030 1031 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 1032 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 1033 1034 match_value->match = match; 1035 match_value->value_size = sizeof(u32); 1036 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 1037 if (!match_value->value) 1038 return -ENOMEM; 1039 1040 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1041 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1042 1043 action_value->action = action; 1044 action_value->value_size = sizeof(u64); 1045 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 1046 if (!action_value->value) 1047 return -ENOMEM; 1048 1049 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1050 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1051 1052 action_value->action = action; 1053 action_value->value_size = sizeof(u32); 1054 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 1055 if (!action_value->value) 1056 return -ENOMEM; 1057 1058 return 0; 1059 } 1060 1061 static void 1062 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry, 1063 u32 adj_index, u32 adj_size, 1064 u32 adj_hash_index, unsigned char *ha, 1065 struct mlxsw_sp_rif *rif) 1066 { 1067 struct devlink_dpipe_value *value; 1068 u32 *p_rif_value; 1069 u32 *p_index; 1070 1071 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 1072 p_index = value->value; 1073 *p_index = adj_index; 1074 1075 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 1076 p_index = value->value; 1077 *p_index = adj_size; 1078 1079 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 1080 p_index = value->value; 1081 *p_index = adj_hash_index; 1082 1083 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1084 ether_addr_copy(value->value, ha); 1085 1086 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1087 p_rif_value = value->value; 1088 *p_rif_value = mlxsw_sp_rif_index(rif); 1089 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 1090 value->mapping_valid = true; 1091 } 1092 1093 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp, 1094 struct mlxsw_sp_nexthop *nh, 1095 struct devlink_dpipe_entry *entry) 1096 { 1097 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh); 1098 unsigned char *ha = mlxsw_sp_nexthop_ha(nh); 1099 u32 adj_hash_index = 0; 1100 u32 adj_index = 0; 1101 u32 adj_size = 0; 1102 int err; 1103 1104 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index); 1105 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size, 1106 adj_hash_index, ha, rif); 1107 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter); 1108 if (!err) 1109 entry->counter_valid = true; 1110 } 1111 1112 static int 1113 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp, 1114 struct devlink_dpipe_entry *entry, 1115 bool counters_enabled, 1116 struct devlink_dpipe_dump_ctx *dump_ctx) 1117 { 1118 struct mlxsw_sp_nexthop *nh; 1119 int entry_index = 0; 1120 int nh_count_max; 1121 int nh_count = 0; 1122 int nh_skip; 1123 int j; 1124 int err; 1125 1126 rtnl_lock(); 1127 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 1128 start_again: 1129 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 1130 if (err) 1131 goto err_ctx_prepare; 1132 j = 0; 1133 nh_skip = nh_count; 1134 nh_count = 0; 1135 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 1136 if (!mlxsw_sp_nexthop_offload(nh) || 1137 mlxsw_sp_nexthop_group_has_ipip(nh)) 1138 continue; 1139 1140 if (nh_count < nh_skip) 1141 goto skip; 1142 1143 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry); 1144 entry->index = entry_index; 1145 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 1146 if (err) { 1147 if (err == -EMSGSIZE) { 1148 if (!j) 1149 goto err_entry_append; 1150 break; 1151 } 1152 goto err_entry_append; 1153 } 1154 entry_index++; 1155 j++; 1156 skip: 1157 nh_count++; 1158 } 1159 1160 devlink_dpipe_entry_ctx_close(dump_ctx); 1161 if (nh_count != nh_count_max) 1162 goto start_again; 1163 rtnl_unlock(); 1164 1165 return 0; 1166 1167 err_ctx_prepare: 1168 err_entry_append: 1169 rtnl_unlock(); 1170 return err; 1171 } 1172 1173 static int 1174 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled, 1175 struct devlink_dpipe_dump_ctx *dump_ctx) 1176 { 1177 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 1178 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 1179 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 1180 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 1181 struct devlink_dpipe_entry entry = {0}; 1182 struct mlxsw_sp *mlxsw_sp = priv; 1183 int err; 1184 1185 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 1186 sizeof(matches[0])); 1187 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 1188 sizeof(match_values[0])); 1189 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 1190 sizeof(actions[0])); 1191 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 1192 sizeof(action_values[0])); 1193 1194 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions); 1195 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry, 1196 match_values, matches, 1197 action_values, actions); 1198 if (err) 1199 goto out; 1200 1201 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry, 1202 counters_enabled, dump_ctx); 1203 out: 1204 devlink_dpipe_entry_clear(&entry); 1205 return err; 1206 } 1207 1208 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable) 1209 { 1210 struct mlxsw_sp *mlxsw_sp = priv; 1211 struct mlxsw_sp_nexthop *nh; 1212 u32 adj_hash_index = 0; 1213 u32 adj_index = 0; 1214 u32 adj_size = 0; 1215 1216 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 1217 if (!mlxsw_sp_nexthop_offload(nh) || 1218 mlxsw_sp_nexthop_group_has_ipip(nh)) 1219 continue; 1220 1221 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, 1222 &adj_hash_index); 1223 if (enable) 1224 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh); 1225 else 1226 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh); 1227 mlxsw_sp_nexthop_update(mlxsw_sp, 1228 adj_index + adj_hash_index, nh); 1229 } 1230 return 0; 1231 } 1232 1233 static u64 1234 mlxsw_sp_dpipe_table_adj_size_get(void *priv) 1235 { 1236 struct mlxsw_sp *mlxsw_sp = priv; 1237 u64 size; 1238 1239 rtnl_lock(); 1240 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 1241 rtnl_unlock(); 1242 1243 return size; 1244 } 1245 1246 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = { 1247 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump, 1248 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump, 1249 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump, 1250 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update, 1251 .size_get = mlxsw_sp_dpipe_table_adj_size_get, 1252 }; 1253 1254 #define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1 1255 1256 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp) 1257 { 1258 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1259 int err; 1260 1261 err = devlink_dpipe_table_register(devlink, 1262 MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 1263 &mlxsw_sp_dpipe_table_adj_ops, 1264 mlxsw_sp, false); 1265 if (err) 1266 return err; 1267 1268 err = devlink_dpipe_table_resource_set(devlink, 1269 MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 1270 MLXSW_SP_RESOURCE_KVD_LINEAR, 1271 MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ); 1272 if (err) 1273 goto err_resource_set; 1274 1275 return 0; 1276 1277 err_resource_set: 1278 devlink_dpipe_table_unregister(devlink, 1279 MLXSW_SP_DPIPE_TABLE_NAME_ADJ); 1280 return err; 1281 } 1282 1283 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp) 1284 { 1285 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1286 1287 devlink_dpipe_table_unregister(devlink, 1288 MLXSW_SP_DPIPE_TABLE_NAME_ADJ); 1289 } 1290 1291 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) 1292 { 1293 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1294 int err; 1295 1296 err = devlink_dpipe_headers_register(devlink, 1297 &mlxsw_sp_dpipe_headers); 1298 if (err) 1299 return err; 1300 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); 1301 if (err) 1302 goto err_erif_table_init; 1303 1304 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp); 1305 if (err) 1306 goto err_host4_table_init; 1307 1308 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp); 1309 if (err) 1310 goto err_host6_table_init; 1311 1312 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp); 1313 if (err) 1314 goto err_adj_table_init; 1315 1316 return 0; 1317 err_adj_table_init: 1318 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 1319 err_host6_table_init: 1320 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 1321 err_host4_table_init: 1322 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 1323 err_erif_table_init: 1324 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); 1325 return err; 1326 } 1327 1328 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) 1329 { 1330 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1331 1332 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp); 1333 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 1334 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 1335 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 1336 devlink_dpipe_headers_unregister(devlink); 1337 } 1338