diff mbox series

[RFC,net-next,v4,8/9] bridge: mrp: Integrate MRP into the bridge

Message ID 20200327092126.15407-9-horatiu.vultur@microchip.com
State RFC
Delegated to: David Miller
Headers show
Series net: bridge: mrp: Add support for Media Redundancy Protocol(MRP) | expand

Commit Message

Horatiu Vultur March 27, 2020, 9:21 a.m. UTC
To integrate MRP into the bridge, the bridge needs to do the following:
- add new flag(BR_MPP_AWARE) to the net bridge ports, this bit will be set when
  the port is added to an MRP instance. In this way it knows if the frame was
  received on MRP ring port
- detect if the MRP frame was received on MRP ring port in that case it would be
  processed otherwise just forward it as usual.
- enable parsing of MRP
- before whenever the bridge was set up, it would set all the ports in
  forwarding state. Add an extra check to not set ports in forwarding state if
  the port is an MRP ring port. The reason of this change is that if the MRP
  instance initially sets the port in blocked state by setting the bridge up it
  would overwrite this setting.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
 include/linux/if_bridge.h |  1 +
 net/bridge/br_device.c    |  3 +++
 net/bridge/br_input.c     |  3 +++
 net/bridge/br_netlink.c   |  5 +++++
 net/bridge/br_private.h   | 22 ++++++++++++++++++++++
 net/bridge/br_stp.c       |  6 ++++++
 6 files changed, 40 insertions(+)

Comments

Nikolay Aleksandrov March 30, 2020, 4:16 p.m. UTC | #1
On 27/03/2020 11:21, Horatiu Vultur wrote:
> To integrate MRP into the bridge, the bridge needs to do the following:
> - add new flag(BR_MPP_AWARE) to the net bridge ports, this bit will be set when
>   the port is added to an MRP instance. In this way it knows if the frame was
>   received on MRP ring port
> - detect if the MRP frame was received on MRP ring port in that case it would be
>   processed otherwise just forward it as usual.
> - enable parsing of MRP
> - before whenever the bridge was set up, it would set all the ports in
>   forwarding state. Add an extra check to not set ports in forwarding state if
>   the port is an MRP ring port. The reason of this change is that if the MRP
>   instance initially sets the port in blocked state by setting the bridge up it
>   would overwrite this setting.
> 
> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> ---
>  include/linux/if_bridge.h |  1 +
>  net/bridge/br_device.c    |  3 +++
>  net/bridge/br_input.c     |  3 +++
>  net/bridge/br_netlink.c   |  5 +++++
>  net/bridge/br_private.h   | 22 ++++++++++++++++++++++
>  net/bridge/br_stp.c       |  6 ++++++
>  6 files changed, 40 insertions(+)
> 
> diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
> index 9e57c4411734..10baa9efdae8 100644
> --- a/include/linux/if_bridge.h
> +++ b/include/linux/if_bridge.h
> @@ -47,6 +47,7 @@ struct br_ip_list {
>  #define BR_BCAST_FLOOD		BIT(14)
>  #define BR_NEIGH_SUPPRESS	BIT(15)
>  #define BR_ISOLATED		BIT(16)
> +#define BR_MRP_AWARE		BIT(17)
>  
>  #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
>  
> diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
> index 0e3dbc5f3c34..8ec1362588af 100644
> --- a/net/bridge/br_device.c
> +++ b/net/bridge/br_device.c
> @@ -463,6 +463,9 @@ void br_dev_setup(struct net_device *dev)
>  	spin_lock_init(&br->lock);
>  	INIT_LIST_HEAD(&br->port_list);
>  	INIT_HLIST_HEAD(&br->fdb_list);
> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> +	INIT_LIST_HEAD(&br->mrp_list);
> +#endif
>  	spin_lock_init(&br->hash_lock);
>  
>  	br->bridge_id.prio[0] = 0x80;
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index fcc260840028..d5c34f36f0f4 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -342,6 +342,9 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
>  		}
>  	}
>  
> +	if (unlikely(br_mrp_process(p, skb)))
> +		return RX_HANDLER_PASS;
> +
>  forward:
>  	switch (p->state) {
>  	case BR_STATE_FORWARDING:
> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
> index 43dab4066f91..77bc96745be6 100644
> --- a/net/bridge/br_netlink.c
> +++ b/net/bridge/br_netlink.c
> @@ -669,6 +669,11 @@ static int br_afspec(struct net_bridge *br,
>  			if (err)
>  				return err;
>  			break;
> +		case IFLA_BRIDGE_MRP:
> +			err = br_mrp_parse(br, p, attr, cmd);
> +			if (err)
> +				return err;
> +			break;
>  		}
>  	}
>  
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 1f97703a52ff..38894f2cf98f 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -428,6 +428,10 @@ struct net_bridge {
>  	int offload_fwd_mark;
>  #endif
>  	struct hlist_head		fdb_list;
> +
> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> +	struct list_head		__rcu mrp_list;
> +#endif
>  };
>  
>  struct br_input_skb_cb {
> @@ -1304,6 +1308,24 @@ unsigned long br_timer_value(const struct timer_list *timer);
>  extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
>  #endif
>  
> +/* br_mrp.c */
> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> +int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> +		 struct nlattr *attr, int cmd);
> +int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
> +#else
> +static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> +			       struct nlattr *attr, int cmd)
> +{
> +	return -1;

You should return proper error here.

> +}
> +
> +static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
> +{
> +	return -1;

The bridge can't possibly work with MRP disabled with this.

> +}
> +#endif
> +
>  /* br_netlink.c */
>  extern struct rtnl_link_ops br_link_ops;
>  int br_netlink_init(void);
> diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
> index 1f14b8455345..3e88be7aa269 100644
> --- a/net/bridge/br_stp.c
> +++ b/net/bridge/br_stp.c
> @@ -36,6 +36,12 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
>  	};
>  	int err;
>  
> +	/* Don't change the state of the ports if they are driven by a different
> +	 * protocol.
> +	 */
> +	if (p->flags & BR_MRP_AWARE)
> +		return;
> +

