• 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\n", 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\n", 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\n", 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\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);
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\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);
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\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);
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(&wait_policy, 1, &attr, blob_data(msg), blob_len(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\n", 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'\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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         int 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(brpol, __BRIDGE_MAX, tb, blobmsg_data(config), blobmsg_len(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(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
829                         (config));
830 
831                         diff = 0;
832                         uci_blob_diff(brtb, old_tb, config_params, &diff);
833                         if (diff) {
834                                 if (diff & ~(1 << BRIDGE_IFNAMES)) {
835                                         change = DEV_CONFIG_RESTART;
836                                 } else {
837                                         change = __do_bridge_reload(ebr, config);
838                                 }
839 
840                                 free(ebr->config);
841                         }
842                 }
843 
844                 ebr->ifnames = tb[BRIDGE_IFNAMES];
845                 ebr->config = config;
846         }
847 
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;
856                 }
857         }
858 
859         __bridge_config_init(ebr);
860         ebr->edev.dev.config_pending = false;
861         uloop_timeout_cancel(&ebr->edev.retry);
862 
863         return change;
864 }
865 
866 static enum dev_change_type
867 __reload(struct extdev_device *edev, struct blob_attr *config)
868 {
869         unsigned long diff = 0;
870         struct uci_blob_param_list *params;
871 
872         params = edev->etype->config_params;
873 
874         struct blob_attr *tb[params->n_params];
875         struct blob_attr *old_tb[params->n_params];
876 
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));
881 
882         uci_blob_diff(tb, old_tb, edev->etype->config_params, &diff);
883         if (!diff)
884                 return DEV_CONFIG_NO_CHANGE;
885 
886         // TODO: make reload ubus call with old and new config
887 
888         device_set_present(&edev->dev, false);
889         device_set_present(&edev->dev, true);
890 
891         return DEV_CONFIG_APPLIED;
892 }
893 
894 static enum dev_change_type
895 extdev_reload(struct device *dev, struct blob_attr *config)
896 {
897         struct extdev_type *etype;
898         struct extdev_device *edev;
899         struct extdev_bridge *ebr;
900 
901         etype = container_of(dev->type, struct extdev_type, handler);
902 
903         if (!etype->subscribed)
904                 return DEV_CONFIG_NO_CHANGE;
905 
906         edev = container_of(dev, struct extdev_device, dev);
907 
908         if (dev->type->bridge_capability) {
909                 ebr = container_of(edev, struct extdev_bridge, edev);
910                 return __bridge_reload(ebr, config);
911         } else {
912                 return __reload(edev, config);
913         }
914 }
915 
916 static struct device*
917 __create(const char *name, struct device_type *type, struct blob_attr *config)
918 {
919         struct extdev_device *edev;
920         struct extdev_type *etype;
921         int ret;
922 
923         etype = container_of(type, struct extdev_type, handler);
924         edev = calloc(1, sizeof(struct extdev_device));
925         if (!edev)
926                 return NULL;
927 
928         ret = device_init(&edev->dev, type, name);
929         if (ret)
930                 goto error;
931 
932         edev->etype = etype;
933 
934         ret = netifd_extdev_create(edev, config);
935         if (ret)
936                 goto inv_error;
937 
938         edev->dev.config_pending = false;
939 
940         return &edev->dev;
941 
942 inv_error:
943         extdev_invocation_error(ret, __extdev_methods[METHOD_CREATE], name);
944 error:
945         free(edev->dev.config);
946         device_cleanup(&edev->dev);
947         free(edev);
948         netifd_log_message(L_WARNING, "Failed to create %s %s\n", type->name, name);
949         return NULL;
950 }
951 
952 static const struct device_hotplug_ops extdev_hotplug_ops = {
953         .prepare = extdev_hotplug_prepare,
954         .add = extdev_hotplug_add,
955         .del = extdev_hotplug_remove
956 };
957 
958 static struct device*
959 __bridge_create(const char *name, struct device_type *devtype, struct blob_attr *config)
960 {
961         struct extdev_bridge *ebr;
962 
963         ebr = calloc(1, sizeof(*ebr));
964         if (!ebr)
965                 return NULL;
966 
967         device_init(&ebr->edev.dev, devtype, name);
968         ebr->edev.dev.config_pending = true;
969         ebr->retry.cb = extdev_bridge_retry_enable_members;
970         ebr->edev.etype = container_of(devtype, struct extdev_type, handler);
971         ebr->set_state = ebr->edev.dev.set_state;
972         ebr->edev.dev.set_state = extdev_bridge_set_state;
973         ebr->edev.dev.hotplug_ops = &extdev_hotplug_ops;
974         vlist_init(&ebr->members, avl_strcmp, extdev_bridge_member_update);
975         ebr->members.keep_old = true;
976         __bridge_reload(ebr, config);
977 
978         return &ebr->edev.dev;
979 }
980 
981 /* Device creation process:
982  * For bridges without dependencies:
983  *  1) The bridge state is initialized in netifd. Devices for the members are
984  *     created and added to the members vlist by config_init automatically.
985  *  2) When the first bridge member device is brought up in
986  *     extdev_bridge_enable_member the 'create' call to the external device
987  *     handler is issued.
988  *  3) After successful device creation the bridge is marked "present" and a
989  *     new attempt at adding the member is made.
990  * For bridges with dependencies:
991  *  1) The bridge state is initialized in netifd. If a dependency is expressed
992  *     via the 'depends_on' UCI option and the dependency is not ready (i.e. it
993  *     does not exist or config_pending == true) the call to
994  *     __bridge_config_init() is postponed and a retry timer is started. Retries
995  *     happen until the dependency is ready. Then, __bridge_config_init() gets
996  *     called and the process continues as with bridges without dependencies
997  * For regular devices:
998  *  1) The device structure is created in netifd.
999  *  2) config_init is called automatically which issues the 'create' call to the
1000  *     external device handler.
1001  */
1002 static struct device *
1003 extdev_create(const char *name, struct device_type *devtype, struct blob_attr *config)
1004 {
1005         struct extdev_type *etype = container_of(devtype, struct extdev_type, handler);
1006 
1007         if (!etype->subscribed)
1008                 return NULL;
1009 
1010         if (devtype->bridge_capability)
1011                 return __bridge_create(name, devtype, config);
1012         else
1013                 return __create(name, devtype, config);
1014 }
1015 
1016 static void
1017 extdev_free(struct device *dev)
1018 {
1019         struct extdev_type *etype;
1020         struct extdev_device *edev;
1021         struct extdev_bridge *ebr;
1022         int ret;
1023 
1024         etype = container_of(dev->type, struct extdev_type, handler);
1025         edev = container_of(dev, struct extdev_device, dev);
1026 
1027         if (!etype->subscribed)
1028                 return;
1029 
1030         blob_buf_init(&b, 0);
1031         blobmsg_add_string(&b, "name", dev->ifname);
1032 
1033         ret = netifd_extdev_free(edev, b.head);
1034 
1035         if (ret && ret != UBUS_STATUS_NOT_FOUND)
1036                 goto error;
1037 
1038         if (dev->type->bridge_capability) {
1039                 ebr = container_of(dev, struct extdev_bridge, edev.dev);
1040 
1041                 vlist_flush_all(&ebr->members);
1042 //              vlist_flush_all(&dev->vlans); TODO: do we need this?
1043 
1044                 free(ebr->config);
1045                 free(ebr);
1046         }
1047 
1048         return;
1049 
1050 error:
1051         extdev_invocation_error(ret, __extdev_methods[METHOD_FREE],
1052                 dev->ifname);
1053 }
1054 
1055 static void
1056 __bridge_config_init(struct extdev_bridge *ebr)
1057 {
1058         int rem, ret;
1059         struct blob_attr *cur;
1060 
1061         if (ebr->empty) {
1062                 ebr->force_active = true;
1063                 ret = netifd_extdev_create(&ebr->edev, ebr->config);
1064                 if (ret)
1065                         goto error;
1066                 device_set_present(&ebr->edev.dev, true);
1067         }
1068 
1069         ebr->n_failed = 0;
1070         vlist_update(&ebr->members);
1071         if (ebr->ifnames) {
1072                 blobmsg_for_each_attr(cur, ebr->ifnames, rem)
1073                         extdev_bridge_add_member(ebr, blobmsg_data(cur));
1074         }
1075 
1076         vlist_flush(&ebr->members);
1077         extdev_bridge_check_retry(ebr);
1078         return;
1079 
1080 error:
1081         fprintf(stderr, "Failed to init config for '%s': %s\n", ebr->edev.dev.ifname,
1082                 ubus_strerror(ret));
1083 }
1084 
1085 static void
1086 extdev_config_init(struct device *dev)
1087 {
1088         struct extdev_type *etype;
1089         struct extdev_bridge *ebr;
1090 
1091         etype = container_of(dev->type, struct extdev_type, handler);
1092 
1093         if (!etype->subscribed)
1094                 return;
1095 
1096         if (dev->type->bridge_capability) {
1097                 ebr = container_of(dev, struct extdev_bridge, edev.dev);
1098                 __bridge_config_init(ebr);
1099         }
1100 }
1101 
1102 static void
1103 extdev_buf_add_list(struct blob_attr *attr, int len, const char *name,
1104                      struct blob_buf *buf, bool array)
1105 {
1106         struct blob_attr *cur;
1107         struct blobmsg_hdr *hdr;
1108         void *list;
1109         int type;
1110 
1111         if (array)
1112                 list = blobmsg_open_array(buf, name);
1113         else
1114                 list = blobmsg_open_table(buf, name);
1115 
1116         blobmsg_for_each_attr(cur, attr, len) {
1117                 hdr = blob_data(cur);
1118                 type = blobmsg_type(cur);
1119                 switch (type) {
1120                         case BLOBMSG_TYPE_STRING:
1121                                 blobmsg_add_string(buf, (char *) hdr->name,
1122                                         blobmsg_get_string(cur));
1123                                 break;
1124                         case BLOBMSG_TYPE_TABLE:
1125                         case BLOBMSG_TYPE_ARRAY:
1126                                 extdev_buf_add_list(blobmsg_data(cur), blobmsg_data_len(cur),
1127                                         (char *) hdr->name, buf, type == BLOBMSG_TYPE_ARRAY);
1128                                 break;
1129                         case BLOBMSG_TYPE_INT64:
1130                                 blobmsg_add_u64(buf, (char *) hdr->name, blobmsg_get_u64(cur));
1131                                 break;
1132                         case BLOBMSG_TYPE_INT32:
1133                                 blobmsg_add_u32(buf, (char *) hdr->name, blobmsg_get_u32(cur));
1134                                 break;
1135                         case BLOBMSG_TYPE_INT16:
1136                                 blobmsg_add_u16(buf, (char *) hdr->name, blobmsg_get_u16(cur));
1137                                 break;
1138                         case BLOBMSG_TYPE_INT8:
1139                                 blobmsg_add_u8(buf, (char *) hdr->name, blobmsg_get_u8(cur));
1140                                 break;
1141                         default:
1142                                 break;
1143                 }
1144         }
1145 
1146         if (array)
1147                 blobmsg_close_array(buf, list);
1148         else
1149                 blobmsg_close_table(buf, list);
1150 }
1151 
1152 static void
1153 add_parsed_data(struct blob_attr **tb, const struct blobmsg_policy *policy, int n_params,
1154                 struct blob_buf *buf)
1155 {
1156         for (int i = 0; i < n_params; i++) {
1157                 if (!tb[i])
1158                         continue;
1159 
1160                 switch (policy[i].type) {
1161                         case BLOBMSG_TYPE_STRING:
1162                                 blobmsg_add_string(buf, policy[i].name, blobmsg_get_string(tb[i]));
1163                                 break;
1164                         case BLOBMSG_TYPE_ARRAY:
1165                         case BLOBMSG_TYPE_TABLE:
1166                                 extdev_buf_add_list(blobmsg_data(tb[i]), blobmsg_data_len(tb[i]),
1167                                         policy[i].name, buf, policy[i].type == BLOBMSG_TYPE_ARRAY);
1168                                 break;
1169                         case BLOBMSG_TYPE_INT64:
1170                                 blobmsg_add_u64(buf, policy[i].name, blobmsg_get_u64(tb[i]));
1171                                 break;
1172                         case BLOBMSG_TYPE_INT32:
1173                                 blobmsg_add_u32(buf, policy[i].name, blobmsg_get_u32(tb[i]));
1174                                 break;
1175                         case BLOBMSG_TYPE_INT16:
1176                                 blobmsg_add_u16(buf, policy[i].name, blobmsg_get_u16(tb[i]));
1177                                 break;
1178                         case BLOBMSG_TYPE_INT8:
1179                                 blobmsg_add_u8(buf, policy[i].name, blobmsg_get_u8(tb[i]));
1180                                 break;
1181                         default:
1182                                 break;
1183                 }
1184         }
1185 }
1186 
1187 struct dump_data {
1188         const struct device *dev;
1189         struct blob_buf *buf;
1190 };
1191 
1192 static void
1193 dump_cb(struct ubus_request *req, int type, struct blob_attr *reply)
1194 {
1195         struct dump_data *data;
1196         struct extdev_type *etype;
1197         const struct blobmsg_policy *info_policy;
1198         int n_params;
1199         struct blob_buf *buf;
1200 
1201         data = req->priv;
1202         etype = container_of(data->dev->type, struct extdev_type, handler);
1203         info_policy = etype->info_params->params;
1204         n_params = etype->info_params->n_params;
1205         buf = data->buf;
1206 
1207         struct blob_attr *tb[n_params];
1208 
1209         blobmsg_parse(info_policy, n_params, tb, blobmsg_data(reply), blobmsg_len(reply));
1210         add_parsed_data(tb, info_policy, n_params, buf);
1211 }
1212 
1213 static void
1214 extdev_dump(const char *method, struct device *dev, struct blob_buf *buf)
1215 {
1216         static struct dump_data data;
1217         struct extdev_type *etype;
1218 
1219         etype = container_of(dev->type, struct extdev_type, handler);
1220 
1221         if (!etype->subscribed)
1222                 return;
1223 
1224         data.dev = dev;
1225         data.buf = buf;
1226 
1227         blob_buf_init(&b, 0);
1228         blobmsg_add_string(&b, "name", dev->ifname);
1229 
1230         netifd_extdev_invoke(etype->peer_id, method, b.head, dump_cb, &data);
1231 }
1232 
1233 static void
1234 extdev_dump_info(struct device *dev, struct blob_buf *buf)
1235 {
1236         extdev_dump(__extdev_methods[METHOD_DUMP_INFO], dev, buf);
1237 }
1238 
1239 static void
1240 extdev_dump_stats(struct device *dev, struct blob_buf *buf)
1241 {
1242         extdev_dump(__extdev_methods[METHOD_DUMP_STATS], dev, buf);
1243 }
1244 
1245 static void
1246 extdev_ext_handler_remove_cb(struct ubus_context *ctx,
1247                               struct ubus_subscriber *obj, uint32_t id)
1248 {
1249         struct extdev_type *etype;
1250         etype = container_of(obj, struct extdev_type, ubus_sub);
1251 
1252         netifd_log_message(L_NOTICE, "%s: external device handler "
1253                 "'%s' disappeared. Waiting for it to re-appear.\n",
1254                 etype->handler.name, etype->name);
1255 
1256         etype->peer_id = 0;
1257         etype->subscribed = false;
1258 
1259         extdev_ext_ubus_obj_wait(&etype->obj_wait);
1260 }
1261 
1262 static void
1263 extdev_add_devtype(const char *cfg_file, const char *tname, const char *ubus_name,
1264                     bool bridge_capability, const char *br_prefix, json_object *cfg_obj,
1265                     json_object *info_obj, json_object *stats_obj)
1266 {
1267         static const char *OBJ_PREFIX = "network.device.";
1268 
1269         struct extdev_type *etype;
1270         struct device_type *devtype;
1271         char *ubus_obj_name, *devtype_name, *ext_dev_handler_name, *name_prefix;
1272         struct uci_blob_param_list *config_params, *info_params, *stats_params;
1273         int ret;
1274 
1275         etype = calloc_a(sizeof(*etype),
1276                 &ubus_obj_name, strlen(OBJ_PREFIX) + strlen(ubus_name) + 1,
1277                 &devtype_name, strlen(tname) + 1,
1278                 &ext_dev_handler_name, strlen(ubus_name) + 1,
1279                 &config_params, sizeof(struct uci_blob_param_list),
1280                 &info_params, sizeof(struct uci_blob_param_list),
1281                 &stats_params, sizeof(struct uci_blob_param_list));
1282 
1283         if (!etype)
1284                 return;
1285 
1286         etype->config_params = config_params;
1287         etype->info_params = info_params;
1288         etype->name = strcpy(ext_dev_handler_name, ubus_name);
1289 
1290         devtype = &etype->handler;
1291         devtype->name = strcpy(devtype_name, tname);
1292         devtype->create = extdev_create;
1293         devtype->free = extdev_free;
1294         devtype->config_init = extdev_config_init;
1295         devtype->reload = extdev_reload;
1296         devtype->dump_info = extdev_dump_info;
1297         devtype->dump_stats = extdev_dump_stats;
1298         devtype->bridge_capability = bridge_capability;
1299         devtype->config_params = etype->config_params;
1300 
1301         if (bridge_capability) {
1302                 name_prefix = malloc(strlen(br_prefix) + 1);
1303                 if (!name_prefix)
1304                         goto error;
1305 
1306                 strcpy(name_prefix, br_prefix);
1307                 devtype->name_prefix = name_prefix;
1308         }
1309 
1310         /* subscribe to external device handler */
1311         sprintf(ubus_obj_name, "%s%s", OBJ_PREFIX,  ubus_name);
1312         etype->ubus_sub.obj.name = ubus_obj_name;
1313         etype->ubus_sub.obj.type = &extdev_ubus_object_type;
1314         ret = ubus_register_subscriber(ubus_ctx, &etype->ubus_sub);
1315         if (ret) {
1316                 fprintf(stderr, "Failed to register subscriber object '%s'\n",
1317                         etype->ubus_sub.obj.name);
1318                 goto error;
1319         }
1320         etype->obj_wait.cb = extdev_wait_ev_cb;
1321         etype->ubus_sub.remove_cb = extdev_ext_handler_remove_cb;
1322         extdev_subscribe(etype);
1323 
1324         /* parse config params from JSON object */
1325         etype->config_strbuf = netifd_handler_parse_config(etype->config_params, cfg_obj);
1326         if (!etype->config_strbuf)
1327                 goto error;
1328 
1329         /* parse info dump params from JSON object */
1330         if (!info_obj) {
1331                 devtype->dump_info = NULL;
1332         } else {
1333                 etype->info_strbuf = netifd_handler_parse_config(etype->info_params, info_obj);
1334                 if (!etype->info_strbuf)
1335                         devtype->dump_info = NULL;
1336         }
1337 
1338         /* parse statistics dump params from JSON object */
1339         if (!stats_obj) {
1340                 devtype->dump_stats = NULL;
1341         } else {
1342                 etype->stats_strbuf = netifd_handler_parse_config(etype->stats_params, stats_obj);
1343                 if (!etype->stats_strbuf)
1344                         devtype->dump_stats = NULL;
1345         }
1346 
1347         ret = device_type_add(devtype);
1348         if (ret)
1349                 goto config_error;
1350 
1351         return;
1352 
1353 config_error:
1354         free(etype->config_strbuf);
1355         free(etype->info_strbuf);
1356         free(etype->stats_strbuf);
1357 
1358 error:
1359         fprintf(stderr, "Failed to create device handler for device"
1360                 "type '%s' from file '%s'\n", tname, cfg_file);
1361         free(ubus_obj_name);
1362         free(devtype_name);
1363         free(etype);
1364 }
1365 
1366 /* create extdev device handler stubs from JSON description */
1367 void
1368 extdev_init(void)
1369 {
1370         confdir_fd = netifd_open_subdir("extdev-config");
1371         if (confdir_fd < 0)
1372                 return;
1373         netifd_init_extdev_handlers(confdir_fd, extdev_add_devtype);
1374 }
1375 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt