sfc: add Layer 2 matches to ef100 TC offload
authorEdward Cree <ecree.xilinx@gmail.com>
Thu, 3 Nov 2022 15:27:28 +0000 (15:27 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 5 Nov 2022 02:54:23 +0000 (19:54 -0700)
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>
drivers/net/ethernet/sfc/mae.c
drivers/net/ethernet/sfc/mcdi.h
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc.h

index cd01495..6dfcf87 100644 (file)
@@ -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;
 }
 
index 1f18e9d..883a4db 100644 (file)
@@ -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)                    \
index b21a961..b469a12 100644 (file)
@@ -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;
 }
 
index 4373c32..272efba 100644 (file)
@@ -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 {