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]
Message-Id: <20210609151602.29004-11-oleksandr.mazur@plvision.eu>
Date:   Wed,  9 Jun 2021 18:16:00 +0300
From:   Oleksandr Mazur <oleksandr.mazur@...ision.eu>
To:     oleksandr.mazur@...ision.eu, jiri@...dia.com, davem@...emloft.net,
        kuba@...nel.org, Vadym Kochan <vkochan@...vell.com>,
        Taras Chornyi <tchornyi@...vell.com>
Cc:     netdev@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH net-next 10/11] net: marvell: prestera: add storm control (rate limiter) implementation

Storm control (BUM) provides a mechanism to limit rate of ingress
port traffic (matched by type). Devlink port parameter API is used:
driver registers a set of per-port parameters that can be accessed to both
get/set per-port per-type rate limit.
Add new FW command - RATE_LIMIT_MODE_SET.

Signed-off-by: Oleksandr Mazur <oleksandr.mazur@...ision.eu>
---
 .../net/ethernet/marvell/prestera/prestera.h  |   7 +
 .../marvell/prestera/prestera_devlink.c       | 134 +++++++++++++++++-
 .../ethernet/marvell/prestera/prestera_hw.c   |  25 ++++
 .../ethernet/marvell/prestera/prestera_hw.h   |   9 ++
 4 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/prestera/prestera.h b/drivers/net/ethernet/marvell/prestera/prestera.h
index 2c94bdec84b1..4b99a7421452 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera.h
@@ -60,6 +60,12 @@ struct prestera_port_caps {
 	u8 transceiver;
 };
 
