[Bridge] [PATCH net v2 2/2] bridge: mrp: Validate when setting the port role
This patch adds specific checks for primary(0x0) and secondary(0x1) when setting the port role. For any other value the function 'br_mrp_set_port_role' will return -EINVAL. Fixes: 20f6a05ef63594 ("bridge: mrp: Rework the MRP netlink interface") Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 24986ec7d38cc..779e1eb754430 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -411,10 +411,16 @@ int br_mrp_set_port_role(struct net_bridge_port *p, if (!mrp) return -EINVAL; - if (role == BR_MRP_PORT_ROLE_PRIMARY) + switch (role) { + case BR_MRP_PORT_ROLE_PRIMARY: rcu_assign_pointer(mrp->p_port, p); - else + break; + case BR_MRP_PORT_ROLE_SECONDARY: rcu_assign_pointer(mrp->s_port, p); + break; + default: + return -EINVAL; + } br_mrp_port_switchdev_set_role(p, role); -- 2.26.2
[Bridge] [PATCH net v2 0/2] bridge: mrp: Update MRP_PORT_ROLE
This patch series does the following: - fixes the enum br_mrp_port_role_type. It removes the port role none(0x2) because this is in conflict with the standard. The standard defines the interconnect port role as value 0x2. - adds checks regarding current defined port roles: primary(0x0) and secondary(0x1). v2: - add the validation code when setting the port role. Horatiu Vultur (2): bridge: uapi: mrp: Fix MRP_PORT_ROLE bridge: mrp: Validate when setting the port role include/uapi/linux/mrp_bridge.h | 1 - net/bridge/br_mrp.c | 10 -- 2 files changed, 8 insertions(+), 3 deletions(-) -- 2.26.2
[Bridge] [PATCH net v2 1/2] bridge: uapi: mrp: Fix MRP_PORT_ROLE
Currently the MRP_PORT_ROLE_NONE has the value 0x2 but this is in conflict with the IEC 62439-2 standard. The standard defines the following port roles: primary (0x0), secondary(0x1), interconnect(0x2). Therefore remove the port role none. Fixes: 4714d13791f831 ("bridge: uapi: mrp: Add mrp attributes.") Signed-off-by: Horatiu Vultur --- include/uapi/linux/mrp_bridge.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index 84f15f48a7cb1..bee3665402129 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -36,7 +36,6 @@ enum br_mrp_port_state_type { enum br_mrp_port_role_type { BR_MRP_PORT_ROLE_PRIMARY, BR_MRP_PORT_ROLE_SECONDARY, - BR_MRP_PORT_ROLE_NONE, }; enum br_mrp_tlv_header_type { -- 2.26.2
[Bridge] [PATCH net-next] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
In case the userspace daemon dies, then when is restarted it doesn't know if there are any MRP instances in the kernel. Therefore extend the netlink interface to allow the daemon to clear all MRP instances when is started. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 8 net/bridge/br_mrp.c| 15 +++ net/bridge/br_mrp_netlink.c| 26 ++ net/bridge/br_private_mrp.h| 1 + 4 files changed, 50 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..2ae7d0c0d46b8 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_CLEAR, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,13 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_CLEAR_UNSPEC, + __IFLA_BRIDGE_MRP_CLEAR_MAX, +}; + +#define IFLA_BRIDGE_MRP_CLEAR_MAX (__IFLA_BRIDGE_MRP_CLEAR_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 24986ec7d38cc..02d102edd 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -372,6 +372,21 @@ int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance) return 0; } +/* Deletes all MRP instances on the bridge + * note: called under rtnl_lock + */ +int br_mrp_clear(struct net_bridge *br) +{ + struct br_mrp *mrp; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { + br_mrp_del_impl(br, mrp); + } + + return 0; +} + /* Set port state, port state can be forwarding, blocked or disabled * note: already called with rtnl_lock */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..5e743538464f6 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,7 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_CLEAR] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +236,25 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_clear_policy[IFLA_BRIDGE_MRP_CLEAR_MAX + 1] = { + [IFLA_BRIDGE_MRP_CLEAR_UNSPEC] = { .type = NLA_REJECT }, +}; + +static int br_mrp_clear_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_CLEAR_MAX, attr, + br_mrp_clear_policy, extack); + if (err) + return err; + + return br_mrp_clear(br); +} + int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) { @@ -301,6 +321,12 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return err; } + if (tb[IFLA_BRIDGE_MRP_CLEAR]) { + err = br_mrp_clear_parse(br, tb[IFLA_BRIDGE_MRP_CLEAR], extack); + if (err) + return err; + } + return 0; } diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..25c3b8596c25b 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -36,6 +36,7 @@ struct br_mrp { /* br_mrp.c */ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance); int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance); +int br_mrp_clear(struct net_bridge *br); int br_mrp_set_port_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_set_port_role(struct net_bridge_port *p, -- 2.26.2
Re: [Bridge] [PATCH net-next] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
The 06/24/2020 11:19, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 24/06/2020 11:05, Horatiu Vultur wrote: > > In case the userspace daemon dies, then when is restarted it doesn't > > know if there are any MRP instances in the kernel. Therefore extend the > > netlink interface to allow the daemon to clear all MRP instances when is > > started. > > > > Signed-off-by: Horatiu Vultur > > --- > > include/uapi/linux/if_bridge.h | 8 > > net/bridge/br_mrp.c| 15 +++ > > net/bridge/br_mrp_netlink.c| 26 ++ > > net/bridge/br_private_mrp.h| 1 + > > 4 files changed, 50 insertions(+) > > > > diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h > > index caa6914a3e53a..2ae7d0c0d46b8 100644 > > --- a/include/uapi/linux/if_bridge.h > > +++ b/include/uapi/linux/if_bridge.h > > @@ -166,6 +166,7 @@ enum { > > IFLA_BRIDGE_MRP_RING_STATE, > > IFLA_BRIDGE_MRP_RING_ROLE, > > IFLA_BRIDGE_MRP_START_TEST, > > + IFLA_BRIDGE_MRP_CLEAR, > > __IFLA_BRIDGE_MRP_MAX, > > }; > > > > @@ -228,6 +229,13 @@ enum { > > > > #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - > > 1) > > > > +enum { > > + IFLA_BRIDGE_MRP_CLEAR_UNSPEC, > > + __IFLA_BRIDGE_MRP_CLEAR_MAX, > > +}; > > Out of curiousity - do you plan to have any clean attributes? > In case you don't this can simply be a flag that clears the MRP instances > instead > of a nested attribute. Currently I don't plan to add any clean attributes. But I have used the nested attribute just in case in the future something will be needed. > > > + > > +#define IFLA_BRIDGE_MRP_CLEAR_MAX (__IFLA_BRIDGE_MRP_CLEAR_MAX - 1) > > + > > struct br_mrp_instance { > > __u32 ring_id; > > __u32 p_ifindex; > > diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c > > index 24986ec7d38cc..02d102edd 100644 > > --- a/net/bridge/br_mrp.c > > +++ b/net/bridge/br_mrp.c > > @@ -372,6 +372,21 @@ int br_mrp_del(struct net_bridge *br, struct > > br_mrp_instance *instance) > > return 0; > > } > > > > +/* Deletes all MRP instances on the bridge > > + * note: called under rtnl_lock > > + */ > > +int br_mrp_clear(struct net_bridge *br) > > +{ > > + struct br_mrp *mrp; > > + > > + list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > + lockdep_rtnl_is_held()) { > > + br_mrp_del_impl(br, mrp); > > I don't think you're in RCU-protected region here, as the lockdep above > confirms, which > means br_mrp_del_impl() can free mrp and you can access freed memory while > walking the list > (trying to access of the next element). > > You should be using list_for_each_entry_safe() to delete elements while > walking the list. Good catch! I will update in the next version. > > Cheers, > Nik > > > + } > > + > > + return 0; > > +} > > + > > /* Set port state, port state can be forwarding, blocked or disabled > > * note: already called with rtnl_lock > > */ > > diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c > > index 34b3a8776991f..5e743538464f6 100644 > > --- a/net/bridge/br_mrp_netlink.c > > +++ b/net/bridge/br_mrp_netlink.c > > @@ -14,6 +14,7 @@ static const struct nla_policy > > br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { > > [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, > > [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, > > [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, > > + [IFLA_BRIDGE_MRP_CLEAR] = { .type = NLA_NESTED }, > > }; > > > > static const struct nla_policy > > @@ -235,6 +236,25 @@ static int br_mrp_start_test_parse(struct net_bridge > > *br, struct nlattr *attr, > > return br_mrp_start_test(br, &test); > > } > > > > +static const struct nla_policy > > +br_mrp_clear_policy[IFLA_BRIDGE_MRP_CLEAR_MAX + 1] = { > > + [IFLA_BRIDGE_MRP_CLEAR_UNSPEC] = { .type = NLA_REJECT }, > > +}; > > + > > +static int br_mrp_clear_parse(struct net_bridge *br, struct nlattr *attr, > > + struct netlink_ext_ack *extack) > > +{ > > + struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; > > + int err; > > + > > + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_CLEAR_MAX, attr, > > +br_mrp_clear_policy, extack); > > + if (err) > > + return err; > > + > > + return br_mrp_clear(br); > > +} > > + > > int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, > >struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) > > { > > @@ -301,6 +321,12 @@ int br_mrp_parse(struct net_bridge *br, struct > > net_bridge_port *p, > > return err; > > } > > > > + if (tb[IFLA_BRIDGE_MRP_CLEAR]) { > > + err = br_mrp_clear_parse(br, tb[IFLA_BRIDGE_MRP_CLEAR], > > ex
Re: [Bridge] [PATCH net v2 0/2] bridge: mrp: Update MRP_PORT_ROLE
The 06/23/2020 14:38, David Miller wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > From: Horatiu Vultur > Date: Tue, 23 Jun 2020 11:05:39 +0200 > > > This patch series does the following: > > - fixes the enum br_mrp_port_role_type. It removes the port role none(0x2) > > because this is in conflict with the standard. The standard defines the > > interconnect port role as value 0x2. > > - adds checks regarding current defined port roles: primary(0x0) and > > secondary(0x1). > > > > v2: > > - add the validation code when setting the port role. > > Series applied, thank you. Thanks. Will these patches be applied also on net-next? Because if I start now to add support for the interconnect port, these patches are needed on net-next. Or do I need to add these patches to the patch series for the interconnect port? What is the correct way of doing this? -- /Horatiu
[Bridge] [PATCH net-next v2] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
In case the userspace daemon dies, then when is restarted it doesn't know if there are any MRP instances in the kernel. Therefore extend the netlink interface to allow the daemon to clear all MRP instances when is started. Signed-off-by: Horatiu Vultur --- v2: - use list_for_each_entry_safe instead of list_for_each_entry_rcu when deleting mrp instances --- include/uapi/linux/if_bridge.h | 8 net/bridge/br_mrp.c| 15 +++ net/bridge/br_mrp_netlink.c| 26 ++ net/bridge/br_private_mrp.h| 1 + 4 files changed, 50 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..2ae7d0c0d46b8 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_CLEAR, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,13 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_CLEAR_UNSPEC, + __IFLA_BRIDGE_MRP_CLEAR_MAX, +}; + +#define IFLA_BRIDGE_MRP_CLEAR_MAX (__IFLA_BRIDGE_MRP_CLEAR_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 24986ec7d38cc..02da4e22d277a 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -372,6 +372,21 @@ int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance) return 0; } +/* Deletes all MRP instances on the bridge + * note: called under rtnl_lock + */ +int br_mrp_clear(struct net_bridge *br) +{ + struct br_mrp *mrp; + struct br_mrp *tmp; + + list_for_each_entry_safe(mrp, tmp, &br->mrp_list, list) { + br_mrp_del_impl(br, mrp); + } + + return 0; +} + /* Set port state, port state can be forwarding, blocked or disabled * note: already called with rtnl_lock */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..5e743538464f6 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,7 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_CLEAR] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +236,25 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_clear_policy[IFLA_BRIDGE_MRP_CLEAR_MAX + 1] = { + [IFLA_BRIDGE_MRP_CLEAR_UNSPEC] = { .type = NLA_REJECT }, +}; + +static int br_mrp_clear_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_CLEAR_MAX, attr, + br_mrp_clear_policy, extack); + if (err) + return err; + + return br_mrp_clear(br); +} + int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) { @@ -301,6 +321,12 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return err; } + if (tb[IFLA_BRIDGE_MRP_CLEAR]) { + err = br_mrp_clear_parse(br, tb[IFLA_BRIDGE_MRP_CLEAR], extack); + if (err) + return err; + } + return 0; } diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..25c3b8596c25b 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -36,6 +36,7 @@ struct br_mrp { /* br_mrp.c */ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance); int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance); +int br_mrp_clear(struct net_bridge *br); int br_mrp_set_port_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_set_port_role(struct net_bridge_port *p, -- 2.26.2
Re: [Bridge] [PATCH net-next v2] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
The 06/25/2020 15:17, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 25/06/2020 15:03, kernel test robot wrote: > > Hi Horatiu, > > > > Thank you for the patch! Perhaps something to improve: > > > Hi Nik, > Hi, > I think you should drop the __rcu tag for the mrp_list member and also > from the "list" member of struct br_mrp to fix most of the below. > > Cheers, > Nik Thanks, your suggestion worked. I really had problems understanding these sparse warnings. I will move this patch in a patch series where I will fix also these warnings. > > > [auto build test WARNING on net-next/master] > > > > url: > > https://github.com/0day-ci/linux/commits/Horatiu-Vultur/bridge-mrp-Extend-MRP-netlink-interface-with-IFLA_BRIDGE_MRP_CLEAR/20200625-150941 > > base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git > > 147373d968f1c1b5d6bb71e4e8b7495eeb9cdcae > > config: i386-randconfig-s001-20200624 (attached as .config) > > compiler: gcc-9 (Debian 9.3.0-13) 9.3.0 > > reproduce: > > # apt-get install sparse > > # sparse version: v0.6.2-dirty > > # save the attached .config to linux build tree > > make W=1 C=1 ARCH=i386 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' > > > > If you fix the issue, kindly add following tag as appropriate > > Reported-by: kernel test robot > > > > > > sparse warnings: (new ones prefixed by >>) > > > >net/bridge/br_mrp.c:106:18: sparse: sparse: incorrect type in assignment > > (different base types) @@ expected unsigned short [usertype] @@ got > > restricted __be16 [usertype] @@ > >net/bridge/br_mrp.c:106:18: sparse: expected unsigned short > > [usertype] > >net/bridge/br_mrp.c:106:18: sparse: got restricted __be16 [usertype] > >net/bridge/br_mrp.c:281:23: sparse: sparse: incorrect type in argument 1 > > (different modifiers) @@ expected struct list_head *entry @@ got > > struct list_head [noderef] * @@ > >net/bridge/br_mrp.c:281:23: sparse: expected struct list_head *entry > >net/bridge/br_mrp.c:281:23: sparse: got struct list_head [noderef] * > >net/bridge/br_mrp.c:332:28: sparse: sparse: incorrect type in argument 1 > > (different modifiers) @@ expected struct list_head *new @@ got > > struct list_head [noderef] * @@ > >net/bridge/br_mrp.c:332:28: sparse: expected struct list_head *new > >net/bridge/br_mrp.c:332:28: sparse: got struct list_head [noderef] * > >net/bridge/br_mrp.c:332:40: sparse: sparse: incorrect type in argument 2 > > (different modifiers) @@ expected struct list_head *head @@ got > > struct list_head [noderef] * @@ > >net/bridge/br_mrp.c:332:40: sparse: expected struct list_head *head > >net/bridge/br_mrp.c:332:40: sparse: got struct list_head [noderef] * > >net/bridge/br_mrp.c:691:29: sparse: sparse: incorrect type in argument 1 > > (different modifiers) @@ expected struct list_head const *head @@ > > got struct list_head [noderef] * @@ > >net/bridge/br_mrp.c:691:29: sparse: expected struct list_head const > > *head > >net/bridge/br_mrp.c:691:29: sparse: got struct list_head [noderef] * > >>> net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef > >>> expression > >>> net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef > >>> expression > >>> net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef > >>> expression > > > > vim +383 net/bridge/br_mrp.c > > > >284 > >285/* Adds a new MRP instance. > >286 * note: called under rtnl_lock > >287 */ > >288int br_mrp_add(struct net_bridge *br, struct br_mrp_instance > > *instance) > >289{ > >290struct net_bridge_port *p; > >291struct br_mrp *mrp; > >292int err; > >293 > >294/* If the ring exists, it is not possible to create > > another one with the > >295 * same ring_id > >296 */ > >297mrp = br_mrp_find_id(br, instance->ring_id); > >298if (mrp) > >299return -EINVAL; > >300 > >301if (!br_mrp_get_port(br, instance->p_ifindex) || > >302!br_mrp_get_port(br, instance->s_ifindex)) > >303return -EINVAL; > >304 > >305/* It is not possible to have the same port part of > > multiple rings */ > >306if (!br_mrp_unique_ifindex(br, instance->p_ifindex) || > >307!br_mrp_unique_ifindex(br, instance->s_ifindex)) > >308return -EINVAL; > >309 > >310mrp = kzalloc(sizeof(*mrp), GFP_KERNEL); > >311if (!mrp) > >312return -ENOMEM; > >
[Bridge] [PATCH net-next v3 0/2] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
This patch series extends MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR. To allow the userspace to clear all MRP instances when is started. The second patch in the series fix different sparse warnings. v3: - add the second patch to fix sparse warnings v2: - use list_for_each_entry_safe instead of list_for_each_entry_rcu when deleting mrp instances Horatiu Vultur (2): bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR bridge: mrp: Fix endian conversion and some other warnings include/uapi/linux/if_bridge.h | 8 net/bridge/br_mrp.c| 17 - net/bridge/br_mrp_netlink.c| 26 ++ net/bridge/br_private.h| 2 +- net/bridge/br_private_mrp.h| 3 ++- 5 files changed, 53 insertions(+), 3 deletions(-) -- 2.26.2
[Bridge] [PATCH net-next v3 1/2] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
In case the userspace daemon dies, then when is restarted it doesn't know if there are any MRP instances in the kernel. Therefore extend the netlink interface to allow the daemon to clear all MRP instances when is started. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 8 net/bridge/br_mrp.c| 15 +++ net/bridge/br_mrp_netlink.c| 26 ++ net/bridge/br_private_mrp.h| 1 + 4 files changed, 50 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..2ae7d0c0d46b8 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_CLEAR, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,13 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_CLEAR_UNSPEC, + __IFLA_BRIDGE_MRP_CLEAR_MAX, +}; + +#define IFLA_BRIDGE_MRP_CLEAR_MAX (__IFLA_BRIDGE_MRP_CLEAR_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 779e1eb754430..dcbf21b91313d 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -372,6 +372,21 @@ int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance) return 0; } +/* Deletes all MRP instances on the bridge + * note: called under rtnl_lock + */ +int br_mrp_clear(struct net_bridge *br) +{ + struct br_mrp *mrp; + struct br_mrp *tmp; + + list_for_each_entry_safe(mrp, tmp, &br->mrp_list, list) { + br_mrp_del_impl(br, mrp); + } + + return 0; +} + /* Set port state, port state can be forwarding, blocked or disabled * note: already called with rtnl_lock */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..5e743538464f6 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,7 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_CLEAR] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +236,25 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_clear_policy[IFLA_BRIDGE_MRP_CLEAR_MAX + 1] = { + [IFLA_BRIDGE_MRP_CLEAR_UNSPEC] = { .type = NLA_REJECT }, +}; + +static int br_mrp_clear_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_CLEAR_MAX, attr, + br_mrp_clear_policy, extack); + if (err) + return err; + + return br_mrp_clear(br); +} + int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) { @@ -301,6 +321,12 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return err; } + if (tb[IFLA_BRIDGE_MRP_CLEAR]) { + err = br_mrp_clear_parse(br, tb[IFLA_BRIDGE_MRP_CLEAR], extack); + if (err) + return err; + } + return 0; } diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..25c3b8596c25b 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -36,6 +36,7 @@ struct br_mrp { /* br_mrp.c */ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance); int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance); +int br_mrp_clear(struct net_bridge *br); int br_mrp_set_port_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_set_port_role(struct net_bridge_port *p, -- 2.26.2
[Bridge] [PATCH net-next v3 2/2] bridge: mrp: Fix endian conversion and some other warnings
The following sparse warnings are fixed: net/bridge/br_mrp.c:106:18: warning: incorrect type in assignment (different base types) net/bridge/br_mrp.c:106:18:expected unsigned short [usertype] net/bridge/br_mrp.c:106:18:got restricted __be16 [usertype] net/bridge/br_mrp.c:281:23: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:281:23:expected struct list_head *entry net/bridge/br_mrp.c:281:23:got struct list_head [noderef] * net/bridge/br_mrp.c:332:28: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:332:28:expected struct list_head *new net/bridge/br_mrp.c:332:28:got struct list_head [noderef] * net/bridge/br_mrp.c:332:40: warning: incorrect type in argument 2 (different modifiers) net/bridge/br_mrp.c:332:40:expected struct list_head *head net/bridge/br_mrp.c:332:40:got struct list_head [noderef] * net/bridge/br_mrp.c:691:29: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:691:29:expected struct list_head const *head net/bridge/br_mrp.c:691:29:got struct list_head [noderef] * net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef expression net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef expression net/bridge/br_mrp.c:383:9: sparse: sparse: dereference of noderef expression Reported-by: kernel test robot Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 2 +- net/bridge/br_private.h | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index dcbf21b91313d..7541482898642 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -86,7 +86,7 @@ static struct sk_buff *br_mrp_skb_alloc(struct net_bridge_port *p, { struct ethhdr *eth_hdr; struct sk_buff *skb; - u16 *version; + __be16 *version; skb = dev_alloc_skb(MRP_MAX_FRAME_LENGTH); if (!skb) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6a7d8e218ae7e..bbffbaac1beb6 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -434,7 +434,7 @@ struct net_bridge { struct hlist_head fdb_list; #if IS_ENABLED(CONFIG_BRIDGE_MRP) - struct list_head__rcu mrp_list; + struct list_headmrp_list; #endif }; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 25c3b8596c25b..3243a2cc3a729 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -8,7 +8,7 @@ struct br_mrp { /* list of mrp instances */ - struct list_head__rcu list; + struct list_headlist; struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; -- 2.26.2
Re: [Bridge] [PATCH net-next v3 0/2] bridge: mrp: Extend MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR
The 06/26/2020 13:00, David Miller wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > From: Horatiu Vultur > Date: Fri, 26 Jun 2020 09:33:47 +0200 > > > This patch series extends MRP netlink interface with IFLA_BRIDGE_MRP_CLEAR. > > To allow the userspace to clear all MRP instances when is started. The > > second patch in the series fix different sparse warnings. > > > > v3: > > - add the second patch to fix sparse warnings Hi, > > These changes are completely unrelated. > > The sparse stuff should probably be submitted to 'net'. I will send a patch for this to 'net'. > > And I have to ask why you really need a clear operation. Because we didn't have any way for the userspace to know what ports are part of the MRP ring. I thought the easiest way would be for the daemon to clear everything when is started. > Routing > daemons come up and see what routes are installed, and update their > internal SW tables to match. This not only allows efficient restart > after a crash, but it also allows multiple daemons to work > cooperatively as an agent for the same forwarding/routing table. I think it would be possible to have something similar for the MRP daemon. But I still have problems to see how to have multiple MRP daemons running at the same time. Because each deamon implements MRP state machine. So for example if the link of one of the MRP ports is changing then each daemon is notified about this change so then each daemon will send some frames, and that would mean that we have duplicate frames in the network. > > Your usage model limits one daemon to manage the table and that > limitation is completely unnecessary. > > Furthermore, even in a one-daemon scenerio, it's wasteful to throw > away all the work the previous daemon did to load the MRP entries into > the bridge. > > Thanks. > -- /Horatiu
[Bridge] [PATCH net] bridge: mrp: Fix endian conversion and some other warnings
The following sparse warnings are fixed: net/bridge/br_mrp.c:106:18: warning: incorrect type in assignment (different base types) net/bridge/br_mrp.c:106:18:expected unsigned short [usertype] net/bridge/br_mrp.c:106:18:got restricted __be16 [usertype] net/bridge/br_mrp.c:281:23: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:281:23:expected struct list_head *entry net/bridge/br_mrp.c:281:23:got struct list_head [noderef] * net/bridge/br_mrp.c:332:28: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:332:28:expected struct list_head *new net/bridge/br_mrp.c:332:28:got struct list_head [noderef] * net/bridge/br_mrp.c:332:40: warning: incorrect type in argument 2 (different modifiers) net/bridge/br_mrp.c:332:40:expected struct list_head *head net/bridge/br_mrp.c:332:40:got struct list_head [noderef] * net/bridge/br_mrp.c:682:29: warning: incorrect type in argument 1 (different modifiers) net/bridge/br_mrp.c:682:29:expected struct list_head const *head net/bridge/br_mrp.c:682:29:got struct list_head [noderef] * Reported-by: kernel test robot Fixes: 2f1a11ae11d222 ("bridge: mrp: Add MRP interface.") Fixes: 4b8d7d4c599182 ("bridge: mrp: Extend bridge interface") Fixes: 9a9f26e8f7ea30 ("bridge: mrp: Connect MRP API with the switchdev API") Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 2 +- net/bridge/br_private.h | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 779e1eb754430..90592af9db619 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -86,7 +86,7 @@ static struct sk_buff *br_mrp_skb_alloc(struct net_bridge_port *p, { struct ethhdr *eth_hdr; struct sk_buff *skb; - u16 *version; + __be16 *version; skb = dev_alloc_skb(MRP_MAX_FRAME_LENGTH); if (!skb) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2130fe0194e64..e0ea6dbbc97ed 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -430,7 +430,7 @@ struct net_bridge { struct hlist_head fdb_list; #if IS_ENABLED(CONFIG_BRIDGE_MRP) - struct list_head__rcu mrp_list; + struct list_headmrp_list; #endif }; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..315eb37d89f0f 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -8,7 +8,7 @@ struct br_mrp { /* list of mrp instances */ - struct list_head__rcu list; + struct list_headlist; struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; -- 2.26.2
[Bridge] [PATCH net-next 1/3] bridge: uapi: mrp: Extend MRP attributes to get the status
Add MRP attribute IFLA_BRIDGE_MRP_INFO to allow the userspace to get the current state of the MRP instances. This is a nested attribute that contains other attributes like, ring id, index of primary and secondary port, priority, ring state, ring role. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 17 + 1 file changed, 17 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..c114c1c2bd533 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_INFO, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,22 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_INFO_UNSPEC, + IFLA_BRIDGE_MRP_INFO_RING_ID, + IFLA_BRIDGE_MRP_INFO_P_IFINDEX, + IFLA_BRIDGE_MRP_INFO_S_IFINDEX, + IFLA_BRIDGE_MRP_INFO_PRIO, + IFLA_BRIDGE_MRP_INFO_RING_STATE, + IFLA_BRIDGE_MRP_INFO_RING_ROLE, + IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + __IFLA_BRIDGE_MRP_INFO_MAX, +}; + +#define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; -- 2.27.0
[Bridge] [PATCH net-next 3/3] bridge: Extend br_fill_ifinfo to return MPR status
This patch extends the function br_fill_ifinfo to return also the MRP status for each instance on a bridge. It also adds a new filter RTEXT_FILTER_MRP to return the MRP status only when this is set, not to interfer with the vlans. The MRP status is return only on the bridge interfaces. Signed-off-by: Horatiu Vultur --- include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_netlink.c| 29 - 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 879e64950a0a2..9b814c92de123 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -778,6 +778,7 @@ enum { #define RTEXT_FILTER_BRVLAN(1 << 1) #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) #defineRTEXT_FILTER_SKIP_STATS (1 << 3) +#define RTEXT_FILTER_MRP (1 << 4) /* End of information exported to user level */ diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 240e260e3461c..6ecb7c7453dcb 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -453,6 +453,32 @@ static int br_fill_ifinfo(struct sk_buff *skb, rcu_read_unlock(); if (err) goto nla_put_failure; + + nla_nest_end(skb, af); + } + + if (filter_mask & RTEXT_FILTER_MRP) { + struct nlattr *af; + int err; + + /* RCU needed because of the VLAN locking rules (rcu || rtnl) */ + rcu_read_lock(); + if (!br_mrp_enabled(br) || port) { + rcu_read_unlock(); + goto done; + } + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); + if (!af) { + rcu_read_unlock(); + goto nla_put_failure; + } + + err = br_mrp_fill_info(skb, br); + + rcu_read_unlock(); + if (err) + goto nla_put_failure; + nla_nest_end(skb, af); } @@ -516,7 +542,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_bridge_port *port = br_port_get_rtnl(dev); if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && - !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) + !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) && + !(filter_mask & RTEXT_FILTER_MRP)) return 0; return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, -- 2.27.0
[Bridge] [PATCH net-next 0/3] bridge: mrp: Add support for getting the status
This patch series extends the MRP netlink interface to allow the userspace daemon to get the status of the MRP instances in the kernel. Horatiu Vultur (3): bridge: uapi: mrp: Extend MRP attributes to get the status bridge: mrp: Add br_mrp_fill_info bridge: Extend br_fill_ifinfo to return MPR status include/uapi/linux/if_bridge.h | 17 ++ include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_mrp_netlink.c| 57 ++ net/bridge/br_netlink.c| 29 - net/bridge/br_private.h| 7 + 5 files changed, 110 insertions(+), 1 deletion(-) -- 2.27.0
[Bridge] [PATCH net-next 2/3] bridge: mrp: Add br_mrp_fill_info
Add the function br_mrp_fill_info which populates the MRP attributes regarding the status of each MRP instance. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 57 + net/bridge/br_private.h | 7 + 2 files changed, 64 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..c7dd0cc5b90e5 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -304,6 +304,63 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return 0; } +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + struct nlattr *tb, *mrp_tb; + struct br_mrp *mrp; + + mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); + if (!mrp_tb) + return -EMSGSIZE; + + list_for_each_entry(mrp, &br->mrp_list, list) { + tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); + if (!tb) + goto nla_info_failure; + + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID, + mrp->ring_id)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX, + mrp->p_port->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX, + mrp->s_port->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, + mrp->prio)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE, + mrp->ring_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE, + mrp->ring_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + mrp->test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + mrp->test_max_miss)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + mrp->test_monitor)) + goto nla_put_failure; + + nla_nest_end(skb, tb); + } + nla_nest_end(skb, mrp_tb); + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, tb); + +nla_info_failure: + nla_nest_cancel(skb, mrp_tb); + + return -EMSGSIZE; +} + int br_mrp_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6a7d8e218ae7e..65d2c163a24ab 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1317,6 +1317,7 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb); bool br_mrp_enabled(struct net_bridge *br); void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p); +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br); #else static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, @@ -1339,6 +1340,12 @@ static inline void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p) { } + +static inline int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + return 0; +} + #endif /* br_netlink.c */ -- 2.27.0
Re: [Bridge] [PATCH net-next 2/3] bridge: mrp: Add br_mrp_fill_info
The 06/30/2020 09:12, Jakub Kicinski wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On Tue, 30 Jun 2020 15:44:23 +0200 Horatiu Vultur wrote: > > Add the function br_mrp_fill_info which populates the MRP attributes > > regarding the status of each MRP instance. > > > > Signed-off-by: Horatiu Vultur > > This adds warnings when built with W=1 C=1: The warnings at line 316 will be fixed once net will be merged into net-next. But I need to fix the others. > > net/bridge/br_mrp_netlink.c:316:9: warning: dereference of noderef expression > net/bridge/br_mrp_netlink.c:325:36: warning: dereference of noderef expression > net/bridge/br_mrp_netlink.c:328:36: warning: dereference of noderef expression > net/bridge/br_mrp_netlink.c:316:9: warning: dereference of noderef expression -- /Horatiu
[Bridge] [PATCH net-next v2 0/3] bridge: mrp: Add support for getting the status
This patch series extends the MRP netlink interface to allow the userspace daemon to get the status of the MRP instances in the kernel. v2: - fix sparse warnings Horatiu Vultur (3): bridge: uapi: mrp: Extend MRP attributes to get the status bridge: mrp: Add br_mrp_fill_info bridge: Extend br_fill_ifinfo to return MPR status include/uapi/linux/if_bridge.h | 17 + include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_mrp_netlink.c| 64 ++ net/bridge/br_netlink.c| 29 ++- net/bridge/br_private.h| 7 5 files changed, 117 insertions(+), 1 deletion(-) -- 2.27.0
[Bridge] [PATCH net-next v2 0/3] bridge: mrp: Add support for getting the status
This patch series extends the MRP netlink interface to allow the userspace daemon to get the status of the MRP instances in the kernel. v2: - fix sparse warnings Horatiu Vultur (3): bridge: uapi: mrp: Extend MRP attributes to get the status bridge: mrp: Add br_mrp_fill_info bridge: Extend br_fill_ifinfo to return MPR status include/uapi/linux/if_bridge.h | 17 + include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_mrp_netlink.c| 64 ++ net/bridge/br_netlink.c| 29 ++- net/bridge/br_private.h| 7 5 files changed, 117 insertions(+), 1 deletion(-) -- 2.27.0
[Bridge] [PATCH net-next v2 1/3] bridge: uapi: mrp: Extend MRP attributes to get the status
Add MRP attribute IFLA_BRIDGE_MRP_INFO to allow the userspace to get the current state of the MRP instances. This is a nested attribute that contains other attributes like, ring id, index of primary and secondary port, priority, ring state, ring role. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 17 + 1 file changed, 17 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..c114c1c2bd533 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_INFO, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,22 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_INFO_UNSPEC, + IFLA_BRIDGE_MRP_INFO_RING_ID, + IFLA_BRIDGE_MRP_INFO_P_IFINDEX, + IFLA_BRIDGE_MRP_INFO_S_IFINDEX, + IFLA_BRIDGE_MRP_INFO_PRIO, + IFLA_BRIDGE_MRP_INFO_RING_STATE, + IFLA_BRIDGE_MRP_INFO_RING_ROLE, + IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + __IFLA_BRIDGE_MRP_INFO_MAX, +}; + +#define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; -- 2.27.0
[Bridge] [PATCH net-next v2 2/3] bridge: mrp: Add br_mrp_fill_info
Add the function br_mrp_fill_info which populates the MRP attributes regarding the status of each MRP instance. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 64 + net/bridge/br_private.h | 7 2 files changed, 71 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..c4e80844e53bd 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -304,6 +304,70 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return 0; } +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + struct nlattr *tb, *mrp_tb; + struct br_mrp *mrp; + + mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); + if (!mrp_tb) + return -EMSGSIZE; + + list_for_each_entry(mrp, &br->mrp_list, list) { + struct net_bridge_port *p; + + tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); + if (!tb) + goto nla_info_failure; + + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID, + mrp->ring_id)) + goto nla_put_failure; + + p = rtnl_dereference(mrp->p_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + + p = rtnl_dereference(mrp->s_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, + mrp->prio)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE, + mrp->ring_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE, + mrp->ring_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + mrp->test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + mrp->test_max_miss)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + mrp->test_monitor)) + goto nla_put_failure; + + nla_nest_end(skb, tb); + } + nla_nest_end(skb, mrp_tb); + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, tb); + +nla_info_failure: + nla_nest_cancel(skb, mrp_tb); + + return -EMSGSIZE; +} + int br_mrp_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6a7d8e218ae7e..65d2c163a24ab 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1317,6 +1317,7 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb); bool br_mrp_enabled(struct net_bridge *br); void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p); +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br); #else static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, @@ -1339,6 +1340,12 @@ static inline void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p) { } + +static inline int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + return 0; +} + #endif /* br_netlink.c */ -- 2.27.0
[Bridge] [PATCH net-next v2 3/3] bridge: Extend br_fill_ifinfo to return MPR status
This patch extends the function br_fill_ifinfo to return also the MRP status for each instance on a bridge. It also adds a new filter RTEXT_FILTER_MRP to return the MRP status only when this is set, not to interfer with the vlans. The MRP status is return only on the bridge interfaces. Signed-off-by: Horatiu Vultur --- include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_netlink.c| 29 - 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 879e64950a0a2..9b814c92de123 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -778,6 +778,7 @@ enum { #define RTEXT_FILTER_BRVLAN(1 << 1) #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) #defineRTEXT_FILTER_SKIP_STATS (1 << 3) +#define RTEXT_FILTER_MRP (1 << 4) /* End of information exported to user level */ diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 240e260e3461c..6ecb7c7453dcb 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -453,6 +453,32 @@ static int br_fill_ifinfo(struct sk_buff *skb, rcu_read_unlock(); if (err) goto nla_put_failure; + + nla_nest_end(skb, af); + } + + if (filter_mask & RTEXT_FILTER_MRP) { + struct nlattr *af; + int err; + + /* RCU needed because of the VLAN locking rules (rcu || rtnl) */ + rcu_read_lock(); + if (!br_mrp_enabled(br) || port) { + rcu_read_unlock(); + goto done; + } + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); + if (!af) { + rcu_read_unlock(); + goto nla_put_failure; + } + + err = br_mrp_fill_info(skb, br); + + rcu_read_unlock(); + if (err) + goto nla_put_failure; + nla_nest_end(skb, af); } @@ -516,7 +542,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_bridge_port *port = br_port_get_rtnl(dev); if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && - !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) + !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) && + !(filter_mask & RTEXT_FILTER_MRP)) return 0; return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, -- 2.27.0
Re: [Bridge] [PATCH net-next v2 3/3] bridge: Extend br_fill_ifinfo to return MPR status
The 07/01/2020 12:51, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 01/07/2020 10:22, Horatiu Vultur wrote: > > This patch extends the function br_fill_ifinfo to return also the MRP > > status for each instance on a bridge. It also adds a new filter > > RTEXT_FILTER_MRP to return the MRP status only when this is set, not to > > interfer with the vlans. The MRP status is return only on the bridge > > interfaces. > > > > Signed-off-by: Horatiu Vultur > > --- > > include/uapi/linux/rtnetlink.h | 1 + > > net/bridge/br_netlink.c| 29 - > > 2 files changed, 29 insertions(+), 1 deletion(-) > > > > diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h > > index 879e64950a0a2..9b814c92de123 100644 > > --- a/include/uapi/linux/rtnetlink.h > > +++ b/include/uapi/linux/rtnetlink.h > > @@ -778,6 +778,7 @@ enum { > > #define RTEXT_FILTER_BRVLAN (1 << 1) > > #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) > > #define RTEXT_FILTER_SKIP_STATS (1 << 3) > > +#define RTEXT_FILTER_MRP (1 << 4) > > > > /* End of information exported to user level */ > > > > diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c > > index 240e260e3461c..6ecb7c7453dcb 100644 > > --- a/net/bridge/br_netlink.c > > +++ b/net/bridge/br_netlink.c > > @@ -453,6 +453,32 @@ static int br_fill_ifinfo(struct sk_buff *skb, > > rcu_read_unlock(); > > if (err) > > goto nla_put_failure; > > + > > + nla_nest_end(skb, af); > > + } > > + > > + if (filter_mask & RTEXT_FILTER_MRP) { > > + struct nlattr *af; > > + int err; > > + > > + /* RCU needed because of the VLAN locking rules (rcu || rtnl) > > */ > > + rcu_read_lock(); Hi Nik, > > If you're using RCU, then in the previous patch (02) you should be using RCU > primitives > to walk the list and deref the ports. > Alternatively if you rely on rtnl only then drop these RCU locks here as > they're misleading. > > I'd prefer to just use RCU for it in case we drop rtnl one day when dumping. Thanks for the comments. I will create a new series where I will use the RCU. > > > + if (!br_mrp_enabled(br) || port) { > > + rcu_read_unlock(); > > + goto done; > > + } > > + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); > > + if (!af) { > > + rcu_read_unlock(); > > + goto nla_put_failure; > > + } > > + > > + err = br_mrp_fill_info(skb, br); > > + > > + rcu_read_unlock(); > > + if (err) > > + goto nla_put_failure; > > + > > nla_nest_end(skb, af); > > } > > > > @@ -516,7 +542,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, > > struct net_bridge_port *port = br_port_get_rtnl(dev); > > > > if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && > > - !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) > > + !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) && > > + !(filter_mask & RTEXT_FILTER_MRP)) > > return 0; > > > > return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, > > > -- /Horatiu
[Bridge] [PATCH net-next v3 3/3] bridge: Extend br_fill_ifinfo to return MPR status
This patch extends the function br_fill_ifinfo to return also the MRP status for each instance on a bridge. It also adds a new filter RTEXT_FILTER_MRP to return the MRP status only when this is set, not to interfer with the vlans. The MRP status is return only on the bridge interfaces. Signed-off-by: Horatiu Vultur --- include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_netlink.c| 25 - 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 879e64950a0a2..9b814c92de123 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -778,6 +778,7 @@ enum { #define RTEXT_FILTER_BRVLAN(1 << 1) #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) #defineRTEXT_FILTER_SKIP_STATS (1 << 3) +#define RTEXT_FILTER_MRP (1 << 4) /* End of information exported to user level */ diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 240e260e3461c..c532fa65c9834 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -453,6 +453,28 @@ static int br_fill_ifinfo(struct sk_buff *skb, rcu_read_unlock(); if (err) goto nla_put_failure; + + nla_nest_end(skb, af); + } + + if (filter_mask & RTEXT_FILTER_MRP) { + struct nlattr *af; + int err; + + if (!br_mrp_enabled(br) || port) + goto done; + + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); + if (!af) + goto nla_put_failure; + + rcu_read_lock(); + err = br_mrp_fill_info(skb, br); + rcu_read_unlock(); + + if (err) + goto nla_put_failure; + nla_nest_end(skb, af); } @@ -516,7 +538,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_bridge_port *port = br_port_get_rtnl(dev); if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && - !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) + !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) && + !(filter_mask & RTEXT_FILTER_MRP)) return 0; return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, -- 2.27.0
[Bridge] [PATCH net-next v3 0/3] bridge: mrp: Add support for getting the status
This patch series extends the MRP netlink interface to allow the userspace daemon to get the status of the MRP instances in the kernel. v3: - remove misleading comment - fix to use correctly the RCU v2: - fix sparse warnings Horatiu Vultur (3): bridge: uapi: mrp: Extend MRP attributes to get the status bridge: mrp: Add br_mrp_fill_info bridge: Extend br_fill_ifinfo to return MPR status include/uapi/linux/if_bridge.h | 17 + include/uapi/linux/rtnetlink.h | 1 + net/bridge/br_mrp_netlink.c| 64 ++ net/bridge/br_netlink.c| 25 - net/bridge/br_private.h| 7 5 files changed, 113 insertions(+), 1 deletion(-) -- 2.27.0
[Bridge] [PATCH net-next v3 1/3] bridge: uapi: mrp: Extend MRP attributes to get the status
Add MRP attribute IFLA_BRIDGE_MRP_INFO to allow the userspace to get the current state of the MRP instances. This is a nested attribute that contains other attributes like, ring id, index of primary and secondary port, priority, ring state, ring role. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 17 + 1 file changed, 17 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index caa6914a3e53a..c114c1c2bd533 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -166,6 +166,7 @@ enum { IFLA_BRIDGE_MRP_RING_STATE, IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, + IFLA_BRIDGE_MRP_INFO, __IFLA_BRIDGE_MRP_MAX, }; @@ -228,6 +229,22 @@ enum { #define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1) +enum { + IFLA_BRIDGE_MRP_INFO_UNSPEC, + IFLA_BRIDGE_MRP_INFO_RING_ID, + IFLA_BRIDGE_MRP_INFO_P_IFINDEX, + IFLA_BRIDGE_MRP_INFO_S_IFINDEX, + IFLA_BRIDGE_MRP_INFO_PRIO, + IFLA_BRIDGE_MRP_INFO_RING_STATE, + IFLA_BRIDGE_MRP_INFO_RING_ROLE, + IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + __IFLA_BRIDGE_MRP_INFO_MAX, +}; + +#define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; -- 2.27.0
[Bridge] [PATCH net-next v3 2/3] bridge: mrp: Add br_mrp_fill_info
Add the function br_mrp_fill_info which populates the MRP attributes regarding the status of each MRP instance. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 64 + net/bridge/br_private.h | 7 2 files changed, 71 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 34b3a8776991f..c4f5c356811f3 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -304,6 +304,70 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, return 0; } +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + struct nlattr *tb, *mrp_tb; + struct br_mrp *mrp; + + mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); + if (!mrp_tb) + return -EMSGSIZE; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list) { + struct net_bridge_port *p; + + tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); + if (!tb) + goto nla_info_failure; + + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID, + mrp->ring_id)) + goto nla_put_failure; + + p = rcu_dereference(mrp->p_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + + p = rcu_dereference(mrp->s_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, + mrp->prio)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE, + mrp->ring_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE, + mrp->ring_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, + mrp->test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, + mrp->test_max_miss)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + mrp->test_monitor)) + goto nla_put_failure; + + nla_nest_end(skb, tb); + } + nla_nest_end(skb, mrp_tb); + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, tb); + +nla_info_failure: + nla_nest_cancel(skb, mrp_tb); + + return -EMSGSIZE; +} + int br_mrp_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6a7d8e218ae7e..65d2c163a24ab 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1317,6 +1317,7 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb); bool br_mrp_enabled(struct net_bridge *br); void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p); +int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br); #else static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, struct nlattr *attr, int cmd, @@ -1339,6 +1340,12 @@ static inline void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p) { } + +static inline int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) +{ + return 0; +} + #endif /* br_netlink.c */ -- 2.27.0
[Bridge] [PATCH net-next 01/12] switchdev: mrp: Extend switchdev API for MRP Interconnect
Extend switchdev API to add support for MRP interconnect. The HW is notified in the following cases: SWITCHDEV_OBJ_ID_IN_ROLE_MRP: This is used when the interconnect role of the node changes. The supported roles are MIM and MIC. SWITCHDEV_OBJ_ID_IN_STATE_MRP: This is used when the interconnect ring changes it states to open or closed. SWITCHDEV_OBJ_ID_IN_TEST_MRP: This is used to start/stop sending MRP_InTest frames on all MRP ports. This is called only on nodes that have the interconnect role MIM. Signed-off-by: Horatiu Vultur --- include/net/switchdev.h | 38 ++ 1 file changed, 38 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b8c059b4e06d9..ffa2706d8bc6f 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -76,6 +76,10 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_RING_TEST_MRP, SWITCHDEV_OBJ_ID_RING_ROLE_MRP, SWITCHDEV_OBJ_ID_RING_STATE_MRP, + SWITCHDEV_OBJ_ID_IN_TEST_MRP, + SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + SWITCHDEV_OBJ_ID_IN_STATE_MRP, + #endif }; @@ -155,6 +159,40 @@ struct switchdev_obj_ring_state_mrp { #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) +/* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ +struct switchdev_obj_in_test_mrp { + struct switchdev_obj obj; + /* The value is in us and a value of 0 represents to stop */ + u32 interval; + u8 max_miss; + u32 in_id; + u32 period; +}; + +#define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) + +/* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ +struct switchdev_obj_in_role_mrp { + struct switchdev_obj obj; + u16 in_id; + u32 ring_id; + u8 in_role; + struct net_device *i_port; +}; + +#define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) + +struct switchdev_obj_in_state_mrp { + struct switchdev_obj obj; + u8 in_state; + u32 in_id; +}; + +#define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) + #endif typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); -- 2.27.0
[Bridge] [PATCH net-next 06/12] bridge: mrp: Add br_mrp_in_port_open function
This function notifies the userspace when the node lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 22 ++ net/bridge/br_private_mrp.h | 1 + 2 files changed, 23 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index acce300c0cc29..4bf7aaeb29152 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -389,3 +389,25 @@ int br_mrp_ring_port_open(struct net_device *dev, u8 loc) out: return err; } + +int br_mrp_in_port_open(struct net_device *dev, u8 loc) +{ + struct net_bridge_port *p; + int err = 0; + + p = br_port_get_rcu(dev); + if (!p) { + err = -EINVAL; + goto out; + } + + if (loc) + p->flags |= BR_MRP_LOST_IN_CONT; + else + p->flags &= ~BR_MRP_LOST_IN_CONT; + + br_ifinfo_notify(RTM_NEWLINK, NULL, p); + +out: + return err; +} diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index d5957f7e687ff..384cb69b47e02 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -75,5 +75,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); +int br_mrp_in_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next 00/12] bridge: mrp: Add support for interconnect ring
This patch series extends existing MRP to add support for interconnect ring. An interconnect ring is a ring that connects 2 rings. In this way is possible to connect multiple rings. Each interconnect ring is form of 4 nodes, in which 3 have the role MIC(Media Redundancy Interconnect Client) and one has the role MIM(Media Redundancy Interconnect Manager). All these nodes need to have the same ID and the ID needs to be unique between multiple interconnect rings. And 2 nodes needs to be part of one ring and the other 2 nodes needs to be part of the other ring that is connected. +-+ | | +--| MRM |---+ | | | | | +-+ | || || || +--+ +-+ | | | | | MRC/MIC |--|MRC/MIM | | | | | +--+ +-+ | | |Interconnect port|Interconnect port | | | | +--+ +-+ | | | | | MRC/MIC |- | MRC/MIC | | | | | +--+ +-+ | | | | | +-+| | | || +--| MRM|+ | | +-+ Each node in a ring needs to have one of the following ring roles, MRM or MRC. And it can also have an interconnect role like MIM or MIC if it is part of an interconnect ring. In the figure above the MRM doesn't have any interconnect role but the MRC from the top ring have the interconnect roles MIC respectively MIM. Therefore it is not possible for a node to have only an interconnect role. There are 2 ways for interconnect ring to detect when is open or closed: 1. To use CCM frames on the interconnect port to detect when the interconnect link goes down/up. This mode is called LC-mode. 2. To send InTest frames on all 3 ports(2 ring ports and 1 interconnect port) and detect when these frames are received back. This mode is called RC-mode. This patch series adds support only for RC-mode. Where MIM sends InTest frames on all 3 ports and detects when it receives back the InTest. When it receives the InTest it means that the ring is closed so it would set the interconnect port in blocking state. If it stops receiving the InTest frames then it would set the port in forwarding state and it would send InTopo frames. These InTopo frames will be received by MRM nodes and process them. And then the MRM will send Topo frames in the rings so each client will clear its FDB. Horatiu Vultur (12): switchdev: mrp: Extend switchdev API for MRP Interconnect bridge: uapi: mrp: Extend MRP attributes for MRP interconnect bridge: mrp: Extend bridge interface bridge: mrp: Extend br_mrp for MRP interconnect bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open bridge: mrp: Add br_mrp_in_port_open function bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect bridge: mrp: Implement the MRP Interconnect API bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status bridge: mrp: Extend br_mrp_fill_info net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN include/linux/if_bridge.h | 1 + include/net/switchdev.h| 38 +++ include/uapi/linux/if_bridge.h | 58 include/uapi/linux/if_link.h | 1 + include/uapi/linux/mrp_bridge.h| 38 +++ net/bridge/br_mrp.c| 531 +++-- net/bridge/br_mrp_netlink.c| 182 +- net/bridge/br_mrp_switchdev.c | 62 net/bridge/br_netlink.c| 3 + net/bridge/br_private_mrp.h| 27 +- tools/include/uapi/linux/if_link.h | 1 + 11 files changed, 906 insertions(+), 36 deletions(-) -- 2.27.0
[Bridge] [PATCH net-next 05/12] bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open
This patch renames the function br_mrp_port_open to br_mrp_ring_port_open. In this way is more clear that a ring port lost the continuity because there will be also a br_mrp_in_port_open. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 6 +++--- net/bridge/br_mrp_netlink.c | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 779e1eb754430..d4176f8956d05 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -213,7 +213,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } p = rcu_dereference(mrp->s_port); @@ -229,7 +229,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } out: @@ -537,7 +537,7 @@ static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port, * not closed */ if (mrp->ring_state != BR_MRP_RING_STATE_CLOSED) - br_mrp_port_open(port->dev, false); + br_mrp_ring_port_open(port->dev, false); } /* Determin if the test hdr has a better priority than the node */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index c4f5c356811f3..acce300c0cc29 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -368,7 +368,7 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) return -EMSGSIZE; } -int br_mrp_port_open(struct net_device *dev, u8 loc) +int br_mrp_ring_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; int err = 0; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 5e612123c5605..d5957f7e687ff 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -74,6 +74,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); /* br_mrp_netlink.c */ -int br_mrp_port_open(struct net_device *dev, u8 loc); +int br_mrp_ring_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next 07/12] bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect
Implement the MRP API for interconnect switchdev. Similar with the other br_mrp_switchdev function, these function will just eventually call the switchdev functions: switchdev_port_obj_add/del. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_switchdev.c | 62 +++ net/bridge/br_private_mrp.h | 7 2 files changed, 69 insertions(+) diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c index 0da68a0da4b5a..ed547e03ace17 100644 --- a/net/bridge/br_mrp_switchdev.c +++ b/net/bridge/br_mrp_switchdev.c @@ -107,6 +107,68 @@ int br_mrp_switchdev_set_ring_state(struct net_bridge *br, return 0; } +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role) +{ + struct switchdev_obj_in_role_mrp mrp_role = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + .in_role = role, + .in_id = mrp->in_id, + .ring_id = mrp->ring_id, + .i_port = rtnl_dereference(mrp->i_port)->dev, + }; + int err; + + if (role == BR_MRP_IN_ROLE_DISABLED) + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); + else + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); + + return err; +} + +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state) +{ + struct switchdev_obj_in_state_mrp mrp_state = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP, + .in_state = state, + .in_id = mrp->in_id, + }; + int err; + + err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period) +{ + struct switchdev_obj_in_test_mrp test = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP, + .interval = interval, + .max_miss = max_miss, + .in_id = mrp->in_id, + .period = period, + }; + int err; + + if (interval == 0) + err = switchdev_port_obj_del(br->dev, &test.obj); + else + err = switchdev_port_obj_add(br->dev, &test.obj, NULL); + + return err; +} + int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state) { diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 384cb69b47e02..50dbf046a9be3 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -72,6 +72,13 @@ int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role); +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state); +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period); /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); -- 2.27.0
[Bridge] [PATCH net-next 03/12] bridge: mrp: Extend bridge interface
This patch adds a new flag(BR_MRP_LOST_IN_CONT) to the net bridge ports. This bit will be set when the port lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/linux/if_bridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index b3a8d3054af0f..6479a38e52fa9 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -49,6 +49,7 @@ struct br_ip_list { #define BR_ISOLATEDBIT(16) #define BR_MRP_AWARE BIT(17) #define BR_MRP_LOST_CONT BIT(18) +#define BR_MRP_LOST_IN_CONTBIT(19) #define BR_DEFAULT_AGEING_TIME (300 * HZ) -- 2.27.0
[Bridge] [PATCH net-next 04/12] bridge: mrp: Extend br_mrp for MRP interconnect
This patch extends the 'struct br_mrp' to contain information regarding the MRP interconnect. It contains the following: - the interconnect port 'i_port', which is NULL if the node doesn't have a interconnect role - the interconnect id, which is similar with the ring id, but this field is also part of the MRP_InTest frames. - the interconnect role, which can be MIM or MIC. - the interconnect state, which can be open or closed. - the interconnect delayed_work for sending MRP_InTest frames and check for lost of continuity. Signed-off-by: Horatiu Vultur --- net/bridge/br_private_mrp.h | 13 + 1 file changed, 13 insertions(+) diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..5e612123c5605 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -12,8 +12,10 @@ struct br_mrp { struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; + struct net_bridge_port __rcu*i_port; u32 ring_id; + u16 in_id; u16 prio; enum br_mrp_ring_role_type ring_role; @@ -21,6 +23,11 @@ struct br_mrp { enum br_mrp_ring_state_type ring_state; u32 ring_transitions; + enum br_mrp_in_role_typein_role; + u8 in_role_offloaded; + enum br_mrp_in_state_type in_state; + u32 in_transitions; + struct delayed_work test_work; u32 test_interval; unsigned long test_end; @@ -28,6 +35,12 @@ struct br_mrp { u32 test_max_miss; booltest_monitor; + struct delayed_work in_test_work; + u32 in_test_interval; + unsigned long in_test_end; + u32 in_test_count_miss; + u32 in_test_max_miss; + u32 seq_id; struct rcu_head rcu; -- 2.27.0
[Bridge] [PATCH net-next 02/12] bridge: uapi: mrp: Extend MRP attributes for MRP interconnect
Extend the existing MRP netlink attributes to allow to configure MRP Interconnect: IFLA_BRIDGE_MRP_IN_ROLE - the parameter type is br_mrp_in_role which contains the interconnect id, the ring id, the interconnect role(MIM or MIC) and the port ifindex that represents the interconnect port. IFLA_BRIDGE_MRP_IN_STATE - the parameter type is br_mrp_in_state which contains the interconnect id and the interconnect state. IFLA_BRIDGE_MRP_IN_TEST - the parameter type is br_mrp_start_in_test which contains the interconnect id, the interval at which to send MRP_InTest frames, how many test frames can be missed before declaring the interconnect ring open and the period which represents for how long to send MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 53 + include/uapi/linux/mrp_bridge.h | 38 +++ 2 files changed, 91 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index c114c1c2bd533..722b114959f66 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -167,6 +167,9 @@ enum { IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, IFLA_BRIDGE_MRP_INFO, + IFLA_BRIDGE_MRP_IN_ROLE, + IFLA_BRIDGE_MRP_IN_STATE, + IFLA_BRIDGE_MRP_START_IN_TEST, __IFLA_BRIDGE_MRP_MAX, }; @@ -245,6 +248,37 @@ enum { #define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) +enum { + IFLA_BRIDGE_MRP_IN_STATE_UNSPEC, + IFLA_BRIDGE_MRP_IN_STATE_IN_ID, + IFLA_BRIDGE_MRP_IN_STATE_STATE, + __IFLA_BRIDGE_MRP_IN_STATE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC, + IFLA_BRIDGE_MRP_IN_ROLE_RING_ID, + IFLA_BRIDGE_MRP_IN_ROLE_IN_ID, + IFLA_BRIDGE_MRP_IN_ROLE_ROLE, + IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX, + __IFLA_BRIDGE_MRP_IN_ROLE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC, + IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID, + IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD, + __IFLA_BRIDGE_MRP_START_IN_TEST_MAX, +}; + +#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; @@ -270,6 +304,25 @@ struct br_mrp_start_test { __u32 monitor; }; +struct br_mrp_in_state { + __u16 in_id; + __u32 in_state; +}; + +struct br_mrp_in_role { + __u16 in_id; + __u32 ring_id; + __u32 in_role; + __u32 i_ifindex; +}; + +struct br_mrp_start_in_test { + __u16 in_id; + __u32 interval; + __u32 max_miss; + __u32 period; +}; + struct bridge_stp_xstats { __u64 transition_blk; __u64 transition_fwd; diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index bee3665402129..6aeb13ef0b1ec 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -21,11 +21,22 @@ enum br_mrp_ring_role_type { BR_MRP_RING_ROLE_MRA, }; +enum br_mrp_in_role_type { + BR_MRP_IN_ROLE_DISABLED, + BR_MRP_IN_ROLE_MIC, + BR_MRP_IN_ROLE_MIM, +}; + enum br_mrp_ring_state_type { BR_MRP_RING_STATE_OPEN, BR_MRP_RING_STATE_CLOSED, }; +enum br_mrp_in_state_type { + BR_MRP_IN_STATE_OPEN, + BR_MRP_IN_STATE_CLOSED, +}; + enum br_mrp_port_state_type { BR_MRP_PORT_STATE_DISABLED, BR_MRP_PORT_STATE_BLOCKED, @@ -36,6 +47,7 @@ enum br_mrp_port_state_type { enum br_mrp_port_role_type { BR_MRP_PORT_ROLE_PRIMARY, BR_MRP_PORT_ROLE_SECONDARY, + BR_MRP_PORT_ROLE_INTER, }; enum br_mrp_tlv_header_type { @@ -45,6 +57,10 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_RING_TOPO = 0x3, BR_MRP_TLV_HEADER_RING_LINK_DOWN = 0x4, BR_MRP_TLV_HEADER_RING_LINK_UP = 0x5, + BR_MRP_TLV_HEADER_IN_TEST = 0x6, + BR_MRP_TLV_HEADER_IN_TOPO = 0x7, + BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, + BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; @@ -118,4 +134,26 @@ struct br_mrp_oui_hdr { __u8 oui[MRP_OUI_LENGTH]; }; +struct br_mrp_in_test_hdr { + __be16 id; + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 state; + __be16 transitions; + __be32 timestamp; +}; + +struct br_mrp_in_topo_hdr { + __u8 sa[ETH_ALEN]; + __be16 id; + __be16 interval; +}; + +struct br_mrp_in_link_hdr { + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 id; + __be16 interval; +}; + #endif -- 2.27.0
[Bridge] [PATCH net-next 09/12] bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect
This patch extends the existing MRP netlink interface with the following attributes: IFLA_BRIDGE_MRP_IN_ROLE, IFLA_BRIDGE_MRP_IN_STATE and IFLA_BRIDGE_MRP_START_IN_TEST. These attributes are similar with their ring attributes but they apply to the interconnect port. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 140 1 file changed, 140 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 4bf7aaeb29152..a006e0771e8d3 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,9 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +238,121 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_STATE_IN_ID]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_STATE_STATE]= { .type = NLA_U32 }, +}; + +static int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, +struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; + struct br_mrp_in_state state; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, + br_mrp_in_state_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: IN_ID or STATE"); + return -EINVAL; + } + + memset(&state, 0x0, sizeof(state)); + + state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); + state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); + + return br_mrp_set_in_state(br, &state); +} + +static const struct nla_policy +br_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC]= { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, + [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, +}; + +static int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; + struct br_mrp_in_role role; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, + br_mrp_in_role_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); + return -EINVAL; + } + + memset(&role, 0x0, sizeof(role)); + + role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); + role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); + role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); + role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); + + return br_mrp_set_in_role(br, &role); +} + +static const struct nla_policy +br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { + [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, +}; + +static int br_mrp_start_in_test_parse(struct net_bridge *br, + struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; + struct br_mrp_start_in_test test; +
[Bridge] [PATCH net-next 08/12] bridge: mrp: Implement the MRP Interconnect API
Thie patch adds support for MRP Interconnect. Similar with the MRP ring, if the HW can't generate MRP_InTest frames, then the SW will try to generate them. And if also the SW fails to generate the frames then an error is return to userspace. The forwarding/termination of MRP_In frames is happening in the kernel and is done by MRP instances. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 525 +--- net/bridge/br_private_mrp.h | 4 + 2 files changed, 498 insertions(+), 31 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index d4176f8956d05..a82f311e968d7 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -4,6 +4,27 @@ #include "br_private_mrp.h" static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; + +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, + struct net_bridge_port *s_port, + struct net_bridge_port *port) +{ + if (port == p_port || + port == s_port) + return true; + + return false; +} + +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, + struct net_bridge_port *port) +{ + if (port == i_port) + return true; + + return false; +} static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, u32 ifindex) @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) return res; } +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) +{ + struct br_mrp *res = NULL; + struct br_mrp *mrp; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { + if (mrp->in_id == in_id) { + res = mrp; + break; + } + } + + return res; +} + static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) p = rtnl_dereference(mrp->s_port); if (p && p->dev->ifindex == ifindex) return false; + + p = rtnl_dereference(mrp->i_port); + if (p && p->dev->ifindex == ifindex) + return false; } return true; @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, list_for_each_entry_rcu(mrp, &br->mrp_list, list, lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || - rcu_access_pointer(mrp->s_port) == p) { + rcu_access_pointer(mrp->s_port) == p || + rcu_access_pointer(mrp->i_port) == p) { res = mrp; break; } @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp, return skb; } +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, + struct net_bridge_port *p, + enum br_mrp_port_role_type port_role) +{ + struct br_mrp_in_test_hdr *hdr = NULL; + struct sk_buff *skb = NULL; + + if (!p) + return NULL; + + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); + if (!skb) + return NULL; + + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); + + hdr->id = cpu_to_be16(mrp->in_id); + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); + hdr->port_role = cpu_to_be16(port_role); + hdr->state = cpu_to_be16(mrp->in_state); + hdr->transitions = cpu_to_be16(mrp->in_transitions); + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); + + br_mrp_skb_common(skb, mrp); + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); + + return skb; +} + /* This function is continuously called in the following cases: * - when node role is MRM, in this case test_monitor is always set to false * because it needs to notify the userspace that the ring is open and needs to @@ -239,6 +311,83 @@ static void br_mrp_test_work_expired(struct work_struct *work) usecs_to_jiffies(mrp->test_interval)); } +/* This function is continuously called when the node has the interconnect rol + * MIM. It would generate interconnect test frames and will send them on all 3 + * ports. But will also check if it stop receiving interconnect test frames. + */ +static void br_mrp_in_test_work_expired(struct work_struct *work) +{ + struct d
[Bridge] [PATCH net-next 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which allows to notify the userspace when the node lost the contiuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c| 3 +++ tools/include/uapi/linux/if_link.h | 1 + 3 files changed, 5 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index cc185a007ade8..26842ffd0501d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index c532fa65c9834..147d52596e174 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) #endif + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_RING_OPEN */ + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN */ + 0; } @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, !!(p->flags & BR_NEIGH_SUPPRESS)) || nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & BR_MRP_LOST_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, + !!(p->flags & BR_MRP_LOST_IN_CONT)) || nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) return -EMSGSIZE; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cafedbbfefbe9..781e482dc499f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -- 2.27.0
[Bridge] [PATCH net-next 11/12] bridge: mrp: Extend br_mrp_fill_info
This patch extends the function br_mrp_fill_info to return also the status for the interconnect ring. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index a006e0771e8d3..2a2fdf3500c5b 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -474,6 +474,11 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) p->dev->ifindex)) goto nla_put_failure; + p = rcu_dereference(mrp->i_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, mrp->prio)) goto nla_put_failure; @@ -493,6 +498,19 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) mrp->test_monitor)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, + mrp->in_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, + mrp->in_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + mrp->in_test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, + mrp->in_test_max_miss)) + goto nla_put_failure; + nla_nest_end(skb, tb); } nla_nest_end(skb, mrp_tb); -- 2.27.0
[Bridge] [PATCH net-next 10/12] bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status
Extend the existing MRP_INFO to return status of MRP interconnect. In case there is no MRP interconnect on the node then the role will be disabled so the other attributes can be ignored. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 722b114959f66..a637755b7c2ef 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -243,6 +243,11 @@ enum { IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + IFLA_BRIDGE_MRP_INFO_I_IFINDEX, + IFLA_BRIDGE_MRP_INFO_IN_STATE, + IFLA_BRIDGE_MRP_INFO_IN_ROLE, + IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, __IFLA_BRIDGE_MRP_INFO_MAX, }; -- 2.27.0
Re: [Bridge] [PATCH net-next 01/12] switchdev: mrp: Extend switchdev API for MRP Interconnect
The 07/06/2020 12:26, David Miller wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > From: Horatiu Vultur > Date: Mon, 6 Jul 2020 11:18:31 +0200 > > > +/* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ > > +struct switchdev_obj_in_test_mrp { > > + struct switchdev_obj obj; > > + /* The value is in us and a value of 0 represents to stop */ > > + u32 interval; > > + u8 max_miss; > > + u32 in_id; > > + u32 period; > > +}; > ... > > +#define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ > > + container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) > > + > > +/* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ > > +struct switchdev_obj_in_role_mrp { > > + struct switchdev_obj obj; > > + u16 in_id; > > + u32 ring_id; > > + u8 in_role; > > + struct net_device *i_port; > > +}; > ... > > +#define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ > > + container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) > > + > > +struct switchdev_obj_in_state_mrp { > > + struct switchdev_obj obj; > > + u8 in_state; > > + u32 in_id; > > +}; > > Please arrange these structure members in a more optimal order so that > the resulting object is denser. For example, in switchdev_obj_in_role_mrp > if you order it such that: > > > + u32 ring_id; > > + u16 in_id; > > + u8 in_role; > > You'll have less wasted space from padding. > > Use 'pahole' or similar tools to guide you. Thanks, I will try to use 'pahole' and see how they need to be arranged. -- /Horatiu
Re: [Bridge] [PATCH net-next 02/12] bridge: uapi: mrp: Extend MRP attributes for MRP interconnect
The 07/06/2020 12:27, David Miller wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > From: Horatiu Vultur > Date: Mon, 6 Jul 2020 11:18:32 +0200 > > > +struct br_mrp_in_state { > > + __u16 in_id; > > + __u32 in_state; > > +}; > > Put the __u32 first then the __u16. > > > +struct br_mrp_in_role { > > + __u16 in_id; > > + __u32 ring_id; > > + __u32 in_role; > > + __u32 i_ifindex; > > +}; > > Likewise. > > > +struct br_mrp_start_in_test { > > + __u16 in_id; > > + __u32 interval; > > + __u32 max_miss; > > + __u32 period; > > +}; > > Likewise. > > > +struct br_mrp_in_test_hdr { > > + __be16 id; > > + __u8 sa[ETH_ALEN]; > > + __be16 port_role; > > + __be16 state; > > + __be16 transitions; > > + __be32 timestamp; > > +}; > > Likewise. Put the larger members first. There is lots of unnecessary > padding in this structure. I will do the same here, except for the 'struct br_mrp_in_test_hdr' because this represents the frame header for InTest frames. And this is defined in the standard how it has to be. But I will do it for the other structures. > -- /Horatiu
Re: [Bridge] [PATCH net-next 08/12] bridge: mrp: Implement the MRP Interconnect API
The 07/07/2020 16:27, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 06/07/2020 12:18, Horatiu Vultur wrote: > > Thie patch adds support for MRP Interconnect. Similar with the MRP ring, > > if the HW can't generate MRP_InTest frames, then the SW will try to > > generate them. And if also the SW fails to generate the frames then an > > error is return to userspace. > > > > The forwarding/termination of MRP_In frames is happening in the kernel > > and is done by MRP instances. > > > > Signed-off-by: Horatiu Vultur > > --- > > net/bridge/br_mrp.c | 525 +--- > > net/bridge/br_private_mrp.h | 4 + > > 2 files changed, 498 insertions(+), 31 deletions(-) > > > > I see that you queue in_test_work, but I don't see anywhere cancelling it. Good catch, I need to update the function 'br_mrp_del_impl' to cancel in_test_work, similar to test_work. I will update this in the next patch series. > > > diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c > > index d4176f8956d05..a82f311e968d7 100644 > > --- a/net/bridge/br_mrp.c > > +++ b/net/bridge/br_mrp.c > > @@ -4,6 +4,27 @@ > > #include "br_private_mrp.h" > > > > static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 > > }; > > +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, > > 0x3 }; > > + > > +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, > > + struct net_bridge_port *s_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == p_port || > > + port == s_port) > > + return true; > > + > > + return false; > > +} > > + > > +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == i_port) > > + return true; > > + > > + return false; > > +} > > > > static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, > > u32 ifindex) > > @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge > > *br, u32 ring_id) > > return res; > > } > > > > +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) > > +{ > > + struct br_mrp *res = NULL; > > + struct br_mrp *mrp; > > + > > + list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > + lockdep_rtnl_is_held()) { > > + if (mrp->in_id == in_id) { > > + res = mrp; > > + break; > > + } > > + } > > + > > + return res; > > +} > > + > > static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) > > { > > struct br_mrp *mrp; > > @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, > > u32 ifindex) > > p = rtnl_dereference(mrp->s_port); > > if (p && p->dev->ifindex == ifindex) > > return false; > > + > > + p = rtnl_dereference(mrp->i_port); > > + if (p && p->dev->ifindex == ifindex) > > + return false; > > } > > > > return true; > > @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge > > *br, > > list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > lockdep_rtnl_is_held()) { > > if (rcu_access_pointer(mrp->p_port) == p || > > - rcu_access_pointer(mrp->s_port) == p) { > > + rcu_access_pointer(mrp->s_port) == p || > > + rcu_access_pointer(mrp->i_port) == p) { > > res = mrp; > > break; > > } > > @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct > > br_mrp *mrp, > > return skb; > > } > > > > +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, > > + struct net_bridge_port *p, > > + enum br_mrp_port_role_type > > port_role) > > +{ > > + struct br_mrp_in_test_hdr *hdr = NULL; > > + struct sk_buff *skb = NULL; > > + > > + if (!p) > > + return NULL; > > + > > + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); > > + if (!skb) > > + return NULL; > > + > > + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); > > + hdr = skb_put(skb, sizeof(*hdr)); > > + > > + hdr->id = cpu_to_be16(mrp->in_id); > > + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); > > + hdr->port_role = cpu_to_be16(port_role); > > + hdr->state = cpu_to_be16(mrp->in_state); > > + hdr->transitions = cpu_to_be16(mrp->in_transitions); > > + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); > > + > > + br_mrp_skb_common(sk
[Bridge] [PATCH net-next v2 07/12] bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect
Implement the MRP API for interconnect switchdev. Similar with the other br_mrp_switchdev function, these function will just eventually call the switchdev functions: switchdev_port_obj_add/del. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_switchdev.c | 62 +++ net/bridge/br_private_mrp.h | 7 2 files changed, 69 insertions(+) diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c index 0da68a0da4b5a..ed547e03ace17 100644 --- a/net/bridge/br_mrp_switchdev.c +++ b/net/bridge/br_mrp_switchdev.c @@ -107,6 +107,68 @@ int br_mrp_switchdev_set_ring_state(struct net_bridge *br, return 0; } +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role) +{ + struct switchdev_obj_in_role_mrp mrp_role = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + .in_role = role, + .in_id = mrp->in_id, + .ring_id = mrp->ring_id, + .i_port = rtnl_dereference(mrp->i_port)->dev, + }; + int err; + + if (role == BR_MRP_IN_ROLE_DISABLED) + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); + else + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); + + return err; +} + +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state) +{ + struct switchdev_obj_in_state_mrp mrp_state = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP, + .in_state = state, + .in_id = mrp->in_id, + }; + int err; + + err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period) +{ + struct switchdev_obj_in_test_mrp test = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP, + .interval = interval, + .max_miss = max_miss, + .in_id = mrp->in_id, + .period = period, + }; + int err; + + if (interval == 0) + err = switchdev_port_obj_del(br->dev, &test.obj); + else + err = switchdev_port_obj_add(br->dev, &test.obj, NULL); + + return err; +} + int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state) { diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 384cb69b47e02..50dbf046a9be3 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -72,6 +72,13 @@ int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role); +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state); +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period); /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); -- 2.27.0
[Bridge] [PATCH net-next v2 06/12] bridge: mrp: Add br_mrp_in_port_open function
This function notifies the userspace when the node lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 22 ++ net/bridge/br_private_mrp.h | 1 + 2 files changed, 23 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index acce300c0cc29..4bf7aaeb29152 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -389,3 +389,25 @@ int br_mrp_ring_port_open(struct net_device *dev, u8 loc) out: return err; } + +int br_mrp_in_port_open(struct net_device *dev, u8 loc) +{ + struct net_bridge_port *p; + int err = 0; + + p = br_port_get_rcu(dev); + if (!p) { + err = -EINVAL; + goto out; + } + + if (loc) + p->flags |= BR_MRP_LOST_IN_CONT; + else + p->flags &= ~BR_MRP_LOST_IN_CONT; + + br_ifinfo_notify(RTM_NEWLINK, NULL, p); + +out: + return err; +} diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index d5957f7e687ff..384cb69b47e02 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -75,5 +75,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); +int br_mrp_in_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v2 00/12] bridge: mrp: Add support for interconnect ring
This patch series extends existing MRP to add support for interconnect ring. An interconnect ring is a ring that connects 2 rings. In this way is possible to connect multiple rings. Each interconnect ring is form of 4 nodes, in which 3 have the role MIC(Media Redundancy Interconnect Client) and one has the role MIM(Media Redundancy Interconnect Manager). All these nodes need to have the same ID and the ID needs to be unique between multiple interconnect rings. And 2 nodes needs to be part of one ring and the other 2 nodes needs to be part of the other ring that is connected. +-+ | | +--| MRM |---+ | | | | | +-+ | || || || +--+ +-+ | | | | | MRC/MIC |--|MRC/MIM | | | | | +--+ +-+ | | |Interconnect port|Interconnect port | | | | +--+ +-+ | | | | | MRC/MIC |- | MRC/MIC | | | | | +--+ +-+ | | | | | +-+| | | || +--| MRM|+ | | +-+ Each node in a ring needs to have one of the following ring roles, MRM or MRC. And it can also have an interconnect role like MIM or MIC if it is part of an interconnect ring. In the figure above the MRM doesn't have any interconnect role but the MRC from the top ring have the interconnect roles MIC respectively MIM. Therefore it is not possible for a node to have only an interconnect role. There are 2 ways for interconnect ring to detect when is open or closed: 1. To use CCM frames on the interconnect port to detect when the interconnect link goes down/up. This mode is called LC-mode. 2. To send InTest frames on all 3 ports(2 ring ports and 1 interconnect port) and detect when these frames are received back. This mode is called RC-mode. This patch series adds support only for RC-mode. Where MIM sends InTest frames on all 3 ports and detects when it receives back the InTest. When it receives the InTest it means that the ring is closed so it would set the interconnect port in blocking state. If it stops receiving the InTest frames then it would set the port in forwarding state and it would send InTopo frames. These InTopo frames will be received by MRM nodes and process them. And then the MRM will send Topo frames in the rings so each client will clear its FDB. v2: - rearrange structures not to contain holes - stop sending MRP_InTest frames when the MRP instance is deleted Horatiu Vultur (12): switchdev: mrp: Extend switchdev API for MRP Interconnect bridge: uapi: mrp: Extend MRP attributes for MRP interconnect bridge: mrp: Extend bridge interface bridge: mrp: Extend br_mrp for MRP interconnect bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open bridge: mrp: Add br_mrp_in_port_open function bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect bridge: mrp: Implement the MRP Interconnect API bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status bridge: mrp: Extend br_mrp_fill_info net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN include/linux/if_bridge.h | 1 + include/net/switchdev.h| 38 ++ include/uapi/linux/if_bridge.h | 58 include/uapi/linux/if_link.h | 1 + include/uapi/linux/mrp_bridge.h| 38 ++ net/bridge/br_mrp.c| 537 +++-- net/bridge/br_mrp_netlink.c| 182 +- net/bridge/br_mrp_switchdev.c | 62 net/bridge/br_netlink.c| 3 + net/bridge/br_private_mrp.h| 27 +- tools/include/uapi/linux/if_link.h | 1 + 11 files changed, 912 insertions(+), 36 deletions(-) -- 2.27.0
[Bridge] [PATCH net-next v2 08/12] bridge: mrp: Implement the MRP Interconnect API
Thie patch adds support for MRP Interconnect. Similar with the MRP ring, if the HW can't generate MRP_InTest frames, then the SW will try to generate them. And if also the SW fails to generate the frames then an error is return to userspace. The forwarding/termination of MRP_In frames is happening in the kernel and is done by MRP instances. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 531 +--- net/bridge/br_private_mrp.h | 4 + 2 files changed, 504 insertions(+), 31 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index d4176f8956d05..26eb40d610b3a 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -4,6 +4,27 @@ #include "br_private_mrp.h" static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; + +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, + struct net_bridge_port *s_port, + struct net_bridge_port *port) +{ + if (port == p_port || + port == s_port) + return true; + + return false; +} + +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, + struct net_bridge_port *port) +{ + if (port == i_port) + return true; + + return false; +} static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, u32 ifindex) @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) return res; } +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) +{ + struct br_mrp *res = NULL; + struct br_mrp *mrp; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { + if (mrp->in_id == in_id) { + res = mrp; + break; + } + } + + return res; +} + static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) p = rtnl_dereference(mrp->s_port); if (p && p->dev->ifindex == ifindex) return false; + + p = rtnl_dereference(mrp->i_port); + if (p && p->dev->ifindex == ifindex) + return false; } return true; @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, list_for_each_entry_rcu(mrp, &br->mrp_list, list, lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || - rcu_access_pointer(mrp->s_port) == p) { + rcu_access_pointer(mrp->s_port) == p || + rcu_access_pointer(mrp->i_port) == p) { res = mrp; break; } @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp, return skb; } +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, + struct net_bridge_port *p, + enum br_mrp_port_role_type port_role) +{ + struct br_mrp_in_test_hdr *hdr = NULL; + struct sk_buff *skb = NULL; + + if (!p) + return NULL; + + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); + if (!skb) + return NULL; + + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); + + hdr->id = cpu_to_be16(mrp->in_id); + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); + hdr->port_role = cpu_to_be16(port_role); + hdr->state = cpu_to_be16(mrp->in_state); + hdr->transitions = cpu_to_be16(mrp->in_transitions); + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); + + br_mrp_skb_common(skb, mrp); + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); + + return skb; +} + /* This function is continuously called in the following cases: * - when node role is MRM, in this case test_monitor is always set to false * because it needs to notify the userspace that the ring is open and needs to @@ -239,6 +311,83 @@ static void br_mrp_test_work_expired(struct work_struct *work) usecs_to_jiffies(mrp->test_interval)); } +/* This function is continuously called when the node has the interconnect rol + * MIM. It would generate interconnect test frames and will send them on all 3 + * ports. But will also check if it stop receiving interconnect test frames. + */ +static void br_mrp_in_test_work_expired(struct work_struct *work) +{ + struct d
[Bridge] [PATCH net-next v2 03/12] bridge: mrp: Extend bridge interface
This patch adds a new flag(BR_MRP_LOST_IN_CONT) to the net bridge ports. This bit will be set when the port lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/linux/if_bridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index b3a8d3054af0f..6479a38e52fa9 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -49,6 +49,7 @@ struct br_ip_list { #define BR_ISOLATEDBIT(16) #define BR_MRP_AWARE BIT(17) #define BR_MRP_LOST_CONT BIT(18) +#define BR_MRP_LOST_IN_CONTBIT(19) #define BR_DEFAULT_AGEING_TIME (300 * HZ) -- 2.27.0
[Bridge] [PATCH net-next v2 01/12] switchdev: mrp: Extend switchdev API for MRP Interconnect
Extend switchdev API to add support for MRP interconnect. The HW is notified in the following cases: SWITCHDEV_OBJ_ID_IN_ROLE_MRP: This is used when the interconnect role of the node changes. The supported roles are MIM and MIC. SWITCHDEV_OBJ_ID_IN_STATE_MRP: This is used when the interconnect ring changes it states to open or closed. SWITCHDEV_OBJ_ID_IN_TEST_MRP: This is used to start/stop sending MRP_InTest frames on all MRP ports. This is called only on nodes that have the interconnect role MIM. Signed-off-by: Horatiu Vultur --- include/net/switchdev.h | 38 ++ 1 file changed, 38 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b8c059b4e06d9..ff22469143013 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -76,6 +76,10 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_RING_TEST_MRP, SWITCHDEV_OBJ_ID_RING_ROLE_MRP, SWITCHDEV_OBJ_ID_RING_STATE_MRP, + SWITCHDEV_OBJ_ID_IN_TEST_MRP, + SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + SWITCHDEV_OBJ_ID_IN_STATE_MRP, + #endif }; @@ -155,6 +159,40 @@ struct switchdev_obj_ring_state_mrp { #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) +/* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ +struct switchdev_obj_in_test_mrp { + struct switchdev_obj obj; + /* The value is in us and a value of 0 represents to stop */ + u32 interval; + u32 in_id; + u32 period; + u8 max_miss; +}; + +#define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) + +/* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ +struct switchdev_obj_in_role_mrp { + struct switchdev_obj obj; + struct net_device *i_port; + u32 ring_id; + u16 in_id; + u8 in_role; +}; + +#define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) + +struct switchdev_obj_in_state_mrp { + struct switchdev_obj obj; + u32 in_id; + u8 in_state; +}; + +#define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) + #endif typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); -- 2.27.0
[Bridge] [PATCH net-next v2 04/12] bridge: mrp: Extend br_mrp for MRP interconnect
This patch extends the 'struct br_mrp' to contain information regarding the MRP interconnect. It contains the following: - the interconnect port 'i_port', which is NULL if the node doesn't have a interconnect role - the interconnect id, which is similar with the ring id, but this field is also part of the MRP_InTest frames. - the interconnect role, which can be MIM or MIC. - the interconnect state, which can be open or closed. - the interconnect delayed_work for sending MRP_InTest frames and check for lost of continuity. Signed-off-by: Horatiu Vultur --- net/bridge/br_private_mrp.h | 13 + 1 file changed, 13 insertions(+) diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 33b255e38ffec..5e612123c5605 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -12,8 +12,10 @@ struct br_mrp { struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; + struct net_bridge_port __rcu*i_port; u32 ring_id; + u16 in_id; u16 prio; enum br_mrp_ring_role_type ring_role; @@ -21,6 +23,11 @@ struct br_mrp { enum br_mrp_ring_state_type ring_state; u32 ring_transitions; + enum br_mrp_in_role_typein_role; + u8 in_role_offloaded; + enum br_mrp_in_state_type in_state; + u32 in_transitions; + struct delayed_work test_work; u32 test_interval; unsigned long test_end; @@ -28,6 +35,12 @@ struct br_mrp { u32 test_max_miss; booltest_monitor; + struct delayed_work in_test_work; + u32 in_test_interval; + unsigned long in_test_end; + u32 in_test_count_miss; + u32 in_test_max_miss; + u32 seq_id; struct rcu_head rcu; -- 2.27.0
[Bridge] [PATCH net-next v2 05/12] bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open
This patch renames the function br_mrp_port_open to br_mrp_ring_port_open. In this way is more clear that a ring port lost the continuity because there will be also a br_mrp_in_port_open. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 6 +++--- net/bridge/br_mrp_netlink.c | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 779e1eb754430..d4176f8956d05 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -213,7 +213,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } p = rcu_dereference(mrp->s_port); @@ -229,7 +229,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } out: @@ -537,7 +537,7 @@ static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port, * not closed */ if (mrp->ring_state != BR_MRP_RING_STATE_CLOSED) - br_mrp_port_open(port->dev, false); + br_mrp_ring_port_open(port->dev, false); } /* Determin if the test hdr has a better priority than the node */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index c4f5c356811f3..acce300c0cc29 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -368,7 +368,7 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) return -EMSGSIZE; } -int br_mrp_port_open(struct net_device *dev, u8 loc) +int br_mrp_ring_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; int err = 0; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 5e612123c5605..d5957f7e687ff 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -74,6 +74,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); /* br_mrp_netlink.c */ -int br_mrp_port_open(struct net_device *dev, u8 loc); +int br_mrp_ring_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v2 09/12] bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect
This patch extends the existing MRP netlink interface with the following attributes: IFLA_BRIDGE_MRP_IN_ROLE, IFLA_BRIDGE_MRP_IN_STATE and IFLA_BRIDGE_MRP_START_IN_TEST. These attributes are similar with their ring attributes but they apply to the interconnect port. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 140 1 file changed, 140 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 4bf7aaeb29152..a006e0771e8d3 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,9 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +238,121 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_STATE_IN_ID]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_STATE_STATE]= { .type = NLA_U32 }, +}; + +static int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, +struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; + struct br_mrp_in_state state; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, + br_mrp_in_state_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: IN_ID or STATE"); + return -EINVAL; + } + + memset(&state, 0x0, sizeof(state)); + + state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); + state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); + + return br_mrp_set_in_state(br, &state); +} + +static const struct nla_policy +br_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC]= { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, + [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, +}; + +static int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; + struct br_mrp_in_role role; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, + br_mrp_in_role_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); + return -EINVAL; + } + + memset(&role, 0x0, sizeof(role)); + + role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); + role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); + role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); + role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); + + return br_mrp_set_in_role(br, &role); +} + +static const struct nla_policy +br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { + [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, +}; + +static int br_mrp_start_in_test_parse(struct net_bridge *br, + struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; + struct br_mrp_start_in_test test; +
[Bridge] [PATCH net-next v2 11/12] bridge: mrp: Extend br_mrp_fill_info
This patch extends the function br_mrp_fill_info to return also the status for the interconnect ring. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index a006e0771e8d3..2a2fdf3500c5b 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -474,6 +474,11 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) p->dev->ifindex)) goto nla_put_failure; + p = rcu_dereference(mrp->i_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, mrp->prio)) goto nla_put_failure; @@ -493,6 +498,19 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) mrp->test_monitor)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, + mrp->in_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, + mrp->in_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + mrp->in_test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, + mrp->in_test_max_miss)) + goto nla_put_failure; + nla_nest_end(skb, tb); } nla_nest_end(skb, mrp_tb); -- 2.27.0
[Bridge] [PATCH net-next v2 02/12] bridge: uapi: mrp: Extend MRP attributes for MRP interconnect
Extend the existing MRP netlink attributes to allow to configure MRP Interconnect: IFLA_BRIDGE_MRP_IN_ROLE - the parameter type is br_mrp_in_role which contains the interconnect id, the ring id, the interconnect role(MIM or MIC) and the port ifindex that represents the interconnect port. IFLA_BRIDGE_MRP_IN_STATE - the parameter type is br_mrp_in_state which contains the interconnect id and the interconnect state. IFLA_BRIDGE_MRP_IN_TEST - the parameter type is br_mrp_start_in_test which contains the interconnect id, the interval at which to send MRP_InTest frames, how many test frames can be missed before declaring the interconnect ring open and the period which represents for how long to send MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 53 + include/uapi/linux/mrp_bridge.h | 38 +++ 2 files changed, 91 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index c114c1c2bd533..d840a3e37a37c 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -167,6 +167,9 @@ enum { IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, IFLA_BRIDGE_MRP_INFO, + IFLA_BRIDGE_MRP_IN_ROLE, + IFLA_BRIDGE_MRP_IN_STATE, + IFLA_BRIDGE_MRP_START_IN_TEST, __IFLA_BRIDGE_MRP_MAX, }; @@ -245,6 +248,37 @@ enum { #define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) +enum { + IFLA_BRIDGE_MRP_IN_STATE_UNSPEC, + IFLA_BRIDGE_MRP_IN_STATE_IN_ID, + IFLA_BRIDGE_MRP_IN_STATE_STATE, + __IFLA_BRIDGE_MRP_IN_STATE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC, + IFLA_BRIDGE_MRP_IN_ROLE_RING_ID, + IFLA_BRIDGE_MRP_IN_ROLE_IN_ID, + IFLA_BRIDGE_MRP_IN_ROLE_ROLE, + IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX, + __IFLA_BRIDGE_MRP_IN_ROLE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC, + IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID, + IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD, + __IFLA_BRIDGE_MRP_START_IN_TEST_MAX, +}; + +#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; @@ -270,6 +304,25 @@ struct br_mrp_start_test { __u32 monitor; }; +struct br_mrp_in_state { + __u32 in_state; + __u16 in_id; +}; + +struct br_mrp_in_role { + __u32 ring_id; + __u32 in_role; + __u32 i_ifindex; + __u16 in_id; +}; + +struct br_mrp_start_in_test { + __u32 interval; + __u32 max_miss; + __u32 period; + __u16 in_id; +}; + struct bridge_stp_xstats { __u64 transition_blk; __u64 transition_fwd; diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index bee3665402129..6aeb13ef0b1ec 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -21,11 +21,22 @@ enum br_mrp_ring_role_type { BR_MRP_RING_ROLE_MRA, }; +enum br_mrp_in_role_type { + BR_MRP_IN_ROLE_DISABLED, + BR_MRP_IN_ROLE_MIC, + BR_MRP_IN_ROLE_MIM, +}; + enum br_mrp_ring_state_type { BR_MRP_RING_STATE_OPEN, BR_MRP_RING_STATE_CLOSED, }; +enum br_mrp_in_state_type { + BR_MRP_IN_STATE_OPEN, + BR_MRP_IN_STATE_CLOSED, +}; + enum br_mrp_port_state_type { BR_MRP_PORT_STATE_DISABLED, BR_MRP_PORT_STATE_BLOCKED, @@ -36,6 +47,7 @@ enum br_mrp_port_state_type { enum br_mrp_port_role_type { BR_MRP_PORT_ROLE_PRIMARY, BR_MRP_PORT_ROLE_SECONDARY, + BR_MRP_PORT_ROLE_INTER, }; enum br_mrp_tlv_header_type { @@ -45,6 +57,10 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_RING_TOPO = 0x3, BR_MRP_TLV_HEADER_RING_LINK_DOWN = 0x4, BR_MRP_TLV_HEADER_RING_LINK_UP = 0x5, + BR_MRP_TLV_HEADER_IN_TEST = 0x6, + BR_MRP_TLV_HEADER_IN_TOPO = 0x7, + BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, + BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; @@ -118,4 +134,26 @@ struct br_mrp_oui_hdr { __u8 oui[MRP_OUI_LENGTH]; }; +struct br_mrp_in_test_hdr { + __be16 id; + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 state; + __be16 transitions; + __be32 timestamp; +}; + +struct br_mrp_in_topo_hdr { + __u8 sa[ETH_ALEN]; + __be16 id; + __be16 interval; +}; + +struct br_mrp_in_link_hdr { + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 id; + __be16 interval; +}; + #endif -- 2.27.0
[Bridge] [PATCH net-next v2 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which allows to notify the userspace when the node lost the contiuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c| 3 +++ tools/include/uapi/linux/if_link.h | 1 + 3 files changed, 5 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index cc185a007ade8..26842ffd0501d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index c532fa65c9834..147d52596e174 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) #endif + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_RING_OPEN */ + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN */ + 0; } @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, !!(p->flags & BR_NEIGH_SUPPRESS)) || nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & BR_MRP_LOST_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, + !!(p->flags & BR_MRP_LOST_IN_CONT)) || nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) return -EMSGSIZE; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cafedbbfefbe9..781e482dc499f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -- 2.27.0
[Bridge] [PATCH net-next v2 10/12] bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status
Extend the existing MRP_INFO to return status of MRP interconnect. In case there is no MRP interconnect on the node then the role will be disabled so the other attributes can be ignored. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index d840a3e37a37c..c1227aecd38fd 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -243,6 +243,11 @@ enum { IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + IFLA_BRIDGE_MRP_INFO_I_IFINDEX, + IFLA_BRIDGE_MRP_INFO_IN_STATE, + IFLA_BRIDGE_MRP_INFO_IN_ROLE, + IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, __IFLA_BRIDGE_MRP_INFO_MAX, }; -- 2.27.0
Re: [Bridge] [PATCH net-next v2 08/12] bridge: mrp: Implement the MRP Interconnect API
The 07/09/2020 15:26, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 09/07/2020 13:00, Horatiu Vultur wrote: > > Thie patch adds support for MRP Interconnect. Similar with the MRP ring, > > if the HW can't generate MRP_InTest frames, then the SW will try to > > generate them. And if also the SW fails to generate the frames then an > > error is return to userspace. > > > > The forwarding/termination of MRP_In frames is happening in the kernel > > and is done by MRP instances. > > > > Signed-off-by: Horatiu Vultur > > --- > > net/bridge/br_mrp.c | 531 +--- > > net/bridge/br_private_mrp.h | 4 + > > 2 files changed, 504 insertions(+), 31 deletions(-) > > Hi Nik, > > Hi, > Few comments below. > > > diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c > > index d4176f8956d05..26eb40d610b3a 100644 > > --- a/net/bridge/br_mrp.c > > +++ b/net/bridge/br_mrp.c > > @@ -4,6 +4,27 @@ > > #include "br_private_mrp.h" > > > > static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 > > }; > > +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, > > 0x3 }; > > + > > +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, > > + struct net_bridge_port *s_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == p_port || > > + port == s_port) > > + return true; > > + > > + return false; > > +} > > + > > +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == i_port) > > + return true; > > + > > + return false; > > +} > > > > static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, > > u32 ifindex) > > @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge > > *br, u32 ring_id) > > return res; > > } > > > > +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) > > +{ > > + struct br_mrp *res = NULL; > > + struct br_mrp *mrp; > > + > > + list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > + lockdep_rtnl_is_held()) { > > + if (mrp->in_id == in_id) { > > + res = mrp; > > + break; > > + } > > + } > > + > > + return res; > > +} > > + > > static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) > > { > > struct br_mrp *mrp; > > @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, > > u32 ifindex) > > p = rtnl_dereference(mrp->s_port); > > if (p && p->dev->ifindex == ifindex) > > return false; > > + > > + p = rtnl_dereference(mrp->i_port); > > + if (p && p->dev->ifindex == ifindex) > > + return false; > > } > > > > return true; > > @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge > > *br, > > list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > lockdep_rtnl_is_held()) { > > if (rcu_access_pointer(mrp->p_port) == p || > > - rcu_access_pointer(mrp->s_port) == p) { > > + rcu_access_pointer(mrp->s_port) == p || > > + rcu_access_pointer(mrp->i_port) == p) { > > res = mrp; > > break; > > } > > @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct > > br_mrp *mrp, > > return skb; > > } > > > > +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, > > + struct net_bridge_port *p, > > + enum br_mrp_port_role_type > > port_role) > > +{ > > + struct br_mrp_in_test_hdr *hdr = NULL; > > + struct sk_buff *skb = NULL; > > + > > + if (!p) > > + return NULL; > > + > > + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); > > + if (!skb) > > + return NULL; > > + > > + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); > > + hdr = skb_put(skb, sizeof(*hdr)); > > + > > + hdr->id = cpu_to_be16(mrp->in_id); > > + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); > > + hdr->port_role = cpu_to_be16(port_role); > > + hdr->state = cpu_to_be16(mrp->in_state); > > + hdr->transitions = cpu_to_be16(mrp->in_transitions); > > + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); > > + > > + br_mrp_skb_common(skb, mrp); > > + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); > > + > > + return skb; > > +} > > + > > /* This function is continuously called in the following cases: > > * - when
[Bridge] [PATCH net-next v3 11/12] bridge: mrp: Extend br_mrp_fill_info
This patch extends the function br_mrp_fill_info to return also the status for the interconnect ring. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index a006e0771e8d3..2a2fdf3500c5b 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -474,6 +474,11 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) p->dev->ifindex)) goto nla_put_failure; + p = rcu_dereference(mrp->i_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, mrp->prio)) goto nla_put_failure; @@ -493,6 +498,19 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) mrp->test_monitor)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, + mrp->in_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, + mrp->in_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + mrp->in_test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, + mrp->in_test_max_miss)) + goto nla_put_failure; + nla_nest_end(skb, tb); } nla_nest_end(skb, mrp_tb); -- 2.27.0
[Bridge] [PATCH net-next v3 04/12] bridge: mrp: Extend br_mrp for MRP interconnect
This patch extends the 'struct br_mrp' to contain information regarding the MRP interconnect. It contains the following: - the interconnect port 'i_port', which is NULL if the node doesn't have a interconnect role - the interconnect id, which is similar with the ring id, but this field is also part of the MRP_InTest frames. - the interconnect role, which can be MIM or MIC. - the interconnect state, which can be open or closed. - the interconnect delayed_work for sending MRP_InTest frames and check for lost of continuity. Signed-off-by: Horatiu Vultur --- net/bridge/br_private_mrp.h | 13 + 1 file changed, 13 insertions(+) diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 315eb37d89f0f..8841ba847fb29 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -12,8 +12,10 @@ struct br_mrp { struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; + struct net_bridge_port __rcu*i_port; u32 ring_id; + u16 in_id; u16 prio; enum br_mrp_ring_role_type ring_role; @@ -21,6 +23,11 @@ struct br_mrp { enum br_mrp_ring_state_type ring_state; u32 ring_transitions; + enum br_mrp_in_role_typein_role; + u8 in_role_offloaded; + enum br_mrp_in_state_type in_state; + u32 in_transitions; + struct delayed_work test_work; u32 test_interval; unsigned long test_end; @@ -28,6 +35,12 @@ struct br_mrp { u32 test_max_miss; booltest_monitor; + struct delayed_work in_test_work; + u32 in_test_interval; + unsigned long in_test_end; + u32 in_test_count_miss; + u32 in_test_max_miss; + u32 seq_id; struct rcu_head rcu; -- 2.27.0
[Bridge] [PATCH net-next v3 08/12] bridge: mrp: Implement the MRP Interconnect API
Thie patch adds support for MRP Interconnect. Similar with the MRP ring, if the HW can't generate MRP_InTest frames, then the SW will try to generate them. And if also the SW fails to generate the frames then an error is return to userspace. The forwarding/termination of MRP_In frames is happening in the kernel and is done by MRP instances. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 570 ++-- net/bridge/br_private_mrp.h | 4 + 2 files changed, 543 insertions(+), 31 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index fe7cf1446b58a..bf05ae093faa2 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -4,6 +4,27 @@ #include "br_private_mrp.h" static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; + +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, + struct net_bridge_port *s_port, + struct net_bridge_port *port) +{ + if (port == p_port || + port == s_port) + return true; + + return false; +} + +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, + struct net_bridge_port *port) +{ + if (port == i_port) + return true; + + return false; +} static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, u32 ifindex) @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) return res; } +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) +{ + struct br_mrp *res = NULL; + struct br_mrp *mrp; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { + if (mrp->in_id == in_id) { + res = mrp; + break; + } + } + + return res; +} + static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) p = rtnl_dereference(mrp->s_port); if (p && p->dev->ifindex == ifindex) return false; + + p = rtnl_dereference(mrp->i_port); + if (p && p->dev->ifindex == ifindex) + return false; } return true; @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, list_for_each_entry_rcu(mrp, &br->mrp_list, list, lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || - rcu_access_pointer(mrp->s_port) == p) { + rcu_access_pointer(mrp->s_port) == p || + rcu_access_pointer(mrp->i_port) == p) { res = mrp; break; } @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp, return skb; } +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, + struct net_bridge_port *p, + enum br_mrp_port_role_type port_role) +{ + struct br_mrp_in_test_hdr *hdr = NULL; + struct sk_buff *skb = NULL; + + if (!p) + return NULL; + + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); + if (!skb) + return NULL; + + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); + + hdr->id = cpu_to_be16(mrp->in_id); + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); + hdr->port_role = cpu_to_be16(port_role); + hdr->state = cpu_to_be16(mrp->in_state); + hdr->transitions = cpu_to_be16(mrp->in_transitions); + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); + + br_mrp_skb_common(skb, mrp); + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); + + return skb; +} + /* This function is continuously called in the following cases: * - when node role is MRM, in this case test_monitor is always set to false * because it needs to notify the userspace that the ring is open and needs to @@ -239,6 +311,83 @@ static void br_mrp_test_work_expired(struct work_struct *work) usecs_to_jiffies(mrp->test_interval)); } +/* This function is continuously called when the node has the interconnect role + * MIM. It would generate interconnect test frames and will send them on all 3 + * ports. But will also check if it stop receiving interconnect test frames. + */ +static void br_mrp_in_test_work_expired(struct work_struct *work) +{ + struct
[Bridge] [PATCH net-next v3 00/12] bridge: mrp: Add support for interconnect ring
This patch series extends existing MRP to add support for interconnect ring. An interconnect ring is a ring that connects 2 rings. In this way is possible to connect multiple rings. Each interconnect ring is form of 4 nodes, in which 3 have the role MIC(Media Redundancy Interconnect Client) and one has the role MIM(Media Redundancy Interconnect Manager). All these nodes need to have the same ID and the ID needs to be unique between multiple interconnect rings. And 2 nodes needs to be part of one ring and the other 2 nodes needs to be part of the other ring that is connected. +-+ | | +--| MRM |---+ | | | | | +-+ | || || || +--+ +-+ | | | | | MRC/MIC |--|MRC/MIM | | | | | +--+ +-+ | | |Interconnect port|Interconnect port | | | | +--+ +-+ | | | | | MRC/MIC |- | MRC/MIC | | | | | +--+ +-+ | | | | | +-+| | | || +--| MRM|+ | | +-+ Each node in a ring needs to have one of the following ring roles, MRM or MRC. And it can also have an interconnect role like MIM or MIC if it is part of an interconnect ring. In the figure above the MRM doesn't have any interconnect role but the MRC from the top ring have the interconnect roles MIC respectively MIM. Therefore it is not possible for a node to have only an interconnect role. There are 2 ways for interconnect ring to detect when is open or closed: 1. To use CCM frames on the interconnect port to detect when the interconnect link goes down/up. This mode is called LC-mode. 2. To send InTest frames on all 3 ports(2 ring ports and 1 interconnect port) and detect when these frames are received back. This mode is called RC-mode. This patch series adds support only for RC-mode. Where MIM sends InTest frames on all 3 ports and detects when it receives back the InTest. When it receives the InTest it means that the ring is closed so it would set the interconnect port in blocking state. If it stops receiving the InTest frames then it would set the port in forwarding state and it would send InTopo frames. These InTopo frames will be received by MRM nodes and process them. And then the MRM will send Topo frames in the rings so each client will clear its FDB. v3: - update 'br_mrp_set_in_role' to stop sending test if the role is disabled and don't allow to set a different interconnect port if there is already one. v2: - rearrange structures not to contain holes - stop sending MRP_InTest frames when the MRP instance is deleted Horatiu Vultur (12): switchdev: mrp: Extend switchdev API for MRP Interconnect bridge: uapi: mrp: Extend MRP attributes for MRP interconnect bridge: mrp: Extend bridge interface bridge: mrp: Extend br_mrp for MRP interconnect bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open bridge: mrp: Add br_mrp_in_port_open function bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect bridge: mrp: Implement the MRP Interconnect API bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status bridge: mrp: Extend br_mrp_fill_info net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN include/linux/if_bridge.h | 1 + include/net/switchdev.h| 38 ++ include/uapi/linux/if_bridge.h | 58 +++ include/uapi/linux/if_link.h | 1 + include/uapi/linux/mrp_bridge.h| 38 ++ net/bridge/br_mrp.c| 576 +++-- net/bridge/br_mrp_netlink.c| 182 - net/bridge/br_mrp_switchdev.c | 62 net/bridge/br_netlink.c| 3 + net/bridge/br_private_mrp.h| 27 +- tools/include/uapi/linux/if_link.h | 1 + 11 files changed, 951 insertions(+), 36 deletions(-) -- 2.27.0
[Bridge] [PATCH net-next v3 09/12] bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect
This patch extends the existing MRP netlink interface with the following attributes: IFLA_BRIDGE_MRP_IN_ROLE, IFLA_BRIDGE_MRP_IN_STATE and IFLA_BRIDGE_MRP_START_IN_TEST. These attributes are similar with their ring attributes but they apply to the interconnect port. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 140 1 file changed, 140 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 4bf7aaeb29152..a006e0771e8d3 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,9 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +238,121 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_STATE_IN_ID]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_STATE_STATE]= { .type = NLA_U32 }, +}; + +static int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, +struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; + struct br_mrp_in_state state; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, + br_mrp_in_state_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: IN_ID or STATE"); + return -EINVAL; + } + + memset(&state, 0x0, sizeof(state)); + + state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); + state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); + + return br_mrp_set_in_state(br, &state); +} + +static const struct nla_policy +br_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC]= { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, + [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, +}; + +static int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; + struct br_mrp_in_role role; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, + br_mrp_in_role_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); + return -EINVAL; + } + + memset(&role, 0x0, sizeof(role)); + + role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); + role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); + role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); + role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); + + return br_mrp_set_in_role(br, &role); +} + +static const struct nla_policy +br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { + [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, +}; + +static int br_mrp_start_in_test_parse(struct net_bridge *br, + struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; + struct br_mrp_start_in_test test; +
[Bridge] [PATCH net-next v3 07/12] bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect
Implement the MRP API for interconnect switchdev. Similar with the other br_mrp_switchdev function, these function will just eventually call the switchdev functions: switchdev_port_obj_add/del. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_switchdev.c | 62 +++ net/bridge/br_private_mrp.h | 7 2 files changed, 69 insertions(+) diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c index 0da68a0da4b5a..ed547e03ace17 100644 --- a/net/bridge/br_mrp_switchdev.c +++ b/net/bridge/br_mrp_switchdev.c @@ -107,6 +107,68 @@ int br_mrp_switchdev_set_ring_state(struct net_bridge *br, return 0; } +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role) +{ + struct switchdev_obj_in_role_mrp mrp_role = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + .in_role = role, + .in_id = mrp->in_id, + .ring_id = mrp->ring_id, + .i_port = rtnl_dereference(mrp->i_port)->dev, + }; + int err; + + if (role == BR_MRP_IN_ROLE_DISABLED) + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); + else + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); + + return err; +} + +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state) +{ + struct switchdev_obj_in_state_mrp mrp_state = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP, + .in_state = state, + .in_id = mrp->in_id, + }; + int err; + + err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period) +{ + struct switchdev_obj_in_test_mrp test = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP, + .interval = interval, + .max_miss = max_miss, + .in_id = mrp->in_id, + .period = period, + }; + int err; + + if (interval == 0) + err = switchdev_port_obj_del(br->dev, &test.obj); + else + err = switchdev_port_obj_add(br->dev, &test.obj, NULL); + + return err; +} + int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state) { diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 23da2f956ad0e..0d554ef88db85 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -72,6 +72,13 @@ int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role); +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state); +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period); /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); -- 2.27.0
[Bridge] [PATCH net-next v3 03/12] bridge: mrp: Extend bridge interface
This patch adds a new flag(BR_MRP_LOST_IN_CONT) to the net bridge ports. This bit will be set when the port lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/linux/if_bridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index b3a8d3054af0f..6479a38e52fa9 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -49,6 +49,7 @@ struct br_ip_list { #define BR_ISOLATEDBIT(16) #define BR_MRP_AWARE BIT(17) #define BR_MRP_LOST_CONT BIT(18) +#define BR_MRP_LOST_IN_CONTBIT(19) #define BR_DEFAULT_AGEING_TIME (300 * HZ) -- 2.27.0
[Bridge] [PATCH net-next v3 06/12] bridge: mrp: Add br_mrp_in_port_open function
This function notifies the userspace when the node lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 22 ++ net/bridge/br_private_mrp.h | 1 + 2 files changed, 23 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index acce300c0cc29..4bf7aaeb29152 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -389,3 +389,25 @@ int br_mrp_ring_port_open(struct net_device *dev, u8 loc) out: return err; } + +int br_mrp_in_port_open(struct net_device *dev, u8 loc) +{ + struct net_bridge_port *p; + int err = 0; + + p = br_port_get_rcu(dev); + if (!p) { + err = -EINVAL; + goto out; + } + + if (loc) + p->flags |= BR_MRP_LOST_IN_CONT; + else + p->flags &= ~BR_MRP_LOST_IN_CONT; + + br_ifinfo_notify(RTM_NEWLINK, NULL, p); + +out: + return err; +} diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index e93c8f9d4df58..23da2f956ad0e 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -75,5 +75,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); +int br_mrp_in_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v3 10/12] bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status
Extend the existing MRP_INFO to return status of MRP interconnect. In case there is no MRP interconnect on the node then the role will be disabled so the other attributes can be ignored. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index d840a3e37a37c..c1227aecd38fd 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -243,6 +243,11 @@ enum { IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + IFLA_BRIDGE_MRP_INFO_I_IFINDEX, + IFLA_BRIDGE_MRP_INFO_IN_STATE, + IFLA_BRIDGE_MRP_INFO_IN_ROLE, + IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, __IFLA_BRIDGE_MRP_INFO_MAX, }; -- 2.27.0
[Bridge] [PATCH net-next v3 05/12] bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open
This patch renames the function br_mrp_port_open to br_mrp_ring_port_open. In this way is more clear that a ring port lost the continuity because there will be also a br_mrp_in_port_open. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 6 +++--- net/bridge/br_mrp_netlink.c | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 90592af9db619..fe7cf1446b58a 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -213,7 +213,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } p = rcu_dereference(mrp->s_port); @@ -229,7 +229,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } out: @@ -537,7 +537,7 @@ static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port, * not closed */ if (mrp->ring_state != BR_MRP_RING_STATE_CLOSED) - br_mrp_port_open(port->dev, false); + br_mrp_ring_port_open(port->dev, false); } /* Determin if the test hdr has a better priority than the node */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index c4f5c356811f3..acce300c0cc29 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -368,7 +368,7 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) return -EMSGSIZE; } -int br_mrp_port_open(struct net_device *dev, u8 loc) +int br_mrp_ring_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; int err = 0; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 8841ba847fb29..e93c8f9d4df58 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -74,6 +74,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); /* br_mrp_netlink.c */ -int br_mrp_port_open(struct net_device *dev, u8 loc); +int br_mrp_ring_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v3 01/12] switchdev: mrp: Extend switchdev API for MRP Interconnect
Extend switchdev API to add support for MRP interconnect. The HW is notified in the following cases: SWITCHDEV_OBJ_ID_IN_ROLE_MRP: This is used when the interconnect role of the node changes. The supported roles are MIM and MIC. SWITCHDEV_OBJ_ID_IN_STATE_MRP: This is used when the interconnect ring changes it states to open or closed. SWITCHDEV_OBJ_ID_IN_TEST_MRP: This is used to start/stop sending MRP_InTest frames on all MRP ports. This is called only on nodes that have the interconnect role MIM. Signed-off-by: Horatiu Vultur --- include/net/switchdev.h | 38 ++ 1 file changed, 38 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b8c059b4e06d9..ff22469143013 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -76,6 +76,10 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_RING_TEST_MRP, SWITCHDEV_OBJ_ID_RING_ROLE_MRP, SWITCHDEV_OBJ_ID_RING_STATE_MRP, + SWITCHDEV_OBJ_ID_IN_TEST_MRP, + SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + SWITCHDEV_OBJ_ID_IN_STATE_MRP, + #endif }; @@ -155,6 +159,40 @@ struct switchdev_obj_ring_state_mrp { #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) +/* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ +struct switchdev_obj_in_test_mrp { + struct switchdev_obj obj; + /* The value is in us and a value of 0 represents to stop */ + u32 interval; + u32 in_id; + u32 period; + u8 max_miss; +}; + +#define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) + +/* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ +struct switchdev_obj_in_role_mrp { + struct switchdev_obj obj; + struct net_device *i_port; + u32 ring_id; + u16 in_id; + u8 in_role; +}; + +#define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) + +struct switchdev_obj_in_state_mrp { + struct switchdev_obj obj; + u32 in_id; + u8 in_state; +}; + +#define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) + #endif typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); -- 2.27.0
[Bridge] [PATCH net-next v3 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which allows to notify the userspace when the node lost the contiuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c| 3 +++ tools/include/uapi/linux/if_link.h | 1 + 3 files changed, 5 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index cc185a007ade8..26842ffd0501d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index c532fa65c9834..147d52596e174 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) #endif + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_RING_OPEN */ + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN */ + 0; } @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, !!(p->flags & BR_NEIGH_SUPPRESS)) || nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & BR_MRP_LOST_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, + !!(p->flags & BR_MRP_LOST_IN_CONT)) || nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) return -EMSGSIZE; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cafedbbfefbe9..781e482dc499f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -- 2.27.0
[Bridge] [PATCH net-next v3 02/12] bridge: uapi: mrp: Extend MRP attributes for MRP interconnect
Extend the existing MRP netlink attributes to allow to configure MRP Interconnect: IFLA_BRIDGE_MRP_IN_ROLE - the parameter type is br_mrp_in_role which contains the interconnect id, the ring id, the interconnect role(MIM or MIC) and the port ifindex that represents the interconnect port. IFLA_BRIDGE_MRP_IN_STATE - the parameter type is br_mrp_in_state which contains the interconnect id and the interconnect state. IFLA_BRIDGE_MRP_IN_TEST - the parameter type is br_mrp_start_in_test which contains the interconnect id, the interval at which to send MRP_InTest frames, how many test frames can be missed before declaring the interconnect ring open and the period which represents for how long to send MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 53 + include/uapi/linux/mrp_bridge.h | 38 +++ 2 files changed, 91 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index c114c1c2bd533..d840a3e37a37c 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -167,6 +167,9 @@ enum { IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, IFLA_BRIDGE_MRP_INFO, + IFLA_BRIDGE_MRP_IN_ROLE, + IFLA_BRIDGE_MRP_IN_STATE, + IFLA_BRIDGE_MRP_START_IN_TEST, __IFLA_BRIDGE_MRP_MAX, }; @@ -245,6 +248,37 @@ enum { #define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) +enum { + IFLA_BRIDGE_MRP_IN_STATE_UNSPEC, + IFLA_BRIDGE_MRP_IN_STATE_IN_ID, + IFLA_BRIDGE_MRP_IN_STATE_STATE, + __IFLA_BRIDGE_MRP_IN_STATE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC, + IFLA_BRIDGE_MRP_IN_ROLE_RING_ID, + IFLA_BRIDGE_MRP_IN_ROLE_IN_ID, + IFLA_BRIDGE_MRP_IN_ROLE_ROLE, + IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX, + __IFLA_BRIDGE_MRP_IN_ROLE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC, + IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID, + IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD, + __IFLA_BRIDGE_MRP_START_IN_TEST_MAX, +}; + +#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; @@ -270,6 +304,25 @@ struct br_mrp_start_test { __u32 monitor; }; +struct br_mrp_in_state { + __u32 in_state; + __u16 in_id; +}; + +struct br_mrp_in_role { + __u32 ring_id; + __u32 in_role; + __u32 i_ifindex; + __u16 in_id; +}; + +struct br_mrp_start_in_test { + __u32 interval; + __u32 max_miss; + __u32 period; + __u16 in_id; +}; + struct bridge_stp_xstats { __u64 transition_blk; __u64 transition_fwd; diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index bee3665402129..6aeb13ef0b1ec 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -21,11 +21,22 @@ enum br_mrp_ring_role_type { BR_MRP_RING_ROLE_MRA, }; +enum br_mrp_in_role_type { + BR_MRP_IN_ROLE_DISABLED, + BR_MRP_IN_ROLE_MIC, + BR_MRP_IN_ROLE_MIM, +}; + enum br_mrp_ring_state_type { BR_MRP_RING_STATE_OPEN, BR_MRP_RING_STATE_CLOSED, }; +enum br_mrp_in_state_type { + BR_MRP_IN_STATE_OPEN, + BR_MRP_IN_STATE_CLOSED, +}; + enum br_mrp_port_state_type { BR_MRP_PORT_STATE_DISABLED, BR_MRP_PORT_STATE_BLOCKED, @@ -36,6 +47,7 @@ enum br_mrp_port_state_type { enum br_mrp_port_role_type { BR_MRP_PORT_ROLE_PRIMARY, BR_MRP_PORT_ROLE_SECONDARY, + BR_MRP_PORT_ROLE_INTER, }; enum br_mrp_tlv_header_type { @@ -45,6 +57,10 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_RING_TOPO = 0x3, BR_MRP_TLV_HEADER_RING_LINK_DOWN = 0x4, BR_MRP_TLV_HEADER_RING_LINK_UP = 0x5, + BR_MRP_TLV_HEADER_IN_TEST = 0x6, + BR_MRP_TLV_HEADER_IN_TOPO = 0x7, + BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, + BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; @@ -118,4 +134,26 @@ struct br_mrp_oui_hdr { __u8 oui[MRP_OUI_LENGTH]; }; +struct br_mrp_in_test_hdr { + __be16 id; + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 state; + __be16 transitions; + __be32 timestamp; +}; + +struct br_mrp_in_topo_hdr { + __u8 sa[ETH_ALEN]; + __be16 id; + __be16 interval; +}; + +struct br_mrp_in_link_hdr { + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 id; + __be16 interval; +}; + #endif -- 2.27.0
Re: [Bridge] [PATCH net-next v3 08/12] bridge: mrp: Implement the MRP Interconnect API
The 07/13/2020 21:54, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 12/07/2020 17:05, Horatiu Vultur wrote: > > Thie patch adds support for MRP Interconnect. Similar with the MRP ring, > > if the HW can't generate MRP_InTest frames, then the SW will try to > > generate them. And if also the SW fails to generate the frames then an > > error is return to userspace. > > > > The forwarding/termination of MRP_In frames is happening in the kernel > > and is done by MRP instances. > > > > Signed-off-by: Horatiu Vultur > > --- > > net/bridge/br_mrp.c | 570 ++-- > > net/bridge/br_private_mrp.h | 4 + > > 2 files changed, 543 insertions(+), 31 deletions(-) > > > > diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c > > index fe7cf1446b58a..bf05ae093faa2 100644 > > --- a/net/bridge/br_mrp.c > > +++ b/net/bridge/br_mrp.c > > @@ -4,6 +4,27 @@ > > #include "br_private_mrp.h" > > > > static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 > > }; > > +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, > > 0x3 }; > > + > > +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, > > + struct net_bridge_port *s_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == p_port || > > + port == s_port) > > + return true; > > + > > + return false; > > +} > > + > > +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, > > + struct net_bridge_port *port) > > +{ > > + if (port == i_port) > > + return true; > > + > > + return false; > > +} > > > > static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, > > u32 ifindex) > > @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge > > *br, u32 ring_id) > > return res; > > } > > > > +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) > > +{ > > + struct br_mrp *res = NULL; > > + struct br_mrp *mrp; > > + > > + list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > + lockdep_rtnl_is_held()) { > > + if (mrp->in_id == in_id) { > > + res = mrp; > > + break; > > + } > > + } > > + > > + return res; > > +} > > + > > static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) > > { > > struct br_mrp *mrp; > > @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, > > u32 ifindex) > > p = rtnl_dereference(mrp->s_port); > > if (p && p->dev->ifindex == ifindex) > > return false; > > + > > + p = rtnl_dereference(mrp->i_port); > > + if (p && p->dev->ifindex == ifindex) > > + return false; > > } > > > > return true; > > @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge > > *br, > > list_for_each_entry_rcu(mrp, &br->mrp_list, list, > > lockdep_rtnl_is_held()) { > > if (rcu_access_pointer(mrp->p_port) == p || > > - rcu_access_pointer(mrp->s_port) == p) { > > + rcu_access_pointer(mrp->s_port) == p || > > + rcu_access_pointer(mrp->i_port) == p) { > > res = mrp; > > break; > > } > > @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct > > br_mrp *mrp, > > return skb; > > } > > > > +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, > > + struct net_bridge_port *p, > > + enum br_mrp_port_role_type > > port_role) > > +{ > > + struct br_mrp_in_test_hdr *hdr = NULL; > > + struct sk_buff *skb = NULL; > > + > > + if (!p) > > + return NULL; > > + > > + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); > > + if (!skb) > > + return NULL; > > + > > + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); > > + hdr = skb_put(skb, sizeof(*hdr)); > > + > > + hdr->id = cpu_to_be16(mrp->in_id); > > + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); > > + hdr->port_role = cpu_to_be16(port_role); > > + hdr->state = cpu_to_be16(mrp->in_state); > > + hdr->transitions = cpu_to_be16(mrp->in_transitions); > > + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); > > + > > + br_mrp_skb_common(skb, mrp); > > + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); > > + > > + return skb; > > +} > > + > > /* This function is continuously called in the following cases: > > * - when node role is MRM, in this case test_monitor
[Bridge] [PATCH net-next v4 01/12] switchdev: mrp: Extend switchdev API for MRP Interconnect
Extend switchdev API to add support for MRP interconnect. The HW is notified in the following cases: SWITCHDEV_OBJ_ID_IN_ROLE_MRP: This is used when the interconnect role of the node changes. The supported roles are MIM and MIC. SWITCHDEV_OBJ_ID_IN_STATE_MRP: This is used when the interconnect ring changes it states to open or closed. SWITCHDEV_OBJ_ID_IN_TEST_MRP: This is used to start/stop sending MRP_InTest frames on all MRP ports. This is called only on nodes that have the interconnect role MIM. Signed-off-by: Horatiu Vultur --- include/net/switchdev.h | 38 ++ 1 file changed, 38 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b8c059b4e06d9..ff22469143013 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -76,6 +76,10 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_RING_TEST_MRP, SWITCHDEV_OBJ_ID_RING_ROLE_MRP, SWITCHDEV_OBJ_ID_RING_STATE_MRP, + SWITCHDEV_OBJ_ID_IN_TEST_MRP, + SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + SWITCHDEV_OBJ_ID_IN_STATE_MRP, + #endif }; @@ -155,6 +159,40 @@ struct switchdev_obj_ring_state_mrp { #define SWITCHDEV_OBJ_RING_STATE_MRP(OBJ) \ container_of((OBJ), struct switchdev_obj_ring_state_mrp, obj) +/* SWITCHDEV_OBJ_ID_IN_TEST_MRP */ +struct switchdev_obj_in_test_mrp { + struct switchdev_obj obj; + /* The value is in us and a value of 0 represents to stop */ + u32 interval; + u32 in_id; + u32 period; + u8 max_miss; +}; + +#define SWITCHDEV_OBJ_IN_TEST_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_test_mrp, obj) + +/* SWICHDEV_OBJ_ID_IN_ROLE_MRP */ +struct switchdev_obj_in_role_mrp { + struct switchdev_obj obj; + struct net_device *i_port; + u32 ring_id; + u16 in_id; + u8 in_role; +}; + +#define SWITCHDEV_OBJ_IN_ROLE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_role_mrp, obj) + +struct switchdev_obj_in_state_mrp { + struct switchdev_obj obj; + u32 in_id; + u8 in_state; +}; + +#define SWITCHDEV_OBJ_IN_STATE_MRP(OBJ) \ + container_of((OBJ), struct switchdev_obj_in_state_mrp, obj) + #endif typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); -- 2.27.0
[Bridge] [PATCH net-next v4 00/12] bridge: mrp: Add support for interconnect ring
This patch series extends existing MRP to add support for interconnect ring. An interconnect ring is a ring that connects 2 rings. In this way is possible to connect multiple rings. Each interconnect ring is form of 4 nodes, in which 3 have the role MIC(Media Redundancy Interconnect Client) and one has the role MIM(Media Redundancy Interconnect Manager). All these nodes need to have the same ID and the ID needs to be unique between multiple interconnect rings. And 2 nodes needs to be part of one ring and the other 2 nodes needs to be part of the other ring that is connected. +-+ | | +--| MRM |---+ | | | | | +-+ | || || || +--+ +-+ | | | | | MRC/MIC |--|MRC/MIM | | | | | +--+ +-+ | | |Interconnect port|Interconnect port | | | | +--+ +-+ | | | | | MRC/MIC |- | MRC/MIC | | | | | +--+ +-+ | | | | | +-+| | | || +--| MRM|+ | | +-+ Each node in a ring needs to have one of the following ring roles, MRM or MRC. And it can also have an interconnect role like MIM or MIC if it is part of an interconnect ring. In the figure above the MRM doesn't have any interconnect role but the MRC from the top ring have the interconnect roles MIC respectively MIM. Therefore it is not possible for a node to have only an interconnect role. There are 2 ways for interconnect ring to detect when is open or closed: 1. To use CCM frames on the interconnect port to detect when the interconnect link goes down/up. This mode is called LC-mode. 2. To send InTest frames on all 3 ports(2 ring ports and 1 interconnect port) and detect when these frames are received back. This mode is called RC-mode. This patch series adds support only for RC-mode. Where MIM sends InTest frames on all 3 ports and detects when it receives back the InTest. When it receives the InTest it means that the ring is closed so it would set the interconnect port in blocking state. If it stops receiving the InTest frames then it would set the port in forwarding state and it would send InTopo frames. These InTopo frames will be received by MRM nodes and process them. And then the MRM will send Topo frames in the rings so each client will clear its FDB. v4: - always cancel delay work if the MRP instance is deleted or interconnect role is disabled but allow only to start to send InTest frames only if the role is MIM. v3: - update 'br_mrp_set_in_role' to stop sending test if the role is disabled and don't allow to set a different interconnect port if there is already one. v2: - rearrange structures not to contain holes - stop sending MRP_InTest frames when the MRP instance is deleted Horatiu Vultur (12): switchdev: mrp: Extend switchdev API for MRP Interconnect bridge: uapi: mrp: Extend MRP attributes for MRP interconnect bridge: mrp: Extend bridge interface bridge: mrp: Extend br_mrp for MRP interconnect bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open bridge: mrp: Add br_mrp_in_port_open function bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect bridge: mrp: Implement the MRP Interconnect API bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status bridge: mrp: Extend br_mrp_fill_info net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN include/linux/if_bridge.h | 1 + include/net/switchdev.h| 38 ++ include/uapi/linux/if_bridge.h | 58 +++ include/uapi/linux/if_link.h | 1 + include/uapi/linux/mrp_bridge.h| 38 ++ net/bridge/br_mrp.c| 576 +++-- net/bridge/br_mrp_netlink.c| 182 - net/bridge/br_mrp_switchdev.c | 62 net/bridge/br_netlink.c| 3 + net/bridge/br_private_mrp.h| 27 +- tools/include/uapi/linux/if_link.h | 1 + 11 files changed, 951 insertions(+), 36 deletio
[Bridge] [PATCH net-next v4 02/12] bridge: uapi: mrp: Extend MRP attributes for MRP interconnect
Extend the existing MRP netlink attributes to allow to configure MRP Interconnect: IFLA_BRIDGE_MRP_IN_ROLE - the parameter type is br_mrp_in_role which contains the interconnect id, the ring id, the interconnect role(MIM or MIC) and the port ifindex that represents the interconnect port. IFLA_BRIDGE_MRP_IN_STATE - the parameter type is br_mrp_in_state which contains the interconnect id and the interconnect state. IFLA_BRIDGE_MRP_IN_TEST - the parameter type is br_mrp_start_in_test which contains the interconnect id, the interval at which to send MRP_InTest frames, how many test frames can be missed before declaring the interconnect ring open and the period which represents for how long to send MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 53 + include/uapi/linux/mrp_bridge.h | 38 +++ 2 files changed, 91 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index c114c1c2bd533..d840a3e37a37c 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -167,6 +167,9 @@ enum { IFLA_BRIDGE_MRP_RING_ROLE, IFLA_BRIDGE_MRP_START_TEST, IFLA_BRIDGE_MRP_INFO, + IFLA_BRIDGE_MRP_IN_ROLE, + IFLA_BRIDGE_MRP_IN_STATE, + IFLA_BRIDGE_MRP_START_IN_TEST, __IFLA_BRIDGE_MRP_MAX, }; @@ -245,6 +248,37 @@ enum { #define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1) +enum { + IFLA_BRIDGE_MRP_IN_STATE_UNSPEC, + IFLA_BRIDGE_MRP_IN_STATE_IN_ID, + IFLA_BRIDGE_MRP_IN_STATE_STATE, + __IFLA_BRIDGE_MRP_IN_STATE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC, + IFLA_BRIDGE_MRP_IN_ROLE_RING_ID, + IFLA_BRIDGE_MRP_IN_ROLE_IN_ID, + IFLA_BRIDGE_MRP_IN_ROLE_ROLE, + IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX, + __IFLA_BRIDGE_MRP_IN_ROLE_MAX, +}; + +#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1) + +enum { + IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC, + IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID, + IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS, + IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD, + __IFLA_BRIDGE_MRP_START_IN_TEST_MAX, +}; + +#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1) + struct br_mrp_instance { __u32 ring_id; __u32 p_ifindex; @@ -270,6 +304,25 @@ struct br_mrp_start_test { __u32 monitor; }; +struct br_mrp_in_state { + __u32 in_state; + __u16 in_id; +}; + +struct br_mrp_in_role { + __u32 ring_id; + __u32 in_role; + __u32 i_ifindex; + __u16 in_id; +}; + +struct br_mrp_start_in_test { + __u32 interval; + __u32 max_miss; + __u32 period; + __u16 in_id; +}; + struct bridge_stp_xstats { __u64 transition_blk; __u64 transition_fwd; diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index bee3665402129..6aeb13ef0b1ec 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -21,11 +21,22 @@ enum br_mrp_ring_role_type { BR_MRP_RING_ROLE_MRA, }; +enum br_mrp_in_role_type { + BR_MRP_IN_ROLE_DISABLED, + BR_MRP_IN_ROLE_MIC, + BR_MRP_IN_ROLE_MIM, +}; + enum br_mrp_ring_state_type { BR_MRP_RING_STATE_OPEN, BR_MRP_RING_STATE_CLOSED, }; +enum br_mrp_in_state_type { + BR_MRP_IN_STATE_OPEN, + BR_MRP_IN_STATE_CLOSED, +}; + enum br_mrp_port_state_type { BR_MRP_PORT_STATE_DISABLED, BR_MRP_PORT_STATE_BLOCKED, @@ -36,6 +47,7 @@ enum br_mrp_port_state_type { enum br_mrp_port_role_type { BR_MRP_PORT_ROLE_PRIMARY, BR_MRP_PORT_ROLE_SECONDARY, + BR_MRP_PORT_ROLE_INTER, }; enum br_mrp_tlv_header_type { @@ -45,6 +57,10 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_RING_TOPO = 0x3, BR_MRP_TLV_HEADER_RING_LINK_DOWN = 0x4, BR_MRP_TLV_HEADER_RING_LINK_UP = 0x5, + BR_MRP_TLV_HEADER_IN_TEST = 0x6, + BR_MRP_TLV_HEADER_IN_TOPO = 0x7, + BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, + BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; @@ -118,4 +134,26 @@ struct br_mrp_oui_hdr { __u8 oui[MRP_OUI_LENGTH]; }; +struct br_mrp_in_test_hdr { + __be16 id; + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 state; + __be16 transitions; + __be32 timestamp; +}; + +struct br_mrp_in_topo_hdr { + __u8 sa[ETH_ALEN]; + __be16 id; + __be16 interval; +}; + +struct br_mrp_in_link_hdr { + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 id; + __be16 interval; +}; + #endif -- 2.27.0
[Bridge] [PATCH net-next v4 08/12] bridge: mrp: Implement the MRP Interconnect API
Thie patch adds support for MRP Interconnect. Similar with the MRP ring, if the HW can't generate MRP_InTest frames, then the SW will try to generate them. And if also the SW fails to generate the frames then an error is return to userspace. The forwarding/termination of MRP_In frames is happening in the kernel and is done by MRP instances. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 570 ++-- net/bridge/br_private_mrp.h | 4 + 2 files changed, 543 insertions(+), 31 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index fe7cf1446b58a..b36689e6e7cba 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -4,6 +4,27 @@ #include "br_private_mrp.h" static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; +static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; + +static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, + struct net_bridge_port *s_port, + struct net_bridge_port *port) +{ + if (port == p_port || + port == s_port) + return true; + + return false; +} + +static bool br_mrp_is_in_port(struct net_bridge_port *i_port, + struct net_bridge_port *port) +{ + if (port == i_port) + return true; + + return false; +} static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, u32 ifindex) @@ -37,6 +58,22 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) return res; } +static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) +{ + struct br_mrp *res = NULL; + struct br_mrp *mrp; + + list_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { + if (mrp->in_id == in_id) { + res = mrp; + break; + } + } + + return res; +} + static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; @@ -52,6 +89,10 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) p = rtnl_dereference(mrp->s_port); if (p && p->dev->ifindex == ifindex) return false; + + p = rtnl_dereference(mrp->i_port); + if (p && p->dev->ifindex == ifindex) + return false; } return true; @@ -66,7 +107,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, list_for_each_entry_rcu(mrp, &br->mrp_list, list, lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || - rcu_access_pointer(mrp->s_port) == p) { + rcu_access_pointer(mrp->s_port) == p || + rcu_access_pointer(mrp->i_port) == p) { res = mrp; break; } @@ -160,6 +202,36 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp, return skb; } +static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, + struct net_bridge_port *p, + enum br_mrp_port_role_type port_role) +{ + struct br_mrp_in_test_hdr *hdr = NULL; + struct sk_buff *skb = NULL; + + if (!p) + return NULL; + + skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); + if (!skb) + return NULL; + + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); + + hdr->id = cpu_to_be16(mrp->in_id); + ether_addr_copy(hdr->sa, p->br->dev->dev_addr); + hdr->port_role = cpu_to_be16(port_role); + hdr->state = cpu_to_be16(mrp->in_state); + hdr->transitions = cpu_to_be16(mrp->in_transitions); + hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); + + br_mrp_skb_common(skb, mrp); + br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); + + return skb; +} + /* This function is continuously called in the following cases: * - when node role is MRM, in this case test_monitor is always set to false * because it needs to notify the userspace that the ring is open and needs to @@ -239,6 +311,83 @@ static void br_mrp_test_work_expired(struct work_struct *work) usecs_to_jiffies(mrp->test_interval)); } +/* This function is continuously called when the node has the interconnect role + * MIM. It would generate interconnect test frames and will send them on all 3 + * ports. But will also check if it stop receiving interconnect test frames. + */ +static void br_mrp_in_test_work_expired(struct work_struct *work) +{ + struct
[Bridge] [PATCH net-next v4 05/12] bridge: mrp: Rename br_mrp_port_open to br_mrp_ring_port_open
This patch renames the function br_mrp_port_open to br_mrp_ring_port_open. In this way is more clear that a ring port lost the continuity because there will be also a br_mrp_in_port_open. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp.c | 6 +++--- net/bridge/br_mrp_netlink.c | 2 +- net/bridge/br_private_mrp.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index 90592af9db619..fe7cf1446b58a 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -213,7 +213,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } p = rcu_dereference(mrp->s_port); @@ -229,7 +229,7 @@ static void br_mrp_test_work_expired(struct work_struct *work) } if (notify_open && !mrp->ring_role_offloaded) - br_mrp_port_open(p->dev, true); + br_mrp_ring_port_open(p->dev, true); } out: @@ -537,7 +537,7 @@ static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port, * not closed */ if (mrp->ring_state != BR_MRP_RING_STATE_CLOSED) - br_mrp_port_open(port->dev, false); + br_mrp_ring_port_open(port->dev, false); } /* Determin if the test hdr has a better priority than the node */ diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index c4f5c356811f3..acce300c0cc29 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -368,7 +368,7 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) return -EMSGSIZE; } -int br_mrp_port_open(struct net_device *dev, u8 loc) +int br_mrp_ring_port_open(struct net_device *dev, u8 loc) { struct net_bridge_port *p; int err = 0; diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 8841ba847fb29..e93c8f9d4df58 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -74,6 +74,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); /* br_mrp_netlink.c */ -int br_mrp_port_open(struct net_device *dev, u8 loc); +int br_mrp_ring_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v4 06/12] bridge: mrp: Add br_mrp_in_port_open function
This function notifies the userspace when the node lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 22 ++ net/bridge/br_private_mrp.h | 1 + 2 files changed, 23 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index acce300c0cc29..4bf7aaeb29152 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -389,3 +389,25 @@ int br_mrp_ring_port_open(struct net_device *dev, u8 loc) out: return err; } + +int br_mrp_in_port_open(struct net_device *dev, u8 loc) +{ + struct net_bridge_port *p; + int err = 0; + + p = br_port_get_rcu(dev); + if (!p) { + err = -EINVAL; + goto out; + } + + if (loc) + p->flags |= BR_MRP_LOST_IN_CONT; + else + p->flags &= ~BR_MRP_LOST_IN_CONT; + + br_ifinfo_notify(RTM_NEWLINK, NULL, p); + +out: + return err; +} diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index e93c8f9d4df58..23da2f956ad0e 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -75,5 +75,6 @@ int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); +int br_mrp_in_port_open(struct net_device *dev, u8 loc); #endif /* _BR_PRIVATE_MRP_H */ -- 2.27.0
[Bridge] [PATCH net-next v4 11/12] bridge: mrp: Extend br_mrp_fill_info
This patch extends the function br_mrp_fill_info to return also the status for the interconnect ring. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index a006e0771e8d3..2a2fdf3500c5b 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -474,6 +474,11 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) p->dev->ifindex)) goto nla_put_failure; + p = rcu_dereference(mrp->i_port); + if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, +p->dev->ifindex)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, mrp->prio)) goto nla_put_failure; @@ -493,6 +498,19 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) mrp->test_monitor)) goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, + mrp->in_state)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, + mrp->in_role)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + mrp->in_test_interval)) + goto nla_put_failure; + if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, + mrp->in_test_max_miss)) + goto nla_put_failure; + nla_nest_end(skb, tb); } nla_nest_end(skb, mrp_tb); -- 2.27.0
[Bridge] [PATCH net-next v4 07/12] bridge: switchdev: mrp: Extend MRP API for switchdev for MRP Interconnect
Implement the MRP API for interconnect switchdev. Similar with the other br_mrp_switchdev function, these function will just eventually call the switchdev functions: switchdev_port_obj_add/del. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_switchdev.c | 62 +++ net/bridge/br_private_mrp.h | 7 2 files changed, 69 insertions(+) diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c index 0da68a0da4b5a..ed547e03ace17 100644 --- a/net/bridge/br_mrp_switchdev.c +++ b/net/bridge/br_mrp_switchdev.c @@ -107,6 +107,68 @@ int br_mrp_switchdev_set_ring_state(struct net_bridge *br, return 0; } +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role) +{ + struct switchdev_obj_in_role_mrp mrp_role = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP, + .in_role = role, + .in_id = mrp->in_id, + .ring_id = mrp->ring_id, + .i_port = rtnl_dereference(mrp->i_port)->dev, + }; + int err; + + if (role == BR_MRP_IN_ROLE_DISABLED) + err = switchdev_port_obj_del(br->dev, &mrp_role.obj); + else + err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL); + + return err; +} + +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state) +{ + struct switchdev_obj_in_state_mrp mrp_state = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP, + .in_state = state, + .in_id = mrp->in_id, + }; + int err; + + err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL); + + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period) +{ + struct switchdev_obj_in_test_mrp test = { + .obj.orig_dev = br->dev, + .obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP, + .interval = interval, + .max_miss = max_miss, + .in_id = mrp->in_id, + .period = period, + }; + int err; + + if (interval == 0) + err = switchdev_port_obj_del(br->dev, &test.obj); + else + err = switchdev_port_obj_add(br->dev, &test.obj, NULL); + + return err; +} + int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state) { diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 23da2f956ad0e..0d554ef88db85 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -72,6 +72,13 @@ int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, enum br_mrp_port_state_type state); int br_mrp_port_switchdev_set_role(struct net_bridge_port *p, enum br_mrp_port_role_type role); +int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp, +u16 in_id, u32 ring_id, +enum br_mrp_in_role_type role); +int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp, + enum br_mrp_in_state_type state); +int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp, + u32 interval, u8 max_miss, u32 period); /* br_mrp_netlink.c */ int br_mrp_ring_port_open(struct net_device *dev, u8 loc); -- 2.27.0
[Bridge] [PATCH net-next v4 10/12] bridge: uapi: mrp: Extend MRP_INFO attributes for interconnect status
Extend the existing MRP_INFO to return status of MRP interconnect. In case there is no MRP interconnect on the node then the role will be disabled so the other attributes can be ignored. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_bridge.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index d840a3e37a37c..c1227aecd38fd 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -243,6 +243,11 @@ enum { IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, + IFLA_BRIDGE_MRP_INFO_I_IFINDEX, + IFLA_BRIDGE_MRP_INFO_IN_STATE, + IFLA_BRIDGE_MRP_INFO_IN_ROLE, + IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, + IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, __IFLA_BRIDGE_MRP_INFO_MAX, }; -- 2.27.0
[Bridge] [PATCH net-next v4 09/12] bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect
This patch extends the existing MRP netlink interface with the following attributes: IFLA_BRIDGE_MRP_IN_ROLE, IFLA_BRIDGE_MRP_IN_STATE and IFLA_BRIDGE_MRP_START_IN_TEST. These attributes are similar with their ring attributes but they apply to the interconnect port. Signed-off-by: Horatiu Vultur --- net/bridge/br_mrp_netlink.c | 140 1 file changed, 140 insertions(+) diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 4bf7aaeb29152..a006e0771e8d3 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -14,6 +14,9 @@ static const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { [IFLA_BRIDGE_MRP_RING_STATE]= { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, [IFLA_BRIDGE_MRP_START_TEST]= { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, + [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -235,6 +238,121 @@ static int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, return br_mrp_start_test(br, &test); } +static const struct nla_policy +br_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_STATE_IN_ID]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_STATE_STATE]= { .type = NLA_U32 }, +}; + +static int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, +struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; + struct br_mrp_in_state state; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, + br_mrp_in_state_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: IN_ID or STATE"); + return -EINVAL; + } + + memset(&state, 0x0, sizeof(state)); + + state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); + state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); + + return br_mrp_set_in_state(br, &state); +} + +static const struct nla_policy +br_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { + [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC]= { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, + [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, +}; + +static int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; + struct br_mrp_in_role role; + int err; + + err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, + br_mrp_in_role_policy, extack); + if (err) + return err; + + if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || + !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { + NL_SET_ERR_MSG_MOD(extack, + "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); + return -EINVAL; + } + + memset(&role, 0x0, sizeof(role)); + + role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); + role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); + role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); + role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); + + return br_mrp_set_in_role(br, &role); +} + +static const struct nla_policy +br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { + [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, + [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]= { .type = NLA_U32 }, + [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, +}; + +static int br_mrp_start_in_test_parse(struct net_bridge *br, + struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; + struct br_mrp_start_in_test test; +
[Bridge] [PATCH net-next v4 03/12] bridge: mrp: Extend bridge interface
This patch adds a new flag(BR_MRP_LOST_IN_CONT) to the net bridge ports. This bit will be set when the port lost the continuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/linux/if_bridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index b3a8d3054af0f..6479a38e52fa9 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -49,6 +49,7 @@ struct br_ip_list { #define BR_ISOLATEDBIT(16) #define BR_MRP_AWARE BIT(17) #define BR_MRP_LOST_CONT BIT(18) +#define BR_MRP_LOST_IN_CONTBIT(19) #define BR_DEFAULT_AGEING_TIME (300 * HZ) -- 2.27.0
[Bridge] [PATCH net-next v4 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which allows to notify the userspace when the node lost the contiuity of MRP_InTest frames. Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c| 3 +++ tools/include/uapi/linux/if_link.h | 1 + 3 files changed, 5 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index cc185a007ade8..26842ffd0501d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index c532fa65c9834..147d52596e174 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) #endif + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_RING_OPEN */ + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN */ + 0; } @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, !!(p->flags & BR_NEIGH_SUPPRESS)) || nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & BR_MRP_LOST_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, + !!(p->flags & BR_MRP_LOST_IN_CONT)) || nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) return -EMSGSIZE; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cafedbbfefbe9..781e482dc499f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -344,6 +344,7 @@ enum { IFLA_BRPORT_ISOLATED, IFLA_BRPORT_BACKUP_PORT, IFLA_BRPORT_MRP_RING_OPEN, + IFLA_BRPORT_MRP_IN_OPEN, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -- 2.27.0
[Bridge] [PATCH net-next v4 04/12] bridge: mrp: Extend br_mrp for MRP interconnect
This patch extends the 'struct br_mrp' to contain information regarding the MRP interconnect. It contains the following: - the interconnect port 'i_port', which is NULL if the node doesn't have a interconnect role - the interconnect id, which is similar with the ring id, but this field is also part of the MRP_InTest frames. - the interconnect role, which can be MIM or MIC. - the interconnect state, which can be open or closed. - the interconnect delayed_work for sending MRP_InTest frames and check for lost of continuity. Signed-off-by: Horatiu Vultur --- net/bridge/br_private_mrp.h | 13 + 1 file changed, 13 insertions(+) diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h index 315eb37d89f0f..8841ba847fb29 100644 --- a/net/bridge/br_private_mrp.h +++ b/net/bridge/br_private_mrp.h @@ -12,8 +12,10 @@ struct br_mrp { struct net_bridge_port __rcu*p_port; struct net_bridge_port __rcu*s_port; + struct net_bridge_port __rcu*i_port; u32 ring_id; + u16 in_id; u16 prio; enum br_mrp_ring_role_type ring_role; @@ -21,6 +23,11 @@ struct br_mrp { enum br_mrp_ring_state_type ring_state; u32 ring_transitions; + enum br_mrp_in_role_typein_role; + u8 in_role_offloaded; + enum br_mrp_in_state_type in_state; + u32 in_transitions; + struct delayed_work test_work; u32 test_interval; unsigned long test_end; @@ -28,6 +35,12 @@ struct br_mrp { u32 test_max_miss; booltest_monitor; + struct delayed_work in_test_work; + u32 in_test_interval; + unsigned long in_test_end; + u32 in_test_count_miss; + u32 in_test_max_miss; + u32 seq_id; struct rcu_head rcu; -- 2.27.0
Re: [Bridge] [PATCH net-next v4 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
The 07/14/2020 16:29, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 14/07/2020 10:34, Horatiu Vultur wrote: > > This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which > > allows to notify the userspace when the node lost the contiuity of > > MRP_InTest frames. > > > > Signed-off-by: Horatiu Vultur > > --- > > include/uapi/linux/if_link.h | 1 + > > net/bridge/br_netlink.c| 3 +++ > > tools/include/uapi/linux/if_link.h | 1 + > > 3 files changed, 5 insertions(+) > > Hi Nik, > > It's kind of late by now, but I'd wish these were contained in a nested MRP > attribute. :) > Horatiu, do you expect to have many more MRP attributes outside of MRP > netlink code? I don't expect to add any other MRP attributes outside of MRP netlink code. > > Perhaps we should at least dump them only for MRP-aware ports, that should be > easy. > They make no sense outside of MRP anyway, but increase the size of the dump > for all > right now. You are right. Then should I first send a fix on the net for this and after that I will fix these patches or just fix this in the next patch series? > > Acked-by: Nikolay Aleksandrov > > > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > > index cc185a007ade8..26842ffd0501d 100644 > > --- a/include/uapi/linux/if_link.h > > +++ b/include/uapi/linux/if_link.h > > @@ -344,6 +344,7 @@ enum { > > IFLA_BRPORT_ISOLATED, > > IFLA_BRPORT_BACKUP_PORT, > > IFLA_BRPORT_MRP_RING_OPEN, > > + IFLA_BRPORT_MRP_IN_OPEN, > > __IFLA_BRPORT_MAX > > }; > > #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) > > diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c > > index c532fa65c9834..147d52596e174 100644 > > --- a/net/bridge/br_netlink.c > > +++ b/net/bridge/br_netlink.c > > @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) > > #endif > > + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK > > */ > > + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_RING_OPEN > > */ > > + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN */ > > + 0; > > } > > > > @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, > > !!(p->flags & BR_NEIGH_SUPPRESS)) || > > nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & > > BR_MRP_LOST_CONT)) > > || > > + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, > > +!!(p->flags & BR_MRP_LOST_IN_CONT)) || > > nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) > > return -EMSGSIZE; > > > > diff --git a/tools/include/uapi/linux/if_link.h > > b/tools/include/uapi/linux/if_link.h > > index cafedbbfefbe9..781e482dc499f 100644 > > --- a/tools/include/uapi/linux/if_link.h > > +++ b/tools/include/uapi/linux/if_link.h > > @@ -344,6 +344,7 @@ enum { > > IFLA_BRPORT_ISOLATED, > > IFLA_BRPORT_BACKUP_PORT, > > IFLA_BRPORT_MRP_RING_OPEN, > > + IFLA_BRPORT_MRP_IN_OPEN, > > __IFLA_BRPORT_MAX > > }; > > #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) > > > -- /Horatiu
Re: [Bridge] [PATCH net-next v4 12/12] net: bridge: Add port attribute IFLA_BRPORT_MRP_IN_OPEN
The 07/14/2020 18:33, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 14/07/2020 18:07, Horatiu Vultur wrote: > > The 07/14/2020 16:29, Nikolay Aleksandrov wrote: > >> EXTERNAL EMAIL: Do not click links or open attachments unless you know the > >> content is safe > >> > >> On 14/07/2020 10:34, Horatiu Vultur wrote: > >>> This patch adds a new port attribute, IFLA_BRPORT_MRP_IN_OPEN, which > >>> allows to notify the userspace when the node lost the contiuity of > >>> MRP_InTest frames. > >>> > >>> Signed-off-by: Horatiu Vultur > >>> --- > >>> include/uapi/linux/if_link.h | 1 + > >>> net/bridge/br_netlink.c| 3 +++ > >>> tools/include/uapi/linux/if_link.h | 1 + > >>> 3 files changed, 5 insertions(+) > >>> > > > > Hi Nik, > > > >> > >> It's kind of late by now, but I'd wish these were contained in a nested > >> MRP attribute. :) > >> Horatiu, do you expect to have many more MRP attributes outside of MRP > >> netlink code? > > > > I don't expect to add any other MRP attributes outside of MRP netlink > > code. > > > >> > >> Perhaps we should at least dump them only for MRP-aware ports, that should > >> be easy. > >> They make no sense outside of MRP anyway, but increase the size of the > >> dump for all > >> right now. > > > > You are right. Then should I first send a fix on the net for this and > > after that I will fix these patches or just fix this in the next patch > > series? > > > > IMO it's more of an improvement rather than a bug, but since you don't expect > to have more > attributes outside of MRP's netlink I guess we can drop it for now. Up to you. OK, lets just drop it for now. > > It definitely shouldn't block this patch-set. > > >> > >> Acked-by: Nikolay Aleksandrov > >> > >>> diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > >>> index cc185a007ade8..26842ffd0501d 100644 > >>> --- a/include/uapi/linux/if_link.h > >>> +++ b/include/uapi/linux/if_link.h > >>> @@ -344,6 +344,7 @@ enum { > >>> IFLA_BRPORT_ISOLATED, > >>> IFLA_BRPORT_BACKUP_PORT, > >>> IFLA_BRPORT_MRP_RING_OPEN, > >>> + IFLA_BRPORT_MRP_IN_OPEN, > >>> __IFLA_BRPORT_MAX > >>> }; > >>> #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) > >>> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c > >>> index c532fa65c9834..147d52596e174 100644 > >>> --- a/net/bridge/br_netlink.c > >>> +++ b/net/bridge/br_netlink.c > >>> @@ -152,6 +152,7 @@ static inline size_t br_port_info_size(void) > >>> #endif > >>> + nla_total_size(sizeof(u16)) /* > >>> IFLA_BRPORT_GROUP_FWD_MASK */ > >>> + nla_total_size(sizeof(u8))/* > >>> IFLA_BRPORT_MRP_RING_OPEN */ > >>> + + nla_total_size(sizeof(u8))/* IFLA_BRPORT_MRP_IN_OPEN > >>> */ > >>> + 0; > >>> } > >>> > >>> @@ -216,6 +217,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, > >>> !!(p->flags & BR_NEIGH_SUPPRESS)) || > >>> nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & > >>> > >>> BR_MRP_LOST_CONT)) || > >>> + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, > >>> +!!(p->flags & BR_MRP_LOST_IN_CONT)) || > >>> nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & > >>> BR_ISOLATED))) > >>> return -EMSGSIZE; > >>> > >>> diff --git a/tools/include/uapi/linux/if_link.h > >>> b/tools/include/uapi/linux/if_link.h > >>> index cafedbbfefbe9..781e482dc499f 100644 > >>> --- a/tools/include/uapi/linux/if_link.h > >>> +++ b/tools/include/uapi/linux/if_link.h > >>> @@ -344,6 +344,7 @@ enum { > >>> IFLA_BRPORT_ISOLATED, > >>> IFLA_BRPORT_BACKUP_PORT, > >>> IFLA_BRPORT_MRP_RING_OPEN, > >>> + IFLA_BRPORT_MRP_IN_OPEN, > >>> __IFLA_BRPORT_MAX > >>> }; > >>> #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) > >>> > >> > > > -- /Horatiu
Re: [Bridge] [PATCH RFC 0/7] net: bridge: cfm: Add support for Connectivity Fault Management(CFM)
The 09/04/2020 15:44, Stephen Hemminger wrote: > > On Fri, 4 Sep 2020 09:15:20 + > Henrik Bjoernlund wrote: > > > Connectivity Fault Management (CFM) is defined in 802.1Q section 12.14. > > > > Connectivity Fault Management (CFM) comprises capabilities for > > detecting, verifying, and isolating connectivity failures in > > Virtual Bridged Networks. These capabilities can be used in > > networks operated by multiple independent organizations, each > > with restricted management access to each other’s equipment. > > > > CFM functions are partitioned as follows: > > — Path discovery > > — Fault detection > > — Fault verification and isolation > > — Fault notification > > — Fault recovery > > > > The primary CFM protocol shims are called Maintenance Points (MPs). > > A MP can be either a MEP or a MHF. > > The MEP: > > -It is the Maintenance association End Point > > described in 802.1Q section 19.2. > > -It is created on a specific level (1-7) and is assuring > > that no CFM frames are passing through this MEP on lower levels. > > -It initiates and terminates/validates CFM frames on its level. > > -It can only exist on a port that is related to a bridge. > > The MHF: > > -It is the Maintenance Domain Intermediate Point > > (MIP) Half Function (MHF) described in 802.1Q section 19.3. > > -It is created on a specific level (1-7). > > -It is extracting/injecting certain CFM frame on this level. > > -It can only exist on a port that is related to a bridge. > > -Currently not supported. > > > > There are defined the following CFM protocol functions: > > -Continuity Check > > -Loopback. Currently not supported. > > -Linktrace. Currently not supported. > > > > This CFM component supports create/delete of MEP instances and > > configuration of the different CFM protocols. Also status information > > can be fetched and delivered through notification due to defect status > > change. > > > > The user interacts with CFM using the 'cfm' user space client program, the > > client talks with the kernel using netlink. The kernel will try to offload > > the requests to the HW via switchdev API (not implemented yet). > > > > Any notification emitted by CFM from the kernel can be monitored in user > > space by starting 'cfm_server' program. > > > > Currently this 'cfm' and 'cfm_server' programs are standalone placed in a > > cfm repository https://github.com/microchip-ung/cfm but it is considered > > to integrate this into 'iproute2'. > > > > Reviewed-by: Horatiu Vultur > > Signed-off-by: Henrik Bjoernlund Hi Stephen, > > Could this be done in userspace? It is a control plane protocol. > Could it be done by using eBPF? I might be able to answer this. We have not considered this approach of using eBPF. Because we want actually to push this in HW extending switchdev API. I know that this series doesn't cover the switchdev part but we posted like this because we wanted to get some feedback from community. We had a similar approach for MRP, where we extended the bridge and switchdev API, so we tought that is the way to go forward. Regarding eBPF, I can't say that it would work or not because I lack knowledge in this. > > Adding more code in bridge impacts a large number of users of Linux distros. > It creates bloat and potential security vulnerabilities. -- /Horatiu
[Bridge] [PATCH net-next] bridge: mrp: Use hlist_head instead of list_head for mrp
Replace list_head with hlist_head for MRP list under the bridge. There is no need for a circular list when a linear list will work. This will also decrease the size of 'struct net_bridge'. Signed-off-by: Horatiu Vultur --- net/bridge/br_device.c | 2 +- net/bridge/br_mrp.c | 26 +- net/bridge/br_mrp_netlink.c | 2 +- net/bridge/br_private.h | 2 +- net/bridge/br_private_mrp.h | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 2400a66fe76e8..387403931a63f 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -456,7 +456,7 @@ void br_dev_setup(struct net_device *dev) INIT_HLIST_HEAD(&br->fdb_list); INIT_HLIST_HEAD(&br->frame_type_list); #if IS_ENABLED(CONFIG_BRIDGE_MRP) - INIT_LIST_HEAD(&br->mrp_list); + INIT_HLIST_HEAD(&br->mrp_list); #endif #if IS_ENABLED(CONFIG_BRIDGE_CFM) INIT_HLIST_HEAD(&br->mep_list); diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index f94d72bb7c32a..bb12fbf9aaf2b 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -54,8 +54,8 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, +lockdep_rtnl_is_held()) { if (mrp->ring_id == ring_id) { res = mrp; break; @@ -70,8 +70,8 @@ static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, +lockdep_rtnl_is_held()) { if (mrp->in_id == in_id) { res = mrp; break; @@ -85,8 +85,8 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, +lockdep_rtnl_is_held()) { struct net_bridge_port *p; p = rtnl_dereference(mrp->p_port); @@ -111,8 +111,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, +lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || rcu_access_pointer(mrp->s_port) == p || rcu_access_pointer(mrp->i_port) == p) { @@ -450,10 +450,10 @@ static void br_mrp_del_impl(struct net_bridge *br, struct br_mrp *mrp) rcu_assign_pointer(mrp->i_port, NULL); } - list_del_rcu(&mrp->list); + hlist_del_rcu(&mrp->list); kfree_rcu(mrp, rcu); - if (list_empty(&br->mrp_list)) + if (hlist_empty(&br->mrp_list)) br_del_frame(br, &mrp_frame_type); } @@ -503,12 +503,12 @@ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance) spin_unlock_bh(&br->lock); rcu_assign_pointer(mrp->s_port, p); - if (list_empty(&br->mrp_list)) + if (hlist_empty(&br->mrp_list)) br_add_frame(br, &mrp_frame_type); INIT_DELAYED_WORK(&mrp->test_work, br_mrp_test_work_expired); INIT_DELAYED_WORK(&mrp->in_test_work, br_mrp_in_test_work_expired); - list_add_tail_rcu(&mrp->list, &br->mrp_list); + hlist_add_tail_rcu(&mrp->list, &br->mrp_list); err = br_mrp_switchdev_add(br, mrp); if (err) @@ -1198,5 +1198,5 @@ static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb) bool br_mrp_enabled(struct net_bridge *br) { - return !list_empty(&br->mrp_list); + return !hlist_empty(&br->mrp_list); } diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c index 2a2fdf3500c5b..ce6f63c77cc0a 100644 --- a/net/bridge/br_mrp_netlink.c +++ b/net/bridge/br_mrp_netlink.c @@ -453,7 +453,7 @@ int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) if (!mrp_tb) return -EMSGSIZE; - list_for_each_entry_rcu(mrp, &br->mrp_list, list) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list) { struct net_bridge_port *p; tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); diff --git a/net/
[Bridge] [PATCH net-next] bridge: mrp: Implement LC mode for MRP
Extend MRP to support LC mode(link check) for the interconnect port. This applies only to the interconnect ring. Opposite to RC mode(ring check) the LC mode is using CFM frames to detect when the link goes up or down and based on that the userspace will need to react. One advantage of the LC mode over RC mode is that there will be fewer frames in the normal rings. Because RC mode generates InTest on all ports while LC mode sends CFM frame only on the interconnect port. All 4 nodes part of the interconnect ring needs to have the same mode. And it is not possible to have running LC and RC mode at the same time on a node. Whenever the MIM starts it needs to detect the status of the other 3 nodes in the interconnect ring so it would send a frame called InLinkStatus, on which the clients needs to reply with their link status. This patch adds the frame header for the frame InLinkStatus and extends existing rules on how to forward this frame. Signed-off-by: Horatiu Vultur --- include/uapi/linux/mrp_bridge.h | 7 +++ net/bridge/br_mrp.c | 18 +++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index 6aeb13ef0b1e..450f6941a5a1 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -61,6 +61,7 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_IN_TOPO = 0x7, BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, + BR_MRP_TLV_HEADER_IN_LINK_STATUS = 0xa, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; @@ -156,4 +157,10 @@ struct br_mrp_in_link_hdr { __be16 interval; }; +struct br_mrp_in_link_status_hdr { + __u8 sa[ETH_ALEN]; + __be16 port_role; + __be16 id; +}; + #endif diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index bb12fbf9aaf2..cec2c4e4561d 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -858,7 +858,8 @@ static bool br_mrp_in_frame(struct sk_buff *skb) if (hdr->type == BR_MRP_TLV_HEADER_IN_TEST || hdr->type == BR_MRP_TLV_HEADER_IN_TOPO || hdr->type == BR_MRP_TLV_HEADER_IN_LINK_DOWN || - hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP) + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP || + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) return true; return false; @@ -1126,9 +1127,9 @@ static int br_mrp_rcv(struct net_bridge_port *p, goto no_forward; } } else { - /* MIM should forward IntLinkChange and + /* MIM should forward IntLinkChange/Status and * IntTopoChange between ring ports but MIM -* should not forward IntLinkChange and +* should not forward IntLinkChange/Status and * IntTopoChange if the frame was received at * the interconnect port */ @@ -1155,6 +1156,17 @@ static int br_mrp_rcv(struct net_bridge_port *p, in_type == BR_MRP_TLV_HEADER_IN_LINK_DOWN)) goto forward; + /* MIC should forward IntLinkStatus frames only to +* interconnect port if it was received on a ring port. +* If it is received on interconnect port then, it +* should be forward on both ring ports +*/ + if (br_mrp_is_ring_port(p_port, s_port, p) && + in_type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) { + p_dst = NULL; + s_dst = NULL; + } + /* Should forward the InTopo frames only between the * ring ports */ -- 2.27.0
Re: [Bridge] [PATCH net-next] bridge: mrp: Implement LC mode for MRP
The 11/23/2020 14:13, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 23/11/2020 13:14, Horatiu Vultur wrote: > > Extend MRP to support LC mode(link check) for the interconnect port. > > This applies only to the interconnect ring. > > > > Opposite to RC mode(ring check) the LC mode is using CFM frames to > > detect when the link goes up or down and based on that the userspace > > will need to react. > > One advantage of the LC mode over RC mode is that there will be fewer > > frames in the normal rings. Because RC mode generates InTest on all > > ports while LC mode sends CFM frame only on the interconnect port. > > > > All 4 nodes part of the interconnect ring needs to have the same mode. > > And it is not possible to have running LC and RC mode at the same time > > on a node. > > > > Whenever the MIM starts it needs to detect the status of the other 3 > > nodes in the interconnect ring so it would send a frame called > > InLinkStatus, on which the clients needs to reply with their link > > status. > > > > This patch adds the frame header for the frame InLinkStatus and > > extends existing rules on how to forward this frame. > > > > Signed-off-by: Horatiu Vultur > > --- > > include/uapi/linux/mrp_bridge.h | 7 +++ > > net/bridge/br_mrp.c | 18 +++--- > > 2 files changed, 22 insertions(+), 3 deletions(-) > > > > Hi Horatiu, > The patch looks good overall, just one question below. Hi Nik, Thanks for taking time to review the patch. > > > diff --git a/include/uapi/linux/mrp_bridge.h > > b/include/uapi/linux/mrp_bridge.h > > index 6aeb13ef0b1e..450f6941a5a1 100644 > > --- a/include/uapi/linux/mrp_bridge.h > > +++ b/include/uapi/linux/mrp_bridge.h > > @@ -61,6 +61,7 @@ enum br_mrp_tlv_header_type { > > BR_MRP_TLV_HEADER_IN_TOPO = 0x7, > > BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, > > BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, > > + BR_MRP_TLV_HEADER_IN_LINK_STATUS = 0xa, > > BR_MRP_TLV_HEADER_OPTION = 0x7f, > > }; > > > > @@ -156,4 +157,10 @@ struct br_mrp_in_link_hdr { > > __be16 interval; > > }; > > > > +struct br_mrp_in_link_status_hdr { > > + __u8 sa[ETH_ALEN]; > > + __be16 port_role; > > + __be16 id; > > +}; > > + > > I didn't see this struct used anywhere, am I missing anything? Yes, you are right, the struct is not used any. But I put it there as I put the other frame types for MRP. > > Cheers, > Nik > > > #endif > > diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c > > index bb12fbf9aaf2..cec2c4e4561d 100644 > > --- a/net/bridge/br_mrp.c > > +++ b/net/bridge/br_mrp.c > > @@ -858,7 +858,8 @@ static bool br_mrp_in_frame(struct sk_buff *skb) > > if (hdr->type == BR_MRP_TLV_HEADER_IN_TEST || > > hdr->type == BR_MRP_TLV_HEADER_IN_TOPO || > > hdr->type == BR_MRP_TLV_HEADER_IN_LINK_DOWN || > > - hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP) > > + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP || > > + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) > > return true; > > > > return false; > > @@ -1126,9 +1127,9 @@ static int br_mrp_rcv(struct net_bridge_port *p, > > goto no_forward; > > } > > } else { > > - /* MIM should forward IntLinkChange and > > + /* MIM should forward IntLinkChange/Status and > >* IntTopoChange between ring ports but MIM > > - * should not forward IntLinkChange and > > + * should not forward IntLinkChange/Status and > >* IntTopoChange if the frame was received at > >* the interconnect port > >*/ > > @@ -1155,6 +1156,17 @@ static int br_mrp_rcv(struct net_bridge_port *p, > >in_type == BR_MRP_TLV_HEADER_IN_LINK_DOWN)) > > goto forward; > > > > + /* MIC should forward IntLinkStatus frames only to > > + * interconnect port if it was received on a ring > > port. > > + * If it is received on interconnect port then, it > > + * should be forward on both ring ports > > + */ > > + if (br_mrp_is_ring_port(p_port, s_port, p) && > > + in_type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) { > > + p_dst = NULL; > > + s_dst = NULL; > > + } > > + > > /* Should forward the InTopo frames only between the > >* ring ports > >*/ > > > -- /Horatiu
Re: [Bridge] [PATCH net-next] bridge: mrp: Implement LC mode for MRP
The 11/23/2020 14:05, Jakub Kicinski wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On Mon, 23 Nov 2020 16:25:53 +0200 Nikolay Aleksandrov wrote: > > >>> @@ -156,4 +157,10 @@ struct br_mrp_in_link_hdr { > > >>> __be16 interval; > > >>> }; > > >>> > > >>> +struct br_mrp_in_link_status_hdr { > > >>> + __u8 sa[ETH_ALEN]; > > >>> + __be16 port_role; > > >>> + __be16 id; > > >>> +}; > > >>> + > > >> > > >> I didn't see this struct used anywhere, am I missing anything? > > > > > > Yes, you are right, the struct is not used any. But I put it there as I > > > put the other frame types for MRP. > > > > > > > I see, we don't usually add unused code. The patch is fine as-is and since > > this is already the case for other MRP parts I'm not strictly against it, > > so: > > > > Acked-by: Nikolay Aleksandrov > > > > If Jakub decides to adhere to that rule you can keep my acked-by and just > > remove > > the struct for v2. Hi Jakub, > > Yes, good catch, let's drop it, we don't want to make too much of > a precedent for using kernel uAPI headers as a place to provide > protocol-related structs if the kernel doesn't need them. OK, I see. I will send a new version for this patch where I will drop the struct 'br_mrp_in_link_stauts_hdr'. > > The existing structs are only present in net-next as well, so if you > don't mind Horatiu it'd be good to follow up and remove the unused ones > and move the ones (if any) which are only used by the kernel but not by > the user space <-> kernel API communication out of include/uapi. Maybe we don't refer to the same structs, but I could see that they are already in net and in Linus' tree. For example the struct 'br_mrp_ring_topo_hdr'. Or am I missunderstanding something? -- /Horatiu
[Bridge] [PATCH net-next v2] bridge: mrp: Implement LC mode for MRP
Extend MRP to support LC mode(link check) for the interconnect port. This applies only to the interconnect ring. Opposite to RC mode(ring check) the LC mode is using CFM frames to detect when the link goes up or down and based on that the userspace will need to react. One advantage of the LC mode over RC mode is that there will be fewer frames in the normal rings. Because RC mode generates InTest on all ports while LC mode sends CFM frame only on the interconnect port. All 4 nodes part of the interconnect ring needs to have the same mode. And it is not possible to have running LC and RC mode at the same time on a node. Whenever the MIM starts it needs to detect the status of the other 3 nodes in the interconnect ring so it would send a frame called InLinkStatus, on which the clients needs to reply with their link status. This patch adds InLinkStatus frame type and extends existing rules on how to forward this frame. Acked-by: Nikolay Aleksandrov Signed-off-by: Horatiu Vultur --- v1 -> v2: - remove struct 'br_mrp_in_link_status_hdr' as is unused --- include/uapi/linux/mrp_bridge.h | 1 + net/bridge/br_mrp.c | 18 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/mrp_bridge.h b/include/uapi/linux/mrp_bridge.h index 6aeb13ef0b1e..9744773de5ff 100644 --- a/include/uapi/linux/mrp_bridge.h +++ b/include/uapi/linux/mrp_bridge.h @@ -61,6 +61,7 @@ enum br_mrp_tlv_header_type { BR_MRP_TLV_HEADER_IN_TOPO = 0x7, BR_MRP_TLV_HEADER_IN_LINK_DOWN = 0x8, BR_MRP_TLV_HEADER_IN_LINK_UP = 0x9, + BR_MRP_TLV_HEADER_IN_LINK_STATUS = 0xa, BR_MRP_TLV_HEADER_OPTION = 0x7f, }; diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index bb12fbf9aaf2..cec2c4e4561d 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -858,7 +858,8 @@ static bool br_mrp_in_frame(struct sk_buff *skb) if (hdr->type == BR_MRP_TLV_HEADER_IN_TEST || hdr->type == BR_MRP_TLV_HEADER_IN_TOPO || hdr->type == BR_MRP_TLV_HEADER_IN_LINK_DOWN || - hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP) + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP || + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) return true; return false; @@ -1126,9 +1127,9 @@ static int br_mrp_rcv(struct net_bridge_port *p, goto no_forward; } } else { - /* MIM should forward IntLinkChange and + /* MIM should forward IntLinkChange/Status and * IntTopoChange between ring ports but MIM -* should not forward IntLinkChange and +* should not forward IntLinkChange/Status and * IntTopoChange if the frame was received at * the interconnect port */ @@ -1155,6 +1156,17 @@ static int br_mrp_rcv(struct net_bridge_port *p, in_type == BR_MRP_TLV_HEADER_IN_LINK_DOWN)) goto forward; + /* MIC should forward IntLinkStatus frames only to +* interconnect port if it was received on a ring port. +* If it is received on interconnect port then, it +* should be forward on both ring ports +*/ + if (br_mrp_is_ring_port(p_port, s_port, p) && + in_type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) { + p_dst = NULL; + s_dst = NULL; + } + /* Should forward the InTopo frames only between the * ring ports */ -- 2.27.0
[Bridge] [RFC net-next] net: bridge: igmp: Extend IGMP query with vlan support
This patch tries to add vlan support to IGMP queries. It extends the function 'br_ip4_multicast_alloc_query' to add also a vlan tag if vlan is enabled. Therefore the bridge will send queries for each vlan the ports are in. There are few other places that needs to be updated to be fully functional. But I am curious if this is the way to go forward or is there a different way of implementing this? Signed-off-by: Horatiu Vultur --- net/bridge/br_multicast.c | 31 ++- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 484820c223a3..4c2db8a9efe0 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -688,7 +688,8 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, __be32 ip_dst, __be32 group, bool with_srcs, bool over_lmqt, u8 sflag, u8 *igmp_type, - bool *need_rexmit) + bool *need_rexmit, + __u16 vid) { struct net_bridge_port *p = pg ? pg->key.port : NULL; struct net_bridge_group_src *ent; @@ -724,6 +725,9 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, } pkt_size = sizeof(*eth) + sizeof(*iph) + 4 + igmp_hdr_size; + if (br_vlan_enabled(br->dev) && vid != 0) + pkt_size += 4; + if ((p && pkt_size > p->dev->mtu) || pkt_size > br->dev->mtu) return NULL; @@ -732,6 +736,9 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, if (!skb) goto out; + if (br_vlan_enabled(br->dev) && vid != 0) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); + skb->protocol = htons(ETH_P_IP); skb_reset_mac_header(skb); @@ -1008,7 +1015,8 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, ip4_dst, group->dst.ip4, with_srcs, over_lmqt, sflag, igmp_type, - need_rexmit); + need_rexmit, + group->vid); #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): { struct in6_addr ip6_dst; @@ -1477,6 +1485,8 @@ static void br_multicast_send_query(struct net_bridge *br, struct bridge_mcast_own_query *own_query) { struct bridge_mcast_other_query *other_query = NULL; + struct net_bridge_vlan_group *vg; + struct net_bridge_vlan *v; struct br_ip br_group; unsigned long time; @@ -1485,7 +1495,7 @@ static void br_multicast_send_query(struct net_bridge *br, !br_opt_get(br, BROPT_MULTICAST_QUERIER)) return; - memset(&br_group.dst, 0, sizeof(br_group.dst)); + memset(&br_group, 0, sizeof(br_group)); if (port ? (own_query == &port->ip4_own_query) : (own_query == &br->ip4_own_query)) { @@ -1501,8 +1511,19 @@ static void br_multicast_send_query(struct net_bridge *br, if (!other_query || timer_pending(&other_query->timer)) return; - __br_multicast_send_query(br, port, NULL, NULL, &br_group, false, 0, - NULL); + if (br_vlan_enabled(br->dev) && port) { + vg = nbp_vlan_group(port); + + list_for_each_entry(v, &vg->vlan_list, vlist) { + br_group.vid = v->vid == vg->pvid ? 0 : v->vid; + + __br_multicast_send_query(br, port, NULL, NULL, + &br_group, false, 0, NULL); + } + } else { + __br_multicast_send_query(br, port, NULL, NULL, &br_group, + false, 0, NULL); + } time = jiffies; time += own_query->startup_sent < br->multicast_startup_query_count ? -- 2.27.0
Re: [Bridge] [RFC net-next] net: bridge: igmp: Extend IGMP query with vlan support
The 12/11/2020 11:46, Nikolay Aleksandrov wrote: > > On 11/12/2020 11:26, Horatiu Vultur wrote: > > This patch tries to add vlan support to IGMP queries. > > It extends the function 'br_ip4_multicast_alloc_query' to add > > also a vlan tag if vlan is enabled. Therefore the bridge will send > > queries for each vlan the ports are in. > > > > There are few other places that needs to be updated to be fully > > functional. But I am curious if this is the way to go forward or is > > there a different way of implementing this? > > > > Signed-off-by: Horatiu Vultur > > --- > > net/bridge/br_multicast.c | 31 ++- > > 1 file changed, 26 insertions(+), 5 deletions(-) > > Hi Nik, > > Hi Horatiu, > We've discussed this with other people on netdev before, the way forward is to > implement it as a per-vlan option and then have a per-vlan querier. Which > would also > make the change much bigger and more complex. In general some of the > multicast options > need to be replicated for vlans to get proper per-vlan multicast control and > operation, but > that would require to change a lot of logic around the whole bridge > (fast-path included, > where it'd be most sensitive). Thanks for the suggestion and for the heads up. I will have a look and see how to do it like you mention. > The good news is that these days we have per-vlan options > support and so only the actual per-vlan multicast implementation is left to > be done. > I have this on my TODO list, unfortunately that list gets longer and longer, > so I'd be happy to review patches if someone decides to do it sooner. :) That would be much appreciated :). > > Sorry, I couldn't find the previous discussion, it was a few years back. > > Cheers, > Nik > > > diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c > > index 484820c223a3..4c2db8a9efe0 100644 > > --- a/net/bridge/br_multicast.c > > +++ b/net/bridge/br_multicast.c > > @@ -688,7 +688,8 @@ static struct sk_buff > > *br_ip4_multicast_alloc_query(struct net_bridge *br, > > __be32 ip_dst, __be32 > > group, > > bool with_srcs, bool > > over_lmqt, > > u8 sflag, u8 *igmp_type, > > - bool *need_rexmit) > > + bool *need_rexmit, > > + __u16 vid) > > { > > struct net_bridge_port *p = pg ? pg->key.port : NULL; > > struct net_bridge_group_src *ent; > > @@ -724,6 +725,9 @@ static struct sk_buff > > *br_ip4_multicast_alloc_query(struct net_bridge *br, > > } > > > > pkt_size = sizeof(*eth) + sizeof(*iph) + 4 + igmp_hdr_size; > > + if (br_vlan_enabled(br->dev) && vid != 0) > > + pkt_size += 4; > > + > > if ((p && pkt_size > p->dev->mtu) || > > pkt_size > br->dev->mtu) > > return NULL; > > @@ -732,6 +736,9 @@ static struct sk_buff > > *br_ip4_multicast_alloc_query(struct net_bridge *br, > > if (!skb) > > goto out; > > > > + if (br_vlan_enabled(br->dev) && vid != 0) > > + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); > > + > > skb->protocol = htons(ETH_P_IP); > > > > skb_reset_mac_header(skb); > > @@ -1008,7 +1015,8 @@ static struct sk_buff > > *br_multicast_alloc_query(struct net_bridge *br, > > ip4_dst, group->dst.ip4, > > with_srcs, over_lmqt, > > sflag, igmp_type, > > - need_rexmit); > > + need_rexmit, > > + group->vid); > > #if IS_ENABLED(CONFIG_IPV6) > > case htons(ETH_P_IPV6): { > > struct in6_addr ip6_dst; > > @@ -1477,6 +1485,8 @@ static void br_multicast_send_query(struct net_bridge > > *br, > > struct bridge_mcast_own_query *own_query) > > { > > struct bridge_mcast_other_query *other_query = NULL; > > + struct net_bridge_vlan_group *vg; > > + struct net_bridge_vlan *v; > > struct br_ip br_group; > > unsigned long time; > > > > @@ -1485,7 +1495,7 @@ static void br_multicast_send_query(struct net_bridge > > *br, > > !br_opt_get(br, BROPT_MULTICAST_QUERIER)) > > return; > > > > - memset(&br_group.dst, 0, sizeof(br_group.dst)); > > + memset(&br_group, 0, sizeof(br_group)); > > > > if (port ? (own_query == &port->ip4_own_query) : > > (own_query == &br->ip4_own_query)) { > > @@ -1501,8 +1511,19 @@ static void br_multicast_send_query(struct > > net_bridge *br, > > if (!other_query || timer_pending(&other_query->timer
[Bridge] [RFC PATCH v2] net: bridge: igmp: Extend IGMP query to be per vlan
Based on the comments of the previous version, we started to work on a new version, so it would be possible to enable/disable queries per vlan. This is still work in progress and there are plenty of things that are not implemented and tested: - ipv6 support - the fast path needs to be improved - currently it is possible only to enable/disable the queries per vlan, all the other configurations are global - toggling vlan_filtering is not tested - remove duplicated information - etc... But there are few things that are working like: - sending queries per vlan - stop sending queries if there is a better querier per vlan - when ports are added/removed from vlan - etc... We were wondering if this what you had in mind when you proposed to have this per vlan? Or we are completely off? Or we should fix some of the issues that I mentioned, before you can see more clearly the direction? Signed-off-by: Horatiu Vultur --- include/uapi/linux/if_link.h | 1 + net/bridge/br_device.c | 2 +- net/bridge/br_input.c| 2 +- net/bridge/br_multicast.c| 505 ++- net/bridge/br_netlink.c | 9 +- net/bridge/br_private.h | 90 ++- net/bridge/br_sysfs_br.c | 31 ++- net/bridge/br_vlan.c | 3 + 8 files changed, 560 insertions(+), 83 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 82708c6db432..11ec1d45c24e 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -472,6 +472,7 @@ enum { IFLA_BR_MCAST_MLD_VERSION, IFLA_BR_VLAN_STATS_PER_PORT, IFLA_BR_MULTI_BOOLOPT, + IFLA_BR_MCAST_QUERIER_VID, __IFLA_BR_MAX, }; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 3f2f06b4dd27..aca4e8074a8f 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -89,7 +89,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) mdst = br_mdb_get(br, skb, vid); if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && - br_multicast_querier_exists(br, eth_hdr(skb), mdst)) + br_multicast_querier_exists(br, eth_hdr(skb), mdst, vid)) br_multicast_flood(mdst, skb, false, true); else br_flood(br, skb, BR_PKT_MULTICAST, false, true); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 85d9dae2..03e445af6c1f 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -130,7 +130,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb case BR_PKT_MULTICAST: mdst = br_mdb_get(br, skb, vid); if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && - br_multicast_querier_exists(br, eth_hdr(skb), mdst)) { + br_multicast_querier_exists(br, eth_hdr(skb), mdst, vid)) { if ((mdst && mdst->host_joined) || br_multicast_is_router(br)) { local_rcv = true; diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 257ac4e25f6d..b4fac25101e4 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -48,8 +48,11 @@ static const struct rhashtable_params br_sg_port_rht_params = { .automatic_shrinking = true, }; +static void br_ip4_multicast_query_expired(struct timer_list *t); +static void br_ip4_multicast_querier_expired(struct timer_list *t); static void br_multicast_start_querier(struct net_bridge *br, - struct bridge_mcast_own_query *query); + struct bridge_mcast_own_query *query, + u16 vid); static void br_multicast_add_router(struct net_bridge *br, struct net_bridge_port *port); static void br_ip4_multicast_leave_group(struct net_bridge *br, @@ -87,6 +90,112 @@ br_sg_port_find(struct net_bridge *br, br_sg_port_rht_params); } +static void br_mcast_del_other_query(struct bridge_mcast_other_query *query) +{ + del_timer_sync(&query->timer); + list_del(&query->list); + kfree(query); +} + +static struct bridge_mcast_other_query * +br_mcast_add_other_query(struct list_head *list, u16 vid, +void (*callback)(struct timer_list *t)) +{ + struct bridge_mcast_other_query *query; + + query = kzalloc(sizeof(*query), GFP_KERNEL); + if (!query) + return NULL; + + query->vid = vid; + timer_setup(&query->timer, callback, 0); + + list_add(&query->list, list); + + return query; +} + +static void br_mcast_del_own_query(struct bridge_mcast_own_query *query) +{ + del_timer_sync(&query->timer); + list_del(&query->list); + kfree(query); +} + +static struct bridge_mcast_own_query * +br
Re: [Bridge] [RFC PATCH v2] net: bridge: igmp: Extend IGMP query to be per vlan
The 01/13/2021 14:15, Nikolay Aleksandrov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On 12/01/2021 15:59, Horatiu Vultur wrote: > > Based on the comments of the previous version, we started to work on a > > new version, so it would be possible to enable/disable queries per vlan. > > This is still work in progress and there are plenty of things that are > > not implemented and tested: > > - ipv6 support > > - the fast path needs to be improved > > - currently it is possible only to enable/disable the queries per vlan, > > all the other configurations are global > > - toggling vlan_filtering is not tested > > - remove duplicated information > > - etc... > > > > But there are few things that are working like: > > - sending queries per vlan > > - stop sending queries if there is a better querier per vlan > > - when ports are added/removed from vlan > > - etc... > > > > We were wondering if this what you had in mind when you proposed to have > > this per vlan? Or we are completely off? Or we should fix some of the > > issues that I mentioned, before you can see more clearly the direction? > > > > Signed-off-by: Horatiu Vultur > > --- > > include/uapi/linux/if_link.h | 1 + > > net/bridge/br_device.c | 2 +- > > net/bridge/br_input.c| 2 +- > > net/bridge/br_multicast.c| 505 ++- > > net/bridge/br_netlink.c | 9 +- > > net/bridge/br_private.h | 90 ++- > > net/bridge/br_sysfs_br.c | 31 ++- > > net/bridge/br_vlan.c | 3 + > > 8 files changed, 560 insertions(+), 83 deletions(-) > > > Hi Nik, > Hi Horatiu, > No, unfortunately not even close. At least is good that I didn't continue in this direction :) > We already have per-port per-vlan and global per-vlan > contexts which are also linked together for each vlan, those must be used for > any vlan > configuration and state. The problem is that you'd have to mix igmp and vlan > code and > those two live under two different kconfig options, and worse rely on > different locks, so > extra care must be taken. Point taken. > Any vlan lookups must use the vlan hashes, (almost) _no_ linear > walks or new lists are needed (the exception is obviously port going down > where a walk > over port's vlans is needed). Yes, I was thinking about this vlan lookups that need to be change to use the hashes but I thought I can do it later. > In almost all contexts below a vlan lookup has already been > done by the input functions, the result of that lookup must be saved and > re-used. The > vlan options API needs to be used for configuring vlans (per-vlan mcast > options), unfortunately > I still haven't upstreamed the iproute2 part, so you might have to do that as > well. > Obviously with all of the above the current default situation must not change > unless the > user configures it so. If you don't need this asap, I'll probably get to it > in two months > after EHT and the new bridge flush api, even we are still carrying an > out-of-tree patch > for this which someone (not from cumulus) tried to upstream a few years back, > but it also has > wrong design in general. :) Definetly this is not asap. But I would like to try to have another look at this to see if I get closer to what you are looking for :) > > Thanks, > Nik > > > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > > index 82708c6db432..11ec1d45c24e 100644 > > --- a/include/uapi/linux/if_link.h > > +++ b/include/uapi/linux/if_link.h > > @@ -472,6 +472,7 @@ enum { > > IFLA_BR_MCAST_MLD_VERSION, > > IFLA_BR_VLAN_STATS_PER_PORT, > > IFLA_BR_MULTI_BOOLOPT, > > + IFLA_BR_MCAST_QUERIER_VID, > > __IFLA_BR_MAX, > > }; > > > > diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c > > index 3f2f06b4dd27..aca4e8074a8f 100644 > > --- a/net/bridge/br_device.c > > +++ b/net/bridge/br_device.c > > @@ -89,7 +89,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct > > net_device *dev) > > > > mdst = br_mdb_get(br, skb, vid); > > if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && > > - br_multicast_querier_exists(br, eth_hdr(skb), mdst)) > > + br_multicast_querier_exists(br, eth_hdr(skb), mdst, vid)) > > br_multicast_flood(mdst, skb, false, true); > > else > > br_flood(br, skb, BR_PKT_MULTICAST, false, true); > > diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c > > index 85d9dae2..03e445af6c1f 100644 > > --- a/net/bridge/br_input.c > > +++ b/net/bridge/br_input.c > > @@ -130,7 +130,7 @@ int br_handle_frame_finish(struct net *net, struct sock > > *sk, struct sk_buff *skb > > case BR_PKT_MULTICAST: > > mdst = br_mdb_get(br, skb, vid); > > if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && > > - br_multicast_querier_exis
Re: [Bridge] [PATCH net] net: mrp: use stp state as substitute for unimplemented mrp state
The 01/18/2021 19:13, Rasmus Villemoes wrote: > Hi Rasmus, > When using MRP with hardware that does understand the concept of > blocked or forwarding ports, but not the full MRP offload, we > currently fail to tell the hardware what state it should put the port > in when the ring is closed - resulting in a ring of forwarding ports > and all the trouble that comes with that. But why don't you implement the SWITCHDEV_ATTR_ID_MRP_PORT_STATE in your driver? if already the HW understands the concept of block or forwarding? > > Signed-off-by: Rasmus Villemoes > --- > > I don't really understand why SWITCHDEV_ATTR_ID_MRP_PORT_STATE even > has to exist seperately from SWITCHDEV_ATTR_ID_PORT_STP_STATE, and > it's hard to tell what the difference might be since no kernel code > implements the former. The reason was to stay away from STP, because you can't run these two protocols at the same time. Even though in SW, we reuse port's state. In our driver(which is not upstreamed), we currently implement SWITCHDEV_ATTR_ID_MRP_PORT_STATE and just call the SWITCHDEV_ATTR_ID_PORT_STP_STATE. > > net/bridge/br_mrp_switchdev.c | 18 ++ > 1 file changed, 18 insertions(+) > > diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c > index ed547e03ace1..8a1c7953e57a 100644 > --- a/net/bridge/br_mrp_switchdev.c > +++ b/net/bridge/br_mrp_switchdev.c > @@ -180,6 +180,24 @@ int br_mrp_port_switchdev_set_state(struct > net_bridge_port *p, > int err; > > err = switchdev_port_attr_set(p->dev, &attr); > + if (err == -EOPNOTSUPP) { > + attr.id = SWITCHDEV_ATTR_ID_PORT_STP_STATE; > + switch (state) { > + case BR_MRP_PORT_STATE_DISABLED: > + case BR_MRP_PORT_STATE_NOT_CONNECTED: > + attr.u.stp_state = BR_STATE_DISABLED; > + break; > + case BR_MRP_PORT_STATE_BLOCKED: > + attr.u.stp_state = BR_STATE_BLOCKING; > + break; > + case BR_MRP_PORT_STATE_FORWARDING: > + attr.u.stp_state = BR_STATE_FORWARDING; > + break; > + default: > + return err; > + }; > + err = switchdev_port_attr_set(p->dev, &attr); > + } > if (err && err != -EOPNOTSUPP) > br_warn(p->br, "error setting offload MRP state on port > %u(%s)\n", > (unsigned int)p->port_no, p->dev->name); > -- > 2.23.0 > -- /Horatiu
Re: [Bridge] [PATCH net] net: mrp: use stp state as substitute for unimplemented mrp state
The 01/18/2021 19:46, Vladimir Oltean wrote: > > On Mon, Jan 18, 2021 at 07:56:18PM +0100, Horatiu Vultur wrote: > > The reason was to stay away from STP, because you can't run these two > > protocols at the same time. Even though in SW, we reuse port's state. > > In our driver(which is not upstreamed), we currently implement > > SWITCHDEV_ATTR_ID_MRP_PORT_STATE and just call the > > SWITCHDEV_ATTR_ID_PORT_STP_STATE. > > And isn't Rasmus's approach reasonable, in that it allows unmodified > switchdev drivers to offload MRP port states without creating > unnecessary code churn? I am sorry but I don't see this as the correct solution. In my opinion, I would prefer to have 3 extra lines in the driver and have a better view of what is happening. Than having 2 calls in the driver for different protocols. If it is not a problem to have STP calls when you configure the MRP, then why not just remove SWITCHDEV_ATTR_ID_MRP_PORT_STATE? > > Also, if it has no in-kernel users, why does it even exist as a > switchdev attribute? -- /Horatiu
Re: [Bridge] [PATCH net] net: mrp: use stp state as substitute for unimplemented mrp state
The 01/18/2021 21:27, Vladimir Oltean wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > On Mon, Jan 18, 2021 at 09:20:36PM +0100, Horatiu Vultur wrote: > > The 01/18/2021 19:46, Vladimir Oltean wrote: > > > > > > On Mon, Jan 18, 2021 at 07:56:18PM +0100, Horatiu Vultur wrote: > > > > The reason was to stay away from STP, because you can't run these two > > > > protocols at the same time. Even though in SW, we reuse port's state. > > > > In our driver(which is not upstreamed), we currently implement > > > > SWITCHDEV_ATTR_ID_MRP_PORT_STATE and just call the > > > > SWITCHDEV_ATTR_ID_PORT_STP_STATE. > > > > > > And isn't Rasmus's approach reasonable, in that it allows unmodified > > > switchdev drivers to offload MRP port states without creating > > > unnecessary code churn? > > > > I am sorry but I don't see this as the correct solution. In my opinion, > > I would prefer to have 3 extra lines in the driver and have a better > > view of what is happening. Than having 2 calls in the driver for > > different protocols. > > I think the question boils down to: is a MRP-unaware driver expected to > work with the current bridge MRP code? If the driver has switchdev support, then is not expected to work with the current bridge MRP code. For example, the Ocelot driver, it has switchdev support but no MRP support so this is not expected to work. The main reason is that MRP is using as DMAC 01:15:4E:00:00:0x(where x is between 1-4) so then when these frames will arrive to HW then they will just be flooded which is the wrong behavior. But, the Ocelot which is not MRP aware, it can behave as MRP node if the callbacks are implemented. For example, in MRP you have a notion of MRC (Client) which needs to forward MRP Test frames between 2 ports and copy to CPU MRP TopologyChange frames and forward these frames between 2 ports. Then using some TCAM rules(match on DMAC and source port) you can implement this because you can differentiate between Test and Topology frames by using the last byte of the DMAC. > > > If it is not a problem to have STP calls when you configure the MRP, > > then why not just remove SWITCHDEV_ATTR_ID_MRP_PORT_STATE? > > Good question, why not? -- /Horatiu