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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt