1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 5 */ 6 7 #include "devl_internal.h" 8 9 static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = { 10 { 11 .name = "destination mac", 12 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC, 13 .bitwidth = 48, 14 }, 15 }; 16 17 struct devlink_dpipe_header devlink_dpipe_header_ethernet = { 18 .name = "ethernet", 19 .id = DEVLINK_DPIPE_HEADER_ETHERNET, 20 .fields = devlink_dpipe_fields_ethernet, 21 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet), 22 .global = true, 23 }; 24 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet); 25 26 static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = { 27 { 28 .name = "destination ip", 29 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP, 30 .bitwidth = 32, 31 }, 32 }; 33 34 struct devlink_dpipe_header devlink_dpipe_header_ipv4 = { 35 .name = "ipv4", 36 .id = DEVLINK_DPIPE_HEADER_IPV4, 37 .fields = devlink_dpipe_fields_ipv4, 38 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4), 39 .global = true, 40 }; 41 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4); 42 43 static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = { 44 { 45 .name = "destination ip", 46 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP, 47 .bitwidth = 128, 48 }, 49 }; 50 51 struct devlink_dpipe_header devlink_dpipe_header_ipv6 = { 52 .name = "ipv6", 53 .id = DEVLINK_DPIPE_HEADER_IPV6, 54 .fields = devlink_dpipe_fields_ipv6, 55 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6), 56 .global = true, 57 }; 58 EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6); 59 60 int devlink_dpipe_match_put(struct sk_buff *skb, 61 struct devlink_dpipe_match *match) 62 { 63 struct devlink_dpipe_header *header = match->header; 64 struct devlink_dpipe_field *field = &header->fields[match->field_id]; 65 struct nlattr *match_attr; 66 67 match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH); 68 if (!match_attr) 69 return -EMSGSIZE; 70 71 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) || 72 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) || 73 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 74 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 75 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 76 goto nla_put_failure; 77 78 nla_nest_end(skb, match_attr); 79 return 0; 80 81 nla_put_failure: 82 nla_nest_cancel(skb, match_attr); 83 return -EMSGSIZE; 84 } 85 EXPORT_SYMBOL_GPL(devlink_dpipe_match_put); 86 87 static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table, 88 struct sk_buff *skb) 89 { 90 struct nlattr *matches_attr; 91 92 matches_attr = nla_nest_start_noflag(skb, 93 DEVLINK_ATTR_DPIPE_TABLE_MATCHES); 94 if (!matches_attr) 95 return -EMSGSIZE; 96 97 if (table->table_ops->matches_dump(table->priv, skb)) 98 goto nla_put_failure; 99 100 nla_nest_end(skb, matches_attr); 101 return 0; 102 103 nla_put_failure: 104 nla_nest_cancel(skb, matches_attr); 105 return -EMSGSIZE; 106 } 107 108 int devlink_dpipe_action_put(struct sk_buff *skb, 109 struct devlink_dpipe_action *action) 110 { 111 struct devlink_dpipe_header *header = action->header; 112 struct devlink_dpipe_field *field = &header->fields[action->field_id]; 113 struct nlattr *action_attr; 114 115 action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION); 116 if (!action_attr) 117 return -EMSGSIZE; 118 119 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) || 120 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) || 121 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 122 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 123 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 124 goto nla_put_failure; 125 126 nla_nest_end(skb, action_attr); 127 return 0; 128 129 nla_put_failure: 130 nla_nest_cancel(skb, action_attr); 131 return -EMSGSIZE; 132 } 133 EXPORT_SYMBOL_GPL(devlink_dpipe_action_put); 134 135 static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table, 136 struct sk_buff *skb) 137 { 138 struct nlattr *actions_attr; 139 140 actions_attr = nla_nest_start_noflag(skb, 141 DEVLINK_ATTR_DPIPE_TABLE_ACTIONS); 142 if (!actions_attr) 143 return -EMSGSIZE; 144 145 if (table->table_ops->actions_dump(table->priv, skb)) 146 goto nla_put_failure; 147 148 nla_nest_end(skb, actions_attr); 149 return 0; 150 151 nla_put_failure: 152 nla_nest_cancel(skb, actions_attr); 153 return -EMSGSIZE; 154 } 155 156 static int devlink_dpipe_table_put(struct sk_buff *skb, 157 struct devlink_dpipe_table *table) 158 { 159 struct nlattr *table_attr; 160 u64 table_size; 161 162 table_size = table->table_ops->size_get(table->priv); 163 table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE); 164 if (!table_attr) 165 return -EMSGSIZE; 166 167 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) || 168 devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size)) 169 goto nla_put_failure; 170 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, 171 table->counters_enabled)) 172 goto nla_put_failure; 173 174 if (table->resource_valid) { 175 if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, 176 table->resource_id) || 177 devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, 178 table->resource_units)) 179 goto nla_put_failure; 180 } 181 if (devlink_dpipe_matches_put(table, skb)) 182 goto nla_put_failure; 183 184 if (devlink_dpipe_actions_put(table, skb)) 185 goto nla_put_failure; 186 187 nla_nest_end(skb, table_attr); 188 return 0; 189 190 nla_put_failure: 191 nla_nest_cancel(skb, table_attr); 192 return -EMSGSIZE; 193 } 194 195 static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb, 196 struct genl_info *info) 197 { 198 int err; 199 200 if (*pskb) { 201 err = genlmsg_reply(*pskb, info); 202 if (err) 203 return err; 204 } 205 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 206 if (!*pskb) 207 return -ENOMEM; 208 return 0; 209 } 210 211 static int devlink_dpipe_tables_fill(struct genl_info *info, 212 enum devlink_command cmd, int flags, 213 struct list_head *dpipe_tables, 214 const char *table_name) 215 { 216 struct devlink *devlink = info->user_ptr[0]; 217 struct devlink_dpipe_table *table; 218 struct nlattr *tables_attr; 219 struct sk_buff *skb = NULL; 220 struct nlmsghdr *nlh; 221 bool incomplete; 222 void *hdr; 223 int i; 224 int err; 225 226 table = list_first_entry(dpipe_tables, 227 struct devlink_dpipe_table, list); 228 start_again: 229 err = devlink_dpipe_send_and_alloc_skb(&skb, info); 230 if (err) 231 return err; 232 233 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 234 &devlink_nl_family, NLM_F_MULTI, cmd); 235 if (!hdr) { 236 nlmsg_free(skb); 237 return -EMSGSIZE; 238 } 239 240 if (devlink_nl_put_handle(skb, devlink)) 241 goto nla_put_failure; 242 tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES); 243 if (!tables_attr) 244 goto nla_put_failure; 245 246 i = 0; 247 incomplete = false; 248 list_for_each_entry_from(table, dpipe_tables, list) { 249 if (!table_name) { 250 err = devlink_dpipe_table_put(skb, table); 251 if (err) { 252 if (!i) 253 goto err_table_put; 254 incomplete = true; 255 break; 256 } 257 } else { 258 if (!strcmp(table->name, table_name)) { 259 err = devlink_dpipe_table_put(skb, table); 260 if (err) 261 break; 262 } 263 } 264 i++; 265 } 266 267 nla_nest_end(skb, tables_attr); 268 genlmsg_end(skb, hdr); 269 if (incomplete) 270 goto start_again; 271 272 send_done: 273 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 274 NLMSG_DONE, 0, flags | NLM_F_MULTI); 275 if (!nlh) { 276 err = devlink_dpipe_send_and_alloc_skb(&skb, info); 277 if (err) 278 return err; 279 goto send_done; 280 } 281 282 return genlmsg_reply(skb, info); 283 284 nla_put_failure: 285 err = -EMSGSIZE; 286 err_table_put: 287 nlmsg_free(skb); 288 return err; 289 } 290 291 int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info) 292 { 293 struct devlink *devlink = info->user_ptr[0]; 294 const char *table_name = NULL; 295 296 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]) 297 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 298 299 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0, 300 &devlink->dpipe_table_list, 301 table_name); 302 } 303 304 static int devlink_dpipe_value_put(struct sk_buff *skb, 305 struct devlink_dpipe_value *value) 306 { 307 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE, 308 value->value_size, value->value)) 309 return -EMSGSIZE; 310 if (value->mask) 311 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK, 312 value->value_size, value->mask)) 313 return -EMSGSIZE; 314 if (value->mapping_valid) 315 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING, 316 value->mapping_value)) 317 return -EMSGSIZE; 318 return 0; 319 } 320 321 static int devlink_dpipe_action_value_put(struct sk_buff *skb, 322 struct devlink_dpipe_value *value) 323 { 324 if (!value->action) 325 return -EINVAL; 326 if (devlink_dpipe_action_put(skb, value->action)) 327 return -EMSGSIZE; 328 if (devlink_dpipe_value_put(skb, value)) 329 return -EMSGSIZE; 330 return 0; 331 } 332 333 static int devlink_dpipe_action_values_put(struct sk_buff *skb, 334 struct devlink_dpipe_value *values, 335 unsigned int values_count) 336 { 337 struct nlattr *action_attr; 338 int i; 339 int err; 340 341 for (i = 0; i < values_count; i++) { 342 action_attr = nla_nest_start_noflag(skb, 343 DEVLINK_ATTR_DPIPE_ACTION_VALUE); 344 if (!action_attr) 345 return -EMSGSIZE; 346 err = devlink_dpipe_action_value_put(skb, &values[i]); 347 if (err) 348 goto err_action_value_put; 349 nla_nest_end(skb, action_attr); 350 } 351 return 0; 352 353 err_action_value_put: 354 nla_nest_cancel(skb, action_attr); 355 return err; 356 } 357 358 static int devlink_dpipe_match_value_put(struct sk_buff *skb, 359 struct devlink_dpipe_value *value) 360 { 361 if (!value->match) 362 return -EINVAL; 363 if (devlink_dpipe_match_put(skb, value->match)) 364 return -EMSGSIZE; 365 if (devlink_dpipe_value_put(skb, value)) 366 return -EMSGSIZE; 367 return 0; 368 } 369 370 static int devlink_dpipe_match_values_put(struct sk_buff *skb, 371 struct devlink_dpipe_value *values, 372 unsigned int values_count) 373 { 374 struct nlattr *match_attr; 375 int i; 376 int err; 377 378 for (i = 0; i < values_count; i++) { 379 match_attr = nla_nest_start_noflag(skb, 380 DEVLINK_ATTR_DPIPE_MATCH_VALUE); 381 if (!match_attr) 382 return -EMSGSIZE; 383 err = devlink_dpipe_match_value_put(skb, &values[i]); 384 if (err) 385 goto err_match_value_put; 386 nla_nest_end(skb, match_attr); 387 } 388 return 0; 389 390 err_match_value_put: 391 nla_nest_cancel(skb, match_attr); 392 return err; 393 } 394 395 static int devlink_dpipe_entry_put(struct sk_buff *skb, 396 struct devlink_dpipe_entry *entry) 397 { 398 struct nlattr *entry_attr, *matches_attr, *actions_attr; 399 int err; 400 401 entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY); 402 if (!entry_attr) 403 return -EMSGSIZE; 404 405 if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index)) 406 goto nla_put_failure; 407 if (entry->counter_valid) 408 if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER, 409 entry->counter)) 410 goto nla_put_failure; 411 412 matches_attr = nla_nest_start_noflag(skb, 413 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES); 414 if (!matches_attr) 415 goto nla_put_failure; 416 417 err = devlink_dpipe_match_values_put(skb, entry->match_values, 418 entry->match_values_count); 419 if (err) { 420 nla_nest_cancel(skb, matches_attr); 421 goto err_match_values_put; 422 } 423 nla_nest_end(skb, matches_attr); 424 425 actions_attr = nla_nest_start_noflag(skb, 426 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES); 427 if (!actions_attr) 428 goto nla_put_failure; 429 430 err = devlink_dpipe_action_values_put(skb, entry->action_values, 431 entry->action_values_count); 432 if (err) { 433 nla_nest_cancel(skb, actions_attr); 434 goto err_action_values_put; 435 } 436 nla_nest_end(skb, actions_attr); 437 438 nla_nest_end(skb, entry_attr); 439 return 0; 440 441 nla_put_failure: 442 err = -EMSGSIZE; 443 err_match_values_put: 444 err_action_values_put: 445 nla_nest_cancel(skb, entry_attr); 446 return err; 447 } 448 449 static struct devlink_dpipe_table * 450 devlink_dpipe_table_find(struct list_head *dpipe_tables, 451 const char *table_name, struct devlink *devlink) 452 { 453 struct devlink_dpipe_table *table; 454 455 list_for_each_entry_rcu(table, dpipe_tables, list, 456 lockdep_is_held(&devlink->lock)) { 457 if (!strcmp(table->name, table_name)) 458 return table; 459 } 460 return NULL; 461 } 462 463 int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx) 464 { 465 struct devlink *devlink; 466 int err; 467 468 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb, 469 dump_ctx->info); 470 if (err) 471 return err; 472 473 dump_ctx->hdr = genlmsg_put(dump_ctx->skb, 474 dump_ctx->info->snd_portid, 475 dump_ctx->info->snd_seq, 476 &devlink_nl_family, NLM_F_MULTI, 477 dump_ctx->cmd); 478 if (!dump_ctx->hdr) 479 goto nla_put_failure; 480 481 devlink = dump_ctx->info->user_ptr[0]; 482 if (devlink_nl_put_handle(dump_ctx->skb, devlink)) 483 goto nla_put_failure; 484 dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb, 485 DEVLINK_ATTR_DPIPE_ENTRIES); 486 if (!dump_ctx->nest) 487 goto nla_put_failure; 488 return 0; 489 490 nla_put_failure: 491 nlmsg_free(dump_ctx->skb); 492 return -EMSGSIZE; 493 } 494 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare); 495 496 int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx, 497 struct devlink_dpipe_entry *entry) 498 { 499 return devlink_dpipe_entry_put(dump_ctx->skb, entry); 500 } 501 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append); 502 503 int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx) 504 { 505 nla_nest_end(dump_ctx->skb, dump_ctx->nest); 506 genlmsg_end(dump_ctx->skb, dump_ctx->hdr); 507 return 0; 508 } 509 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close); 510 511 void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry) 512 513 { 514 unsigned int value_count, value_index; 515 struct devlink_dpipe_value *value; 516 517 value = entry->action_values; 518 value_count = entry->action_values_count; 519 for (value_index = 0; value_index < value_count; value_index++) { 520 kfree(value[value_index].value); 521 kfree(value[value_index].mask); 522 } 523 524 value = entry->match_values; 525 value_count = entry->match_values_count; 526 for (value_index = 0; value_index < value_count; value_index++) { 527 kfree(value[value_index].value); 528 kfree(value[value_index].mask); 529 } 530 } 531 EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear); 532 533 static int devlink_dpipe_entries_fill(struct genl_info *info, 534 enum devlink_command cmd, int flags, 535 struct devlink_dpipe_table *table) 536 { 537 struct devlink_dpipe_dump_ctx dump_ctx; 538 struct nlmsghdr *nlh; 539 int err; 540 541 dump_ctx.skb = NULL; 542 dump_ctx.cmd = cmd; 543 dump_ctx.info = info; 544 545 err = table->table_ops->entries_dump(table->priv, 546 table->counters_enabled, 547 &dump_ctx); 548 if (err) 549 return err; 550 551 send_done: 552 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq, 553 NLMSG_DONE, 0, flags | NLM_F_MULTI); 554 if (!nlh) { 555 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info); 556 if (err) 557 return err; 558 goto send_done; 559 } 560 return genlmsg_reply(dump_ctx.skb, info); 561 } 562 563 int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb, 564 struct genl_info *info) 565 { 566 struct devlink *devlink = info->user_ptr[0]; 567 struct devlink_dpipe_table *table; 568 const char *table_name; 569 570 if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME)) 571 return -EINVAL; 572 573 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 574 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 575 table_name, devlink); 576 if (!table) 577 return -EINVAL; 578 579 if (!table->table_ops->entries_dump) 580 return -EINVAL; 581 582 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET, 583 0, table); 584 } 585 586 static int devlink_dpipe_fields_put(struct sk_buff *skb, 587 const struct devlink_dpipe_header *header) 588 { 589 struct devlink_dpipe_field *field; 590 struct nlattr *field_attr; 591 int i; 592 593 for (i = 0; i < header->fields_count; i++) { 594 field = &header->fields[i]; 595 field_attr = nla_nest_start_noflag(skb, 596 DEVLINK_ATTR_DPIPE_FIELD); 597 if (!field_attr) 598 return -EMSGSIZE; 599 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) || 600 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) || 601 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) || 602 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type)) 603 goto nla_put_failure; 604 nla_nest_end(skb, field_attr); 605 } 606 return 0; 607 608 nla_put_failure: 609 nla_nest_cancel(skb, field_attr); 610 return -EMSGSIZE; 611 } 612 613 static int devlink_dpipe_header_put(struct sk_buff *skb, 614 struct devlink_dpipe_header *header) 615 { 616 struct nlattr *fields_attr, *header_attr; 617 int err; 618 619 header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER); 620 if (!header_attr) 621 return -EMSGSIZE; 622 623 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) || 624 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) || 625 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global)) 626 goto nla_put_failure; 627 628 fields_attr = nla_nest_start_noflag(skb, 629 DEVLINK_ATTR_DPIPE_HEADER_FIELDS); 630 if (!fields_attr) 631 goto nla_put_failure; 632 633 err = devlink_dpipe_fields_put(skb, header); 634 if (err) { 635 nla_nest_cancel(skb, fields_attr); 636 goto nla_put_failure; 637 } 638 nla_nest_end(skb, fields_attr); 639 nla_nest_end(skb, header_attr); 640 return 0; 641 642 nla_put_failure: 643 err = -EMSGSIZE; 644 nla_nest_cancel(skb, header_attr); 645 return err; 646 } 647 648 static int devlink_dpipe_headers_fill(struct genl_info *info, 649 enum devlink_command cmd, int flags, 650 struct devlink_dpipe_headers * 651 dpipe_headers) 652 { 653 struct devlink *devlink = info->user_ptr[0]; 654 struct nlattr *headers_attr; 655 struct sk_buff *skb = NULL; 656 struct nlmsghdr *nlh; 657 void *hdr; 658 int i, j; 659 int err; 660 661 i = 0; 662 start_again: 663 err = devlink_dpipe_send_and_alloc_skb(&skb, info); 664 if (err) 665 return err; 666 667 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 668 &devlink_nl_family, NLM_F_MULTI, cmd); 669 if (!hdr) { 670 nlmsg_free(skb); 671 return -EMSGSIZE; 672 } 673 674 if (devlink_nl_put_handle(skb, devlink)) 675 goto nla_put_failure; 676 headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS); 677 if (!headers_attr) 678 goto nla_put_failure; 679 680 j = 0; 681 for (; i < dpipe_headers->headers_count; i++) { 682 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]); 683 if (err) { 684 if (!j) 685 goto err_table_put; 686 break; 687 } 688 j++; 689 } 690 nla_nest_end(skb, headers_attr); 691 genlmsg_end(skb, hdr); 692 if (i != dpipe_headers->headers_count) 693 goto start_again; 694 695 send_done: 696 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, 697 NLMSG_DONE, 0, flags | NLM_F_MULTI); 698 if (!nlh) { 699 err = devlink_dpipe_send_and_alloc_skb(&skb, info); 700 if (err) 701 return err; 702 goto send_done; 703 } 704 return genlmsg_reply(skb, info); 705 706 nla_put_failure: 707 err = -EMSGSIZE; 708 err_table_put: 709 nlmsg_free(skb); 710 return err; 711 } 712 713 int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb, 714 struct genl_info *info) 715 { 716 struct devlink *devlink = info->user_ptr[0]; 717 718 if (!devlink->dpipe_headers) 719 return -EOPNOTSUPP; 720 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET, 721 0, devlink->dpipe_headers); 722 } 723 724 static int devlink_dpipe_table_counters_set(struct devlink *devlink, 725 const char *table_name, 726 bool enable) 727 { 728 struct devlink_dpipe_table *table; 729 730 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 731 table_name, devlink); 732 if (!table) 733 return -EINVAL; 734 735 if (table->counter_control_extern) 736 return -EOPNOTSUPP; 737 738 if (!(table->counters_enabled ^ enable)) 739 return 0; 740 741 table->counters_enabled = enable; 742 if (table->table_ops->counters_set_update) 743 table->table_ops->counters_set_update(table->priv, enable); 744 return 0; 745 } 746 747 int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb, 748 struct genl_info *info) 749 { 750 struct devlink *devlink = info->user_ptr[0]; 751 const char *table_name; 752 bool counters_enable; 753 754 if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME) || 755 GENL_REQ_ATTR_CHECK(info, 756 DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED)) 757 return -EINVAL; 758 759 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]); 760 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]); 761 762 return devlink_dpipe_table_counters_set(devlink, table_name, 763 counters_enable); 764 } 765 766 /** 767 * devl_dpipe_headers_register - register dpipe headers 768 * 769 * @devlink: devlink 770 * @dpipe_headers: dpipe header array 771 * 772 * Register the headers supported by hardware. 773 */ 774 void devl_dpipe_headers_register(struct devlink *devlink, 775 struct devlink_dpipe_headers *dpipe_headers) 776 { 777 lockdep_assert_held(&devlink->lock); 778 779 devlink->dpipe_headers = dpipe_headers; 780 } 781 EXPORT_SYMBOL_GPL(devl_dpipe_headers_register); 782 783 /** 784 * devl_dpipe_headers_unregister - unregister dpipe headers 785 * 786 * @devlink: devlink 787 * 788 * Unregister the headers supported by hardware. 789 */ 790 void devl_dpipe_headers_unregister(struct devlink *devlink) 791 { 792 lockdep_assert_held(&devlink->lock); 793 794 devlink->dpipe_headers = NULL; 795 } 796 EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister); 797 798 /** 799 * devlink_dpipe_table_counter_enabled - check if counter allocation 800 * required 801 * @devlink: devlink 802 * @table_name: tables name 803 * 804 * Used by driver to check if counter allocation is required. 805 * After counter allocation is turned on the table entries 806 * are updated to include counter statistics. 807 * 808 * After that point on the driver must respect the counter 809 * state so that each entry added to the table is added 810 * with a counter. 811 */ 812 bool devlink_dpipe_table_counter_enabled(struct devlink *devlink, 813 const char *table_name) 814 { 815 struct devlink_dpipe_table *table; 816 bool enabled; 817 818 rcu_read_lock(); 819 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 820 table_name, devlink); 821 enabled = false; 822 if (table) 823 enabled = table->counters_enabled; 824 rcu_read_unlock(); 825 return enabled; 826 } 827 EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled); 828 829 /** 830 * devl_dpipe_table_register - register dpipe table 831 * 832 * @devlink: devlink 833 * @table_name: table name 834 * @table_ops: table ops 835 * @priv: priv 836 * @counter_control_extern: external control for counters 837 */ 838 int devl_dpipe_table_register(struct devlink *devlink, 839 const char *table_name, 840 const struct devlink_dpipe_table_ops *table_ops, 841 void *priv, bool counter_control_extern) 842 { 843 struct devlink_dpipe_table *table; 844 845 lockdep_assert_held(&devlink->lock); 846 847 if (WARN_ON(!table_ops->size_get)) 848 return -EINVAL; 849 850 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name, 851 devlink)) 852 return -EEXIST; 853 854 table = kzalloc(sizeof(*table), GFP_KERNEL); 855 if (!table) 856 return -ENOMEM; 857 858 table->name = table_name; 859 table->table_ops = table_ops; 860 table->priv = priv; 861 table->counter_control_extern = counter_control_extern; 862 863 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list); 864 865 return 0; 866 } 867 EXPORT_SYMBOL_GPL(devl_dpipe_table_register); 868 869 /** 870 * devl_dpipe_table_unregister - unregister dpipe table 871 * 872 * @devlink: devlink 873 * @table_name: table name 874 */ 875 void devl_dpipe_table_unregister(struct devlink *devlink, 876 const char *table_name) 877 { 878 struct devlink_dpipe_table *table; 879 880 lockdep_assert_held(&devlink->lock); 881 882 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 883 table_name, devlink); 884 if (!table) 885 return; 886 list_del_rcu(&table->list); 887 kfree_rcu(table, rcu); 888 } 889 EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister); 890 891 /** 892 * devl_dpipe_table_resource_set - set the resource id 893 * 894 * @devlink: devlink 895 * @table_name: table name 896 * @resource_id: resource id 897 * @resource_units: number of resource's units consumed per table's entry 898 */ 899 int devl_dpipe_table_resource_set(struct devlink *devlink, 900 const char *table_name, u64 resource_id, 901 u64 resource_units) 902 { 903 struct devlink_dpipe_table *table; 904 905 table = devlink_dpipe_table_find(&devlink->dpipe_table_list, 906 table_name, devlink); 907 if (!table) 908 return -EINVAL; 909 910 table->resource_id = resource_id; 911 table->resource_units = resource_units; 912 table->resource_valid = true; 913 return 0; 914 } 915 EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set); 916