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 }; 47 48 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = { 49 { .name = "erif_port", 50 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 51 .bitwidth = 32, 52 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX, 53 }, 54 { .name = "l3_forward", 55 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 56 .bitwidth = 1, 57 }, 58 { .name = "l3_drop", 59 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 60 .bitwidth = 1, 61 }, 62 }; 63 64 enum mlxsw_sp_dpipe_header_id { 65 MLXSW_SP_DPIPE_HEADER_METADATA, 66 }; 67 68 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = { 69 .name = "mlxsw_meta", 70 .id = MLXSW_SP_DPIPE_HEADER_METADATA, 71 .fields = mlxsw_sp_dpipe_fields_metadata, 72 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata), 73 }; 74 75 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = { 76 &mlxsw_sp_dpipe_header_metadata, 77 &devlink_dpipe_header_ethernet, 78 &devlink_dpipe_header_ipv4, 79 &devlink_dpipe_header_ipv6, 80 }; 81 82 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = { 83 .headers = mlxsw_dpipe_headers, 84 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers), 85 }; 86 87 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv, 88 struct sk_buff *skb) 89 { 90 struct devlink_dpipe_action action = {0}; 91 int err; 92 93 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 94 action.header = &mlxsw_sp_dpipe_header_metadata; 95 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 96 97 err = devlink_dpipe_action_put(skb, &action); 98 if (err) 99 return err; 100 101 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 102 action.header = &mlxsw_sp_dpipe_header_metadata; 103 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP; 104 105 return devlink_dpipe_action_put(skb, &action); 106 } 107 108 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv, 109 struct sk_buff *skb) 110 { 111 struct devlink_dpipe_match match = {0}; 112 113 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 114 match.header = &mlxsw_sp_dpipe_header_metadata; 115 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 116 117 return devlink_dpipe_match_put(skb, &match); 118 } 119 120 static void 121 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match, 122 struct devlink_dpipe_action *action) 123 { 124 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 125 action->header = &mlxsw_sp_dpipe_header_metadata; 126 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 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 133 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry, 134 struct devlink_dpipe_value *match_value, 135 struct devlink_dpipe_match *match, 136 struct devlink_dpipe_value *action_value, 137 struct devlink_dpipe_action *action) 138 { 139 entry->match_values = match_value; 140 entry->match_values_count = 1; 141 142 entry->action_values = action_value; 143 entry->action_values_count = 1; 144 145 match_value->match = match; 146 match_value->value_size = sizeof(u32); 147 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 148 if (!match_value->value) 149 return -ENOMEM; 150 151 action_value->action = action; 152 action_value->value_size = sizeof(u32); 153 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 154 if (!action_value->value) 155 goto err_action_alloc; 156 return 0; 157 158 err_action_alloc: 159 kfree(match_value->value); 160 return -ENOMEM; 161 } 162 163 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp, 164 struct devlink_dpipe_entry *entry, 165 struct mlxsw_sp_rif *rif, 166 bool counters_enabled) 167 { 168 u32 *action_value; 169 u32 *rif_value; 170 u64 cnt; 171 int err; 172 173 /* Set Match RIF index */ 174 rif_value = entry->match_values->value; 175 *rif_value = mlxsw_sp_rif_index(rif); 176 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 177 entry->match_values->mapping_valid = true; 178 179 /* Set Action Forwarding */ 180 action_value = entry->action_values->value; 181 *action_value = 1; 182 183 entry->counter_valid = false; 184 entry->counter = 0; 185 entry->index = mlxsw_sp_rif_index(rif); 186 187 if (!counters_enabled) 188 return 0; 189 190 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif, 191 MLXSW_SP_RIF_COUNTER_EGRESS, 192 &cnt); 193 if (!err) { 194 entry->counter = cnt; 195 entry->counter_valid = true; 196 } 197 return 0; 198 } 199 200 static int 201 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, 202 struct devlink_dpipe_dump_ctx *dump_ctx) 203 { 204 struct devlink_dpipe_value match_value, action_value; 205 struct devlink_dpipe_action action = {0}; 206 struct devlink_dpipe_match match = {0}; 207 struct devlink_dpipe_entry entry = {0}; 208 struct mlxsw_sp *mlxsw_sp = priv; 209 unsigned int rif_count; 210 int i, j; 211 int err; 212 213 memset(&match_value, 0, sizeof(match_value)); 214 memset(&action_value, 0, sizeof(action_value)); 215 216 mlxsw_sp_erif_match_action_prepare(&match, &action); 217 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, 218 &action_value, &action); 219 if (err) 220 return err; 221 222 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 223 rtnl_lock(); 224 i = 0; 225 start_again: 226 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 227 if (err) 228 return err; 229 j = 0; 230 for (; i < rif_count; i++) { 231 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 232 233 if (!rif) 234 continue; 235 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, 236 counters_enabled); 237 if (err) 238 goto err_entry_get; 239 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry); 240 if (err) { 241 if (err == -EMSGSIZE) { 242 if (!j) 243 goto err_entry_append; 244 break; 245 } 246 goto err_entry_append; 247 } 248 j++; 249 } 250 251 devlink_dpipe_entry_ctx_close(dump_ctx); 252 if (i != rif_count) 253 goto start_again; 254 rtnl_unlock(); 255 256 devlink_dpipe_entry_clear(&entry); 257 return 0; 258 err_entry_append: 259 err_entry_get: 260 rtnl_unlock(); 261 devlink_dpipe_entry_clear(&entry); 262 return err; 263 } 264 265 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable) 266 { 267 struct mlxsw_sp *mlxsw_sp = priv; 268 int i; 269 270 rtnl_lock(); 271 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 272 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 273 274 if (!rif) 275 continue; 276 if (enable) 277 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, 278 MLXSW_SP_RIF_COUNTER_EGRESS); 279 else 280 mlxsw_sp_rif_counter_free(mlxsw_sp, rif, 281 MLXSW_SP_RIF_COUNTER_EGRESS); 282 } 283 rtnl_unlock(); 284 return 0; 285 } 286 287 static u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv) 288 { 289 struct mlxsw_sp *mlxsw_sp = priv; 290 291 return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 292 } 293 294 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = { 295 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump, 296 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump, 297 .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump, 298 .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update, 299 .size_get = mlxsw_sp_dpipe_table_erif_size_get, 300 }; 301 302 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp) 303 { 304 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 305 306 return devlink_dpipe_table_register(devlink, 307 MLXSW_SP_DPIPE_TABLE_NAME_ERIF, 308 &mlxsw_sp_erif_ops, 309 mlxsw_sp, false); 310 } 311 312 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp) 313 { 314 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 315 316 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF); 317 } 318 319 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type) 320 { 321 struct devlink_dpipe_match match = {0}; 322 int err; 323 324 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 325 match.header = &mlxsw_sp_dpipe_header_metadata; 326 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 327 328 err = devlink_dpipe_match_put(skb, &match); 329 if (err) 330 return err; 331 332 switch (type) { 333 case AF_INET: 334 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 335 match.header = &devlink_dpipe_header_ipv4; 336 match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 337 break; 338 case AF_INET6: 339 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 340 match.header = &devlink_dpipe_header_ipv6; 341 match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 342 break; 343 default: 344 WARN_ON(1); 345 return -EINVAL; 346 } 347 348 return devlink_dpipe_match_put(skb, &match); 349 } 350 351 static int 352 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb) 353 { 354 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET); 355 } 356 357 static int 358 mlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb) 359 { 360 struct devlink_dpipe_action action = {0}; 361 362 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 363 action.header = &devlink_dpipe_header_ethernet; 364 action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 365 366 return devlink_dpipe_action_put(skb, &action); 367 } 368 369 enum mlxsw_sp_dpipe_table_host_match { 370 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF, 371 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP, 372 MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT, 373 }; 374 375 static void 376 mlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches, 377 struct devlink_dpipe_action *action, 378 int type) 379 { 380 struct devlink_dpipe_match *match; 381 382 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 383 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 384 match->header = &mlxsw_sp_dpipe_header_metadata; 385 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 386 387 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 388 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 389 switch (type) { 390 case AF_INET: 391 match->header = &devlink_dpipe_header_ipv4; 392 match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 393 break; 394 case AF_INET6: 395 match->header = &devlink_dpipe_header_ipv6; 396 match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 397 break; 398 default: 399 WARN_ON(1); 400 return; 401 } 402 403 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 404 action->header = &devlink_dpipe_header_ethernet; 405 action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 406 } 407 408 static int 409 mlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry, 410 struct devlink_dpipe_value *match_values, 411 struct devlink_dpipe_match *matches, 412 struct devlink_dpipe_value *action_value, 413 struct devlink_dpipe_action *action, 414 int type) 415 { 416 struct devlink_dpipe_value *match_value; 417 struct devlink_dpipe_match *match; 418 419 entry->match_values = match_values; 420 entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT; 421 422 entry->action_values = action_value; 423 entry->action_values_count = 1; 424 425 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 426 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 427 428 match_value->match = match; 429 match_value->value_size = sizeof(u32); 430 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 431 if (!match_value->value) 432 return -ENOMEM; 433 434 match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 435 match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 436 437 match_value->match = match; 438 switch (type) { 439 case AF_INET: 440 match_value->value_size = sizeof(u32); 441 break; 442 case AF_INET6: 443 match_value->value_size = sizeof(struct in6_addr); 444 break; 445 default: 446 WARN_ON(1); 447 return -EINVAL; 448 } 449 450 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 451 if (!match_value->value) 452 return -ENOMEM; 453 454 action_value->action = action; 455 action_value->value_size = sizeof(u64); 456 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 457 if (!action_value->value) 458 return -ENOMEM; 459 460 return 0; 461 } 462 463 static void 464 __mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry, 465 struct mlxsw_sp_rif *rif, 466 unsigned char *ha, void *dip) 467 { 468 struct devlink_dpipe_value *value; 469 u32 *rif_value; 470 u8 *ha_value; 471 472 /* Set Match RIF index */ 473 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 474 475 rif_value = value->value; 476 *rif_value = mlxsw_sp_rif_index(rif); 477 value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 478 value->mapping_valid = true; 479 480 /* Set Match DIP */ 481 value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 482 memcpy(value->value, dip, value->value_size); 483 484 /* Set Action DMAC */ 485 value = entry->action_values; 486 ha_value = value->value; 487 ether_addr_copy(ha_value, ha); 488 } 489 490 static void 491 mlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry, 492 struct mlxsw_sp_neigh_entry *neigh_entry, 493 struct mlxsw_sp_rif *rif) 494 { 495 unsigned char *ha; 496 u32 dip; 497 498 ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 499 dip = mlxsw_sp_neigh4_entry_dip(neigh_entry); 500 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip); 501 } 502 503 static void 504 mlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry, 505 struct mlxsw_sp_neigh_entry *neigh_entry, 506 struct mlxsw_sp_rif *rif) 507 { 508 struct in6_addr *dip; 509 unsigned char *ha; 510 511 ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 512 dip = mlxsw_sp_neigh6_entry_dip(neigh_entry); 513 514 __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip); 515 } 516 517 static void 518 mlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp, 519 struct devlink_dpipe_entry *entry, 520 struct mlxsw_sp_neigh_entry *neigh_entry, 521 struct mlxsw_sp_rif *rif, 522 int type) 523 { 524 int err; 525 526 switch (type) { 527 case AF_INET: 528 mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif); 529 break; 530 case AF_INET6: 531 mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif); 532 break; 533 default: 534 WARN_ON(1); 535 return; 536 } 537 538 err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry, 539 &entry->counter); 540 if (!err) 541 entry->counter_valid = true; 542 } 543 544 static int 545 mlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp, 546 struct devlink_dpipe_entry *entry, 547 bool counters_enabled, 548 struct devlink_dpipe_dump_ctx *dump_ctx, 549 int type) 550 { 551 int rif_neigh_count = 0; 552 int rif_neigh_skip = 0; 553 int neigh_count = 0; 554 int rif_count; 555 int i, j; 556 int err; 557 558 rtnl_lock(); 559 i = 0; 560 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 561 start_again: 562 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 563 if (err) 564 goto err_ctx_prepare; 565 j = 0; 566 rif_neigh_skip = rif_neigh_count; 567 for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 568 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 569 struct mlxsw_sp_neigh_entry *neigh_entry; 570 571 if (!rif) 572 continue; 573 574 rif_neigh_count = 0; 575 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 576 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 577 578 if (neigh_type != type) 579 continue; 580 581 if (neigh_type == AF_INET6 && 582 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 583 continue; 584 585 if (rif_neigh_count < rif_neigh_skip) 586 goto skip; 587 588 mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry, 589 neigh_entry, rif, 590 type); 591 entry->index = neigh_count; 592 err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 593 if (err) { 594 if (err == -EMSGSIZE) { 595 if (!j) 596 goto err_entry_append; 597 else 598 goto out; 599 } 600 goto err_entry_append; 601 } 602 neigh_count++; 603 j++; 604 skip: 605 rif_neigh_count++; 606 } 607 rif_neigh_skip = 0; 608 } 609 out: 610 devlink_dpipe_entry_ctx_close(dump_ctx); 611 if (i != rif_count) 612 goto start_again; 613 614 rtnl_unlock(); 615 return 0; 616 617 err_ctx_prepare: 618 err_entry_append: 619 rtnl_unlock(); 620 return err; 621 } 622 623 static int 624 mlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp, 625 bool counters_enabled, 626 struct devlink_dpipe_dump_ctx *dump_ctx, 627 int type) 628 { 629 struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 630 struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 631 struct devlink_dpipe_value action_value; 632 struct devlink_dpipe_action action = {0}; 633 struct devlink_dpipe_entry entry = {0}; 634 int err; 635 636 memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 637 sizeof(matches[0])); 638 memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 639 sizeof(match_values[0])); 640 memset(&action_value, 0, sizeof(action_value)); 641 642 mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type); 643 err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values, 644 matches, &action_value, 645 &action, type); 646 if (err) 647 goto out; 648 649 err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry, 650 counters_enabled, dump_ctx, 651 type); 652 out: 653 devlink_dpipe_entry_clear(&entry); 654 return err; 655 } 656 657 static int 658 mlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled, 659 struct devlink_dpipe_dump_ctx *dump_ctx) 660 { 661 struct mlxsw_sp *mlxsw_sp = priv; 662 663 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 664 counters_enabled, 665 dump_ctx, AF_INET); 666 } 667 668 static void 669 mlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp, 670 bool enable, int type) 671 { 672 int i; 673 674 rtnl_lock(); 675 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 676 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 677 struct mlxsw_sp_neigh_entry *neigh_entry; 678 679 if (!rif) 680 continue; 681 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 682 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 683 684 if (neigh_type != type) 685 continue; 686 687 if (neigh_type == AF_INET6 && 688 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 689 continue; 690 691 mlxsw_sp_neigh_entry_counter_update(mlxsw_sp, 692 neigh_entry, 693 enable); 694 } 695 } 696 rtnl_unlock(); 697 } 698 699 static int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable) 700 { 701 struct mlxsw_sp *mlxsw_sp = priv; 702 703 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET); 704 return 0; 705 } 706 707 static u64 708 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type) 709 { 710 u64 size = 0; 711 int i; 712 713 rtnl_lock(); 714 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 715 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 716 struct mlxsw_sp_neigh_entry *neigh_entry; 717 718 if (!rif) 719 continue; 720 mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 721 int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 722 723 if (neigh_type != type) 724 continue; 725 726 if (neigh_type == AF_INET6 && 727 mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 728 continue; 729 730 size++; 731 } 732 } 733 rtnl_unlock(); 734 735 return size; 736 } 737 738 static u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv) 739 { 740 struct mlxsw_sp *mlxsw_sp = priv; 741 742 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET); 743 } 744 745 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = { 746 .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump, 747 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 748 .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump, 749 .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update, 750 .size_get = mlxsw_sp_dpipe_table_host4_size_get, 751 }; 752 753 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp) 754 { 755 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 756 757 return devlink_dpipe_table_register(devlink, 758 MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 759 &mlxsw_sp_host4_ops, 760 mlxsw_sp, false); 761 } 762 763 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp) 764 { 765 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 766 767 devlink_dpipe_table_unregister(devlink, 768 MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 769 } 770 771 static int 772 mlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb) 773 { 774 return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6); 775 } 776 777 static int 778 mlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled, 779 struct devlink_dpipe_dump_ctx *dump_ctx) 780 { 781 struct mlxsw_sp *mlxsw_sp = priv; 782 783 return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 784 counters_enabled, 785 dump_ctx, AF_INET6); 786 } 787 788 static int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable) 789 { 790 struct mlxsw_sp *mlxsw_sp = priv; 791 792 mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6); 793 return 0; 794 } 795 796 static u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv) 797 { 798 struct mlxsw_sp *mlxsw_sp = priv; 799 800 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6); 801 } 802 803 static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = { 804 .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump, 805 .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 806 .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump, 807 .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update, 808 .size_get = mlxsw_sp_dpipe_table_host6_size_get, 809 }; 810 811 static int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp) 812 { 813 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 814 815 return devlink_dpipe_table_register(devlink, 816 MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 817 &mlxsw_sp_host6_ops, 818 mlxsw_sp, false); 819 } 820 821 static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp) 822 { 823 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 824 825 devlink_dpipe_table_unregister(devlink, 826 MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 827 } 828 829 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) 830 { 831 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 832 int err; 833 834 err = devlink_dpipe_headers_register(devlink, 835 &mlxsw_sp_dpipe_headers); 836 if (err) 837 return err; 838 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); 839 if (err) 840 goto err_erif_table_init; 841 842 err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp); 843 if (err) 844 goto err_host4_table_init; 845 846 err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp); 847 if (err) 848 goto err_host6_table_init; 849 return 0; 850 851 err_host6_table_init: 852 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 853 err_host4_table_init: 854 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 855 err_erif_table_init: 856 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); 857 return err; 858 } 859 860 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) 861 { 862 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 863 864 mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 865 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 866 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 867 devlink_dpipe_headers_unregister(devlink); 868 } 869