• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/netifd/extdev.c

  1 /*
  2  * netifd - network interface daemon
  3  * Copyright (C) 2015 Arne Kappen <arne.kappen@hhi.fraunhofer.de>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License version 2
  7  * as published by the Free Software Foundation
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  *
 15  * extdev - external device handler interface
 16  *
 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.
 29  */
 30 
 31 #include <libubox/blobmsg.h>
 32 #include <libubox/list.h>
 33 #include <libubus.h>
 34 #include <assert.h>
 35 
 36 #include "netifd.h"
 37 #include "handler.h"
 38 #include "device.h"
 39 #include "ubus.h"
 40 #include "extdev.h"
 41 #include "interface.h"
 42 #include "system.h"
 43 
 44 
 45 static struct blob_buf b;
 46 static int confdir_fd = -1;
 47 
 48 struct extdev_type {
 49         struct device_type handler;
 50 
 51         const char *name;
 52         uint32_t peer_id;
 53         struct ubus_subscriber ubus_sub;
 54         bool subscribed;
 55         struct ubus_event_handler obj_wait;
 56 
 57         struct uci_blob_param_list *config_params;
 58         char *config_strbuf;
 59 
 60         struct uci_blob_param_list *info_params;
 61         char *info_strbuf;
 62 
 63         struct uci_blob_param_list *stats_params;
 64         char *stats_strbuf;
 65 };
 66 
 67 struct extdev_device {
 68         struct device dev;
 69         struct extdev_type *etype;
 70         const char *dep_name;
 71         struct uloop_timeout retry;
 72 };
 73 
 74 struct extdev_bridge {
 75         struct extdev_device edev;
 76         device_state_cb set_state;
 77 
 78         struct blob_attr *config;
 79         bool empty;
 80         struct blob_attr *ifnames;
 81         bool active;
 82         bool force_active;
 83 
 84         struct uloop_timeout retry;
 85         struct vlist_tree members;
 86         int n_present;
 87         int n_failed;
 88 };
 89 
 90 struct extdev_bridge_member {
 91         struct vlist_node node;
 92         struct extdev_bridge *parent_br;
 93         struct device_user dev_usr;
 94         bool present;
 95         char *name;
 96 };
 97 
 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);
