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 /* Disable IPv6 for bonding ports */
225 if (!(bp
->dev
.dev
->settings
.flags
& DEV_OPT_IPV6
)) {
226 bp
->dev
.dev
->settings
.ipv6
= 0;
227 bp
->dev
.dev
->settings
.flags
|= DEV_OPT_IPV6
;
230 ret
= device_claim(&bp
->dev
);
234 ret
= bonding_set_active(bdev
, true);
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);
261 device_release(&bp
->dev
);
267 bonding_port_cb(struct device_user
*dep
, enum device_event ev
)
269 struct bonding_port
*bp
= container_of(dep
, struct bonding_port
, dev
);
270 struct bonding_device
*bdev
= bp
->bdev
;
271 struct device
*dev
= dep
->dev
;
281 if (bdev
->n_present
== 1)
282 device_set_present(&bdev
->dev
, true);
284 case DEV_EVENT_AUTH_UP
:
285 if (!bdev
->dev
.active
)
288 if (bonding_enable_port(bp
))
292 * Adding a bonding port can overwrite the bonding device mtu
293 * in the kernel, apply the bonding settings in case the
294 * bonding device mtu is set
296 system_if_apply_settings(&bdev
->dev
, &bdev
->dev
.settings
,
297 DEV_OPT_MTU
| DEV_OPT_MTU6
);
299 case DEV_EVENT_LINK_DOWN
:
300 if (!dev
->settings
.auth
)
303 bonding_disable_port(bp
, true);
305 case DEV_EVENT_REMOVE
:
306 if (dep
->hotplug
&& !dev
->sys_present
) {
307 vlist_delete(&bdev
->ports
, &bp
->node
);
312 bonding_remove_port(bp
);
320 static struct bonding_port
*
321 bonding_create_port(struct bonding_device
*bdev
, const char *name
,
322 struct device
*dev
, bool hotplug
)
324 struct bonding_port
*bp
;
326 bp
= calloc(1, sizeof(*bp
) + strlen(name
) + 1);
331 bp
->dev
.cb
= bonding_port_cb
;
332 bp
->dev
.hotplug
= hotplug
;
333 strcpy(bp
->name
, name
);
335 vlist_add(&bdev
->ports
, &bp
->node
, bp
->name
);
337 * Need to look up the bonding port again as the above
338 * created pointer will be freed in case the bonding port
344 bp
= vlist_find(&bdev
->ports
, name
, bp
, node
);
346 bp
->node
.version
= -1;
352 bonding_config_init(struct device
*dev
)
354 struct bonding_device
*bdev
;
355 struct blob_attr
*cur
;
358 bdev
= container_of(dev
, struct bonding_device
, dev
);
362 vlist_update(&bdev
->ports
);
363 blobmsg_for_each_attr(cur
, bdev
->port_list
, rem
) {
364 const char *name
= blobmsg_get_string(cur
);
366 dev
= device_get(name
, true);
370 bonding_create_port(bdev
, name
, dev
, false);
372 vlist_flush(&bdev
->ports
);
375 uloop_timeout_set(&bdev
->retry
, 100);
379 bonding_apply_settings(struct bonding_device
*bdev
, struct blob_attr
**tb
)
381 struct bonding_config
*cfg
= &bdev
->config
;
382 struct blob_attr
*cur
;
385 memset(cfg
, 0, sizeof(*cfg
));
386 cfg
->resend_igmp
= 1;
387 cfg
->ad_actor_sys_prio
= 65535;
388 cfg
->lp_interval
= 1;
389 cfg
->num_peer_notif
= 1;
391 #define cfg_item(_type, _field, _attr) \
393 if ((cur = tb[BOND_ATTR_##_attr]) != NULL) \
394 cfg->_field = blobmsg_get_##_type(cur); \
397 if ((cur
= tb
[BOND_ATTR_POLICY
]) != NULL
) {
398 const char *policy
= blobmsg_get_string(cur
);
401 for (i
= 0; i
< ARRAY_SIZE(bonding_policy_str
); i
++) {
402 if (strcmp(policy
, bonding_policy_str
[i
]) != 0)
410 cfg_item(string
, xmit_hash_policy
, XMIT_HASH_POLICY
);
411 cfg_item(bool, all_ports_active
, ALL_PORTS_ACTIVE
);
412 cfg_item(u32
, min_links
, MIN_LINKS
);
413 cfg_item(string
, ad_actor_system
, AD_ACTOR_SYSTEM
);
414 cfg_item(u32
, ad_actor_sys_prio
, AD_ACTOR_SYS_PRIO
);
415 cfg_item(string
, ad_select
, AD_SELECT
);
416 cfg_item(string
, lacp_rate
, LACP_RATE
);
417 cfg_item(u32
, packets_per_port
, PACKETS_PER_PORT
);
418 cfg_item(u32
, lp_interval
, LP_INTERVAL
);
419 cfg_item(bool, dynamic_lb
, DYNAMIC_LB
);
420 cfg_item(u32
, resend_igmp
, RESEND_IGMP
);
421 cfg_item(u32
, num_peer_notif
, NUM_PEER_NOTIF
);
422 cfg_item(string
, primary
, PRIMARY
);
423 cfg_item(string
, primary_reselect
, PRIMARY_RESELECT
);
424 cfg_item(string
, failover_mac
, FAILOVER_MAC
);
425 cfg_item(u32
, monitor_interval
, MON_INTERVAL
);
426 cfg_item(bool, arp_all_targets
, ARP_ALL_TARGETS
);
427 cfg_item(string
, arp_validate
, ARP_VALIDATE
);
428 cfg_item(bool, use_carrier
, USE_CARRIER
);
429 cfg_item(u32
, updelay
, UPDELAY
);
430 cfg_item(u32
, downdelay
, DOWNDELAY
);
432 if ((cur
= tb
[BOND_ATTR_MON_MODE
]) != NULL
&&
433 !strcmp(blobmsg_get_string(cur
), "arp"))
434 cfg
->monitor_arp
= true;
435 cfg
->arp_target
= tb
[BOND_ATTR_ARP_TARGET
];
439 static enum dev_change_type
440 bonding_reload(struct device
*dev
, struct blob_attr
*attr
)
442 struct blob_attr
*tb_dev
[__DEV_ATTR_MAX
];
443 struct blob_attr
*tb_b
[__BOND_ATTR_MAX
];
444 enum dev_change_type ret
= DEV_CONFIG_APPLIED
;
445 unsigned long diff
[2] = {};
446 struct bonding_device
*bdev
;
448 BUILD_BUG_ON(sizeof(diff
[0]) < __BOND_ATTR_MAX
/ 8);
449 BUILD_BUG_ON(sizeof(diff
) < __DEV_ATTR_MAX
/ 8);
451 bdev
= container_of(dev
, struct bonding_device
, dev
);
452 attr
= blob_memdup(attr
);
454 blobmsg_parse(device_attr_list
.params
, __DEV_ATTR_MAX
, tb_dev
,
455 blob_data(attr
), blob_len(attr
));
456 blobmsg_parse(bonding_attrs
, __BOND_ATTR_MAX
, tb_b
,
457 blob_data(attr
), blob_len(attr
));
459 bdev
->has_macaddr
= tb_dev
[DEV_ATTR_MACADDR
];
460 if (bdev
->primary_port
&& !bdev
->primary_port
->set_primary
&&
461 tb_dev
[DEV_ATTR_MACADDR
])
462 bdev
->primary_port
= NULL
;
464 bdev
->port_list
= tb_b
[BOND_ATTR_PORTS
];
465 device_init_settings(dev
, tb_dev
);
466 bonding_apply_settings(bdev
, tb_b
);
468 if (bdev
->config_data
) {
469 struct blob_attr
*otb_dev
[__DEV_ATTR_MAX
];
470 struct blob_attr
*otb_b
[__BOND_ATTR_MAX
];
472 blobmsg_parse(device_attr_list
.params
, __DEV_ATTR_MAX
, otb_dev
,
473 blob_data(bdev
->config_data
), blob_len(bdev
->config_data
));
475 uci_blob_diff(tb_dev
, otb_dev
, &device_attr_list
, diff
);
476 if (diff
[0] | diff
[1])
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
[0] & ~(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
);
568 device_remove_user(&bp
->dev
);
571 * When reloading the config and moving a device from one master to
572 * another, the other master may have tried to claim this device
573 * before it was removed here.
574 * Ensure that claiming the device is retried by toggling its present
578 device_set_present(dev
, false);
579 device_set_present(dev
, true);
586 bonding_port_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
587 struct vlist_node
*node_old
)
589 struct bonding_port
*bp
;
593 bp
= container_of(node_new
, struct bonding_port
, node
);
602 device_add_user(&bp
->dev
, dev
);
607 bp
= container_of(node_old
, struct bonding_port
, node
);
608 bonding_free_port(bp
);
613 bonding_set_down(struct bonding_device
*bdev
)
615 struct bonding_port
*bp
;
617 bdev
->set_state(&bdev
->dev
, false);
619 vlist_for_each_element(&bdev
->ports
, bp
, node
)
620 bonding_disable_port(bp
, false);
622 bonding_set_active(bdev
, false);
628 bonding_set_up(struct bonding_device
*bdev
)
630 struct bonding_port
*bp
;
633 if (!bdev
->n_present
) {
634 if (!bdev
->force_active
)
637 ret
= bonding_set_active(bdev
, true);
643 vlist_for_each_element(&bdev
->ports
, bp
, node
)
644 bonding_enable_port(bp
);
646 uloop_timeout_set(&bdev
->retry
, 100);
648 if (!bdev
->force_active
&& !bdev
->n_present
) {
649 /* initialization of all port interfaces failed */
650 bonding_set_active(bdev
, false);
651 device_set_present(&bdev
->dev
, false);
655 bonding_reset_primary(bdev
);
656 ret
= bdev
->set_state(&bdev
->dev
, true);
658 bonding_set_down(bdev
);
664 bonding_set_state(struct device
*dev
, bool up
)
666 struct bonding_device
*bdev
;
668 bdev
= container_of(dev
, struct bonding_device
, dev
);
671 return bonding_set_up(bdev
);
673 return bonding_set_down(bdev
);
676 static struct device
*
677 bonding_create(const char *name
, struct device_type
*devtype
,
678 struct blob_attr
*attr
)
680 static const struct device_hotplug_ops bonding_ops
= {
681 .prepare
= bonding_hotplug_prepare
,
682 .add
= bonding_hotplug_add
,
683 .del
= bonding_hotplug_del
685 struct bonding_device
*bdev
;
686 struct device
*dev
= NULL
;
688 bdev
= calloc(1, sizeof(*bdev
));
694 if (device_init(dev
, devtype
, name
) < 0) {
700 dev
->config_pending
= true;
701 bdev
->retry
.cb
= bonding_retry_ports
;
703 bdev
->set_state
= dev
->set_state
;
704 dev
->set_state
= bonding_set_state
;
706 dev
->hotplug_ops
= &bonding_ops
;
708 vlist_init(&bdev
->ports
, avl_strcmp
, bonding_port_update
);
709 bdev
->ports
.keep_old
= true;
711 bonding_reload(dev
, attr
);
717 bonding_free(struct device
*dev
)
719 struct bonding_device
*bdev
;
721 bdev
= container_of(dev
, struct bonding_device
, dev
);
722 vlist_flush_all(&bdev
->ports
);
723 free(bdev
->config_data
);
727 static struct device_type bonding_device_type
= {
729 .config_params
= &bonding_attr_list
,
731 .bridge_capability
= true,
733 .create
= bonding_create
,
734 .config_init
= bonding_config_init
,
735 .reload
= bonding_reload
,
736 .free
= bonding_free
,
739 static void __init
bonding_device_type_init(void)
741 device_type_add(&bonding_device_type
);