bonding.c 17 KB

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