lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 13 Jan 2020 13:46:20 +0100
From:   Horatiu Vultur <horatiu.vultur@...rochip.com>
To:     <linux-kernel@...r.kernel.org>, <netdev@...r.kernel.org>,
        <bridge@...ts.linux-foundation.org>, <davem@...emloft.net>,
        <roopa@...ulusnetworks.com>, <nikolay@...ulusnetworks.com>,
        <jakub.kicinski@...ronome.com>, <vivien.didelot@...il.com>,
        <olteanv@...il.com>, <anirudh.venkataramanan@...el.com>,
        <andrew@...n.ch>, <dsahern@...il.com>, <jiri@...nulli.us>,
        <ivecera@...hat.com>, <UNGLinuxDriver@...rochip.com>
CC:     Horatiu Vultur <horatiu.vultur@...rochip.com>
Subject: [RFC net-next Patch v2 4/4] net: bridge: mrp: switchdev: Add HW offload

Extend switchdev interface to add support for MRP. The HW is notified in
following cases:
- SWITCHDEV_OBJ_ID_PORT_MRP. This is used when a port is added/removed from the
  mrp ring.
- SWITCHDEV_OBJ_ID_RING_ROLE_MRP. This is used when the role of the node
  changes. The current supported roles are Media Redundancy Manager and Media
  Redundancy Client.
- SWITCHDEV_OBJ_ID_RING_TEST_MRP. This is used when to start/stop sending
  MRP_Test frames on the mrp ring ports. This is called only on nodes that have
  the role Media Redundancy Manager.
- SWITCHDEV_ATTR_ID_MRP_PORT_STATE. This is used when the port's state is
  changed. It can be in blocking/forwarding mode.
- SWITCHDEV_ATTR_ID_MRP_PORT_ROLE. This is used when ports's role changes. The
  roles of the port can be primary/secondary. This is required to notify HW
  because the MRP_Test frame contains the field MRP_PortRole that contains this
  information.
- SWITCHDEV_ATTR_ID_MRP_STATE. This is used when the ring changes it states to
  open or closed. This is required to notify HW because the MRP_Test frame
  contains the field MRP_InState which contains this information.
- SWITCHDEV_ATTR_ID_RING_TRANS. This is used to count the number of times the
  ring goes in open state. This is required to notify the HW because the
  MRP_Test frame contains the field MRP_Transition which contains this
  information.

Signed-off-by: Horatiu Vultur <horatiu.vultur@...rochip.com>
---
 include/net/switchdev.h       |  52 ++++++++++
 net/bridge/Makefile           |   2 +-
 net/bridge/br_mrp.c           |  96 +++++++++++-------
 net/bridge/br_mrp_switchdev.c | 180 ++++++++++++++++++++++++++++++++++
 net/bridge/br_mrp_timer.c     |  37 ++++++-
 net/bridge/br_private_mrp.h   |  16 +++
 6 files changed, 344 insertions(+), 39 deletions(-)
 create mode 100644 net/bridge/br_mrp_switchdev.c

diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index aee86a189432..c4cd180fbf5a 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -40,6 +40,12 @@ enum switchdev_attr_id {
 	SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
 	SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED,
 	SWITCHDEV_ATTR_ID_BRIDGE_MROUTER,
+#ifdef CONFIG_BRIDGE_MRP
+	SWITCHDEV_ATTR_ID_MRP_PORT_STATE,
+	SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,
+	SWITCHDEV_ATTR_ID_MRP_RING_STATE,
+	SWITCHDEV_ATTR_ID_MRP_RING_TRANS,
+#endif
 };
 
 struct switchdev_attr {
@@ -55,6 +61,12 @@ struct switchdev_attr {
 		clock_t ageing_time;			/* BRIDGE_AGEING_TIME */
 		bool vlan_filtering;			/* BRIDGE_VLAN_FILTERING */
 		bool mc_disabled;			/* MC_DISABLED */
+#ifdef CONFIG_BRIDGE_MRP
+		u8 mrp_port_state;			/* MRP_PORT_STATE */
+		u8 mrp_port_role;			/* MRP_PORT_ROLE */
+		u8 mrp_ring_state;			/* MRP_RING_STATE */
+		u32 mrp_ring_trans;			/* MRP_RING_TRANSITION */
+#endif
 	} u;
 };
 
