From 6519cf31e4b033fd4a03c031ad882166be84fa6d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 22 Aug 2021 08:00:18 +0200 Subject: [PATCH] bridge: add support for an external STP daemon netifd notifies the stp daemon through the network.device object and sends STP related configuration parameters. The daemon can also trigger a STP restart in order to close the race on init Signed-off-by: Felix Fietkau --- bridge.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ device.c | 12 ++++++++++++ device.h | 2 ++ system-dummy.c | 4 ++++ system-linux.c | 8 +++++--- system.h | 3 +++ ubus.c | 16 ++++++++++++++++ ubus.h | 1 + 8 files changed, 94 insertions(+), 3 deletions(-) diff --git a/bridge.c b/bridge.c index 58e1b8b..15e09dd 100644 --- a/bridge.c +++ b/bridge.c @@ -21,6 +21,7 @@ #include "device.h" #include "interface.h" #include "system.h" +#include "ubus.h" enum { BRIDGE_ATTR_PORTS, @@ -40,6 +41,8 @@ enum { BRIDGE_ATTR_LAST_MEMBER_INTERVAL, BRIDGE_ATTR_VLAN_FILTERING, BRIDGE_ATTR_HAS_VLANS, + BRIDGE_ATTR_STP_KERNEL, + BRIDGE_ATTR_STP_PROTO, __BRIDGE_ATTR_MAX }; @@ -61,6 +64,8 @@ static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = { [BRIDGE_ATTR_LAST_MEMBER_INTERVAL] = { "last_member_interval", BLOBMSG_TYPE_INT32 }, [BRIDGE_ATTR_VLAN_FILTERING] = { "vlan_filtering", BLOBMSG_TYPE_BOOL }, [BRIDGE_ATTR_HAS_VLANS] = { "__has_vlans", BLOBMSG_TYPE_BOOL }, /* internal */ + [BRIDGE_ATTR_STP_KERNEL] = { "stp_kernel", BLOBMSG_TYPE_BOOL }, + [BRIDGE_ATTR_STP_PROTO] = { "stp_proto", BLOBMSG_TYPE_STRING }, }; static const struct uci_blob_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = { @@ -76,11 +81,13 @@ static const struct uci_blob_param_list bridge_attr_list = { .next = { &device_attr_list }, }; +static struct blob_buf b; static struct device *bridge_create(const char *name, struct device_type *devtype, struct blob_attr *attr); static void bridge_config_init(struct device *dev); static void bridge_dev_vlan_update(struct device *dev); static void bridge_free(struct device *dev); +static void bridge_stp_init(struct device *dev); static void bridge_dump_info(struct device *dev, struct blob_buf *b); static enum dev_change_type bridge_reload(struct device *dev, struct blob_attr *attr); @@ -98,6 +105,7 @@ static struct device_type bridge_device_type = { .reload = bridge_reload, .free = bridge_free, .dump_info = bridge_dump_info, + .stp_init = bridge_stp_init, }; struct bridge_state { @@ -319,6 +327,27 @@ bridge_disable_member(struct bridge_member *bm, bool keep_dev) return 0; } +static void bridge_stp_notify(struct bridge_state *bst) +{ + struct bridge_config *cfg = &bst->config; + + if (!cfg->stp || cfg->stp_kernel) + return; + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "name", bst->dev.ifname); + if (cfg->stp_proto) + blobmsg_add_string(&b, "proto", cfg->stp_proto); + blobmsg_add_u32(&b, "forward_delay", cfg->forward_delay); + if (cfg->flags & BRIDGE_OPT_HELLO_TIME) + blobmsg_add_u32(&b, "hello_time", cfg->hello_time); + if (cfg->flags & BRIDGE_OPT_MAX_AGE) + blobmsg_add_u32(&b, "max_age", cfg->max_age); + if (cfg->flags & BRIDGE_OPT_AGEING_TIME) + blobmsg_add_u32(&b, "ageing_time", cfg->ageing_time); + netifd_ubus_device_notify("stp_init", b.head, 1000); +} + static int bridge_enable_interface(struct bridge_state *bst) { @@ -327,6 +356,7 @@ bridge_enable_interface(struct bridge_state *bst) if (bst->active) return 0; + bridge_stp_notify(bst); ret = system_bridge_addbr(&bst->dev, &bst->config); if (ret < 0) return ret; @@ -342,6 +372,20 @@ bridge_enable_interface(struct bridge_state *bst) return 0; } +static void +bridge_stp_init(struct device *dev) +{ + struct bridge_state *bst; + + bst = container_of(dev, struct bridge_state, dev); + if (!bst->config.stp || !bst->active) + return; + + bridge_stp_notify(bst); + system_bridge_set_stp_state(&bst->dev, false); + system_bridge_set_stp_state(&bst->dev, true); +} + static void bridge_disable_interface(struct bridge_state *bst) { @@ -1000,6 +1044,7 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) /* defaults */ memset(cfg, 0, sizeof(*cfg)); cfg->stp = false; + cfg->stp_kernel = false; cfg->forward_delay = 2; cfg->robustness = 2; cfg->igmp_snoop = false; @@ -1015,6 +1060,12 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) if ((cur = tb[BRIDGE_ATTR_STP])) cfg->stp = blobmsg_get_bool(cur); + if ((cur = tb[BRIDGE_ATTR_STP_KERNEL])) + cfg->stp = blobmsg_get_bool(cur); + + if ((cur = tb[BRIDGE_ATTR_STP_PROTO])) + cfg->stp_proto = blobmsg_get_string(cur); + if ((cur = tb[BRIDGE_ATTR_FORWARD_DELAY])) cfg->forward_delay = blobmsg_get_u32(cur); diff --git a/device.c b/device.c index 521d9a6..bb39ea7 100644 --- a/device.c +++ b/device.c @@ -139,6 +139,18 @@ void device_vlan_update(bool done) } } +void device_stp_init(void) +{ + struct device *dev; + + avl_for_each_element(&devices, dev, avl) { + if (!dev->type->stp_init) + continue; + + dev->type->stp_init(dev); + } +} + static int set_device_state(struct device *dev, bool state) { if (state) { diff --git a/device.h b/device.h index 0968c98..4f80caa 100644 --- a/device.h +++ b/device.h @@ -89,6 +89,7 @@ struct device_type { void (*dump_info)(struct device *, struct blob_buf *buf); void (*dump_stats)(struct device *, struct blob_buf *buf); int (*check_state)(struct device *); + void (*stp_init)(struct device *); void (*free)(struct device *); }; @@ -301,6 +302,7 @@ void device_lock(void); void device_unlock(void); void device_vlan_update(bool done); +void device_stp_init(void); int device_type_add(struct device_type *devtype); struct device_type *device_type_get(const char *tname); diff --git a/system-dummy.c b/system-dummy.c index ab178f3..7eb4e08 100644 --- a/system-dummy.c +++ b/system-dummy.c @@ -66,6 +66,10 @@ int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int v return 0; } +void system_bridge_set_stp_state(struct device *dev, bool val) +{ +} + int system_bridge_vlan_check(struct device *dev, char *ifname) { return 0; diff --git a/system-linux.c b/system-linux.c index c0ba279..e9a19f7 100644 --- a/system-linux.c +++ b/system-linux.c @@ -460,9 +460,11 @@ static void system_bridge_set_startup_query_interval(struct device *dev, const c dev->ifname, val); } -static void system_bridge_set_stp_state(struct device *dev, const char *val) +void system_bridge_set_stp_state(struct device *dev, bool val) { - system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/stp_state", dev->ifname, val); + const char *valstr = val ? "1" : "0"; + + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/stp_state", dev->ifname, valstr); } static void system_bridge_set_forward_delay(struct device *dev, const char *val) @@ -1263,7 +1265,7 @@ int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg) if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0) return -1; - system_bridge_set_stp_state(bridge, cfg->stp ? "1" : "0"); + system_bridge_set_stp_state(bridge, cfg->stp); snprintf(buf, sizeof(buf), "%lu", sec_to_jiffies(cfg->forward_delay)); system_bridge_set_forward_delay(bridge, buf); diff --git a/system.h b/system.h index ae10c59..c5c4f23 100644 --- a/system.h +++ b/system.h @@ -121,6 +121,8 @@ enum bridge_opt { struct bridge_config { enum bridge_opt flags; bool stp; + bool stp_kernel; + const char *stp_proto; bool igmp_snoop; bool multicast_querier; @@ -208,6 +210,7 @@ int system_bridge_addif(struct device *bridge, struct device *dev); int system_bridge_delif(struct device *bridge, struct device *dev); int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int vflags); int system_bridge_vlan_check(struct device *dev, char *ifname); +void system_bridge_set_stp_state(struct device *dev, bool val); int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg); int system_macvlan_del(struct device *macvlan); diff --git a/ubus.c b/ubus.c index 8a0c53a..56cce81 100644 --- a/ubus.c +++ b/ubus.c @@ -371,6 +371,16 @@ netifd_handle_dev_hotplug(struct ubus_context *ctx, struct ubus_object *obj, } #endif +static int +netifd_handle_stp_init(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + device_stp_init(); + + return 0; +} + static struct ubus_method dev_object_methods[] = { UBUS_METHOD("status", netifd_dev_status, dev_policy), UBUS_METHOD("set_alias", netifd_handle_alias, alias_attrs), @@ -378,6 +388,7 @@ static struct ubus_method dev_object_methods[] = { #ifdef DUMMY_MODE UBUS_METHOD("hotplug_event", netifd_handle_dev_hotplug, dev_hotplug_policy), #endif + UBUS_METHOD_NOARG("stp_init", netifd_handle_stp_init) }; static struct ubus_object_type dev_object_type = @@ -397,6 +408,11 @@ netifd_ubus_add_fd(void) system_fd_set_cloexec(ubus_ctx->sock.fd); } +void netifd_ubus_device_notify(const char *event, struct blob_attr *data, int timeout) +{ + ubus_notify(ubus_ctx, &dev_object, event, data, timeout); +} + static void netifd_ubus_reconnect_timer(struct uloop_timeout *timeout) { diff --git a/ubus.h b/ubus.h index 590f5fc..dde7124 100644 --- a/ubus.h +++ b/ubus.h @@ -25,5 +25,6 @@ void netifd_ubus_add_interface(struct interface *iface); void netifd_ubus_remove_interface(struct interface *iface); void netifd_ubus_interface_event(struct interface *iface, bool up); void netifd_ubus_interface_notify(struct interface *iface, bool up); +void netifd_ubus_device_notify(const char *event, struct blob_attr *data, int timeout); #endif -- 2.30.2