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: <20230427164546.31296-3-shannon.nelson@amd.com>
Date:   Thu, 27 Apr 2023 09:45:46 -0700
From:   Shannon Nelson <shannon.nelson@....com>
To:     <shannon.nelson@....com>, <brett.creeley@....com>,
        <netdev@...r.kernel.org>
CC:     <drivers@...sando.io>
Subject: [PATCH RFC net-next 2/2] pds_core: tc command handling for vlan push-pop

Set up handling of tc commands for adding VF vlan push-pop HW
offload through the VF's representor.  The FW doesn't currently
have a proper set of adminq commands for any tc filtering,
that's a future discussion.  For now we have to get by with
using the existing VF_SETATTR command that will add the push
and pop in a single request.

Example commands for use:

    # add a qdisc for context
    tc qdisc add dev eth0 handle ffff: ingress

    # add a rule to wrap outgoing traffic with vlan id 124
    tc filter add dev eth0 parent ffff: pref 11 protocol all u32 skip_sw \
	   match u32 0 0 flowid 1:1 action vlan push id 124

    # add a rule to pop the tag from incoming traffic
    # this is required normally, but redundant with current FW
    tc filter add dev eth0 parent ffff: pref 1 protocol 802.1Q u32 skip_sw \
	   match u32 0 0 action vlan pop

    # remove rules
    tc filter del dev eth0 parent ffff:

Signed-off-by: Shannon Nelson <shannon.nelson@....com>
---
 drivers/net/ethernet/amd/pds_core/core.h |   2 +
 drivers/net/ethernet/amd/pds_core/rep.c  | 182 +++++++++++++++++++++++
 2 files changed, 184 insertions(+)

diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
index 2f38143dd5c2..ebd55bc0a7dc 100644
--- a/drivers/net/ethernet/amd/pds_core/core.h
+++ b/drivers/net/ethernet/amd/pds_core/core.h
@@ -37,6 +37,8 @@ struct pdsc_vf {
 	struct pdsc *vf;
 	u16     index;
 	__le16  vif_types[PDS_DEV_TYPE_MAX];
+
+	u16     vlanid;
 };
 
 struct pdsc_devinfo {
diff --git a/drivers/net/ethernet/amd/pds_core/rep.c b/drivers/net/ethernet/amd/pds_core/rep.c
index 297d9e2bac31..265b3be5b9d3 100644
--- a/drivers/net/ethernet/amd/pds_core/rep.c
+++ b/drivers/net/ethernet/amd/pds_core/rep.c
@@ -4,15 +4,194 @@
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_vlan.h>
 
 #include "core.h"
 
 struct pds_rep {
 	struct pdsc *vf;
 	struct pdsc *pf;
+	u32 vlan_offload_handle;
+	u16 vlan_id;
 };
 
+static int pdsc_set_vf_vlan(struct net_device *netdev, int vf_id,
+			    u16 vid, u8 qos, __be16 proto)
+{
+	struct pds_rep *vf_rep = netdev_priv(netdev);
+	union pds_core_dev_comp comp = { 0 };
+	union pds_core_dev_cmd cmd = {
+		.vf_setattr.opcode = PDS_CORE_CMD_VF_SETATTR,
+		.vf_setattr.attr = PDS_CORE_VF_ATTR_VLAN,
+		.vf_setattr.vf_index = cpu_to_le16(vf_id),
+		.vf_setattr.vlanid = cpu_to_le16(vid),
+	};
+	struct pdsc *pf = vf_rep->pf;
+	int err;
+
+	netdev_info(netdev, "%s: vf %d vlan %d\n", __func__, vf_id, vid);
+
+	err = pdsc_devcmd(pf, &cmd, &comp, pf->devcmd_timeout);
+	if (!err)
+		pf->vfs[vf_id].vlanid = vid;
+
+	return err;
+}
+
+static void print_cls(struct net_device *netdev,
+		      struct tc_cls_u32_offload *cls)
+{
+	netdev_info(netdev, "cmd %d chain_i %d proto %#x prio %d\n",
+		    cls->command, cls->common.chain_index,
+		    cls->common.protocol, cls->common.prio);
+	netdev_info(netdev, "  handle %#x val %#x mask %#x link_handle %#x fshift %d\n",
+		    cls->knode.handle, cls->knode.val, cls->knode.mask,
+		    cls->knode.link_handle, cls->knode.fshift);
+	netdev_info(netdev, "  exts %p res %p sel %p\n",
+		    cls->knode.exts,  cls->knode.res,  cls->knode.sel);
+}
+
+static int pdsc_configure_clsu32(struct net_device *netdev,
+				 struct tc_cls_u32_offload *cls)
+{
+	struct pds_rep *vf_rep = netdev_priv(netdev);
+	const struct tc_action *a, *act = NULL;
+	int err = 0;
+	u16 vid;
+	int i;
+
+	netdev_info(netdev, "%s: top handle %#x\n",
+		    __func__, vf_rep->vlan_offload_handle);
+	print_cls(netdev, cls);
+
+	if (!tcf_exts_has_actions(cls->knode.exts))
+		return -EINVAL;
+
+	/* only one action TCA_ID_VLAN is supported */
+	tcf_exts_for_each_action(i, a, cls->knode.exts) {
+		if (!is_tcf_vlan(a)) {
+			netdev_err(netdev, "%s: unsupported action %d\n",
+				   __func__, a->ops->id);
+			return -EOPNOTSUPP;
+		} else if (act) {
+			netdev_err(netdev, "%s: multiple vlan actions?\n",
+				   __func__);
+			return -EOPNOTSUPP;
+		}
+
+		act = a;
+	}
+
+	switch (tcf_vlan_action(act)) {
+	case TCA_VLAN_ACT_PUSH:
+		vid = tcf_vlan_push_vid(act);
+		if (!vid)
+			return -EINVAL;
+
+		/* only one allowed at a time */
+		if (vf_rep->vlan_id)
+			return -EBUSY;
+
+		/* with existing FW this will set up both push and pop */
+		err = pdsc_set_vf_vlan(netdev, vf_rep->vf->vf_id, vid, 0,
+				       tcf_vlan_push_proto(act));
+		if (!err) {
+			vf_rep->vlan_id = vid;
+			vf_rep->vlan_offload_handle = TC_U32_USERHTID(cls->knode.handle);
+		}
+		break;
+	case TCA_VLAN_ACT_POP:
+		/* with existing FW this is redundant */
+		err = 0;
+		break;
+	default:
+		netdev_err(netdev, "%s: tcf_vlan_action %d unsupported\n",
+			   __func__, tcf_vlan_action(act));
+		return -EOPNOTSUPP;
+	}
+
+	return err;
+}
+
+static int pdsc_delete_clsu32(struct net_device *netdev,
+			      struct tc_cls_u32_offload *cls)
+{
+	struct pds_rep *vf_rep = netdev_priv(netdev);
+	int err;
+
+	netdev_info(netdev, "%s: top handle %#x\n",
+		    __func__, vf_rep->vlan_offload_handle);
+	print_cls(netdev, cls);
+
+	if (vf_rep->vlan_offload_handle != TC_U32_USERHTID(cls->knode.handle))
+		return -EINVAL;
+
+	netdev_info(netdev, "%s: vf_id %d vlan_id %d delete\n",
+		    __func__, vf_rep->vf->vf_id, vf_rep->vlan_id);
+
+	/* with existing FW this will remove both push and pop */
+	err = pdsc_set_vf_vlan(netdev, vf_rep->vf->vf_id, 0, 0, 0);
+	vf_rep->vlan_id = 0;
+	vf_rep->vlan_offload_handle = 0;
+
+	return err;
+}
+
+static int pdsc_setup_tc_cls_u32(struct net_device *netdev,
+				 struct tc_cls_u32_offload *cls_u32)
+{
+	switch (cls_u32->command) {
+	case TC_CLSU32_NEW_KNODE:
+	case TC_CLSU32_REPLACE_KNODE:
+		return pdsc_configure_clsu32(netdev, cls_u32);
+	case TC_CLSU32_DELETE_KNODE:
+		return pdsc_delete_clsu32(netdev, cls_u32);
+
+	case TC_CLSU32_NEW_HNODE:
+	case TC_CLSU32_REPLACE_HNODE:
+	case TC_CLSU32_DELETE_HNODE:
+		return 0;
+	default:
+		netdev_info(netdev, "%s: unhandled cls_u32->command = %d\n",
+			    __func__, cls_u32->command);
+		return -EOPNOTSUPP;
+	}
+}
+
+static int pdsc_setup_tc_block_cb(enum tc_setup_type tc_type, void *type_data,
+				  void *cb_priv)
+{
+	struct net_device *netdev = cb_priv;
+
+	if (!tc_cls_can_offload_and_chain0(netdev, type_data))
+		return -EOPNOTSUPP;
+
+	switch (tc_type) {
+	case TC_SETUP_CLSU32:
+		return pdsc_setup_tc_cls_u32(netdev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static LIST_HEAD(pdsc_block_cb_list);
+
+static int pdsc_setup_tc(struct net_device *netdev, enum tc_setup_type tc_type, void *type_data)
+{
+	switch (tc_type) {
+	case TC_SETUP_BLOCK:
+		return flow_block_cb_setup_simple(type_data,
+						  &pdsc_block_cb_list,
+						  pdsc_setup_tc_block_cb,
+						  netdev, netdev, true);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static const struct net_device_ops pdsc_rep_netdev_ops = {
+	.ndo_setup_tc		= pdsc_setup_tc,
 };
 
 static void pdsc_get_rep_drvinfo(struct net_device *netdev,
@@ -60,6 +239,9 @@ int pdsc_add_rep(struct pdsc *vf, struct pdsc *pf)
 
 	vf->netdev->netdev_ops = &pdsc_rep_netdev_ops;
 	vf->netdev->ethtool_ops = &pdsc_rep_ethtool_ops;
+	vf->netdev->features |= NETIF_F_HW_TC;
+	vf->netdev->hw_features |= NETIF_F_HW_TC;
+
 	netif_carrier_off(vf->netdev);
 
 	SET_NETDEV_DEVLINK_PORT(vf->netdev,  &vf->dl_port);
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