Commit c178dff3 authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski

sfc: add Layer 3 matches to ef100 TC offload

Support matching on IP protocol, Type of Service, Time To Live, source
 and destination addresses, with masking if supported by the hardware.
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6d1c604d
......@@ -290,6 +290,15 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
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(RECIRC_ID, recirc_id))
return rc;
return 0;
......@@ -495,6 +504,36 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
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
return 0;
}
......
......@@ -236,6 +236,12 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
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)
......
......@@ -144,11 +144,29 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
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) {
NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported match on control.flags %#x",
......@@ -161,22 +179,28 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
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_CVLAN) |
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_IP))) {
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->ip_proto) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported ip_proto match");
return -EOPNOTSUPP;
/* 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_IP))) {
NL_SET_ERR_MSG_FMT_MOD(extack, "L3 flower keys %#x require protocol ipv[46]",
dissector->used_keys);
return -EINVAL;
}
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan fm;
......@@ -216,6 +240,20 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
ether_addr_copy(match->mask.eth_daddr, fm.mask->dst);
}
MAP_KEY_AND_MASK(BASIC, basic, ip_proto, ip_proto);
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
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;
......@@ -30,6 +32,12 @@ struct efx_tc_match_fields {
__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
};
struct efx_tc_match {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment