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
@ -283,7 +283,14 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
|
||||
mask_type_name(ingress_port_mask_type));
|
||||
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 0;
|
||||
}
|
||||
@ -460,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;
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user