[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <a550c4f3f8c406f6b5162ff378e0ec08ae9d0eaa.1666603600.git.ecree.xilinx@gmail.com>
Date: Mon, 24 Oct 2022 10:29:22 +0100
From: <edward.cree@....com>
To: <netdev@...r.kernel.org>, <linux-net-drivers@....com>
CC: <davem@...emloft.net>, <kuba@...nel.org>, <pabeni@...hat.com>,
<edumazet@...gle.com>, <habetsm.xilinx@...il.com>,
Edward Cree <ecree.xilinx@...il.com>
Subject: [PATCH net-next 2/5] sfc: add Layer 2 matches to ef100 TC offload
From: Edward Cree <ecree.xilinx@...il.com>
Support matching on EtherType, VLANs and ethernet source/destination
addresses, with masking if supported by the hardware.
Signed-off-by: Edward Cree <ecree.xilinx@...il.com>
---
drivers/net/ethernet/sfc/mae.c | 36 +++++++++++++++++++
drivers/net/ethernet/sfc/mcdi.h | 6 ++++
drivers/net/ethernet/sfc/tc.c | 62 ++++++++++++++++++++++++++++++---
drivers/net/ethernet/sfc/tc.h | 4 +++
4 files changed, 103 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 4ceb8c8f5548..e119bc61ced7 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -284,9 +284,17 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
mask_type_name(ingress_port_mask_type));
return rc;
}
+ CHECK(ETHER_TYPE, eth_proto);
+ CHECK(VLAN0_TCI, vlan_tci[0]);
+ CHECK(VLAN0_PROTO, vlan_proto[0]);
+ CHECK(VLAN1_TCI, vlan_tci[1]);
+ CHECK(VLAN1_PROTO, vlan_proto[1]);
+ CHECK(ETH_SADDR, eth_saddr);
+ CHECK(ETH_DADDR, eth_daddr);
CHECK(RECIRC_ID, recirc_id);
return 0;
}
+#undef CHECK
static bool efx_mae_asl_id(u32 id)
{
@@ -459,6 +467,34 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
match->value.recirc_id);
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
match->mask.recirc_id);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE,
+ match->value.eth_proto);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK,
+ match->mask.eth_proto);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE,
+ match->value.vlan_tci[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK,
+ match->mask.vlan_tci[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE,
+ match->value.vlan_proto[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK,
+ match->mask.vlan_proto[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE,
+ match->value.vlan_tci[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK,
+ match->mask.vlan_tci[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE,
+ match->value.vlan_proto[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK,
+ match->mask.vlan_proto[1]);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE),
+ match->value.eth_saddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK),
+ match->mask.eth_saddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE),
+ match->value.eth_daddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK),
+ match->mask.eth_daddr, ETH_ALEN);
return 0;
}
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 1f18e9dc62e8..883a4db695e2 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -224,6 +224,12 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
#define MCDI_WORD(_buf, _field) \
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
+/* Write a 16-bit field defined in the protocol as being big-endian. */
+#define MCDI_STRUCT_SET_WORD_BE(_buf, _field, _value) do { \
+ BUILD_BUG_ON(_field ## _LEN != 2); \
+ BUILD_BUG_ON(_field ## _OFST & 1); \
+ *(__force __be16 *)MCDI_STRUCT_PTR(_buf, _field) = (_value); \
+ } while (0)
#define MCDI_SET_DWORD(_buf, _field, _value) \
EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value)
#define MCDI_STRUCT_SET_DWORD(_buf, _field, _value) \
diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c
index b21a961eabb1..b469a1263211 100644
--- a/drivers/net/ethernet/sfc/tc.c
+++ b/drivers/net/ethernet/sfc/tc.c
@@ -124,6 +124,20 @@ static void efx_tc_flow_free(void *ptr, void *arg)
kfree(rule);
}
+/* Boilerplate for the simple 'copy a field' cases */
+#define _MAP_KEY_AND_MASK(_name, _type, _tcget, _tcfield, _field) \
+if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_##_name)) { \
+ struct flow_match_##_type fm; \
+ \
+ flow_rule_match_##_tcget(rule, &fm); \
+ match->value._field = fm.key->_tcfield; \
+ match->mask._field = fm.mask->_tcfield; \
+}
+#define MAP_KEY_AND_MASK(_name, _type, _tcfield, _field) \
+ _MAP_KEY_AND_MASK(_name, _type, _type, _tcfield, _field)
+#define MAP_ENC_KEY_AND_MASK(_name, _type, _tcget, _tcfield, _field) \
+ _MAP_KEY_AND_MASK(ENC_##_name, _type, _tcget, _tcfield, _field)
+
static int efx_tc_flower_parse_match(struct efx_nic *efx,
struct flow_rule *rule,
struct efx_tc_match *match,
@@ -144,26 +158,64 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
}
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC))) {
+ BIT(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT(FLOW_DISSECTOR_KEY_CVLAN))) {
NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x",
dissector->used_keys);
return -EOPNOTSUPP;
}
+ MAP_KEY_AND_MASK(BASIC, basic, n_proto, eth_proto);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic fm;
flow_rule_match_basic(rule, &fm);
- if (fm.mask->n_proto) {
- NL_SET_ERR_MSG_MOD(extack, "Unsupported eth_proto match");
- return -EOPNOTSUPP;
- }
if (fm.mask->ip_proto) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match");
return -EOPNOTSUPP;
}
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
+ struct flow_match_vlan fm;
+
+ flow_rule_match_vlan(rule, &fm);
+ if (fm.mask->vlan_id || fm.mask->vlan_priority || fm.mask->vlan_tpid) {
+ match->value.vlan_proto[0] = fm.key->vlan_tpid;
+ match->mask.vlan_proto[0] = fm.mask->vlan_tpid;
+ match->value.vlan_tci[0] = cpu_to_be16(fm.key->vlan_priority << 13 |
+ fm.key->vlan_id);
+ match->mask.vlan_tci[0] = cpu_to_be16(fm.mask->vlan_priority << 13 |
+ fm.mask->vlan_id);
+ }
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
+ struct flow_match_vlan fm;
+
+ flow_rule_match_cvlan(rule, &fm);
+ if (fm.mask->vlan_id || fm.mask->vlan_priority || fm.mask->vlan_tpid) {
+ match->value.vlan_proto[1] = fm.key->vlan_tpid;
+ match->mask.vlan_proto[1] = fm.mask->vlan_tpid;
+ match->value.vlan_tci[1] = cpu_to_be16(fm.key->vlan_priority << 13 |
+ fm.key->vlan_id);
+ match->mask.vlan_tci[1] = cpu_to_be16(fm.mask->vlan_priority << 13 |
+ fm.mask->vlan_id);
+ }
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+ struct flow_match_eth_addrs fm;
+
+ flow_rule_match_eth_addrs(rule, &fm);
+ ether_addr_copy(match->value.eth_saddr, fm.key->src);
+ ether_addr_copy(match->value.eth_daddr, fm.key->dst);
+ ether_addr_copy(match->mask.eth_saddr, fm.mask->src);
+ ether_addr_copy(match->mask.eth_daddr, fm.mask->dst);
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h
index 4373c3243e3c..272efbabd6be 100644
--- a/drivers/net/ethernet/sfc/tc.h
+++ b/drivers/net/ethernet/sfc/tc.h
@@ -26,6 +26,10 @@ struct efx_tc_match_fields {
/* L1 */
u32 ingress_port;
u8 recirc_id;
+ /* L2 (inner when encap) */
+ __be16 eth_proto;
+ __be16 vlan_tci[2], vlan_proto[2];
+ u8 eth_saddr[ETH_ALEN], eth_daddr[ETH_ALEN];
};
struct efx_tc_match {
Powered by blists - more mailing lists