@@ -63,6 +75,11 @@ enum switchdev_obj_id {
 	SWITCHDEV_OBJ_ID_PORT_VLAN,
 	SWITCHDEV_OBJ_ID_PORT_MDB,
 	SWITCHDEV_OBJ_ID_HOST_MDB,
+#ifdef CONFIG_BRIDGE_MRP
+	SWITCHDEV_OBJ_ID_PORT_MRP,
+	SWITCHDEV_OBJ_ID_RING_TEST_MRP,
+	SWITCHDEV_OBJ_ID_RING_ROLE_MRP,
+#endif
 };
 
 struct switchdev_obj {
@@ -94,6 +111,41 @@ struct switchdev_obj_port_mdb {
 #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \
 	container_of((OBJ), struct switchdev_obj_port_mdb, obj)
 
+#ifdef CONFIG_BRIDGE_MRP
+/* SWITCHDEV_OBJ_ID_PORT_MRP */
+struct switchdev_obj_port_mrp {
+	struct switchdev_obj obj;
+	struct net_device *port;
+	u32 ring_nr;
+};
+
+#define SWITCHDEV_OBJ_PORT_MRP(OBJ) \
+	container_of((OBJ), struct switchdev_obj_port_mrp, obj)
+
+/* SWITCHDEV_OBJ_ID_RING_TEST_MRP */
+struct switchdev_obj_ring_test_mrp {
+	struct switchdev_obj obj;
+	/* The value is in us and a value of 0 represents to stop */
+	u32 interval;
+	u8 max;
+	u32 ring_nr;
+};
+
+#define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \
+	container_of((OBJ), struct switchdev_obj_ring_test_mrp, obj)
+
+/* SWITCHDEV_OBJ_ID_RING_ROLE_MRP */
+struct switchdev_obj_ring_role_mrp {
+	struct switchdev_obj obj;
+	u8 ring_role;
+	u32 ring_nr;
+};
+
+#define SWITCHDEV_OBJ_RING_ROLE_MRP(OBJ) \
+	container_of((OBJ), struct switchdev_obj_ring_role_mrp, obj)
+
+#endif
+
 typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj);
 
 enum switchdev_notifier_type {
diff --git a/net/bridge/Makefile b/net/bridge/Makefile
index 917826c9d8de..a51a9fc112ed 100644
--- a/net/bridge/Makefile
+++ b/net/bridge/Makefile
@@ -26,4 +26,4 @@ bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o
 
 obj-$(CONFIG_NETFILTER) += netfilter/
 
-bridge-$(CONFIG_BRIDGE_MRP)	+= br_mrp.o br_mrp_timer.o
+bridge-$(CONFIG_BRIDGE_MRP)	+= br_mrp.o br_mrp_timer.o br_mrp_switchdev.o
diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c
index 4173021d3bfa..d109fce226d5 100644
--- a/net/bridge/br_mrp.c
+++ b/net/bridge/br_mrp.c
@@ -78,6 +78,10 @@ void br_mrp_set_mrm_state(struct br_mrp *mrp,
 {
 	br_debug(mrp->br, "mrm_state: %s\n", br_mrp_get_mrm_state(state));
 	mrp->mrm_state = state;
+
+	br_mrp_switchdev_set_ring_state(mrp, state == BR_MRP_MRM_STATE_CHK_RC ?
+					BR_MRP_RING_STATE_CLOSED :
+					BR_MRP_RING_STATE_OPEN);
 }
 
 void br_mrp_set_mrc_state(struct br_mrp *mrp,
@@ -101,9 +105,9 @@ static int br_mrp_set_mrm_role(struct br_mrp *mrp)
 
 	br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_AC_STAT1);
 
-	mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
-	mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
-	mrp->ring_role = BR_MRP_RING_ROLE_MRM;
+	br_mrp_port_switchdev_set_state(mrp->p_port, BR_MRP_PORT_STATE_BLOCKED);
+	br_mrp_port_switchdev_set_state(mrp->s_port, BR_MRP_PORT_STATE_BLOCKED);
+	br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_MRM);
 
 	if (br_mrp_is_port_up(mrp->p_port))
 		br_mrp_port_link_change(mrp->p_port, true);
@@ -128,9 +132,9 @@ static int br_mrp_set_mrc_role(struct br_mrp *mrp)
 
 	br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1);
 
-	mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
-	mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
-	mrp->ring_role = BR_MRP_RING_ROLE_MRC;
+	br_mrp_port_switchdev_set_state(mrp->p_port, BR_MRP_PORT_STATE_BLOCKED);
+	br_mrp_port_switchdev_set_state(mrp->s_port, BR_MRP_PORT_STATE_BLOCKED);
+	br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_MRC);
 
 	if (br_mrp_is_port_up(mrp->p_port))
 		br_mrp_port_link_change(mrp->p_port, true);
