mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-03-09 15:40:03 +00:00
865 lines
24 KiB
Diff
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)
|
|
{
|