diff mbox series

[net-next,10/11] net: marvell: prestera: add storm control (rate limiter) implementation

Message ID 20210609151602.29004-11-oleksandr.mazur@plvision.eu (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Marvell Prestera driver implementation of devlink functionality. | expand

Checks

Context Check Description
netdev/apply fail Patch does not apply to net-next
netdev/tree_selection success Clearly marked for net-next

Commit Message

Oleksandr Mazur June 9, 2021, 3:16 p.m. UTC
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@plvision.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(-)

Comments

Ido Schimmel June 9, 2021, 5:59 p.m. UTC | #1
On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
> 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.

This should be properly modeled in the bridge driver and offloaded to
capable drivers via switchdev. Modeling it as a driver-specific devlink
parameter is wrong.
Nikolay Aleksandrov June 10, 2021, 9:31 a.m. UTC | #2
On 09/06/2021 20:59, Ido Schimmel wrote:
> On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
>> 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.
> 
> This should be properly modeled in the bridge driver and offloaded to
> capable drivers via switchdev. Modeling it as a driver-specific devlink
> parameter is wrong.
> 

Absolutely agree with Ido, there are many different ways to achieve it through
the bridge (e.g. generic bridge helpers to be used by bpf, directly by tc or new br tc hooks
to name a few). I'd personally be excited to see any of these implemented as they
could open the door for a lot other interesting use cases. Unfortunately I'm currently swamped
with per-vlan multicast support, after that depending on time availability I could look
into this unless someone beats me to it. :)

Cheers,
 Nik
Andrew Lunn June 10, 2021, 12:41 p.m. UTC | #3
On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
> 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.

Hi Oleksandr

Just expanding on the two comments you already received about this.

We often see people miss that switchdev is about. It is not about
writing switch drivers. It is about writing network stack
accelerators. You take a feature of the Linux network stack and you
accelerate it by offloading it to the hardware. So look around the
network stack and see how you configure it to perform rate limiting of
broadcast traffic ingress. Once you have found a suitable mechanism,
accelerate it via offloading.

If you find Linux has no way to perform a feature the hardware could
accelerate, you first need to add a pure software version of that
feature to the network stack, and then add acceleration support for
it.


	   Andrew
Oleksandr Mazur June 11, 2021, 1:19 p.m. UTC | #4
>>  On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
> 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.

> Hi Oleksandr

> Just expanding on the two comments you already received about this.

> We often see people miss that switchdev is about. It is not about
> writing switch drivers. It is about writing network stack
> accelerators. You take a feature of the Linux network stack and you
> accelerate it by offloading it to the hardware. So look around the
> network stack and see how you configure it to perform rate limiting of
> broadcast traffic ingress. Once you have found a suitable mechanism,
> accelerate it via offloading.

> If you find Linux has no way to perform a feature the hardware could
> accelerate, you first need to add a pure software version of that
> feature to the network stack, and then add acceleration support for
> it.


Hello Andrew, Ido, Nikolay,
I appreciate your time and comments provided over this patchset, though i have a few questions to ask, if you don't mind:

1. Does it mean that in order to support storm control in switchdev driver i need to implement software storm control in bridge driver,
and then using the switchdev attributes (notifiers) mechanism offload the configuration itself to the HW?
2. Is there any chance of keeping devlink solution untill the discussed (storm control implemented in the bridge driver) mechanism will be ready/implemented?

Anyway, it relies on the port param API from devlink which is already present in the kernel API.
Andrew Lunn June 11, 2021, 5:08 p.m. UTC | #5
On Fri, Jun 11, 2021 at 01:19:13PM +0000, Oleksandr Mazur wrote:
> >>  On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
> > 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.
> 
> > Hi Oleksandr
> 
> > Just expanding on the two comments you already received about this.
> 
> > We often see people miss that switchdev is about. It is not about
> > writing switch drivers. It is about writing network stack
> > accelerators. You take a feature of the Linux network stack and you
> > accelerate it by offloading it to the hardware. So look around the
> > network stack and see how you configure it to perform rate limiting of
> > broadcast traffic ingress. Once you have found a suitable mechanism,
> > accelerate it via offloading.
> 
> > If you find Linux has no way to perform a feature the hardware could
> > accelerate, you first need to add a pure software version of that
> > feature to the network stack, and then add acceleration support for
> > it.
> 
> 
> Hello Andrew, Ido, Nikolay,
> I appreciate your time and comments provided over this patchset, though i have a few questions to ask, if you don't mind:
> 

