* [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support
@ 2024-06-24 13:00 Tobias Waldekranz
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Tobias Waldekranz @ 2024-06-24 13:00 UTC (permalink / raw)
To: stephen, dsahern; +Cc: liuhangbin, netdev
This series adds support for:
- Enabling MST on a bridge:
ip link set dev <BR> type bridge mst_enable 1
- (Re)associating VLANs with an MSTI:
bridge vlan global set dev <BR> vid <X> msti <Y>
- Setting the port state in a given MSTI:
bridge mst set dev <PORT> msti <Y> state <Z>
- Listing the current port MST states:
bridge mst show
NOTE: Multiple spanning tree support was added to Linux a couple of
years ago[1], but the corresponding iproute2 patches were never
posted. Mea culpa. Yesterday this was brought to my attention[2],
which is why you are seeing them today.
[1]: https://lore.kernel.org/netdev/20220316150857.2442916-1-tobias@waldekranz.com/
[2]: https://lore.kernel.org/netdev/Zmsc54cVKF1wpzj7@Laptop-X1/
v1 -> v2:
- Require exact match for "mst_enabled" bridge option (Liu)
Tobias Waldekranz (3):
ip: bridge: add support for mst_enabled
bridge: vlan: Add support for setting a VLANs MSTI
bridge: mst: Add get/set support for MST states
bridge/Makefile | 2 +-
bridge/br_common.h | 1 +
bridge/bridge.c | 3 +-
bridge/mst.c | 262 ++++++++++++++++++++++++++++++++++++++++++
bridge/vlan.c | 13 +++
ip/iplink_bridge.c | 19 +++
man/man8/bridge.8 | 66 ++++++++++-
man/man8/ip-link.8.in | 14 +++
8 files changed, 377 insertions(+), 3 deletions(-)
create mode 100644 bridge/mst.c
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
@ 2024-06-24 13:00 ` Tobias Waldekranz
2024-06-26 2:04 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
2024-06-24 13:00 ` [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI Tobias Waldekranz
` (3 subsequent siblings)
4 siblings, 2 replies; 14+ messages in thread
From: Tobias Waldekranz @ 2024-06-24 13:00 UTC (permalink / raw)
To: stephen, dsahern; +Cc: liuhangbin, netdev
When enabled, the bridge's legacy per-VLAN STP facility is replaced
with the Multiple Spanning Tree Protocol (MSTP) compatible version.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
ip/iplink_bridge.c | 19 +++++++++++++++++++
man/man8/ip-link.8.in | 14 ++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c
index 6b70ffbb..f01ffe15 100644
--- a/ip/iplink_bridge.c
+++ b/ip/iplink_bridge.c
@@ -30,6 +30,7 @@ static void print_explain(FILE *f)
" [ max_age MAX_AGE ]\n"
" [ ageing_time AGEING_TIME ]\n"
" [ stp_state STP_STATE ]\n"
+ " [ mst_enabled MST_ENABLED ]\n"
" [ priority PRIORITY ]\n"
" [ group_fwd_mask MASK ]\n"
" [ group_address ADDRESS ]\n"
@@ -169,6 +170,18 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
bm.optval |= no_ll_learn_bit;
else
bm.optval &= ~no_ll_learn_bit;
+ } else if (strcmp(*argv, "mst_enabled") == 0) {
+ __u32 mst_bit = 1 << BR_BOOLOPT_MST_ENABLE;
+ __u8 mst_enabled;
+
+ NEXT_ARG();
+ if (get_u8(&mst_enabled, *argv, 0))
+ invarg("invalid mst_enabled", *argv);
+ bm.optmask |= mst_bit;
+ if (mst_enabled)
+ bm.optval |= mst_bit;
+ else
+ bm.optval &= ~mst_bit;
} else if (strcmp(*argv, "fdb_max_learned") == 0) {
__u32 fdb_max_learned;
@@ -609,6 +622,7 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if (tb[IFLA_BR_MULTI_BOOLOPT]) {
__u32 mcvl_bit = 1 << BR_BOOLOPT_MCAST_VLAN_SNOOPING;
__u32 no_ll_learn_bit = 1 << BR_BOOLOPT_NO_LL_LEARN;
+ __u32 mst_bit = 1 << BR_BOOLOPT_MST_ENABLE;
struct br_boolopt_multi *bm;
bm = RTA_DATA(tb[IFLA_BR_MULTI_BOOLOPT]);
@@ -622,6 +636,11 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
"mcast_vlan_snooping",
"mcast_vlan_snooping %u ",
!!(bm->optval & mcvl_bit));
+ if (bm->optmask & mst_bit)
+ print_uint(PRINT_ANY,
+ "mst_enabled",
+ "mst_enabled %u ",
+ !!(bm->optval & mst_bit));
}
if (tb[IFLA_BR_MCAST_ROUTER])
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index c1984158..eabca490 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -1685,6 +1685,8 @@ the following additional arguments are supported:
] [
.BI stp_state " STP_STATE "
] [
+.BI mst_enabled " MST_ENABLED "
+] [
.BI priority " PRIORITY "
] [
.BI no_linklocal_learn " NO_LINKLOCAL_LEARN "
@@ -1788,6 +1790,18 @@ or off
.RI ( STP_STATE " == 0). "
for this bridge.
+.BI mst_enabled " MST_ENABLED "
+- turn multiple spanning tree (MST) support on
+.RI ( MST_ENABLED " > 0) "
+or off
+.RI ( MST_ENABLED " == 0). "
+When enabled, sets of VLANs can be associated with multiple spanning
+tree instances (MSTIs), and STP states for each port can be controlled
+on a per-MSTI basis. Note: no implementation of the MSTP protocol is
+provided, only the primitives needed to implement it. To avoid
+interfering with the legacy per-VLAN STP states, this setting can only
+be changed when no bridge VLANs are configured.
+
.BI priority " PRIORITY "
- set this bridge's spanning tree priority, used during STP root
bridge election.
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
@ 2024-06-24 13:00 ` Tobias Waldekranz
2024-06-26 2:08 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
2024-06-24 13:00 ` [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states Tobias Waldekranz
` (2 subsequent siblings)
4 siblings, 2 replies; 14+ messages in thread
From: Tobias Waldekranz @ 2024-06-24 13:00 UTC (permalink / raw)
To: stephen, dsahern; +Cc: liuhangbin, netdev
Allow the user to associate one or more VLANs with a multiple spanning
tree instance (MSTI), when MST is enabled on the bridge.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
bridge/vlan.c | 13 +++++++++++++
man/man8/bridge.8 | 9 ++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/bridge/vlan.c b/bridge/vlan.c
index 0a7e6c45..34d7f767 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -56,6 +56,7 @@ static void usage(void)
" [ mcast_querier_interval QUERIER_INTERVAL ]\n"
" [ mcast_query_interval QUERY_INTERVAL ]\n"
" [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
+ " [ msti MSTI ]\n"
" bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
exit(-1);
}
@@ -406,6 +407,7 @@ static int vlan_global_option_set(int argc, char **argv)
short vid = -1;
__u64 val64;
__u32 val32;
+ __u16 val16;
__u8 val8;
afspec = addattr_nest(&req.n, sizeof(req),
@@ -536,6 +538,12 @@ static int vlan_global_option_set(int argc, char **argv)
addattr64(&req.n, 1024,
BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
val64);
+ } else if (strcmp(*argv, "msti") == 0) {
+ NEXT_ARG();
+ if (get_u16(&val16, *argv, 0))
+ invarg("invalid msti", *argv);
+ addattr16(&req.n, 1024,
+ BRIDGE_VLANDB_GOPTS_MSTI, val16);
} else {
if (strcmp(*argv, "help") == 0)
NEXT_ARG();
@@ -945,6 +953,11 @@ static void print_vlan_global_opts(struct rtattr *a, int ifindex)
"mcast_query_response_interval %llu ",
rta_getattr_u64(vattr));
}
+ if (vtb[BRIDGE_VLANDB_GOPTS_MSTI]) {
+ vattr = vtb[BRIDGE_VLANDB_GOPTS_MSTI];
+ print_uint(PRINT_ANY, "msti", "msti %u ",
+ rta_getattr_u16(vattr));
+ }
print_nl();
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]) {
vattr = RTA_DATA(vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]);
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index bb02bd27..b4699801 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -266,7 +266,9 @@ bridge \- show / manipulate bridge addresses and devices
.B mcast_query_interval
.IR QUERY_INTERVAL " ] [ "
.B mcast_query_response_interval
-.IR QUERY_RESPONSE_INTERVAL " ]"
+.IR QUERY_RESPONSE_INTERVAL " ] [ "
+.B msti
+.IR MSTI " ]"
.ti -8
.BR "bridge vlan global" " [ " show " ] [ "
@@ -1493,6 +1495,11 @@ startup phase.
set the Max Response Time/Maximum Response Delay for IGMP/MLD
queries sent by the bridge.
+.TP
+.BI msti " MSTI "
+associate the VLAN with the specified multiple spanning tree instance
+(MSTI).
+
.SS bridge vlan global show - list global vlan options.
This command displays the global VLAN options for each VLAN entry.
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
2024-06-24 13:00 ` [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI Tobias Waldekranz
@ 2024-06-24 13:00 ` Tobias Waldekranz
2024-06-26 6:21 ` Nikolay Aleksandrov
2024-06-27 16:56 ` Stephen Hemminger
2024-06-26 6:11 ` [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Nikolay Aleksandrov
2024-06-26 6:47 ` Hangbin Liu
4 siblings, 2 replies; 14+ messages in thread
From: Tobias Waldekranz @ 2024-06-24 13:00 UTC (permalink / raw)
To: stephen, dsahern; +Cc: liuhangbin, netdev
Allow a port's spanning tree state to be modified on a per-MSTI basis,
and support dumping the current MST states for every port and MSTI.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
bridge/Makefile | 2 +-
bridge/br_common.h | 1 +
bridge/bridge.c | 3 +-
bridge/mst.c | 262 +++++++++++++++++++++++++++++++++++++++++++++
man/man8/bridge.8 | 57 ++++++++++
5 files changed, 323 insertions(+), 2 deletions(-)
create mode 100644 bridge/mst.c
diff --git a/bridge/Makefile b/bridge/Makefile
index 01f8a455..4c57df43 100644
--- a/bridge/Makefile
+++ b/bridge/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o vni.o
+BROBJ = bridge.o fdb.o monitor.o link.o mdb.o mst.o vlan.o vni.o
include ../config.mk
diff --git a/bridge/br_common.h b/bridge/br_common.h
index 704e76b0..3a0cf882 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -20,6 +20,7 @@ void print_headers(FILE *fp, const char *label);
int do_fdb(int argc, char **argv);
int do_mdb(int argc, char **argv);
int do_monitor(int argc, char **argv);
+int do_mst(int argc, char **argv);
int do_vlan(int argc, char **argv);
int do_link(int argc, char **argv);
int do_vni(int argc, char **argv);
diff --git a/bridge/bridge.c b/bridge/bridge.c
index ef592815..f8b5646a 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -36,7 +36,7 @@ static void usage(void)
fprintf(stderr,
"Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
" bridge [ -force ] -batch filename\n"
-"where OBJECT := { link | fdb | mdb | vlan | vni | monitor }\n"
+"where OBJECT := { link | fdb | mdb | mst | vlan | vni | monitor }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
" -o[neline] | -t[imestamp] | -n[etns] name |\n"
" -com[pressvlans] -c[olor] -p[retty] -j[son] }\n");
@@ -56,6 +56,7 @@ static const struct cmd {
{ "link", do_link },
{ "fdb", do_fdb },
{ "mdb", do_mdb },
+ { "mst", do_mst },
{ "vlan", do_vlan },
{ "vni", do_vni },
{ "monitor", do_monitor },
diff --git a/bridge/mst.c b/bridge/mst.c
new file mode 100644
index 00000000..873ca536
--- /dev/null
+++ b/bridge/mst.c
@@ -0,0 +1,262 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Get/set Multiple Spanning Tree (MST) states
+ */
+
+#include <stdio.h>
+#include <linux/if_bridge.h>
+#include <net/if.h>
+
+#include "libnetlink.h"
+#include "json_print.h"
+#include "utils.h"
+
+#include "br_common.h"
+
+#define MST_ID_LEN 9
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+static unsigned int filter_index;
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: bridge mst set dev DEV msti MSTI state STATE\n"
+ " bridge mst {show} [ dev DEV ]\n");
+ exit(-1);
+}
+
+static void print_mst_entry(struct rtattr *a, FILE *fp)
+{
+ struct rtattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
+ __u16 msti = 0;
+ __u8 state = 0;
+
+ parse_rtattr_flags(tb, IFLA_BRIDGE_MST_ENTRY_MAX, RTA_DATA(a),
+ RTA_PAYLOAD(a), NLA_F_NESTED);
+
+
+ if (!(tb[IFLA_BRIDGE_MST_ENTRY_MSTI] &&
+ tb[IFLA_BRIDGE_MST_ENTRY_STATE])) {
+ fprintf(stderr, "BUG: broken MST entry");
+ return;
+ }
+
+ msti = rta_getattr_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
+ state = rta_getattr_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
+
+ open_json_object(NULL);
+ print_uint(PRINT_ANY, "msti", "%u", msti);
+ print_nl();
+ print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
+ print_stp_state(state);
+ print_nl();
+ close_json_object();
+}
+
+static int print_msts(struct nlmsghdr *n, void *arg)
+{
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *af_spec, *mst, *a;
+ int rem = n->nlmsg_len;
+ bool opened = false;
+
+ rem -= NLMSG_LENGTH(sizeof(*ifi));
+ if (rem < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", rem);
+ return -1;
+ }
+
+ af_spec = parse_rtattr_one(IFLA_AF_SPEC, IFLA_RTA(ifi), rem);
+ if (!af_spec)
+ return -1;
+
+ if (filter_index && filter_index != ifi->ifi_index)
+ return 0;
+
+ mst = parse_rtattr_one_nested(NLA_F_NESTED | IFLA_BRIDGE_MST, af_spec);
+ if (!mst)
+ return 0;
+
+ rem = RTA_PAYLOAD(mst);
+ for (a = RTA_DATA(mst); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
+ unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
+
+ if (rta_type > IFLA_BRIDGE_MST_MAX)
+ continue;
+
+ switch (rta_type) {
+ case IFLA_BRIDGE_MST_ENTRY:
+ if (!opened) {
+ open_json_object(NULL);
+ print_color_string(PRINT_ANY, COLOR_IFNAME,
+ "ifname",
+ "%-" __stringify(IFNAMSIZ) "s ",
+ ll_index_to_name(ifi->ifi_index));
+ open_json_array(PRINT_JSON, "mst");
+ opened = true;
+ } else {
+ print_string(PRINT_FP, NULL, "%-"
+ __stringify(IFNAMSIZ) "s ", "");
+ }
+
+ print_mst_entry(a, arg);
+ break;
+ }
+ }
+
+ if (opened) {
+ close_json_array(PRINT_JSON, NULL);
+ close_json_object();
+ }
+
+ return 0;
+}
+
+static int mst_show(int argc, char **argv)
+{
+ char *filter_dev = NULL;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (filter_dev)
+ duparg("dev", *argv);
+ filter_dev = *argv;
+ }
+ argc--; argv++;
+ }
+
+ if (filter_dev) {
+ filter_index = ll_name_to_index(filter_dev);
+ if (!filter_index)
+ return nodev(filter_dev);
+ }
+
+ if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE, RTEXT_FILTER_MST) < 0) {
+ perror("Cannon send dump request");
+ exit(1);
+ }
+
+ new_json_obj(json);
+
+ if (!is_json_context()) {
+ printf("%-" __stringify(IFNAMSIZ) "s "
+ "%-" __stringify(MST_ID_LEN) "s",
+ "port", "msti");
+ printf("\n");
+ }
+
+ if (rtnl_dump_filter(&rth, print_msts, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return -1;
+ }
+
+ delete_json_obj();
+ fflush(stdout);
+ return 0;
+}
+
+static int mst_set(int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg ifi;
+ char buf[512];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .n.nlmsg_type = RTM_SETLINK,
+ .ifi.ifi_family = PF_BRIDGE,
+ };
+ char *d = NULL, *m = NULL, *s = NULL, *endptr;
+ struct rtattr *af_spec, *mst, *entry;
+ __u16 msti;
+ __u8 state;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else if (strcmp(*argv, "msti") == 0) {
+ NEXT_ARG();
+ m = *argv;
+ } else if (strcmp(*argv, "state") == 0) {
+ NEXT_ARG();
+ s = *argv;
+ } else {
+ if (matches(*argv, "help") == 0)
+ usage();
+ }
+ argc--; argv++;
+ }
+
+ if (d == NULL || m == NULL || s == NULL) {
+ fprintf(stderr, "Device, MSTI and state are required arguments.\n");
+ return -1;
+ }
+
+ req.ifi.ifi_index = ll_name_to_index(d);
+ if (!req.ifi.ifi_index)
+ return nodev(d);
+
+ msti = strtol(m, &endptr, 10);
+ if (!(*s != '\0' && *endptr == '\0')) {
+ fprintf(stderr,
+ "Error: invalid MSTI\n");
+ return -1;
+ }
+
+ state = strtol(s, &endptr, 10);
+ if (!(*s != '\0' && *endptr == '\0')) {
+ state = parse_stp_state(s);
+ if (state == -1) {
+ fprintf(stderr,
+ "Error: invalid STP port state\n");
+ return -1;
+ }
+ }
+
+ af_spec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
+ mst = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST);
+
+ entry = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY);
+ entry->rta_type |= NLA_F_NESTED;
+
+ addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_MSTI, msti);
+ addattr8(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_STATE, state);
+
+ addattr_nest_end(&req.n, entry);
+
+ addattr_nest_end(&req.n, mst);
+ addattr_nest_end(&req.n, af_spec);
+
+
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+int do_mst(int argc, char **argv)
+{
+ ll_init_map(&rth);
+
+ if (argc > 0) {
+ if (matches(*argv, "set") == 0)
+ return mst_set(argc-1, argv+1);
+
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return mst_show(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return mst_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mst help\".\n", *argv);
+ exit(-1);
+}
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index b4699801..08f329c6 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -207,6 +207,15 @@ bridge \- show / manipulate bridge addresses and devices
.RB "[ " vni
.IR VNI " ]"
+.ti -8
+.B "bridge mst set"
+.IR dev " DEV " msti " MSTI " state " STP_STATE "
+
+.ti -8
+.BR "bridge mst" " [ [ " show " ] [ "
+.B dev
+.IR DEV " ] ]"
+
.ti -8
.BR "bridge vlan" " { " add " | " del " } "
.B dev
@@ -1247,6 +1256,54 @@ endpoint. Match entries only with the specified destination port number.
the VXLAN VNI Network Identifier to use to connect to the remote VXLAN tunnel
endpoint. Match entries only with the specified destination VNI.
+.SH bridge mst - multiple spanning tree port states
+
+In the multiple spanning tree (MST) model, the active paths through a
+network can be different for different VLANs. In other words, a
+bridge port can simultaneously forward one subset of VLANs, while
+blocking another.
+
+Provided that the
+.B mst_enable
+bridge option is enabled, a group of VLANs can be forwarded along the
+same spanning tree by associating them with the same instance (MSTI)
+using
+.BR "bridge vlan global set" .
+
+.SS bridge mst set - set multiple spanning tree state
+
+Set the spanning tree state for
+.IR DEV ,
+in the multiple spanning tree instance
+.IR MSTI ,
+to
+.IR STP_STATE .
+
+.TP
+.BI dev " DEV"
+Interface name of the bridge port.
+
+.TP
+.BI msti " MSTI"
+The multiple spanning tree instance.
+
+.TP
+.BI state " STP_STATE"
+The spanning tree state, see the
+.B state
+option of
+.B "bridge link set"
+for supported states.
+
+.SS bridge mst show - list MST states
+
+List current MST port states in every MSTI.
+
+.TP
+.BI dev " DEV"
+If specified, only display states of the bridge port with this
+interface name.
+
.SH bridge vlan - VLAN filter list
.B vlan
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
@ 2024-06-26 2:04 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
1 sibling, 0 replies; 14+ messages in thread
From: Hangbin Liu @ 2024-06-26 2:04 UTC (permalink / raw)
To: Tobias Waldekranz; +Cc: stephen, dsahern, netdev
On Mon, Jun 24, 2024 at 03:00:33PM +0200, Tobias Waldekranz wrote:
> When enabled, the bridge's legacy per-VLAN STP facility is replaced
> with the Multiple Spanning Tree Protocol (MSTP) compatible version.
>
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
> ip/iplink_bridge.c | 19 +++++++++++++++++++
> man/man8/ip-link.8.in | 14 ++++++++++++++
> 2 files changed, 33 insertions(+)
>
> diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c
> index 6b70ffbb..f01ffe15 100644
> --- a/ip/iplink_bridge.c
> +++ b/ip/iplink_bridge.c
> @@ -30,6 +30,7 @@ static void print_explain(FILE *f)
> " [ max_age MAX_AGE ]\n"
> " [ ageing_time AGEING_TIME ]\n"
> " [ stp_state STP_STATE ]\n"
> + " [ mst_enabled MST_ENABLED ]\n"
> " [ priority PRIORITY ]\n"
> " [ group_fwd_mask MASK ]\n"
> " [ group_address ADDRESS ]\n"
> @@ -169,6 +170,18 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
> bm.optval |= no_ll_learn_bit;
> else
> bm.optval &= ~no_ll_learn_bit;
> + } else if (strcmp(*argv, "mst_enabled") == 0) {
> + __u32 mst_bit = 1 << BR_BOOLOPT_MST_ENABLE;
> + __u8 mst_enabled;
> +
> + NEXT_ARG();
> + if (get_u8(&mst_enabled, *argv, 0))
> + invarg("invalid mst_enabled", *argv);
> + bm.optmask |= mst_bit;
> + if (mst_enabled)
> + bm.optval |= mst_bit;
> + else
> + bm.optval &= ~mst_bit;
> } else if (strcmp(*argv, "fdb_max_learned") == 0) {
> __u32 fdb_max_learned;
>
> @@ -609,6 +622,7 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
> if (tb[IFLA_BR_MULTI_BOOLOPT]) {
> __u32 mcvl_bit = 1 << BR_BOOLOPT_MCAST_VLAN_SNOOPING;
> __u32 no_ll_learn_bit = 1 << BR_BOOLOPT_NO_LL_LEARN;
> + __u32 mst_bit = 1 << BR_BOOLOPT_MST_ENABLE;
> struct br_boolopt_multi *bm;
>
> bm = RTA_DATA(tb[IFLA_BR_MULTI_BOOLOPT]);
> @@ -622,6 +636,11 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
> "mcast_vlan_snooping",
> "mcast_vlan_snooping %u ",
> !!(bm->optval & mcvl_bit));
> + if (bm->optmask & mst_bit)
> + print_uint(PRINT_ANY,
> + "mst_enabled",
> + "mst_enabled %u ",
> + !!(bm->optval & mst_bit));
> }
>
> if (tb[IFLA_BR_MCAST_ROUTER])
> diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
> index c1984158..eabca490 100644
> --- a/man/man8/ip-link.8.in
> +++ b/man/man8/ip-link.8.in
> @@ -1685,6 +1685,8 @@ the following additional arguments are supported:
> ] [
> .BI stp_state " STP_STATE "
> ] [
> +.BI mst_enabled " MST_ENABLED "
> +] [
> .BI priority " PRIORITY "
> ] [
> .BI no_linklocal_learn " NO_LINKLOCAL_LEARN "
> @@ -1788,6 +1790,18 @@ or off
> .RI ( STP_STATE " == 0). "
> for this bridge.
>
> +.BI mst_enabled " MST_ENABLED "
> +- turn multiple spanning tree (MST) support on
> +.RI ( MST_ENABLED " > 0) "
> +or off
> +.RI ( MST_ENABLED " == 0). "
> +When enabled, sets of VLANs can be associated with multiple spanning
> +tree instances (MSTIs), and STP states for each port can be controlled
> +on a per-MSTI basis. Note: no implementation of the MSTP protocol is
> +provided, only the primitives needed to implement it. To avoid
> +interfering with the legacy per-VLAN STP states, this setting can only
> +be changed when no bridge VLANs are configured.
> +
> .BI priority " PRIORITY "
> - set this bridge's spanning tree priority, used during STP root
> bridge election.
> --
> 2.34.1
>
Reviewed-by: Hangbin Liu <liuhangbin@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI
2024-06-24 13:00 ` [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI Tobias Waldekranz
@ 2024-06-26 2:08 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
1 sibling, 0 replies; 14+ messages in thread
From: Hangbin Liu @ 2024-06-26 2:08 UTC (permalink / raw)
To: Tobias Waldekranz; +Cc: stephen, dsahern, netdev
On Mon, Jun 24, 2024 at 03:00:34PM +0200, Tobias Waldekranz wrote:
> Allow the user to associate one or more VLANs with a multiple spanning
> tree instance (MSTI), when MST is enabled on the bridge.
>
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
> bridge/vlan.c | 13 +++++++++++++
> man/man8/bridge.8 | 9 ++++++++-
> 2 files changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/bridge/vlan.c b/bridge/vlan.c
> index 0a7e6c45..34d7f767 100644
> --- a/bridge/vlan.c
> +++ b/bridge/vlan.c
> @@ -56,6 +56,7 @@ static void usage(void)
> " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
> " [ mcast_query_interval QUERY_INTERVAL ]\n"
> " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
> + " [ msti MSTI ]\n"
> " bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
> exit(-1);
> }
> @@ -406,6 +407,7 @@ static int vlan_global_option_set(int argc, char **argv)
> short vid = -1;
> __u64 val64;
> __u32 val32;
> + __u16 val16;
> __u8 val8;
>
> afspec = addattr_nest(&req.n, sizeof(req),
> @@ -536,6 +538,12 @@ static int vlan_global_option_set(int argc, char **argv)
> addattr64(&req.n, 1024,
> BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
> val64);
> + } else if (strcmp(*argv, "msti") == 0) {
> + NEXT_ARG();
> + if (get_u16(&val16, *argv, 0))
> + invarg("invalid msti", *argv);
> + addattr16(&req.n, 1024,
> + BRIDGE_VLANDB_GOPTS_MSTI, val16);
> } else {
> if (strcmp(*argv, "help") == 0)
> NEXT_ARG();
> @@ -945,6 +953,11 @@ static void print_vlan_global_opts(struct rtattr *a, int ifindex)
> "mcast_query_response_interval %llu ",
> rta_getattr_u64(vattr));
> }
> + if (vtb[BRIDGE_VLANDB_GOPTS_MSTI]) {
> + vattr = vtb[BRIDGE_VLANDB_GOPTS_MSTI];
> + print_uint(PRINT_ANY, "msti", "msti %u ",
> + rta_getattr_u16(vattr));
> + }
> print_nl();
> if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]) {
> vattr = RTA_DATA(vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]);
> diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
> index bb02bd27..b4699801 100644
> --- a/man/man8/bridge.8
> +++ b/man/man8/bridge.8
> @@ -266,7 +266,9 @@ bridge \- show / manipulate bridge addresses and devices
> .B mcast_query_interval
> .IR QUERY_INTERVAL " ] [ "
> .B mcast_query_response_interval
> -.IR QUERY_RESPONSE_INTERVAL " ]"
> +.IR QUERY_RESPONSE_INTERVAL " ] [ "
> +.B msti
> +.IR MSTI " ]"
>
> .ti -8
> .BR "bridge vlan global" " [ " show " ] [ "
> @@ -1493,6 +1495,11 @@ startup phase.
> set the Max Response Time/Maximum Response Delay for IGMP/MLD
> queries sent by the bridge.
>
> +.TP
> +.BI msti " MSTI "
> +associate the VLAN with the specified multiple spanning tree instance
> +(MSTI).
> +
> .SS bridge vlan global show - list global vlan options.
>
> This command displays the global VLAN options for each VLAN entry.
> --
> 2.34.1
>
Reviewed-by: Hangbin Liu <liuhangbin@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
` (2 preceding siblings ...)
2024-06-24 13:00 ` [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states Tobias Waldekranz
@ 2024-06-26 6:11 ` Nikolay Aleksandrov
2024-06-26 6:33 ` Tobias Waldekranz
2024-06-26 6:47 ` Hangbin Liu
4 siblings, 1 reply; 14+ messages in thread
From: Nikolay Aleksandrov @ 2024-06-26 6:11 UTC (permalink / raw)
To: Tobias Waldekranz, stephen, dsahern; +Cc: liuhangbin, netdev
On 24/06/2024 16:00, Tobias Waldekranz wrote:
> This series adds support for:
>
> - Enabling MST on a bridge:
>
> ip link set dev <BR> type bridge mst_enable 1
>
> - (Re)associating VLANs with an MSTI:
>
> bridge vlan global set dev <BR> vid <X> msti <Y>
>
> - Setting the port state in a given MSTI:
>
> bridge mst set dev <PORT> msti <Y> state <Z>
>
> - Listing the current port MST states:
>
> bridge mst show
>
> NOTE: Multiple spanning tree support was added to Linux a couple of
> years ago[1], but the corresponding iproute2 patches were never
> posted. Mea culpa. Yesterday this was brought to my attention[2],
> which is why you are seeing them today.
>
> [1]: https://lore.kernel.org/netdev/20220316150857.2442916-1-tobias@waldekranz.com/
> [2]: https://lore.kernel.org/netdev/Zmsc54cVKF1wpzj7@Laptop-X1/
>
> v1 -> v2:
> - Require exact match for "mst_enabled" bridge option (Liu)
>
> Tobias Waldekranz (3):
> ip: bridge: add support for mst_enabled
> bridge: vlan: Add support for setting a VLANs MSTI
> bridge: mst: Add get/set support for MST states
>
> bridge/Makefile | 2 +-
> bridge/br_common.h | 1 +
> bridge/bridge.c | 3 +-
> bridge/mst.c | 262 ++++++++++++++++++++++++++++++++++++++++++
> bridge/vlan.c | 13 +++
> ip/iplink_bridge.c | 19 +++
> man/man8/bridge.8 | 66 ++++++++++-
> man/man8/ip-link.8.in | 14 +++
> 8 files changed, 377 insertions(+), 3 deletions(-)
> create mode 100644 bridge/mst.c
>
Thanks for posting these, I was also wondering what happened with iproute2 support.
I had to do quick hacks to test my recent mst fixes and I almost missed this set,
please CC bridge maintainers on such changes as well.
Cheers,
Nik
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
2024-06-26 2:04 ` Hangbin Liu
@ 2024-06-26 6:12 ` Nikolay Aleksandrov
1 sibling, 0 replies; 14+ messages in thread
From: Nikolay Aleksandrov @ 2024-06-26 6:12 UTC (permalink / raw)
To: Tobias Waldekranz, stephen, dsahern; +Cc: liuhangbin, netdev
On 24/06/2024 16:00, Tobias Waldekranz wrote:
> When enabled, the bridge's legacy per-VLAN STP facility is replaced
> with the Multiple Spanning Tree Protocol (MSTP) compatible version.
>
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
> ip/iplink_bridge.c | 19 +++++++++++++++++++
> man/man8/ip-link.8.in | 14 ++++++++++++++
> 2 files changed, 33 insertions(+)
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI
2024-06-24 13:00 ` [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI Tobias Waldekranz
2024-06-26 2:08 ` Hangbin Liu
@ 2024-06-26 6:12 ` Nikolay Aleksandrov
1 sibling, 0 replies; 14+ messages in thread
From: Nikolay Aleksandrov @ 2024-06-26 6:12 UTC (permalink / raw)
To: Tobias Waldekranz, stephen, dsahern; +Cc: liuhangbin, netdev
On 24/06/2024 16:00, Tobias Waldekranz wrote:
> Allow the user to associate one or more VLANs with a multiple spanning
> tree instance (MSTI), when MST is enabled on the bridge.
>
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
> bridge/vlan.c | 13 +++++++++++++
> man/man8/bridge.8 | 9 ++++++++-
> 2 files changed, 21 insertions(+), 1 deletion(-)
>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states
2024-06-24 13:00 ` [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states Tobias Waldekranz
@ 2024-06-26 6:21 ` Nikolay Aleksandrov
2024-06-27 16:56 ` Stephen Hemminger
1 sibling, 0 replies; 14+ messages in thread
From: Nikolay Aleksandrov @ 2024-06-26 6:21 UTC (permalink / raw)
To: Tobias Waldekranz, stephen, dsahern; +Cc: liuhangbin, netdev
On 24/06/2024 16:00, Tobias Waldekranz wrote:
> Allow a port's spanning tree state to be modified on a per-MSTI basis,
> and support dumping the current MST states for every port and MSTI.
>
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
> bridge/Makefile | 2 +-
> bridge/br_common.h | 1 +
> bridge/bridge.c | 3 +-
> bridge/mst.c | 262 +++++++++++++++++++++++++++++++++++++++++++++
> man/man8/bridge.8 | 57 ++++++++++
> 5 files changed, 323 insertions(+), 2 deletions(-)
> create mode 100644 bridge/mst.c
>
> diff --git a/bridge/Makefile b/bridge/Makefile
> index 01f8a455..4c57df43 100644
> --- a/bridge/Makefile
> +++ b/bridge/Makefile
> @@ -1,5 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0
> -BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o vni.o
> +BROBJ = bridge.o fdb.o monitor.o link.o mdb.o mst.o vlan.o vni.o
>
> include ../config.mk
>
> diff --git a/bridge/br_common.h b/bridge/br_common.h
> index 704e76b0..3a0cf882 100644
> --- a/bridge/br_common.h
> +++ b/bridge/br_common.h
> @@ -20,6 +20,7 @@ void print_headers(FILE *fp, const char *label);
> int do_fdb(int argc, char **argv);
> int do_mdb(int argc, char **argv);
> int do_monitor(int argc, char **argv);
> +int do_mst(int argc, char **argv);
> int do_vlan(int argc, char **argv);
> int do_link(int argc, char **argv);
> int do_vni(int argc, char **argv);
> diff --git a/bridge/bridge.c b/bridge/bridge.c
> index ef592815..f8b5646a 100644
> --- a/bridge/bridge.c
> +++ b/bridge/bridge.c
> @@ -36,7 +36,7 @@ static void usage(void)
> fprintf(stderr,
> "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
> " bridge [ -force ] -batch filename\n"
> -"where OBJECT := { link | fdb | mdb | vlan | vni | monitor }\n"
> +"where OBJECT := { link | fdb | mdb | mst | vlan | vni | monitor }\n"
> " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
> " -o[neline] | -t[imestamp] | -n[etns] name |\n"
> " -com[pressvlans] -c[olor] -p[retty] -j[son] }\n");
> @@ -56,6 +56,7 @@ static const struct cmd {
> { "link", do_link },
> { "fdb", do_fdb },
> { "mdb", do_mdb },
> + { "mst", do_mst },
> { "vlan", do_vlan },
> { "vni", do_vni },
> { "monitor", do_monitor },
> diff --git a/bridge/mst.c b/bridge/mst.c
> new file mode 100644
> index 00000000..873ca536
> --- /dev/null
> +++ b/bridge/mst.c
> @@ -0,0 +1,262 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Get/set Multiple Spanning Tree (MST) states
> + */
> +
> +#include <stdio.h>
> +#include <linux/if_bridge.h>
> +#include <net/if.h>
> +
> +#include "libnetlink.h"
> +#include "json_print.h"
> +#include "utils.h"
> +
> +#include "br_common.h"
> +
> +#define MST_ID_LEN 9
> +
> +#define __stringify_1(x...) #x
> +#define __stringify(x...) __stringify_1(x)
This part seems to be defined in multiple places for the bridge tool,
perhaps pull it in br_common.h?
> +
> +static unsigned int filter_index;
> +
> +static void usage(void)
> +{
> + fprintf(stderr,
> + "Usage: bridge mst set dev DEV msti MSTI state STATE\n"
> + " bridge mst {show} [ dev DEV ]\n");
> + exit(-1);
> +}
> +
> +static void print_mst_entry(struct rtattr *a, FILE *fp)
> +{
> + struct rtattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
> + __u16 msti = 0;
> + __u8 state = 0;
> +
> + parse_rtattr_flags(tb, IFLA_BRIDGE_MST_ENTRY_MAX, RTA_DATA(a),
> + RTA_PAYLOAD(a), NLA_F_NESTED);
> +
> +
> + if (!(tb[IFLA_BRIDGE_MST_ENTRY_MSTI] &&
> + tb[IFLA_BRIDGE_MST_ENTRY_STATE])) {
> + fprintf(stderr, "BUG: broken MST entry");
> + return;
> + }
> +
> + msti = rta_getattr_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
> + state = rta_getattr_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
> +
> + open_json_object(NULL);
> + print_uint(PRINT_ANY, "msti", "%u", msti);
> + print_nl();
> + print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
> + print_stp_state(state);
> + print_nl();
> + close_json_object();
> +}
> +
> +static int print_msts(struct nlmsghdr *n, void *arg)
> +{
> + struct ifinfomsg *ifi = NLMSG_DATA(n);
> + struct rtattr *af_spec, *mst, *a;
> + int rem = n->nlmsg_len;
> + bool opened = false;
> +
> + rem -= NLMSG_LENGTH(sizeof(*ifi));
> + if (rem < 0) {
> + fprintf(stderr, "BUG: wrong nlmsg len %d\n", rem);
> + return -1;
> + }
> +
> + af_spec = parse_rtattr_one(IFLA_AF_SPEC, IFLA_RTA(ifi), rem);
> + if (!af_spec)
> + return -1;
> +
> + if (filter_index && filter_index != ifi->ifi_index)
> + return 0;
> +
> + mst = parse_rtattr_one_nested(NLA_F_NESTED | IFLA_BRIDGE_MST, af_spec);
> + if (!mst)
> + return 0;
> +
> + rem = RTA_PAYLOAD(mst);
> + for (a = RTA_DATA(mst); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
> + unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
> +
> + if (rta_type > IFLA_BRIDGE_MST_MAX)
> + continue;
> +
You can just use the switch below to continue in the default case.
> + switch (rta_type) {
> + case IFLA_BRIDGE_MST_ENTRY:
> + if (!opened) {
> + open_json_object(NULL);
> + print_color_string(PRINT_ANY, COLOR_IFNAME,
> + "ifname",
> + "%-" __stringify(IFNAMSIZ) "s ",
> + ll_index_to_name(ifi->ifi_index));
> + open_json_array(PRINT_JSON, "mst");
> + opened = true;
> + } else {
> + print_string(PRINT_FP, NULL, "%-"
> + __stringify(IFNAMSIZ) "s ", "");
> + }
> +
> + print_mst_entry(a, arg);
> + break;
> + }
> + }
> +
> + if (opened) {
> + close_json_array(PRINT_JSON, NULL);
> + close_json_object();
> + }
> +
> + return 0;
> +}
> +
> +static int mst_show(int argc, char **argv)
> +{
> + char *filter_dev = NULL;
> +
> + while (argc > 0) {
> + if (strcmp(*argv, "dev") == 0) {
> + NEXT_ARG();
> + if (filter_dev)
> + duparg("dev", *argv);
> + filter_dev = *argv;
> + }
> + argc--; argv++;
> + }
> +
> + if (filter_dev) {
> + filter_index = ll_name_to_index(filter_dev);
> + if (!filter_index)
> + return nodev(filter_dev);
> + }
> +
> + if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE, RTEXT_FILTER_MST) < 0) {
> + perror("Cannon send dump request");
> + exit(1);
> + }
> +
> + new_json_obj(json);
> +
> + if (!is_json_context()) {
> + printf("%-" __stringify(IFNAMSIZ) "s "
> + "%-" __stringify(MST_ID_LEN) "s",
> + "port", "msti");
> + printf("\n");
> + }
> +
> + if (rtnl_dump_filter(&rth, print_msts, stdout) < 0) {
> + fprintf(stderr, "Dump terminated\n");
> + return -1;
> + }
> +
> + delete_json_obj();
> + fflush(stdout);
> + return 0;
> +}
> +
> +static int mst_set(int argc, char **argv)
> +{
> + struct {
> + struct nlmsghdr n;
> + struct ifinfomsg ifi;
> + char buf[512];
> + } req = {
> + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
> + .n.nlmsg_flags = NLM_F_REQUEST,
> + .n.nlmsg_type = RTM_SETLINK,
> + .ifi.ifi_family = PF_BRIDGE,
> + };
> + char *d = NULL, *m = NULL, *s = NULL, *endptr;
> + struct rtattr *af_spec, *mst, *entry;
> + __u16 msti;
> + __u8 state;
> +
> + while (argc > 0) {
> + if (strcmp(*argv, "dev") == 0) {
> + NEXT_ARG();
> + d = *argv;
> + } else if (strcmp(*argv, "msti") == 0) {
> + NEXT_ARG();
> + m = *argv;
> + } else if (strcmp(*argv, "state") == 0) {
> + NEXT_ARG();
> + s = *argv;
> + } else {
> + if (matches(*argv, "help") == 0)
> + usage();
> + }
> + argc--; argv++;
> + }
> +
> + if (d == NULL || m == NULL || s == NULL) {
> + fprintf(stderr, "Device, MSTI and state are required arguments.\n");
> + return -1;
> + }
> +
> + req.ifi.ifi_index = ll_name_to_index(d);
> + if (!req.ifi.ifi_index)
> + return nodev(d);
> +
> + msti = strtol(m, &endptr, 10);
> + if (!(*s != '\0' && *endptr == '\0')) {
> + fprintf(stderr,
> + "Error: invalid MSTI\n");
> + return -1;
> + }
> +
> + state = strtol(s, &endptr, 10);
> + if (!(*s != '\0' && *endptr == '\0')) {
> + state = parse_stp_state(s);
> + if (state == -1) {
> + fprintf(stderr,
> + "Error: invalid STP port state\n");
> + return -1;
> + }
> + }
> +
> + af_spec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
> + mst = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST);
> +
> + entry = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY);
> + entry->rta_type |= NLA_F_NESTED;
> +
> + addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_MSTI, msti);
> + addattr8(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_STATE, state);
> +
> + addattr_nest_end(&req.n, entry);
> +
> + addattr_nest_end(&req.n, mst);
> + addattr_nest_end(&req.n, af_spec);
> +
> +
> + if (rtnl_talk(&rth, &req.n, NULL) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +int do_mst(int argc, char **argv)
> +{
> + ll_init_map(&rth);
> +
> + if (argc > 0) {
> + if (matches(*argv, "set") == 0)
> + return mst_set(argc-1, argv+1);
> +
> + if (matches(*argv, "show") == 0 ||
> + matches(*argv, "lst") == 0 ||
> + matches(*argv, "list") == 0)
> + return mst_show(argc-1, argv+1);
> + if (matches(*argv, "help") == 0)
> + usage();
> + } else
> + return mst_show(0, NULL);
> +
> + fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mst help\".\n", *argv);
> + exit(-1);
> +}
> diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
> index b4699801..08f329c6 100644
> --- a/man/man8/bridge.8
> +++ b/man/man8/bridge.8
> @@ -207,6 +207,15 @@ bridge \- show / manipulate bridge addresses and devices
> .RB "[ " vni
> .IR VNI " ]"
>
> +.ti -8
> +.B "bridge mst set"
> +.IR dev " DEV " msti " MSTI " state " STP_STATE "
> +
> +.ti -8
> +.BR "bridge mst" " [ [ " show " ] [ "
> +.B dev
> +.IR DEV " ] ]"
> +
> .ti -8
> .BR "bridge vlan" " { " add " | " del " } "
> .B dev
> @@ -1247,6 +1256,54 @@ endpoint. Match entries only with the specified destination port number.
> the VXLAN VNI Network Identifier to use to connect to the remote VXLAN tunnel
> endpoint. Match entries only with the specified destination VNI.
>
> +.SH bridge mst - multiple spanning tree port states
> +
> +In the multiple spanning tree (MST) model, the active paths through a
> +network can be different for different VLANs. In other words, a
> +bridge port can simultaneously forward one subset of VLANs, while
> +blocking another.
> +
> +Provided that the
> +.B mst_enable
> +bridge option is enabled, a group of VLANs can be forwarded along the
> +same spanning tree by associating them with the same instance (MSTI)
> +using
> +.BR "bridge vlan global set" .
Give a complete command example?
> +
> +.SS bridge mst set - set multiple spanning tree state
> +
> +Set the spanning tree state for
> +.IR DEV ,
> +in the multiple spanning tree instance
> +.IR MSTI ,
> +to
> +.IR STP_STATE .
> +
> +.TP
> +.BI dev " DEV"
> +Interface name of the bridge port.
> +
> +.TP
> +.BI msti " MSTI"
> +The multiple spanning tree instance.
> +
> +.TP
> +.BI state " STP_STATE"
> +The spanning tree state, see the
> +.B state
> +option of
> +.B "bridge link set"
> +for supported states.
> +
> +.SS bridge mst show - list MST states
> +
> +List current MST port states in every MSTI.
> +
> +.TP
> +.BI dev " DEV"
> +If specified, only display states of the bridge port with this
> +interface name.
> +
> .SH bridge vlan - VLAN filter list
>
> .B vlan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support
2024-06-26 6:11 ` [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Nikolay Aleksandrov
@ 2024-06-26 6:33 ` Tobias Waldekranz
0 siblings, 0 replies; 14+ messages in thread
From: Tobias Waldekranz @ 2024-06-26 6:33 UTC (permalink / raw)
To: Nikolay Aleksandrov, stephen, dsahern; +Cc: liuhangbin, netdev
On ons, jun 26, 2024 at 09:11, Nikolay Aleksandrov <razor@blackwall.org> wrote:
> On 24/06/2024 16:00, Tobias Waldekranz wrote:
>> This series adds support for:
>>
>> - Enabling MST on a bridge:
>>
>> ip link set dev <BR> type bridge mst_enable 1
>>
>> - (Re)associating VLANs with an MSTI:
>>
>> bridge vlan global set dev <BR> vid <X> msti <Y>
>>
>> - Setting the port state in a given MSTI:
>>
>> bridge mst set dev <PORT> msti <Y> state <Z>
>>
>> - Listing the current port MST states:
>>
>> bridge mst show
>>
>> NOTE: Multiple spanning tree support was added to Linux a couple of
>> years ago[1], but the corresponding iproute2 patches were never
>> posted. Mea culpa. Yesterday this was brought to my attention[2],
>> which is why you are seeing them today.
>>
>> [1]: https://lore.kernel.org/netdev/20220316150857.2442916-1-tobias@waldekranz.com/
>> [2]: https://lore.kernel.org/netdev/Zmsc54cVKF1wpzj7@Laptop-X1/
>>
>> v1 -> v2:
>> - Require exact match for "mst_enabled" bridge option (Liu)
>>
>> Tobias Waldekranz (3):
>> ip: bridge: add support for mst_enabled
>> bridge: vlan: Add support for setting a VLANs MSTI
>> bridge: mst: Add get/set support for MST states
>>
>> bridge/Makefile | 2 +-
>> bridge/br_common.h | 1 +
>> bridge/bridge.c | 3 +-
>> bridge/mst.c | 262 ++++++++++++++++++++++++++++++++++++++++++
>> bridge/vlan.c | 13 +++
>> ip/iplink_bridge.c | 19 +++
>> man/man8/bridge.8 | 66 ++++++++++-
>> man/man8/ip-link.8.in | 14 +++
>> 8 files changed, 377 insertions(+), 3 deletions(-)
>> create mode 100644 bridge/mst.c
>>
>
> Thanks for posting these, I was also wondering what happened with iproute2 support.
> I had to do quick hacks to test my recent mst fixes and I almost missed this set,
> please CC bridge maintainers on such changes as well.
Sorry about that, I'll make sure to remember it in the future.
Thanks for reviewing!
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
` (3 preceding siblings ...)
2024-06-26 6:11 ` [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Nikolay Aleksandrov
@ 2024-06-26 6:47 ` Hangbin Liu
2024-06-26 6:50 ` Nikolay Aleksandrov
4 siblings, 1 reply; 14+ messages in thread
From: Hangbin Liu @ 2024-06-26 6:47 UTC (permalink / raw)
To: Tobias Waldekranz; +Cc: stephen, dsahern, netdev
On Mon, Jun 24, 2024 at 03:00:32PM +0200, Tobias Waldekranz wrote:
> This series adds support for:
>
> - Enabling MST on a bridge:
>
> ip link set dev <BR> type bridge mst_enable 1
>
> - (Re)associating VLANs with an MSTI:
>
> bridge vlan global set dev <BR> vid <X> msti <Y>
>
> - Setting the port state in a given MSTI:
>
> bridge mst set dev <PORT> msti <Y> state <Z>
>
> - Listing the current port MST states:
>
> bridge mst show
Tested-by: Hangbin Liu <liuhangbin@gmail.com>
With following steps:
+ /home/iproute2/ip/ip link add br0 type bridge
+ /home/iproute2/ip/ip link set br0 type bridge mst_enabled 1
+ /home/iproute2/ip/ip link add type veth
+ /home/iproute2/ip/ip link set veth0 master br0
+ /home/iproute2/bridge/bridge vlan add dev br0 vid 1-3 self
+ /home/iproute2/bridge/bridge vlan global set dev br0 vid 2 msti 3
+ /home/iproute2/bridge/bridge vlan add dev veth0 vid 1-3
+ /home/iproute2/bridge/bridge mst set dev veth0 msti 3 state 1
+ /home/iproute2/bridge/bridge mst show
port msti
veth0 0
state disabled
3
state listening
There is one issue I got (should be kernel issue):
+ /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
Error: MST mode can't be changed while VLANs exist.
If I want disable mst, I got failed as there is VLAN info, which is expected
+ /home/iproute2/ip/ip link set veth0 nomaster
+ /home/iproute2/ip/ip link set veth0 master br0
+ /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
Error: MST mode can't be changed while VLANs exist.
But I got failed again after remove and re-add veth0, is this expected?
I thought the VLAN info should be cleared after removing.
+ /home/iproute2/ip/ip link set veth0 nomaster
+ /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
It works after I remove veth0.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support
2024-06-26 6:47 ` Hangbin Liu
@ 2024-06-26 6:50 ` Nikolay Aleksandrov
0 siblings, 0 replies; 14+ messages in thread
From: Nikolay Aleksandrov @ 2024-06-26 6:50 UTC (permalink / raw)
To: Hangbin Liu, Tobias Waldekranz; +Cc: stephen, dsahern, netdev
On 26/06/2024 09:47, Hangbin Liu wrote:
> On Mon, Jun 24, 2024 at 03:00:32PM +0200, Tobias Waldekranz wrote:
>> This series adds support for:
>>
>> - Enabling MST on a bridge:
>>
>> ip link set dev <BR> type bridge mst_enable 1
>>
>> - (Re)associating VLANs with an MSTI:
>>
>> bridge vlan global set dev <BR> vid <X> msti <Y>
>>
>> - Setting the port state in a given MSTI:
>>
>> bridge mst set dev <PORT> msti <Y> state <Z>
>>
>> - Listing the current port MST states:
>>
>> bridge mst show
>
> Tested-by: Hangbin Liu <liuhangbin@gmail.com>
>
> With following steps:
> + /home/iproute2/ip/ip link add br0 type bridge
> + /home/iproute2/ip/ip link set br0 type bridge mst_enabled 1
> + /home/iproute2/ip/ip link add type veth
> + /home/iproute2/ip/ip link set veth0 master br0
> + /home/iproute2/bridge/bridge vlan add dev br0 vid 1-3 self
> + /home/iproute2/bridge/bridge vlan global set dev br0 vid 2 msti 3
> + /home/iproute2/bridge/bridge vlan add dev veth0 vid 1-3
> + /home/iproute2/bridge/bridge mst set dev veth0 msti 3 state 1
> + /home/iproute2/bridge/bridge mst show
> port msti
> veth0 0
> state disabled
> 3
> state listening
>
>
> There is one issue I got (should be kernel issue):
>
> + /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
> Error: MST mode can't be changed while VLANs exist.
>
> If I want disable mst, I got failed as there is VLAN info, which is expected
>
> + /home/iproute2/ip/ip link set veth0 nomaster
> + /home/iproute2/ip/ip link set veth0 master br0
> + /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
> Error: MST mode can't be changed while VLANs exist.
>
> But I got failed again after remove and re-add veth0, is this expected?
> I thought the VLAN info should be cleared after removing.
>
Probably default vlan 1 got added to the port when it was enslaved.
> + /home/iproute2/ip/ip link set veth0 nomaster
> + /home/iproute2/ip/ip link set br0 type bridge mst_enabled 0
>
> It works after I remove veth0.
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states
2024-06-24 13:00 ` [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states Tobias Waldekranz
2024-06-26 6:21 ` Nikolay Aleksandrov
@ 2024-06-27 16:56 ` Stephen Hemminger
1 sibling, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2024-06-27 16:56 UTC (permalink / raw)
To: Tobias Waldekranz; +Cc: dsahern, liuhangbin, netdev
Please resolve the following issue.
> +static int mst_set(int argc, char **argv)
> +{
> + struct {
> + struct nlmsghdr n;
> + struct ifinfomsg ifi;
> + char buf[512];
> + } req = {
> + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
> + .n.nlmsg_flags = NLM_F_REQUEST,
> + .n.nlmsg_type = RTM_SETLINK,
> + .ifi.ifi_family = PF_BRIDGE,
> + };
> + char *d = NULL, *m = NULL, *s = NULL, *endptr;
> + struct rtattr *af_spec, *mst, *entry;
> + __u16 msti;
> + __u8 state;
> +
> + while (argc > 0) {
> + if (strcmp(*argv, "dev") == 0) {
> + NEXT_ARG();
> + d = *argv;
> + } else if (strcmp(*argv, "msti") == 0) {
> + NEXT_ARG();
> + m = *argv;
> + } else if (strcmp(*argv, "state") == 0) {
> + NEXT_ARG();
> + s = *argv;
> + } else {
> + if (matches(*argv, "help") == 0)
> + usage();
> + }
> + argc--; argv++;
> + }
> +
> + if (d == NULL || m == NULL || s == NULL) {
> + fprintf(stderr, "Device, MSTI and state are required arguments.\n");
> + return -1;
> + }
> +
> + req.ifi.ifi_index = ll_name_to_index(d);
> + if (!req.ifi.ifi_index)
> + return nodev(d);
> +
> + msti = strtol(m, &endptr, 10);
> + if (!(*s != '\0' && *endptr == '\0')) {
> + fprintf(stderr,
> + "Error: invalid MSTI\n");
> + return -1;
> + }
> +
> + state = strtol(s, &endptr, 10);
> + if (!(*s != '\0' && *endptr == '\0')) {
> + state = parse_stp_state(s);
> + if (state == -1) {
> + fprintf(stderr,
> + "Error: invalid STP port state\n");
> + return -1;
>
Building with clang shows this problem.
CC mst.o
mst.c:215:13: warning: result of comparison of constant -1 with expression of type '__u8' (aka 'unsigned char') is always false [-Wtautological-constant-out-of-range-compare]
if (state == -1) {
~~~~~ ^ ~~
1 warning generated.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-06-27 16:56 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-24 13:00 [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Tobias Waldekranz
2024-06-24 13:00 ` [PATCH v2 iproute2 1/3] ip: bridge: add support for mst_enabled Tobias Waldekranz
2024-06-26 2:04 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
2024-06-24 13:00 ` [PATCH v2 iproute2 2/3] bridge: vlan: Add support for setting a VLANs MSTI Tobias Waldekranz
2024-06-26 2:08 ` Hangbin Liu
2024-06-26 6:12 ` Nikolay Aleksandrov
2024-06-24 13:00 ` [PATCH v2 iproute2 3/3] bridge: mst: Add get/set support for MST states Tobias Waldekranz
2024-06-26 6:21 ` Nikolay Aleksandrov
2024-06-27 16:56 ` Stephen Hemminger
2024-06-26 6:11 ` [PATCH v2 iproute2 0/3] Multiple Spanning Tree (MST) Support Nikolay Aleksandrov
2024-06-26 6:33 ` Tobias Waldekranz
2024-06-26 6:47 ` Hangbin Liu
2024-06-26 6:50 ` Nikolay Aleksandrov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).