1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00
openmptcprouter-feeds/netifd/patches/010-add-link-aggregation-support.patch
2022-04-06 20:55:49 +08:00

865 lines
24 KiB
Diff

diff -Nur a/bonding.c netifd-2019-08-05-5e02f944/bonding.c
--- a/bonding.c 1969-12-31 16:00:00.000000000 -0800
+++ netifd-2019-08-05-5e02f944/bonding.c 2020-05-01 16:08:30.225672306 -0700
@@ -0,0 +1,547 @@
+/*
+ * netifd - network interface daemon
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "netifd.h"
+#include "device.h"
+#include "interface.h"
+#include "system.h"
+
+enum {
+ BONDING_ATTR_IFNAME,
+ BONDING_ATTR_SLAVES,
+ BONDING_ATTR_MODE,
+ BONDING_ATTR_XMITHASHPOL,
+ __BONDING_ATTR_MAX
+};
+
+static const struct blobmsg_policy bonding_attrs[__BONDING_ATTR_MAX] = {
+ [BONDING_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_STRING },
+ [BONDING_ATTR_SLAVES] = { "slaves", BLOBMSG_TYPE_ARRAY },
+ [BONDING_ATTR_MODE] = { "mode", BLOBMSG_TYPE_INT32 },
+ [BONDING_ATTR_XMITHASHPOL] = { "xmit_hash_policy", BLOBMSG_TYPE_STRING },
+};
+
+static const struct uci_blob_param_info bonding_attr_info[__BONDING_ATTR_MAX] = {
+ [BONDING_ATTR_SLAVES] = { .type = BLOBMSG_TYPE_STRING },
+};
+
+static const struct uci_blob_param_list bonding_attr_list = {
+ .n_params = __BONDING_ATTR_MAX,
+ .params = bonding_attrs,
+ .info = bonding_attr_info,
+
+ .n_next = 1,
+ .next = { &device_attr_list },
+};
+
+static struct device *bonding_create(const char *name, struct device_type *devtype, struct blob_attr *attr);
+static void bonding_config_init(struct device *dev);
+static void bonding_free(struct device *dev);
+static void bonding_dump_info(struct device *dev, struct blob_buf *b);
+enum dev_change_type
+bonding_reload(struct device *dev, struct blob_attr *attr);
+
+struct device_type bonding_device_type = {
+ .name = "Bonding",
+ .config_params = &bonding_attr_list,
+
+ .create = bonding_create,
+ .config_init = bonding_config_init,
+ .reload = bonding_reload,
+ .free = bonding_free,
+ .dump_info = bonding_dump_info,
+};
+
+struct bonding_state {
+ struct device dev;
+ device_state_cb set_state;
+
+ struct blob_attr *config_data;
+ struct bonding_config config;
+ struct blob_attr *ifnames;
+ bool active;
+ bool force_active;
+
+ struct bonding_member *primary_port;
+ struct vlist_tree members;
+ int n_present;
+};
+
+struct bonding_member {
+ struct vlist_node node;
+ struct bonding_state *bst;
+ struct device_user dev;
+ bool present;
+ char name[];
+};
+
+static void
+bonding_reset_primary(struct bonding_state *bst)
+{
+ struct bonding_member *bm;
+
+ if (!bst->primary_port &&
+ (bst->dev.settings.flags & DEV_OPT_MACADDR))
+ return;
+
+ bst->primary_port = NULL;
+ bst->dev.settings.flags &= ~DEV_OPT_MACADDR;
+ vlist_for_each_element(&bst->members, bm, node) {
+ uint8_t *macaddr;
+
+ if (!bm->present)
+ continue;
+
+ bst->primary_port = bm;
+ if (bm->dev.dev->settings.flags & DEV_OPT_MACADDR)
+ macaddr = bm->dev.dev->settings.macaddr;
+ else
+ macaddr = bm->dev.dev->orig_settings.macaddr;
+ memcpy(bst->dev.settings.macaddr, macaddr, 6);
+ bst->dev.settings.flags |= DEV_OPT_MACADDR;
+ return;
+ }
+}
+
+static int
+bonding_disable_member(struct bonding_member *bm)
+{
+ struct bonding_state *bst = bm->bst;
+
+ if (!bm->present)
+ return 0;
+
+ system_bonding_delif(&bst->dev, bm->dev.dev);
+ device_release(&bm->dev);
+
+ return 0;
+}
+
+static int
+bonding_enable_member(struct bonding_member *bm)
+{
+ struct bonding_state *bst = bm->bst;
+ int ret;
+
+ if (!bm->present)
+ return 0;
+
+ ret = device_claim(&bm->dev);
+ if (ret < 0)
+ goto error;
+
+ ret = system_bonding_addif(&bst->dev, bm->dev.dev);
+ if (ret < 0) {
+ D(DEVICE, "Bridge device %s could not be added\n", bm->dev.dev->ifname);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ bm->present = false;
+ bst->n_present--;
+ return ret;
+}
+
+static void
+bonding_remove_member(struct bonding_member *bm)
+{
+ struct bonding_state *bst = bm->bst;
+
+ if (!bm->present)
+ return;
+
+ if (bm == bst->primary_port)
+ bonding_reset_primary(bst);
+
+ if (bst->dev.active)
+ bonding_disable_member(bm);
+
+ bm->present = false;
+ bm->bst->n_present--;
+
+ bst->force_active = false;
+ if (bst->n_present == 0)
+ device_set_present(&bst->dev, false);
+}
+
+static void
+bonding_free_member(struct bonding_member *bm)
+{
+ struct device *dev = bm->dev.dev;
+
+ bonding_remove_member(bm);
+ device_remove_user(&bm->dev);
+
+ /*
+ * When reloading the config and moving a device from one bonding to
+ * another, the other bonding may have tried to claim this device
+ * before it was removed here.
+ * Ensure that claiming the device is retried by toggling its present
+ * state
+ */
+ if (dev->present) {
+ device_set_present(dev, false);
+ device_set_present(dev, true);
+ }
+
+ free(bm);
+}
+
+static void
+bonding_member_cb(struct device_user *dev, enum device_event ev)
+{
+ struct bonding_member *bm = container_of(dev, struct bonding_member, dev);
+ struct bonding_state *bst = bm->bst;
+
+ switch (ev) {
+ case DEV_EVENT_ADD:
+ assert(!bm->present);
+
+ bm->present = true;
+ bst->n_present++;
+
+ if (bst->dev.active)
+ bonding_enable_member(bm);
+ else if (bst->n_present == 1)
+ device_set_present(&bst->dev, true);
+
+ break;
+ case DEV_EVENT_REMOVE:
+ if (dev->hotplug) {
+ vlist_delete(&bst->members, &bm->node);
+ return;
+ }
+
+ if (bm->present)
+ bonding_remove_member(bm);
+
+ break;
+ default:
+ return;
+ }
+}
+
+static int
+bonding_set_down(struct bonding_state *bst)
+{
+ struct bonding_member *bm;
+
+ bst->set_state(&bst->dev, false);
+
+ vlist_for_each_element(&bst->members, bm, node)
+ bonding_disable_member(bm);
+
+ system_bonding_delbonding(&bst->dev);
+
+ return 0;
+}
+
+static int
+bonding_set_up(struct bonding_state *bst)
+{
+ struct bonding_member *bm;
+ int ret;
+
+ if (!bst->force_active && !bst->n_present)
+ return -ENOENT;
+
+ ret = system_bonding_addbonding(&bst->dev, &bst->config);
+ if (ret < 0)
+ goto out;
+
+ vlist_for_each_element(&bst->members, bm, node)
+ bonding_enable_member(bm);
+
+ if (!bst->force_active && !bst->n_present) {
+ /* initialization of all member interfaces failed */
+ system_bonding_delbonding(&bst->dev);
+ device_set_present(&bst->dev, false);
+ return -ENOENT;
+ }
+
+ bonding_reset_primary(bst);
+ ret = bst->set_state(&bst->dev, true);
+ if (ret < 0)
+ bonding_set_down(bst);
+
+out:
+ return ret;
+}
+
+static int
+bonding_set_state(struct device *dev, bool up)
+{
+ struct bonding_state *bst;
+
+ bst = container_of(dev, struct bonding_state, dev);
+
+ if (up)
+ return bonding_set_up(bst);
+ else
+ return bonding_set_down(bst);
+}
+
+static struct bonding_member *
+bonding_create_member(struct bonding_state *bst, struct device *dev, bool hotplug)
+{
+ struct bonding_member *bm;
+
+ bm = calloc(1, sizeof(*bm) + strlen(dev->ifname) + 1);
+ bm->bst = bst;
+ bm->dev.cb = bonding_member_cb;
+ bm->dev.hotplug = hotplug;
+ strcpy(bm->name, dev->ifname);
+ bm->dev.dev = dev;
+ vlist_add(&bst->members, &bm->node, bm->name);
+ if (hotplug)
+ bm->node.version = -1;
+
+ return bm;
+}
+
+static void
+bonding_member_update(struct vlist_tree *tree, struct vlist_node *node_new,
+ struct vlist_node *node_old)
+{
+ struct bonding_member *bm;
+ struct device *dev;
+
+ if (node_new) {
+ bm = container_of(node_new, struct bonding_member, node);
+
+ if (node_old) {
+ free(bm);
+ return;
+ }
+
+ dev = bm->dev.dev;
+ bm->dev.dev = NULL;
+ device_add_user(&bm->dev, dev);
+ }
+
+
+ if (node_old) {
+ bm = container_of(node_old, struct bonding_member, node);
+ bonding_free_member(bm);
+ }
+}
+
+
+static void
+bonding_add_member(struct bonding_state *bst, const char *name)
+{
+ struct device *dev;
+
+ dev = device_get(name, true);
+ if (!dev)
+ return;
+
+ bonding_create_member(bst, dev, false);
+}
+
+static int
+bonding_hotplug_add(struct device *dev, struct device *member)
+{
+ struct bonding_state *bst = container_of(dev, struct bonding_state, dev);
+
+ bonding_create_member(bst, member, true);
+
+ return 0;
+}
+
+static int
+bonding_hotplug_del(struct device *dev, struct device *member)
+{
+ struct bonding_state *bst = container_of(dev, struct bonding_state, dev);
+ struct bonding_member *bm;
+
+ bm = vlist_find(&bst->members, member->ifname, bm, node);
+ if (!bm)
+ return UBUS_STATUS_NOT_FOUND;
+
+ vlist_delete(&bst->members, &bm->node);
+ return 0;
+}
+
+static int
+bonding_hotplug_prepare(struct device *dev)
+{
+ struct bonding_state *bst;
+
+ bst = container_of(dev, struct bonding_state, dev);
+ bst->force_active = true;
+ device_set_present(&bst->dev, true);
+
+ return 0;
+}
+
+static const struct device_hotplug_ops bonding_ops = {
+ .prepare = bonding_hotplug_prepare,
+ .add = bonding_hotplug_add,
+ .del = bonding_hotplug_del
+};
+
+static void
+bonding_free(struct device *dev)
+{
+ struct bonding_state *bst;
+
+ bst = container_of(dev, struct bonding_state, dev);
+ vlist_flush_all(&bst->members);
+ free(bst);
+}
+
+static void
+bonding_dump_info(struct device *dev, struct blob_buf *b)
+{
+ struct bonding_state *bst;
+ struct bonding_member *bm;
+ void *list;
+
+ bst = container_of(dev, struct bonding_state, dev);
+
+ system_if_dump_info(dev, b);
+ list = blobmsg_open_array(b, "bonding-members");
+
+ vlist_for_each_element(&bst->members, bm, node)
+ blobmsg_add_string(b, NULL, bm->dev.dev->ifname);
+
+ blobmsg_close_array(b, list);
+}
+
+static void
+bonding_config_init(struct device *dev)
+{
+ struct bonding_state *bst;
+ struct blob_attr *cur;
+ int rem;
+
+ bst = container_of(dev, struct bonding_state, dev);
+
+ if (!bst->ifnames)
+ return;
+
+ vlist_update(&bst->members);
+ blobmsg_for_each_attr(cur, bst->ifnames, rem) {
+ bonding_add_member(bst, blobmsg_data(cur));
+ }
+ vlist_flush(&bst->members);
+}
+
+static void
+bonding_apply_settings(struct bonding_state *bst, struct blob_attr **tb)
+{
+ struct bonding_config *cfg = &bst->config;
+ struct blob_attr *cur;
+
+ /* defaults */
+ cfg->mode = 0;
+
+ if ((cur = tb[BONDING_ATTR_MODE]))
+ cfg->mode = blobmsg_get_u32(cur);
+
+ if ((cur = tb[BONDING_ATTR_XMITHASHPOL])) {
+ memcpy(&cfg->xmit_hash_policy, blobmsg_get_string(cur),
+ sizeof(cfg->xmit_hash_policy));
+ }
+}
+
+enum dev_change_type
+bonding_reload(struct device *dev, struct blob_attr *attr)
+{
+ struct blob_attr *tb_dev[__DEV_ATTR_MAX];
+ struct blob_attr *tb_br[__BONDING_ATTR_MAX];
+ enum dev_change_type ret = DEV_CONFIG_APPLIED;
+ unsigned long diff;
+ struct bonding_state *bst;
+
+ BUILD_BUG_ON(sizeof(diff) < __BONDING_ATTR_MAX / 8);
+ BUILD_BUG_ON(sizeof(diff) < __DEV_ATTR_MAX / 8);
+
+ bst = container_of(dev, struct bonding_state, dev);
+
+ blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
+ blob_data(attr), blob_len(attr));
+ blobmsg_parse(bonding_attrs, __BONDING_ATTR_MAX, tb_br,
+ blob_data(attr), blob_len(attr));
+
+ bst->ifnames = tb_br[BONDING_ATTR_SLAVES];
+ device_init_settings(dev, tb_dev);
+ bonding_apply_settings(bst, tb_br);
+
+ if (bst->config_data) {
+ struct blob_attr *otb_dev[__DEV_ATTR_MAX];
+ struct blob_attr *otb_br[__BONDING_ATTR_MAX];
+
+ blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev,
+ blob_data(bst->config_data), blob_len(bst->config_data));
+
+ diff = 0;
+ uci_blob_diff(tb_dev, otb_dev, &device_attr_list, &diff);
+ if (diff)
+ ret = DEV_CONFIG_RESTART;
+
+ blobmsg_parse(bonding_attrs, __BONDING_ATTR_MAX, otb_br,
+ blob_data(bst->config_data), blob_len(bst->config_data));
+
+ diff = 0;
+ uci_blob_diff(tb_br, otb_br, &bonding_attr_list, &diff);
+ if (diff & ~(1 << BONDING_ATTR_IFNAME))
+ ret = DEV_CONFIG_RESTART;
+
+ bonding_config_init(dev);
+ }
+
+ bst->config_data = attr;
+ return ret;
+}
+
+static struct device *
+bonding_create(const char *name, struct device_type *devtype, struct blob_attr *attr)
+{
+ struct bonding_state *bst;
+ struct device *dev = NULL;
+
+ bst = calloc(1, sizeof(*bst));
+ if (!bst)
+ return NULL;
+
+ dev = &bst->dev;
+ device_init(dev, &bonding_device_type, name);
+ dev->config_pending = true;
+
+ bst->set_state = dev->set_state;
+ dev->set_state = bonding_set_state;
+
+ dev->hotplug_ops = &bonding_ops;
+
+ vlist_init(&bst->members, avl_strcmp, bonding_member_update);
+ bst->members.keep_old = true;
+ bonding_reload(dev, attr);
+
+ return dev;
+}
+
+static void __init bonding_device_type_init(void)
+{
+ device_type_add(&bonding_device_type);
+}
diff -Nur a/CMakeLists.txt netifd-2019-08-05-5e02f944/CMakeLists.txt
--- a/CMakeLists.txt 2020-05-01 16:08:04.229808359 -0700
+++ netifd-2019-08-05-5e02f944/CMakeLists.txt 2020-05-01 16:08:23.473707648 -0700
@@ -19,7 +19,7 @@
main.c utils.c system.c tunnel.c handler.c
interface.c interface-ip.c interface-event.c
iprule.c proto.c proto-static.c proto-shell.c
- config.c device.c bridge.c veth.c vlan.c alias.c
+ config.c device.c bridge.c bonding.c veth.c vlan.c alias.c
macvlan.c ubus.c vlandev.c wireless.c)
diff -Nur a/config.c netifd-2019-08-05-5e02f944/config.c
--- a/config.c 2020-05-01 16:08:04.229808359 -0700
+++ netifd-2019-08-05-5e02f944/config.c 2020-05-01 16:08:23.473707648 -0700
@@ -72,13 +72,32 @@
return 0;
}
+static int
+config_parse_bonding_interface(struct uci_section *s)
+{
+ const char *name = uci_lookup_option_string(uci_ctx, s, "ifname");
+ if(!name)
+ {
+ D(INTERFACE, "no ifname specificed for bonding interface");
+ return -EINVAL;
+ }
+
+ uci_to_blob(&b, s, bonding_device_type.config_params);
+ if (!device_create(name, &bonding_device_type, b.head)) {
+ D(INTERFACE, "Failed to create bonding for interface '%s'\n", s->e.name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void
config_parse_interface(struct uci_section *s, bool alias)
{
struct interface *iface;
const char *type = NULL, *disabled;
struct blob_attr *config;
- bool bridge = false;
+ bool is_simple_device = true;
struct device_type *devtype = NULL;
disabled = uci_lookup_option_string(uci_ctx, s, "disabled");
@@ -97,7 +116,13 @@
if (config_parse_bridge_interface(s, devtype))
return;
- bridge = true;
+ is_simple_device = false;
+ }
+ else if (type && !strcmp(type, "bonding")) {
+ if (config_parse_bonding_interface(s))
+ return;
+
+ is_simple_device = false;
}
uci_to_blob(&b, s, &interface_attr_list);
@@ -109,7 +134,7 @@
if (iface->proto_handler && iface->proto_handler->config_params)
uci_to_blob(&b, s, iface->proto_handler->config_params);
- if (!bridge && uci_to_blob(&b, s, simple_device_type.config_params))
+ if (is_simple_device && uci_to_blob(&b, s, simple_device_type.config_params))
iface->device_config = true;
config = blob_memdup(b.head);
diff -Nur a/device.h netifd-2019-08-05-5e02f944/device.h
--- a/device.h 2020-05-01 16:08:04.229808359 -0700
+++ netifd-2019-08-05-5e02f944/device.h 2020-05-01 16:08:23.473707648 -0700
@@ -231,6 +231,7 @@
extern const struct uci_blob_param_list device_attr_list;
extern struct device_type simple_device_type;
extern struct device_type tunnel_device_type;
+extern struct device_type bonding_device_type;
void device_lock(void);
void device_unlock(void);
diff -Nur a/interface.c netifd-2019-08-05-5e02f944/interface.c
--- a/interface.c 2020-05-01 16:08:04.233808340 -0700
+++ netifd-2019-08-05-5e02f944/interface.c 2020-05-01 16:08:23.473707648 -0700
@@ -1241,6 +1241,7 @@
if_old->device_config = if_new->device_config;
if_old->config_autostart = if_new->config_autostart;
+ if_old->autostart = if_old->config_autostart;
if_old->ifname = if_new->ifname;
if_old->parent_ifname = if_new->parent_ifname;
if_old->dynamic = if_new->dynamic;
diff -Nur a/system-dummy.c netifd-2019-08-05-5e02f944/system-dummy.c
--- a/system-dummy.c 2020-05-01 16:08:04.233808340 -0700
+++ netifd-2019-08-05-5e02f944/system-dummy.c 2020-05-01 16:08:23.473707648 -0700
@@ -54,6 +54,30 @@
return 0;
}
+int system_bonding_addbonding(struct device *bonding, struct bridge_config *cfg)
+{
+ D(SYSTEM, "bonding addbonding %s\n", bonding->ifname);
+ return 0;
+}
+
+int system_bonding_delbonding(struct device *bonding)
+{
+ D(SYSTEM, "bonding delbonding %s\n", bonding->ifname);
+ return 0;
+}
+
+int system_bonding_addif(struct device *bonding, struct device *dev)
+{
+ D(SYSTEM, "bonding addif %s %s\n", bonding->ifname, dev->ifname);
+ return 0;
+}
+
+int system_bonding_delif(struct device *bonding, struct device *dev)
+{
+ D(SYSTEM, "bonding delif %s %s\n", bonding->ifname, dev->ifname);
+ return 0;
+}
+
int system_vlan_add(struct device *dev, int id)
{
D(SYSTEM, "vconfig add %s %d\n", dev->ifname, id);
diff -Nur a/system.h netifd-2019-08-05-5e02f944/system.h
--- a/system.h 2020-05-01 16:08:04.233808340 -0700
+++ netifd-2019-08-05-5e02f944/system.h 2020-05-01 16:08:23.473707648 -0700
@@ -128,6 +128,11 @@
int hash_max;
};
+struct bonding_config {
+ int mode;
+ char xmit_hash_policy[16];
+};
+
enum macvlan_opt {
MACVLAN_OPT_MACADDR = (1 << 0),
};
@@ -186,6 +191,11 @@
int system_bridge_addif(struct device *bridge, struct device *dev);
int system_bridge_delif(struct device *bridge, struct device *dev);
+int system_bonding_addbonding(struct device *bonding, struct bonding_config *cfg);
+int system_bonding_delbonding(struct device *bonding);
+int system_bonding_addif(struct device *bonding, struct device *dev);
+int system_bonding_delif(struct device *bonding, struct device *dev);
+
int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg);
int system_macvlan_del(struct device *macvlan);
diff -Nur a/system-linux.c netifd-2019-08-05-5e02f944/system-linux.c
--- a/system-linux.c 2020-05-01 16:08:04.233808340 -0700
+++ netifd-2019-08-05-5e02f944/system-linux.c 2020-05-01 16:08:23.477707628 -0700
@@ -731,6 +731,15 @@
return ioctl(sock_ioctl, SIOCBRDELBR, bridge->ifname);
}
+int system_bonding_delbonding(struct device *bonding)
+{
+ char cmd[32];
+ snprintf(cmd, sizeof(cmd), "-%s", bonding->ifname);
+ system_set_sysctl("/sys/class/net/bonding_masters", cmd);
+
+ return 0;
+}
+
static int system_bridge_if(const char *bridge, struct device *dev, int cmd, void *data)
{
struct ifreq ifr;
@@ -744,6 +753,17 @@
return ioctl(sock_ioctl, cmd, &ifr);
}
+static bool system_is_bonding(const char *name, char *buf, int buflen)
+{
+ struct stat st;
+
+ snprintf(buf, buflen, "/sys/devices/virtual/net/%s/bonding", name);
+ if (stat(buf, &st) < 0)
+ return false;
+
+ return true;
+}
+
static bool system_is_bridge(const char *name, char *buf, int buflen)
{
struct stat st;
@@ -781,6 +801,34 @@
return path + 1;
}
+static struct device *system_get_bonding(const char *name, char *buf, int buflen)
+{
+ char path[64], *devname;
+ int ifindex, len;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/sys/class/net/%s/master/ifindex", name);
+ f = fopen(path, "r");
+ if (!f)
+ return NULL;
+
+ len = fread(buf, 1, buflen - 1, f);
+ fclose(f);
+
+ if (len <= 0)
+ return NULL;
+
+ buf[len] = 0;
+ ifindex = strtoul(buf, NULL, 0);
+
+ devname = if_indextoname(ifindex, buf);
+
+ if (!devname)
+ return NULL;
+
+ return device_get(devname, false);
+}
+
static void
system_bridge_set_wireless(struct device *bridge, struct device *dev)
{
@@ -835,6 +883,28 @@
return ret;
}
+int system_bonding_addif(struct device *bonding, struct device *dev)
+{
+ char cmd[32];
+
+ system_if_down(dev);
+ snprintf(cmd, sizeof(cmd), "+%s", dev->ifname);
+ system_set_dev_sysctl("/sys/class/net/%s/bonding/slaves", bonding->ifname, cmd);
+
+ return 0;
+}
+
+int system_bonding_delif(struct device *bonding, struct device *dev)
+{
+ char cmd[32];
+
+ snprintf(cmd, sizeof(cmd), "-%s", dev->ifname);
+ system_set_dev_sysctl("/sys/class/net/%s/bonding/slaves", bonding->ifname, cmd);
+ system_if_up(dev);
+
+ return 0;
+}
+
int system_bridge_delif(struct device *bridge, struct device *dev)
{
return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
@@ -1040,11 +1110,19 @@
{
static char buf[256];
char *bridge;
+ struct device *bonding;
+
device_set_ifindex(dev, system_if_resolve(dev));
if (dev->external || !dev->ifindex)
return;
+ if (system_is_bonding(dev->ifname, buf, sizeof(buf))) {
+ D(SYSTEM, "Delete existing bonding named '%s'\n", dev->ifname);
+ system_bonding_delbonding(dev);
+ return;
+ }
+
system_if_flags(dev->ifname, 0, IFF_UP);
if (system_is_bridge(dev->ifname, buf, sizeof(buf))) {
@@ -1059,6 +1137,12 @@
system_bridge_if(bridge, dev, SIOCBRDELIF, NULL);
}
+ bonding = system_get_bonding(dev->ifname, buf, sizeof(buf));
+ if (bonding) {
+ D(SYSTEM, "Remove device '%s' from bonding '%s'\n", dev->ifname, bonding->ifname);
+ system_bonding_delif(bonding, dev);
+ }
+
system_if_clear_entries(dev, RTM_GETROUTE, AF_INET);
system_if_clear_entries(dev, RTM_GETADDR, AF_INET);
system_if_clear_entries(dev, RTM_GETROUTE, AF_INET6);
@@ -1068,6 +1152,23 @@
system_set_disable_ipv6(dev, "0");
}
+int system_bonding_addbonding(struct device *bonding, struct bonding_config *cfg)
+{
+ char cmd[32], mode[4], policy[16];
+
+ snprintf(cmd, sizeof(cmd), "+%s", bonding->ifname);
+ system_set_sysctl("/sys/class/net/bonding_masters", cmd);
+
+ snprintf(mode, sizeof(mode), "%d", cfg->mode);
+ system_set_dev_sysctl("/sys/class/net/%s/bonding/mode", bonding->ifname, mode);
+
+ snprintf(policy, sizeof(policy), "%s", cfg->xmit_hash_policy);
+ system_set_dev_sysctl("/sys/class/net/%s/bonding/xmit_hash_policy",
+ bonding->ifname, policy);
+
+ return 0;
+}
+
static inline unsigned long
sec_to_jiffies(int val)
{