100 
101 enum {
102         METHOD_CREATE,
103         METHOD_CONFIG_INIT,
104         METHOD_RELOAD,
105         METHOD_DUMP_INFO,
106         METHOD_DUMP_STATS,
107         METHOD_CHECK_STATE,
108         METHOD_FREE,
109         METHOD_HOTPLUG_PREPARE,
110         METHOD_HOTPLUG_ADD,
111         METHOD_HOTPLUG_REMOVE,
112         __METHODS_MAX
113 };
114 
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",
126 };
127 
128 static inline int
129 netifd_extdev_create(struct extdev_device *edev, struct blob_attr *msg)
130 {
131         D(DEVICE, "create %s '%s' at external device handler", edev->dev.type->name,
132                 edev->dev.ifname);
133         return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_CREATE], msg,
134                                      NULL, NULL);
135 }
136 
137 static inline int
138 netifd_extdev_reload(struct extdev_device *edev, struct blob_attr *msg)
139 {
140         D(DEVICE, "reload %s '%s' at external device handler", edev->dev.type->name,
141                 edev->dev.ifname);
142         return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_RELOAD], msg,
143                                      NULL, NULL);
144 }
145 
146 static inline int
147 netifd_extdev_free(struct extdev_device *edev, struct blob_attr *msg)
148 {
149         D(DEVICE, "delete %s '%s' with external device handler", edev->dev.type->name,
150                 edev->dev.ifname);
151         return netifd_extdev_invoke(edev->etype->peer_id, __extdev_methods[METHOD_FREE], msg,
152                                      NULL, NULL);
153 }
154 
155 static inline int
156 netifd_extdev_prepare(struct extdev_bridge *ebr, struct blob_attr *msg)
157 {
158         D(DEVICE, "prepare %s bridge '%s' at external device handler", 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);
162 }
163 
164 static inline int
165 netifd_extdev_add(struct extdev_bridge *ebr, struct blob_attr *msg)
166 {
167         D(DEVICE, "add a member to %s bridge '%s' at external device handler",
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);
171 }
172 
173 static inline int
174 netifd_extdev_remove(struct extdev_bridge *ebr, struct blob_attr *msg)
175 {
176         D(DEVICE, "remove a member from %s bridge '%s' at external device handler",
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);
180 }
181 
182 static inline void
183 extdev_invocation_error(int error, const char *method, const char *devname)
184 {
185         netifd_log_message(L_CRIT, "'%s' failed for '%s': %s\n",
186                 method, devname, ubus_strerror(error));
187 }
188 
189 static struct ubus_method extdev_ubus_obj_methods[] = {};
190 
191 static struct ubus_object_type extdev_ubus_object_type =
192         UBUS_OBJECT_TYPE("netifd_extdev", extdev_ubus_obj_methods);
193 
194 static int
195 extdev_lookup_id(struct extdev_type *etype)
196 {
197         int ret = UBUS_STATUS_UNKNOWN_ERROR;
198 
199         if (!etype || !etype->name)
200                 goto error;
201 
202         ret = ubus_lookup_id(ubus_ctx, etype->name, &etype->peer_id);
203         if (ret)
204                 goto error;
205 
206         return 0;
207 
208 error:
209         netifd_log_message(L_CRIT, "Could not find '%s' ubus ID: %s\n",
210                            etype->name, ubus_strerror(ret));
211         return ret;
212 }
213 
214 static int
215 extdev_ext_ubus_obj_wait(struct ubus_event_handler *h)
216 {
217         return ubus_register_event_handler(ubus_ctx, h, "ubus.object.add");
218 }
219 
220 static int
221 extdev_subscribe(struct extdev_type *etype)
222 {
223         int ret;
224 
225         ret = extdev_lookup_id(etype);
226         if (ret) {
227                 etype->subscribed = false;
228                 return ret;
229         }
230 
231         ret = ubus_subscribe(ubus_ctx, &etype->ubus_sub, etype->peer_id);
232         if (ret) {
233                 etype->subscribed = false;
234                 extdev_ext_ubus_obj_wait(&etype->obj_wait);
235         } else {
236                 netifd_log_message(L_NOTICE, "subscribed to external device handler '%s'\n",
237                         etype->name);
238                 etype->subscribed = true;
239         }
240 
241         return ret;
242 }
243 
244 static void
245 extdev_wait_ev_cb(struct ubus_context *ctx, struct ubus_event_handler *ev_handler,
246         const char *type, struct blob_attr *msg)
247 {
248         static const struct blobmsg_policy wait_policy = {
249                 "path", BLOBMSG_TYPE_STRING
250         };
251 
252         struct blob_attr *attr;
253         const char *path;
254         struct extdev_type *etype;
255 
256         etype = container_of(ev_handler, struct extdev_type, obj_wait);
257 
258         if (strcmp(type, "ubus.object.add"))
259                 return;
260 
261         blobmsg_parse_attr(&wait_policy, 1, &attr, msg);
262         if (!attr)
263                 return;
264 
265         path = blobmsg_data(attr);
266         if (strcmp(etype->name, path))
267                 return;
268 
269         extdev_subscribe(etype);
270 }
271 
272 static int
273 extdev_bridge_disable_interface(struct extdev_bridge *ebr)
274 {
275         int ret;
276 
277         if (!ebr->active)
278                 return 0;
279 
280         blob_buf_init(&b, 0);
281         blobmsg_add_string(&b, "name", ebr->edev.dev.ifname);
282 
283         ret = netifd_extdev_free(&ebr->edev, b.head);
284 
285         if (ret && ret != UBUS_STATUS_NOT_FOUND)
286                 goto error;
287 
288         ebr->active = false;
289         return 0;
290 
291 error:
292         extdev_invocation_error(ret, __extdev_methods[METHOD_FREE], ebr->edev.dev.ifname);
293         return ret;
294 }
295 
296 static int
297 extdev_bridge_enable_interface(struct extdev_bridge *ebr)
298 {
299         int ret;
300 
301         if (ebr->active)
302                 return 0;
303 
304         ret = netifd_extdev_create(&ebr->edev, ebr->config);
305         if (ret)
306                 goto error;
307 
308         ebr->active = true;
309         return 0;
310 
311 error:
312         extdev_invocation_error(ret, __extdev_methods[METHOD_CREATE], ebr->edev.dev.ifname);
313         return ret;
314 }
315 
316 static int
317 extdev_bridge_enable_member(struct extdev_bridge_member *ubm)
318 {
319         int ret;
320         struct extdev_bridge *ebr = ubm->parent_br;
321 
322         D(DEVICE, "%s enable member %s", ebr->edev.dev.ifname, ubm->name);
323 
324         if (!ubm->present)
325                 return 0;
326 
327         ret = extdev_bridge_enable_interface(ebr);
328         if (ret)
329                 goto error;
330 
331         ret = device_claim(&ubm->dev_usr);
332         if (ret < 0)
333                 goto error;
334 
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);
338 
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);
342         if (ret) {
343                 extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_ADD],
344                                          ubm->dev_usr.dev->ifname);
345                 goto error;
346         }
347 
348         device_set_present(&ebr->edev.dev, true);
349         device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE);
350 
351         return 0;
352 
353 error:
354         D(DEVICE, "%s: failed to enable member '%s'", ebr->edev.dev.ifname, ubm->name);
355 
356         ebr->n_failed++;
357         ubm->present = false;
358         ebr->n_present--;
359 
360         return ret;
361 }
362 
363 static int
364 extdev_bridge_disable_member(struct extdev_bridge_member *ubm)
365 {
366         int ret;
367         struct extdev_bridge *ebr = ubm->parent_br;
368 
369         if (!ubm->present)
370                 return 0;
371 
372         D(DEVICE, "%s disable member %s", ubm->parent_br->edev.dev.ifname, ubm->name);
373 
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);
377 
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);
381 
382         /* continue in case of NOT FOUND since we're trying to remove anyway */
383         if (ret && ret != UBUS_STATUS_NOT_FOUND)
384                 goto error;
385 
386         device_release(&ubm->dev_usr);
387         device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE);
388 
389         return 0;
390 
391 error:
392         extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_REMOVE],
393                         ubm->dev_usr.dev->ifname);
394 
395         return ret;
396 }
397 
398 static int
399 extdev_bridge_set_down(struct extdev_bridge *ebr)
400 {
401         D(DEVICE, "set %s bridge %s down", ebr->edev.dev.type->name, ebr->edev.dev.ifname);
402 
403         struct extdev_bridge_member *ubm;
404 
405         ebr->set_state(&ebr->edev.dev, false);
406 
407         vlist_for_each_element(&ebr->members, ubm, node)
408                 extdev_bridge_disable_member(ubm);
409 
410         extdev_bridge_disable_interface(ebr);
411 
412         return 0;
413 }
414 
415 static void
416 extdev_bridge_check_retry(struct extdev_bridge *ebr)
417 {
418         if (!ebr->n_failed)
419                 return;
420 
421         uloop_timeout_set(&ebr->retry, 200);
422 }
423 
424 static int
425 extdev_bridge_set_up(struct extdev_bridge *ebr)
426 {
427         D(DEVICE, "set %s bridge %s up", ebr->edev.dev.type->name, ebr->edev.dev.ifname);
428 
429         struct extdev_bridge_member *ubm;
430         int ret;
431 
432         if (!ebr->n_present) {
433                 if (!ebr->force_active)
434                         return -ENOENT;
435 
436                 ret = extdev_bridge_enable_interface(ebr);
437                 if (ret)
438                         return ret;
439         }
440 
441         ebr->n_failed = 0;
442         vlist_for_each_element(&ebr->members, ubm, node)
443                 extdev_bridge_enable_member(ubm);
444 
445         extdev_bridge_check_retry(ebr);
446 
447         if (!ebr->force_active && !ebr->n_present) {
448                 extdev_bridge_disable_interface(ebr);
449                 device_set_present(&ebr->edev.dev, false);
450                 return -ENOENT;
451         }
452 
453         return 0;
454 }
455 
456 static int
457 extdev_bridge_set_state(struct device *dev, bool up)
458 {
459         struct extdev_bridge *ebr;
460 
461         if (!dev->type->bridge_capability)
462                 return -1;
463 
464         ebr = container_of(dev, struct extdev_bridge, edev.dev);
465 
466         if (up)
467                 return extdev_bridge_set_up(ebr);
468         else
469                 return extdev_bridge_set_down(ebr);
470 }
471 
472 static void
473 extdev_bridge_remove_member(struct extdev_bridge_member *member)
474 {
475         struct extdev_bridge *ebr = member->parent_br;
476 
477         if (!member->present)
478                 return;
479 
480         if (ebr->edev.dev.active)
481                 extdev_bridge_disable_member(member);
482 
483         member->present = false;
484         ebr->n_present--;
485 
486         if (ebr->empty)
487                 return;
488 
489         ebr->force_active = false;
490         if (ebr->n_present == 0)
491                 device_set_present(&ebr->edev.dev, false);
492 }
493 
494 static void
495 extdev_bridge_member_cb(struct device_user *usr, enum device_event event)
496 {
497         int ret;
498         struct extdev_bridge_member *ubm;
499         struct extdev_bridge *ebr;
500 
501         ubm = container_of(usr, struct extdev_bridge_member, dev_usr);
502         ebr = ubm->parent_br;
503 
504         switch (event) {
505                 case DEV_EVENT_ADD:
506                         assert(!ubm->present);
507 
508                         ubm->present = true;
509                         ebr->n_present++;
510 
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);
515                                 if (ret)
516                                         goto error;
517 
518                                 ebr->active = true;
519                                 ret = ebr->set_state(&ebr->edev.dev, true);
520                                 if (ret < 0)
521                                         extdev_bridge_set_down(ebr);
522                                 device_set_present(&ebr->edev.dev, true);
523                         }
524 
525                         extdev_bridge_enable_member(ubm);
526                         break;
527                 case DEV_EVENT_REMOVE:
528                         if (usr->hotplug) {
529                                 vlist_delete(&ebr->members, &ubm->node);
530                                 return;
531                         }
532 
533                         if (ubm->present)
534                                 extdev_bridge_remove_member(ubm);
535                         break;
536                 default:
537                         break;
538         }
539 
540         return;
541 
542 error:
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;
546         ebr->n_present--;
547 }
548 
549 static void
550 __bridge_enable_members(struct extdev_bridge *ebr)
551 {
552         struct extdev_bridge_member *cur;
553 
554         ebr->n_failed = 0;
555 
556         vlist_for_each_element(&ebr->members, cur, node) {
557                 if (cur->present)
558                         continue;
559 
560                 if (!cur->dev_usr.dev->present)
561                         continue;
562 
563                 cur->present = true;
564                 ebr->n_present++;
565                 extdev_bridge_enable_member(cur);
566         }
567 }
568 
569 static void
570 extdev_bridge_retry_enable_members(struct uloop_timeout *timeout)
571 {
572         struct extdev_bridge *ebr = container_of(timeout, struct extdev_bridge, retry);
573 
574         D(DEVICE, "%s retry enable members", ebr->edev.dev.ifname);
575 
576         __bridge_enable_members(ebr);
577 }
578 
579 static struct extdev_bridge_member *
580 extdev_bridge_create_member(struct extdev_bridge *ebr, struct device *dev)
581 {
582         struct extdev_bridge_member *ubm;
583         char *name;
584 
585         ubm = calloc_a(sizeof(*ubm), &name, strlen(dev->ifname) + 1);
586         if (!ubm)
587                 return NULL;
588 
589         ubm->parent_br = ebr;
590         ubm->name = name;
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
597          * already existed */
598         ubm = vlist_find(&ebr->members, dev->ifname, ubm, node);
599         if (!ubm)
600                 return NULL;
601 
602         return ubm;
603 }
604 
605 static void
606 extdev_bridge_add_member(struct extdev_bridge *ebr, const char *name)
607 {
608         D(DEVICE, "%s add member %s", ebr->edev.dev.ifname, name);
609 
610         struct device *dev;
611 
612         dev = device_get(name, 1);
613         if (!dev)
614                 return;
615 
616         extdev_bridge_create_member(ebr, dev);
617 }
618 
619 /* TODO: how to handle vlan arg? */
620 static int
621 extdev_hotplug_add(struct device *ebr_dev, struct device *ebm_dev, struct blob_attr *vlan)
622 {
623         D(DEVICE, "%s hotplug add member %s", ebr_dev->ifname, ebm_dev->ifname);
624 
625         struct extdev_bridge *ebr;
626         struct extdev_bridge_member *ubm;
627 
628         if (!ebr_dev->type->bridge_capability)
629                 return UBUS_STATUS_NOT_SUPPORTED;
630 
631         ebr = container_of(ebr_dev, struct extdev_bridge, edev.dev);
632 
633         if (!ebr->edev.etype->subscribed)
634                 return UBUS_STATUS_NOT_FOUND;
635 
636         ubm = extdev_bridge_create_member(ebr, ebm_dev);
637         if (!ubm)
638                 return UBUS_STATUS_UNKNOWN_ERROR;
639 
640         device_broadcast_event(&ebr->edev.dev, DEV_EVENT_TOPO_CHANGE);
641 
642         return 0;
643 }
644 
645 static int
646 extdev_hotplug_remove(struct device *dev, struct device *member, struct blob_attr *vlan)
647 {
648         struct extdev_bridge *ebr;
649         struct extdev_bridge_member *ubm;
650 
651         if (!dev->type->bridge_capability)
652                 return UBUS_STATUS_NOT_SUPPORTED;
653 
654         ebr = container_of(dev, struct extdev_bridge, edev.dev);
655 
656         if (!ebr->edev.etype->subscribed)
657                 return UBUS_STATUS_NOT_FOUND;
658 
659         ubm = vlist_find(&ebr->members, member->ifname, ubm, node);
660         if (!ubm)
661                 return UBUS_STATUS_NOT_FOUND;
662 
663         vlist_delete(&ebr->members, &ubm->node);
664         extdev_bridge_remove_member(ubm);
665 
666         return 0;
667 }
668 
669 static int
670 extdev_hotplug_prepare(struct device *dev, struct device **bridge_dev)
671 {
672         struct extdev_bridge *ebr;
673         int ret;
674 
675         if (!dev->type->bridge_capability)
676                 return UBUS_STATUS_NOT_SUPPORTED;
677 
678         if (bridge_dev)
679                 *bridge_dev = dev;
680 
681         ebr = container_of(dev, struct extdev_bridge, edev.dev);
682 
683         blob_buf_init(&b, 0);
684         blobmsg_add_string(&b, "name", dev->ifname);
685 
686         ret = netifd_extdev_prepare(ebr, b.head);
687         if (ret)
688                 goto error;
689 
690         ebr->force_active = true;
691         device_set_present(&ebr->edev.dev, true);
692 
693         return 0;
694 
695 error:
696         extdev_invocation_error(ret, __extdev_methods[METHOD_HOTPLUG_PREPARE], dev->ifname);
697         return ret;
698 }
699 
700 static void
701 extdev_bridge_free_member(struct extdev_bridge_member *ubm)
702 {
703         struct device *dev = ubm->dev_usr.dev;
704 
705         extdev_bridge_remove_member(ubm);
706         device_remove_user(&ubm->dev_usr);
707 
708         if (dev->present) {
709                 device_set_present(dev, false);
710                 device_set_present(dev, true);
711         }
712 
713         free(ubm);
714 }
715 
716 static void
717 extdev_bridge_member_update(struct vlist_tree *tree, struct vlist_node *node_new,
718                              struct vlist_node *node_old)
719 {
720         struct extdev_bridge_member *ubm;
721         struct device *dev;
722 
723         if (node_new) {
724                 ubm = container_of(node_new, struct extdev_bridge_member, node);
725 
726                 if (node_old) {
727                         free(ubm);
728                         return;
729                 }
730 
731                 dev = ubm->dev_usr.dev;
732                 ubm->dev_usr.dev = NULL;
733                 device_add_user(&ubm->dev_usr, dev);
734         }
735 
736         if (node_old) {
737                 ubm = container_of(node_old, struct extdev_bridge_member, node);
738                 extdev_bridge_free_member(ubm);
739         }
740 }
741 
742 
743 static void
744 bridge_dependency_retry(struct uloop_timeout *timeout)
745 {
746         struct extdev_bridge *ebr;
747 
748         ebr = container_of(timeout, struct extdev_bridge, edev.retry);
749 
750         __bridge_reload(ebr, NULL);
751 }
752 
753 static void
754 __buf_add_all(struct blob_attr *attr)
755 {
756         struct blob_attr *cur;
757         size_t rem;
758 
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));
762 }
763 
764 enum {
765         BRIDGE_EMPTY,
766         BRIDGE_IFNAMES,
767         BRIDGE_DEPENDS_ON,
768         __BRIDGE_MAX
769 };
770 
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 },
775 };
776 
777 static enum dev_change_type
778 __do_bridge_reload(struct extdev_bridge *ebr, struct blob_attr *config)
779 {
780         void *cfg_table;
781         int ret;
782 
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);
790 
791         ret = netifd_extdev_reload(&ebr->edev, b.head);
792 
793         if (ret) {
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;
797         } else {
798                 return DEV_CONFIG_RESTART;
799         }
800 }
801 
802 static enum dev_change_type
803 __bridge_reload(struct extdev_bridge *ebr, struct blob_attr *config)
804 {
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;
811         struct device *dev;
812         unsigned long diff = 0;
813 
814         if (config) {
815                 config = blob_memdup(config);
816                 blobmsg_parse_attr(brpol, __BRIDGE_MAX, tb, config);
817                 ebr->edev.dep_name = blobmsg_get_string(tb[BRIDGE_DEPENDS_ON]);
818 
819                 if (tb[BRIDGE_EMPTY] && blobmsg_get_bool(tb[BRIDGE_EMPTY]))
820                         ebr->empty = true;
821 
822                 if (ebr->config) {
823                         config_params = ebr->edev.dev.type->config_params;
824                         pol = config_params->params;
825 
826                         blobmsg_parse_attr(pol, n_params, old_tb, ebr->config);
827                         blobmsg_parse_attr(pol, n_params, brtb, config);
828 
829                         diff = 0;
830                         uci_blob_diff(brtb, old_tb, config_params, &diff);
831                         if (diff) {
832                                 if (diff & ~(1 << BRIDGE_IFNAMES)) {
833                                         change = DEV_CONFIG_RESTART;
834                                 } else {
835                                         change = __do_bridge_reload(ebr, config);
836                                 }
837 
838                                 free(ebr->config);
839                         }
840                 }
841 
842                 ebr->ifnames = tb[BRIDGE_IFNAMES];
843                 ebr->config = config;
844         }
845 
846         if (ebr->edev.dep_name) {
847                 dev = device_get(ebr->edev.dep_name, 0);
848                 if (!(dev && dev->current_config)) {
849                         D(DEVICE, "%s: cannot yet init config since dependency '%s' is not ready",
850                           ebr->edev.dev.ifname, ebr->edev.dep_name);
851                         ebr->edev.retry.cb = bridge_dependency_retry;
852                         uloop_timeout_set(&ebr->edev.retry, 200);
853                         return DEV_CONFIG_RESTART;
854                 }
855         }
856 
857         __bridge_config_init(ebr);
858         ebr->edev.dev.config_pending = false;
859         uloop_timeout_cancel(&ebr->edev.retry);
860 
861         return change;
862 }
863 
864 static enum dev_change_type
865 __reload(struct extdev_device *edev, struct blob_attr *config)
866 {
867         unsigned long diff = 0;
868         struct uci_blob_param_list *params;
869 
870         params = edev->etype->config_params;
871 
872         struct blob_attr *tb[params->n_params];
873         struct blob_attr *old_tb[params->n_params];
874 
875         blobmsg_parse_attr(params->params, params->n_params, tb, config);
876         blobmsg_parse_attr(params->params, params->n_params, old_tb, edev->dev.config);
877 
878         uci_blob_diff(tb, old_tb, edev->etype->config_params, &diff);
879         if (!diff)
880                 return DEV_CONFIG_NO_CHANGE;
881 
882         // TODO: make reload ubus call with old and new config
883 
884         device_set_present(&edev->dev, false);
885         device_set_present(&edev->dev, true);
886 
887         return DEV_CONFIG_APPLIED;
888 }
889 
890 static enum dev_change_type
891 extdev_reload(struct device *dev, struct blob_attr *config)
892 {
893         struct extdev_type *etype;
894         struct extdev_device *edev;
895         struct extdev_bridge *ebr;
896 
897         etype = container_of(dev->type, struct extdev_type, handler);
898 
899         if (!etype->subscribed)
900                 return DEV_CONFIG_NO_CHANGE;
901 
902         edev = container_of(dev, struct extdev_device, dev);
903 
904         if (dev->type->bridge_capability) {
905                 ebr = container_of(edev, struct extdev_bridge, edev);
906                 return __bridge_reload(ebr, config);
907         } else {
908                 return __reload(edev, config);
909         }
910 }
911 
912 static struct device*
913 __create(const char *name, struct device_type *type, struct blob_attr *config)
914 {
915         struct extdev_device *edev;
916         struct extdev_type *etype;
917         int ret;
918 
919         etype = container_of(type, struct extdev_type, handler);
920         edev = calloc(1, sizeof(struct extdev_device));
921         if (!edev)
922                 return NULL;
923 
924         ret = device_init(&edev->dev, type, name);
925         if (ret)
926                 goto error;
927 
928         edev->etype = etype;
929 
930         ret = netifd_extdev_create(edev, config);
931         if (ret)
932                 goto inv_error;
933 
934         edev->dev.config_pending = false;
935 
936         return &edev->dev;
937 
938 inv_error:
939         extdev_invocation_error(ret, __extdev_methods[METHOD_CREATE], name);
940 error:
941         free(edev->dev.config);
942         device_cleanup(&edev->dev);
943         free(edev);
944         netifd_log_message(L_WARNING, "Failed to create %s %s\n", type->name, name);
945         return NULL;
946 }
947 
948 static const struct device_hotplug_ops extdev_hotplug_ops = {
949         .prepare = extdev_hotplug_prepare,
950         .add = extdev_hotplug_add,
951         .del = extdev_hotplug_remove
952 };
953 
954 static struct device*
955 __bridge_create(const char *name, struct device_type *devtype, struct blob_attr *config)
956 {
957         struct extdev_bridge *ebr;
958 
959         ebr = calloc(1, sizeof(*ebr));
960         if (!ebr)
961                 return NULL;
962 
963         device_init(&ebr->edev.dev, devtype, name);
964         ebr->edev.dev.config_pending = true;
965         ebr->retry.cb = extdev_bridge_retry_enable_members;
966         ebr->edev.etype = container_of(devtype, struct extdev_type, handler);
967         ebr->set_state = ebr->edev.dev.set_state;
968         ebr->edev.dev.set_state = extdev_bridge_set_state;
969         ebr->edev.dev.hotplug_ops = &extdev_hotplug_ops;
970         vlist_init(&ebr->members, avl_strcmp, extdev_bridge_member_update);
971         ebr->members.keep_old = true;
972         __bridge_reload(ebr, config);
973 
974         return &ebr->edev.dev;
975 }
976 
977 /* Device creation process:
978  * For bridges without dependencies:
979  *  1) The bridge state is initialized in netifd. Devices for the members are
980  *     created and added to the members vlist by config_init automatically.
981  *  2) When the first bridge member device is brought up in
982  *     extdev_bridge_enable_member the 'create' call to the external device
983  *     handler is issued.
984  *  3) After successful device creation the bridge is marked "present" and a
985  *     new attempt at adding the member is made.
986  * For bridges with dependencies:
987  *  1) The bridge state is initialized in netifd. If a dependency is expressed
988  *     via the 'depends_on' UCI option and the dependency is not ready (i.e. it
989  *     does not exist or config_pending == true) the call to
990  *     __bridge_config_init() is postponed and a retry timer is started. Retries
991  *     happen until the dependency is ready. Then, __bridge_config_init() gets
992  *     called and the process continues as with bridges without dependencies
993  * For regular devices:
994  *  1) The device structure is created in netifd.
995  *  2) config_init is called automatically which issues the 'create' call to the
996  *     external device handler.
997  */
998 static struct device *
999 extdev_create(const char *name, struct device_type *devtype, struct blob_attr *config)
1000 {
1001         struct extdev_type *etype = container_of(devtype, struct extdev_type, handler);
1002 
1003         if (!etype->subscribed)
1004                 return NULL;
1005 
1006         if (devtype->bridge_capability)
1007                 return __bridge_create(name, devtype, config);
1008         else
1009                 return __create(name, devtype, config);
1010 }
1011 
1012 static void
1013 extdev_free(struct device *dev)
1014 {
1015         struct extdev_type *etype;
1016         struct extdev_device *edev;
1017         struct extdev_bridge *ebr;
1018         int ret;
1019 
1020         etype = container_of(dev->type, struct extdev_type, handler);
1021         edev = container_of(dev, struct extdev_device, dev);
1022 
1023         if (!etype->subscribed)
1024                 return;
1025 
1026         blob_buf_init(&b, 0);
1027         blobmsg_add_string(&b, "name", dev->ifname);
1028 
1029         ret = netifd_extdev_free(edev, b.head);
1030 
1031         if (ret && ret != UBUS_STATUS_NOT_FOUND)
1032                 goto error;
1033 
1034         if (dev->type->bridge_capability) {
1035                 ebr = container_of(dev, struct extdev_bridge, edev.dev);
1036 
1037                 vlist_flush_all(&ebr->members);
1038 //              vlist_flush_all(&dev->vlans); TODO: do we need this?
1039 
1040                 free(ebr->config);
1041                 free(ebr);
1042         }
1043 
1044         return;
1045 
1046 error:
1047         extdev_invocation_error(ret, __extdev_methods[METHOD_FREE],
1048                 dev->ifname);
1049 }
1050 
1051 static void
1052 __bridge_config_init(struct extdev_bridge *ebr)
1053 {
1054         int ret;
1055         size_t rem;
1056         struct blob_attr *cur;
1057 
1058         if (ebr->empty) {
1059                 ebr->force_active = true;
1060                 ret = netifd_extdev_create(&ebr->edev, ebr->config);
1061                 if (ret)
1062                         goto error;
1063                 device_set_present(&ebr->edev.dev, true);
1064         }
1065 
1066         ebr->n_failed = 0;
1067         vlist_update(&ebr->members);
1068         if (ebr->ifnames) {
1069                 blobmsg_for_each_attr(cur, ebr->ifnames, rem)
1070                         extdev_bridge_add_member(ebr, blobmsg_data(cur));
1071         }
1072 
1073         vlist_flush(&ebr->members);
1074         extdev_bridge_check_retry(ebr);
1075         return;
1076 
1077 error:
1078         fprintf(stderr, "Failed to init config for '%s': %s\n", ebr->edev.dev.ifname,
1079                 ubus_strerror(ret));
1080 }
1081 
1082 static void
1083 extdev_config_init(struct device *dev)
1084 {
1085         struct extdev_type *etype;
1086         struct extdev_bridge *ebr;
1087 
1088         etype = container_of(dev->type, struct extdev_type, handler);
1089 
1090         if (!etype->subscribed)
1091                 return;
1092 
1093         if (dev->type->bridge_capability) {
1094                 ebr = container_of(dev, struct extdev_bridge, edev.dev);
1095                 __bridge_config_init(ebr);
1096         }
1097 }
1098 
1099 static void
1100 extdev_buf_add_list(struct blob_attr *attr, size_t len, const char *name,
1101                      struct blob_buf *buf, bool array)
1102 {
1103         struct blob_attr *cur;
1104         struct blobmsg_hdr *hdr;
1105         void *list;
1106         int type;
1107 
1108         if (array)
1109                 list = blobmsg_open_array(buf, name);
1110         else
1111                 list = blobmsg_open_table(buf, name);
1112 
1113         blobmsg_for_each_attr(cur, attr, len) {
1114                 hdr = blob_data(cur);
1115                 type = blobmsg_type(cur);
1116                 switch (type) {
1117                         case BLOBMSG_TYPE_STRING:
1118                                 blobmsg_add_string(buf, (char *) hdr->name,
1119                                         blobmsg_get_string(cur));
1120                                 break;
1121                         case BLOBMSG_TYPE_TABLE:
1122                         case BLOBMSG_TYPE_ARRAY:
1123                                 extdev_buf_add_list(blobmsg_data(cur), blobmsg_data_len(cur),
1124                                         (char *) hdr->name, buf, type == BLOBMSG_TYPE_ARRAY);
1125                                 break;
1126                         case BLOBMSG_TYPE_INT64:
1127                                 blobmsg_add_u64(buf, (char *) hdr->name, blobmsg_get_u64(cur));
1128                                 break;
1129                         case BLOBMSG_TYPE_INT32:
1130                                 blobmsg_add_u32(buf, (char *) hdr->name, blobmsg_get_u32(cur));
1131                                 break;
1132                         case BLOBMSG_TYPE_INT16:
1133                                 blobmsg_add_u16(buf, (char *) hdr->name, blobmsg_get_u16(cur));
1134                                 break;
1135                         case BLOBMSG_TYPE_INT8:
1136                                 blobmsg_add_u8(buf, (char *) hdr->name, blobmsg_get_u8(cur));
1137                                 break;
1138                         default:
1139                                 break;
1140                 }
1141         }
1142 
1143         if (array)
1144                 blobmsg_close_array(buf, list);
1145         else
1146                 blobmsg_close_table(buf, list);
1147 }
1148 
1149 static void
1150 add_parsed_data(struct blob_attr **tb, const struct blobmsg_policy *policy, int n_params,
1151                 struct blob_buf *buf)
1152 {
1153         for (int i = 0; i < n_params; i++) {
1154                 if (!tb[i])
1155                         continue;
1156 
1157                 switch (policy[i].type) {
1158                         case BLOBMSG_TYPE_STRING:
1159                                 blobmsg_add_string(buf, policy[i].name, blobmsg_get_string(tb[i]));
1160                                 break;
1161                         case BLOBMSG_TYPE_ARRAY:
1162                         case BLOBMSG_TYPE_TABLE:
1163                                 extdev_buf_add_list(blobmsg_data(tb[i]), blobmsg_data_len(tb[i]),
1164                                         policy[i].name, buf, policy[i].type == BLOBMSG_TYPE_ARRAY);
1165                                 break;
1166                         case BLOBMSG_TYPE_INT64:
1167                                 blobmsg_add_u64(buf, policy[i].name, blobmsg_get_u64(tb[i]));
1168                                 break;
1169                         case BLOBMSG_TYPE_INT32:
1170                                 blobmsg_add_u32(buf, policy[i].name, blobmsg_get_u32(tb[i]));
1171                                 break;
1172                         case BLOBMSG_TYPE_INT16:
1173                                 blobmsg_add_u16(buf, policy[i].name, blobmsg_get_u16(tb[i]));
1174                                 break;
1175                         case BLOBMSG_TYPE_INT8:
1176                                 blobmsg_add_u8(buf, policy[i].name, blobmsg_get_u8(tb[i]));
1177                                 break;
1178                         default:
1179                                 break;
1180                 }
1181         }
1182 }
1183 
1184 struct dump_data {
1185         const struct device *dev;
1186         struct blob_buf *buf;
1187 };
1188 
1189 static void
1190 dump_cb(struct ubus_request *req, int type, struct blob_attr *reply)
1191 {
1192         struct dump_data *data;
1193         struct extdev_type *etype;
1194         const struct blobmsg_policy *info_policy;
1195         int n_params;
1196         struct blob_buf *buf;
1197 
1198         data = req->priv;
1199         etype = container_of(data->dev->type, struct extdev_type, handler);
1200         info_policy = etype->info_params->params;
1201         n_params = etype->info_params->n_params;
1202         buf = data->buf;
1203 
1204         struct blob_attr *tb[n_params];
1205 
1206         blobmsg_parse_attr(info_policy, n_params, tb, reply);
1207         add_parsed_data(tb, info_policy, n_params, buf);
1208 }
1209 
1210 static void
1211 extdev_dump(const char *method, struct device *dev, struct blob_buf *buf)
1212 {
1213         static struct dump_data data;
1214         struct extdev_type *etype;
1215 
1216         etype = container_of(dev->type, struct extdev_type, handler);
1217 
1218         if (!etype->subscribed)
1219                 return;
1220 
1221         data.dev = dev;
1222         data.buf = buf;
1223 
1224         blob_buf_init(&b, 0);
1225         blobmsg_add_string(&b, "name", dev->ifname);
1226 
1227         netifd_extdev_invoke(etype->peer_id, method, b.head, dump_cb, &data);
1228 }
1229 
1230 static void
1231 extdev_dump_info(struct device *dev, struct blob_buf *buf)
1232 {
1233         extdev_dump(__extdev_methods[METHOD_DUMP_INFO], dev, buf);
1234 }
1235 
1236 static void
1237 extdev_dump_stats(struct device *dev, struct blob_buf *buf)
1238 {
1239         extdev_dump(__extdev_methods[METHOD_DUMP_STATS], dev, buf);
1240 }
1241 
1242 static void
1243 extdev_ext_handler_remove_cb(struct ubus_context *ctx,
1244                               struct ubus_subscriber *obj, uint32_t id)
1245 {
1246         struct extdev_type *etype;
1247         etype = container_of(obj, struct extdev_type, ubus_sub);
1248 
1249         netifd_log_message(L_NOTICE, "%s: external device handler "
1250                 "'%s' disappeared. Waiting for it to re-appear.\n",
1251                 etype->handler.name, etype->name);
1252 
1253         etype->peer_id = 0;
1254         etype->subscribed = false;
1255 
1256         extdev_ext_ubus_obj_wait(&etype->obj_wait);
1257 }
1258 
1259 static void
1260 extdev_add_devtype(const char *cfg_file, const char *tname, const char *ubus_name,
1261                     bool bridge_capability, const char *br_prefix, json_object *cfg_obj,
1262                     json_object *info_obj, json_object *stats_obj)
1263 {
1264         static const char *OBJ_PREFIX = "network.device.";
1265 
1266         struct extdev_type *etype;
1267         struct device_type *devtype;
1268         char *ubus_obj_name, *devtype_name, *ext_dev_handler_name, *name_prefix;
1269         struct uci_blob_param_list *config_params, *info_params, *stats_params;
1270         int ret;
1271 
1272         etype = calloc_a(sizeof(*etype),
1273                 &ubus_obj_name, strlen(OBJ_PREFIX) + strlen(ubus_name) + 1,
1274                 &devtype_name, strlen(tname) + 1,
1275                 &ext_dev_handler_name, strlen(ubus_name) + 1,
1276                 &config_params, sizeof(struct uci_blob_param_list),
1277                 &info_params, sizeof(struct uci_blob_param_list),
1278                 &stats_params, sizeof(struct uci_blob_param_list));
1279 
1280         if (!etype)
1281                 return;
1282 
1283         etype->config_params = config_params;
1284         etype->info_params = info_params;
1285         etype->name = strcpy(ext_dev_handler_name, ubus_name);
1286 
1287         devtype = &etype->handler;
1288         devtype->name = strcpy(devtype_name, tname);
1289         devtype->create = extdev_create;
1290         devtype->free = extdev_free;
1291         devtype->config_init = extdev_config_init;
1292         devtype->reload = extdev_reload;
1293         devtype->dump_info = extdev_dump_info;
1294         devtype->dump_stats = extdev_dump_stats;
1295         devtype->bridge_capability = bridge_capability;
1296         devtype->config_params = etype->config_params;
1297 
1298         if (bridge_capability) {
1299                 name_prefix = malloc(strlen(br_prefix) + 1);
1300                 if (!name_prefix)
1301                         goto error;
1302 
1303                 strcpy(name_prefix, br_prefix);
1304                 devtype->name_prefix = name_prefix;
1305         }
1306 
1307         /* subscribe to external device handler */
1308         sprintf(ubus_obj_name, "%s%s", OBJ_PREFIX,  ubus_name);
1309         etype->ubus_sub.obj.name = ubus_obj_name;
1310         etype->ubus_sub.obj.type = &extdev_ubus_object_type;
1311         ret = ubus_register_subscriber(ubus_ctx, &etype->ubus_sub);
1312         if (ret) {
1313                 fprintf(stderr, "Failed to register subscriber object '%s'\n",
1314                         etype->ubus_sub.obj.name);
1315                 goto error;
1316         }
1317         etype->obj_wait.cb = extdev_wait_ev_cb;
1318         etype->ubus_sub.remove_cb = extdev_ext_handler_remove_cb;
1319         extdev_subscribe(etype);
1320 
1321         /* parse config params from JSON object */
1322         etype->config_strbuf = netifd_handler_parse_config(etype->config_params, cfg_obj);
1323         if (!etype->config_strbuf)
1324                 goto error;
1325 
1326         /* parse info dump params from JSON object */
1327         if (!info_obj) {
1328                 devtype->dump_info = NULL;
1329         } else {
1330                 etype->info_strbuf = netifd_handler_parse_config(etype->info_params, info_obj);
1331                 if (!etype->info_strbuf)
1332                         devtype->dump_info = NULL;
1333         }
1334 
1335         /* parse statistics dump params from JSON object */
1336         if (!stats_obj) {
1337                 devtype->dump_stats = NULL;
1338         } else {
1339                 etype->stats_strbuf = netifd_handler_parse_config(etype->stats_params, stats_obj);
1340                 if (!etype->stats_strbuf)
1341                         devtype->dump_stats = NULL;
1342         }
1343 
1344         ret = device_type_add(devtype);
1345         if (ret)
1346                 goto config_error;
1347 
1348         return;
1349 
1350 config_error:
1351         free(etype->config_strbuf);
1352         free(etype->info_strbuf);
1353         free(etype->stats_strbuf);
1354 
1355 error:
1356         fprintf(stderr, "Failed to create device handler for device"
1357                 "type '%s' from file '%s'\n", tname, cfg_file);
1358         free(ubus_obj_name);
1359         free(devtype_name);
1360         free(etype);
1361 }
1362 
1363 /* create extdev device handler stubs from JSON description */
1364 void
1365 extdev_init(void)
1366 {
1367         confdir_fd = netifd_open_subdir("extdev-config");
1368         if (confdir_fd < 0)
1369                 return;
1370         netifd_init_extdev_handlers(confdir_fd, extdev_add_devtype);
1371 }
1372 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt