linux/net/bridge/br_mrp_switchdev.c
Horatiu Vultur b2bdba1cbc bridge: mrp: Fix the usage of br_mrp_port_switchdev_set_state
The function br_mrp_port_switchdev_set_state was called both with MRP
port state and STP port state, which is an issue because they don't
match exactly.

Therefore, update the function to be used only with STP port state and
use the id SWITCHDEV_ATTR_ID_PORT_STP_STATE.

The choice of using STP over MRP is that the drivers already implement
SWITCHDEV_ATTR_ID_PORT_STP_STATE and already in SW we update the port
STP state.

Fixes: 9a9f26e8f7 ("bridge: mrp: Connect MRP API with the switchdev API")
Fixes: fadd409136 ("bridge: switchdev: mrp: Implement MRP API for switchdev")
Fixes: 2f1a11ae11 ("bridge: mrp: Add MRP interface.")
Reported-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-02-08 16:20:57 -08:00

205 lines
4.6 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
#include <net/switchdev.h>
#include "br_private_mrp.h"
int br_mrp_switchdev_add(struct net_bridge *br, struct br_mrp *mrp)
{
struct switchdev_obj_mrp mrp_obj = {
.obj.orig_dev = br->dev,
.obj.id = SWITCHDEV_OBJ_ID_MRP,
.p_port = rtnl_dereference(mrp->p_port)->dev,
.s_port = rtnl_dereference(mrp->s_port)->dev,
.ring_id = mrp->ring_id,
.prio = mrp->prio,
};
int err;
err = switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL);
if (err && err != -EOPNOTSUPP)
return err;
return 0;
}
int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp)
{
struct switchdev_obj_mrp mrp_obj = {
.obj.orig_dev = br->dev,
.obj.id = SWITCHDEV_OBJ_ID_MRP,
.p_port = NULL,
.s_port = NULL,
.ring_id = mrp->ring_id,
};
int err;
err = switchdev_port_obj_del(br->dev, &mrp_obj.obj);
if (err && err != -EOPNOTSUPP)
return err;
return 0;
}
int br_mrp_switchdev_set_ring_role(struct net_bridge *br,
struct br_mrp *mrp,
enum br_mrp_ring_role_type role)
{
struct switchdev_obj_ring_role_mrp mrp_role = {
.obj.orig_dev = br->dev,
.obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP,
.ring_role = role,
.ring_id = mrp->ring_id,
};
int err;
if (role == BR_MRP_RING_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_send_ring_test(struct net_bridge *br,
struct br_mrp *mrp, u32 interval,
u8 max_miss, u32 period,
bool monitor)
{
struct switchdev_obj_ring_test_mrp test = {
.obj.orig_dev = br->dev,
.obj.id = SWITCHDEV_OBJ_ID_RING_TEST_MRP,
.interval = interval,
.max_miss = max_miss,
.ring_id = mrp->ring_id,
.period = period,
.monitor = monitor,
};
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_switchdev_set_ring_state(struct net_bridge *br,
struct br_mrp *mrp,
enum br_mrp_ring_state_type state)
{
struct switchdev_obj_ring_state_mrp mrp_state = {
.obj.orig_dev = br->dev,
.obj.id = SWITCHDEV_OBJ_ID_RING_STATE_MRP,
.ring_state = state,
.ring_id = mrp->ring_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_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, u32 state)
{
struct switchdev_attr attr = {
.orig_dev = p->dev,
.id = SWITCHDEV_ATTR_ID_PORT_STP_STATE,
.u.stp_state = state,
};
int 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);
return err;
}
int br_mrp_port_switchdev_set_role(struct net_bridge_port *p,
enum br_mrp_port_role_type role)
{
struct switchdev_attr attr = {
.orig_dev = p->dev,
.id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,
.u.mrp_port_role = role,
};
int err;
err = switchdev_port_attr_set(p->dev, &attr);
if (err && err != -EOPNOTSUPP)
return err;
return 0;
}