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 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp) 775 { 776 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 777 778 return devlink_dpipe_table_register(devlink, 779 MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 780 &mlxsw_sp_host4_ops, 781 mlxsw_sp, false); 782 } 783 784 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp) 785 { 786 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 787 788 devlink_dpipe_table_unregister(devlink, 789 MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 790 } 791 792 static int 793 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb) 794 { 795 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6); 796 } 797 798 static int 799 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled, 800 struct devlink_dpipe_dump_ctx *dump_ctx) 801 { 802 struct mlxsw_sp *mlxsw_sp = priv; 803 804 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 805 counters_enabled, 806 dump_ctx, AF_INET6); 807 } 808 809 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable) 810 { 811 struct mlxsw_sp *mlxsw_sp = priv; 812 813 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6); 814 return 0; 815 } 816 817 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv) 818 { 819 struct mlxsw_sp *mlxsw_sp = priv; 820 821 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6); 822 } 823 824 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = { 825 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump, 826 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 827 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump, 828 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update, 829 .size_get = mlxsw_sp_dpipe_table_host6_size_get, 830 }; 831 832 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp) 833 { 834 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 835 836 return devlink_dpipe_table_register(devlink, 837 MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 838 &mlxsw_sp_host6_ops, 839 mlxsw_sp, false); 840 } 841 842 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp) 843 { 844 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 845 846 devlink_dpipe_table_unregister(devlink, 847 MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 848 } 849 850 static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv, 851 struct sk_buff *skb) 852 { 853 struct devlink_dpipe_match match = {0}; 854 int err; 855 856 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 857 match.header = &mlxsw_sp_dpipe_header_metadata; 858 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 859 860 err = devlink_dpipe_match_put(skb, &match); 861 if (err) 862 return err; 863 864 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 865 match.header = &mlxsw_sp_dpipe_header_metadata; 866 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 867 868 err = devlink_dpipe_match_put(skb, &match); 869 if (err) 870 return err; 871 872 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 873 match.header = &mlxsw_sp_dpipe_header_metadata; 874 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 875 876 return devlink_dpipe_match_put(skb, &match); 877 } 878 879 static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv, 880 struct sk_buff *skb) 881 { 882 struct devlink_dpipe_action action = {0}; 883 int err; 884 885 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 886 action.header = &devlink_dpipe_header_ethernet; 887 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 888 889 err = devlink_dpipe_action_put(skb, &action); 890 if (err) 891 return err; 892 893 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 894 action.header = &mlxsw_sp_dpipe_header_metadata; 895 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 896 897 return devlink_dpipe_action_put(skb, &action); 898 } 899 900 static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp) 901 { 902 struct mlxsw_sp_nexthop *nh; 903 u64 size = 0; 904 905 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) 906 if (mlxsw_sp_nexthop_offload(nh) && 907 !mlxsw_sp_nexthop_group_has_ipip(nh)) 908 size++; 909 return size; 910 } 911 912 enum mlxsw_sp_dpipe_table_adj_match { 913 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX, 914 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE, 915 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX, 916 MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT, 917 }; 918 919 enum mlxsw_sp_dpipe_table_adj_action { 920 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC, 921 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT, 922 MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT, 923 }; 924 925 static void 926 mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches, 927 struct devlink_dpipe_action *actions) 928 { 929 struct devlink_dpipe_action *action; 930 struct devlink_dpipe_match *match; 931 932 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 933 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 934 match->header = &mlxsw_sp_dpipe_header_metadata; 935 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 936 937 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 938 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 939 match->header = &mlxsw_sp_dpipe_header_metadata; 940 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 941 942 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 943 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 944 match->header = &mlxsw_sp_dpipe_header_metadata; 945 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 946 947 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 948 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 949 action->header = &devlink_dpipe_header_ethernet; 950 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 951 952 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 953 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 954 action->header = &mlxsw_sp_dpipe_header_metadata; 955 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 956 } 957 958 static int 959 mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry, 960 struct devlink_dpipe_value *match_values, 961 struct devlink_dpipe_match *matches, 962 struct devlink_dpipe_value *action_values, 963 struct devlink_dpipe_action *actions) 964 { struct devlink_dpipe_value *action_value; 965 struct devlink_dpipe_value *match_value; 966 struct devlink_dpipe_action *action; 967 struct devlink_dpipe_match *match; 968 969 entry->match_values = match_values; 970 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT; 971 972 entry->action_values = action_values; 973 entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT; 974 975 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 976 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 977 978 match_value->match = match; 979 match_value->value_size = sizeof(u32); 980 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 981 if (!match_value->value) 982 return -ENOMEM; 983 984 match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 985 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 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_HASH_INDEX]; 994 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 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 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1003 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1004 1005 action_value->action = action; 1006 action_value->value_size = sizeof(u64); 1007 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 1008 if (!action_value->value) 1009 return -ENOMEM; 1010 1011 action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1012 action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1013 1014 action_value->action = action; 1015 action_value->value_size = sizeof(u32); 1016 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 1017 if (!action_value->value) 1018 return -ENOMEM; 1019 1020 return 0; 1021 } 1022 1023 static void 1024 __mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry, 1025 u32 adj_index, u32 adj_size, 1026 u32 adj_hash_index, unsigned char *ha, 1027 struct mlxsw_sp_rif *rif) 1028 { 1029 struct devlink_dpipe_value *value; 1030 u32 *p_rif_value; 1031 u32 *p_index; 1032 1033 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 1034 p_index = value->value; 1035 *p_index = adj_index; 1036 1037 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 1038 p_index = value->value; 1039 *p_index = adj_size; 1040 1041 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 1042 p_index = value->value; 1043 *p_index = adj_hash_index; 1044 1045 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 1046 ether_addr_copy(value->value, ha); 1047 1048 value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 1049 p_rif_value = value->value; 1050 *p_rif_value = mlxsw_sp_rif_index(rif); 1051 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 1052 value->mapping_valid = true; 1053 } 1054 1055 static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp, 1056 struct mlxsw_sp_nexthop *nh, 1057 struct devlink_dpipe_entry *entry) 1058 { 1059 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh); 1060 unsigned char *ha = mlxsw_sp_nexthop_ha(nh); 1061 u32 adj_hash_index = 0; 1062 u32 adj_index = 0; 1063 u32 adj_size = 0; 1064 int err; 1065 1066 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index); 1067 __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size, 1068 adj_hash_index, ha, rif); 1069 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter); 1070 if (!err) 1071 entry->counter_valid = true; 1072 } 1073 1074 static int 1075 mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp, 1076 struct devlink_dpipe_entry *entry, 1077 bool counters_enabled, 1078 struct devlink_dpipe_dump_ctx *dump_ctx) 1079 { 1080 struct mlxsw_sp_nexthop *nh; 1081 int entry_index = 0; 1082 int nh_count_max; 1083 int nh_count = 0; 1084 int nh_skip; 1085 int j; 1086 int err; 1087 1088 rtnl_lock(); 1089 nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 1090 start_again: 1091 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 1092 if (err) 1093 goto err_ctx_prepare; 1094 j = 0; 1095 nh_skip = nh_count; 1096 nh_count = 0; 1097 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 1098 if (!mlxsw_sp_nexthop_offload(nh) || 1099 mlxsw_sp_nexthop_group_has_ipip(nh)) 1100 continue; 1101 1102 if (nh_count < nh_skip) 1103 goto skip; 1104 1105 mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry); 1106 entry->index = entry_index; 1107 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 1108 if (err) { 1109 if (err == -EMSGSIZE) { 1110 if (!j) 1111 goto err_entry_append; 1112 break; 1113 } 1114 goto err_entry_append; 1115 } 1116 entry_index++; 1117 j++; 1118 skip: 1119 nh_count++; 1120 } 1121 1122 devlink_dpipe_entry_ctx_close(dump_ctx); 1123 if (nh_count != nh_count_max) 1124 goto start_again; 1125 rtnl_unlock(); 1126 1127 return 0; 1128 1129 err_ctx_prepare: 1130 err_entry_append: 1131 rtnl_unlock(); 1132 return err; 1133 } 1134 1135 static int 1136 mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled, 1137 struct devlink_dpipe_dump_ctx *dump_ctx) 1138 { 1139 struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 1140 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 1141 struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 1142 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 1143 struct devlink_dpipe_entry entry = {0}; 1144 struct mlxsw_sp *mlxsw_sp = priv; 1145 int err; 1146 1147 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 1148 sizeof(matches[0])); 1149 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 1150 sizeof(match_values[0])); 1151 memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 1152 sizeof(actions[0])); 1153 memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 1154 sizeof(action_values[0])); 1155 1156 mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions); 1157 err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry, 1158 match_values, matches, 1159 action_values, actions); 1160 if (err) 1161 goto out; 1162 1163 err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry, 1164 counters_enabled, dump_ctx); 1165 out: 1166 devlink_dpipe_entry_clear(&entry); 1167 return err; 1168 } 1169 1170 static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable) 1171 { 1172 struct mlxsw_sp *mlxsw_sp = priv; 1173 struct mlxsw_sp_nexthop *nh; 1174 u32 adj_hash_index = 0; 1175 u32 adj_index = 0; 1176 u32 adj_size = 0; 1177 1178 mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 1179 if (!mlxsw_sp_nexthop_offload(nh) || 1180 mlxsw_sp_nexthop_group_has_ipip(nh)) 1181 continue; 1182 1183 mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, 1184 &adj_hash_index); 1185 if (enable) 1186 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh); 1187 else 1188 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh); 1189 mlxsw_sp_nexthop_update(mlxsw_sp, 1190 adj_index + adj_hash_index, nh); 1191 } 1192 return 0; 1193 } 1194 1195 static u64 1196 mlxsw_sp_dpipe_table_adj_size_get(void *priv) 1197 { 1198 struct mlxsw_sp *mlxsw_sp = priv; 1199 u64 size; 1200 1201 rtnl_lock(); 1202 size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 1203 rtnl_unlock(); 1204 1205 return size; 1206 } 1207 1208 static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = { 1209 .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump, 1210 .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump, 1211 .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump, 1212 .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update, 1213 .size_get = mlxsw_sp_dpipe_table_adj_size_get, 1214 }; 1215 1216 static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp) 1217 { 1218 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1219 1220 return devlink_dpipe_table_register(devlink, 1221 MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 1222 &mlxsw_sp_dpipe_table_adj_ops, 1223 mlxsw_sp, false); 1224 } 1225 1226 static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp) 1227 { 1228 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1229 1230 devlink_dpipe_table_unregister(devlink, 1231 MLXSW_SP_DPIPE_TABLE_NAME_ADJ); 1232 } 1233 1234 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) 1235 { 1236 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1237 int err; 1238 1239 err = devlink_dpipe_headers_register(devlink, 1240 &mlxsw_sp_dpipe_headers); 1241 if (err) 1242 return err; 1243 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); 1244 if (err) 1245 goto err_erif_table_init; 1246 1247 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp); 1248 if (err) 1249 goto err_host4_table_init; 1250 1251 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp); 1252 if (err) 1253 goto err_host6_table_init; 1254 1255 err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp); 1256 if (err) 1257 goto err_adj_table_init; 1258 1259 return 0; 1260 err_adj_table_init: 1261 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 1262 err_host6_table_init: 1263 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 1264 err_host4_table_init: 1265 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 1266 err_erif_table_init: 1267 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); 1268 return err; 1269 } 1270 1271 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) 1272 { 1273 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1274 1275 mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp); 1276 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 1277 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 1278 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 1279 devlink_dpipe_headers_unregister(devlink); 1280 } 1281