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