1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2015 Arne Kappen <arne.kappen@hhi.fraunhofer.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 7 * as published by the Free Software Foundation 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * 15 * extdev - external device handler interface 16 * 17 * This allows to integrate external daemons that configure network devices 18 * with netifd. At startup, netifd generates device handler stubs from 19 * descriptions in /lib/netifd/extdev-config and adds them to the list of 20 * device handlers. A device handler is an instance of struct device_type 21 * The descriptions are in JSON format and specify 22 * - names of the device type and of the external device handler on ubus, 23 * - whether the device is bridge-like, 24 * - a prefix for device names, 25 * - the UCI config options for devices of this type, and 26 * - the format of calls to dump() and info() 27 * These device handlers stubs act as relays forwarding calls against the 28 * device handler interface to the external daemon. 29 */ 30 31 #include <libubox/blobmsg.h> 32 #include <libubox/list.h> 33 #include <libubus.h> 34 #include <assert.h> 35 36 #include "netifd.h" 37 #include "handler.h" 38 #include "device.h" 39 #include "ubus.h" 40 #include "extdev.h" 41 #include "interface.h" 42 #include "system.h" 43 44 45 static struct blob_buf b; 46 static int confdir_fd = -1; 47 48 struct extdev_type { 49 struct device_type handler; 50 51 const char *name; 52 uint32_t peer_id; 53 struct ubus_subscriber ubus_sub; 54 bool subscribed; 55 struct ubus_event_handler obj_wait; 56 57 struct uci_blob_param_list *config_params; 58 char *config_strbuf; 59 60 struct uci_blob_param_list *info_params; 61 char *info_strbuf; 62 63 struct uci_blob_param_list *stats_params; 64 char *stats_strbuf; 65 }; 66 67 struct extdev_device { 68 struct device dev; 69 struct extdev_type *etype; 70 const char *dep_name; 71 struct uloop_timeout retry; 72 }; 73 74 struct extdev_bridge { 75 struct extdev_device edev; 76 device_state_cb set_state; 77 78 struct blob_attr *config; 79 bool empty; 80 struct blob_attr *ifnames; 81 bool active; 82 bool force_active; 83 84 struct uloop_timeout retry; 85 struct vlist_tree members; 86 int n_present; 87 int n_failed; 88 }; 89 90 struct extdev_bridge_member { 91 struct vlist_node node; 92 struct extdev_bridge *parent_br; 93 struct device_user dev_usr; 94 bool present; 95 char *name; 96 }; 97 98 static void __bridge_config_init(struct extdev_bridge *ebr); 99 static enum dev_change_type __bridge_reload(struct extdev_bridge *ebr, struct blob_attr *config); 100 101 enum { 102 METHOD_CREATE, 103 METHOD_CONFIG_INIT, 104 METHOD_RELOAD, 105 METHOD_DUMP_INFO, 106 METHOD_DUMP_STATS, 107 METHOD_CHECK_STATE, 108 METHOD_FREE, 109 METHOD_HOTPLUG_PREPARE, 110 METHOD_HOTPLUG_ADD, 111 METHOD_HOTPLUG_REMOVE, 112 __METHODS_MAX 113 }; 114 115 static const char *__extdev_methods[__METHODS_MAX] = { 116 [METHOD_CREATE] = "create", 117 [METHOD_CONFIG_INIT] = "config_init", 118 [METHOD_RELOAD] = "reload", 119 [METHOD_DUMP_INFO] = "dump_info", 120 [METHOD_DUMP_STATS] = "dump_stats", 121 [METHOD_CHECK_STATE] = "check_state", 122 [METHOD_FREE] = "free", 123 [METHOD_HOTPLUG_PREPARE] = "prepare", 124 [METHOD_HOTPLUG_ADD] = "add", 125 [METHOD_HOTPLUG_REMOVE] = "remove", 126 }; 127 128 static inline int 129 netifd_extdev_create(struct extdev_device *edev, struct blob_attr *msg) 130 { 131 D(DEVICE, "create %s '%s' at external device handler", edev->dev.type->name, 132 edev->dev.ifname); 133 return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_CREATE], msg, 134 NULL, NULL); 135 } 136 137 static inline int 138 netifd_extdev_reload(struct extdev_device *edev, struct blob_attr *msg) 139 { 140 D(DEVICE, "reload %s '%s' at external device handler", edev->dev.type->name, 141 edev->dev.ifname); 142 return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_RELOAD], msg, 143 NULL, NULL); 144 } 145 146 static inline int 147 netifd_extdev_free(struct extdev_device *edev, struct blob_attr *msg) 148 { 149 D(DEVICE, "delete %s '%s' with external device handler", edev->dev.type->name, 150 edev->dev.ifname); 151 return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_FREE], msg, 152 NULL, NULL); 153 } 154 155 static inline int 156 netifd_extdev_prepare(struct extdev_bridge *ebr, struct blob_attr *msg) 157 { 158 D(DEVICE, "prepare %s bridge '%s' at external device handler", ebr->edev.dev.type->name, 159 ebr->edev.dev.ifname); 160 return netifd_extdev_invoke(ebr->edev.etype->peer_id, 161 __extdev_methods[METHOD_HOTPLUG_PREPARE], msg, NULL, NULL); 162 } 163 164 static inline int 165 netifd_extdev_add(struct extdev_bridge *ebr, struct blob_attr *msg) 166 { 167 D(DEVICE, "add a member to %s bridge '%s' at external device handler", 168 ebr->edev.dev.type->name, ebr->edev.dev.ifname); 169 return netifd_extdev_invoke(ebr->edev.etype->peer_id, 170 __extdev_methods[METHOD_HOTPLUG_ADD], msg,NULL, NULL); 171 } 172 173 static inline int 174 netifd_extdev_remove(struct extdev_bridge *ebr, struct blob_attr *msg) 175 { 176 D(DEVICE, "remove a member from %s bridge '%s' at external device handler", 177 ebr->edev.dev.type->name, ebr->edev.dev.ifname); 178 return netifd_extdev_invoke(ebr->edev.etype->peer_id, 179 __extdev_methods[METHOD_HOTPLUG_REMOVE], msg, NULL, NULL); 180 } 181 182 static inline void 183 extdev_invocation_error(int error, const char *method, const char *devname) 184 { 185 netifd_log_message(L_CRIT, "'%s' failed for '%s': %s\n", 186 method, devname, ubus_strerror(error)); 187 } 188 189 static struct ubus_method extdev_ubus_obj_methods[] = {}; 190 191 static struct ubus_object_type extdev_ubus_object_type = 192 UBUS_OBJECT_TYPE("netifd_extdev", extdev_ubus_obj_methods); 193 194 static int 195 extdev_lookup_id(struct extdev_type *etype) 196 { 197 int ret = UBUS_STATUS_UNKNOWN_ERROR; 198 199 if (!etype || !etype->name) 200 goto error; 201 202 ret = ubus_lookup_id(ubus_ctx, etype->name, &etype->peer_id); 203 if (ret) 204 goto error; 205 206 return 0; 207 208 error: 209 netifd_log_message(L_CRIT, "Could not find '%s' ubus ID: %s\n", 210 etype->name, ubus_strerror(ret)); 211 return ret; 212 } 213 214 static int 215 extdev_ext_ubus_obj_wait(struct ubus_event_handler *h) 216 { 217 return ubus_register_event_handler(ubus_ctx, h, "ubus.object.add"); 218 } 219 220 static int 221 extdev_subscribe(struct extdev_type *etype) 222 { 223 int ret; 224 225 ret = extdev_lookup_id(etype); 226 if (ret) { 227 etype->subscribed = false; 228 return ret; 229 } 230 231 ret = ubus_subscribe(ubus_ctx, &etype->ubus_sub, etype->peer_id); 232 if (ret) { 233 etype->subscribed = false; 234 extdev_ext_ubus_obj_wait(&etype->obj_wait); 235 } else { 236 netifd_log_message(L_NOTICE, "subscribed to external device handler '%s'\n", 237 etype->name); 238 etype->subscribed = true; 239 } 240 241 return ret; 242 } 243 244 static void 245 extdev_wait_ev_cb(struct ubus_context *ctx, struct ubus_event_handler *ev_handler, 246 const char *type, struct blob_attr *msg) 247 { 248 static const struct blobmsg_policy wait_policy = { 249 "path", BLOBMSG_TYPE_STRING 250 }; 251 252 struct blob_attr *attr; 253 const char *path; 254 struct extdev_type *etype; 255 256 etype = container_of(ev_handler, struct extdev_type, obj_wait); 257 258 if (strcmp(type, "ubus.object.add")) 259 return; 260 261 blobmsg_parse(&wait_policy, 1, &attr, blob_data(msg), blob_len(msg)); 262 if (!attr) 263 return; 264 265 path = blobmsg_data(attr); 266 if (strcmp(etype->name, path)) 267 return; 268 269 extdev_subscribe(etype); 270 } 271 272 static int 273 extdev_bridge_disable_interface(struct extdev_bridge *ebr) 274 { 275 int ret; 276 277 if (!ebr->active) 278 return 0; 279 280 blob_buf_init(&b, 0); 281 blobmsg_add_string(&b, "name", ebr->edev.dev.ifname); 282 283 ret = netifd_extdev_free(&ebr->edev, b.head); 284 285 if (ret && ret != UBUS_STATUS_NOT_FOUND) 286 goto error; 287 288 ebr->active = false; 289 return 0; 290 291 error: 292 extdev_invocation_error(ret, __extdev_methods[METHOD_FREE], ebr->edev.dev.ifname); 293 return ret; 294 } 295 296 static int 297 extdev_bridge_enable_interface(struct extdev_bridge *ebr) 298 { 299 int ret; 300 301 if (ebr->active) 302 return 0; 303 304 ret = netifd_extdev_create(&ebr->edev, ebr->config); 305 if (ret) 306 goto error; 307 308 ebr->active = true; 309 return 0; 310 311 error: 312 extdev_invocation_error(ret, __extdev_methods[METHOD_CREATE], ebr->edev.dev.ifname); 313 return ret; 314 } 315 316 static int 317 extdev_bridge_enable_member(struct extdev_bridge_member *ubm) 318 { 319 int ret; 320 struct extdev_bridge *ebr = ubm->parent_br; 321 322 D(DEVICE, "%s enable member %s", ebr->edev.dev.ifname, ubm->name); 323 324 if (!ubm->present) 325 return 0; 326 327 ret = extdev_bridge_enable_interface(ebr); 328 if (ret) 329 goto error; 330 331 ret = device_claim(&ubm->dev_usr); 332 if (ret < 0) 333 goto error; 334 335 blob_buf_init(&b, 0); 336 blobmsg_add_string(&b, "bridge", ebr->edev.dev.ifname); 337 blobmsg_add_string(&b, "member", ubm->dev_usr.dev->ifname); 338 339 /* use hotplug add as addif equivalent. Maybe we need a dedicated ubus 340 * method on the external handler for this sort of operation. */ 341 ret = netifd_extdev_add(ebr, b.head); 342 if (ret) { 343 extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_ADD], 344 ubm->dev_usr.dev->ifname); 345 goto error; 346 } 347 348 device_set_present(&ebr->edev.dev, true); 349 device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE); 350 351 return 0; 352 353 error: 354 D(DEVICE, "%s: failed to enable member '%s'", ebr->edev.dev.ifname, ubm->name); 355 356 ebr->n_failed++; 357 ubm->present = false; 358 ebr->n_present--; 359 360 return ret; 361 } 362 363 static int 364 extdev_bridge_disable_member(struct extdev_bridge_member *ubm) 365 { 366 int ret; 367 struct extdev_bridge *ebr = ubm->parent_br; 368 369 if (!ubm->present) 370 return 0; 371 372 D(DEVICE, "%s disable member %s", ubm->parent_br->edev.dev.ifname, ubm->name); 373 374 blob_buf_init(&b, 0); 375 blobmsg_add_string(&b, "bridge", ebr->edev.dev.ifname); 376 blobmsg_add_string(&b, "member", ubm->dev_usr.dev->ifname); 377 378 /* use hotplug remove as delif equivalent. Maybe we need a dedicated 379 * ubus method on the external handler for this sort of operation. */ 380 ret = netifd_extdev_remove(ebr, b.head); 381 382 /* continue in case of NOT FOUND since we're trying to remove anyway */ 383 if (ret && ret != UBUS_STATUS_NOT_FOUND) 384 goto error; 385 386 device_release(&ubm->dev_usr); 387 device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE); 388 389 return 0; 390 391 error: 392 extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_REMOVE], 393 ubm->dev_usr.dev->ifname); 394 395 return ret; 396 } 397 398 static int 399 extdev_bridge_set_down(struct extdev_bridge *ebr) 400 { 401 D(DEVICE, "set %s bridge %s down", ebr->edev.dev.type->name, ebr->edev.dev.ifname); 402 403 struct extdev_bridge_member *ubm; 404 405 ebr->set_state(&ebr->edev.dev, false); 406 407 vlist_for_each_element(&ebr->members, ubm, node) 408 extdev_bridge_disable_member(ubm); 409 410 extdev_bridge_disable_interface(ebr); 411 412 return 0; 413 } 414 415 static void 416 extdev_bridge_check_retry(struct extdev_bridge *ebr) 417 { 418 if (!ebr->n_failed) 419 return; 420 421 uloop_timeout_set(&ebr->retry, 200); 422 } 423 424 static int 425 extdev_bridge_set_up(struct extdev_bridge *ebr) 426 { 427 D(DEVICE, "set %s bridge %s up", ebr->edev.dev.type->name, ebr->edev.dev.ifname); 428 429 struct extdev_bridge_member *ubm; 430 int ret; 431 432 if (!ebr->n_present) { 433 if (!ebr->force_active) 434 return -ENOENT; 435 436 ret = extdev_bridge_enable_interface(ebr); 437 if (ret) 438 return ret; 439 } 440 441 ebr->n_failed = 0; 442 vlist_for_each_element(&ebr->members, ubm, node) 443 extdev_bridge_enable_member(ubm); 444 445 extdev_bridge_check_retry(ebr); 446 447 if (!ebr->force_active && !ebr->n_present) { 448 extdev_bridge_disable_interface(ebr); 449 device_set_present(&ebr->edev.dev, false); 450 return -ENOENT; 451 } 452 453 return 0; 454 } 455 456 static int 457 extdev_bridge_set_state(struct device *dev, bool up) 458 { 459 struct extdev_bridge *ebr; 460 461 if (!dev->type->bridge_capability) 462 return -1; 463 464 ebr = container_of(dev, struct extdev_bridge, edev.dev); 465 466 if (up) 467 return extdev_bridge_set_up(ebr); 468 else 469 return extdev_bridge_set_down(ebr); 470 } 471 472 static void 473 extdev_bridge_remove_member(struct extdev_bridge_member *member) 474 { 475 struct extdev_bridge *ebr = member->parent_br; 476 477 if (!member->present) 478 return; 479 480 if (ebr->edev.dev.active) 481 extdev_bridge_disable_member(member); 482 483 member->present = false; 484 ebr->n_present--; 485 486 if (ebr->empty) 487 return; 488 489 ebr->force_active = false; 490 if (ebr->n_present == 0) 491 device_set_present(&ebr->edev.dev, false); 492 } 493 494 static void 495 extdev_bridge_member_cb(struct device_user *usr, enum device_event event) 496 { 497 int ret; 498 struct extdev_bridge_member *ubm; 499 struct extdev_bridge *ebr; 500 501 ubm = container_of(usr, struct extdev_bridge_member, dev_usr); 502 ebr = ubm->parent_br; 503 504 switch (event) { 505 case DEV_EVENT_ADD: 506 assert(!ubm->present); 507 508 ubm->present = true; 509 ebr->n_present++; 510 511 /* if this member is the first one that is brought up, 512 * create the bridge at the external device handler */ 513 if (ebr->n_present == 1) { 514 ret = netifd_extdev_create(&ebr->edev, ebr->config); 515 if (ret) 516 goto error; 517 518 ebr->active = true; 519 ret = ebr->set_state(&ebr->edev.dev, true); 520 if (ret < 0) 521 extdev_bridge_set_down(ebr); 522 device_set_present(&ebr->edev.dev, true); 523 } 524 525 extdev_bridge_enable_member(ubm); 526 break; 527 case DEV_EVENT_REMOVE: 528 if (usr->hotplug) { 529 vlist_delete(&ebr->members, &ubm->node); 530 return; 531 } 532 533 if (ubm->present) 534 extdev_bridge_remove_member(ubm); 535 break; 536 default: 537 break; 538 } 539 540 return; 541 542 error: 543 netifd_log_message(L_CRIT, "Failed to create %s bridge %s: %s\n", 544 ebr->edev.dev.type->name, ebr->edev.dev.ifname, ubus_strerror(ret)); 545 ubm->present = false; 546 ebr->n_present--; 547 } 548 549 static void 550 __bridge_enable_members(struct extdev_bridge *ebr) 551 { 552 struct extdev_bridge_member *cur; 553 554 ebr->n_failed = 0; 555 556 vlist_for_each_element(&ebr->members, cur, node) { 557 if (cur->present) 558 continue; 559 560 if (!cur->dev_usr.dev->present) 561 continue; 562 563 cur->present = true; 564 ebr->n_present++; 565 extdev_bridge_enable_member(cur); 566 } 567 } 568 569 static void 570 extdev_bridge_retry_enable_members(struct uloop_timeout *timeout) 571 { 572 struct extdev_bridge *ebr = container_of(timeout, struct extdev_bridge, retry); 573 574 D(DEVICE, "%s retry enable members", ebr->edev.dev.ifname); 575 576 __bridge_enable_members(ebr); 577 } 578 579 static struct extdev_bridge_member * 580 extdev_bridge_create_member(struct extdev_bridge *ebr, struct device *dev) 581 { 582 struct extdev_bridge_member *ubm; 583 char *name; 584 585 ubm = calloc_a(sizeof(*ubm), &name, strlen(dev->ifname) + 1); 586 if (!ubm) 587 return NULL; 588 589 ubm->parent_br = ebr; 590 ubm->name = name; 591 strcpy(name, dev->ifname); 592 ubm->dev_usr.dev = dev; 593 ubm->dev_usr.cb = extdev_bridge_member_cb; 594 vlist_add(&ebr->members, &ubm->node, ubm->name); 595 /* Need to look up the bridge member again as the above 596 * created pointer will be freed in case the bridge member 597 * already existed */ 598 ubm = vlist_find(&ebr->members, dev->ifname, ubm, node); 599 if (!ubm) 600 return NULL; 601 602 return ubm; 603 } 604 605 static void 606 extdev_bridge_add_member(struct extdev_bridge *ebr, const char *name) 607 { 608 D(DEVICE, "%s add member %s", ebr->edev.dev.ifname, name); 609 610 struct device *dev; 611 612 dev = device_get(name, 1); 613 if (!dev) 614 return; 615 616 extdev_bridge_create_member(ebr, dev); 617 } 618 619 /* TODO: how to handle vlan arg? */ 620 static int 621 extdev_hotplug_add(struct device *ebr_dev, struct device *ebm_dev, struct blob_attr *vlan) 622 { 623 D(DEVICE, "%s hotplug add member %s", ebr_dev->ifname, ebm_dev->ifname); 624 625 struct extdev_bridge *ebr; 626 struct extdev_bridge_member *ubm; 627 628 if (!ebr_dev->type->bridge_capability) 629 return UBUS_STATUS_NOT_SUPPORTED; 630 631 ebr = container_of(ebr_dev, struct extdev_bridge, edev.dev); 632 633 if (!ebr->edev.etype->subscribed) 634 return UBUS_STATUS_NOT_FOUND; 635 636 ubm = extdev_bridge_create_member(ebr, ebm_dev); 637 if (!ubm) 638 return UBUS_STATUS_UNKNOWN_ERROR; 639 640 device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE); 641 642 return 0; 643 } 644 645 static int 646 extdev_hotplug_remove(struct device *dev, struct device *member, struct blob_attr *vlan) 647 { 648 struct extdev_bridge *ebr; 649 struct extdev_bridge_member *ubm; 650 651 if (!dev->type->bridge_capability) 652 return UBUS_STATUS_NOT_SUPPORTED; 653 654 ebr = container_of(dev, struct extdev_bridge, edev.dev); 655 656 if (!ebr->edev.etype->subscribed) 657 return UBUS_STATUS_NOT_FOUND; 658 659 ubm = vlist_find(&ebr->members, member->ifname, ubm, node); 660 if (!ubm) 661 return UBUS_STATUS_NOT_FOUND; 662 663 vlist_delete(&ebr->members, &ubm->node); 664 extdev_bridge_remove_member(ubm); 665 666 return 0; 667 } 668 669 static int 670 extdev_hotplug_prepare(struct device *dev, struct device **bridge_dev) 671 { 672 struct extdev_bridge *ebr; 673 int ret; 674 675 if (!dev->type->bridge_capability) 676 return UBUS_STATUS_NOT_SUPPORTED; 677 678 if (bridge_dev) 679 *bridge_dev = dev; 680 681 ebr = container_of(dev, struct extdev_bridge, edev.dev); 682 683 blob_buf_init(&b, 0); 684 blobmsg_add_string(&b, "name", dev->ifname); 685 686 ret = netifd_extdev_prepare(ebr, b.head); 687 if (ret) 688 goto error; 689 690 ebr->force_active = true; 691 device_set_present(&ebr->edev.dev, true); 692 693 return 0; 694 695 error: 696 extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_PREPARE], dev->ifname); 697 return ret; 698 } 699 700 static void 701 extdev_bridge_free_member(struct extdev_bridge_member *ubm) 702 { 703 struct device *dev = ubm->dev_usr.dev; 704 705 extdev_bridge_remove_member(ubm); 706 device_remove_user(&ubm->dev_usr); 707 708 if (dev->present) { 709 device_set_present(dev, false); 710 device_set_present(dev, true); 711 } 712 713 free(ubm); 714 } 715 716 static void 717 extdev_bridge_member_update(struct vlist_tree *tree, struct vlist_node *node_new, 718 struct vlist_node *node_old) 719 { 720 struct extdev_bridge_member *ubm; 721 struct device *dev; 722 723 if (node_new) { 724 ubm = container_of(node_new, struct extdev_bridge_member, node); 725 726 if (node_old) { 727 free(ubm); 728 return; 729 } 730 731 dev = ubm->dev_usr.dev; 732 ubm->dev_usr.dev = NULL; 733 device_add_user(&ubm->dev_usr, dev); 734 } 735 736 if (node_old) { 737 ubm = container_of(node_old, struct extdev_bridge_member, node); 738 extdev_bridge_free_member(ubm); 739 } 740 } 741 742 743 static void 744 bridge_dependency_retry(struct uloop_timeout *timeout) 745 { 746 struct extdev_bridge *ebr; 747 748 ebr = container_of(timeout, struct extdev_bridge, edev.retry); 749 750 __bridge_reload(ebr, NULL); 751 } 752 753 static void 754 __buf_add_all(struct blob_attr *attr) 755 { 756 struct blob_attr *cur; 757 size_t rem; 758 759 blobmsg_for_each_attr(cur, attr, rem) 760 blobmsg_add_field(&b, blobmsg_type(cur), blobmsg_name(cur), blobmsg_data(cur), 761 blobmsg_data_len(cur)); 762 } 763 764 enum { 765 BRIDGE_EMPTY, 766 BRIDGE_IFNAMES, 767 BRIDGE_DEPENDS_ON, 768 __BRIDGE_MAX 769 }; 770 771 static const struct blobmsg_policy brpol[__BRIDGE_MAX] = { 772 [BRIDGE_EMPTY] = { "empty", BLOBMSG_TYPE_BOOL }, 773 [BRIDGE_IFNAMES] = { "ifname", BLOBMSG_TYPE_ARRAY }, 774 [BRIDGE_DEPENDS_ON] = { "depends_on", BLOBMSG_TYPE_STRING }, 775 }; 776 777 static enum dev_change_type 778 __do_bridge_reload(struct extdev_bridge *ebr, struct blob_attr *config) 779 { 780 void *cfg_table; 781 int ret; 782 783 blob_buf_init(&b, 0); 784 cfg_table = blobmsg_open_table(&b, "old"); 785 __buf_add_all(ebr->config); 786 blobmsg_close_table(&b, cfg_table); 787 cfg_table = blobmsg_open_table(&b, "new"); 788 __buf_add_all(config); 789 blobmsg_close_table(&b, cfg_table); 790 791 ret = netifd_extdev_reload(&ebr->edev, b.head); 792 793 if (ret) { 794 netifd_log_message(L_WARNING, "%s config reload failed: %s\n", 795 ebr->edev.dev.ifname, ubus_strerror(ret)); 796 return DEV_CONFIG_RECREATE; 797 } else { 798 return DEV_CONFIG_RESTART; 799 } 800 } 801 802 static enum dev_change_type 803 __bridge_reload(struct extdev_bridge *ebr, struct blob_attr *config) 804 { 805 int n_params = ebr->edev.dev.type->config_params->n_params; 806 struct blob_attr *tb[__BRIDGE_MAX]; 807 const struct uci_blob_param_list *config_params; 808 const struct blobmsg_policy *pol; 809 struct blob_attr *old_tb[n_params], *brtb[n_params]; 810 enum dev_change_type change = DEV_CONFIG_APPLIED; 811 struct device *dev; 812 unsigned long diff = 0; 813 814 if (config) { 815 config = blob_memdup(config); 816 blobmsg_parse(brpol, __BRIDGE_MAX, tb, blobmsg_data(config), blobmsg_len(config)); 817 ebr->edev.dep_name = blobmsg_get_string(tb[BRIDGE_DEPENDS_ON]); 818 819 if (tb[BRIDGE_EMPTY] && blobmsg_get_bool(tb[BRIDGE_EMPTY])) 820 ebr->empty = true; 821 822 if (ebr->config) { 823 config_params = ebr->edev.dev.type->config_params; 824 pol = config_params->params; 825 826 blobmsg_parse(pol, n_params, old_tb, blobmsg_data(ebr->config), 827 blobmsg_len(ebr->config)); 828 blobmsg_parse(pol, n_params, brtb, blobmsg_data(config), blobmsg_len 829 (config)); 830 831 diff = 0; 832 uci_blob_diff(brtb, old_tb, config_params, &diff); 833 if (diff) { 834 if (diff & ~(1 << BRIDGE_IFNAMES)) { 835 change = DEV_CONFIG_RESTART; 836 } else { 837 change = __do_bridge_reload(ebr, config); 838 } 839 840 free(ebr->config); 841 } 842 } 843 844 ebr->ifnames = tb[BRIDGE_IFNAMES]; 845 ebr->config = config; 846 } 847 848 if (ebr->edev.dep_name) { 849 dev = device_get(ebr->edev.dep_name, 0); 850 if (!(dev && dev->current_config)) { 851 D(DEVICE, "%s: cannot yet init config since dependency '%s' is not ready", 852 ebr->edev.dev.ifname, ebr->edev.dep_name); 853 ebr->edev.retry.cb = bridge_dependency_retry; 854 uloop_timeout_set(&ebr->edev.retry, 200); 855 return DEV_CONFIG_RESTART; 856 } 857 } 858 859 __bridge_config_init(ebr); 860 ebr->edev.dev.config_pending = false; 861 uloop_timeout_cancel(&ebr->edev.retry); 862 863 return change; 864 } 865 866 static enum dev_change_type 867 __reload(struct extdev_device *edev, struct blob_attr *config) 868 { 869 unsigned long diff = 0; 870 struct uci_blob_param_list *params; 871 872 params = edev->etype->config_params; 873 874 struct blob_attr *tb[params->n_params]; 875 struct blob_attr *old_tb[params->n_params]; 876 877 blobmsg_parse(params->params, params->n_params, tb, blobmsg_data(config), 878 blobmsg_len(config)); 879 blobmsg_parse(params->params, params->n_params, old_tb, blobmsg_data(edev->dev.config), 880 blobmsg_len(edev->dev.config)); 881 882 uci_blob_diff(tb, old_tb, edev->etype->config_params, &diff); 883 if (!diff) 884 return DEV_CONFIG_NO_CHANGE; 885 886 // TODO: make reload ubus call with old and new config 887 888 device_set_present(&edev->dev, false); 889 device_set_present(&edev->dev, true); 890 891 return DEV_CONFIG_APPLIED; 892 } 893 894 static enum dev_change_type 895 extdev_reload(struct device *dev, struct blob_attr *config) 896 { 897 struct extdev_type *etype; 898 struct extdev_device *edev; 899 struct extdev_bridge *ebr; 900 901 etype = container_of(dev->type, struct extdev_type, handler); 902 903 if (!etype->subscribed) 904 return DEV_CONFIG_NO_CHANGE; 905 906 edev = container_of(dev, struct extdev_device, dev); 907 908 if (dev->type->bridge_capability) { 909 ebr = container_of(edev, struct extdev_bridge, edev); 910 return __bridge_reload(ebr, config); 911 } else { 912 return __reload(edev, config); 913 } 914 } 915 916 static struct device* 917 __create(const char *name, struct device_type *type, struct blob_attr *config) 918 { 919 struct extdev_device *edev; 920 struct extdev_type *etype; 921 int ret; 922 923 etype = container_of(type, struct extdev_type, handler); 924 edev = calloc(1, sizeof(struct extdev_device)); 925 if (!edev) 926 return NULL; 927 928 ret = device_init(&edev->dev, type, name); 929 if (ret) 930 goto error; 931 932 edev->etype = etype; 933 934 ret = netifd_extdev_create(edev, config); 935 if (ret) 936 goto inv_error; 937 938 edev->dev.config_pending = false; 939 940 return &edev->dev; 941 942 inv_error: 943 extdev_invocation_error(ret, __extdev_methods[METHOD_CREATE], name); 944 error: 945 free(edev->dev.config); 946 device_cleanup(&edev->dev); 947 free(edev); 948 netifd_log_message(L_WARNING, "Failed to create %s %s\n", type->name, name); 949 return NULL; 950 } 951 952 static const struct device_hotplug_ops extdev_hotplug_ops = { 953 .prepare = extdev_hotplug_prepare, 954 .add = extdev_hotplug_add, 955 .del = extdev_hotplug_remove 956 }; 957 958 static struct device* 959 __bridge_create(const char *name, struct device_type *devtype, struct blob_attr *config) 960 { 961 struct extdev_bridge *ebr; 962 963 ebr = calloc(1, sizeof(*ebr)); 964 if (!ebr) 965 return NULL; 966 967 device_init(&ebr->edev.dev, devtype, name); 968 ebr->edev.dev.config_pending = true; 969 ebr->retry.cb = extdev_bridge_retry_enable_members; 970 ebr->edev.etype = container_of(devtype, struct extdev_type, handler); 971 ebr->set_state = ebr->edev.dev.set_state; 972 ebr->edev.dev.set_state = extdev_bridge_set_state; 973 ebr->edev.dev.hotplug_ops = &extdev_hotplug_ops; 974 vlist_init(&ebr->members, avl_strcmp, extdev_bridge_member_update); 975 ebr->members.keep_old = true; 976 __bridge_reload(ebr, config); 977 978 return &ebr->edev.dev; 979 } 980 981 /* Device creation process: 982 * For bridges without dependencies: 983 * 1) The bridge state is initialized in netifd. Devices for the members are 984 * created and added to the members vlist by config_init automatically. 985 * 2) When the first bridge member device is brought up in 986 * extdev_bridge_enable_member the 'create' call to the external device 987 * handler is issued. 988 * 3) After successful device creation the bridge is marked "present" and a 989 * new attempt at adding the member is made. 990 * For bridges with dependencies: 991 * 1) The bridge state is initialized in netifd. If a dependency is expressed 992 * via the 'depends_on' UCI option and the dependency is not ready (i.e. it 993 * does not exist or config_pending == true) the call to 994 * __bridge_config_init() is postponed and a retry timer is started. Retries 995 * happen until the dependency is ready. Then, __bridge_config_init() gets 996 * called and the process continues as with bridges without dependencies 997 * For regular devices: 998 * 1) The device structure is created in netifd. 999 * 2) config_init is called automatically which issues the 'create' call to the 1000 * external device handler. 1001 */ 1002 static struct device * 1003 extdev_create(const char *name, struct device_type *devtype, struct blob_attr *config) 1004 { 1005 struct extdev_type *etype = container_of(devtype, struct extdev_type, handler); 1006 1007 if (!etype->subscribed) 1008 return NULL; 1009 1010 if (devtype->bridge_capability) 1011 return __bridge_create(name, devtype, config); 1012 else 1013 return __create(name, devtype, config); 1014 } 1015 1016 static void 1017 extdev_free(struct device *dev) 1018 { 1019 struct extdev_type *etype; 1020 struct extdev_device *edev; 1021 struct extdev_bridge *ebr; 1022 int ret; 1023 1024 etype = container_of(dev->type, struct extdev_type, handler); 1025 edev = container_of(dev, struct extdev_device, dev); 1026 1027 if (!etype->subscribed) 1028 return; 1029 1030 blob_buf_init(&b, 0); 1031 blobmsg_add_string(&b, "name", dev->ifname); 1032 1033 ret = netifd_extdev_free(edev, b.head); 1034 1035 if (ret && ret != UBUS_STATUS_NOT_FOUND) 1036 goto error; 1037 1038 if (dev->type->bridge_capability) { 1039 ebr = container_of(dev, struct extdev_bridge, edev.dev); 1040 1041 vlist_flush_all(&ebr->members); 1042 // vlist_flush_all(&dev->vlans); TODO: do we need this? 1043 1044 free(ebr->config); 1045 free(ebr); 1046 } 1047 1048 return; 1049 1050 error: 1051 extdev_invocation_error(ret, __extdev_methods[METHOD_FREE], 1052 dev->ifname); 1053 } 1054 1055 static void 1056 __bridge_config_init(struct extdev_bridge *ebr) 1057 { 1058 int ret; 1059 size_t rem; 1060 struct blob_attr *cur; 1061 1062 if (ebr->empty) { 1063 ebr->force_active = true; 1064 ret = netifd_extdev_create(&ebr->edev, ebr->config); 1065 if (ret) 1066 goto error; 1067 device_set_present(&ebr->edev.dev, true); 1068 } 1069 1070 ebr->n_failed = 0; 1071 vlist_update(&ebr->members); 1072 if (ebr->ifnames) { 1073 blobmsg_for_each_attr(cur, ebr->ifnames, rem) 1074 extdev_bridge_add_member(ebr, blobmsg_data(cur)); 1075 } 1076 1077 vlist_flush(&ebr->members); 1078 extdev_bridge_check_retry(ebr); 1079 return; 1080 1081 error: 1082 fprintf(stderr, "Failed to init config for '%s': %s\n", ebr->edev.dev.ifname, 1083 ubus_strerror(ret)); 1084 } 1085 1086 static void 1087 extdev_config_init(struct device *dev) 1088 { 1089 struct extdev_type *etype; 1090 struct extdev_bridge *ebr; 1091 1092 etype = container_of(dev->type, struct extdev_type, handler); 1093 1094 if (!etype->subscribed) 1095 return; 1096 1097 if (dev->type->bridge_capability) { 1098 ebr = container_of(dev, struct extdev_bridge, edev.dev); 1099 __bridge_config_init(ebr); 1100 } 1101 } 1102 1103 static void 1104 extdev_buf_add_list(struct blob_attr *attr, size_t len, const char *name, 1105 struct blob_buf *buf, bool array) 1106 { 1107 struct blob_attr *cur; 1108 struct blobmsg_hdr *hdr; 1109 void *list; 1110 int type; 1111 1112 if (array) 1113 list = blobmsg_open_array(buf, name); 1114 else 1115 list = blobmsg_open_table(buf, name); 1116 1117 blobmsg_for_each_attr(cur, attr, len) { 1118 hdr = blob_data(cur); 1119 type = blobmsg_type(cur); 1120 switch (type) { 1121 case BLOBMSG_TYPE_STRING: 1122 blobmsg_add_string(buf, (char *) hdr->name, 1123 blobmsg_get_string(cur)); 1124 break; 1125 case BLOBMSG_TYPE_TABLE: 1126 case BLOBMSG_TYPE_ARRAY: 1127 extdev_buf_add_list(blobmsg_data(cur), blobmsg_data_len(cur), 1128 (char *) hdr->name, buf, type == BLOBMSG_TYPE_ARRAY); 1129 break; 1130 case BLOBMSG_TYPE_INT64: 1131 blobmsg_add_u64(buf, (char *) hdr->name, blobmsg_get_u64(cur)); 1132 break; 1133 case BLOBMSG_TYPE_INT32: 1134 blobmsg_add_u32(buf, (char *) hdr->name, blobmsg_get_u32(cur)); 1135 break; 1136 case BLOBMSG_TYPE_INT16: 1137 blobmsg_add_u16(buf, (char *) hdr->name, blobmsg_get_u16(cur)); 1138 break; 1139 case BLOBMSG_TYPE_INT8: 1140 blobmsg_add_u8(buf, (char *) hdr->name, blobmsg_get_u8(cur)); 1141 break; 1142 default: 1143 break; 1144 } 1145 } 1146 1147 if (array) 1148 blobmsg_close_array(buf, list); 1149 else 1150 blobmsg_close_table(buf, list); 1151 } 1152 1153 static void 1154 add_parsed_data(struct blob_attr **tb, const struct blobmsg_policy *policy, int n_params, 1155 struct blob_buf *buf) 1156 { 1157 for (int i = 0; i < n_params; i++) { 1158 if (!tb[i]) 1159 continue; 1160 1161 switch (policy[i].type) { 1162 case BLOBMSG_TYPE_STRING: 1163 blobmsg_add_string(buf, policy[i].name, blobmsg_get_string(tb[i])); 1164 break; 1165 case BLOBMSG_TYPE_ARRAY: 1166 case BLOBMSG_TYPE_TABLE: 1167 extdev_buf_add_list(blobmsg_data(tb[i]), blobmsg_data_len(tb[i]), 1168 policy[i].name, buf, policy[i].type == BLOBMSG_TYPE_ARRAY); 1169 break; 1170 case BLOBMSG_TYPE_INT64: 1171 blobmsg_add_u64(buf, policy[i].name, blobmsg_get_u64(tb[i])); 1172 break; 1173 case BLOBMSG_TYPE_INT32: 1174 blobmsg_add_u32(buf, policy[i].name, blobmsg_get_u32(tb[i])); 1175 break; 1176 case BLOBMSG_TYPE_INT16: 1177 blobmsg_add_u16(buf, policy[i].name, blobmsg_get_u16(tb[i])); 1178 break; 1179 case BLOBMSG_TYPE_INT8: 1180 blobmsg_add_u8(buf, policy[i].name, blobmsg_get_u8(tb[i])); 1181 break; 1182 default: 1183 break; 1184 } 1185 } 1186 } 1187 1188 struct dump_data { 1189 const struct device *dev; 1190 struct blob_buf *buf; 1191 }; 1192 1193 static void 1194 dump_cb(struct ubus_request *req, int type, struct blob_attr *reply) 1195 { 1196 struct dump_data *data; 1197 struct extdev_type *etype; 1198 const struct blobmsg_policy *info_policy; 1199 int n_params; 1200 struct blob_buf *buf; 1201 1202 data = req->priv; 1203 etype = container_of(data->dev->type, struct extdev_type, handler); 1204 info_policy = etype->info_params->params; 1205 n_params = etype->info_params->n_params; 1206 buf = data->buf; 1207 1208 struct blob_attr *tb[n_params]; 1209 1210 blobmsg_parse(info_policy, n_params, tb, blobmsg_data(reply), blobmsg_len(reply)); 1211 add_parsed_data(tb, info_policy, n_params, buf); 1212 } 1213 1214 static void 1215 extdev_dump(const char *method, struct device *dev, struct blob_buf *buf) 1216 { 1217 static struct dump_data data; 1218 struct extdev_type *etype; 1219 1220 etype = container_of(dev->type, struct extdev_type, handler); 1221 1222 if (!etype->subscribed) 1223 return; 1224 1225 data.dev = dev; 1226 data.buf = buf; 1227 1228 blob_buf_init(&b, 0); 1229 blobmsg_add_string(&b, "name", dev->ifname); 1230 1231 netifd_extdev_invoke(etype->peer_id, method, b.head, dump_cb, &data); 1232 } 1233 1234 static void 1235 extdev_dump_info(struct device *dev, struct blob_buf *buf) 1236 { 1237 extdev_dump(__extdev_methods[METHOD_DUMP_INFO], dev, buf); 1238 } 1239 1240 static void 1241 extdev_dump_stats(struct device *dev, struct blob_buf *buf) 1242 { 1243 extdev_dump(__extdev_methods[METHOD_DUMP_STATS], dev, buf); 1244 } 1245 1246 static void 1247 extdev_ext_handler_remove_cb(struct ubus_context *ctx, 1248 struct ubus_subscriber *obj, uint32_t id) 1249 { 1250 struct extdev_type *etype; 1251 etype = container_of(obj, struct extdev_type, ubus_sub); 1252 1253 netifd_log_message(L_NOTICE, "%s: external device handler " 1254 "'%s' disappeared. Waiting for it to re-appear.\n", 1255 etype->handler.name, etype->name); 1256 1257 etype->peer_id = 0; 1258 etype->subscribed = false; 1259 1260 extdev_ext_ubus_obj_wait(&etype->obj_wait); 1261 } 1262 1263 static void 1264 extdev_add_devtype(const char *cfg_file, const char *tname, const char *ubus_name, 1265 bool bridge_capability, const char *br_prefix, json_object *cfg_obj, 1266 json_object *info_obj, json_object *stats_obj) 1267 { 1268 static const char *OBJ_PREFIX = "network.device."; 1269 1270 struct extdev_type *etype; 1271 struct device_type *devtype; 1272 char *ubus_obj_name, *devtype_name, *ext_dev_handler_name, *name_prefix; 1273 struct uci_blob_param_list *config_params, *info_params, *stats_params; 1274 int ret; 1275 1276 etype = calloc_a(sizeof(*etype), 1277 &ubus_obj_name, strlen(OBJ_PREFIX) + strlen(ubus_name) + 1, 1278 &devtype_name, strlen(tname) + 1, 1279 &ext_dev_handler_name, strlen(ubus_name) + 1, 1280 &config_params, sizeof(struct uci_blob_param_list), 1281 &info_params, sizeof(struct uci_blob_param_list), 1282 &stats_params, sizeof(struct uci_blob_param_list)); 1283 1284 if (!etype) 1285 return; 1286 1287 etype->config_params = config_params; 1288 etype->info_params = info_params; 1289 etype->name = strcpy(ext_dev_handler_name, ubus_name); 1290 1291 devtype = &etype->handler; 1292 devtype->name = strcpy(devtype_name, tname); 1293 devtype->create = extdev_create; 1294 devtype->free = extdev_free; 1295 devtype->config_init = extdev_config_init; 1296 devtype->reload = extdev_reload; 1297 devtype->dump_info = extdev_dump_info; 1298 devtype->dump_stats = extdev_dump_stats; 1299 devtype->bridge_capability = bridge_capability; 1300 devtype->config_params = etype->config_params; 1301 1302 if (bridge_capability) { 1303 name_prefix = malloc(strlen(br_prefix) + 1); 1304 if (!name_prefix) 1305 goto error; 1306 1307 strcpy(name_prefix, br_prefix); 1308 devtype->name_prefix = name_prefix; 1309 } 1310 1311 /* subscribe to external device handler */ 1312 sprintf(ubus_obj_name, "%s%s", OBJ_PREFIX, ubus_name); 1313 etype->ubus_sub.obj.name = ubus_obj_name; 1314 etype->ubus_sub.obj.type = &extdev_ubus_object_type; 1315 ret = ubus_register_subscriber(ubus_ctx, &etype->ubus_sub); 1316 if (ret) { 1317 fprintf(stderr, "Failed to register subscriber object '%s'\n", 1318 etype->ubus_sub.obj.name); 1319 goto error; 1320 } 1321 etype->obj_wait.cb = extdev_wait_ev_cb; 1322 etype->ubus_sub.remove_cb = extdev_ext_handler_remove_cb; 1323 extdev_subscribe(etype); 1324 1325 /* parse config params from JSON object */ 1326 etype->config_strbuf = netifd_handler_parse_config(etype->config_params, cfg_obj); 1327 if (!etype->config_strbuf) 1328 goto error; 1329 1330 /* parse info dump params from JSON object */ 1331 if (!info_obj) { 1332 devtype->dump_info = NULL; 1333 } else { 1334 etype->info_strbuf = netifd_handler_parse_config(etype->info_params, info_obj); 1335 if (!etype->info_strbuf) 1336 devtype->dump_info = NULL; 1337 } 1338 1339 /* parse statistics dump params from JSON object */ 1340 if (!stats_obj) { 1341 devtype->dump_stats = NULL; 1342 } else { 1343 etype->stats_strbuf = netifd_handler_parse_config(etype->stats_params, stats_obj); 1344 if (!etype->stats_strbuf) 1345 devtype->dump_stats = NULL; 1346 } 1347 1348 ret = device_type_add(devtype); 1349 if (ret) 1350 goto config_error; 1351 1352 return; 1353 1354 config_error: 1355 free(etype->config_strbuf); 1356 free(etype->info_strbuf); 1357 free(etype->stats_strbuf); 1358 1359 error: 1360 fprintf(stderr, "Failed to create device handler for device" 1361 "type '%s' from file '%s'\n", tname, cfg_file); 1362 free(ubus_obj_name); 1363 free(devtype_name); 1364 free(etype); 1365 } 1366 1367 /* create extdev device handler stubs from JSON description */ 1368 void 1369 extdev_init(void) 1370 { 1371 confdir_fd = netifd_open_subdir("extdev-config"); 1372 if (confdir_fd < 0) 1373 return; 1374 netifd_init_extdev_handlers(confdir_fd, extdev_add_devtype); 1375 } 1376
This page was automatically generated by LXR 0.3.1. • OpenWrt