Maybe disallow STP type (kernel/user-space/no-stp) changing as well, force it to no-stp.

>  	p->state = state;
>  	err = switchdev_port_attr_set(p->dev, &attr);
>  	if (err && err != -EOPNOTSUPP)
>
Horatiu Vultur April 1, 2020, 4:10 p.m. UTC | #2
Hi Nik,

The 03/30/2020 19:16, Nikolay Aleksandrov wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 27/03/2020 11:21, Horatiu Vultur wrote:
> > To integrate MRP into the bridge, the bridge needs to do the following:
> > - add new flag(BR_MPP_AWARE) to the net bridge ports, this bit will be set when
> >   the port is added to an MRP instance. In this way it knows if the frame was
> >   received on MRP ring port
> > - detect if the MRP frame was received on MRP ring port in that case it would be
> >   processed otherwise just forward it as usual.
> > - enable parsing of MRP
> > - before whenever the bridge was set up, it would set all the ports in
> >   forwarding state. Add an extra check to not set ports in forwarding state if
> >   the port is an MRP ring port. The reason of this change is that if the MRP
> >   instance initially sets the port in blocked state by setting the bridge up it
> >   would overwrite this setting.
> >
> > Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> > ---
> >  include/linux/if_bridge.h |  1 +
> >  net/bridge/br_device.c    |  3 +++
> >  net/bridge/br_input.c     |  3 +++
> >  net/bridge/br_netlink.c   |  5 +++++
> >  net/bridge/br_private.h   | 22 ++++++++++++++++++++++
> >  net/bridge/br_stp.c       |  6 ++++++
> >  6 files changed, 40 insertions(+)
> >
> > diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
> > index 9e57c4411734..10baa9efdae8 100644
> > --- a/include/linux/if_bridge.h
> > +++ b/include/linux/if_bridge.h
> > @@ -47,6 +47,7 @@ struct br_ip_list {
> >  #define BR_BCAST_FLOOD               BIT(14)
> >  #define BR_NEIGH_SUPPRESS    BIT(15)
> >  #define BR_ISOLATED          BIT(16)
> > +#define BR_MRP_AWARE         BIT(17)
> >
> >  #define BR_DEFAULT_AGEING_TIME       (300 * HZ)
> >
> > diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
> > index 0e3dbc5f3c34..8ec1362588af 100644
> > --- a/net/bridge/br_device.c
> > +++ b/net/bridge/br_device.c
> > @@ -463,6 +463,9 @@ void br_dev_setup(struct net_device *dev)
> >       spin_lock_init(&br->lock);
> >       INIT_LIST_HEAD(&br->port_list);
> >       INIT_HLIST_HEAD(&br->fdb_list);
> > +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> > +     INIT_LIST_HEAD(&br->mrp_list);
> > +#endif
> >       spin_lock_init(&br->hash_lock);
> >
> >       br->bridge_id.prio[0] = 0x80;
> > diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> > index fcc260840028..d5c34f36f0f4 100644
> > --- a/net/bridge/br_input.c
> > +++ b/net/bridge/br_input.c
> > @@ -342,6 +342,9 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
> >               }
> >       }
> >
> > +     if (unlikely(br_mrp_process(p, skb)))
> > +             return RX_HANDLER_PASS;
> > +
> >  forward:
> >       switch (p->state) {
> >       case BR_STATE_FORWARDING:
> > diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
> > index 43dab4066f91..77bc96745be6 100644
> > --- a/net/bridge/br_netlink.c
> > +++ b/net/bridge/br_netlink.c
> > @@ -669,6 +669,11 @@ static int br_afspec(struct net_bridge *br,
> >                       if (err)
> >                               return err;
> >                       break;
> > +             case IFLA_BRIDGE_MRP:
> > +                     err = br_mrp_parse(br, p, attr, cmd);
> > +                     if (err)
> > +                             return err;
> > +                     break;
> >               }
> >       }
> >
> > diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> > index 1f97703a52ff..38894f2cf98f 100644
> > --- a/net/bridge/br_private.h
> > +++ b/net/bridge/br_private.h
> > @@ -428,6 +428,10 @@ struct net_bridge {
> >       int offload_fwd_mark;
> >  #endif
> >       struct hlist_head               fdb_list;
> > +
> > +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> > +     struct list_head                __rcu mrp_list;
> > +#endif
> >  };
> >
> >  struct br_input_skb_cb {
> > @@ -1304,6 +1308,24 @@ unsigned long br_timer_value(const struct timer_list *timer);
> >  extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
> >  #endif
> >
> > +/* br_mrp.c */
> > +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> > +int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> > +              struct nlattr *attr, int cmd);
> > +int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
> > +#else
> > +static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> > +                            struct nlattr *attr, int cmd)
> > +{
> > +     return -1;
> 
> You should return proper error here.

It will return -EOPNOTSUPP.

> 
> > +}
> > +
> > +static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
> > +{
> > +     return -1;
> 
> The bridge can't possibly work with MRP disabled with this.

Good catch, it will return 0.

> 
> > +}
> > +#endif
> > +
> >  /* br_netlink.c */
> >  extern struct rtnl_link_ops br_link_ops;
> >  int br_netlink_init(void);
> > diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
> > index 1f14b8455345..3e88be7aa269 100644
> > --- a/net/bridge/br_stp.c
> > +++ b/net/bridge/br_stp.c
> > @@ -36,6 +36,12 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
> >       };
> >       int err;
> >
> > +     /* Don't change the state of the ports if they are driven by a different
> > +      * protocol.
> > +      */
> > +     if (p->flags & BR_MRP_AWARE)
> > +             return;
> > +
> 
> Maybe disallow STP type (kernel/user-space/no-stp) changing as well, force it to no-stp.

