sfc: add functions to insert encap matches into the MAE
authorEdward Cree <ecree.xilinx@gmail.com>
Mon, 27 Mar 2023 10:36:06 +0000 (11:36 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 Mar 2023 08:06:08 +0000 (09:06 +0100)
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 <ecree.xilinx@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/mae.c
drivers/net/ethernet/sfc/mae.h
drivers/net/ethernet/sfc/tc.h

index 2290a63..92f1383 100644 (file)
@@ -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)
 {
index 2ccbc62..79d315a 100644 (file)
@@ -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);
index c148567..fff7396 100644 (file)
@@ -70,6 +70,7 @@ struct efx_tc_encap_match {
        __be32 src_ip, dst_ip;
        struct in6_addr src_ip6, dst_ip6;
        __be16 udp_dport;
+       enum efx_encap_type tun_type;
        u32 fw_id; /* index of this entry in firmware encap match table */
 };