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_config_init(struct extdev_device
*edev
, struct blob_attr
*msg
)
140 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_CONFIG_INIT
],
145 netifd_extdev_reload(struct extdev_device
*edev
, struct blob_attr
*msg
)
147 D(DEVICE
, "reload %s '%s' at external device handler\n", edev
->dev
.type
->name
,
149 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_RELOAD
], msg
,
154 netifd_extdev_free(struct extdev_device
*edev
, struct blob_attr
*msg
)
156 D(DEVICE
, "delete %s '%s' with external device handler\n", edev
->dev
.type
->name
,
158 return netifd_extdev_invoke(edev
->etype
->peer_id
, __extdev_methods
[METHOD_FREE
], msg
,
163 netifd_extdev_prepare(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
165 D(DEVICE
, "prepare %s bridge '%s' at external device handler\n", ebr
->edev
.dev
.type
->name
,
166 ebr
->edev
.dev
.ifname
);
167 return netifd_extdev_invoke(ebr
->edev
.etype
->peer_id
,
168 __extdev_methods
[METHOD_HOTPLUG_PREPARE
], msg
, NULL
, NULL
);
172 netifd_extdev_add(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
174 D(DEVICE
, "add a member to %s bridge '%s' at external device handler\n",
175 ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
176 return netifd_extdev_invoke(ebr
->edev
.etype
->peer_id
,
177 __extdev_methods
[METHOD_HOTPLUG_ADD
], msg
,NULL
, NULL
);
181 netifd_extdev_remove(struct extdev_bridge
*ebr
, struct blob_attr
*msg
)
183 D(DEVICE
, "remove a member from %s bridge '%s' at external device handler\n",
184 ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
185 return netifd_extdev_invoke(ebr
->edev
.etype
->peer_id
,
186 __extdev_methods
[METHOD_HOTPLUG_REMOVE
], msg
, NULL
, NULL
);
190 extdev_invocation_error(int error
, const char *method
, const char *devname
)
192 netifd_log_message(L_CRIT
, "'%s' failed for '%s': %s\n",
193 method
, devname
, ubus_strerror(error
));
196 static struct ubus_method extdev_ubus_obj_methods
[] = {};
198 static struct ubus_object_type extdev_ubus_object_type
=
199 UBUS_OBJECT_TYPE("netifd_extdev", extdev_ubus_obj_methods
);
202 extdev_lookup_id(struct extdev_type
*etype
)
204 int ret
= UBUS_STATUS_UNKNOWN_ERROR
;
206 if (!etype
|| !etype
->name
)
209 ret
= ubus_lookup_id(ubus_ctx
, etype
->name
, &etype
->peer_id
);
216 netifd_log_message(L_CRIT
, "Could not find '%s' ubus ID: %s\n",
217 etype
->name
, ubus_strerror(ret
));
222 extdev_ext_ubus_obj_wait(struct ubus_event_handler
*h
)
224 return ubus_register_event_handler(ubus_ctx
, h
, "ubus.object.add");
228 extdev_subscribe(struct extdev_type
*etype
)
232 ret
= extdev_lookup_id(etype
);
234 etype
->subscribed
= false;
238 ret
= ubus_subscribe(ubus_ctx
, &etype
->ubus_sub
, etype
->peer_id
);
240 etype
->subscribed
= false;
241 extdev_ext_ubus_obj_wait(&etype
->obj_wait
);
243 netifd_log_message(L_NOTICE
, "subscribed to external device handler '%s'\n",
245 etype
->subscribed
= true;
252 extdev_wait_ev_cb(struct ubus_context
*ctx
, struct ubus_event_handler
*ev_handler
,
253 const char *type
, struct blob_attr
*msg
)
255 static const struct blobmsg_policy wait_policy
= {
256 "path", BLOBMSG_TYPE_STRING
259 struct blob_attr
*attr
;
261 struct extdev_type
*etype
;
263 etype
= container_of(ev_handler
, struct extdev_type
, obj_wait
);
265 if (strcmp(type
, "ubus.object.add"))
268 blobmsg_parse(&wait_policy
, 1, &attr
, blob_data(msg
), blob_len(msg
));
272 path
= blobmsg_data(attr
);
273 if (strcmp(etype
->name
, path
))
276 extdev_subscribe(etype
);
280 extdev_bridge_disable_interface(struct extdev_bridge
*ebr
)
287 blob_buf_init(&b
, 0);
288 blobmsg_add_string(&b
, "name", ebr
->edev
.dev
.ifname
);
290 ret
= netifd_extdev_free(&ebr
->edev
, b
.head
);
292 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
299 extdev_invocation_error(ret
, __extdev_methods
[METHOD_FREE
], ebr
->edev
.dev
.ifname
);
304 extdev_bridge_enable_interface(struct extdev_bridge
*ebr
)
311 ret
= netifd_extdev_create(&ebr
->edev
, ebr
->config
);
319 extdev_invocation_error(ret
, __extdev_methods
[METHOD_CREATE
], ebr
->edev
.dev
.ifname
);
324 extdev_bridge_enable_member(struct extdev_bridge_member
*ubm
)
327 struct extdev_bridge
*ebr
= ubm
->parent_br
;
329 D(DEVICE
, "%s enable member %s\n", ebr
->edev
.dev
.ifname
, ubm
->name
);
334 ret
= extdev_bridge_enable_interface(ebr
);
338 ret
= device_claim(&ubm
->dev_usr
);
342 blob_buf_init(&b
, 0);
343 blobmsg_add_string(&b
, "bridge", ebr
->edev
.dev
.ifname
);
344 blobmsg_add_string(&b
, "member", ubm
->dev_usr
.dev
->ifname
);
346 /* use hotplug add as addif equivalent. Maybe we need a dedicated ubus
347 * method on the external handler for this sort of operation. */
348 ret
= netifd_extdev_add(ebr
, b
.head
);
350 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_ADD
],
351 ubm
->dev_usr
.dev
->ifname
);
355 device_set_present(&ebr
->edev
.dev
, true);
356 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
361 D(DEVICE
, "%s: failed to enable member '%s'\n", ebr
->edev
.dev
.ifname
, ubm
->name
);
364 ubm
->present
= false;
371 extdev_bridge_disable_member(struct extdev_bridge_member
*ubm
)
374 struct extdev_bridge
*ebr
= ubm
->parent_br
;
379 D(DEVICE
, "%s disable member %s\n", ubm
->parent_br
->edev
.dev
.ifname
, ubm
->name
);
381 blob_buf_init(&b
, 0);
382 blobmsg_add_string(&b
, "bridge", ebr
->edev
.dev
.ifname
);
383 blobmsg_add_string(&b
, "member", ubm
->dev_usr
.dev
->ifname
);
385 /* use hotplug remove as delif equivalent. Maybe we need a dedicated
386 * ubus method on the external handler for this sort of operation. */
387 ret
= netifd_extdev_remove(ebr
, b
.head
);
389 /* continue in case of NOT FOUND since we're trying to remove anyway */
390 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
393 device_release(&ubm
->dev_usr
);
394 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
399 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_REMOVE
],
400 ubm
->dev_usr
.dev
->ifname
);
406 extdev_bridge_set_down(struct extdev_bridge
*ebr
)
408 D(DEVICE
, "set %s bridge %s down\n", ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
410 struct extdev_bridge_member
*ubm
;
412 ebr
->set_state(&ebr
->edev
.dev
, false);
414 vlist_for_each_element(&ebr
->members
, ubm
, node
)
415 extdev_bridge_disable_member(ubm
);
417 extdev_bridge_disable_interface(ebr
);
423 extdev_bridge_check_retry(struct extdev_bridge
*ebr
)
428 uloop_timeout_set(&ebr
->retry
, 200);
432 extdev_bridge_set_up(struct extdev_bridge
*ebr
)
434 D(DEVICE
, "set %s bridge %s up\n", ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
);
436 struct extdev_bridge_member
*ubm
;
439 if (!ebr
->n_present
) {
440 if (!ebr
->force_active
)
443 ret
= extdev_bridge_enable_interface(ebr
);
449 vlist_for_each_element(&ebr
->members
, ubm
, node
)
450 extdev_bridge_enable_member(ubm
);
452 extdev_bridge_check_retry(ebr
);
454 if (!ebr
->force_active
&& !ebr
->n_present
) {
455 extdev_bridge_disable_interface(ebr
);
456 device_set_present(&ebr
->edev
.dev
, false);
464 extdev_bridge_set_state(struct device
*dev
, bool up
)
466 struct extdev_bridge
*ebr
;
468 if (!dev
->type
->bridge_capability
)
471 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
474 return extdev_bridge_set_up(ebr
);
476 return extdev_bridge_set_down(ebr
);
480 extdev_bridge_remove_member(struct extdev_bridge_member
*member
)
482 struct extdev_bridge
*ebr
= member
->parent_br
;
484 if (!member
->present
)
487 if (ebr
->edev
.dev
.active
)
488 extdev_bridge_disable_member(member
);
490 member
->present
= false;
496 ebr
->force_active
= false;
497 if (ebr
->n_present
== 0)
498 device_set_present(&ebr
->edev
.dev
, false);
502 extdev_bridge_member_cb(struct device_user
*usr
, enum device_event event
)
505 struct extdev_bridge_member
*ubm
;
506 struct extdev_bridge
*ebr
;
508 ubm
= container_of(usr
, struct extdev_bridge_member
, dev_usr
);
509 ebr
= ubm
->parent_br
;
513 assert(!ubm
->present
);
518 /* if this member is the first one that is brought up,
519 * create the bridge at the external device handler */
520 if (ebr
->n_present
== 1) {
521 ret
= netifd_extdev_create(&ebr
->edev
, ebr
->config
);
526 ret
= ebr
->set_state(&ebr
->edev
.dev
, true);
528 extdev_bridge_set_down(ebr
);
529 device_set_present(&ebr
->edev
.dev
, true);
532 extdev_bridge_enable_member(ubm
);
534 case DEV_EVENT_REMOVE
:
536 vlist_delete(&ebr
->members
, &ubm
->node
);
541 extdev_bridge_remove_member(ubm
);
550 netifd_log_message(L_CRIT
, "Failed to create %s bridge %s: %s\n",
551 ebr
->edev
.dev
.type
->name
, ebr
->edev
.dev
.ifname
, ubus_strerror(ret
));
552 ubm
->present
= false;
557 __bridge_enable_members(struct extdev_bridge
*ebr
)
559 struct extdev_bridge_member
*cur
;
563 vlist_for_each_element(&ebr
->members
, cur
, node
) {
567 if (!cur
->dev_usr
.dev
->present
)
572 extdev_bridge_enable_member(cur
);
577 extdev_bridge_retry_enable_members(struct uloop_timeout
*timeout
)
579 struct extdev_bridge
*ebr
= container_of(timeout
, struct extdev_bridge
, retry
);
581 D(DEVICE
, "%s retry enable members\n", ebr
->edev
.dev
.ifname
);
583 __bridge_enable_members(ebr
);
586 static struct extdev_bridge_member
*
587 extdev_bridge_create_member(struct extdev_bridge
*ebr
, struct device
*dev
)
589 struct extdev_bridge_member
*ubm
;
592 ubm
= calloc_a(sizeof(*ubm
), &name
, strlen(dev
->ifname
) + 1);
596 ubm
->parent_br
= ebr
;
598 strcpy(name
, dev
->ifname
);
599 ubm
->dev_usr
.dev
= dev
;
600 ubm
->dev_usr
.cb
= extdev_bridge_member_cb
;
601 vlist_add(&ebr
->members
, &ubm
->node
, ubm
->name
);
602 /* Need to look up the bridge member again as the above
603 * created pointer will be freed in case the bridge member
605 ubm
= vlist_find(&ebr
->members
, dev
->ifname
, ubm
, node
);
613 extdev_bridge_add_member(struct extdev_bridge
*ebr
, const char *name
)
615 D(DEVICE
, "%s add member %s\n", ebr
->edev
.dev
.ifname
, name
);
619 dev
= device_get(name
, 1);
623 extdev_bridge_create_member(ebr
, dev
);
626 /* TODO: how to handle vlan arg? */
628 extdev_hotplug_add(struct device
*ebr_dev
, struct device
*ebm_dev
, struct blob_attr
*vlan
)
630 D(DEVICE
, "%s hotplug add member %s\n", ebr_dev
->ifname
, ebm_dev
->ifname
);
632 struct extdev_bridge
*ebr
;
633 struct extdev_bridge_member
*ubm
;
635 if (!ebr_dev
->type
->bridge_capability
)
636 return UBUS_STATUS_NOT_SUPPORTED
;
638 ebr
= container_of(ebr_dev
, struct extdev_bridge
, edev
.dev
);
640 if (!ebr
->edev
.etype
->subscribed
)
641 return UBUS_STATUS_NOT_FOUND
;
643 ubm
= extdev_bridge_create_member(ebr
, ebm_dev
);
645 return UBUS_STATUS_UNKNOWN_ERROR
;
647 device_broadcast_event(&ebr
->edev
.dev
, DEV_EVENT_TOPO_CHANGE
);
653 extdev_hotplug_remove(struct device
*dev
, struct device
*member
)
655 struct extdev_bridge
*ebr
;
656 struct extdev_bridge_member
*ubm
;
658 if (!dev
->type
->bridge_capability
)
659 return UBUS_STATUS_NOT_SUPPORTED
;
661 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
663 if (!ebr
->edev
.etype
->subscribed
)
664 return UBUS_STATUS_NOT_FOUND
;
666 ubm
= vlist_find(&ebr
->members
, member
->ifname
, ubm
, node
);
668 return UBUS_STATUS_NOT_FOUND
;
670 vlist_delete(&ebr
->members
, &ubm
->node
);
671 extdev_bridge_remove_member(ubm
);
677 extdev_hotplug_prepare(struct device
*dev
, struct device
**bridge_dev
)
679 struct extdev_bridge
*ebr
;
682 if (!dev
->type
->bridge_capability
)
683 return UBUS_STATUS_NOT_SUPPORTED
;
688 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
690 blob_buf_init(&b
, 0);
691 blobmsg_add_string(&b
, "name", dev
->ifname
);
693 ret
= netifd_extdev_prepare(ebr
, b
.head
);
697 ebr
->force_active
= true;
698 device_set_present(&ebr
->edev
.dev
, true);
703 extdev_invocation_error(ret
, __extdev_methods
[METHOD_HOTPLUG_PREPARE
], dev
->ifname
);
708 extdev_bridge_free_member(struct extdev_bridge_member
*ubm
)
710 struct device
*dev
= ubm
->dev_usr
.dev
;
712 extdev_bridge_remove_member(ubm
);
713 device_remove_user(&ubm
->dev_usr
);
716 device_set_present(dev
, false);
717 device_set_present(dev
, true);
724 extdev_bridge_member_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
725 struct vlist_node
*node_old
)
727 struct extdev_bridge_member
*ubm
;
731 ubm
= container_of(node_new
, struct extdev_bridge_member
, node
);
738 dev
= ubm
->dev_usr
.dev
;
739 ubm
->dev_usr
.dev
= NULL
;
740 device_add_user(&ubm
->dev_usr
, dev
);
744 ubm
= container_of(node_old
, struct extdev_bridge_member
, node
);
745 extdev_bridge_free_member(ubm
);
751 bridge_dependency_retry(struct uloop_timeout
*timeout
)
753 struct extdev_bridge
*ebr
;
755 ebr
= container_of(timeout
, struct extdev_bridge
, edev
.retry
);
757 __bridge_reload(ebr
, NULL
);
761 __buf_add_all(struct blob_attr
*attr
)
763 struct blob_attr
*cur
;
766 blobmsg_for_each_attr(cur
, attr
, rem
)
767 blobmsg_add_field(&b
, blobmsg_type(cur
), blobmsg_name(cur
), blobmsg_data(cur
),
768 blobmsg_data_len(cur
));
778 static const struct blobmsg_policy brpol
[__BRIDGE_MAX
] = {
779 [BRIDGE_EMPTY
] = { "empty", BLOBMSG_TYPE_BOOL
},
780 [BRIDGE_IFNAMES
] = { "ifname", BLOBMSG_TYPE_ARRAY
},
781 [BRIDGE_DEPENDS_ON
] = { "depends_on", BLOBMSG_TYPE_STRING
},
784 static enum dev_change_type
785 __do_bridge_reload(struct extdev_bridge
*ebr
, struct blob_attr
*config
)
790 blob_buf_init(&b
, 0);
791 cfg_table
= blobmsg_open_table(&b
, "old");
792 __buf_add_all(ebr
->config
);
793 blobmsg_close_table(&b
, cfg_table
);
794 cfg_table
= blobmsg_open_table(&b
, "new");
795 __buf_add_all(config
);
796 blobmsg_close_table(&b
, cfg_table
);
798 ret
= netifd_extdev_reload(&ebr
->edev
, b
.head
);
801 netifd_log_message(L_WARNING
, "%s config reload failed: %s\n",
802 ebr
->edev
.dev
.ifname
, ubus_strerror(ret
));
803 return DEV_CONFIG_RECREATE
;
805 return DEV_CONFIG_RESTART
;
809 static enum dev_change_type
810 __bridge_reload(struct extdev_bridge
*ebr
, struct blob_attr
*config
)
812 int n_params
= ebr
->edev
.dev
.type
->config_params
->n_params
;
813 struct blob_attr
*tb
[__BRIDGE_MAX
];
814 const struct uci_blob_param_list
*config_params
;
815 const struct blobmsg_policy
*pol
;
816 struct blob_attr
*old_tb
[n_params
], *brtb
[n_params
];
817 enum dev_change_type change
= DEV_CONFIG_APPLIED
;
819 unsigned long diff
= 0;
822 config
= blob_memdup(config
);
823 blobmsg_parse(brpol
, __BRIDGE_MAX
, tb
, blobmsg_data(config
), blobmsg_len(config
));
824 ebr
->edev
.dep_name
= blobmsg_get_string(tb
[BRIDGE_DEPENDS_ON
]);
826 if (tb
[BRIDGE_EMPTY
] && blobmsg_get_bool(tb
[BRIDGE_EMPTY
]))
830 config_params
= ebr
->edev
.dev
.type
->config_params
;
831 pol
= config_params
->params
;
833 blobmsg_parse(pol
, n_params
, old_tb
, blobmsg_data(ebr
->config
),
834 blobmsg_len(ebr
->config
));
835 blobmsg_parse(pol
, n_params
, brtb
, blobmsg_data(config
), blobmsg_len
839 uci_blob_diff(brtb
, old_tb
, config_params
, &diff
);
841 if (diff
& ~(1 << BRIDGE_IFNAMES
)) {
842 change
= DEV_CONFIG_RESTART
;
844 change
= __do_bridge_reload(ebr
, config
);
851 ebr
->ifnames
= tb
[BRIDGE_IFNAMES
];
852 ebr
->config
= config
;
855 if (ebr
->edev
.dep_name
) {
856 dev
= device_get(ebr
->edev
.dep_name
, 0);
857 if (!(dev
&& dev
->current_config
)) {
858 D(DEVICE
, "%s: cannot yet init config since dependency '%s' is not ready\n",
859 ebr
->edev
.dev
.ifname
, ebr
->edev
.dep_name
);
860 ebr
->edev
.retry
.cb
= bridge_dependency_retry
;
861 uloop_timeout_set(&ebr
->edev
.retry
, 200);
862 return DEV_CONFIG_RESTART
;
866 __bridge_config_init(ebr
);
867 ebr
->edev
.dev
.config_pending
= false;
868 uloop_timeout_cancel(&ebr
->edev
.retry
);
873 static enum dev_change_type
874 __reload(struct extdev_device
*edev
, struct blob_attr
*config
)
876 unsigned long diff
= 0;
877 struct uci_blob_param_list
*params
;
879 params
= edev
->etype
->config_params
;
881 struct blob_attr
*tb
[params
->n_params
];
882 struct blob_attr
*old_tb
[params
->n_params
];
884 blobmsg_parse(params
->params
, params
->n_params
, tb
, blobmsg_data(config
),
885 blobmsg_len(config
));
886 blobmsg_parse(params
->params
, params
->n_params
, old_tb
, blobmsg_data(edev
->dev
.config
),
887 blobmsg_len(edev
->dev
.config
));
889 uci_blob_diff(tb
, old_tb
, edev
->etype
->config_params
, &diff
);
891 return DEV_CONFIG_NO_CHANGE
;
893 // TODO: make reload ubus call with old and new config
895 device_set_present(&edev
->dev
, false);
896 device_set_present(&edev
->dev
, true);
898 return DEV_CONFIG_APPLIED
;
901 static enum dev_change_type
902 extdev_reload(struct device
*dev
, struct blob_attr
*config
)
904 struct extdev_type
*etype
;
905 struct extdev_device
*edev
;
906 struct extdev_bridge
*ebr
;
908 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
910 if (!etype
->subscribed
)
911 return DEV_CONFIG_NO_CHANGE
;
913 edev
= container_of(dev
, struct extdev_device
, dev
);
915 if (dev
->type
->bridge_capability
) {
916 ebr
= container_of(edev
, struct extdev_bridge
, edev
);
917 return __bridge_reload(ebr
, config
);
919 return __reload(edev
, config
);
923 static struct device
*
924 __create(const char *name
, struct device_type
*type
, struct blob_attr
*config
)
926 struct extdev_device
*edev
;
927 struct extdev_type
*etype
;
930 etype
= container_of(type
, struct extdev_type
, handler
);
931 edev
= calloc(1, sizeof(struct extdev_device
));
935 ret
= device_init(&edev
->dev
, type
, name
);
941 ret
= netifd_extdev_create(edev
, config
);
945 edev
->dev
.config_pending
= false;
950 extdev_invocation_error(ret
, __extdev_methods
[METHOD_CREATE
], name
);
953 free(edev
->dev
.config
);
954 device_cleanup(&edev
->dev
);
957 netifd_log_message(L_WARNING
, "Failed to create %s %s\n", type
->name
, name
);
961 static const struct device_hotplug_ops extdev_hotplug_ops
= {
962 .prepare
= extdev_hotplug_prepare
,
963 .add
= extdev_hotplug_add
,
964 .del
= extdev_hotplug_remove
967 static struct device
*
968 __bridge_create(const char *name
, struct device_type
*devtype
, struct blob_attr
*config
)
970 struct extdev_bridge
*ebr
;
972 ebr
= calloc(1, sizeof(*ebr
));
976 device_init(&ebr
->edev
.dev
, devtype
, name
);
977 ebr
->edev
.dev
.config_pending
= true;
978 ebr
->retry
.cb
= extdev_bridge_retry_enable_members
;
979 ebr
->edev
.etype
= container_of(devtype
, struct extdev_type
, handler
);
980 ebr
->set_state
= ebr
->edev
.dev
.set_state
;
981 ebr
->edev
.dev
.set_state
= extdev_bridge_set_state
;
982 ebr
->edev
.dev
.hotplug_ops
= &extdev_hotplug_ops
;
983 vlist_init(&ebr
->members
, avl_strcmp
, extdev_bridge_member_update
);
984 ebr
->members
.keep_old
= true;
985 __bridge_reload(ebr
, config
);
987 return &ebr
->edev
.dev
;
990 /* Device creation process:
991 * For bridges without dependencies:
992 * 1) The bridge state is initialized in netifd. Devices for the members are
993 * created and added to the members vlist by config_init automatically.
994 * 2) When the first bridge member device is brought up in
995 * extdev_bridge_enable_member the 'create' call to the external device
997 * 3) After successful device creation the bridge is marked "present" and a
998 * new attempt at adding the member is made.
999 * For bridges with dependencies:
1000 * 1) The bridge state is initialized in netifd. If a dependency is expressed
1001 * via the 'depends_on' UCI option and the dependency is not ready (i.e. it
1002 * does not exist or config_pending == true) the call to
1003 * __bridge_config_init() is postponed and a retry timer is started. Retries
1004 * happen until the dependency is ready. Then, __bridge_config_init() gets
1005 * called and the process continues as with bridges without dependencies
1006 * For regular devices:
1007 * 1) The device structure is created in netifd.
1008 * 2) config_init is called automatically which issues the 'create' call to the
1009 * external device handler.
1011 static struct device
*
1012 extdev_create(const char *name
, struct device_type
*devtype
, struct blob_attr
*config
)
1014 struct extdev_type
*etype
= container_of(devtype
, struct extdev_type
, handler
);
1016 if (!etype
->subscribed
)
1019 if (devtype
->bridge_capability
)
1020 return __bridge_create(name
, devtype
, config
);
1022 return __create(name
, devtype
, config
);
1026 extdev_free(struct device
*dev
)
1028 struct extdev_type
*etype
;
1029 struct extdev_device
*edev
;
1030 struct extdev_bridge
*ebr
;
1033 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1034 edev
= container_of(dev
, struct extdev_device
, dev
);
1036 if (!etype
->subscribed
)
1039 blob_buf_init(&b
, 0);
1040 blobmsg_add_string(&b
, "name", dev
->ifname
);
1042 ret
= netifd_extdev_free(edev
, b
.head
);
1044 if (ret
&& ret
!= UBUS_STATUS_NOT_FOUND
)
1047 if (dev
->type
->bridge_capability
) {
1048 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
1050 vlist_flush_all(&ebr
->members
);
1051 // vlist_flush_all(&dev->vlans); TODO: do we need this?
1060 extdev_invocation_error(ret
, __extdev_methods
[METHOD_FREE
],
1065 __bridge_config_init(struct extdev_bridge
*ebr
)
1068 struct blob_attr
*cur
;
1071 ebr
->force_active
= true;
1072 ret
= netifd_extdev_create(&ebr
->edev
, ebr
->config
);
1075 device_set_present(&ebr
->edev
.dev
, true);
1079 vlist_update(&ebr
->members
);
1081 blobmsg_for_each_attr(cur
, ebr
->ifnames
, rem
)
1082 extdev_bridge_add_member(ebr
, blobmsg_data(cur
));
1085 vlist_flush(&ebr
->members
);
1086 extdev_bridge_check_retry(ebr
);
1090 fprintf(stderr
, "Failed to init config for '%s': %s\n", ebr
->edev
.dev
.ifname
,
1091 ubus_strerror(ret
));
1095 extdev_config_init(struct device
*dev
)
1097 struct extdev_type
*etype
;
1098 struct extdev_bridge
*ebr
;
1100 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1102 if (!etype
->subscribed
)
1105 if (dev
->type
->bridge_capability
) {
1106 ebr
= container_of(dev
, struct extdev_bridge
, edev
.dev
);
1107 __bridge_config_init(ebr
);
1112 extdev_buf_add_list(struct blob_attr
*attr
, int len
, const char *name
,
1113 struct blob_buf
*buf
, bool array
)
1115 struct blob_attr
*cur
;
1116 struct blobmsg_hdr
*hdr
;
1121 list
= blobmsg_open_array(buf
, name
);
1123 list
= blobmsg_open_table(buf
, name
);
1125 blobmsg_for_each_attr(cur
, attr
, len
) {
1126 hdr
= blob_data(cur
);
1127 type
= blobmsg_type(cur
);
1129 case BLOBMSG_TYPE_STRING
:
1130 blobmsg_add_string(buf
, (char *) hdr
->name
,
1131 blobmsg_get_string(cur
));
1133 case BLOBMSG_TYPE_TABLE
:
1134 case BLOBMSG_TYPE_ARRAY
:
1135 extdev_buf_add_list(blobmsg_data(cur
), blobmsg_data_len(cur
),
1136 (char *) hdr
->name
, buf
, type
== BLOBMSG_TYPE_ARRAY
);
1138 case BLOBMSG_TYPE_INT64
:
1139 blobmsg_add_u64(buf
, (char *) hdr
->name
, blobmsg_get_u64(cur
));
1141 case BLOBMSG_TYPE_INT32
:
1142 blobmsg_add_u32(buf
, (char *) hdr
->name
, blobmsg_get_u32(cur
));
1144 case BLOBMSG_TYPE_INT16
:
1145 blobmsg_add_u16(buf
, (char *) hdr
->name
, blobmsg_get_u16(cur
));
1147 case BLOBMSG_TYPE_INT8
:
1148 blobmsg_add_u8(buf
, (char *) hdr
->name
, blobmsg_get_u8(cur
));
1156 blobmsg_close_array(buf
, list
);
1158 blobmsg_close_table(buf
, list
);
1162 add_parsed_data(struct blob_attr
**tb
, const struct blobmsg_policy
*policy
, int n_params
,
1163 struct blob_buf
*buf
)
1165 for (int i
= 0; i
< n_params
; i
++) {
1169 switch (policy
[i
].type
) {
1170 case BLOBMSG_TYPE_STRING
:
1171 blobmsg_add_string(buf
, policy
[i
].name
, blobmsg_get_string(tb
[i
]));
1173 case BLOBMSG_TYPE_ARRAY
:
1174 case BLOBMSG_TYPE_TABLE
:
1175 extdev_buf_add_list(blobmsg_data(tb
[i
]), blobmsg_data_len(tb
[i
]),
1176 policy
[i
].name
, buf
, policy
[i
].type
== BLOBMSG_TYPE_ARRAY
);
1178 case BLOBMSG_TYPE_INT64
:
1179 blobmsg_add_u64(buf
, policy
[i
].name
, blobmsg_get_u64(tb
[i
]));
1181 case BLOBMSG_TYPE_INT32
:
1182 blobmsg_add_u32(buf
, policy
[i
].name
, blobmsg_get_u32(tb
[i
]));
1184 case BLOBMSG_TYPE_INT16
:
1185 blobmsg_add_u16(buf
, policy
[i
].name
, blobmsg_get_u16(tb
[i
]));
1187 case BLOBMSG_TYPE_INT8
:
1188 blobmsg_add_u8(buf
, policy
[i
].name
, blobmsg_get_u8(tb
[i
]));
1197 const struct device
*dev
;
1198 struct blob_buf
*buf
;
1202 dump_cb(struct ubus_request
*req
, int type
, struct blob_attr
*reply
)
1204 struct dump_data
*data
;
1205 struct extdev_type
*etype
;
1206 const struct blobmsg_policy
*info_policy
;
1208 struct blob_buf
*buf
;
1211 etype
= container_of(data
->dev
->type
, struct extdev_type
, handler
);
1212 info_policy
= etype
->info_params
->params
;
1213 n_params
= etype
->info_params
->n_params
;
1216 struct blob_attr
*tb
[n_params
];
1218 blobmsg_parse(info_policy
, n_params
, tb
, blobmsg_data(reply
), blobmsg_len(reply
));
1219 add_parsed_data(tb
, info_policy
, n_params
, buf
);
1223 extdev_dump(const char *method
, struct device
*dev
, struct blob_buf
*buf
)
1225 static struct dump_data data
;
1226 struct extdev_type
*etype
;
1228 etype
= container_of(dev
->type
, struct extdev_type
, handler
);
1230 if (!etype
->subscribed
)
1236 blob_buf_init(&b
, 0);
1237 blobmsg_add_string(&b
, "name", dev
->ifname
);
1239 netifd_extdev_invoke(etype
->peer_id
, method
, b
.head
, dump_cb
, &data
);
1243 extdev_dump_info(struct device
*dev
, struct blob_buf
*buf
)
1245 extdev_dump(__extdev_methods
[METHOD_DUMP_INFO
], dev
, buf
);
1249 extdev_dump_stats(struct device
*dev
, struct blob_buf
*buf
)
1251 extdev_dump(__extdev_methods
[METHOD_DUMP_STATS
], dev
, buf
);
1255 extdev_ext_handler_remove_cb(struct ubus_context
*ctx
,
1256 struct ubus_subscriber
*obj
, uint32_t id
)
1258 struct extdev_type
*etype
;
1259 etype
= container_of(obj
, struct extdev_type
, ubus_sub
);
1261 netifd_log_message(L_NOTICE
, "%s: external device handler "
1262 "'%s' disappeared. Waiting for it to re-appear.\n",
1263 etype
->handler
.name
, etype
->name
);
1266 etype
->subscribed
= false;
1268 extdev_ext_ubus_obj_wait(&etype
->obj_wait
);
1272 extdev_add_devtype(const char *cfg_file
, const char *tname
, const char *ubus_name
,
1273 bool bridge_capability
, const char *br_prefix
, json_object
*cfg_obj
,
1274 json_object
*info_obj
, json_object
*stats_obj
)
1276 static const char *OBJ_PREFIX
= "network.device.";
1278 struct extdev_type
*etype
;
1279 struct device_type
*devtype
;
1280 char *ubus_obj_name
, *devtype_name
, *ext_dev_handler_name
, *name_prefix
;
1281 struct uci_blob_param_list
*config_params
, *info_params
, *stats_params
;
1284 etype
= calloc_a(sizeof(*etype
),
1285 &ubus_obj_name
, strlen(OBJ_PREFIX
) + strlen(ubus_name
) + 1,
1286 &devtype_name
, strlen(tname
) + 1,
1287 &ext_dev_handler_name
, strlen(ubus_name
) + 1,
1288 &config_params
, sizeof(struct uci_blob_param_list
),
1289 &info_params
, sizeof(struct uci_blob_param_list
),
1290 &stats_params
, sizeof(struct uci_blob_param_list
));
1295 etype
->config_params
= config_params
;
1296 etype
->info_params
= info_params
;
1297 etype
->name
= strcpy(ext_dev_handler_name
, ubus_name
);
1299 devtype
= &etype
->handler
;
1300 devtype
->name
= strcpy(devtype_name
, tname
);
1301 devtype
->create
= extdev_create
;
1302 devtype
->free
= extdev_free
;
1303 devtype
->config_init
= extdev_config_init
;
1304 devtype
->reload
= extdev_reload
;
1305 devtype
->dump_info
= extdev_dump_info
;
1306 devtype
->dump_stats
= extdev_dump_stats
;
1307 devtype
->bridge_capability
= bridge_capability
;
1308 devtype
->config_params
= etype
->config_params
;
1310 if (bridge_capability
) {
1311 name_prefix
= malloc(strlen(br_prefix
) + 1);
1315 strcpy(name_prefix
, br_prefix
);
1316 devtype
->name_prefix
= name_prefix
;
1319 /* subscribe to external device handler */
1320 sprintf(ubus_obj_name
, "%s%s", OBJ_PREFIX
, ubus_name
);
1321 etype
->ubus_sub
.obj
.name
= ubus_obj_name
;
1322 etype
->ubus_sub
.obj
.type
= &extdev_ubus_object_type
;
1323 ret
= ubus_register_subscriber(ubus_ctx
, &etype
->ubus_sub
);
1325 fprintf(stderr
, "Failed to register subscriber object '%s'\n",
1326 etype
->ubus_sub
.obj
.name
);
1329 etype
->obj_wait
.cb
= extdev_wait_ev_cb
;
1330 etype
->ubus_sub
.remove_cb
= extdev_ext_handler_remove_cb
;
1331 extdev_subscribe(etype
);
1333 /* parse config params from JSON object */
1334 etype
->config_strbuf
= netifd_handler_parse_config(etype
->config_params
, cfg_obj
);
1335 if (!etype
->config_strbuf
)
1338 /* parse info dump params from JSON object */
1340 devtype
->dump_info
= NULL
;
1342 etype
->info_strbuf
= netifd_handler_parse_config(etype
->info_params
, info_obj
);
1343 if (!etype
->info_strbuf
)
1344 devtype
->dump_info
= NULL
;
1347 /* parse statistics dump params from JSON object */
1349 devtype
->dump_stats
= NULL
;
1351 etype
->stats_strbuf
= netifd_handler_parse_config(etype
->stats_params
, stats_obj
);
1352 if (!etype
->stats_strbuf
)
1353 devtype
->dump_stats
= NULL
;
1356 ret
= device_type_add(devtype
);
1363 free(etype
->config_strbuf
);
1364 free(etype
->info_strbuf
);
1365 free(etype
->stats_strbuf
);
1368 fprintf(stderr
, "Failed to create device handler for device"
1369 "type '%s' from file '%s'\n", tname
, cfg_file
);
1370 free(ubus_obj_name
);
1375 /* create extdev device handler stubs from JSON description */
1379 confdir_fd
= netifd_open_subdir("extdev-config");
1382 netifd_init_extdev_handlers(confdir_fd
, extdev_add_devtype
);