I am not sure that I understand completely here, do you want me to
disable STP if MRP is started?

> 
> >       p->state = state;
> >       err = switchdev_port_attr_set(p->dev, &attr);
> >       if (err && err != -EOPNOTSUPP)
> >
>
Nikolay Aleksandrov April 1, 2020, 4:33 p.m. UTC | #3
On 01/04/2020 19:10, Horatiu Vultur wrote:
> Hi Nik,
> 
> The 03/30/2020 19:16, Nikolay Aleksandrov wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>
>> On 27/03/2020 11:21, Horatiu Vultur wrote:
>>> To integrate MRP into the bridge, the bridge needs to do the following:
>>> - add new flag(BR_MPP_AWARE) to the net bridge ports, this bit will be set when
>>>   the port is added to an MRP instance. In this way it knows if the frame was
>>>   received on MRP ring port
>>> - detect if the MRP frame was received on MRP ring port in that case it would be
>>>   processed otherwise just forward it as usual.
>>> - enable parsing of MRP
>>> - before whenever the bridge was set up, it would set all the ports in
>>>   forwarding state. Add an extra check to not set ports in forwarding state if
>>>   the port is an MRP ring port. The reason of this change is that if the MRP
>>>   instance initially sets the port in blocked state by setting the bridge up it
>>>   would overwrite this setting.
>>>
>>> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
>>> ---
>>>  include/linux/if_bridge.h |  1 +
>>>  net/bridge/br_device.c    |  3 +++
>>>  net/bridge/br_input.c     |  3 +++
>>>  net/bridge/br_netlink.c   |  5 +++++
>>>  net/bridge/br_private.h   | 22 ++++++++++++++++++++++
>>>  net/bridge/br_stp.c       |  6 ++++++
>>>  6 files changed, 40 insertions(+)
>>>
>>> diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
>>> index 9e57c4411734..10baa9efdae8 100644
>>> --- a/include/linux/if_bridge.h
>>> +++ b/include/linux/if_bridge.h
>>> @@ -47,6 +47,7 @@ struct br_ip_list {
>>>  #define BR_BCAST_FLOOD               BIT(14)
>>>  #define BR_NEIGH_SUPPRESS    BIT(15)
>>>  #define BR_ISOLATED          BIT(16)
>>> +#define BR_MRP_AWARE         BIT(17)
>>>
>>>  #define BR_DEFAULT_AGEING_TIME       (300 * HZ)
>>>
>>> diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
>>> index 0e3dbc5f3c34..8ec1362588af 100644
>>> --- a/net/bridge/br_device.c
>>> +++ b/net/bridge/br_device.c
>>> @@ -463,6 +463,9 @@ void br_dev_setup(struct net_device *dev)
>>>       spin_lock_init(&br->lock);
>>>       INIT_LIST_HEAD(&br->port_list);
>>>       INIT_HLIST_HEAD(&br->fdb_list);
>>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
>>> +     INIT_LIST_HEAD(&br->mrp_list);
>>> +#endif
>>>       spin_lock_init(&br->hash_lock);
>>>
>>>       br->bridge_id.prio[0] = 0x80;
>>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>>> index fcc260840028..d5c34f36f0f4 100644
>>> --- a/net/bridge/br_input.c
>>> +++ b/net/bridge/br_input.c
>>> @@ -342,6 +342,9 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
>>>               }
>>>       }
>>>
>>> +     if (unlikely(br_mrp_process(p, skb)))
>>> +             return RX_HANDLER_PASS;
>>> +
>>>  forward:
>>>       switch (p->state) {
>>>       case BR_STATE_FORWARDING:
>>> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
>>> index 43dab4066f91..77bc96745be6 100644
>>> --- a/net/bridge/br_netlink.c
>>> +++ b/net/bridge/br_netlink.c
>>> @@ -669,6 +669,11 @@ static int br_afspec(struct net_bridge *br,
>>>                       if (err)
>>>                               return err;
>>>                       break;
>>> +             case IFLA_BRIDGE_MRP:
>>> +                     err = br_mrp_parse(br, p, attr, cmd);
>>> +                     if (err)
>>> +                             return err;
>>> +                     break;
>>>               }
>>>       }
>>>
>>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>>> index 1f97703a52ff..38894f2cf98f 100644
>>> --- a/net/bridge/br_private.h
>>> +++ b/net/bridge/br_private.h
>>> @@ -428,6 +428,10 @@ struct net_bridge {
>>>       int offload_fwd_mark;
>>>  #endif
>>>       struct hlist_head               fdb_list;
>>> +
>>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
>>> +     struct list_head                __rcu mrp_list;
>>> +#endif
>>>  };
>>>
>>>  struct br_input_skb_cb {
>>> @@ -1304,6 +1308,24 @@ unsigned long br_timer_value(const struct timer_list *timer);
>>>  extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
>>>  #endif
>>>
>>> +/* br_mrp.c */
>>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
>>> +int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
>>> +              struct nlattr *attr, int cmd);
>>> +int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
>>> +#else
>>> +static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
>>> +                            struct nlattr *attr, int cmd)
>>> +{
>>> +     return -1;
>>
>> You should return proper error here.
> 
> It will return -EOPNOTSUPP.
> 
>>
>>> +}
>>> +
>>> +static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
>>> +{
>>> +     return -1;
>>
>> The bridge can't possibly work with MRP disabled with this.
> 
> Good catch, it will return 0.
> 
>>
>>> +}
>>> +#endif
>>> +
>>>  /* br_netlink.c */
>>>  extern struct rtnl_link_ops br_link_ops;
>>>  int br_netlink_init(void);
>>> diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
>>> index 1f14b8455345..3e88be7aa269 100644
>>> --- a/net/bridge/br_stp.c
>>> +++ b/net/bridge/br_stp.c
>>> @@ -36,6 +36,12 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
>>>       };
>>>       int err;
>>>
>>> +     /* Don't change the state of the ports if they are driven by a different
>>> +      * protocol.
>>> +      */
>>> +     if (p->flags & BR_MRP_AWARE)
>>> +             return;
>>> +
>>
>> Maybe disallow STP type (kernel/user-space/no-stp) changing as well, force it to no-stp.
> 
> I am not sure that I understand completely here, do you want me to
> disable STP if MRP is started?
> 

