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