@@ -385,7 +389,8 @@ static void br_mrp_mrm_recv_ring_test(struct br_mrp *mrp)
 		br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RC);
 		break;
 	case BR_MRP_MRM_STATE_CHK_RO:
-		mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+		br_mrp_port_switchdev_set_state(mrp->s_port,
+						BR_MRP_PORT_STATE_BLOCKED);
 
 		mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1;
 		mrp->ring_test_curr = 0;
@@ -455,7 +460,8 @@ static void br_mrp_recv_ring_topo(struct net_bridge_port *port,
 	case BR_MRP_MRC_STATE_PT:
 		mrp->ring_link_curr_max = mrp->ring_link_conf_max;
 		br_mrp_ring_link_up_stop(mrp);
-		mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+		br_mrp_port_switchdev_set_state(mrp->s_port,
+						BR_MRP_PORT_STATE_FORWARDING);
 		br_mrp_clear_fdb_start(mrp, ntohs(hdr->interval));
 		br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT_IDLE);
 		break;
@@ -538,7 +544,8 @@ static void br_mrp_recv_ring_link(struct net_bridge_port *port,
 		}
 
 		if (type == BR_MRP_TLV_HEADER_RING_LINK_UP && !mrp->blocked) {
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1;
 			mrp->ring_test_curr = 0;
 
@@ -570,8 +577,9 @@ static void br_mrp_recv_ring_link(struct net_bridge_port *port,
 
 		if (type == BR_MRP_TLV_HEADER_RING_LINK_DOWN &&
 		    mrp->react_on_link_change) {
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
-			mrp->ring_transitions++;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_FORWARDING);
+			br_mrp_switchdev_update_ring_transitions(mrp);
 			br_mrp_ring_topo_req(mrp, 0);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RO);
 			break;
@@ -808,14 +816,16 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up)
 	switch (mrp->mrm_state) {
 	case BR_MRP_MRM_STATE_AC_STAT1:
 		if (up && p == mrp->p_port) {
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_FORWARDING);
 			br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 		}
 		if (up && p != mrp->p_port) {
 			mrp->s_port = mrp->p_port;
 			mrp->p_port = p;
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_FORWARDING);
 			br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 		}
