2 * netifd - network interface daemon
3 * Copyright (C) 2015 Arne Kappen <arne.kappen@hhi.fraunhofer.de>
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.
15 * extdev - external device handler interface
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.
31 #include <libubox/blobmsg.h>
32 #include <libubox/list.h>
41 #include "interface.h"
45 static struct blob_buf b
;
46 static int confdir_fd
= -1;
49 struct device_type handler
;
53 struct ubus_subscriber ubus_sub
;
55 struct ubus_event_handler obj_wait
;
57 struct uci_blob_param_list
*config_params
;
60 struct uci_blob_param_list
*info_params
;
63 struct uci_blob_param_list
*stats_params
;
67 struct extdev_device
{
69 struct extdev_type
*etype
;
71 struct uloop_timeout retry
;
74 struct extdev_bridge
{
75 struct extdev_device edev
;
76 device_state_cb set_state
;
78 struct blob_attr
*config
;
80 struct blob_attr
*ifnames
;
84 struct uloop_timeout retry
;
85 struct vlist_tree members
;
90 struct extdev_bridge_member
{
91 struct vlist_node node
;
92 struct extdev_bridge
*parent_br
;
93 struct device_user dev_usr
;
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
);
109 METHOD_HOTPLUG_PREPARE
,
111 METHOD_HOTPLUG_REMOVE
,
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",
129 netifd_extdev_create(struct extdev_device
*edev
, struct blob_attr
*msg
)
131 D(DEVICE
, "create %s '%s' at external device handler\n", edev
->dev
.type
->name
,
133 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_CREATE
], msg
,
138 netifd_extdev_reload(struct extdev_device
*edev
, struct blob_attr
*msg
)
140 D(DEVICE
, "reload %s '%s' at external device handler\n", edev
->dev
.type
->name
,
142 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_RELOAD
], msg
,
147 netifd_extdev_free(struct extdev_device
*edev
, struct blob_attr
*msg
)
149 D(DEVICE
, "delete %s '%s' with external device handler\n", edev
->dev
.type
->name
,
151 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_FREE
], msg
,
156 netifd_extdev_prepare(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
158 D(DEVICE
, "prepare %s bridge '%s' at external device handler\n", 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
);
165 netifd_extdev_add(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
167 D(DEVICE
, "add a member to %s bridge '%s' at external device handler\n",
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
);
174 netifd_extdev_remove(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
176 D(DEVICE
, "remove a member from %s bridge '%s' at external device handler\n",
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
);
183 extdev_invocation_error(int error
, const char *method
, const char *devname
)
185 netifd_log_message(L_CRIT
, "'%s' failed for '%s': %s\n",
186 method
, devname
, ubus_strerror(error
));
189 static struct ubus_method extdev_ubus_obj_methods
[] = {};
191 static struct ubus_object_type extdev_ubus_object_type
=
192 UBUS_OBJECT_TYPE("netifd_extdev", extdev_ubus_obj_methods
);
195 extdev_lookup_id(struct extdev_type
*etype
)
197 int ret
= UBUS_STATUS_UNKNOWN_ERROR
;
199 if (!etype
|| !etype
->name
)
202 ret
= ubus_lookup_id(ubus_ctx
, etype
->name
, &etype
->peer_id
);
209 netifd_log_message(L_CRIT
, "Could not find '%s' ubus ID: %s\n",
210 etype
->name
, ubus_strerror(ret
));
215 extdev_ext_ubus_obj_wait(struct ubus_event_handler
*h
)
217 return ubus_register_event_handler(ubus_ctx
, h
, "ubus.object.add");
221 extdev_subscribe(struct extdev_type
*etype
)
225 ret
= extdev_lookup_id(etype
);
227 etype
->subscribed
= false;
231 ret
= ubus_subscribe(ubus_ctx
, &etype
->ubus_sub
, etype
->peer_id
);
233 etype
->subscribed
= false;
234 extdev_ext_ubus_obj_wait(&etype
->obj_wait
);
236 netifd_log_message(L_NOTICE
, "subscribed to external device handler '%s'\n",
238 etype
->subscribed
= true;
245 extdev_wait_ev_cb(struct ubus_context
*ctx
, struct ubus_event_handler
*ev_handler
,
246 const char *type
, struct blob_attr
*msg
)
248 static const struct blobmsg_policy wait_policy
= {
249 "path", BLOBMSG_TYPE_STRING
252 struct blob_attr
*attr
;
254 struct extdev_type
*etype
;
256 etype
= container_of(ev_handler
, struct extdev_type
, obj_wait
);
258 if (strcmp(type
, "ubus.object.add"))
261 blobmsg_parse(&wait_policy
, 1, &attr
, blob_data(msg
), blob_len(msg
));
265 path
= blobmsg_data(attr
);
266 if (strcmp(etype
->name
, path
))
269 extdev_subscribe(etype
);
273 extdev_bridge_disable_interface(struct extdev_bridge
*ebr
)
280 blob_buf_init(&b
, 0);
281 blobmsg_add_string(&b
, "name", ebr
->edev
.dev
.ifname
);
283 ret
= netifd_extdev_free(&ebr
->edev
, b
.head
);
285 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
292 extdev_invocation_error(ret
, __extdev_methods
[METHOD_FREE
], ebr
->edev
.dev
.ifname
);
297 extdev_bridge_enable_interface(struct extdev_bridge
*ebr
)
304 ret
= netifd_extdev_create(&ebr
->edev
, ebr
->config
);
312 extdev_invocation_error(ret
, __extdev_methods
[METHOD_CREATE
], ebr
->edev
.dev
.ifname
);
317 extdev_bridge_enable_member(struct extdev_bridge_member
*ubm
)
320 struct extdev_bridge
*ebr
= ubm
->parent_br
;
322 D(DEVICE
, "%s enable member %s\n", ebr
->edev
.dev
.ifname
, ubm
->name
);
327 ret
= extdev_bridge_enable_interface(ebr
);
331 ret
= device_claim(&ubm
->dev_usr
);
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
);
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
);
343 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_ADD
],
344 ubm
->dev_usr
.dev
->ifname
);
348 device_set_present(&ebr
->edev
.dev
, true);
349 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
354 D(DEVICE
, "%s: failed to enable member '%s'\n", ebr
->edev
.dev
.ifname
, ubm
->name
);
357 ubm
->present
= false;
364 extdev_bridge_disable_member(struct extdev_bridge_member
*ubm
)
367 struct extdev_bridge
*ebr
= ubm
->parent_br
;
372 D(DEVICE
, "%s disable member %s\n", ubm
->parent_br
->edev
.dev
.ifname
, ubm
->name
);
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
);
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
);
382 /* continue in case of NOT FOUND since we're trying to remove anyway */
383 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
386 device_release(&ubm
->dev_usr
);
387 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
392 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_REMOVE
],
393 ubm
->dev_usr
.dev
->ifname
);
399 extdev_bridge_set_down(struct extdev_bridge
*ebr
)
401 D(DEVICE
, "set %s bridge %s down\n", ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
403 struct extdev_bridge_member
*ubm
;
405 ebr
->set_state(&ebr
->edev
.dev
, false);
407 vlist_for_each_element(&ebr
->members
, ubm
, node
)
408 extdev_bridge_disable_member(ubm
);
410 extdev_bridge_disable_interface(ebr
);
416 extdev_bridge_check_retry(struct extdev_bridge
*ebr
)
421 uloop_timeout_set(&ebr
->retry
, 200);
425 extdev_bridge_set_up(struct extdev_bridge
*ebr
)
427 D(DEVICE
, "set %s bridge %s up\n", ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
429 struct extdev_bridge_member
*ubm
;
432 if (!ebr
->n_present
) {
433 if (!ebr
->force_active
)
436 ret
= extdev_bridge_enable_interface(ebr
);
442 vlist_for_each_element(&ebr
->members
, ubm
, node
)
443 extdev_bridge_enable_member(ubm
);
445 extdev_bridge_check_retry(ebr
);
447 if (!ebr
->force_active
&& !ebr
->n_present
) {
448 extdev_bridge_disable_interface(ebr
);
449 device_set_present(&ebr
->edev
.dev
, false);
457 extdev_bridge_set_state(struct device
*dev
, bool up
)
459 struct extdev_bridge
*ebr
;
461 if (!dev
->type
->bridge_capability
)
464 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
467 return extdev_bridge_set_up(ebr
);
469 return extdev_bridge_set_down(ebr
);
473 extdev_bridge_remove_member(struct extdev_bridge_member
*member
)
475 struct extdev_bridge
*ebr
= member
->parent_br
;
477 if (!member
->present
)
480 if (ebr
->edev
.dev
.active
)
481 extdev_bridge_disable_member(member
);
483 member
->present
= false;
489 ebr
->force_active
= false;
490 if (ebr
->n_present
== 0)
491 device_set_present(&ebr
->edev
.dev
, false);
495 extdev_bridge_member_cb(struct device_user
*usr
, enum device_event event
)
498 struct extdev_bridge_member
*ubm
;
499 struct extdev_bridge
*ebr
;
501 ubm
= container_of(usr
, struct extdev_bridge_member
, dev_usr
);
502 ebr
= ubm
->parent_br
;
506 assert(!ubm
->present
);
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
);
519 ret
= ebr
->set_state(&ebr
->edev
.dev
, true);
521 extdev_bridge_set_down(ebr
);
522 device_set_present(&ebr
->edev
.dev
, true);
525 extdev_bridge_enable_member(ubm
);
527 case DEV_EVENT_REMOVE
:
529 vlist_delete(&ebr
->members
, &ubm
->node
);
534 extdev_bridge_remove_member(ubm
);
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;
550 __bridge_enable_members(struct extdev_bridge
*ebr
)
552 struct extdev_bridge_member
*cur
;
556 vlist_for_each_element(&ebr
->members
, cur
, node
) {
560 if (!cur
->dev_usr
.dev
->present
)
565 extdev_bridge_enable_member(cur
);
570 extdev_bridge_retry_enable_members(struct uloop_timeout
*timeout
)
572 struct extdev_bridge
*ebr
= container_of(timeout
, struct extdev_bridge
, retry
);
574 D(DEVICE
, "%s retry enable members\n", ebr
->edev
.dev
.ifname
);
576 __bridge_enable_members(ebr
);
579 static struct extdev_bridge_member
*
580 extdev_bridge_create_member(struct extdev_bridge
*ebr
, struct device
*dev
)
582 struct extdev_bridge_member
*ubm
;
585 ubm
= calloc_a(sizeof(*ubm
), &name
, strlen(dev
->ifname
) + 1);
589 ubm
->parent_br
= ebr
;
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
598 ubm
= vlist_find(&ebr
->members
, dev
->ifname
, ubm
, node
);
606 extdev_bridge_add_member(struct extdev_bridge
*ebr
, const char *name
)
608 D(DEVICE
, "%s add member %s\n", ebr
->edev
.dev
.ifname
, name
);
612 dev
= device_get(name
, 1);
616 extdev_bridge_create_member(ebr
, dev
);
619 /* TODO: how to handle vlan arg? */
621 extdev_hotplug_add(struct device
*ebr_dev
, struct device
*ebm_dev
, struct blob_attr
*vlan
)
623 D(DEVICE
, "%s hotplug add member %s\n", ebr_dev
->ifname
, ebm_dev
->ifname
);
625 struct extdev_bridge
*ebr
;
626 struct extdev_bridge_member
*ubm
;
628 if (!ebr_dev
->type
->bridge_capability
)
629 return UBUS_STATUS_NOT_SUPPORTED
;
631 ebr
= container_of(ebr_dev
, struct extdev_bridge
, edev
.dev
);
633 if (!ebr
->edev
.etype
->subscribed
)
634 return UBUS_STATUS_NOT_FOUND
;
636 ubm
= extdev_bridge_create_member(ebr
, ebm_dev
);
638 return UBUS_STATUS_UNKNOWN_ERROR
;
640 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
646 extdev_hotplug_remove(struct device
*dev
, struct device
*member
, struct blob_attr
*vlan
)
648 struct extdev_bridge
*ebr
;
649 struct extdev_bridge_member
*ubm
;
651 if (!dev
->type
->bridge_capability
)
652 return UBUS_STATUS_NOT_SUPPORTED
;
654 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
656 if (!ebr
->edev
.etype
->subscribed
)
657 return UBUS_STATUS_NOT_FOUND
;
659 ubm
= vlist_find(&ebr
->members
, member
->ifname
, ubm
, node
);
661 return UBUS_STATUS_NOT_FOUND
;
663 vlist_delete(&ebr
->members
, &ubm
->node
);
664 extdev_bridge_remove_member(ubm
);
670 extdev_hotplug_prepare(struct device
*dev
, struct device
**bridge_dev
)
672 struct extdev_bridge
*ebr
;
675 if (!dev
->type
->bridge_capability
)
676 return UBUS_STATUS_NOT_SUPPORTED
;
681 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
683 blob_buf_init(&b
, 0);
684 blobmsg_add_string(&b
, "name", dev
->ifname
);
686 ret
= netifd_extdev_prepare(ebr
, b
.head
);
690 ebr
->force_active
= true;
691 device_set_present(&ebr
->edev
.dev
, true);
696 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_PREPARE
], dev
->ifname
);
701 extdev_bridge_free_member(struct extdev_bridge_member
*ubm
)
703 struct device
*dev
= ubm
->dev_usr
.dev
;
705 extdev_bridge_remove_member(ubm
);
706 device_remove_user(&ubm
->dev_usr
);
709 device_set_present(dev
, false);
710 device_set_present(dev
, true);
717 extdev_bridge_member_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
718 struct vlist_node
*node_old
)
720 struct extdev_bridge_member
*ubm
;
724 ubm
= container_of(node_new
, struct extdev_bridge_member
, node
);
731 dev
= ubm
->dev_usr
.dev
;
732 ubm
->dev_usr
.dev
= NULL
;
733 device_add_user(&ubm
->dev_usr
, dev
);
737 ubm
= container_of(node_old
, struct extdev_bridge_member
, node
);
738 extdev_bridge_free_member(ubm
);
744 bridge_dependency_retry(struct uloop_timeout
*timeout
)
746 struct extdev_bridge
*ebr
;
748 ebr
= container_of(timeout
, struct extdev_bridge
, edev
.retry
);
750 __bridge_reload(ebr
, NULL
);
754 __buf_add_all(struct blob_attr
*attr
)
756 struct blob_attr
*cur
;
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
));
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
},
777 static enum dev_change_type
778 __do_bridge_reload(struct extdev_bridge
*ebr
, struct blob_attr
*config
)
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
);
791 ret
= netifd_extdev_reload(&ebr
->edev
, b
.head
);
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
;
798 return DEV_CONFIG_RESTART
;
802 static enum dev_change_type
803 __bridge_reload(struct extdev_bridge
*ebr
, struct blob_attr
*config
)
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
;
812 unsigned long diff
= 0;
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
]);
819 if (tb
[BRIDGE_EMPTY
] && blobmsg_get_bool(tb
[BRIDGE_EMPTY
]))
823 config_params
= ebr
->edev
.dev
.type
->config_params
;
824 pol
= config_params
->params
;
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
832 uci_blob_diff(brtb
, old_tb
, config_params
, &diff
);
834 if (diff
& ~(1 << BRIDGE_IFNAMES
)) {
835 change
= DEV_CONFIG_RESTART
;
837 change
= __do_bridge_reload(ebr
, config
);
844 ebr
->ifnames
= tb
[BRIDGE_IFNAMES
];
845 ebr
->config
= config
;
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\n",
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
;
859 __bridge_config_init(ebr
);
860 ebr
->edev
.dev
.config_pending
= false;
861 uloop_timeout_cancel(&ebr
->edev
.retry
);
866 static enum dev_change_type
867 __reload(struct extdev_device
*edev
, struct blob_attr
*config
)
869 unsigned long diff
= 0;
870 struct uci_blob_param_list
*params
;
872 params
= edev
->etype
->config_params
;
874 struct blob_attr
*tb
[params
->n_params
];
875 struct blob_attr
*old_tb
[params
->n_params
];
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
));
882 uci_blob_diff(tb
, old_tb
, edev
->etype
->config_params
, &diff
);
884 return DEV_CONFIG_NO_CHANGE
;
886 // TODO: make reload ubus call with old and new config
888 device_set_present(&edev
->dev
, false);
889 device_set_present(&edev
->dev
, true);
891 return DEV_CONFIG_APPLIED
;
894 static enum dev_change_type
895 extdev_reload(struct device
*dev
, struct blob_attr
*config
)
897 struct extdev_type
*etype
;
898 struct extdev_device
*edev
;
899 struct extdev_bridge
*ebr
;
901 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
903 if (!etype
->subscribed
)
904 return DEV_CONFIG_NO_CHANGE
;
906 edev
= container_of(dev
, struct extdev_device
, dev
);
908 if (dev
->type
->bridge_capability
) {
909 ebr
= container_of(edev
, struct extdev_bridge
, edev
);
910 return __bridge_reload(ebr
, config
);
912 return __reload(edev
, config
);
916 static struct device
*
917 __create(const char *name
, struct device_type
*type
, struct blob_attr
*config
)
919 struct extdev_device
*edev
;
920 struct extdev_type
*etype
;
923 etype
= container_of(type
, struct extdev_type
, handler
);
924 edev
= calloc(1, sizeof(struct extdev_device
));
928 ret
= device_init(&edev
->dev
, type
, name
);
934 ret
= netifd_extdev_create(edev
, config
);
938 edev
->dev
.config_pending
= false;
943 extdev_invocation_error(ret
, __extdev_methods
[METHOD_CREATE
], name
);
946 free(edev
->dev
.config
);
947 device_cleanup(&edev
->dev
);
950 netifd_log_message(L_WARNING
, "Failed to create %s %s\n", type
->name
, name
);
954 static const struct device_hotplug_ops extdev_hotplug_ops
= {
955 .prepare
= extdev_hotplug_prepare
,
956 .add
= extdev_hotplug_add
,
957 .del
= extdev_hotplug_remove
960 static struct device
*
961 __bridge_create(const char *name
, struct device_type
*devtype
, struct blob_attr
*config
)
963 struct extdev_bridge
*ebr
;
965 ebr
= calloc(1, sizeof(*ebr
));
969 device_init(&ebr
->edev
.dev
, devtype
, name
);
970 ebr
->edev
.dev
.config_pending
= true;
971 ebr
->retry
.cb
= extdev_bridge_retry_enable_members
;
972 ebr
->edev
.etype
= container_of(devtype
, struct extdev_type
, handler
);
973 ebr
->set_state
= ebr
->edev
.dev
.set_state
;
974 ebr
->edev
.dev
.set_state
= extdev_bridge_set_state
;
975 ebr
->edev
.dev
.hotplug_ops
= &extdev_hotplug_ops
;
976 vlist_init(&ebr
->members
, avl_strcmp
, extdev_bridge_member_update
);
977 ebr
->members
.keep_old
= true;
978 __bridge_reload(ebr
, config
);
980 return &ebr
->edev
.dev
;
983 /* Device creation process:
984 * For bridges without dependencies:
985 * 1) The bridge state is initialized in netifd. Devices for the members are
986 * created and added to the members vlist by config_init automatically.
987 * 2) When the first bridge member device is brought up in
988 * extdev_bridge_enable_member the 'create' call to the external device
990 * 3) After successful device creation the bridge is marked "present" and a
991 * new attempt at adding the member is made.
992 * For bridges with dependencies:
993 * 1) The bridge state is initialized in netifd. If a dependency is expressed
994 * via the 'depends_on' UCI option and the dependency is not ready (i.e. it
995 * does not exist or config_pending == true) the call to
996 * __bridge_config_init() is postponed and a retry timer is started. Retries
997 * happen until the dependency is ready. Then, __bridge_config_init() gets
998 * called and the process continues as with bridges without dependencies
999 * For regular devices:
1000 * 1) The device structure is created in netifd.
1001 * 2) config_init is called automatically which issues the 'create' call to the
1002 * external device handler.
1004 static struct device
*
1005 extdev_create(const char *name
, struct device_type
*devtype
, struct blob_attr
*config
)
1007 struct extdev_type
*etype
= container_of(devtype
, struct extdev_type
, handler
);
1009 if (!etype
->subscribed
)
1012 if (devtype
->bridge_capability
)
1013 return __bridge_create(name
, devtype
, config
);
1015 return __create(name
, devtype
, config
);
1019 extdev_free(struct device
*dev
)
1021 struct extdev_type
*etype
;
1022 struct extdev_device
*edev
;
1023 struct extdev_bridge
*ebr
;
1026 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1027 edev
= container_of(dev
, struct extdev_device
, dev
);
1029 if (!etype
->subscribed
)
1032 blob_buf_init(&b
, 0);
1033 blobmsg_add_string(&b
, "name", dev
->ifname
);
1035 ret
= netifd_extdev_free(edev
, b
.head
);
1037 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
1040 if (dev
->type
->bridge_capability
) {
1041 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
1043 vlist_flush_all(&ebr
->members
);
1044 // vlist_flush_all(&dev->vlans); TODO: do we need this?
1053 extdev_invocation_error(ret
, __extdev_methods
[METHOD_FREE
],
1058 __bridge_config_init(struct extdev_bridge
*ebr
)
1061 struct blob_attr
*cur
;
1064 ebr
->force_active
= true;
1065 ret
= netifd_extdev_create(&ebr
->edev
, ebr
->config
);
1068 device_set_present(&ebr
->edev
.dev
, true);
1072 vlist_update(&ebr
->members
);
1074 blobmsg_for_each_attr(cur
, ebr
->ifnames
, rem
)
1075 extdev_bridge_add_member(ebr
, blobmsg_data(cur
));
1078 vlist_flush(&ebr
->members
);
1079 extdev_bridge_check_retry(ebr
);
1083 fprintf(stderr
, "Failed to init config for '%s': %s\n", ebr
->edev
.dev
.ifname
,
1084 ubus_strerror(ret
));
1088 extdev_config_init(struct device
*dev
)
1090 struct extdev_type
*etype
;
1091 struct extdev_bridge
*ebr
;
1093 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1095 if (!etype
->subscribed
)
1098 if (dev
->type
->bridge_capability
) {
1099 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
1100 __bridge_config_init(ebr
);
1105 extdev_buf_add_list(struct blob_attr
*attr
, int len
, const char *name
,
1106 struct blob_buf
*buf
, bool array
)
1108 struct blob_attr
*cur
;
1109 struct blobmsg_hdr
*hdr
;
1114 list
= blobmsg_open_array(buf
, name
);
1116 list
= blobmsg_open_table(buf
, name
);
1118 blobmsg_for_each_attr(cur
, attr
, len
) {
1119 hdr
= blob_data(cur
);
1120 type
= blobmsg_type(cur
);
1122 case BLOBMSG_TYPE_STRING
:
1123 blobmsg_add_string(buf
, (char *) hdr
->name
,
1124 blobmsg_get_string(cur
));
1126 case BLOBMSG_TYPE_TABLE
:
1127 case BLOBMSG_TYPE_ARRAY
:
1128 extdev_buf_add_list(blobmsg_data(cur
), blobmsg_data_len(cur
),
1129 (char *) hdr
->name
, buf
, type
== BLOBMSG_TYPE_ARRAY
);
1131 case BLOBMSG_TYPE_INT64
:
1132 blobmsg_add_u64(buf
, (char *) hdr
->name
, blobmsg_get_u64(cur
));
1134 case BLOBMSG_TYPE_INT32
:
1135 blobmsg_add_u32(buf
, (char *) hdr
->name
, blobmsg_get_u32(cur
));
1137 case BLOBMSG_TYPE_INT16
:
1138 blobmsg_add_u16(buf
, (char *) hdr
->name
, blobmsg_get_u16(cur
));
1140 case BLOBMSG_TYPE_INT8
:
1141 blobmsg_add_u8(buf
, (char *) hdr
->name
, blobmsg_get_u8(cur
));
1149 blobmsg_close_array(buf
, list
);
1151 blobmsg_close_table(buf
, list
);
1155 add_parsed_data(struct blob_attr
**tb
, const struct blobmsg_policy
*policy
, int n_params
,
1156 struct blob_buf
*buf
)
1158 for (int i
= 0; i
< n_params
; i
++) {
1162 switch (policy
[i
].type
) {
1163 case BLOBMSG_TYPE_STRING
:
1164 blobmsg_add_string(buf
, policy
[i
].name
, blobmsg_get_string(tb
[i
]));
1166 case BLOBMSG_TYPE_ARRAY
:
1167 case BLOBMSG_TYPE_TABLE
:
1168 extdev_buf_add_list(blobmsg_data(tb
[i
]), blobmsg_data_len(tb
[i
]),
1169 policy
[i
].name
, buf
, policy
[i
].type
== BLOBMSG_TYPE_ARRAY
);
1171 case BLOBMSG_TYPE_INT64
:
1172 blobmsg_add_u64(buf
, policy
[i
].name
, blobmsg_get_u64(tb
[i
]));
1174 case BLOBMSG_TYPE_INT32
:
1175 blobmsg_add_u32(buf
, policy
[i
].name
, blobmsg_get_u32(tb
[i
]));
1177 case BLOBMSG_TYPE_INT16
:
1178 blobmsg_add_u16(buf
, policy
[i
].name
, blobmsg_get_u16(tb
[i
]));
1180 case BLOBMSG_TYPE_INT8
:
1181 blobmsg_add_u8(buf
, policy
[i
].name
, blobmsg_get_u8(tb
[i
]));
1190 const struct device
*dev
;
1191 struct blob_buf
*buf
;
1195 dump_cb(struct ubus_request
*req
, int type
, struct blob_attr
*reply
)
1197 struct dump_data
*data
;
1198 struct extdev_type
*etype
;
1199 const struct blobmsg_policy
*info_policy
;
1201 struct blob_buf
*buf
;
1204 etype
= container_of(data
->dev
->type
, struct extdev_type
, handler
);
1205 info_policy
= etype
->info_params
->params
;
1206 n_params
= etype
->info_params
->n_params
;
1209 struct blob_attr
*tb
[n_params
];
1211 blobmsg_parse(info_policy
, n_params
, tb
, blobmsg_data(reply
), blobmsg_len(reply
));
1212 add_parsed_data(tb
, info_policy
, n_params
, buf
);
1216 extdev_dump(const char *method
, struct device
*dev
, struct blob_buf
*buf
)
1218 static struct dump_data data
;
1219 struct extdev_type
*etype
;
1221 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1223 if (!etype
->subscribed
)
1229 blob_buf_init(&b
, 0);
1230 blobmsg_add_string(&b
, "name", dev
->ifname
);
1232 netifd_extdev_invoke(etype
->peer_id
, method
, b
.head
, dump_cb
, &data
);
1236 extdev_dump_info(struct device
*dev
, struct blob_buf
*buf
)
1238 extdev_dump(__extdev_methods
[METHOD_DUMP_INFO
], dev
, buf
);
1242 extdev_dump_stats(struct device
*dev
, struct blob_buf
*buf
)
1244 extdev_dump(__extdev_methods
[METHOD_DUMP_STATS
], dev
, buf
);
1248 extdev_ext_handler_remove_cb(struct ubus_context
*ctx
,
1249 struct ubus_subscriber
*obj
, uint32_t id
)
1251 struct extdev_type
*etype
;
1252 etype
= container_of(obj
, struct extdev_type
, ubus_sub
);
1254 netifd_log_message(L_NOTICE
, "%s: external device handler "
1255 "'%s' disappeared. Waiting for it to re-appear.\n",
1256 etype
->handler
.name
, etype
->name
);
1259 etype
->subscribed
= false;
1261 extdev_ext_ubus_obj_wait(&etype
->obj_wait
);
1265 extdev_add_devtype(const char *cfg_file
, const char *tname
, const char *ubus_name
,
1266 bool bridge_capability
, const char *br_prefix
, json_object
*cfg_obj
,
1267 json_object
*info_obj
, json_object
*stats_obj
)
1269 static const char *OBJ_PREFIX
= "network.device.";
1271 struct extdev_type
*etype
;
1272 struct device_type
*devtype
;
1273 char *ubus_obj_name
, *devtype_name
, *ext_dev_handler_name
, *name_prefix
;
1274 struct uci_blob_param_list
*config_params
, *info_params
, *stats_params
;
1277 etype
= calloc_a(sizeof(*etype
),
1278 &ubus_obj_name
, strlen(OBJ_PREFIX
) + strlen(ubus_name
) + 1,
1279 &devtype_name
, strlen(tname
) + 1,
1280 &ext_dev_handler_name
, strlen(ubus_name
) + 1,
1281 &config_params
, sizeof(struct uci_blob_param_list
),
1282 &info_params
, sizeof(struct uci_blob_param_list
),
1283 &stats_params
, sizeof(struct uci_blob_param_list
));
1288 etype
->config_params
= config_params
;
1289 etype
->info_params
= info_params
;
1290 etype
->name
= strcpy(ext_dev_handler_name
, ubus_name
);
1292 devtype
= &etype
->handler
;
1293 devtype
->name
= strcpy(devtype_name
, tname
);
1294 devtype
->create
= extdev_create
;
1295 devtype
->free
= extdev_free
;
1296 devtype
->config_init
= extdev_config_init
;
1297 devtype
->reload
= extdev_reload
;
1298 devtype
->dump_info
= extdev_dump_info
;
1299 devtype
->dump_stats
= extdev_dump_stats
;
1300 devtype
->bridge_capability
= bridge_capability
;
1301 devtype
->config_params
= etype
->config_params
;
1303 if (bridge_capability
) {
1304 name_prefix
= malloc(strlen(br_prefix
) + 1);
1308 strcpy(name_prefix
, br_prefix
);
1309 devtype
->name_prefix
= name_prefix
;
1312 /* subscribe to external device handler */
1313 sprintf(ubus_obj_name
, "%s%s", OBJ_PREFIX
, ubus_name
);
1314 etype
->ubus_sub
.obj
.name
= ubus_obj_name
;
1315 etype
->ubus_sub
.obj
.type
= &extdev_ubus_object_type
;
1316 ret
= ubus_register_subscriber(ubus_ctx
, &etype
->ubus_sub
);
1318 fprintf(stderr
, "Failed to register subscriber object '%s'\n",
1319 etype
->ubus_sub
.obj
.name
);
1322 etype
->obj_wait
.cb
= extdev_wait_ev_cb
;
1323 etype
->ubus_sub
.remove_cb
= extdev_ext_handler_remove_cb
;
1324 extdev_subscribe(etype
);
1326 /* parse config params from JSON object */
1327 etype
->config_strbuf
= netifd_handler_parse_config(etype
->config_params
, cfg_obj
);
1328 if (!etype
->config_strbuf
)
1331 /* parse info dump params from JSON object */
1333 devtype
->dump_info
= NULL
;
1335 etype
->info_strbuf
= netifd_handler_parse_config(etype
->info_params
, info_obj
);
1336 if (!etype
->info_strbuf
)
1337 devtype
->dump_info
= NULL
;
1340 /* parse statistics dump params from JSON object */
1342 devtype
->dump_stats
= NULL
;
1344 etype
->stats_strbuf
= netifd_handler_parse_config(etype
->stats_params
, stats_obj
);
1345 if (!etype
->stats_strbuf
)
1346 devtype
->dump_stats
= NULL
;
1349 ret
= device_type_add(devtype
);
1356 free(etype
->config_strbuf
);
1357 free(etype
->info_strbuf
);
1358 free(etype
->stats_strbuf
);
1361 fprintf(stderr
, "Failed to create device handler for device"
1362 "type '%s' from file '%s'\n", tname
, cfg_file
);
1363 free(ubus_obj_name
);
1368 /* create extdev device handler stubs from JSON description */
1372 confdir_fd
= netifd_open_subdir("extdev-config");
1375 netifd_init_extdev_handlers(confdir_fd
, extdev_add_devtype
);