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

Sources/netifd/bonding.c

  1 /*
  2  * netifd - network interface daemon
  3  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
  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 #include <string.h>
 15 #include <stdlib.h>
 16 #include <stdio.h>
 17 
 18 #include "netifd.h"
 19 #include "device.h"
 20 #include "system.h"
 21 
 22 struct bonding_device {
 23         struct device dev;
 24         device_state_cb set_state;
 25 
 26         struct blob_attr *port_list;
 27         struct vlist_tree ports;
 28         int n_present;
 29         int n_failed;
 30 
 31         struct bonding_port *primary_port;
 32         struct uloop_timeout retry;
 33 
 34         struct bonding_config config;
 35         struct blob_attr *config_data;
 36         bool has_macaddr;
 37         bool force_active;
 38         bool reset_primary;
 39         bool active;
 40 };
 41 
 42 struct bonding_port {
 43         struct vlist_node node;
 44         struct bonding_device *bdev;
 45         struct device_user dev;
 46         bool set_primary;
 47         bool present;
 48         bool active;
 49         char name[];
 50 };
 51 
 52 enum {
 53         BOND_ATTR_PORTS,
 54 
 55         BOND_ATTR_POLICY,
 56         BOND_ATTR_XMIT_HASH_POLICY,
 57         BOND_ATTR_ALL_PORTS_ACTIVE,
 58 
 59         BOND_ATTR_MIN_LINKS,
 60         BOND_ATTR_AD_ACTOR_SYSTEM,
 61         BOND_ATTR_AD_ACTOR_SYS_PRIO,
 62         BOND_ATTR_AD_SELECT,
 63         BOND_ATTR_LACP_RATE,
 64 
 65         BOND_ATTR_PACKETS_PER_PORT,
 66         BOND_ATTR_LP_INTERVAL,
 67         BOND_ATTR_DYNAMIC_LB,
 68         BOND_ATTR_RESEND_IGMP,
 69 
 70         BOND_ATTR_NUM_PEER_NOTIF,
 71         BOND_ATTR_PRIMARY,
 72         BOND_ATTR_PRIMARY_RESELECT,
 73         BOND_ATTR_FAILOVER_MAC,
 74 
 75         BOND_ATTR_MON_MODE,
 76         BOND_ATTR_MON_INTERVAL,
 77         BOND_ATTR_ARP_TARGET,
 78         BOND_ATTR_ARP_ALL_TARGETS,
 79         BOND_ATTR_ARP_VALIDATE,
 80         BOND_ATTR_USE_CARRIER,
 81         BOND_ATTR_UPDELAY,
 82         BOND_ATTR_DOWNDELAY,
 83 
 84         __BOND_ATTR_MAX,
 85 };
 86 
 87 static const struct blobmsg_policy bonding_attrs[__BOND_ATTR_MAX] = {
 88         [BOND_ATTR_PORTS] = { "ports", BLOBMSG_TYPE_ARRAY },
 89         [BOND_ATTR_POLICY] = { "policy", BLOBMSG_TYPE_STRING },
 90         [BOND_ATTR_XMIT_HASH_POLICY] = { "xmit_hash_policy", BLOBMSG_TYPE_STRING },
 91         [BOND_ATTR_ALL_PORTS_ACTIVE] = { "all_ports_active", BLOBMSG_TYPE_BOOL },
 92         [BOND_ATTR_MIN_LINKS] = { "min_links", BLOBMSG_TYPE_INT32 },
 93         [BOND_ATTR_AD_ACTOR_SYSTEM] = { "ad_actor_system", BLOBMSG_TYPE_STRING },
 94         [BOND_ATTR_AD_ACTOR_SYS_PRIO] = { "ad_actor_sys_prio", BLOBMSG_TYPE_INT32 },
 95         [BOND_ATTR_AD_SELECT] = { "ad_select", BLOBMSG_TYPE_STRING },
 96         [BOND_ATTR_LACP_RATE] = { "lacp_rate", BLOBMSG_TYPE_STRING },
 97         [BOND_ATTR_PACKETS_PER_PORT] = { "packets_per_port", BLOBMSG_TYPE_INT32 },
 98         [BOND_ATTR_LP_INTERVAL] = { "lp_interval", BLOBMSG_TYPE_INT32 },
 99         [BOND_ATTR_DYNAMIC_LB] = { "dynamic_lb", BLOBMSG_TYPE_BOOL },
100         [BOND_ATTR_RESEND_IGMP] = { "resend_igmp", BLOBMSG_TYPE_INT32 },
101         [BOND_ATTR_NUM_PEER_NOTIF] = { "num_peer_notif", BLOBMSG_TYPE_INT32 },
102         [BOND_ATTR_PRIMARY] = { "primary", BLOBMSG_TYPE_STRING },
103         [BOND_ATTR_PRIMARY_RESELECT] = { "primary_reselect", BLOBMSG_TYPE_STRING },
104         [BOND_ATTR_FAILOVER_MAC] = { "failover_mac", BLOBMSG_TYPE_STRING },
105         [BOND_ATTR_MON_MODE] = { "monitor_mode", BLOBMSG_TYPE_STRING },
106         [BOND_ATTR_MON_INTERVAL] = { "monitor_interval", BLOBMSG_TYPE_INT32 },
107         [BOND_ATTR_ARP_TARGET] = { "arp_target", BLOBMSG_TYPE_ARRAY },
108         [BOND_ATTR_ARP_ALL_TARGETS] = { "arp_all_targets", BLOBMSG_TYPE_BOOL },
109         [BOND_ATTR_ARP_VALIDATE] = { "arp_validate", BLOBMSG_TYPE_STRING },
110         [BOND_ATTR_USE_CARRIER] = { "use_carrier", BLOBMSG_TYPE_BOOL },
111         [BOND_ATTR_UPDELAY] = { "updelay", BLOBMSG_TYPE_INT32 },
112         [BOND_ATTR_DOWNDELAY] = { "downdelay", BLOBMSG_TYPE_INT32 },
113 };
114 
115 static const struct uci_blob_param_info bonding_attr_info[__BOND_ATTR_MAX] = {
116         [BOND_ATTR_PORTS] = { .type = BLOBMSG_TYPE_STRING },
117         [BOND_ATTR_ARP_TARGET] = { .type = BLOBMSG_TYPE_STRING },
118 };
119 
120 static const struct uci_blob_param_list bonding_attr_list = {
121         .n_params = __BOND_ATTR_MAX,
122         .params = bonding_attrs,
123         .info = bonding_attr_info,
124 
125         .n_next = 1,
126         .next = { &device_attr_list },
127 };
128 
129 static void
130 bonding_reset_primary(struct bonding_device *bdev)
131 {
132         struct bonding_port *bp;
133 
134         bdev->primary_port = NULL;
135         if (!bdev->has_macaddr)
136                 bdev->dev.settings.flags &= ~DEV_OPT_MACADDR;
137 
138         vlist_for_each_element(&bdev->ports, bp, node) {
139                 uint8_t *macaddr;
140 
141                 if (!bp->present)
142                         continue;
143 
144                 if (bdev->primary_port && !bp->set_primary)
145                         continue;
146 
147                 bdev->primary_port = bp;
148                 if (bdev->has_macaddr)
149                         continue;
150 
151                 if (bp->dev.dev->settings.flags & DEV_OPT_MACADDR)
152                         macaddr = bp->dev.dev->settings.macaddr;
153                 else
154                         macaddr = bp->dev.dev->orig_settings.macaddr;
155                 memcpy(bdev->dev.settings.macaddr, macaddr, 6);
156                 bdev->dev.settings.flags |= DEV_OPT_MACADDR;
157         }
158 }
159 
160 static int
161 bonding_disable_port(struct bonding_port *bp, bool keep_dev)
162 {
163         struct bonding_device *bdev = bp->bdev;
164 
165         if (!bp->present || !bp->active)
166                 return 0;
167 
168         bp->active = false;
169 
170         system_bonding_set_port(&bdev->dev, bp->dev.dev, false, bp->set_primary);
171         if (!keep_dev)
172                 device_release(&bp->dev);
173 
174         if (bp->dev.dev->settings.flags & DEV_OPT_IPV6) {
175                 bp->dev.dev->settings.ipv6 = 1;
176                 bp->dev.dev->settings.flags &= ~DEV_OPT_IPV6;
177         }
178 
179         return 0;
180 }
181 
182 static void
183 bonding_remove_port(struct bonding_port *bp)
184 {
185         struct bonding_device *bdev = bp->bdev;
186 
187         if (!bp->present)
188                 return;
189 
190         if (bdev->dev.active)
191                 bonding_disable_port(bp, false);
192 
193         bp->present = false;
194         bp->bdev->n_present--;
195 
196         if (bp == bdev->primary_port)
197                 bonding_reset_primary(bdev);
198 
199         bdev->force_active = false;
200         if (bdev->n_present == 0)
201                 device_set_present(&bdev->dev, false);
202 }
203 
204 static int
205 bonding_set_active(struct bonding_device *bdev, bool active)
206 {
207         int ret;
208 
209         if (bdev->active == active)
210                 return 0;
211 
212         ret = system_bonding_set_device(&bdev->dev, active ? &bdev->config : NULL);
213         if (ret < 0)
214                 return ret;
215 
216         bdev->active = active;
217         return 0;
218 }
219 
220 static int
221 bonding_enable_port(struct bonding_port *bp)
222 {
223         struct bonding_device *bdev = bp->bdev;
224         struct device *dev;
225         int ret;
226 
227         if (!bp->present)
228                 return 0;
229 
230         /* Disable IPv6 for bonding ports */
231         if (!(bp->dev.dev->settings.flags & DEV_OPT_IPV6)) {
232                 bp->dev.dev->settings.ipv6 = 0;
233                 bp->dev.dev->settings.flags |= DEV_OPT_IPV6;
234         }
235 
236         ret = device_claim(&bp->dev);
237         if (ret < 0)
238                 return ret;
239 
240         ret = bonding_set_active(bdev, true);
241         if (ret)
242                 goto release;
243 
244         dev = bp->dev.dev;
245         if (dev->settings.auth && !dev->auth_status)
246                 return -1;
247 
248         if (bp->active)
249                 return 0;
250 
251         ret = system_bonding_set_port(&bdev->dev, bp->dev.dev, true, bp->set_primary);
252         if (ret < 0) {
253                 D(DEVICE, "Bonding port %s could not be added", bp->dev.dev->ifname);
254                 goto error;
255         }
256 
257         bp->active = true;
258         device_set_present(&bdev->dev, true);
259 
260         return 0;
261 
262 error:
263         bdev->n_failed++;
264         bp->present = false;
265         bdev->n_present--;
266 release:
267         device_release(&bp->dev);
268 
269         return ret;
270 }
271 
272 static void
273 bonding_port_cb(struct device_user *dep, enum device_event ev)
274 {
275         struct bonding_port *bp = container_of(dep, struct bonding_port, dev);
276         struct bonding_device *bdev = bp->bdev;
277         struct device *dev = dep->dev;
278 
279         switch (ev) {
280         case DEV_EVENT_ADD:
281                 if (bp->present)
282                         break;
283 
284                 bp->present = true;
285                 bdev->n_present++;
286 
287                 if (bdev->n_present == 1)
288                         device_set_present(&bdev->dev, true);
289                 fallthrough;
290         case DEV_EVENT_AUTH_UP:
291                 if (!bdev->dev.active)
292                         break;
293 
294                 if (bonding_enable_port(bp))
295                         break;
296 
297                 /*
298                  * Adding a bonding port can overwrite the bonding device mtu
299                  * in the kernel, apply the bonding settings in case the
300                  * bonding device mtu is set
301                  */
302                 system_if_apply_settings(&bdev->dev, &bdev->dev.settings,
303                                          DEV_OPT_MTU | DEV_OPT_MTU6);
304                 break;
305         case DEV_EVENT_LINK_DOWN:
306                 if (!dev->settings.auth)
307                         break;
308 
309                 bonding_disable_port(bp, true);
310                 break;
311         case DEV_EVENT_REMOVE:
312                 if (dep->hotplug && !dev->sys_present) {
313                         vlist_delete(&bdev->ports, &bp->node);
314                         return;
315                 }
316 
317                 if (bp->present)
318                         bonding_remove_port(bp);
319 
320                 break;
321         default:
322                 return;
323         }
324 }
325 
326 static struct bonding_port *
327 bonding_create_port(struct bonding_device *bdev, const char *name,
328                     struct device *dev, bool hotplug)
329 {
330         struct bonding_port *bp;
331         struct bonding_config *cfg = &bdev->config;
332 
333         bp = calloc(1, sizeof(*bp) + strlen(name) + 1);
334         if (!bp)
335                 return NULL;
336 
337         bp->bdev = bdev;
338         bp->dev.cb = bonding_port_cb;
339         bp->dev.hotplug = hotplug;
340         strcpy(bp->name, name);
341         bp->dev.dev = dev;
342 
343         if (cfg->primary != NULL) {
344                 bp->set_primary = strcmp(cfg->primary, name) == 0;
345         }
346 
347         vlist_add(&bdev->ports, &bp->node, bp->name);
348         /*
349          * Need to look up the bonding port again as the above
350          * created pointer will be freed in case the bonding port
351          * already existed
352          */
353         if (!hotplug)
354                 return bp;
355 
356         bp = vlist_find(&bdev->ports, name, bp, node);
357         if (bp)
358                 bp->node.version = -1;
359 
360         return bp;
361 }
362 
363 static void
364 bonding_config_init(struct device *dev)
365 {
366         struct bonding_device *bdev;
367         struct blob_attr *cur;
368         size_t rem;
369 
370         bdev = container_of(dev, struct bonding_device, dev);
371 
372         bdev->n_failed = 0;
373 
374         vlist_update(&bdev->ports);
375         blobmsg_for_each_attr(cur, bdev->port_list, rem) {
376                 const char *name = blobmsg_get_string(cur);
377 
378                 dev = device_get(name, true);
379                 if (!dev)
380                         continue;
381 
382                 bonding_create_port(bdev, name, dev, false);
383         }
384         vlist_flush(&bdev->ports);
385 
386         if (bdev->reset_primary) {
387                 bonding_reset_primary(bdev);
388                 bdev->reset_primary = false;
389         }
390 
391         if (bdev->n_failed)
392                 uloop_timeout_set(&bdev->retry, 100);
393 }
394 
395 static void
396 bonding_apply_settings(struct bonding_device *bdev, struct blob_attr **tb)
397 {
398         struct bonding_config *cfg = &bdev->config;
399         struct blob_attr *cur;
400 
401         /* defaults */
402         memset(cfg, 0, sizeof(*cfg));
403         cfg->resend_igmp = 1;
404         cfg->ad_actor_sys_prio = 65535;
405         cfg->lp_interval = 1;
406         cfg->num_peer_notif = 1;
407 
408 #define cfg_item(_type, _field, _attr)                          \
409         do {                                                    \
410                 if ((cur = tb[BOND_ATTR_##_attr]) != NULL)      \
411                         cfg->_field = blobmsg_get_##_type(cur); \
412         } while (0)
413 
414         if ((cur = tb[BOND_ATTR_POLICY]) != NULL) {
415                 const char *policy = blobmsg_get_string(cur);
416                 size_t i;
417 
418                 for (i = 0; i < ARRAY_SIZE(bonding_policy_str); i++) {
419                         if (strcmp(policy, bonding_policy_str[i]) != 0)
420                                 continue;
421 
422                         cfg->policy = i;
423                         break;
424                 }
425         }
426 
427         cfg_item(string, xmit_hash_policy, XMIT_HASH_POLICY);
428         cfg_item(bool, all_ports_active, ALL_PORTS_ACTIVE);
429         cfg_item(u32, min_links, MIN_LINKS);
430         cfg_item(string, ad_actor_system, AD_ACTOR_SYSTEM);
431         cfg_item(u32, ad_actor_sys_prio, AD_ACTOR_SYS_PRIO);
432         cfg_item(string, ad_select, AD_SELECT);
433         cfg_item(string, lacp_rate, LACP_RATE);
434         cfg_item(u32, packets_per_port, PACKETS_PER_PORT);
435         cfg_item(u32, lp_interval, LP_INTERVAL);
436         cfg_item(bool, dynamic_lb, DYNAMIC_LB);
437         cfg_item(u32, resend_igmp, RESEND_IGMP);
438         cfg_item(u32, num_peer_notif, NUM_PEER_NOTIF);
439         cfg_item(string, primary, PRIMARY);
440         cfg_item(string, primary_reselect, PRIMARY_RESELECT);
441         cfg_item(string, failover_mac, FAILOVER_MAC);
442         cfg_item(u32, monitor_interval, MON_INTERVAL);
443         cfg_item(bool, arp_all_targets, ARP_ALL_TARGETS);
444         cfg_item(string, arp_validate, ARP_VALIDATE);
445         cfg_item(bool, use_carrier, USE_CARRIER);
446         cfg_item(u32, updelay, UPDELAY);
447         cfg_item(u32, downdelay, DOWNDELAY);
448 
449         if ((cur = tb[BOND_ATTR_MON_MODE]) != NULL &&
450             !strcmp(blobmsg_get_string(cur), "arp"))
451                 cfg->monitor_arp = true;
452         cfg->arp_target = tb[BOND_ATTR_ARP_TARGET];
453 #undef cfg_item
454 }
455 
456 static enum dev_change_type
457 bonding_reload(struct device *dev, struct blob_attr *attr)
458 {
459         struct blob_attr *tb_dev[__DEV_ATTR_MAX];
460         struct blob_attr *tb_b[__BOND_ATTR_MAX];
461         enum dev_change_type ret = DEV_CONFIG_APPLIED;
462         unsigned long diff[2] = {};
463         struct bonding_device *bdev;
464 
465         BUILD_BUG_ON(sizeof(diff[0]) < __BOND_ATTR_MAX / 8);
466         BUILD_BUG_ON(sizeof(diff) < __DEV_ATTR_MAX / 8);
467 
468         bdev = container_of(dev, struct bonding_device, dev);
469         attr = blob_memdup(attr);
470 
471         blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
472                 blob_data(attr), blob_len(attr));
473         blobmsg_parse(bonding_attrs, __BOND_ATTR_MAX, tb_b,
474                 blob_data(attr), blob_len(attr));
475 
476         bdev->has_macaddr = tb_dev[DEV_ATTR_MACADDR];
477         if (bdev->primary_port && !bdev->primary_port->set_primary &&
478             tb_dev[DEV_ATTR_MACADDR])
479                 bdev->primary_port = NULL;
480 
481         bdev->port_list = tb_b[BOND_ATTR_PORTS];
482         device_init_settings(dev, tb_dev);
483         bonding_apply_settings(bdev, tb_b);
484 
485         if (bdev->config_data) {
486                 struct blob_attr *otb_dev[__DEV_ATTR_MAX];
487                 struct blob_attr *otb_b[__BOND_ATTR_MAX];
488 
489                 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev,
490                         blob_data(bdev->config_data), blob_len(bdev->config_data));
491 
492                 uci_blob_diff(tb_dev, otb_dev, &device_attr_list, diff);
493                 if (diff[0] | diff[1])
494                     ret = DEV_CONFIG_RESTART;
495 
496                 blobmsg_parse(bonding_attrs, __BOND_ATTR_MAX, otb_b,
497                         blob_data(bdev->config_data), blob_len(bdev->config_data));
498 
499                 diff[0] = 0;
500                 uci_blob_diff(tb_b, otb_b, &bonding_attr_list, diff);
501                 if (diff[0] & ~(1 << BOND_ATTR_PORTS))
502                     ret = DEV_CONFIG_RESTART;
503 
504                 bonding_config_init(dev);
505         }
506 
507         free(bdev->config_data);
508         bdev->config_data = attr;
509 
510         return ret;
511 }
512 
513 static int
514 bonding_hotplug_add(struct device *dev, struct device *port, struct blob_attr *vlan)
515 {
516         struct bonding_device *bdev = container_of(dev, struct bonding_device, dev);
517         struct bonding_port *bp;
518 
519         bp = vlist_find(&bdev->ports, port->ifname, bp, node);
520         if (!bp)
521                 bonding_create_port(bdev, port->ifname, port, true);
522 
523         return 0;
524 }
525 
526 static int
527 bonding_hotplug_del(struct device *dev, struct device *port, struct blob_attr *vlan)
528 {
529         struct bonding_device *bdev = container_of(dev, struct bonding_device, dev);
530         struct bonding_port *bp;
531 
532         bp = vlist_find(&bdev->ports, port->ifname, bp, node);
533         if (!bp)
534                 return UBUS_STATUS_NOT_FOUND;
535 
536         if (bp->dev.hotplug)
537                 vlist_delete(&bdev->ports, &bp->node);
538 
539         return 0;
540 }
541 
542 static int
543 bonding_hotplug_prepare(struct device *dev, struct device **bonding_dev)
544 {
545         struct bonding_device *bdev;
546 
547         if (bonding_dev)
548                 *bonding_dev = dev;
549 
550         bdev = container_of(dev, struct bonding_device, dev);
551         bdev->force_active = true;
552         device_set_present(&bdev->dev, true);
553 
554         return 0;
555 }
556 
557 static void
558 bonding_retry_ports(struct uloop_timeout *timeout)
559 {
560         struct bonding_device *bdev = container_of(timeout, struct bonding_device, retry);
561         struct bonding_port *bp;
562 
563         bdev->n_failed = 0;
564         vlist_for_each_element(&bdev->ports, bp, node) {
565                 if (bp->present)
566                         continue;
567 
568                 if (!bp->dev.dev->present)
569                         continue;
570 
571                 bp->present = true;
572                 bdev->n_present++;
573                 bonding_enable_port(bp);
574         }
575 }
576 
577 
578 static void
579 bonding_free_port(struct bonding_port *bp)
580 {
581         struct device *dev = bp->dev.dev;
582 
583         bonding_remove_port(bp);
584 
585         device_remove_user(&bp->dev);
586 
587         /*
588          * When reloading the config and moving a device from one master to
589          * another, the other master may have tried to claim this device
590          * before it was removed here.
591          * Ensure that claiming the device is retried by toggling its present
592          * state
593          */
594         if (dev->present) {
595                 device_set_present(dev, false);
596                 device_set_present(dev, true);
597         }
598 
599         free(bp);
600 }
601 
602 static void
603 bonding_port_update(struct vlist_tree *tree, struct vlist_node *node_new,
604                      struct vlist_node *node_old)
605 {
606         struct bonding_port *bp;
607         struct device *dev;
608         struct bonding_device *bdev = container_of(tree, struct bonding_device, ports);
609 
610         if (node_new) {
611                 bp = container_of(node_new, struct bonding_port, node);
612 
613                 if (node_old) {
614                         struct bonding_port *bp_old;
615 
616                         bp_old = container_of(node_old, struct bonding_port, node);
617                         if (bp_old->set_primary != bp->set_primary) {
618                                 bp_old->set_primary = bp->set_primary;
619                                 bdev->reset_primary = true;
620                         }
621 
622                         free(bp);
623                         return;
624                 }
625 
626                 dev = bp->dev.dev;
627                 bp->dev.dev = NULL;
628                 device_add_user(&bp->dev, dev);
629         }
630 
631 
632         if (node_old) {
633                 bp = container_of(node_old, struct bonding_port, node);
634                 bonding_free_port(bp);
635         }
636 }
637 
638 static int
639 bonding_set_down(struct bonding_device *bdev)
640 {
641         struct bonding_port *bp;
642 
643         bdev->set_state(&bdev->dev, false);
644 
645         vlist_for_each_element(&bdev->ports, bp, node)
646                 bonding_disable_port(bp, false);
647 
648         bonding_set_active(bdev, false);
649 
650         return 0;
651 }
652 
653 static int
654 bonding_set_up(struct bonding_device *bdev)
655 {
656         struct bonding_port *bp;
657         int ret;
658 
659         if (!bdev->n_present) {
660                 if (!bdev->force_active)
661                         return -ENOENT;
662 
663                 ret = bonding_set_active(bdev, true);
664                 if (ret)
665                         return ret;
666         }
667 
668         bdev->n_failed = 0;
669         vlist_for_each_element(&bdev->ports, bp, node)
670                 bonding_enable_port(bp);
671         if (bdev->n_failed)
672                 uloop_timeout_set(&bdev->retry, 100);
673 
674         if (!bdev->force_active && !bdev->n_present) {
675                 /* initialization of all port interfaces failed */
676                 bonding_set_active(bdev, false);
677                 device_set_present(&bdev->dev, false);
678                 return -ENOENT;
679         }
680 
681         bonding_reset_primary(bdev);
682         ret = bdev->set_state(&bdev->dev, true);
683         if (ret < 0)
684                 bonding_set_down(bdev);
685 
686         return ret;
687 }
688 
689 static int
690 bonding_set_state(struct device *dev, bool up)
691 {
692         struct bonding_device *bdev;
693 
694         bdev = container_of(dev, struct bonding_device, dev);
695 
696         if (up)
697                 return bonding_set_up(bdev);
698         else
699                 return bonding_set_down(bdev);
700 }
701 
702 static struct device *
703 bonding_create(const char *name, struct device_type *devtype,
704         struct blob_attr *attr)
705 {
706         static const struct device_hotplug_ops bonding_ops = {
707                 .prepare = bonding_hotplug_prepare,
708                 .add = bonding_hotplug_add,
709                 .del = bonding_hotplug_del
710         };
711         struct bonding_device *bdev;
712         struct device *dev = NULL;
713 
714         bdev = calloc(1, sizeof(*bdev));
715         if (!bdev)
716                 return NULL;
717 
718         dev = &bdev->dev;
719 
720         if (device_init(dev, devtype, name) < 0) {
721                 device_cleanup(dev);
722                 free(bdev);
723                 return NULL;
724         }
725 
726         dev->config_pending = true;
727         bdev->retry.cb = bonding_retry_ports;
728 
729         bdev->set_state = dev->set_state;
730         dev->set_state = bonding_set_state;
731 
732         dev->hotplug_ops = &bonding_ops;
733 
734         vlist_init(&bdev->ports, avl_strcmp, bonding_port_update);
735         bdev->ports.keep_old = true;
736 
737         bonding_reload(dev, attr);
738 
739         return dev;
740 }
741 
742 static void
743 bonding_free(struct device *dev)
744 {
745         struct bonding_device *bdev;
746 
747         bdev = container_of(dev, struct bonding_device, dev);
748         vlist_flush_all(&bdev->ports);
749         free(bdev->config_data);
750         free(bdev);
751 }
752 
753 static struct device_type bonding_device_type = {
754         .name = "bonding",
755         .config_params = &bonding_attr_list,
756 
757         .bridge_capability = true,
758 
759         .create = bonding_create,
760         .config_init = bonding_config_init,
761         .reload = bonding_reload,
762         .free = bonding_free,
763 };
764 
765 static void __init bonding_device_type_init(void)
766 {
767         device_type_add(&bonding_device_type);
768 }
769 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt