mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
sfc: add Layer 2 matches to ef100 TC offload
Support matching on EtherType, VLANs and ethernet source/destination addresses, with masking if supported by the hardware. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
f0b59ad11e
commit
6d1c604d10
4 changed files with 103 additions and 6 deletions
|
@ -283,7 +283,14 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
|
||||||
mask_type_name(ingress_port_mask_type));
|
mask_type_name(ingress_port_mask_type));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (CHECK(RECIRC_ID, recirc_id))
|
if (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 rc;
|
return rc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -460,6 +467,34 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
|
||||||
match->value.recirc_id);
|
match->value.recirc_id);
|
||||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
|
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
|
||||||
match->mask.recirc_id);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,12 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
|
||||||
#define MCDI_WORD(_buf, _field) \
|
#define MCDI_WORD(_buf, _field) \
|
||||||
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
|
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
|
||||||
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
|
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) \
|
#define MCDI_SET_DWORD(_buf, _field, _value) \
|
||||||
EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value)
|
EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value)
|
||||||
#define MCDI_STRUCT_SET_DWORD(_buf, _field, _value) \
|
#define MCDI_STRUCT_SET_DWORD(_buf, _field, _value) \
|
||||||
|
|
|
@ -124,6 +124,20 @@ static void efx_tc_flow_free(void *ptr, void *arg)
|
||||||
kfree(rule);
|
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,
|
static int efx_tc_flower_parse_match(struct efx_nic *efx,
|
||||||
struct flow_rule *rule,
|
struct flow_rule *rule,
|
||||||
struct efx_tc_match *match,
|
struct efx_tc_match *match,
|
||||||
|
@ -144,26 +158,64 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
|
||||||
}
|
}
|
||||||
if (dissector->used_keys &
|
if (dissector->used_keys &
|
||||||
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
|
~(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",
|
NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x",
|
||||||
dissector->used_keys);
|
dissector->used_keys);
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAP_KEY_AND_MASK(BASIC, basic, n_proto, eth_proto);
|
||||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
|
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
|
||||||
struct flow_match_basic fm;
|
struct flow_match_basic fm;
|
||||||
|
|
||||||
flow_rule_match_basic(rule, &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) {
|
if (fm.mask->ip_proto) {
|
||||||
NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match");
|
NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match");
|
||||||
return -EOPNOTSUPP;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,10 @@ struct efx_tc_match_fields {
|
||||||
/* L1 */
|
/* L1 */
|
||||||
u32 ingress_port;
|
u32 ingress_port;
|
||||||
u8 recirc_id;
|
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 {
|
struct efx_tc_match {
|
||||||
|
|
Loading…
Add table
Reference in a new issue