sfc: support TC decap rules
Subsystems (3)
v2 cover sfc: support TC decap rules
From: Edward Cree <[email protected]>
This series adds support for offloading tunnel decapsulation TC rules to
ef100 NICs, allowing matching encapsulated packets to be decapsulated in hardware and redirected to VFs.
For now an encap match must be on precisely the following fields:
ethertype (IPv4 or IPv6), source IP, destination IP, ipproto UDP, UDP destination port. This simplifies checking for overlaps in the driver; the hardware supports a wider range of match fields which future driver work may expose.
Edward Cree (6):
sfc: document TC-to-EF100-MAE action translation concepts
sfc: add notion of match on enc keys to MAE machinery
sfc: handle enc keys in efx_tc_flower_parse_match()
sfc: add functions to insert encap matches into the MAE
sfc: add code to register and unregister encap matches
sfc: add offloading of 'foreign' TC (decap) rules
drivers/net/ethernet/sfc/mae.c | 227 ++++++++++++- drivers/net/ethernet/sfc/mae.h | 11 + drivers/net/ethernet/sfc/tc.c | 600 ++++++++++++++++++++++++++++++++- drivers/net/ethernet/sfc/tc.h | 37 ++ 4 files changed, 857 insertions(+), 18 deletions(-)
PATCH v2 1/6 sfc: document TC-to-EF100-MAE action translation concepts
From: Edward Cree <[email protected]>
Includes an explanation of the lifetime of the 'cursor' action-set act.
---
Changed in v2: newly added patch
--- drivers/net/ethernet/sfc/tc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
drivers/net/ethernet/sfc/tc.c +25 -1
@@ -66,7 +66,7 @@ static const struct rhashtable_params efx_tc_match_action_ht_params = {static void efx_tc_free_action_set (struct efx_nic *efx,struct efx_tc_action_set *act,bool in_hw) { -/* Failure paths calling this on the 'running action' set in_hw=false, +/* Failure paths calling this on the 'cursor' action set in_hw=false, * because if the alloc had succeeded we'd've put it in acts.list and * not still have it in act. */
@@ -407,6 +407,30 @@ static int efx_tc_flower_replace(struct efx_nic *efx, goto release; } +/** +* DOC: TC action translation +* +* Actions in TC are sequential and cumulative, with delivery actions +* potentially anywhere in the order. The EF100 MAE, however, takes +* an 'action set list' consisting of 'action sets', each of which is +* applied to the _original_ packet, and consists of a set of optional +* actions in a fixed order with delivery at the end. +* To translate between these two models, we maintain a 'cursor', @act, +* which describes the cumulative effect of all the packet-mutating +* actions encountered so far; on handling a delivery (mirred or drop) +* action, once the action-set has been inserted into hardware, we +* append @act to the action-set list (@rule->acts); if this is a pipe +* action (mirred mirror) we then allocate a new @act with a copy of +* the cursor state _before_ the delivery action, otherwise we set @act +* to %NULL. +* This ensures that every allocated action-set is either attached to +* @rule->acts or pointed to by @act (and never both), and that only +* those action-sets in @rule->acts exist in hardware. Consequently, +* in the failure path, @act only needs to be freed in memory, whereas +* for @rule->acts we remove each action-set from hardware before +* freeing it (efx_tc_free_action_set_list()), even if the action-set +* list itself is not in hardware. +*/ flow_action_for_each (i, fa, &fr->action) {struct efx_tc_action_set save;u16 tci;
Re: [PATCH net-next v2 1/6] sfc: document TC-to-EF100-MAE action translation concepts
Quoted 5 lines · On Thu, Mar 23, 2023 at 08:45:09PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Includes an explanation of the lifetime of the 'cursor' action-set
act.Signed-off-by Edward Cree <[email protected]>
PATCH v2 2/6 sfc: add notion of match on enc keys to MAE machinery
In reply to [email protected]From: Edward Cree <[email protected]>
Extend the MAE caps check to validate that the hardware supports used
outer-header matches.
Extend efx_mae_populate_match_criteria() to fill in the outer rule ID
and VNI match fields.
Nothing yet populates these match fields, nor creates outer rules.
---
Changed in v2: efx_mae_check_encap_match_caps now takes a bool ipv6 rather
than an unsigned char ipv, simplifying the code.
--- drivers/net/ethernet/sfc/mae.c | 97 +++++++++++++++++++++++++++++++++- drivers/net/ethernet/sfc/mae.h | 3 ++ drivers/net/ethernet/sfc/tc.h | 24 +++++++++ 3 files changed, 122 insertions(+), 2 deletions(-)
drivers/net/ethernet/sfc/mae.c +95 -2
@@ -254,13 +254,23 @@ static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,size_t outlen;int rc, i; +/* AR and OR caps MCDIs have identical layout, so we are using the +* same code for both. +*/ +BUILD_BUG_ON (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN (MAE_NUM_FIELDS ) < +MC_CMD_MAE_GET_OR_CAPS_OUT_LEN (MAE_NUM_FIELDS ));BUILD_BUG_ON (MC_CMD_MAE_GET_AR_CAPS_IN_LEN ); +BUILD_BUG_ON (MC_CMD_MAE_GET_OR_CAPS_IN_LEN ); rc =efx_mcdi_rpc (efx, cmd,NULL ,0 , outbuf,sizeof (outbuf), &outlen);if (rc)return rc; +BUILD_BUG_ON (MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST != +MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST ); count =MCDI_DWORD (outbuf,MAE_GET_AR_CAPS_OUT_COUNT );memset (field_support,MAE_FIELD_UNSUPPORTED ,MAE_NUM_FIELDS ); +BUILD_BUG_ON (MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST != +MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST ); caps =_MCDI_DWORD (outbuf,MAE_GET_AR_CAPS_OUT_FIELD_FLAGS );/* We're only interested in the support status enum, not any other * flags, so just extract that from each entry.
@@ -278,8 +288,12 @@ int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps) rc =efx_mae_get_basic_caps (efx, caps);if (rc)return rc; -return efx_mae_get_rule_fields (efx,MC_CMD_MAE_GET_AR_CAPS , - caps->action_rule_fields); + rc =efx_mae_get_rule_fields (efx,MC_CMD_MAE_GET_AR_CAPS , + caps->action_rule_fields); +if (rc) +return rc; +return efx_mae_get_rule_fields (efx,MC_CMD_MAE_GET_OR_CAPS , + caps->outer_rule_fields); }/* Bit twiddling:
@@ -432,11 +446,67 @@ int efx_mae_match_check_caps(struct efx_nic *efx, CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) || CHECK(RECIRC_ID, recirc_id))return rc; +/* Matches on outer fields are done in a separate hardware table, +* the Outer Rule table. Thus the Action Rule merely does an +* exact match on Outer Rule ID if any outer field matches are +* present. The exception is the VNI/VSID (enc_keyid), which is +* available to the Action Rule match iff the Outer Rule matched +* (and thus identified the encap protocol to use to extract it). +*/ +if (efx_tc_match_is_encap (mask)) { + rc =efx_mae_match_check_cap_typ ( + supported_fields[MAE_FIELD_OUTER_RULE_ID ], +MASK_ONES ); +if (rc) { +NL_SET_ERR_MSG_MOD (extack,"No support for encap rule ID matches" ); +return rc; + } +if (CHECK (ENC_VNET_ID , enc_keyid)) +return rc; + }else if (mask->enc_keyid) { +NL_SET_ERR_MSG_MOD (extack,"Match on enc_keyid requires other encap fields" ); +return -EINVAL ; + }return 0 ; }#undef CHECK_BIT#undef CHECK +#define CHECK (_mcdi) ({ \ + rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ + MASK_ONES); \ + if (rc) \ + NL_SET_ERR_MSG_FMT_MOD(extack, \ + "No support for field %s", #_mcdi); \ + rc; \ +}) +/* Checks that the fields needed for encap-rule matches are supported by the +* MAE. All the fields are exact-match. +*/ +int efx_mae_check_encap_match_caps (struct efx_nic *efx,bool ipv6, +struct netlink_ext_ack *extack) +{ +u8 *supported_fields = efx->tc->caps->outer_rule_fields; +int rc; + +if (CHECK (ENC_ETHER_TYPE )) +return rc; +if (ipv6) { +if (CHECK (ENC_SRC_IP6 ) || +CHECK (ENC_DST_IP6 )) +return rc; + }else { +if (CHECK (ENC_SRC_IP4 ) || +CHECK (ENC_DST_IP4 )) +return rc; + } +if (CHECK (ENC_L4_DPORT ) || +CHECK (ENC_IP_PROTO )) +return rc; +return 0 ; +} +#undef CHECK +int efx_mae_allocate_counter (struct efx_nic *efx,struct efx_tc_counter *cnt) {MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));
@@ -941,6 +1011,29 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 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); +/* enc-keys are handled indirectly, through encap_match ID */ +if (match->encap) { +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID , + match->encap->fw_id); +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK , +U32_MAX ); +/* enc_keyid (VNI/VSID) is not part of the encap_match */ +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE , + match->value.enc_keyid); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK , + match->mask.enc_keyid); + }else if (WARN_ON_ONCE (match->mask.enc_src_ip) || +WARN_ON_ONCE (match->mask.enc_dst_ip) || +WARN_ON_ONCE (!ipv6_addr_any (&match->mask.enc_src_ip6)) || +WARN_ON_ONCE (!ipv6_addr_any (&match->mask.enc_dst_ip6)) || +WARN_ON_ONCE (match->mask.enc_ip_tos) || +WARN_ON_ONCE (match->mask.enc_ip_ttl) || +WARN_ON_ONCE (match->mask.enc_sport) || +WARN_ON_ONCE (match->mask.enc_dport) || +WARN_ON_ONCE (match->mask.enc_keyid)) { +/* No enc-keys should appear in a rule without an encap_match */ +return -EOPNOTSUPP ; + }return 0 ; }
drivers/net/ethernet/sfc/mae.h +3 -0
@@ -72,6 +72,7 @@ struct mae_caps {u32 match_field_count;u32 action_prios;u8 action_rule_fields[MAE_NUM_FIELDS ]; +u8 outer_rule_fields[MAE_NUM_FIELDS ]; };int efx_mae_get_caps (struct efx_nic *efx,struct mae_caps *caps);
@@ -79,6 +80,8 @@ int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps);int efx_mae_match_check_caps (struct efx_nic *efx,const struct efx_tc_match_fields *mask,struct netlink_ext_ack *extack); +int efx_mae_check_encap_match_caps (struct efx_nic *efx,bool ipv6, +struct netlink_ext_ack *extack);int efx_mae_allocate_counter (struct efx_nic *efx,struct efx_tc_counter *cnt);int efx_mae_free_counter (struct efx_nic *efx,struct efx_tc_counter *cnt);
drivers/net/ethernet/sfc/tc.h +24 -0
@@ -48,11 +48,35 @@ struct efx_tc_match_fields {/* L4 */ __be16 l4_sport, l4_dport;/* Ports (UDP, TCP) */ __be16 tcp_flags; +/* Encap. The following are *outer* fields. Note that there are no +* outer eth (L2) fields; this is because TC doesn't have them. +*/ +__be32 enc_src_ip, enc_dst_ip; +struct in6_addr enc_src_ip6, enc_dst_ip6; +u8 enc_ip_tos, enc_ip_ttl; +__be16 enc_sport, enc_dport; +__be32 enc_keyid;/* e.g. VNI, VSID */ +}; + +static inline bool efx_tc_match_is_encap (const struct efx_tc_match_fields *mask) +{ +return mask->enc_src_ip || mask->enc_dst_ip || + !ipv6_addr_any (&mask->enc_src_ip6) || + !ipv6_addr_any (&mask->enc_dst_ip6) || mask->enc_ip_tos || + mask->enc_ip_ttl || mask->enc_sport || mask->enc_dport; +} + +struct efx_tc_encap_match { +__be32 src_ip, dst_ip; +struct in6_addr src_ip6, dst_ip6; +__be16 udp_dport; +u32 fw_id;/* index of this entry in firmware encap match table */ };struct efx_tc_match {struct efx_tc_match_fields value;struct efx_tc_match_fields mask; +struct efx_tc_encap_match *encap; };struct efx_tc_action_set_list {
Re: [PATCH net-next v2 2/6] sfc: add notion of match on enc keys to MAE machinery
Hi Edward,
Looks good to me.
A few minor comments inline.
Quoted 4 lines · On Thu, Mar 23, 2023 at 08:45:10PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Extend the MAE caps check to validate that the hardware supports used
outer-header matches.
s/used// ?
Quoted 5 lines
Extend
efx_mae_populate_match_criteria()to fill in the outer rule ID
and VNI match fields.
Nothing yet populates these match fields, nor creates outer rules.Signed-off-by Edward Cree <[email protected]>
...
Quoted 8 lines
int
efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt){drivers/net/ethernet/sfc/mae.c +1
-0MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));@@ -941,6 +1011,29 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 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); +/* enc-keys are handled indirectly, through encap_match ID */
drivers/net/ethernet/sfc/mae.c static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), · line 1024
Quoted 10 lines
drivers/net/ethernet/sfc/mae.c +10
-0+if (match->encap) { +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID , + match->encap->fw_id); +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK , +U32_MAX ); +/* enc_keyid (VNI/VSID) is not part of the encap_match */ +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE , + match->value.enc_keyid); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK , + match->mask.enc_keyid);
Is it intentional that value.enc_keyid is used as the mask. Perhaps naively I would have expected something more like U32_MAX.
Quoted 14 lines
drivers/net/ethernet/sfc/mae.c +12
-0+ }else if (WARN_ON_ONCE (match->mask.enc_src_ip) || +WARN_ON_ONCE (match->mask.enc_dst_ip) || +WARN_ON_ONCE (!ipv6_addr_any (&match->mask.enc_src_ip6)) || +WARN_ON_ONCE (!ipv6_addr_any (&match->mask.enc_dst_ip6)) || +WARN_ON_ONCE (match->mask.enc_ip_tos) || +WARN_ON_ONCE (match->mask.enc_ip_ttl) || +WARN_ON_ONCE (match->mask.enc_sport) || +WARN_ON_ONCE (match->mask.enc_dport) || +WARN_ON_ONCE (match->mask.enc_keyid)) { +/* No enc-keys should appear in a rule without an encap_match */ +return -EOPNOTSUPP ; + }return 0 ; }
Edward Cree
maintainerRe: [PATCH net-next v2 2/6] sfc: add notion of match on enc keys to MAE machinery
Quoted 5 lines · Simon Horman
Hi Edward,
Looks good to me.
A few minor comments inline.
Quoted 7 lines
Quoted 4 lines · On Thu, Mar 23, 2023 at 08:45:10PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Extend the MAE caps check to validate that the hardware supports used
outer-header matches.s/used// ?
I think I meant it in the sense of "the outer-header matches which
are used by the driver"; I can definitely reword it to spell that out better.
Quoted 12 lines
Quoted 12 lines
int
efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt){drivers/net/ethernet/sfc/mae.c +5
-0MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));@@ -941,6 +1011,29 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 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); +/* enc-keys are handled indirectly, through encap_match ID */ +if (match->encap) { +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID , + match->encap->fw_id); + MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK,
Quoted 8 lines
drivers/net/ethernet/sfc/mae.c static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), · line 1024
Quoted 6 lines
drivers/net/ethernet/sfc/mae.c +6
-0+ U32_MAX); +/* enc_keyid (VNI/VSID) is not part of the encap_match */ +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE , + match->value.enc_keyid); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK , + match->mask.enc_keyid);Is it intentional that value.enc_keyid is used as the mask.
But it isn't. mask.enc_keyid is.
Re: [PATCH net-next v2 2/6] sfc: add notion of match on enc keys to MAE machinery
Quoted 9 lines · Edward Cree
Quoted 8 lines · Simon Horman
Hi Edward,
Looks good to me.
A few minor comments inline.Quoted 2 lines · On Thu, Mar 23, 2023 at 08:45:10PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Extend the MAE caps check to validate that the hardware supports used
outer-header matches.s/used// ?
I think I meant it in the sense of "the outer-header matches which
are used by the driver"; I can definitely reword it to spell that out better.
Thanks, I did have a bit of trouble parsing the text.
Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
int
efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt){drivers/net/ethernet/sfc/mae.c +5
-0MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));@@ -941,6 +1011,29 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 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); +/* enc-keys are handled indirectly, through encap_match ID */ +if (match->encap) { +MCDI_STRUCT_SET_DWORD (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID , + match->encap->fw_id); + MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK,Quoted 8 lines
drivers/net/ethernet/sfc/mae.c static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), · line 1024
Quoted 6 lines
drivers/net/ethernet/sfc/mae.c +6
-0+ U32_MAX); +/* enc_keyid (VNI/VSID) is not part of the encap_match */ +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE , + match->value.enc_keyid); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK , + match->mask.enc_keyid);Is it intentional that value.enc_keyid is used as the mask.
Quoted 1 line
But it isn't. mask.enc_keyid is.
Indeed it is :)
PATCH v2 3/6 sfc: handle enc keys in efx_tc_flower_parse_match()
In reply to [email protected]From: Edward Cree <[email protected]>
Translate the fields from flow dissector into struct efx_tc_match. In efx_tc_flower_replace(), reject filters that match on them, because
only 'foreign' filters (i.e. those for which the ingress dev is not the sfc netdev or any of its representors, e.g. a tunnel netdev) can use them.
---
Changed in v2: removed bogus 'kcompat' ifdefs (spotted by Michal)
--- drivers/net/ethernet/sfc/tc.c | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
drivers/net/ethernet/sfc/tc.c +61 -0
@@ -193,6 +193,11 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx, BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_PORTS) | + BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | + BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | + BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | + BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | + BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | BIT(FLOW_DISSECTOR_KEY_TCP) | BIT(FLOW_DISSECTOR_KEY_IP))) { NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x",
@@ -280,6 +285,57 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,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); +if (flow_rule_match_key (rule,FLOW_DISSECTOR_KEY_ENC_CONTROL )) { +struct flow_match_control fm; + +flow_rule_match_enc_control (rule, &fm); +if (fm.mask->flags) { +NL_SET_ERR_MSG_FMT_MOD (extack,"Unsupported match on enc_control.flags %#x" , + fm.mask->flags); +return -EOPNOTSUPP ; + } +if (!IS_ALL_ONES (fm.mask->addr_type)) { +NL_SET_ERR_MSG_FMT_MOD (extack,"Unsupported enc addr_type mask %u (key %u)" , + fm.mask->addr_type, + fm.key->addr_type); +return -EOPNOTSUPP ; + } +switch (fm.key->addr_type) { +case FLOW_DISSECTOR_KEY_IPV4_ADDRS : +MAP_ENC_KEY_AND_MASK (IPV4_ADDRS , ipv4_addrs, enc_ipv4_addrs, + src, enc_src_ip); +MAP_ENC_KEY_AND_MASK (IPV4_ADDRS , ipv4_addrs, enc_ipv4_addrs, + dst, enc_dst_ip); +break ; +#ifdef CONFIG_IPV6 +case FLOW_DISSECTOR_KEY_IPV6_ADDRS : +MAP_ENC_KEY_AND_MASK (IPV6_ADDRS , ipv6_addrs, enc_ipv6_addrs, + src, enc_src_ip6); +MAP_ENC_KEY_AND_MASK (IPV6_ADDRS , ipv6_addrs, enc_ipv6_addrs, + dst, enc_dst_ip6); +break ; +#endif +default : +NL_SET_ERR_MSG_FMT_MOD (extack, +"Unsupported enc addr_type %u (supported are IPv4, IPv6)" , + fm.key->addr_type); +return -EOPNOTSUPP ; + } +MAP_ENC_KEY_AND_MASK (IP , ip, enc_ip, tos, enc_ip_tos); +MAP_ENC_KEY_AND_MASK (IP , ip, enc_ip, ttl, enc_ip_ttl); +MAP_ENC_KEY_AND_MASK (PORTS , ports, enc_ports, src, enc_sport); +MAP_ENC_KEY_AND_MASK (PORTS , ports, enc_ports, dst, enc_dport); +MAP_ENC_KEY_AND_MASK (KEYID , enc_keyid, enc_keyid, keyid, enc_keyid); + }else if (dissector->used_keys & + (BIT (FLOW_DISSECTOR_KEY_ENC_KEYID ) | +BIT (FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS ) | +BIT (FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS ) | +BIT (FLOW_DISSECTOR_KEY_ENC_IP ) | +BIT (FLOW_DISSECTOR_KEY_ENC_PORTS ))) { +NL_SET_ERR_MSG_FMT_MOD (extack,"Flower enc keys require enc_control (keys: %#x)" , + dissector->used_keys); +return -EOPNOTSUPP ; + }return 0 ; }
@@ -373,6 +429,11 @@ static int efx_tc_flower_replace(struct efx_nic *efx, rc =efx_tc_flower_parse_match (efx, fr, &match, extack);if (rc)return rc; +if (efx_tc_match_is_encap (&match.mask)) { +NL_SET_ERR_MSG_MOD (extack,"Ingress enc_key matches not supported" ); + rc = -EOPNOTSUPP ; + goto release; + }if (tc->common.chain_index) {NL_SET_ERR_MSG_MOD (extack,"No support for nonzero chain_index" );
Re: [PATCH net-next v2 3/6] sfc: handle enc keys in efx_tc_flower_parse_match()
Quoted 9 lines · On Thu, Mar 23, 2023 at 08:45:11PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Translate the fields from flow dissector into struct
efx_tc_match. Inefx_tc_flower_replace(), reject filters that match on them, because
only 'foreign' filters (i.e. those for which the ingress dev is not the sfc netdev or any of its representors, e.g. a tunnel netdev) can use them.Signed-off-by Edward Cree <[email protected]>
PATCH v2 4/6 sfc: add functions to insert encap matches into the MAE
In reply to [email protected]From: Edward Cree <[email protected]>
An encap match corresponds to an entry in the exact-match Outer Rule
table; the lookup response includes the encap type (protocol) allowing the hardware to continue parsing into the inner headers.
--- drivers/net/ethernet/sfc/mae.c | 105 +++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/mae.h | 5 ++ drivers/net/ethernet/sfc/tc.h | 1 + 3 files changed, 111 insertions(+)
drivers/net/ethernet/sfc/mae.c +105 -0
@@ -558,6 +558,20 @@ int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)return 0 ; } +static int efx_mae_encap_type_to_mae_type (enum efx_encap_type type) +{ +switch (type &EFX_ENCAP_TYPES_MASK ) { +case EFX_ENCAP_TYPE_NONE : +return MAE_MCDI_ENCAP_TYPE_NONE ; +case EFX_ENCAP_TYPE_VXLAN : +return MAE_MCDI_ENCAP_TYPE_VXLAN ; +case EFX_ENCAP_TYPE_GENEVE : +return MAE_MCDI_ENCAP_TYPE_GENEVE ; +default : +return -EOPNOTSUPP ; + } +} +int efx_mae_lookup_mport (struct efx_nic *efx,u32 vf_idx,u32 *id) {struct ef100_nic_data *nic_data = efx->nic_data;
@@ -915,6 +929,97 @@ int efx_mae_free_action_set_list(struct efx_nic *efx,return 0 ; } +int efx_mae_register_encap_match (struct efx_nic *efx, +struct efx_tc_encap_match *encap) +{ +MCDI_DECLARE_BUF (inbuf,MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN (MAE_ENC_FIELD_PAIRS_LEN )); +MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN ); +MCDI_DECLARE_STRUCT_PTR (match_crit); +size_t outlen; +int rc; + + rc =efx_mae_encap_type_to_mae_type (encap->tun_type); +if (rc <0 ) +return rc; + match_crit =_MCDI_DWORD (inbuf,MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA ); +/* The struct contains IP src and dst, and udp dport. +* So we actually need to filter on IP src and dst, L4 dport, and +* ipproto == udp. +*/ +MCDI_SET_DWORD (inbuf,MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE , rc); +#ifdef CONFIG_IPV6 +if (encap->src_ip | encap->dst_ip) { +#endif +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE , + encap->src_ip); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK , + ~(__be32 )0 ); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE , + encap->dst_ip); +MCDI_STRUCT_SET_DWORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK , + ~(__be32 )0 ); +MCDI_STRUCT_SET_WORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE , +htons (ETH_P_IP )); +#ifdef CONFIG_IPV6 + }else { +memcpy (MCDI_STRUCT_PTR (match_crit,MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE ), + &encap->src_ip6,sizeof (encap->src_ip6)); +memset (MCDI_STRUCT_PTR (match_crit,MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK ), +0xff ,sizeof (encap->src_ip6)); +memcpy (MCDI_STRUCT_PTR (match_crit,MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE ), + &encap->dst_ip6,sizeof (encap->dst_ip6)); +memset (MCDI_STRUCT_PTR (match_crit,MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK ), +0xff ,sizeof (encap->dst_ip6)); +MCDI_STRUCT_SET_WORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE , +htons (ETH_P_IPV6 )); + } +#endif +MCDI_STRUCT_SET_WORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK , + ~(__be16 )0 ); +MCDI_STRUCT_SET_WORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE , + encap->udp_dport); +MCDI_STRUCT_SET_WORD_BE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK , + ~(__be16 )0 ); +MCDI_STRUCT_SET_BYTE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO ,IPPROTO_UDP ); +MCDI_STRUCT_SET_BYTE (match_crit,MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK , ~0 ); + rc =efx_mcdi_rpc (efx,MC_CMD_MAE_OUTER_RULE_INSERT , inbuf, +sizeof (inbuf), outbuf,sizeof (outbuf), &outlen); +if (rc) +return rc; +if (outlen <sizeof (outbuf)) +return -EIO ; + encap->fw_id =MCDI_DWORD (outbuf,MAE_OUTER_RULE_INSERT_OUT_OR_ID ); +return 0 ; +} + +int efx_mae_unregister_encap_match (struct efx_nic *efx, +struct efx_tc_encap_match *encap) +{ +MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN (1 )); +MCDI_DECLARE_BUF (inbuf,MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN (1 )); +size_t outlen; +int rc; + +MCDI_SET_DWORD (inbuf,MAE_OUTER_RULE_REMOVE_IN_OR_ID , encap->fw_id); + rc =efx_mcdi_rpc (efx,MC_CMD_MAE_OUTER_RULE_REMOVE , inbuf, +sizeof (inbuf), outbuf,sizeof (outbuf), &outlen); +if (rc) +return rc; +if (outlen <sizeof (outbuf)) +return -EIO ; +/* FW freed a different ID than we asked for, should also never happen. +* Warn because it means we've now got a different idea to the FW of +* what encap_mds exist, which could cause mayhem later. +*/ +if (WARN_ON (MCDI_DWORD (outbuf,MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID ) != encap->fw_id)) +return -EIO ; +/* We're probably about to free @encap, but let's just make sure its +* fw_id is blatted so that it won't look valid if it leaks out. +*/ + encap->fw_id =MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL ; +return 0 ; +} +static int efx_mae_populate_match_criteria (MCDI_DECLARE_STRUCT_PTR (match_crit ),const struct efx_tc_match *match) {
drivers/net/ethernet/sfc/mae.h +5 -0
@@ -94,6 +94,11 @@ int efx_mae_alloc_action_set_list(struct efx_nic *efx,int efx_mae_free_action_set_list (struct efx_nic *efx,struct efx_tc_action_set_list *acts); +int efx_mae_register_encap_match (struct efx_nic *efx, +struct efx_tc_encap_match *encap); +int efx_mae_unregister_encap_match (struct efx_nic *efx, +struct efx_tc_encap_match *encap); +int efx_mae_insert_rule (struct efx_nic *efx,const struct efx_tc_match *match,u32 prio,u32 acts_id,u32 *id);int efx_mae_delete_rule (struct efx_nic *efx,u32 id);
drivers/net/ethernet/sfc/tc.h +1 -0
@@ -70,6 +70,7 @@ struct efx_tc_encap_match {__be32 src_ip, dst_ip;struct in6_addr src_ip6, dst_ip6;__be16 udp_dport; +u16 tun_type;/* enum efx_encap_type */ u32 fw_id;/* index of this entry in firmware encap match table */ };
Re: [PATCH net-next v2 4/6] sfc: add functions to insert encap matches into the MAE
Quoted 7 lines · On Thu, Mar 23, 2023 at 08:45:12PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
An encap match corresponds to an entry in the exact-match Outer Rule
table; the lookup response includes the encap type (protocol) allowing the hardware to continue parsing into the inner headers.Signed-off-by Edward Cree <[email protected]>
Hi Edward,
this also looks good to me.
Minor nit below not withstanding.
...
Quoted 41 lines
drivers/net/ethernet/sfc/mae.c +26
-0@@ -558,6 +558,20 @@ int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)return 0 ; } +static int efx_mae_encap_type_to_mae_type (enum efx_encap_type type) +{ +switch (type &EFX_ENCAP_TYPES_MASK ) { +case EFX_ENCAP_TYPE_NONE : +return MAE_MCDI_ENCAP_TYPE_NONE ; +case EFX_ENCAP_TYPE_VXLAN : +return MAE_MCDI_ENCAP_TYPE_VXLAN ; +case EFX_ENCAP_TYPE_GENEVE : +return MAE_MCDI_ENCAP_TYPE_GENEVE ; +default : +return -EOPNOTSUPP ; + } +} +int efx_mae_lookup_mport (struct efx_nic *efx,u32 vf_idx,u32 *id) {struct ef100_nic_data *nic_data = efx->nic_data;@@ -915,6 +929,97 @@ int efx_mae_free_action_set_list(struct efx_nic *efx,return 0 ; } +int efx_mae_register_encap_match (struct efx_nic *efx, +struct efx_tc_encap_match *encap) +{ +MCDI_DECLARE_BUF (inbuf,MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN (MAE_ENC_FIELD_PAIRS_LEN )); +MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN ); +MCDI_DECLARE_STRUCT_PTR (match_crit); +size_t outlen; +int rc; + + rc =efx_mae_encap_type_to_mae_type (encap->tun_type); +if (rc <0 ) +return rc;
...
drivers/net/ethernet/sfc/tc.h struct efx_tc_encap_match { · line 73
Quoted 9 lines
drivers/net/ethernet/sfc/tc.h +1
-0@@ -70,6 +70,7 @@ struct efx_tc_encap_match {__be32 src_ip, dst_ip;struct in6_addr src_ip6, dst_ip6;__be16 udp_dport; +u16 tun_type;/* enum efx_encap_type */
nit: maybe the type of tyn_type can be enum efx_encap_type.
Quoted 4 lines
drivers/net/ethernet/sfc/tc.h +0
-0u32 fw_id;/* index of this entry in firmware encap match table */ };
Edward Cree
maintainerRe: [PATCH net-next v2 4/6] sfc: add functions to insert encap matches into the MAE
Quoted 12 lines · Simon Horman
drivers/net/ethernet/sfc/tc.h struct efx_tc_encap_match { · line 73
Quoted 9 lines · On Thu, Mar 23, 2023 at 08:45:12PM +0000, [email protected] wrote:
drivers/net/ethernet/sfc/tc.h +1
-0@@ -70,6 +70,7 @@ struct efx_tc_encap_match {__be32 src_ip, dst_ip;struct in6_addr src_ip6, dst_ip6;__be16 udp_dport; +u16 tun_type;/* enum efx_encap_type */ nit: maybe the type of
tyn_typecan be enumefx_encap_type.
Yeah, it probably should. Looking at my git history I think the
initial reason was for struct-packing reasons (enums are int-sized at minimum, which is excessive for a field whose largest value is 3), but with the rhash_head that later appears between these two fields, using the narrower type doesn't actually avoid a 16-bit hole like it appears to here.
Will change in v3.
Re: [PATCH net-next v2 4/6] sfc: add functions to insert encap matches into the MAE
Quoted 14 lines · Edward Cree
Quoted 12 lines · Simon Horman
drivers/net/ethernet/sfc/tc.h struct efx_tc_encap_match { · line 73
Quoted 9 lines · On Thu, Mar 23, 2023 at 08:45:12PM +0000, [email protected] wrote:
drivers/net/ethernet/sfc/tc.h +1
-0@@ -70,6 +70,7 @@ struct efx_tc_encap_match {__be32 src_ip, dst_ip;struct in6_addr src_ip6, dst_ip6;__be16 udp_dport; +u16 tun_type;/* enum efx_encap_type */ nit: maybe the type of
tyn_typecan be enumefx_encap_type.
Quoted 7 lines
Yeah, it probably should. Looking at my git history I think the
initial reason was for struct-packing reasons (enums are int-sized at minimum, which is excessive for a field whose largest value is 3), but with therhash_headthat later appears between these two fields, using the narrower type doesn't actually avoid a 16-bit hole like it appears to here.
Will change in v3.
Thanks.
PATCH v2 5/6 sfc: add code to register and unregister encap matches
In reply to [email protected]From: Edward Cree <[email protected]>
Add a hashtable to detect duplicate and conflicting matches. If match
is not a duplicate, call MAE functions to add/remove it from OR table.
Calling code not added yet, so mark the new functions as unused.
---
Changed in v2: replace unsigned char ipv with bool ipv6, simplifying
code (suggested by Michal)
--- drivers/net/ethernet/sfc/tc.c | 163 ++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/tc.h | 11 +++ 2 files changed, 174 insertions(+)
drivers/net/ethernet/sfc/tc.c +163 -0
@@ -57,6 +57,12 @@ static s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efvreturn mport; } +static const struct rhashtable_params efx_tc_encap_match_ht_params = { + .key_len = offsetof(struct efx_tc_encap_match , linkage), + .key_offset =0 , + .head_offset = offsetof(struct efx_tc_encap_match , linkage), +}; +static const struct rhashtable_params efx_tc_match_action_ht_params = { .key_len =sizeof (unsigned long ), .key_offset = offsetof(struct efx_tc_flow_rule , cookie),
@@ -340,6 +346,144 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,return 0 ; } +__always_unused +static int efx_tc_flower_record_encap_match(struct efx_nic *efx, + struct efx_tc_match *match, + enum efx_encap_type type, + struct netlink_ext_ack *extack) +{ + struct efx_tc_encap_match *encap, *old; + bool ipv6; + int rc; + + /* We require that the socket-defining fields (IP addrs and UDP dest + * port) are present and exact-match. Other fields are currently not + * allowed. This meets what OVS will ask for, and means that we don't + * need to handle difficult checks for overlapping matches as could + * come up if we allowed masks or varying sets of match fields. + */ + if (match->mask.enc_dst_ip | match->mask.enc_src_ip) { + if (!IS_ALL_ONES(match->mask.enc_dst_ip)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress encap match is not exact on dst IP address"); + return -EOPNOTSUPP; + } + if (!IS_ALL_ONES(match->mask.enc_src_ip)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress encap match is not exact on src IP address"); + return -EOPNOTSUPP; + } +#ifdef CONFIG_IPV6 + if (!ipv6_addr_any(&match->mask.enc_dst_ip6) || + !ipv6_addr_any(&match->mask.enc_src_ip6)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress encap match on both IPv4 and IPv6, don't understand"); + return -EOPNOTSUPP; + } + } else { + ipv6 = true; + if (!efx_ipv6_addr_all_ones(&match->mask.enc_dst_ip6)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress encap match is not exact on dst IP address"); + return -EOPNOTSUPP; + } + if (!efx_ipv6_addr_all_ones(&match->mask.enc_src_ip6)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress encap match is not exact on src IP address"); + return -EOPNOTSUPP; + } +#endif + } + if (!IS_ALL_ONES(match->mask.enc_dport)) { + NL_SET_ERR_MSG_MOD(extack, "Egress encap match is not exact on dst UDP port"); + return -EOPNOTSUPP; + } + if (match->mask.enc_sport) { + NL_SET_ERR_MSG_MOD(extack, "Egress encap match on src UDP port not supported"); + return -EOPNOTSUPP; + } + if (match->mask.enc_ip_tos) { + NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP ToS not supported"); + return -EOPNOTSUPP; + } + if (match->mask.enc_ip_ttl) { + NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP TTL not supported"); + return -EOPNOTSUPP; + } + + rc = efx_mae_check_encap_match_caps(efx, ipv6, extack); + if (rc) { + NL_SET_ERR_MSG_FMT_MOD(extack, "MAE hw reports no support for IPv%d encap matches", + ipv6 ? 6 : 4); + return -EOPNOTSUPP; + } + + encap = kzalloc(sizeof(*encap), GFP_USER); + if (!encap) + return -ENOMEM; + encap->src_ip = match->value.enc_src_ip; + encap->dst_ip = match->value.enc_dst_ip; +#ifdef CONFIG_IPV6 + encap->src_ip6 = match->value.enc_src_ip6; + encap->dst_ip6 = match->value.enc_dst_ip6; +#endif + encap->udp_dport = match->value.enc_dport; + encap->tun_type = type; + old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_match_ht, + &encap->linkage, + efx_tc_encap_match_ht_params); + if (old) { + /* don't need our new entry */ + kfree(encap); + if (old->tun_type != type) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Egress encap match with conflicting tun_type %u != %u", + old->tun_type, type); + return -EEXIST; + } + if (!refcount_inc_not_zero(&old->ref)) + return -EAGAIN; + /* existing entry found */ + encap = old; + } else { + rc = efx_mae_register_encap_match(efx, encap); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to record egress encap match in HW"); + goto fail; + } + refcount_set(&encap->ref, 1); + } + match->encap = encap; + return 0; +fail: + rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage, + efx_tc_encap_match_ht_params); + kfree(encap); + return rc; +} + +__always_unused +static void efx_tc_flower_release_encap_match(struct efx_nic *efx, + struct efx_tc_encap_match *encap) +{ + int rc; + + if (!refcount_dec_and_test(&encap->ref)) + return; /* still in use */ + + rc = efx_mae_unregister_encap_match(efx, encap); + if (rc) + /* Display message but carry on and remove entry from our + * SW tables, because there's not much we can do about it. + */ + netif_err(efx, drv, efx->net_dev, + "Failed to release encap match %#x, rc %d\n", + encap->fw_id, rc); + rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage, + efx_tc_encap_match_ht_params); + kfree(encap); +} + /* For details of action order constraints refer to SF-123102-TC-1§12.6.1 */ enum efx_tc_action_order { EFX_TC_AO_VLAN_POP,
@@ -974,6 +1118,18 @@ void efx_fini_tc(struct efx_nic *efx) efx->tc->up = false; } +/* At teardown time, all TC filter rules (and thus all resources they created) +* should already have been removed. If we find any in our hashtables, make a +* cursory attempt to clean up the software side. +*/ +static void efx_tc_encap_match_free (void *ptr,void *__unused) +{ +struct efx_tc_encap_match *encap = ptr; + +WARN_ON (refcount_read (&encap->ref)); +kfree (encap); +} +int efx_init_struct_tc (struct efx_nic *efx) {int rc;
@@ -996,6 +1152,9 @@ int efx_init_struct_tc(struct efx_nic *efx) rc =efx_tc_init_counters (efx);if (rc <0 ) goto fail_counters; + rc =rhashtable_init (&efx->tc->encap_match_ht, &efx_tc_encap_match_ht_params); +if (rc <0 ) + goto fail_encap_match_ht; rc =rhashtable_init (&efx->tc->match_action_ht, &efx_tc_match_action_ht_params);if (rc <0 ) goto fail_match_action_ht;
@@ -1008,6 +1167,8 @@ int efx_init_struct_tc(struct efx_nic *efx) efx->extra_channel_type[EFX_EXTRA_CHANNEL_TC ] = &efx_tc_channel_type;return 0 ; fail_match_action_ht: +rhashtable_destroy (&efx->tc->encap_match_ht); +fail_encap_match_ht:efx_tc_destroy_counters (efx); fail_counters:mutex_destroy (&efx->tc->mutex);
@@ -1030,6 +1191,8 @@ void efx_fini_struct_tc(struct efx_nic *efx) MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);rhashtable_free_and_destroy (&efx->tc->match_action_ht, efx_tc_flow_free, efx); +rhashtable_free_and_destroy (&efx->tc->encap_match_ht, + efx_tc_encap_match_free,NULL );efx_tc_fini_counters (efx);mutex_unlock (&efx->tc->mutex);mutex_destroy (&efx->tc->mutex);
drivers/net/ethernet/sfc/tc.h +11 -0
@@ -18,6 +18,13 @@#define IS_ALL_ONES (v) (!(typeof (v))~(v)) +#ifdef CONFIG_IPV6 +static inline bool efx_ipv6_addr_all_ones (struct in6_addr *addr) +{ +return !memchr_inv (addr,0xff ,sizeof (*addr)); +} +#endif +struct efx_tc_action_set {u16 vlan_push:2 ;u16 vlan_pop:2 ;
@@ -70,7 +77,9 @@ struct efx_tc_encap_match {__be32 src_ip, dst_ip;struct in6_addr src_ip6, dst_ip6;__be16 udp_dport; +struct rhash_head linkage;u16 tun_type;/* enum efx_encap_type */ +refcount_t ref;u32 fw_id;/* index of this entry in firmware encap match table */ };
@@ -107,6 +116,7 @@ enum efx_tc_rule_prios {* @mutex: Used to serialise operations on TC hashtables * @counter_ht: Hashtable of TC counters (FW IDs and counter values) * @counter_id_ht: Hashtable mapping TC counter cookies to counters +* @encap_match_ht: Hashtable of TC encap matches * @match_action_ht: Hashtable of TC match-action rules * @reps_mport_id: MAE port allocated for representor RX * @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
@@ -130,6 +140,7 @@ struct efx_tc_state {struct mutex mutex;struct rhashtable counter_ht;struct rhashtable counter_id_ht; +struct rhashtable encap_match_ht;struct rhashtable match_action_ht;u32 reps_mport_id, reps_mport_vport_id;s32 reps_filter_uc, reps_filter_mc;
Jakub Kicinski
maintainerRe: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches
drivers/net/ethernet/sfc/tc.c static int efx_tc_flower_parse_match(struct efx_nic *efx, · line 357
Quoted 9 lines · On Thu, 23 Mar 2023 20:45:13 +0000 [email protected] wrote:
drivers/net/ethernet/sfc/tc.c +9
-0+__always_unused +static int efx_tc_flower_record_encap_match (struct efx_nic *efx, +struct efx_tc_match *match, +enum efx_encap_type type, +struct netlink_ext_ack *extack) +{ +struct efx_tc_encap_match *encap, *old; +bool ipv6; +int rc;
clang sayeth
drivers/net/ethernet/sfc/tc.c:414:43: warning: variable 'ipv6' is uninitialized when used here [-Wuninitialized]
rc = efx_mae_check_encap_match_caps(efx, ipv6, extack);
^~~~
drivers/net/ethernet/sfc/tc.c:356:11: note: initialize the variable 'ipv6' to silence this warning
bool ipv6;
^
= 0Re: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches
Quoted 13 lines · Jakub Kicinski
drivers/net/ethernet/sfc/tc.c static int efx_tc_flower_parse_match(struct efx_nic *efx, · line 357
Quoted 9 lines · On Thu, 23 Mar 2023 20:45:13 +0000 [email protected] wrote:
drivers/net/ethernet/sfc/tc.c +9
-0+__always_unused +static int efx_tc_flower_record_encap_match (struct efx_nic *efx, +struct efx_tc_match *match, +enum efx_encap_type type, +struct netlink_ext_ack *extack) +{ +struct efx_tc_encap_match *encap, *old; +bool ipv6; +int rc;clang sayeth
Quoted 7 lines
drivers/net/ethernet/sfc/tc.c:414:43: warning: variable 'ipv6' is uninitialized when used here [-Wuninitialized]rc = efx_mae_check_encap_match_caps(efx, ipv6, extack); ^~~~ drivers/net/ethernet/sfc/tc.c:356:11: note: initialize the variable 'ipv6' to silence this warning bool ipv6; ^ = 0
If CONFIG_IPV6 is unset it is never used, to is needs a __maybe_unused as well.
Martin
Edward Cree
maintainerRe: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches
Quoted 8 lines · Martin Habets
Quoted 4 lines · Jakub Kicinski
clang sayeth
drivers/net/ethernet/sfc/tc.c:414:43: warning: variable 'ipv6' is uninitialized when used here [-Wuninitialized]rc = efx_mae_check_encap_match_caps(efx, ipv6, extack);If
CONFIG_IPV6is unset it is never used, to is needs a__maybe_unusedas well.
efx_mae_check_encap_match_caps() uses it regardless of the CONFIG,
as does the extack setting just below it.
So it just needs initialising to false, will fix in v3. (No idea why gcc doesn't warn about it, not even on W=1.)
kernel test robot
build botRe: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches
In reply to [email protected]I love your patch! Perhaps something to improve:
Hi,
I love your patch! Perhaps something to improve:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/edward-cree-amd-com/sfc-document-TC-to-EF100-MAE-action-translation-concepts/20230324-044845 patch link: https://lore.kernel.org/r/57c4e599df3fff7bf678c1813445bd6016c6db79.1679603051.git.ecree.xilinx%40gmail.com patch subject: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches config: arm-randconfig-r025-20230322 (https://download.01.org/0day-ci/archive/20230325/[email protected]/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project 67409911353323ca5edf2049ef0df54132fa1ca7)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm cross compiling tool for clang build
# apt-get install binutils-arm-linux-gnueabi
# https://github.com/intel-lab-lkp/linux/commit/48db650a79ec4f4091360a2c1363d1cac6235707
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review edward-cree-amd-com/sfc-document-TC-to-EF100-MAE-action-translation-concepts/20230324-044845 git checkout 48db650a79ec4f4091360a2c1363d1cac6235707
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/net/ethernet/sfc/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Link: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> drivers/net/ethernet/sfc/tc.c:414:43: warning: variable 'ipv6' is uninitialized when used here [-Wuninitialized]
rc = efx_mae_check_encap_match_caps(efx, ipv6, extack);
^~~~
drivers/net/ethernet/sfc/tc.c:356:11: note: initialize the variable 'ipv6' to silence this warning
bool ipv6;
^
= 01 warning generated.
vim +/ipv6 +414 drivers/net/ethernet/sfc/tc.c
348
349 __always_unused
350 static int efx_tc_flower_record_encap_match(struct efx_nic *efx,
351 struct efx_tc_match *match,
352 enum efx_encap_type type,
353 struct netlink_ext_ack *extack)
354 {
355 struct efx_tc_encap_match *encap, *old;
356 bool ipv6;
357 int rc;
358
359 /* We require that the socket-defining fields (IP addrs and UDP dest
360 * port) are present and exact-match. Other fields are currently not
361 * allowed. This meets what OVS will ask for, and means that we don't
362 * need to handle difficult checks for overlapping matches as could
363 * come up if we allowed masks or varying sets of match fields.
364 */
365 if (match->mask.enc_dst_ip | match->mask.enc_src_ip) {
366 if (!IS_ALL_ONES(match->mask.enc_dst_ip)) {
367 NL_SET_ERR_MSG_MOD(extack,
368 "Egress encap match is not exact on dst IP address");
369 return -EOPNOTSUPP;
370 }
371 if (!IS_ALL_ONES(match->mask.enc_src_ip)) {
372 NL_SET_ERR_MSG_MOD(extack,
373 "Egress encap match is not exact on src IP address");
374 return -EOPNOTSUPP;
375 }
376 #ifdef CONFIG_IPV6
377 if (!ipv6_addr_any(&match->mask.enc_dst_ip6) ||
378 !ipv6_addr_any(&match->mask.enc_src_ip6)) {
379 NL_SET_ERR_MSG_MOD(extack,
380 "Egress encap match on both IPv4 and IPv6, don't understand");
381 return -EOPNOTSUPP;
382 }
383 } else {
384 ipv6 = true;
385 if (!efx_ipv6_addr_all_ones(&match->mask.enc_dst_ip6)) {
386 NL_SET_ERR_MSG_MOD(extack,
387 "Egress encap match is not exact on dst IP address");
388 return -EOPNOTSUPP;
389 }
390 if (!efx_ipv6_addr_all_ones(&match->mask.enc_src_ip6)) {
391 NL_SET_ERR_MSG_MOD(extack,
392 "Egress encap match is not exact on src IP address");
393 return -EOPNOTSUPP;
394 }
395 #endif
396 }
397 if (!IS_ALL_ONES(match->mask.enc_dport)) {
398 NL_SET_ERR_MSG_MOD(extack, "Egress encap match is not exact on dst UDP port");
399 return -EOPNOTSUPP;
400 }
401 if (match->mask.enc_sport) {
402 NL_SET_ERR_MSG_MOD(extack, "Egress encap match on src UDP port not supported");
403 return -EOPNOTSUPP;
404 }
405 if (match->mask.enc_ip_tos) {
406 NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP ToS not supported");
407 return -EOPNOTSUPP;
408 }
409 if (match->mask.enc_ip_ttl) {
410 NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP TTL not supported");
411 return -EOPNOTSUPP;
412 }
413
> 414 rc = efx_mae_check_encap_match_caps(efx, ipv6, extack); 415 if (rc) {
416 NL_SET_ERR_MSG_FMT_MOD(extack, "MAE hw reports no support for IPv%d encap matches",
417 ipv6 ? 6 : 4);
418 return -EOPNOTSUPP;
419 }
420
421 encap = kzalloc(sizeof(*encap), GFP_USER);
422 if (!encap)
423 return -ENOMEM;
424 encap->src_ip = match->value.enc_src_ip;
425 encap->dst_ip = match->value.enc_dst_ip;
426 #ifdef CONFIG_IPV6
427 encap->src_ip6 = match->value.enc_src_ip6;
428 encap->dst_ip6 = match->value.enc_dst_ip6;
429 #endif
430 encap->udp_dport = match->value.enc_dport;
431 encap->tun_type = type;
432 old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_match_ht,
433 &encap->linkage,
434 efx_tc_encap_match_ht_params);
435 if (old) {
436 /* don't need our new entry */
437 kfree(encap);
438 if (old->tun_type != type) {
439 NL_SET_ERR_MSG_FMT_MOD(extack,
440 "Egress encap match with conflicting tun_type %u != %u",
441 old->tun_type, type);
442 return -EEXIST;
443 }
444 if (!refcount_inc_not_zero(&old->ref))
445 return -EAGAIN;
446 /* existing entry found */
447 encap = old;
448 } else {
449 rc = efx_mae_register_encap_match(efx, encap);
450 if (rc) {
451 NL_SET_ERR_MSG_MOD(extack, "Failed to record egress encap match in HW");
452 goto fail;
453 }
454 refcount_set(&encap->ref, 1);
455 }
456 match->encap = encap;
457 return 0;
458 fail:
459 rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage,
460 efx_tc_encap_match_ht_params);
461 kfree(encap);
462 return rc;
463 }
464
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests
Re: [PATCH net-next v2 5/6] sfc: add code to register and unregister encap matches
In reply to [email protected]Quoted 10 lines · On Thu, Mar 23, 2023 at 08:45:13PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
Add a hashtable to detect duplicate and conflicting matches. If match
is not a duplicate, call MAE functions to add/remove it from OR table.
Calling code not added yet, so mark the new functions as unused.Signed-off-by Edward Cree <[email protected]>---
Changed in v2: replaceunsigned char ipvwithbool ipv6, simplifying
code (suggested by Michal)
Many bits have been spilt on a minor problem around initialising 'ipv6 [1][2]. But that aside, this looks good to me.
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/
PATCH v2 6/6 sfc: add offloading of 'foreign' TC (decap) rules
In reply to [email protected]From: Edward Cree <[email protected]>
A 'foreign' rule is one for which the net_dev is not the sfc netdevice
or any of its representors. The driver registers indirect flow blocks for tunnel netdevs so that it can offload decap rules. For example:
tc filter add dev vxlan0 parent ffff: protocol ipv4 flower \
enc_src_ip 10.1.0.2 enc_dst_ip 10.1.0.1 \
enc_key_id 1000 enc_dst_port 4789 \
action tunnel_key unset \
action mirred egress redirect dev $REPRESENTORWhen notified of a rule like this, register an encap match on the IP
and dport tuple (creating an Outer Rule table entry) and insert an MAE action rule to perform the decapsulation and deliver to the representee.
Moved efx_tc_delete_rule() below efx_tc_flower_release_encap_match() to
avoid the need for a forward declaration.
---
Changed in v2:
* in efx_tc_encap_type_name(), use a pr_warn_once to handle unknown values instead of buffer and snprintf complication.
* remove unnecessary clearing of save.count
* correct name of release_act label to release_acts
--- drivers/net/ethernet/sfc/mae.c | 25 ++- drivers/net/ethernet/sfc/mae.h | 3 + drivers/net/ethernet/sfc/tc.c | 354 +++++++++++++++++++++++++++++++-- drivers/net/ethernet/sfc/tc.h | 1 + 4 files changed, 366 insertions(+), 17 deletions(-)
drivers/net/ethernet/sfc/mae.c +23 -2
@@ -241,6 +241,7 @@ static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)if (outlen <sizeof (outbuf))return -EIO ; caps->match_field_count =MCDI_DWORD (outbuf,MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT ); + caps->encap_types =MCDI_DWORD (outbuf,MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED ); caps->action_prios =MCDI_DWORD (outbuf,MAE_GET_CAPS_OUT_ACTION_PRIOS );return 0 ; }
@@ -507,6 +508,25 @@ int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, }#undef CHECK +int efx_mae_check_encap_type_supported (struct efx_nic *efx,enum efx_encap_type typ) +{ +unsigned int bit; + +switch (typ &EFX_ENCAP_TYPES_MASK ) { +case EFX_ENCAP_TYPE_VXLAN : + bit =MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN ; +break ; +case EFX_ENCAP_TYPE_GENEVE : + bit =MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN ; +break ; +default : +return -EOPNOTSUPP ; + } +if (efx->tc->caps->encap_types &BIT (bit)) +return 0 ; +return -EOPNOTSUPP ; +} +int efx_mae_allocate_counter (struct efx_nic *efx,struct efx_tc_counter *cnt) {MCDI_DECLARE_BUF (outbuf,MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));
@@ -766,9 +786,10 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)size_t outlen;int rc; -MCDI_POPULATE_DWORD_2 (inbuf,MAE_ACTION_SET_ALLOC_IN_FLAGS , +MCDI_POPULATE_DWORD_3 (inbuf,MAE_ACTION_SET_ALLOC_IN_FLAGS ,MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH , act->vlan_push, -MAE_ACTION_SET_ALLOC_IN_VLAN_POP , act->vlan_pop); +MAE_ACTION_SET_ALLOC_IN_VLAN_POP , act->vlan_pop, +MAE_ACTION_SET_ALLOC_IN_DECAP , act->decap);MCDI_SET_DWORD (inbuf,MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID ,MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL );
drivers/net/ethernet/sfc/mae.h +3 -0
@@ -70,6 +70,7 @@ void efx_mae_counters_grant_credits(struct work_struct *work);struct mae_caps {u32 match_field_count; +u32 encap_types;u32 action_prios;u8 action_rule_fields[MAE_NUM_FIELDS ];u8 outer_rule_fields[MAE_NUM_FIELDS ];
@@ -82,6 +83,8 @@ int efx_mae_match_check_caps(struct efx_nic *efx, struct netlink_ext_ack *extack);int efx_mae_check_encap_match_caps (struct efx_nic *efx,bool ipv6,struct netlink_ext_ack *extack); +int efx_mae_check_encap_type_supported (struct efx_nic *efx, +enum efx_encap_type typ);int efx_mae_allocate_counter (struct efx_nic *efx,struct efx_tc_counter *cnt);int efx_mae_free_counter (struct efx_nic *efx,struct efx_tc_counter *cnt);
drivers/net/ethernet/sfc/tc.c +339 -15
416 lines not on this page · raw message
drivers/net/ethernet/sfc/tc.h +1 -0
@@ -28,6 +28,7 @@ static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr)struct efx_tc_action_set {u16 vlan_push:2 ;u16 vlan_pop:2 ; +u16 decap:1 ;u16 deliver:1 ;__be16 vlan_tci[2 ];/* TCIs for vlan_push */ __be16 vlan_proto[2 ];/* Ethertypes for vlan_push */
Re: [PATCH net-next v2 6/6] sfc: add offloading of 'foreign' TC (decap) rules
Quoted 12 lines · On Thu, Mar 23, 2023 at 08:45:14PM +0000, [email protected] wrote:
From: Edward Cree <[email protected]>
A 'foreign' rule is one for which the
net_devis not the sfc netdevice
or any of its representors. The driver registers indirect flow blocks for tunnel netdevs so that it can offload decap rules. For example:tc filter add dev vxlan0 parent ffff: protocol ipv4 flower \ enc_src_ip 10.1.0.2 enc_dst_ip 10.1.0.1 \ enc_key_id 1000 enc_dst_port 4789 \ action tunnel_key unset \ action mirred egress redirect dev $REPRESENTOR
Quoted 8 lines
When notified of a rule like this, register an encap match on the IP
and dport tuple (creating an Outer Rule table entry) and insert an MAE action rule to perform the decapsulation and deliver to the representee.Moved
efx_tc_delete_rule()belowefx_tc_flower_release_encap_match()to
avoid the need for a forward declaration.Signed-off-by Edward Cree <[email protected]>
Looks good to me.
...
drivers/net/ethernet/sfc/tc.c static bool efx_tc_flower_action_order_ok(const struct efx_tc_action_set *act, · line 766
Quoted 4 lines
drivers/net/ethernet/sfc/tc.c +4
-0+list_add_tail (&act->list, &rule->acts.list); + act =NULL ; +if (fa->id ==FLOW_ACTION_REDIRECT ) +break ;/* end of the line */
nit: 'act = NULL;' could go inside this if clause.
Quoted 8 lines
drivers/net/ethernet/sfc/tc.c +8
-0+/* Mirror, so continue on with saved act */ + act =kzalloc (sizeof (*act),GFP_USER ); +if (!act) { + rc = -ENOMEM ; + goto release; + } + *act = save; +break ;
...