+struct prestera_strom_control_cfg {
+	u32 bc_kbyte_per_sec_rate;
+	u32 unk_uc_kbyte_per_sec_rate;
+	u32 unreg_mc_kbyte_per_sec_rate;
+};
+
 struct prestera_port {
 	struct net_device *dev;
 	struct prestera_switch *sw;
@@ -79,6 +85,7 @@ struct prestera_port {
 		struct prestera_port_stats stats;
 		struct delayed_work caching_dw;
 	} cached_hw_stats;
+	struct prestera_strom_control_cfg storm_control;
 };
 
 struct prestera_device {
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
index d12e21db9fd6..0786fbb09f71 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
@@ -2,6 +2,8 @@
 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
 
 #include <net/devlink.h>
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
 
 #include "prestera_devlink.h"
 #include "prestera_hw.h"
@@ -159,6 +161,34 @@ struct prestera_trap_data {
 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
 			    PRESTERA_TRAP_METADATA)
 
+#define PRESTERA_PORT_PARAM_DRIVER_RUNTIME(_id, _name, _type)		      \
+	DEVLINK_PARAM_DRIVER(PRESTERA_DEVLINK_PORT_PARAM_ID_##_id, _name,     \
+			     _type, BIT(DEVLINK_PARAM_CMODE_RUNTIME), NULL,   \
+			     NULL, NULL)
+
+struct prestera_storm_control {
+	struct prestera_switch *sw;
+	struct prestera_strom_control_cfg *cfg;
+};
+
+enum prestera_devlink_port_param_id {
+	PRESTERA_DEVLINK_PORT_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX + 1,
+	PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE,
+	PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE,
+	PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE,
+};
+
+struct devlink_param prestera_devlink_port_params[] = {
+	PRESTERA_PORT_PARAM_DRIVER_RUNTIME(BC_RATE, "bc_kbyte_per_sec_rate",
+					   DEVLINK_PARAM_TYPE_U32),
+	PRESTERA_PORT_PARAM_DRIVER_RUNTIME(UC_UNK_RATE,
+					   "unk_uc_kbyte_per_sec_rate",
+					   DEVLINK_PARAM_TYPE_U32),
+	PRESTERA_PORT_PARAM_DRIVER_RUNTIME(MC_RATE,
+					   "unreg_mc_kbyte_per_sec_rate",
+					   DEVLINK_PARAM_TYPE_U32),
+};
+
 static const struct devlink_trap_group prestera_trap_groups_arr[] = {
 	/* No policer is associated with following groups (policerid == 0)*/
 	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
@@ -350,6 +380,10 @@ static void prestera_devlink_traps_fini(struct prestera_switch *sw);
 static int prestera_drop_counter_get(struct devlink *devlink,
 				     const struct devlink_trap *trap,
 				     u64 *p_drops);
+static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id,
+					   struct devlink_param_gset_ctx *ctx);
+static int prestera_devlink_port_param_get(struct devlink_port *dl_port, u32 id,
+					   struct devlink_param_gset_ctx *ctx);
 
 static int prestera_dl_info_get(struct devlink *dl,
 				struct devlink_info_req *req,
@@ -383,11 +417,17 @@ static int prestera_trap_action_set(struct devlink *devlink,
 
 static int prestera_devlink_traps_register(struct prestera_switch *sw);
 
+static const struct devlink_port_param_ops prestera_devlink_port_param_ops = {
+	.get = prestera_devlink_port_param_get,
+	.set = prestera_devlink_port_param_set,
+};
+
 static const struct devlink_ops prestera_dl_ops = {
 	.info_get = prestera_dl_info_get,
 	.trap_init = prestera_trap_init,
 	.trap_action_set = prestera_trap_action_set,
 	.trap_drop_counter_get = prestera_drop_counter_get,
+	.port_param_ops = &prestera_devlink_port_param_ops,
 };
 
 struct prestera_switch *prestera_devlink_alloc(void)
@@ -443,10 +483,12 @@ void prestera_devlink_unregister(struct prestera_switch *sw)
 int prestera_devlink_port_register(struct prestera_port *port)
 {
 	struct prestera_switch *sw = port->sw;
-	struct devlink *dl = priv_to_devlink(sw);
 	struct devlink_port_attrs attrs = {};
+	struct devlink *dl;
 	int err;
 
+	dl = priv_to_devlink(sw);
+
 	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
 	attrs.phys.port_number = port->fp_id;
 	attrs.switch_id.id_len = sizeof(sw->id);
@@ -460,12 +502,32 @@ int prestera_devlink_port_register(struct prestera_port *port)
 		return err;
 	}
 
+	err = devlink_port_params_register(
+			&port->dl_port,
+			prestera_devlink_port_params,
+			ARRAY_SIZE(prestera_devlink_port_params));
+	if (err) {
+		devlink_port_unregister(&port->dl_port);
+		dev_err(sw->dev->dev, "devlink_port_params_register failed\n");
+		return err;
+	}
+
+	devlink_port_params_publish(&port->dl_port);
+
 	return 0;
 }
 
 void prestera_devlink_port_unregister(struct prestera_port *port)
 {
+	devlink_port_params_unpublish(&port->dl_port);
+
+	devlink_port_params_unregister(
+			&port->dl_port,
+			prestera_devlink_port_params,
+			ARRAY_SIZE(prestera_devlink_port_params));
+
 	devlink_port_unregister(&port->dl_port);
+
 }
 
 void prestera_devlink_port_set(struct prestera_port *port)
@@ -622,6 +684,76 @@ static int prestera_drop_counter_get(struct devlink *devlink,
 						 cpu_code_type, p_drops);
 }
 
+static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id,
+					   struct devlink_param_gset_ctx *ctx)
+{
+	struct prestera_strom_control_cfg *cfg;
+	u32 kbyte_per_sec_rate = ctx->val.vu32;
+	struct prestera_port *port;
+	struct prestera_switch *sw;
+	u32 *param_to_set;
+	u32 storm_type;
+	int ret;
+
+	port = container_of(dl_port, struct prestera_port, dl_port);
+	sw = devlink_priv(dl_port->devlink);
+	cfg = &port->storm_control;
+
+	switch (id) {
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE:
+		param_to_set = &cfg->bc_kbyte_per_sec_rate;
+		storm_type = PRESTERA_PORT_STORM_CTL_TYPE_BC;
+		break;
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE:
+		param_to_set = &cfg->unk_uc_kbyte_per_sec_rate;
+		storm_type = PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK;
+		break;
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE:
+		param_to_set = &cfg->unreg_mc_kbyte_per_sec_rate;
+		storm_type = PRESTERA_PORT_STORM_CTL_TYPE_MC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (kbyte_per_sec_rate != *param_to_set) {
+		ret = prestera_hw_port_storm_control_cfg_set(port, storm_type,
+							     kbyte_per_sec_rate);
+		if (ret)
+			return ret;
+
+		*param_to_set = kbyte_per_sec_rate;
+	}
+
+	return 0;
+}
+
+static int prestera_devlink_port_param_get(struct devlink_port *dl_port, u32 id,
+					   struct devlink_param_gset_ctx *ctx)
+{
+	struct prestera_strom_control_cfg *cfg;
+	struct prestera_port *port;
+	struct prestera_switch *sw;
+
+	port = container_of(dl_port, struct prestera_port, dl_port);
+	sw = devlink_priv(dl_port->devlink);
+	cfg = &port->storm_control;
+
+	switch (id) {
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE:
+		ctx->val.vu32 = cfg->bc_kbyte_per_sec_rate;
+		return 0;
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE:
+		ctx->val.vu32 = cfg->unk_uc_kbyte_per_sec_rate;
+		return 0;
+	case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE:
+		ctx->val.vu32 = cfg->unreg_mc_kbyte_per_sec_rate;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
 static void prestera_devlink_traps_fini(struct prestera_switch *sw)
 {
 	struct devlink *dl = priv_to_devlink(sw);
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
index 0e5b3f8e7dc7..85a1a15717df 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
@@ -20,6 +20,7 @@ enum prestera_cmd_type_t {
 	PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100,
 	PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101,
 	PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110,
+	PRESTERA_CMD_TYPE_PORT_RATE_LIMIT_MODE_SET = 0x111,
 
 	PRESTERA_CMD_TYPE_VLAN_CREATE = 0x200,
 	PRESTERA_CMD_TYPE_VLAN_DELETE = 0x201,
@@ -251,6 +252,14 @@ struct prestera_msg_port_info_resp {
 	u16 fp_id;
 };
 
+struct prestera_msg_port_storm_control_cfg_set_req {
+	struct prestera_msg_cmd cmd;
+	u32 port;
+	u32 dev;
+	u32 storm_type;
+	u32 kbyte_per_sec_rate;
+};
+
 struct prestera_msg_vlan_req {
 	struct prestera_msg_cmd cmd;
 	u32 port;
@@ -639,6 +648,22 @@ int prestera_hw_port_accept_frm_type(struct prestera_port *port,
 			    &req.cmd, sizeof(req));
 }
 
+int prestera_hw_port_storm_control_cfg_set(const struct prestera_port *port,
+					   u32 storm_type,
+					   u32 kbyte_per_sec_rate)
+{
+	struct prestera_msg_port_storm_control_cfg_set_req req = {
+		.port = port->hw_id,
+		.dev = port->dev_id,
+		.storm_type = storm_type,
+		.kbyte_per_sec_rate = kbyte_per_sec_rate
+	};
+
+	return prestera_cmd(port->sw,
+			    PRESTERA_CMD_TYPE_PORT_RATE_LIMIT_MODE_SET,
+			    &req.cmd, sizeof(req));
+}
+
 int prestera_hw_port_cap_get(const struct prestera_port *port,
 			     struct prestera_port_caps *caps)
 {
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
index aafecf0ecd16..85373f1d3971 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
@@ -89,6 +89,12 @@ enum {
 	PRESTERA_STP_FORWARD,
 };
 
+enum {
+	PRESTERA_PORT_STORM_CTL_TYPE_BC = 0,
+	PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK = 1,
+	PRESTERA_PORT_STORM_CTL_TYPE_MC = 2
+};
+
 enum prestera_hw_cpu_code_cnt_t {
 	PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP = 0,
 	PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1,
@@ -123,6 +129,9 @@ int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac);
 int prestera_hw_port_mac_get(const struct prestera_port *port, char *mac);
 int prestera_hw_port_cap_get(const struct prestera_port *port,
 			     struct prestera_port_caps *caps);
+int prestera_hw_port_storm_control_cfg_set(const struct prestera_port *port,
+					   u32 storm_type,
+					   u32 kbyte_per_sec_rate);
 int prestera_hw_port_remote_cap_get(const struct prestera_port *port,
 				    u64 *link_mode_bitmap);
 int prestera_hw_port_remote_fc_get(const struct prestera_port *port,
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