2 * netifd - network interface daemon
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
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
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.
22 struct bonding_device
{
24 device_state_cb set_state
;
26 struct blob_attr
*port_list
;
27 struct vlist_tree ports
;
31 struct bonding_port
*primary_port
;
32 struct uloop_timeout retry
;
34 struct bonding_config config
;
35 struct blob_attr
*config_data
;
42 struct vlist_node node
;
43 struct bonding_device
*bdev
;
44 struct device_user dev
;
55 BOND_ATTR_XMIT_HASH_POLICY
,
56 BOND_ATTR_ALL_PORTS_ACTIVE
,
59 BOND_ATTR_AD_ACTOR_SYSTEM
,
60 BOND_ATTR_AD_ACTOR_SYS_PRIO
,
64 BOND_ATTR_PACKETS_PER_PORT
,
65 BOND_ATTR_LP_INTERVAL
,
67 BOND_ATTR_RESEND_IGMP
,
69 BOND_ATTR_NUM_PEER_NOTIF
,
71 BOND_ATTR_PRIMARY_RESELECT
,
72 BOND_ATTR_FAILOVER_MAC
,
75 BOND_ATTR_MON_INTERVAL
,
77 BOND_ATTR_ARP_ALL_TARGETS
,
78 BOND_ATTR_ARP_VALIDATE
,
79 BOND_ATTR_USE_CARRIER
,
86 static const struct blobmsg_policy bonding_attrs
[__BOND_ATTR_MAX
] = {
87 [BOND_ATTR_PORTS
] = { "ports", BLOBMSG_TYPE_ARRAY
},
88 [BOND_ATTR_POLICY
] = { "policy", BLOBMSG_TYPE_STRING
},
89 [BOND_ATTR_XMIT_HASH_POLICY
] = { "xmit_hash_policy", BLOBMSG_TYPE_STRING
},
90 [BOND_ATTR_ALL_PORTS_ACTIVE
] = { "all_ports_active", BLOBMSG_TYPE_BOOL
},
91 [BOND_ATTR_MIN_LINKS
] = { "min_links", BLOBMSG_TYPE_INT32
},
92 [BOND_ATTR_AD_ACTOR_SYSTEM
] = { "ad_actor_system", BLOBMSG_TYPE_STRING
},
93 [BOND_ATTR_AD_ACTOR_SYS_PRIO
] = { "ad_actor_sys_prio", BLOBMSG_TYPE_INT32
},
94 [BOND_ATTR_AD_SELECT
] = { "ad_select", BLOBMSG_TYPE_STRING
},
95 [BOND_ATTR_LACP_RATE
] = { "lacp_rate", BLOBMSG_TYPE_STRING
},
96 [BOND_ATTR_PACKETS_PER_PORT
] = { "packets_per_port", BLOBMSG_TYPE_INT32
},
97 [BOND_ATTR_LP_INTERVAL
] = { "lp_interval", BLOBMSG_TYPE_INT32
},
98 [BOND_ATTR_DYNAMIC_LB
] = { "dynamic_lb", BLOBMSG_TYPE_BOOL
},
99 [BOND_ATTR_RESEND_IGMP
] = { "resend_igmp", BLOBMSG_TYPE_INT32
},
100 [BOND_ATTR_NUM_PEER_NOTIF
] = { "num_peer_notif", BLOBMSG_TYPE_INT32
},
101 [BOND_ATTR_PRIMARY
] = { "primary", BLOBMSG_TYPE_STRING
},
102 [BOND_ATTR_PRIMARY_RESELECT
] = { "primary_reselect", BLOBMSG_TYPE_STRING
},
103 [BOND_ATTR_FAILOVER_MAC
] = { "failover_mac", BLOBMSG_TYPE_STRING
},
104 [BOND_ATTR_MON_MODE
] = { "monitor_mode", BLOBMSG_TYPE_STRING
},
105 [BOND_ATTR_MON_INTERVAL
] = { "monitor_interval", BLOBMSG_TYPE_INT32
},
106 [BOND_ATTR_ARP_TARGET
] = { "arp_target", BLOBMSG_TYPE_ARRAY
},
107 [BOND_ATTR_ARP_ALL_TARGETS
] = { "arp_all_targets", BLOBMSG_TYPE_BOOL
},
108 [BOND_ATTR_ARP_VALIDATE
] = { "arp_validate", BLOBMSG_TYPE_STRING
},
109 [BOND_ATTR_USE_CARRIER
] = { "use_carrier", BLOBMSG_TYPE_BOOL
},
110 [BOND_ATTR_UPDELAY
] = { "updelay", BLOBMSG_TYPE_INT32
},
111 [BOND_ATTR_DOWNDELAY
] = { "downdelay", BLOBMSG_TYPE_INT32
},
114 static const struct uci_blob_param_info bonding_attr_info
[__BOND_ATTR_MAX
] = {
115 [BOND_ATTR_PORTS
] = { .type
= BLOBMSG_TYPE_STRING
},
116 [BOND_ATTR_ARP_TARGET
] = { .type
= BLOBMSG_TYPE_STRING
},
119 static const struct uci_blob_param_list bonding_attr_list
= {
120 .n_params
= __BOND_ATTR_MAX
,
121 .params
= bonding_attrs
,
122 .info
= bonding_attr_info
,
125 .next
= { &device_attr_list
},
129 bonding_reset_primary(struct bonding_device
*bdev
)
131 struct bonding_port
*bp
;
133 bdev
->primary_port
= NULL
;
134 if (!bdev
->has_macaddr
)
135 bdev
->dev
.settings
.flags
&= ~DEV_OPT_MACADDR
;
137 vlist_for_each_element(&bdev
->ports
, bp
, node
) {
143 if (bdev
->primary_port
&& !bp
->set_primary
)
146 bdev
->primary_port
= bp
;
147 if (bdev
->has_macaddr
)
150 if (bp
->dev
.dev
->settings
.flags
& DEV_OPT_MACADDR
)
151 macaddr
= bp
->dev
.dev
->settings
.macaddr
;
153 macaddr
= bp
->dev
.dev
->orig_settings
.macaddr
;
154 memcpy(bdev
->dev
.settings
.macaddr
, macaddr
, 6);
155 bdev
->dev
.settings
.flags
|= DEV_OPT_MACADDR
;
160 bonding_disable_port(struct bonding_port
*bp
, bool keep_dev
)
162 struct bonding_device
*bdev
= bp
->bdev
;
164 if (!bp
->present
|| !bp
->active
)
169 system_bonding_set_port(&bdev
->dev
, bp
->dev
.dev
, false, bp
->set_primary
);
171 device_release(&bp
->dev
);
177 bonding_remove_port(struct bonding_port
*bp
)
179 struct bonding_device
*bdev
= bp
->bdev
;
184 if (bdev
->dev
.active
)
185 bonding_disable_port(bp
, false);
188 bp
->bdev
->n_present
--;
190 if (bp
== bdev
->primary_port
)
191 bonding_reset_primary(bdev
);
193 bdev
->force_active
= false;
194 if (bdev
->n_present
== 0)
195 device_set_present(&bdev
->dev
, false);
199 bonding_set_active(struct bonding_device
*bdev
, bool active
)
203 if (bdev
->active
== active
)
206 ret
= system_bonding_set_device(&bdev
->dev
, active
? &bdev
->config
: NULL
);
210 bdev
->active
= active
;
215 bonding_enable_port(struct bonding_port
*bp
)
217 struct bonding_device
*bdev
= bp
->bdev
;
224 ret
= bonding_set_active(bdev
, true);
228 /* Disable IPv6 for bonding ports */
229 if (!(bp
->dev
.dev
->settings
.flags
& DEV_OPT_IPV6
)) {
230 bp
->dev
.dev
->settings
.ipv6
= 0;
231 bp
->dev
.dev
->settings
.flags
|= DEV_OPT_IPV6
;
234 ret
= device_claim(&bp
->dev
);
239 if (dev
->settings
.auth
&& !dev
->auth_status
)
245 ret
= system_bonding_set_port(&bdev
->dev
, bp
->dev
.dev
, true, bp
->set_primary
);
247 D(DEVICE
, "Bonding port %s could not be added\n", bp
->dev
.dev
->ifname
);
252 device_set_present(&bdev
->dev
, true);
260 device_release(&bp
->dev
);
266 bonding_port_cb(struct device_user
*dep
, enum device_event ev
)
268 struct bonding_port
*bp
= container_of(dep
, struct bonding_port
, dev
);
269 struct bonding_device
*bdev
= bp
->bdev
;
270 struct device
*dev
= dep
->dev
;
280 if (bdev
->n_present
== 1)
281 device_set_present(&bdev
->dev
, true);
283 case DEV_EVENT_AUTH_UP
:
284 if (!bdev
->dev
.active
)
287 if (bonding_enable_port(bp
))
291 * Adding a bonding port can overwrite the bonding device mtu
292 * in the kernel, apply the bonding settings in case the
293 * bonding device mtu is set
295 system_if_apply_settings(&bdev
->dev
, &bdev
->dev
.settings
,
296 DEV_OPT_MTU
| DEV_OPT_MTU6
);
298 case DEV_EVENT_LINK_DOWN
:
299 if (!dev
->settings
.auth
)
302 bonding_disable_port(bp
, true);
304 case DEV_EVENT_REMOVE
:
306 vlist_delete(&bdev
->ports
, &bp
->node
);
311 bonding_remove_port(bp
);
319 static struct bonding_port
*
320 bonding_create_port(struct bonding_device
*bdev
, const char *name
,
321 struct device
*dev
, bool hotplug
)
323 struct bonding_port
*bp
;
325 bp
= calloc(1, sizeof(*bp
) + strlen(name
) + 1);
330 bp
->dev
.cb
= bonding_port_cb
;
331 bp
->dev
.hotplug
= hotplug
;
332 strcpy(bp
->name
, name
);
334 vlist_add(&bdev
->ports
, &bp
->node
, bp
->name
);
336 * Need to look up the bonding port again as the above
337 * created pointer will be freed in case the bonding port
343 bp
= vlist_find(&bdev
->ports
, name
, bp
, node
);
345 bp
->node
.version
= -1;
351 bonding_config_init(struct device
*dev
)
353 struct bonding_device
*bdev
;
354 struct blob_attr
*cur
;
357 bdev
= container_of(dev
, struct bonding_device
, dev
);
361 vlist_update(&bdev
->ports
);
362 blobmsg_for_each_attr(cur
, bdev
->port_list
, rem
) {
363 const char *name
= blobmsg_get_string(cur
);
365 dev
= device_get(name
, true);
369 bonding_create_port(bdev
, name
, dev
, false);
371 vlist_flush(&bdev
->ports
);
374 uloop_timeout_set(&bdev
->retry
, 100);
378 bonding_apply_settings(struct bonding_device
*bdev
, struct blob_attr
**tb
)
380 struct bonding_config
*cfg
= &bdev
->config
;
381 struct blob_attr
*cur
;
384 memset(cfg
, 0, sizeof(*cfg
));
385 cfg
->resend_igmp
= 1;
386 cfg
->ad_actor_sys_prio
= 65535;
387 cfg
->lp_interval
= 1;
388 cfg
->num_peer_notif
= 1;
390 #define cfg_item(_type, _field, _attr) \
392 if ((cur = tb[BOND_ATTR_##_attr]) != NULL) \
393 cfg->_field = blobmsg_get_##_type(cur); \
396 if ((cur
= tb
[BOND_ATTR_POLICY
]) != NULL
) {
397 const char *policy
= blobmsg_get_string(cur
);
400 for (i
= 0; i
< ARRAY_SIZE(bonding_policy_str
); i
++) {
401 if (strcmp(policy
, bonding_policy_str
[i
]) != 0)
409 cfg_item(string
, xmit_hash_policy
, XMIT_HASH_POLICY
);
410 cfg_item(bool, all_ports_active
, ALL_PORTS_ACTIVE
);
411 cfg_item(u32
, min_links
, MIN_LINKS
);
412 cfg_item(string
, ad_actor_system
, AD_ACTOR_SYSTEM
);
413 cfg_item(u32
, ad_actor_sys_prio
, AD_ACTOR_SYS_PRIO
);
414 cfg_item(string
, ad_select
, AD_SELECT
);
415 cfg_item(string
, lacp_rate
, LACP_RATE
);
416 cfg_item(u32
, packets_per_port
, PACKETS_PER_PORT
);
417 cfg_item(u32
, lp_interval
, LP_INTERVAL
);
418 cfg_item(bool, dynamic_lb
, DYNAMIC_LB
);
419 cfg_item(u32
, resend_igmp
, RESEND_IGMP
);
420 cfg_item(u32
, num_peer_notif
, NUM_PEER_NOTIF
);
421 cfg_item(string
, primary
, PRIMARY
);
422 cfg_item(string
, primary_reselect
, PRIMARY_RESELECT
);
423 cfg_item(string
, failover_mac
, FAILOVER_MAC
);
424 cfg_item(u32
, monitor_interval
, MON_INTERVAL
);
425 cfg_item(bool, arp_all_targets
, ARP_ALL_TARGETS
);
426 cfg_item(string
, arp_validate
, ARP_VALIDATE
);
427 cfg_item(bool, use_carrier
, USE_CARRIER
);
428 cfg_item(u32
, updelay
, UPDELAY
);
429 cfg_item(u32
, downdelay
, DOWNDELAY
);
431 if ((cur
= tb
[BOND_ATTR_MON_MODE
]) != NULL
&&
432 !strcmp(blobmsg_get_string(cur
), "arp"))
433 cfg
->monitor_arp
= true;
434 cfg
->arp_target
= tb
[BOND_ATTR_ARP_TARGET
];
438 static enum dev_change_type
439 bonding_reload(struct device
*dev
, struct blob_attr
*attr
)
441 struct blob_attr
*tb_dev
[__DEV_ATTR_MAX
];
442 struct blob_attr
*tb_b
[__BOND_ATTR_MAX
];
443 enum dev_change_type ret
= DEV_CONFIG_APPLIED
;
445 struct bonding_device
*bdev
;
447 BUILD_BUG_ON(sizeof(diff
) < __BOND_ATTR_MAX
/ 8);
448 BUILD_BUG_ON(sizeof(diff
) < __DEV_ATTR_MAX
/ 8);
450 bdev
= container_of(dev
, struct bonding_device
, dev
);
451 attr
= blob_memdup(attr
);
453 blobmsg_parse(device_attr_list
.params
, __DEV_ATTR_MAX
, tb_dev
,
454 blob_data(attr
), blob_len(attr
));
455 blobmsg_parse(bonding_attrs
, __BOND_ATTR_MAX
, tb_b
,
456 blob_data(attr
), blob_len(attr
));
458 bdev
->has_macaddr
= tb_dev
[DEV_ATTR_MACADDR
];
459 if (bdev
->primary_port
&& !bdev
->primary_port
->set_primary
&&
460 tb_dev
[DEV_ATTR_MACADDR
])
461 bdev
->primary_port
= NULL
;
463 bdev
->port_list
= tb_b
[BOND_ATTR_PORTS
];
464 device_init_settings(dev
, tb_dev
);
465 bonding_apply_settings(bdev
, tb_b
);
467 if (bdev
->config_data
) {
468 struct blob_attr
*otb_dev
[__DEV_ATTR_MAX
];
469 struct blob_attr
*otb_b
[__BOND_ATTR_MAX
];
471 blobmsg_parse(device_attr_list
.params
, __DEV_ATTR_MAX
, otb_dev
,
472 blob_data(bdev
->config_data
), blob_len(bdev
->config_data
));
475 uci_blob_diff(tb_dev
, otb_dev
, &device_attr_list
, &diff
);
477 ret
= DEV_CONFIG_RESTART
;
479 blobmsg_parse(bonding_attrs
, __BOND_ATTR_MAX
, otb_b
,
480 blob_data(bdev
->config_data
), blob_len(bdev
->config_data
));
483 uci_blob_diff(tb_b
, otb_b
, &bonding_attr_list
, &diff
);
484 if (diff
& ~(1 << BOND_ATTR_PORTS
))
485 ret
= DEV_CONFIG_RESTART
;
487 bonding_config_init(dev
);
490 free(bdev
->config_data
);
491 bdev
->config_data
= attr
;
497 bonding_hotplug_add(struct device
*dev
, struct device
*port
, struct blob_attr
*vlan
)
499 struct bonding_device
*bdev
= container_of(dev
, struct bonding_device
, dev
);
500 struct bonding_port
*bp
;
502 bp
= vlist_find(&bdev
->ports
, port
->ifname
, bp
, node
);
504 bonding_create_port(bdev
, port
->ifname
, port
, true);
510 bonding_hotplug_del(struct device
*dev
, struct device
*port
, struct blob_attr
*vlan
)
512 struct bonding_device
*bdev
= container_of(dev
, struct bonding_device
, dev
);
513 struct bonding_port
*bp
;
515 bp
= vlist_find(&bdev
->ports
, port
->ifname
, bp
, node
);
517 return UBUS_STATUS_NOT_FOUND
;
520 vlist_delete(&bdev
->ports
, &bp
->node
);
526 bonding_hotplug_prepare(struct device
*dev
, struct device
**bonding_dev
)
528 struct bonding_device
*bdev
;
533 bdev
= container_of(dev
, struct bonding_device
, dev
);
534 bdev
->force_active
= true;
535 device_set_present(&bdev
->dev
, true);
541 bonding_retry_ports(struct uloop_timeout
*timeout
)
543 struct bonding_device
*bdev
= container_of(timeout
, struct bonding_device
, retry
);
544 struct bonding_port
*bp
;
547 vlist_for_each_element(&bdev
->ports
, bp
, node
) {
551 if (!bp
->dev
.dev
->present
)
556 bonding_enable_port(bp
);
562 bonding_free_port(struct bonding_port
*bp
)
564 struct device
*dev
= bp
->dev
.dev
;
566 bonding_remove_port(bp
);
570 device_remove_user(&bp
->dev
);
573 * When reloading the config and moving a device from one master to
574 * another, the other master may have tried to claim this device
575 * before it was removed here.
576 * Ensure that claiming the device is retried by toggling its present
580 device_set_present(dev
, false);
581 device_set_present(dev
, true);
590 bonding_port_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
591 struct vlist_node
*node_old
)
593 struct bonding_port
*bp
;
597 bp
= container_of(node_new
, struct bonding_port
, node
);
606 device_add_user(&bp
->dev
, dev
);
611 bp
= container_of(node_old
, struct bonding_port
, node
);
612 bonding_free_port(bp
);
617 bonding_set_down(struct bonding_device
*bdev
)
619 struct bonding_port
*bp
;
621 bdev
->set_state(&bdev
->dev
, false);
623 vlist_for_each_element(&bdev
->ports
, bp
, node
)
624 bonding_disable_port(bp
, false);
626 bonding_set_active(bdev
, false);
632 bonding_set_up(struct bonding_device
*bdev
)
634 struct bonding_port
*bp
;
637 if (!bdev
->n_present
) {
638 if (!bdev
->force_active
)
641 ret
= bonding_set_active(bdev
, true);
647 vlist_for_each_element(&bdev
->ports
, bp
, node
)
648 bonding_enable_port(bp
);
650 uloop_timeout_set(&bdev
->retry
, 100);
652 if (!bdev
->force_active
&& !bdev
->n_present
) {
653 /* initialization of all port interfaces failed */
654 bonding_set_active(bdev
, false);
655 device_set_present(&bdev
->dev
, false);
659 bonding_reset_primary(bdev
);
660 ret
= bdev
->set_state(&bdev
->dev
, true);
662 bonding_set_down(bdev
);
668 bonding_set_state(struct device
*dev
, bool up
)
670 struct bonding_device
*bdev
;
672 bdev
= container_of(dev
, struct bonding_device
, dev
);
675 return bonding_set_up(bdev
);
677 return bonding_set_down(bdev
);
680 static struct device
*
681 bonding_create(const char *name
, struct device_type
*devtype
,
682 struct blob_attr
*attr
)
684 static const struct device_hotplug_ops bonding_ops
= {
685 .prepare
= bonding_hotplug_prepare
,
686 .add
= bonding_hotplug_add
,
687 .del
= bonding_hotplug_del
689 struct bonding_device
*bdev
;
690 struct device
*dev
= NULL
;
692 bdev
= calloc(1, sizeof(*bdev
));
698 if (device_init(dev
, devtype
, name
) < 0) {
704 dev
->config_pending
= true;
705 bdev
->retry
.cb
= bonding_retry_ports
;
707 bdev
->set_state
= dev
->set_state
;
708 dev
->set_state
= bonding_set_state
;
710 dev
->hotplug_ops
= &bonding_ops
;
712 vlist_init(&bdev
->ports
, avl_strcmp
, bonding_port_update
);
713 bdev
->ports
.keep_old
= true;
715 bonding_reload(dev
, attr
);
721 bonding_free(struct device
*dev
)
723 struct bonding_device
*bdev
;
725 bdev
= container_of(dev
, struct bonding_device
, dev
);
726 vlist_flush_all(&bdev
->ports
);
727 free(bdev
->config_data
);
731 static struct device_type bonding_device_type
= {
733 .config_params
= &bonding_attr_list
,
735 .bridge_capability
= true,
737 .create
= bonding_create
,
738 .config_init
= bonding_config_init
,
739 .reload
= bonding_reload
,
740 .free
= bonding_free
,
743 static void __init
bonding_device_type_init(void)
745 device_type_add(&bonding_device_type
);