> 1. Does it mean that in order to support storm control in switchdev
> driver i need to implement software storm control in bridge driver,
> and then using the switchdev attributes (notifiers) mechanism
> offload the configuration itself to the HW?

Hi Oleksandr

Not necessarily. Is storm control anything more than ingress packet
matching and rate limiting?

I'm not TC expert, but look for example at
https://man7.org/linux/man-pages/man8/tc-police.8.html

and the example:

# tc qdisc add dev eth0 handle ffff: ingress
# tc filter add dev eth0 parent ffff: u32 \
                   match u32 0 0 \
                   police rate 1mbit burst 100k

Replace the "match u32 0 0" with something which matches on broadcast
frames.  Maybe "flower dst_mac ff:ff:ff:ff:ff:ff"

So there is a software solution. Now accelerate it.

> 2. Is there any chance of keeping devlink solution untill the
> discussed (storm control implemented in the bridge driver) mechanism
> will be ready/implemented?

No. Please do it correctly from the beginning. No hacks.

    Andrew
Ido Schimmel June 13, 2021, 7:34 a.m. UTC | #6
On Fri, Jun 11, 2021 at 07:08:00PM +0200, Andrew Lunn wrote:
> On Fri, Jun 11, 2021 at 01:19:13PM +0000, Oleksandr Mazur wrote:
> > >>  On Wed, Jun 09, 2021 at 06:16:00PM +0300, Oleksandr Mazur wrote:
> > > 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.
> > 
> > > Hi Oleksandr
> > 
> > > Just expanding on the two comments you already received about this.
> > 
> > > We often see people miss that switchdev is about. It is not about
> > > writing switch drivers. It is about writing network stack
> > > accelerators. You take a feature of the Linux network stack and you
> > > accelerate it by offloading it to the hardware. So look around the
> > > network stack and see how you configure it to perform rate limiting of
> > > broadcast traffic ingress. Once you have found a suitable mechanism,
> > > accelerate it via offloading.
> > 
> > > If you find Linux has no way to perform a feature the hardware could
> > > accelerate, you first need to add a pure software version of that
> > > feature to the network stack, and then add acceleration support for
> > > it.
> > 
> > 
> > Hello Andrew, Ido, Nikolay,
> > I appreciate your time and comments provided over this patchset, though i have a few questions to ask, if you don't mind:
> > 
> 
> > 1. Does it mean that in order to support storm control in switchdev
> > driver i need to implement software storm control in bridge driver,
> > and then using the switchdev attributes (notifiers) mechanism
> > offload the configuration itself to the HW?
> 
> Hi Oleksandr
> 
> Not necessarily. Is storm control anything more than ingress packet
> matching and rate limiting?
> 
> I'm not TC expert, but look for example at
> https://man7.org/linux/man-pages/man8/tc-police.8.html
> 
> and the example:
> 
> # tc qdisc add dev eth0 handle ffff: ingress
> # tc filter add dev eth0 parent ffff: u32 \
>                    match u32 0 0 \
>                    police rate 1mbit burst 100k
> 
> Replace the "match u32 0 0" with something which matches on broadcast
> frames.  Maybe "flower dst_mac ff:ff:ff:ff:ff:ff"
> 
> So there is a software solution. Now accelerate it.

Storm control also needs the ability to limit other types of flooded
traffic such unknown unicast and unregistered multicast packets. The
entity which classifies packets as such is the bridge, which happens
after the ingress hook.

I see two options to support storm control in Linux:

1. By adding support in the bridge itself as a new bridge slave option.
Something like:

# ip link set dev swp1 type bridge_slave \
	storm_control type { uuc | umc | bc} rate RATE mode { packet | byte }

I suspect this similar to more traditional implementations that users
might be used to and also maps nicely to hardware implementations

2. Teaching tc to call into the bridge to classify a packet. Not sure a
whole new classifier is needed for this. Maybe just extend flower with a
new key: dst_mac_type { uuc | umc }. I personally find this a bit weird,
but it is more flexible and allows to reuse existing actions

> 
> > 2. Is there any chance of keeping devlink solution untill the
> > discussed (storm control implemented in the bridge driver) mechanism
> > will be ready/implemented?
> 
> No. Please do it correctly from the beginning. No hacks.

+1
kernel test robot June 16, 2021, 7:15 a.m. UTC | #7
Hi Oleksandr,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on kselftest/next]
[also build test WARNING on net/master linus/master v5.13-rc6]
[cannot apply to net-next/master sparc-next/master next-20210615]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Oleksandr-Mazur/Marvell-Prestera-driver-implementation-of-devlink-functionality/20210616-112917
base:   https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/d1e2db61850ee143f7aa180d34efb413f0956abd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Oleksandr-Mazur/Marvell-Prestera-driver-implementation-of-devlink-functionality/20210616-112917
        git checkout d1e2db61850ee143f7aa180d34efb413f0956abd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/marvell/prestera/prestera_devlink.c: In function 'prestera_devlink_port_param_set':
>> drivers/net/ethernet/marvell/prestera/prestera_devlink.c:693:26: warning: variable 'sw' set but not used [-Wunused-but-set-variable]
     693 |  struct prestera_switch *sw;
         |                          ^~
   drivers/net/ethernet/marvell/prestera/prestera_devlink.c: In function 'prestera_devlink_port_param_get':
   drivers/net/ethernet/marvell/prestera/prestera_devlink.c:736:26: warning: variable 'sw' set but not used [-Wunused-but-set-variable]
     736 |  struct prestera_switch *sw;
         |                          ^~


vim +/sw +693 drivers/net/ethernet/marvell/prestera/prestera_devlink.c

   686	
   687	static int prestera_devlink_port_param_set(struct devlink_port *dl_port, u32 id,
   688						   struct devlink_param_gset_ctx *ctx)
   689	{
   690		struct prestera_strom_control_cfg *cfg;
   691		u32 kbyte_per_sec_rate = ctx->val.vu32;
   692		struct prestera_port *port;
 > 693		struct prestera_switch *sw;
   694		u32 *param_to_set;
   695		u32 storm_type;
   696		int ret;
   697	
   698		port = container_of(dl_port, struct prestera_port, dl_port);
   699		sw = devlink_priv(dl_port->devlink);
   700		cfg = &port->storm_control;
   701	
   702		switch (id) {
   703		case PRESTERA_DEVLINK_PORT_PARAM_ID_BC_RATE:
   704			param_to_set = &cfg->bc_kbyte_per_sec_rate;
   705			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_BC;
   706			break;
   707		case PRESTERA_DEVLINK_PORT_PARAM_ID_UC_UNK_RATE:
   708			param_to_set = &cfg->unk_uc_kbyte_per_sec_rate;
   709			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_UC_UNK;
   710			break;
   711		case PRESTERA_DEVLINK_PORT_PARAM_ID_MC_RATE:
   712			param_to_set = &cfg->unreg_mc_kbyte_per_sec_rate;
   713			storm_type = PRESTERA_PORT_STORM_CTL_TYPE_MC;
   714			break;
   715		default:
   716			return -EINVAL;
   717		}
   718	
   719		if (kbyte_per_sec_rate != *param_to_set) {
   720			ret = prestera_hw_port_storm_control_cfg_set(port, storm_type,
   721								     kbyte_per_sec_rate);
   722			if (ret)
   723				return ret;
   724	
   725			*param_to_set = kbyte_per_sec_rate;
   726		}
   727	
   728		return 0;
   729	}
   730	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

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,