@@ -823,7 +833,8 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up)
 	case BR_MRP_MRM_STATE_PRM_UP:
 		if (!up && p == mrp->p_port) {
 			br_mrp_ring_test_stop(mrp);
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_AC_STAT1);
 		}
 		if (up && p != mrp->p_port) {
@@ -838,14 +849,16 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up)
 		if (!up && p == mrp->p_port) {
 			mrp->s_port = mrp->p_port;
 			mrp->p_port = p;
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval);
 			br_mrp_ring_topo_req(mrp, topo_interval);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 			break;
 		}
 		if (!up && p != mrp->p_port) {
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 		}
 		break;
@@ -853,16 +866,18 @@ static void br_mrp_mrm_port_link(struct net_bridge_port *p, bool up)
 		if (!up && p == mrp->p_port) {
 			mrp->p_port = mrp->s_port;
 			mrp->s_port = p;
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+			br_mrp_port_switchdev_set_role(mrp->s_port,
+						       BR_MRP_PORT_STATE_BLOCKED);
+			br_mrp_port_switchdev_set_role(mrp->p_port,
+						       BR_MRP_PORT_STATE_FORWARDING);
 			br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval);
 			br_mrp_ring_topo_req(mrp, topo_interval);
-			mrp->ring_transitions++;
+			br_mrp_switchdev_update_ring_transitions(mrp);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 			break;
 		}
 		if (!up && p != mrp->p_port) {
-			mrp->ring_transitions++;
+			br_mrp_switchdev_update_ring_transitions(mrp);
 			br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_PRM_UP);
 			break;
 		}
@@ -887,13 +902,15 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 	switch (mrp->mrc_state) {
 	case BR_MRP_MRC_STATE_AC_STAT1:
 		if (up && p == mrp->p_port) {
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_FORWARDING);
 			br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_DE_IDLE);
 		}
 		if (up && p != mrp->p_port) {
 			mrp->s_port = mrp->p_port;
 			mrp->p_port = p;
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_FORWARDING);
 			br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_DE_IDLE);
 		}
 		break;
@@ -908,7 +925,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 			br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT);
 		}
 		if (!up && p == mrp->p_port) {
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1);
 		}
 		break;
@@ -916,7 +934,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 		if (!up && p != mrp->p_port) {
 			mrp->ring_link_curr_max = mrp->ring_link_conf_max;
 			br_mrp_ring_link_up_stop(mrp);
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_link_down_start(mrp,
 						    mrp->ring_link_conf_interval);
 			br_mrp_ring_link_req(mrp->p_port, up,
@@ -930,8 +949,10 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 			br_mrp_ring_link_up_stop(mrp);
 			mrp->p_port = mrp->s_port;
 			mrp->s_port = p;
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_FORWARDING);
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_link_down_start(mrp,
 						    mrp->ring_link_conf_interval);
 			br_mrp_ring_link_req(mrp->p_port, up,
@@ -953,7 +974,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 		}
 		if (!up && p == mrp->p_port) {
 			mrp->ring_link_curr_max = mrp->ring_link_conf_max;
-			mrp->p_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->p_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_link_down_stop(mrp);
 			br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_AC_STAT1);
 		}
