1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> 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 #include <string.h> 15 #include <stdlib.h> 16 #include <stdio.h> 17 18 #include "netifd.h" 19 #include "device.h" 20 #include "system.h" 21 22 struct bonding_device { 23 struct device dev; 24 device_state_cb set_state; 25 26 struct blob_attr *port_list; 27 struct vlist_tree ports; 28 int n_present; 29 int n_failed; 30 31 struct bonding_port *primary_port; 32 struct uloop_timeout retry; 33 34 struct bonding_config config; 35 struct blob_attr *config_data; 36 bool has_macaddr; 37 bool force_active; 38 bool reset_primary; 39 bool active; 40 }; 41 42 struct bonding_port { 43 struct vlist_node node; 44 struct bonding_device *bdev; 45 struct device_user dev; 46 bool set_primary; 47 bool present; 48 bool active; 49 char name[]; 50 }; 51 52 enum { 53 BOND_ATTR_PORTS, 54 55 BOND_ATTR_POLICY, 56 BOND_ATTR_XMIT_HASH_POLICY, 57 BOND_ATTR_ALL_PORTS_ACTIVE, 58 59 BOND_ATTR_MIN_LINKS, 60 BOND_ATTR_AD_ACTOR_SYSTEM, 61 BOND_ATTR_AD_ACTOR_SYS_PRIO, 62 BOND_ATTR_AD_SELECT, 63 BOND_ATTR_LACP_RATE, 64 65 BOND_ATTR_PACKETS_PER_PORT, 66 BOND_ATTR_LP_INTERVAL, 67 BOND_ATTR_DYNAMIC_LB, 68 BOND_ATTR_RESEND_IGMP, 69 70 BOND_ATTR_NUM_PEER_NOTIF, 71 BOND_ATTR_PRIMARY, 72 BOND_ATTR_PRIMARY_RESELECT, 73 BOND_ATTR_FAILOVER_MAC, 74 75 BOND_ATTR_MON_MODE, 76 BOND_ATTR_MON_INTERVAL, 77 BOND_ATTR_ARP_TARGET, 78 BOND_ATTR_ARP_ALL_TARGETS, 79 BOND_ATTR_ARP_VALIDATE, 80 BOND_ATTR_USE_CARRIER, 81 BOND_ATTR_UPDELAY, 82 BOND_ATTR_DOWNDELAY, 83 84 __BOND_ATTR_MAX, 85 }; 86 87 static const struct blobmsg_policy bonding_attrs[__BOND_ATTR_MAX] = { 88 [BOND_ATTR_PORTS] = { "ports", BLOBMSG_TYPE_ARRAY }, 89 [BOND_ATTR_POLICY] = { "policy", BLOBMSG_TYPE_STRING }, 90 [BOND_ATTR_XMIT_HASH_POLICY] = { "xmit_hash_policy", BLOBMSG_TYPE_STRING }, 91 [BOND_ATTR_ALL_PORTS_ACTIVE] = { "all_ports_active", BLOBMSG_TYPE_BOOL }, 92 [BOND_ATTR_MIN_LINKS] = { "min_links", BLOBMSG_TYPE_INT32 }, 93 [BOND_ATTR_AD_ACTOR_SYSTEM] = { "ad_actor_system", BLOBMSG_TYPE_STRING }, 94 [BOND_ATTR_AD_ACTOR_SYS_PRIO] = { "ad_actor_sys_prio", BLOBMSG_TYPE_INT32 }, 95 [BOND_ATTR_AD_SELECT] = { "ad_select", BLOBMSG_TYPE_STRING }, 96 [BOND_ATTR_LACP_RATE] = { "lacp_rate", BLOBMSG_TYPE_STRING }, 97 [BOND_ATTR_PACKETS_PER_PORT] = { "packets_per_port", BLOBMSG_TYPE_INT32 }, 98 [BOND_ATTR_LP_INTERVAL] = { "lp_interval", BLOBMSG_TYPE_INT32 }, 99 [BOND_ATTR_DYNAMIC_LB] = { "dynamic_lb", BLOBMSG_TYPE_BOOL }, 100 [BOND_ATTR_RESEND_IGMP] = { "resend_igmp", BLOBMSG_TYPE_INT32 }, 101 [BOND_ATTR_NUM_PEER_NOTIF] = { "num_peer_notif", BLOBMSG_TYPE_INT32 }, 102 [BOND_ATTR_PRIMARY] = { "primary", BLOBMSG_TYPE_STRING }, 103 [BOND_ATTR_PRIMARY_RESELECT] = { "primary_reselect", BLOBMSG_TYPE_STRING }, 104 [BOND_ATTR_FAILOVER_MAC] = { "failover_mac", BLOBMSG_TYPE_STRING }, 105 [BOND_ATTR_MON_MODE] = { "monitor_mode", BLOBMSG_TYPE_STRING }, 106 [BOND_ATTR_MON_INTERVAL] = { "monitor_interval", BLOBMSG_TYPE_INT32 }, 107 [BOND_ATTR_ARP_TARGET] = { "arp_target", BLOBMSG_TYPE_ARRAY }, 108 [BOND_ATTR_ARP_ALL_TARGETS] = { "arp_all_targets", BLOBMSG_TYPE_BOOL }, 109 [BOND_ATTR_ARP_VALIDATE] = { "arp_validate", BLOBMSG_TYPE_STRING }, 110 [BOND_ATTR_USE_CARRIER] = { "use_carrier", BLOBMSG_TYPE_BOOL }, 111 [BOND_ATTR_UPDELAY] = { "updelay", BLOBMSG_TYPE_INT32 }, 112 [BOND_ATTR_DOWNDELAY] = { "downdelay", BLOBMSG_TYPE_INT32 }, 113 }; 114 115 static const struct uci_blob_param_info bonding_attr_info[__BOND_ATTR_MAX] = { 116 [BOND_ATTR_PORTS] = { .type = BLOBMSG_TYPE_STRING }, 117 [BOND_ATTR_ARP_TARGET] = { .type = BLOBMSG_TYPE_STRING }, 118 }; 119 120 static const struct uci_blob_param_list bonding_attr_list = { 121 .n_params = __BOND_ATTR_MAX, 122 .params = bonding_attrs, 123 .info = bonding_attr_info, 124 125 .n_next = 1, 126 .next = { &device_attr_list }, 127 }; 128 129 static void 130 bonding_reset_primary(struct bonding_device *bdev) 131 { 132 struct bonding_port *bp; 133 134 bdev->primary_port = NULL; 135 if (!bdev->has_macaddr) 136 bdev->dev.settings.flags &= ~DEV_OPT_MACADDR; 137 138 vlist_for_each_element(&bdev->ports, bp, node) { 139 uint8_t *macaddr; 140 141 if (!bp->present) 142 continue; 143 144 if (bdev->primary_port && !bp->set_primary) 145 continue; 146 147 bdev->primary_port = bp; 148 if (bdev->has_macaddr) 149 continue; 150 151 if (bp->dev.dev->settings.flags & DEV_OPT_MACADDR) 152 macaddr = bp->dev.dev->settings.macaddr; 153 else 154 macaddr = bp->dev.dev->orig_settings.macaddr; 155 memcpy(bdev->dev.settings.macaddr, macaddr, 6); 156 bdev->dev.settings.flags |= DEV_OPT_MACADDR; 157 } 158 } 159 160 static int 161 bonding_disable_port(struct bonding_port *bp, bool keep_dev) 162 { 163 struct bonding_device *bdev = bp->bdev; 164 165 if (!bp->present || !bp->active) 166 return 0; 167 168 bp->active = false; 169 170 system_bonding_set_port(&bdev->dev, bp->dev.dev, false, bp->set_primary); 171 if (!keep_dev) 172 device_release(&bp->dev); 173 174 if (bp->dev.dev->settings.flags & DEV_OPT_IPV6) { 175 bp->dev.dev->settings.ipv6 = 1; 176 bp->dev.dev->settings.flags &= ~DEV_OPT_IPV6; 177 } 178 179 return 0; 180 } 181 182 static void 183 bonding_remove_port(struct bonding_port *bp) 184 { 185 struct bonding_device *bdev = bp->bdev; 186 187 if (!bp->present) 188 return; 189 190 if (bdev->dev.active) 191 bonding_disable_port(bp, false); 192 193 bp->present = false; 194 bp->bdev->n_present--; 195 196 if (bp == bdev->primary_port) 197 bonding_reset_primary(bdev); 198 199 bdev->force_active = false; 200 if (bdev->n_present == 0) 201 device_set_present(&bdev->dev, false); 202 } 203 204 static int 205 bonding_set_active(struct bonding_device *bdev, bool active) 206 { 207 int ret; 208 209 if (bdev->active == active) 210 return 0; 211 212 ret = system_bonding_set_device(&bdev->dev, active ? &bdev->config : NULL); 213 if (ret < 0) 214 return ret; 215 216 bdev->active = active; 217 return 0; 218 } 219 220 static int 221 bonding_enable_port(struct bonding_port *bp) 222 { 223 struct bonding_device *bdev = bp->bdev; 224 struct device *dev; 225 int ret; 226 227 if (!bp->present) 228 return 0; 229 230 /* Disable IPv6 for bonding ports */ 231 if (!(bp->dev.dev->settings.flags & DEV_OPT_IPV6)) { 232 bp->dev.dev->settings.ipv6 = 0; 233 bp->dev.dev->settings.flags |= DEV_OPT_IPV6; 234 } 235 236 ret = device_claim(&bp->dev); 237 if (ret < 0) 238 return ret; 239 240 ret = bonding_set_active(bdev, true); 241 if (ret) 242 goto release; 243 244 dev = bp->dev.dev; 245 if (dev->settings.auth && !dev->auth_status) 246 return -1; 247 248 if (bp->active) 249 return 0; 250 251 ret = system_bonding_set_port(&bdev->dev, bp->dev.dev, true, bp->set_primary); 252 if (ret < 0) { 253 D(DEVICE, "Bonding port %s could not be added", bp->dev.dev->ifname); 254 goto error; 255 } 256 257 bp->active = true; 258 device_set_present(&bdev->dev, true); 259 260 return 0; 261 262 error: 263 bdev->n_failed++; 264 bp->present = false; 265 bdev->n_present--; 266 release: 267 device_release(&bp->dev); 268 269 return ret; 270 } 271 272 static void 273 bonding_port_cb(struct device_user *dep, enum device_event ev) 274 { 275 struct bonding_port *bp = container_of(dep, struct bonding_port, dev); 276 struct bonding_device *bdev = bp->bdev; 277 struct device *dev = dep->dev; 278 279 switch (ev) { 280 case DEV_EVENT_ADD: 281 if (bp->present) 282 break; 283 284 bp->present = true; 285 bdev->n_present++; 286 287 if (bdev->n_present == 1) 288 device_set_present(&bdev->dev, true); 289 fallthrough; 290 case DEV_EVENT_AUTH_UP: 291 if (!bdev->dev.active) 292 break; 293 294 if (bonding_enable_port(bp)) 295 break; 296 297 /* 298 * Adding a bonding port can overwrite the bonding device mtu 299 * in the kernel, apply the bonding settings in case the 300 * bonding device mtu is set 301 */ 302 system_if_apply_settings(&bdev->dev, &bdev->dev.settings, 303 DEV_OPT_MTU | DEV_OPT_MTU6); 304 break; 305 case DEV_EVENT_LINK_DOWN: 306 if (!dev->settings.auth) 307 break; 308 309 bonding_disable_port(bp, true); 310 break; 311 case DEV_EVENT_REMOVE: 312 if (dep->hotplug && !dev->sys_present) { 313 vlist_delete(&bdev->ports, &bp->node); 314 return; 315 } 316 317 if (bp->present) 318 bonding_remove_port(bp); 319 320 break; 321 default: 322 return; 323 } 324 } 325 326 static struct bonding_port * 327 bonding_create_port(struct bonding_device *bdev, const char *name, 328 struct device *dev, bool hotplug) 329 { 330 struct bonding_port *bp; 331 struct bonding_config *cfg = &bdev->config; 332 333 bp = calloc(1, sizeof(*bp) + strlen(name) + 1); 334 if (!bp) 335 return NULL; 336 337 bp->bdev = bdev; 338 bp->dev.cb = bonding_port_cb; 339 bp->dev.hotplug = hotplug; 340 strcpy(bp->name, name); 341 bp->dev.dev = dev; 342 343 if (cfg->primary != NULL) { 344 bp->set_primary = strcmp(cfg->primary, name) == 0; 345 } 346 347 vlist_add(&bdev->ports, &bp->node, bp->name); 348 /* 349 * Need to look up the bonding port again as the above 350 * created pointer will be freed in case the bonding port 351 * already existed 352 */ 353 if (!hotplug) 354 return bp; 355 356 bp = vlist_find(&bdev->ports, name, bp, node); 357 if (bp) 358 bp->node.version = -1; 359 360 return bp; 361 } 362 363 static void 364 bonding_config_init(struct device *dev) 365 { 366 struct bonding_device *bdev; 367 struct blob_attr *cur; 368 size_t rem; 369 370 bdev = container_of(dev, struct bonding_device, dev); 371 372 bdev->n_failed = 0; 373 374 vlist_update(&bdev->ports); 375 blobmsg_for_each_attr(cur, bdev->port_list, rem) { 376 const char *name = blobmsg_get_string(cur); 377 378 dev = device_get(name, true); 379 if (!dev) 380 continue; 381 382 bonding_create_port(bdev, name, dev, false); 383 } 384 vlist_flush(&bdev->ports); 385 386 if (bdev->reset_primary) { 387 bonding_reset_primary(bdev); 388 bdev->reset_primary = false; 389 } 390 391 if (bdev->n_failed) 392 uloop_timeout_set(&bdev->retry, 100); 393 } 394 395 static void 396 bonding_apply_settings(struct bonding_device *bdev, struct blob_attr **tb) 397 { 398 struct bonding_config *cfg = &bdev->config; 399 struct blob_attr *cur; 400 401 /* defaults */ 402 memset(cfg, 0, sizeof(*cfg)); 403 cfg->resend_igmp = 1; 404 cfg->ad_actor_sys_prio = 65535; 405 cfg->lp_interval = 1; 406 cfg->num_peer_notif = 1; 407 408 #define cfg_item(_type, _field, _attr) \ 409 do { \ 410 if ((cur = tb[BOND_ATTR_##_attr]) != NULL) \ 411 cfg->_field = blobmsg_get_##_type(cur); \ 412 } while (0) 413 414 if ((cur = tb[BOND_ATTR_POLICY]) != NULL) { 415 const char *policy = blobmsg_get_string(cur); 416 size_t i; 417 418 for (i = 0; i < ARRAY_SIZE(bonding_policy_str); i++) { 419 if (strcmp(policy, bonding_policy_str[i]) != 0) 420 continue; 421 422 cfg->policy = i; 423 break; 424 } 425 } 426 427 cfg_item(string, xmit_hash_policy, XMIT_HASH_POLICY); 428 cfg_item(bool, all_ports_active, ALL_PORTS_ACTIVE); 429 cfg_item(u32, min_links, MIN_LINKS); 430 cfg_item(string, ad_actor_system, AD_ACTOR_SYSTEM); 431 cfg_item(u32, ad_actor_sys_prio, AD_ACTOR_SYS_PRIO); 432 cfg_item(string, ad_select, AD_SELECT); 433 cfg_item(string, lacp_rate, LACP_RATE); 434 cfg_item(u32, packets_per_port, PACKETS_PER_PORT); 435 cfg_item(u32, lp_interval, LP_INTERVAL); 436 cfg_item(bool, dynamic_lb, DYNAMIC_LB); 437 cfg_item(u32, resend_igmp, RESEND_IGMP); 438 cfg_item(u32, num_peer_notif, NUM_PEER_NOTIF); 439 cfg_item(string, primary, PRIMARY); 440 cfg_item(string, primary_reselect, PRIMARY_RESELECT); 441 cfg_item(string, failover_mac, FAILOVER_MAC); 442 cfg_item(u32, monitor_interval, MON_INTERVAL); 443 cfg_item(bool, arp_all_targets, ARP_ALL_TARGETS); 444 cfg_item(string, arp_validate, ARP_VALIDATE); 445 cfg_item(bool, use_carrier, USE_CARRIER); 446 cfg_item(u32, updelay, UPDELAY); 447 cfg_item(u32, downdelay, DOWNDELAY); 448 449 if ((cur = tb[BOND_ATTR_MON_MODE]) != NULL && 450 !strcmp(blobmsg_get_string(cur), "arp")) 451 cfg->monitor_arp = true; 452 cfg->arp_target = tb[BOND_ATTR_ARP_TARGET]; 453 #undef cfg_item 454 } 455 456 static enum dev_change_type 457 bonding_reload(struct device *dev, struct blob_attr *attr) 458 { 459 struct blob_attr *tb_dev[__DEV_ATTR_MAX]; 460 struct blob_attr *tb_b[__BOND_ATTR_MAX]; 461 enum dev_change_type ret = DEV_CONFIG_APPLIED; 462 unsigned long diff[2] = {}; 463 struct bonding_device *bdev; 464 465 BUILD_BUG_ON(sizeof(diff[0]) < __BOND_ATTR_MAX / 8); 466 BUILD_BUG_ON(sizeof(diff) < __DEV_ATTR_MAX / 8); 467 468 bdev = container_of(dev, struct bonding_device, dev); 469 attr = blob_memdup(attr); 470 471 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev, 472 blob_data(attr), blob_len(attr)); 473 blobmsg_parse(bonding_attrs, __BOND_ATTR_MAX, tb_b, 474 blob_data(attr), blob_len(attr)); 475 476 bdev->has_macaddr = tb_dev[DEV_ATTR_MACADDR]; 477 if (bdev->primary_port && !bdev->primary_port->set_primary && 478 tb_dev[DEV_ATTR_MACADDR]) 479 bdev->primary_port = NULL; 480 481 bdev->port_list = tb_b[BOND_ATTR_PORTS]; 482 device_init_settings(dev, tb_dev); 483 bonding_apply_settings(bdev, tb_b); 484 485 if (bdev->config_data) { 486 struct blob_attr *otb_dev[__DEV_ATTR_MAX]; 487 struct blob_attr *otb_b[__BOND_ATTR_MAX]; 488 489 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev, 490 blob_data(bdev->config_data), blob_len(bdev->config_data)); 491 492 uci_blob_diff(tb_dev, otb_dev, &device_attr_list, diff); 493 if (diff[0] | diff[1]) 494 ret = DEV_CONFIG_RESTART; 495 496 blobmsg_parse(bonding_attrs, __BOND_ATTR_MAX, otb_b, 497 blob_data(bdev->config_data), blob_len(bdev->config_data)); 498 499 diff[0] = 0; 500 uci_blob_diff(tb_b, otb_b, &bonding_attr_list, diff); 501 if (diff[0] & ~(1 << BOND_ATTR_PORTS)) 502 ret = DEV_CONFIG_RESTART; 503 504 bonding_config_init(dev); 505 } 506 507 free(bdev->config_data); 508 bdev->config_data = attr; 509 510 return ret; 511 } 512 513 static int 514 bonding_hotplug_add(struct device *dev, struct device *port, struct blob_attr *vlan) 515 { 516 struct bonding_device *bdev = container_of(dev, struct bonding_device, dev); 517 struct bonding_port *bp; 518 519 bp = vlist_find(&bdev->ports, port->ifname, bp, node); 520 if (!bp) 521 bonding_create_port(bdev, port->ifname, port, true); 522 523 return 0; 524 } 525 526 static int 527 bonding_hotplug_del(struct device *dev, struct device *port, struct blob_attr *vlan) 528 { 529 struct bonding_device *bdev = container_of(dev, struct bonding_device, dev); 530 struct bonding_port *bp; 531 532 bp = vlist_find(&bdev->ports, port->ifname, bp, node); 533 if (!bp) 534 return UBUS_STATUS_NOT_FOUND; 535 536 if (bp->dev.hotplug) 537 vlist_delete(&bdev->ports, &bp->node); 538 539 return 0; 540 } 541 542 static int 543 bonding_hotplug_prepare(struct device *dev, struct device **bonding_dev) 544 { 545 struct bonding_device *bdev; 546 547 if (bonding_dev) 548 *bonding_dev = dev; 549 550 bdev = container_of(dev, struct bonding_device, dev); 551 bdev->force_active = true; 552 device_set_present(&bdev->dev, true); 553 554 return 0; 555 } 556 557 static void 558 bonding_retry_ports(struct uloop_timeout *timeout) 559 { 560 struct bonding_device *bdev = container_of(timeout, struct bonding_device, retry); 561 struct bonding_port *bp; 562 563 bdev->n_failed = 0; 564 vlist_for_each_element(&bdev->ports, bp, node) { 565 if (bp->present) 566 continue; 567 568 if (!bp->dev.dev->present) 569 continue; 570 571 bp->present = true; 572 bdev->n_present++; 573 bonding_enable_port(bp); 574 } 575 } 576 577 578 static void 579 bonding_free_port(struct bonding_port *bp) 580 { 581 struct device *dev = bp->dev.dev; 582 583 bonding_remove_port(bp); 584 585 device_remove_user(&bp->dev); 586 587 /* 588 * When reloading the config and moving a device from one master to 589 * another, the other master may have tried to claim this device 590 * before it was removed here. 591 * Ensure that claiming the device is retried by toggling its present 592 * state 593 */ 594 if (dev->present) { 595 device_set_present(dev, false); 596 device_set_present(dev, true); 597 } 598 599 free(bp); 600 } 601 602 static void 603 bonding_port_update(struct vlist_tree *tree, struct vlist_node *node_new, 604 struct vlist_node *node_old) 605 { 606 struct bonding_port *bp; 607 struct device *dev; 608 struct bonding_device *bdev = container_of(tree, struct bonding_device, ports); 609 610 if (node_new) { 611 bp = container_of(node_new, struct bonding_port, node); 612 613 if (node_old) { 614 struct bonding_port *bp_old; 615 616 bp_old = container_of(node_old, struct bonding_port, node); 617 if (bp_old->set_primary != bp->set_primary) { 618 bp_old->set_primary = bp->set_primary; 619 bdev->reset_primary = true; 620 } 621 622 free(bp); 623 return; 624 } 625 626 dev = bp->dev.dev; 627 bp->dev.dev = NULL; 628 device_add_user(&bp->dev, dev); 629 } 630 631 632 if (node_old) { 633 bp = container_of(node_old, struct bonding_port, node); 634 bonding_free_port(bp); 635 } 636 } 637 638 static int 639 bonding_set_down(struct bonding_device *bdev) 640 { 641 struct bonding_port *bp; 642 643 bdev->set_state(&bdev->dev, false); 644 645 vlist_for_each_element(&bdev->ports, bp, node) 646 bonding_disable_port(bp, false); 647 648 bonding_set_active(bdev, false); 649 650 return 0; 651 } 652 653 static int 654 bonding_set_up(struct bonding_device *bdev) 655 { 656 struct bonding_port *bp; 657 int ret; 658 659 if (!bdev->n_present) { 660 if (!bdev->force_active) 661 return -ENOENT; 662 663 ret = bonding_set_active(bdev, true); 664 if (ret) 665 return ret; 666 } 667 668 bdev->n_failed = 0; 669 vlist_for_each_element(&bdev->ports, bp, node) 670 bonding_enable_port(bp); 671 if (bdev->n_failed) 672 uloop_timeout_set(&bdev->retry, 100); 673 674 if (!bdev->force_active && !bdev->n_present) { 675 /* initialization of all port interfaces failed */ 676 bonding_set_active(bdev, false); 677 device_set_present(&bdev->dev, false); 678 return -ENOENT; 679 } 680 681 bonding_reset_primary(bdev); 682 ret = bdev->set_state(&bdev->dev, true); 683 if (ret < 0) 684 bonding_set_down(bdev); 685 686 return ret; 687 } 688 689 static int 690 bonding_set_state(struct device *dev, bool up) 691 { 692 struct bonding_device *bdev; 693 694 bdev = container_of(dev, struct bonding_device, dev); 695 696 if (up) 697 return bonding_set_up(bdev); 698 else 699 return bonding_set_down(bdev); 700 } 701 702 static struct device * 703 bonding_create(const char *name, struct device_type *devtype, 704 struct blob_attr *attr) 705 { 706 static const struct device_hotplug_ops bonding_ops = { 707 .prepare = bonding_hotplug_prepare, 708 .add = bonding_hotplug_add, 709 .del = bonding_hotplug_del 710 }; 711 struct bonding_device *bdev; 712 struct device *dev = NULL; 713 714 bdev = calloc(1, sizeof(*bdev)); 715 if (!bdev) 716 return NULL; 717 718 dev = &bdev->dev; 719 720 if (device_init(dev, devtype, name) < 0) { 721 device_cleanup(dev); 722 free(bdev); 723 return NULL; 724 } 725 726 dev->config_pending = true; 727 bdev->retry.cb = bonding_retry_ports; 728 729 bdev->set_state = dev->set_state; 730 dev->set_state = bonding_set_state; 731 732 dev->hotplug_ops = &bonding_ops; 733 734 vlist_init(&bdev->ports, avl_strcmp, bonding_port_update); 735 bdev->ports.keep_old = true; 736 737 bonding_reload(dev, attr); 738 739 return dev; 740 } 741 742 static void 743 bonding_free(struct device *dev) 744 { 745 struct bonding_device *bdev; 746 747 bdev = container_of(dev, struct bonding_device, dev); 748 vlist_flush_all(&bdev->ports); 749 free(bdev->config_data); 750 free(bdev); 751 } 752 753 static struct device_type bonding_device_type = { 754 .name = "bonding", 755 .config_params = &bonding_attr_list, 756 757 .bridge_capability = true, 758 759 .create = bonding_create, 760 .config_init = bonding_config_init, 761 .reload = bonding_reload, 762 .free = bonding_free, 763 }; 764 765 static void __init bonding_device_type_init(void) 766 { 767 device_type_add(&bonding_device_type); 768 } 769
This page was automatically generated by LXR 0.3.1. • OpenWrt