I think it should be one of the two since they can step on each other's toes. If MRP is
enabled then STP must be already disabled and should not be possible to enable while MRP
is active and vice-versa.

>>
>>>       p->state = state;
>>>       err = switchdev_port_attr_set(p->dev, &attr);
>>>       if (err && err != -EOPNOTSUPP)
>>>
>>
>
Horatiu Vultur April 2, 2020, 1:46 p.m. UTC | #4
The 04/01/2020 19:33, Nikolay Aleksandrov wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 01/04/2020 19:10, Horatiu Vultur wrote:
> > Hi Nik,
> >
> > The 03/30/2020 19:16, Nikolay Aleksandrov wrote:
> >> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> >>
> >> On 27/03/2020 11:21, Horatiu Vultur wrote:
> >>> To integrate MRP into the bridge, the bridge needs to do the following:
> >>> - add new flag(BR_MPP_AWARE) to the net bridge ports, this bit will be set when
> >>>   the port is added to an MRP instance. In this way it knows if the frame was
> >>>   received on MRP ring port
> >>> - detect if the MRP frame was received on MRP ring port in that case it would be
> >>>   processed otherwise just forward it as usual.
> >>> - enable parsing of MRP
> >>> - before whenever the bridge was set up, it would set all the ports in
> >>>   forwarding state. Add an extra check to not set ports in forwarding state if
> >>>   the port is an MRP ring port. The reason of this change is that if the MRP
> >>>   instance initially sets the port in blocked state by setting the bridge up it
> >>>   would overwrite this setting.
> >>>
> >>> Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
> >>> ---
> >>>  include/linux/if_bridge.h |  1 +
> >>>  net/bridge/br_device.c    |  3 +++
> >>>  net/bridge/br_input.c     |  3 +++
> >>>  net/bridge/br_netlink.c   |  5 +++++
> >>>  net/bridge/br_private.h   | 22 ++++++++++++++++++++++
> >>>  net/bridge/br_stp.c       |  6 ++++++
> >>>  6 files changed, 40 insertions(+)
> >>>
> >>> diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
> >>> index 9e57c4411734..10baa9efdae8 100644
> >>> --- a/include/linux/if_bridge.h
> >>> +++ b/include/linux/if_bridge.h
> >>> @@ -47,6 +47,7 @@ struct br_ip_list {
> >>>  #define BR_BCAST_FLOOD               BIT(14)
> >>>  #define BR_NEIGH_SUPPRESS    BIT(15)
> >>>  #define BR_ISOLATED          BIT(16)
> >>> +#define BR_MRP_AWARE         BIT(17)
> >>>
> >>>  #define BR_DEFAULT_AGEING_TIME       (300 * HZ)
> >>>
> >>> diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
> >>> index 0e3dbc5f3c34..8ec1362588af 100644
> >>> --- a/net/bridge/br_device.c
> >>> +++ b/net/bridge/br_device.c
> >>> @@ -463,6 +463,9 @@ void br_dev_setup(struct net_device *dev)
> >>>       spin_lock_init(&br->lock);
> >>>       INIT_LIST_HEAD(&br->port_list);
> >>>       INIT_HLIST_HEAD(&br->fdb_list);
> >>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> >>> +     INIT_LIST_HEAD(&br->mrp_list);
> >>> +#endif
> >>>       spin_lock_init(&br->hash_lock);
> >>>
> >>>       br->bridge_id.prio[0] = 0x80;
> >>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> >>> index fcc260840028..d5c34f36f0f4 100644
> >>> --- a/net/bridge/br_input.c
> >>> +++ b/net/bridge/br_input.c
> >>> @@ -342,6 +342,9 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
> >>>               }
> >>>       }
> >>>
> >>> +     if (unlikely(br_mrp_process(p, skb)))
> >>> +             return RX_HANDLER_PASS;
> >>> +
> >>>  forward:
> >>>       switch (p->state) {
> >>>       case BR_STATE_FORWARDING:
> >>> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
> >>> index 43dab4066f91..77bc96745be6 100644
> >>> --- a/net/bridge/br_netlink.c
> >>> +++ b/net/bridge/br_netlink.c
> >>> @@ -669,6 +669,11 @@ static int br_afspec(struct net_bridge *br,
> >>>                       if (err)
> >>>                               return err;
> >>>                       break;
> >>> +             case IFLA_BRIDGE_MRP:
> >>> +                     err = br_mrp_parse(br, p, attr, cmd);
> >>> +                     if (err)
> >>> +                             return err;
> >>> +                     break;
> >>>               }
> >>>       }
> >>>
> >>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> >>> index 1f97703a52ff..38894f2cf98f 100644
> >>> --- a/net/bridge/br_private.h
> >>> +++ b/net/bridge/br_private.h
> >>> @@ -428,6 +428,10 @@ struct net_bridge {
> >>>       int offload_fwd_mark;
> >>>  #endif
> >>>       struct hlist_head               fdb_list;
> >>> +
> >>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> >>> +     struct list_head                __rcu mrp_list;
> >>> +#endif
> >>>  };
> >>>
> >>>  struct br_input_skb_cb {
> >>> @@ -1304,6 +1308,24 @@ unsigned long br_timer_value(const struct timer_list *timer);
> >>>  extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
> >>>  #endif
> >>>
> >>> +/* br_mrp.c */
> >>> +#if IS_ENABLED(CONFIG_BRIDGE_MRP)
> >>> +int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> >>> +              struct nlattr *attr, int cmd);
> >>> +int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
> >>> +#else
> >>> +static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
> >>> +                            struct nlattr *attr, int cmd)
> >>> +{
> >>> +     return -1;
> >>
> >> You should return proper error here.
> >
> > It will return -EOPNOTSUPP.
> >
> >>
> >>> +}
> >>> +
> >>> +static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
> >>> +{
> >>> +     return -1;
> >>
> >> The bridge can't possibly work with MRP disabled with this.
> >
> > Good catch, it will return 0.
> >
> >>
> >>> +}
> >>> +#endif
> >>> +
> >>>  /* br_netlink.c */
> >>>  extern struct rtnl_link_ops br_link_ops;
> >>>  int br_netlink_init(void);
> >>> diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
> >>> index 1f14b8455345..3e88be7aa269 100644
> >>> --- a/net/bridge/br_stp.c
> >>> +++ b/net/bridge/br_stp.c
> >>> @@ -36,6 +36,12 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
> >>>       };
> >>>       int err;
> >>>
> >>> +     /* Don't change the state of the ports if they are driven by a different
> >>> +      * protocol.
> >>> +      */
> >>> +     if (p->flags & BR_MRP_AWARE)
> >>> +             return;
> >>> +
> >>
> >> Maybe disallow STP type (kernel/user-space/no-stp) changing as well, force it to no-stp.
> >
> > I am not sure that I understand completely here, do you want me to
> > disable STP if MRP is started?
> >
> 
> I think it should be one of the two since they can step on each other's toes. If MRP is
> enabled then STP must be already disabled and should not be possible to enable while MRP
> is active and vice-versa.

