Merge branch 'sfc-add-basic-flower-matches-to-offload'
Edward Cree says: ==================== sfc: add basic flower matches to offload Support offloading TC flower rules with matches on L2-L4 fields. ==================== Link: https://lore.kernel.org/r/cover.1667412458.git.ecree.xilinx@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
bcc8f44aca
@ -250,6 +250,32 @@ static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ)
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate field mask against hardware capabilities. Captures caller's 'rc' */
|
||||
#define CHECK(_mcdi, _field) ({ \
|
||||
enum mask_type typ = classify_mask((const u8 *)&mask->_field, \
|
||||
sizeof(mask->_field)); \
|
||||
\
|
||||
rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
|
||||
typ); \
|
||||
if (rc) \
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, \
|
||||
"No support for %s mask in field %s", \
|
||||
mask_type_name(typ), #_field); \
|
||||
rc; \
|
||||
})
|
||||
/* Booleans need special handling */
|
||||
#define CHECK_BIT(_mcdi, _field) ({ \
|
||||
enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \
|
||||
\
|
||||
rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
|
||||
typ); \
|
||||
if (rc) \
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, \
|
||||
"No support for %s mask in field %s", \
|
||||
mask_type_name(typ), #_field); \
|
||||
rc; \
|
||||
})
|
||||
|
||||
int efx_mae_match_check_caps(struct efx_nic *efx,
|
||||
const struct efx_tc_match_fields *mask,
|
||||
struct netlink_ext_ack *extack)
|
||||
@ -269,8 +295,33 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
|
||||
mask_type_name(ingress_port_mask_type));
|
||||
return rc;
|
||||
}
|
||||
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(IP_PROTO, ip_proto) ||
|
||||
CHECK(IP_TOS, ip_tos) ||
|
||||
CHECK(IP_TTL, ip_ttl) ||
|
||||
CHECK(SRC_IP4, src_ip) ||
|
||||
CHECK(DST_IP4, dst_ip) ||
|
||||
#ifdef CONFIG_IPV6
|
||||
CHECK(SRC_IP6, src_ip6) ||
|
||||
CHECK(DST_IP6, dst_ip6) ||
|
||||
#endif
|
||||
CHECK(L4_SPORT, l4_sport) ||
|
||||
CHECK(L4_DPORT, l4_dport) ||
|
||||
CHECK(TCP_FLAGS, tcp_flags) ||
|
||||
CHECK_BIT(IS_IP_FRAG, ip_frag) ||
|
||||
CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) ||
|
||||
CHECK(RECIRC_ID, recirc_id))
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
#undef CHECK_BIT
|
||||
#undef CHECK
|
||||
|
||||
static bool efx_mae_asl_id(u32 id)
|
||||
{
|
||||
@ -439,10 +490,90 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
|
||||
}
|
||||
MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
|
||||
match->mask.ingress_port);
|
||||
EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS),
|
||||
MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
|
||||
match->value.ip_frag,
|
||||
MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
|
||||
match->value.ip_firstfrag);
|
||||
EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK),
|
||||
MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
|
||||
match->mask.ip_frag,
|
||||
MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
|
||||
match->mask.ip_firstfrag);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID,
|
||||
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);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO,
|
||||
match->value.ip_proto);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK,
|
||||
match->mask.ip_proto);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS,
|
||||
match->value.ip_tos);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK,
|
||||
match->mask.ip_tos);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL,
|
||||
match->value.ip_ttl);
|
||||
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK,
|
||||
match->mask.ip_ttl);
|
||||
MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE,
|
||||
match->value.src_ip);
|
||||
MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK,
|
||||
match->mask.src_ip);
|
||||
MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE,
|
||||
match->value.dst_ip);
|
||||
MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK,
|
||||
match->mask.dst_ip);
|
||||
#ifdef CONFIG_IPV6
|
||||
memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE),
|
||||
&match->value.src_ip6, sizeof(struct in6_addr));
|
||||
memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK),
|
||||
&match->mask.src_ip6, sizeof(struct in6_addr));
|
||||
memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE),
|
||||
&match->value.dst_ip6, sizeof(struct in6_addr));
|
||||
memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK),
|
||||
&match->mask.dst_ip6, sizeof(struct in6_addr));
|
||||
#endif
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE,
|
||||
match->value.l4_sport);
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK,
|
||||
match->mask.l4_sport);
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE,
|
||||
match->value.l4_dport);
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK,
|
||||
match->mask.l4_dport);
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE,
|
||||
match->value.tcp_flags);
|
||||
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK,
|
||||
match->mask.tcp_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -224,12 +224,24 @@ 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) \
|
||||
EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value)
|
||||
#define MCDI_DWORD(_buf, _field) \
|
||||
EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0)
|
||||
/* Write a 32-bit field defined in the protocol as being big-endian. */
|
||||
#define MCDI_STRUCT_SET_DWORD_BE(_buf, _field, _value) do { \
|
||||
BUILD_BUG_ON(_field ## _LEN != 4); \
|
||||
BUILD_BUG_ON(_field ## _OFST & 3); \
|
||||
*(__force __be32 *)MCDI_STRUCT_PTR(_buf, _field) = (_value); \
|
||||
} while (0)
|
||||
#define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \
|
||||
EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \
|
||||
MC_CMD_ ## _name1, _value1)
|
||||
|
@ -124,19 +124,59 @@ 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,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct flow_dissector *dissector = rule->match.dissector;
|
||||
unsigned char ipv = 0;
|
||||
|
||||
/* Owing to internal TC infelicities, the IPV6_ADDRS key might be set
|
||||
* even on IPv4 filters; so rather than relying on dissector->used_keys
|
||||
* we check the addr_type in the CONTROL key. If we don't find it (or
|
||||
* it's masked, which should never happen), we treat both IPV4_ADDRS
|
||||
* and IPV6_ADDRS as absent.
|
||||
*/
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
|
||||
struct flow_match_control fm;
|
||||
|
||||
flow_rule_match_control(rule, &fm);
|
||||
if (IS_ALL_ONES(fm.mask->addr_type))
|
||||
switch (fm.key->addr_type) {
|
||||
case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
ipv = 4;
|
||||
break;
|
||||
case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
ipv = 6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (fm.mask->flags) {
|
||||
if (fm.mask->flags & FLOW_DIS_IS_FRAGMENT) {
|
||||
match->value.ip_frag = fm.key->flags & FLOW_DIS_IS_FRAGMENT;
|
||||
match->mask.ip_frag = true;
|
||||
}
|
||||
if (fm.mask->flags & FLOW_DIS_FIRST_FRAG) {
|
||||
match->value.ip_firstfrag = fm.key->flags & FLOW_DIS_FIRST_FRAG;
|
||||
match->mask.ip_firstfrag = true;
|
||||
}
|
||||
if (fm.mask->flags & ~(FLOW_DIS_IS_FRAGMENT | FLOW_DIS_FIRST_FRAG)) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported match on control.flags %#x",
|
||||
fm.mask->flags);
|
||||
return -EOPNOTSUPP;
|
||||
@ -144,26 +184,101 @@ 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) |
|
||||
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_PORTS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_TCP) |
|
||||
BIT(FLOW_DISSECTOR_KEY_IP))) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x",
|
||||
dissector->used_keys);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
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;
|
||||
MAP_KEY_AND_MASK(BASIC, basic, n_proto, eth_proto);
|
||||
/* Make sure we're IP if any L3/L4 keys used. */
|
||||
if (!IS_ALL_ONES(match->mask.eth_proto) ||
|
||||
!(match->value.eth_proto == htons(ETH_P_IP) ||
|
||||
match->value.eth_proto == htons(ETH_P_IPV6)))
|
||||
if (dissector->used_keys &
|
||||
(BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_PORTS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_IP) |
|
||||
BIT(FLOW_DISSECTOR_KEY_TCP))) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, "L3/L4 flower keys %#x require protocol ipv[46]",
|
||||
dissector->used_keys);
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
MAP_KEY_AND_MASK(BASIC, basic, ip_proto, ip_proto);
|
||||
/* Make sure we're TCP/UDP if any L4 keys used. */
|
||||
if ((match->value.ip_proto != IPPROTO_UDP &&
|
||||
match->value.ip_proto != IPPROTO_TCP) || !IS_ALL_ONES(match->mask.ip_proto))
|
||||
if (dissector->used_keys &
|
||||
(BIT(FLOW_DISSECTOR_KEY_PORTS) |
|
||||
BIT(FLOW_DISSECTOR_KEY_TCP))) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, "L4 flower keys %#x require ipproto udp or tcp",
|
||||
dissector->used_keys);
|
||||
return -EINVAL;
|
||||
}
|
||||
MAP_KEY_AND_MASK(IP, ip, tos, ip_tos);
|
||||
MAP_KEY_AND_MASK(IP, ip, ttl, ip_ttl);
|
||||
if (ipv == 4) {
|
||||
MAP_KEY_AND_MASK(IPV4_ADDRS, ipv4_addrs, src, src_ip);
|
||||
MAP_KEY_AND_MASK(IPV4_ADDRS, ipv4_addrs, dst, dst_ip);
|
||||
}
|
||||
#ifdef CONFIG_IPV6
|
||||
else if (ipv == 6) {
|
||||
MAP_KEY_AND_MASK(IPV6_ADDRS, ipv6_addrs, src, src_ip6);
|
||||
MAP_KEY_AND_MASK(IPV6_ADDRS, ipv6_addrs, dst, dst_ip6);
|
||||
}
|
||||
#endif
|
||||
MAP_KEY_AND_MASK(PORTS, ports, src, l4_sport);
|
||||
MAP_KEY_AND_MASK(PORTS, ports, dst, l4_dport);
|
||||
MAP_KEY_AND_MASK(TCP, tcp, flags, tcp_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <linux/rhashtable.h>
|
||||
#include "net_driver.h"
|
||||
|
||||
#define IS_ALL_ONES(v) (!(typeof (v))~(v))
|
||||
|
||||
struct efx_tc_action_set {
|
||||
u16 deliver:1;
|
||||
u32 dest_mport;
|
||||
@ -26,6 +28,20 @@ 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];
|
||||
/* L3 (when IP) */
|
||||
u8 ip_proto, ip_tos, ip_ttl;
|
||||
__be32 src_ip, dst_ip;
|
||||
#ifdef CONFIG_IPV6
|
||||
struct in6_addr src_ip6, dst_ip6;
|
||||
#endif
|
||||
bool ip_frag, ip_firstfrag;
|
||||
/* L4 */
|
||||
__be16 l4_sport, l4_dport; /* Ports (UDP, TCP) */
|
||||
__be16 tcp_flags;
|
||||
};
|
||||
|
||||
struct efx_tc_match {
|
||||
|
Loading…
x
Reference in New Issue
Block a user