@@ -961,7 +983,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 	case BR_MRP_MRC_STATE_PT_IDLE:
 		if (!up && p != mrp->p_port) {
 			mrp->ring_link_curr_max = mrp->ring_link_conf_max;
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_link_down_start(mrp,
 						    mrp->ring_link_conf_interval);
 			br_mrp_ring_link_req(mrp->p_port, up,
@@ -973,7 +996,8 @@ static void br_mrp_mrc_port_link(struct net_bridge_port *p, bool up)
 			mrp->ring_link_curr_max = mrp->ring_link_conf_max;
 			mrp->p_port = mrp->s_port;
 			mrp->s_port = p;
-			mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_BLOCKED;
+			br_mrp_port_switchdev_set_state(mrp->s_port,
+							BR_MRP_PORT_STATE_BLOCKED);
 			br_mrp_ring_link_down_start(mrp,
 						    mrp->ring_link_conf_interval);
 			br_mrp_ring_link_req(mrp->p_port, up,
@@ -1183,7 +1207,7 @@ static int br_mrp_port_init(struct net_bridge_port *port, struct br_mrp *mrp,
 	 * to set again the role(MRM or MRC)
 	 */
 	br_mrp_reset_ring_state(mrp);
-	mrp->ring_role = BR_MRP_RING_ROLE_DISABLED;
+	br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_DISABLED);
 
 	if (!port->mrp_port) {
 		port->mrp_port = devm_kzalloc(&port->br->dev->dev,
@@ -1194,8 +1218,9 @@ static int br_mrp_port_init(struct net_bridge_port *port, struct br_mrp *mrp,
 	}
 
 	port->mrp_port->mrp = mrp;
-	port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
-	port->mrp_port->role = role;
+	br_mrp_port_switchdev_set_role(port, BR_MRP_PORT_STATE_FORWARDING);
+	br_mrp_port_switchdev_set_role(port, role);
+	br_mrp_port_switchdev_add(port);
 
 	if (role == BR_MRP_PORT_ROLE_PRIMARY)
 		mrp->p_port = port;
@@ -1218,15 +1243,16 @@ void br_mrp_port_uninit(struct net_bridge_port *port)
 	mutex_lock(&mrp->lock);
 
 	br_mrp_reset_ring_state(mrp);
-	mrp->ring_role = BR_MRP_RING_ROLE_DISABLED;
+	br_mrp_switchdev_set_ring_role(mrp, BR_MRP_RING_ROLE_DISABLED);
 
 	if (port->mrp_port->role == BR_MRP_PORT_ROLE_PRIMARY)
 		mrp->p_port = NULL;
 	if (port->mrp_port->role == BR_MRP_PORT_ROLE_SECONDARY)
 		mrp->s_port = NULL;
 
-	port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
-	port->mrp_port->role = BR_MRP_PORT_ROLE_NONE;
+	br_mrp_port_switchdev_set_state(port, BR_MRP_PORT_STATE_FORWARDING);
+	br_mrp_port_switchdev_set_role(port, BR_MRP_PORT_ROLE_NONE);
+	br_mrp_port_switchdev_del(port);
 	port->mrp_port->mrp = NULL;
 
 	devm_kfree(&port->br->dev->dev, port->mrp_port);
diff --git a/net/bridge/br_mrp_switchdev.c b/net/bridge/br_mrp_switchdev.c
new file mode 100644
index 000000000000..c02f46e0ca47
--- /dev/null
+++ b/net/bridge/br_mrp_switchdev.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <net/switchdev.h>
+
+#include "br_private_mrp.h"
+
+int br_mrp_port_switchdev_add(struct net_bridge_port *p)
+{
+	struct net_bridge *br = p->br;
+	struct switchdev_obj_port_mrp mrp = {
+		.obj.orig_dev = br->dev,
+		.obj.id = SWITCHDEV_OBJ_ID_PORT_MRP,
+		.port = p->dev,
+		.ring_nr = p->mrp_port->mrp->ring_nr,
+	};
+	int err = 0;
+
+	err = switchdev_port_obj_add(br->dev, &mrp.obj, NULL);
+
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
+}
+
+int br_mrp_switchdev_set_ring_role(struct br_mrp *mrp,
+				   enum br_mrp_ring_role_type role)
+{
+	struct switchdev_obj_ring_role_mrp mrp_role = {
+		.obj.orig_dev = mrp->br->dev,
+		.obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP,
+		.ring_role = role,
+		.ring_nr = mrp->ring_nr,
+	};
+	int err = 0;
+
+	mrp->ring_role = role;
+
+	pr_info("%s role: %d\n", __func__, role);
+
+	if (role == BR_MRP_RING_ROLE_DISABLED)
+		err = switchdev_port_obj_del(mrp->br->dev, &mrp_role.obj);
+	else
+		err = switchdev_port_obj_add(mrp->br->dev, &mrp_role.obj, NULL);
+
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
+}
+
+int br_mrp_switchdev_send_ring_test(struct br_mrp *mrp, u32 interval, u8 max)
+{
+	struct switchdev_obj_ring_test_mrp test = {
+		.obj.orig_dev = mrp->br->dev,
+		.obj.id = SWITCHDEV_OBJ_ID_RING_TEST_MRP,
+		.interval = interval,
+		.max = max,
+		.ring_nr = mrp->ring_nr,
+	};
+	int err = 0;
+
+	if (interval == 0)
+		err = switchdev_port_obj_del(mrp->br->dev, &test.obj);
+	else
+		err = switchdev_port_obj_add(mrp->br->dev, &test.obj, NULL);
+
+	return err;
+}
+
+int br_mrp_port_switchdev_del(struct net_bridge_port *p)
+{
+	struct net_bridge *br = p->br;
+	struct switchdev_obj_port_mrp mrp = {
+		.obj.orig_dev = br->dev,
+		.obj.id = SWITCHDEV_OBJ_ID_PORT_MRP,
+		.port = p->dev,
+	};
+	int err = 0;
+
+	if (!p->mrp_port->mrp)
+		return 0;
+
+	mrp.ring_nr = p->mrp_port->mrp->ring_nr;
+
+	err = switchdev_port_obj_del(br->dev, &mrp.obj);
+
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
+}
+
+int br_mrp_port_switchdev_set_state(struct net_bridge_port *p,
+				    enum br_mrp_port_state_type state)
+{
+	struct switchdev_attr attr = {
+		.orig_dev = p->dev,
+		.id = SWITCHDEV_ATTR_ID_MRP_PORT_STATE,
+		.u.mrp_port_state = state,
+	};
+	int err = 0;
+
+	p->mrp_port->state = state;
+
+	pr_info("%s port: %s, state: %d\n", __func__, p->dev->name, state);
+
+	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;
+
+	p->mrp_port->role = role;
+
+	err = switchdev_port_attr_set(p->dev, &attr);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
+}
+
+int br_mrp_switchdev_set_ring_state(struct br_mrp *mrp,
+				    enum br_mrp_ring_state_type state)
+{
+	struct switchdev_attr attr = {
+		.id = SWITCHDEV_ATTR_ID_MRP_RING_STATE,
+		.u.mrp_ring_state = state,
+	};
+	int err = 0;
+
+	attr.orig_dev = mrp->p_port->dev,
+	err = switchdev_port_attr_set(mrp->p_port->dev, &attr);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	attr.orig_dev = mrp->s_port->dev;
+	err = switchdev_port_attr_set(mrp->s_port->dev, &attr);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return err;
+}
+
+int br_mrp_switchdev_update_ring_transitions(struct br_mrp *mrp)
+{
+	struct switchdev_attr attr = {
+		.id = SWITCHDEV_ATTR_ID_MRP_RING_TRANS,
+	};
+	int err;
+
+	mrp->ring_transitions++;
+
+	attr.u.mrp_ring_trans = mrp->ring_transitions;
+
+	attr.orig_dev = mrp->p_port->dev,
+	err = switchdev_port_attr_set(mrp->p_port->dev, &attr);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	attr.orig_dev = mrp->s_port->dev;
+	err = switchdev_port_attr_set(mrp->s_port->dev, &attr);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
+}
+
diff --git a/net/bridge/br_mrp_timer.c b/net/bridge/br_mrp_timer.c
index 59aa8c05724f..6493fc94bd49 100644
--- a/net/bridge/br_mrp_timer.c
+++ b/net/bridge/br_mrp_timer.c
@@ -6,7 +6,8 @@
 
 static void br_mrp_ring_open(struct br_mrp *mrp)
 {
-	mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+	br_mrp_port_switchdev_set_state(mrp->s_port,
+					BR_MRP_PORT_STATE_FORWARDING);
 
 	mrp->ring_test_curr_max = mrp->ring_test_conf_max - 1;
 	mrp->ring_test_curr = 0;
@@ -18,7 +19,7 @@ static void br_mrp_ring_open(struct br_mrp *mrp)
 
 	br_mrp_ring_test_req(mrp, mrp->ring_test_conf_interval);
 
-	mrp->ring_transitions++;
+	br_mrp_switchdev_update_ring_transitions(mrp);
 	br_mrp_set_mrm_state(mrp, BR_MRP_MRM_STATE_CHK_RO);
 }
 
@@ -111,7 +112,8 @@ static void br_mrp_ring_link_up_expired(struct work_struct *work)
 		br_mrp_ring_link_req(mrp->p_port, true, interval);
 	} else {
 		mrp->ring_link_curr_max = mrp->ring_link_conf_max;
-		mrp->s_port->mrp_port->state = BR_MRP_PORT_STATE_FORWARDING;
+		br_mrp_port_switchdev_set_state(mrp->s_port,
+						BR_MRP_PORT_STATE_FORWARDING);
 		br_mrp_set_mrc_state(mrp, BR_MRP_MRC_STATE_PT_IDLE);
 	}
 
@@ -152,12 +154,41 @@ static void br_mrp_ring_link_down_expired(struct work_struct *work)
 
 void br_mrp_ring_test_start(struct br_mrp *mrp, u32 interval)
 {
+	int err;
+
+	err = br_mrp_switchdev_send_ring_test(mrp, interval,
+					      mrp->ring_test_conf_max);
+	/* If HW can transmit the test frames then don't start anymore the
+	 * SW timers
+	 */
+	if (!err) {
+		pr_info("HW timers started\n");
+		return;
+	} else if (err != -EOPNOTSUPP) {
+		pr_info("HW can't start timers error: %d\n", err);
+		return;
+	}
+
 	queue_delayed_work(mrp->timers_queue, &mrp->ring_test_work,
 			   usecs_to_jiffies(interval));
 }
 
 void br_mrp_ring_test_stop(struct br_mrp *mrp)
 {
+	int err;
+
+	err = br_mrp_switchdev_send_ring_test(mrp, 0, 0);
+	/* If HW can stop the transmission of the test frames then the SW timers
+	 * were not start so just exit
+	 */
+	if (!err) {
+		pr_info("HW timers stopped\n");
+		return;
+	} else if (err != -EOPNOTSUPP) {
+		pr_info("HW can't stop timers error: %d\n", err);
+		return;
+	}
+
 	cancel_delayed_work(&mrp->ring_test_work);
 }
 
diff --git a/net/bridge/br_private_mrp.h b/net/bridge/br_private_mrp.h
index 13fd2330ccfc..f3f34749774d 100644
--- a/net/bridge/br_private_mrp.h
+++ b/net/bridge/br_private_mrp.h
@@ -205,4 +205,20 @@ void br_mrp_ring_link_up_stop(struct br_mrp *mrp);
 void br_mrp_ring_link_down_start(struct br_mrp *mrp, u32 interval);
 void br_mrp_ring_link_down_stop(struct br_mrp *mrp);
 
+/* br_mrp_switchdev.c */
+int br_mrp_port_switchdev_add(struct net_bridge_port *p);
+int br_mrp_port_switchdev_del(struct net_bridge_port *p);
+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_ring_role(struct br_mrp *mrp,
+				   enum br_mrp_ring_role_type role);
+int br_mrp_switchdev_set_ring_state(struct br_mrp *mrp,
+				    enum br_mrp_ring_state_type state);
+int br_mrp_switchdev_update_ring_transitions(struct br_mrp *mrp);
+
+int br_mrp_switchdev_send_ring_test(struct br_mrp *mrp, u32 interval, u8 max);
+
 #endif /* BR_PRIVATE_MRP_H_ */
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