I will update this in the next patch series.

> 
> >>
> >>>       p->state = state;
> >>>       err = switchdev_port_attr_set(p->dev, &attr);
> >>>       if (err && err != -EOPNOTSUPP)
> >>>
> >>
> >
>
diff mbox series

Patch

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 9e57c4411734..10baa9efdae8 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -47,6 +47,7 @@  struct br_ip_list {
 #define BR_BCAST_FLOOD		BIT(14)
 #define BR_NEIGH_SUPPRESS	BIT(15)
 #define BR_ISOLATED		BIT(16)
+#define BR_MRP_AWARE		BIT(17)
 
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 0e3dbc5f3c34..8ec1362588af 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -463,6 +463,9 @@  void br_dev_setup(struct net_device *dev)
 	spin_lock_init(&br->lock);
 	INIT_LIST_HEAD(&br->port_list);
 	INIT_HLIST_HEAD(&br->fdb_list);
+#if IS_ENABLED(CONFIG_BRIDGE_MRP)
+	INIT_LIST_HEAD(&br->mrp_list);
+#endif
 	spin_lock_init(&br->hash_lock);
 
 	br->bridge_id.prio[0] = 0x80;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index fcc260840028..d5c34f36f0f4 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -342,6 +342,9 @@  rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
 		}
 	}
 
