diff mbox series

[RFC,net-next,v0,1/2] net: devlink: Add port function for bridge offload

Message ID 20241111013218.1491641-2-aryan.srivastava@alliedtelesis.co.nz (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series Add bridge offloading devlink config | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success Errors and warnings before: 0 (+0) this patch: 0 (+0)
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 5 this patch: 5
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 528 this patch: 528
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc fail Errors and warnings before: 3 this patch: 4
netdev/source_inline success Was 0 now: 0

Commit Message

Aryan Srivastava Nov. 11, 2024, 1:32 a.m. UTC
Add configurable devlink port attr for HW offloading. Most drivers (and
DSA framework) will offload a bridge port to HW if there is mechanism
available to do so. Adding a configurable devlink attr allows users to
change this default setting, in cases where HW offload of a bridge port
is not desired.

Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
---
 include/net/devlink.h        | 13 ++++++++++++
 include/uapi/linux/devlink.h |  2 ++
 net/devlink/port.c           | 41 ++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+)
diff mbox series

Patch

diff --git a/include/net/devlink.h b/include/net/devlink.h
index fbb9a2668e24..64dc3e292c2c 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1613,6 +1613,15 @@  void devlink_free(struct devlink *devlink);
  *			    of event queues. Should be used by device drivers to
  *			    configure maximum number of event queues
  *			    of a function managed by the devlink port.
+ * @port_fn_bridge_offload_get: Callback used to get port function's bridge
+ *				 offload capability. Should be used by device drivers
+ *				 to report the current state of offload
+ *				 capability of a function managed by the devlink
+ *				 port.
+ * @port_fn_bridge_offload_get: Callback used to set port function's bridge
+ *				 offload capability. Should be used by device drivers to
+ *				 enable/disable offload capability of a
+ *				 function managed by the devlink port.
  *
  * Note: Driver should return -EOPNOTSUPP if it doesn't support
  * port function (@port_fn_*) handling for a particular port.
@@ -1668,6 +1677,10 @@  struct devlink_port_ops {
 	int (*port_fn_max_io_eqs_set)(struct devlink_port *devlink_port,
 				      u32 max_eqs,
 				      struct netlink_ext_ack *extack);
+	void (*port_fn_bridge_offload_get)(struct devlink_port *devlink_port,
+					   bool *is_enable);
+	void (*port_fn_bridge_offload_set)(struct devlink_port *devlink_port,
+					   bool enable);
 };
 
 void devlink_port_init(struct devlink *devlink,
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 9401aa343673..e2682bc9ecb1 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -668,6 +668,7 @@  enum devlink_port_fn_attr_cap {
 	DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
 	DEVLINK_PORT_FN_ATTR_CAP_IPSEC_CRYPTO_BIT,
 	DEVLINK_PORT_FN_ATTR_CAP_IPSEC_PACKET_BIT,
+	DEVLINK_PORT_FN_ATTR_CAP_BRIDGE_OFFLOAD_BIT,
 
 	/* Add new caps above */
 	__DEVLINK_PORT_FN_ATTR_CAPS_MAX,
@@ -678,6 +679,7 @@  enum devlink_port_fn_attr_cap {
 	_BITUL(DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT)
 #define DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO _BITUL(DEVLINK_PORT_FN_ATTR_CAP_IPSEC_CRYPTO_BIT)
 #define DEVLINK_PORT_FN_CAP_IPSEC_PACKET _BITUL(DEVLINK_PORT_FN_ATTR_CAP_IPSEC_PACKET_BIT)
+#define DEVLINK_PORT_FN_CAP_BRIDGE_OFFLOAD _BITUL(DEVLINK_PORT_FN_ATTR_CAP_BRIDGE_OFFLOAD_BIT)
 
 enum devlink_port_function_attr {
 	DEVLINK_PORT_FUNCTION_ATTR_UNSPEC,
diff --git a/net/devlink/port.c b/net/devlink/port.c
index be9158b4453c..d7f9276c3601 100644
--- a/net/devlink/port.c
+++ b/net/devlink/port.c
@@ -148,6 +148,21 @@  static int devlink_port_fn_ipsec_packet_fill(struct devlink_port *devlink_port,
 	return 0;
 }
 
+static int devlink_port_bridge_offload_fill(struct devlink_port *devlink_port,
+					    struct nla_bitfield32 *caps)
+{
+	bool is_enable;
+
+	if (!devlink_port->ops->port_fn_bridge_offload_get ||
+	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL)
+		return 0;
+
+	devlink_port->ops->port_fn_bridge_offload_get(devlink_port, &is_enable);
+
+	devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_BRIDGE_OFFLOAD, is_enable);
+	return 0;
+}
+
 static int devlink_port_fn_caps_fill(struct devlink_port *devlink_port,
 				     struct sk_buff *msg,
 				     struct netlink_ext_ack *extack,
@@ -172,6 +187,10 @@  static int devlink_port_fn_caps_fill(struct devlink_port *devlink_port,
 	if (err)
 		return err;
 
+	err = devlink_port_bridge_offload_fill(devlink_port, &caps);
+	if (err)
+		return err;
+
 	if (!caps.selector)
 		return 0;
 	err = nla_put_bitfield32(msg, DEVLINK_PORT_FN_ATTR_CAPS, caps.value,
@@ -393,6 +412,12 @@  devlink_port_fn_ipsec_packet_set(struct devlink_port *devlink_port, bool enable,
 	return devlink_port->ops->port_fn_ipsec_packet_set(devlink_port, enable, extack);
 }
 
+static void
+devlink_port_fn_bridge_offload_set(struct devlink_port *devlink_port, bool enable)
+{
+	return devlink_port->ops->port_fn_bridge_offload_set(devlink_port, enable);
+}
+
 static int devlink_port_fn_caps_set(struct devlink_port *devlink_port,
 				    const struct nlattr *attr,
 				    struct netlink_ext_ack *extack)
@@ -431,6 +456,10 @@  static int devlink_port_fn_caps_set(struct devlink_port *devlink_port,
 		if (err)
 			return err;
 	}
+	if (caps.selector & DEVLINK_PORT_FN_CAP_BRIDGE_OFFLOAD) {
+		devlink_port_fn_bridge_offload_set(devlink_port, caps_value &
+							 DEVLINK_PORT_FN_CAP_BRIDGE_OFFLOAD);
+	}
 	return 0;
 }
 
@@ -765,6 +794,18 @@  static int devlink_port_function_validate(struct devlink_port *devlink_port,
 				return -EOPNOTSUPP;
 			}
 		}
+		if (caps.selector & DEVLINK_PORT_FN_CAP_BRIDGE_OFFLOAD) {
+			if (!ops->port_fn_bridge_offload_set) {
+				NL_SET_ERR_MSG_ATTR(extack, attr,
+						    "Port doesn't support bridge offload function attribute");
+				return -EOPNOTSUPP;
+			}
+			if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL) {
+				NL_SET_ERR_MSG_ATTR(extack, attr,
+						    "bridge offload function attribute supported for physical ports only");
+				return -EOPNOTSUPP;
+			}
+		}
 	}
 	if (tb[DEVLINK_PORT_FN_ATTR_MAX_IO_EQS] &&
 	    !ops->port_fn_max_io_eqs_set) {