+	if (unlikely(br_mrp_process(p, skb)))
+		return RX_HANDLER_PASS;
+
 forward:
 	switch (p->state) {
 	case BR_STATE_FORWARDING:
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 43dab4066f91..77bc96745be6 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -669,6 +669,11 @@  static int br_afspec(struct net_bridge *br,
 			if (err)
 				return err;
 			break;
+		case IFLA_BRIDGE_MRP:
+			err = br_mrp_parse(br, p, attr, cmd);
+			if (err)
+				return err;
+			break;
 		}
 	}
 
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 1f97703a52ff..38894f2cf98f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -428,6 +428,10 @@  struct net_bridge {
 	int offload_fwd_mark;
 #endif
 	struct hlist_head		fdb_list;
+
+#if IS_ENABLED(CONFIG_BRIDGE_MRP)
+	struct list_head		__rcu mrp_list;
+#endif
 };
 
 struct br_input_skb_cb {
@@ -1304,6 +1308,24 @@  unsigned long br_timer_value(const struct timer_list *timer);
 extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
 #endif
 
+/* br_mrp.c */
+#if IS_ENABLED(CONFIG_BRIDGE_MRP)
+int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
+		 struct nlattr *attr, int cmd);
+int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
+#else
+static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
+			       struct nlattr *attr, int cmd)
+{
+	return -1;
+}
+
+static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
+{
+	return -1;
+}
+#endif
+
 /* br_netlink.c */
 extern struct rtnl_link_ops br_link_ops;
 int br_netlink_init(void);
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 1f14b8455345..3e88be7aa269 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -36,6 +36,12 @@  void br_set_state(struct net_bridge_port *p, unsigned int state)
 	};
 	int err;
 
+	/* Don't change the state of the ports if they are driven by a different
+	 * protocol.
+	 */
+	if (p->flags & BR_MRP_AWARE)
+		return;
+
 	p->state = state;
 	err = switchdev_port_attr_set(p->dev, &attr);
 	if (err && err != -EOPNOTSUPP)