-/*
- * Copyright (c) 2007-2016 Solarflare Communications Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
*
- * The views and conclusions contained in the software and documentation are
- * those of the authors and should not be interpreted as representing official
- * policies, either expressed or implied, of the FreeBSD Project.
+ * Copyright (c) 2007-2018 Solarflare Communications Inc.
+ * All rights reserved.
*/
#include "efx.h"
#include "efx_impl.h"
-#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
#if EFSYS_OPT_FILTER
ef10_filter_table_t *eftp;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
- enp->en_family == EFX_FAMILY_MEDFORD);
+ enp->en_family == EFX_FAMILY_MEDFORD ||
+ enp->en_family == EFX_FAMILY_MEDFORD2);
#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
+ EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
+ MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
+ EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
+ MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST));
EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST));
EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
__in efx_nic_t *enp)
{
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
- enp->en_family == EFX_FAMILY_MEDFORD);
+ enp->en_family == EFX_FAMILY_MEDFORD ||
+ enp->en_family == EFX_FAMILY_MEDFORD2);
if (enp->en_filter.ef_ef10_filter_table != NULL) {
EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
spec->efs_dmaq_id);
+
+#if EFSYS_OPT_RX_SCALE
if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
+ uint32_t rss_context;
+
+ if (spec->efs_rss_context == EFX_RSS_CONTEXT_DEFAULT)
+ rss_context = enp->en_rss_context;
+ else
+ rss_context = spec->efs_rss_context;
MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT,
- spec->efs_rss_context);
+ rss_context);
}
+#endif
+
MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE,
spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS :
memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP),
&spec->efs_loc_host.eo_byte[0],
MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
+
+ /*
+ * On Medford, filters for encapsulated packets match based on
+ * the ether type and IP protocol in the outer frame. In
+ * addition we need to fill in the VNI or VSID type field.
+ */
+ switch (spec->efs_encap_type) {
+ case EFX_TUNNEL_PROTOCOL_NONE:
+ break;
+ case EFX_TUNNEL_PROTOCOL_VXLAN:
+ case EFX_TUNNEL_PROTOCOL_GENEVE:
+ MCDI_IN_POPULATE_DWORD_1(req,
+ FILTER_OP_EXT_IN_VNI_OR_VSID,
+ FILTER_OP_EXT_IN_VNI_TYPE,
+ spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ?
+ MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN :
+ MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE);
+ break;
+ case EFX_TUNNEL_PROTOCOL_NVGRE:
+ MCDI_IN_POPULATE_DWORD_1(req,
+ FILTER_OP_EXT_IN_VNI_OR_VSID,
+ FILTER_OP_EXT_IN_VSID_TYPE,
+ MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE);
+ break;
+ default:
+ EFSYS_ASSERT(0);
+ rc = EINVAL;
+ goto fail2;
+ }
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
- goto fail2;
+ goto fail3;
}
if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
rc = EMSGSIZE;
- goto fail3;
+ goto fail4;
}
handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
return (0);
+fail4:
+ EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
return (B_FALSE);
if (left->efs_ip_proto != right->efs_ip_proto)
return (B_FALSE);
+ if (left->efs_encap_type != right->efs_encap_type)
+ return (B_FALSE);
return (B_TRUE);
efx_rc_t rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
- enp->en_family == EFX_FAMILY_MEDFORD);
+ enp->en_family == EFX_FAMILY_MEDFORD ||
+ enp->en_family == EFX_FAMILY_MEDFORD2);
for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
boolean_t locked = B_FALSE;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
- enp->en_family == EFX_FAMILY_MEDFORD);
-
-#if EFSYS_OPT_RX_SCALE
- spec->efs_rss_context = enp->en_rss_context;
-#endif
+ enp->en_family == EFX_FAMILY_MEDFORD ||
+ enp->en_family == EFX_FAMILY_MEDFORD2);
hash = ef10_filter_hash(spec);
boolean_t locked = B_FALSE;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
- enp->en_family == EFX_FAMILY_MEDFORD);
+ enp->en_family == EFX_FAMILY_MEDFORD ||
+ enp->en_family == EFX_FAMILY_MEDFORD2);
hash = ef10_filter_hash(spec);
size_t list_length;
uint32_t i;
efx_rc_t rc;
- uint32_t all_filter_flags =
+ efx_filter_match_flags_t all_filter_flags =
(EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
return (rc);
}
+typedef struct ef10_filter_encap_entry_s {
+ uint16_t ether_type;
+ efx_tunnel_protocol_t encap_type;
+ uint32_t inner_frame_match;
+} ef10_filter_encap_entry_t;
+
+#define EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match) \
+ { EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type, \
+ EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match }
+
+static ef10_filter_encap_entry_t ef10_filter_encap_list[] = {
+ EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST),
+
+ EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST),
+
+ EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST),
+ EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST),
+};
+
+#undef EF10_ENCAP_FILTER_ENTRY
+
+static __checkReturn efx_rc_t
+ef10_filter_insert_encap_filters(
+ __in efx_nic_t *enp,
+ __in boolean_t mulcst,
+ __in efx_filter_flags_t filter_flags)
+{
+ ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
+ uint32_t i;
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <=
+ EFX_ARRAY_SIZE(table->eft_encap_filter_indexes));
+
+ /*
+ * On Medford, full-featured firmware can identify packets as being
+ * tunnel encapsulated, even if no encapsulated packet offloads are in
+ * use. When packets are identified as such, ordinary filters are not
+ * applied, only ones specific to encapsulated packets. Hence we need to
+ * insert filters for encapsulated packets in order to receive them.
+ *
+ * Separate filters need to be inserted for each ether type,
+ * encapsulation type, and inner frame type (unicast or multicast). To
+ * keep things simple and reduce the number of filters needed, catch-all
+ * filters for all combinations of types are inserted, even if
+ * all_unicst or all_mulcst have not been set. (These catch-all filters
+ * may well, however, fail to insert on unprivileged functions.)
+ */
+ table->eft_encap_filter_count = 0;
+ for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) {
+ efx_filter_spec_t spec;
+ ef10_filter_encap_entry_t *encap_filter =
+ &ef10_filter_encap_list[i];
+
+ /*
+ * Skip multicast filters if we've not been asked for
+ * any multicast traffic.
+ */
+ if ((mulcst == B_FALSE) &&
+ (encap_filter->inner_frame_match ==
+ EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST))
+ continue;
+
+ efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+ filter_flags,
+ table->eft_default_rxq);
+ efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type);
+ rc = efx_filter_spec_set_encap_type(&spec,
+ encap_filter->encap_type,
+ encap_filter->inner_frame_match);
+ if (rc != 0)
+ goto fail1;
+
+ rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
+ &table->eft_encap_filter_indexes[
+ table->eft_encap_filter_count]);
+ if (rc != 0) {
+ if (rc != EACCES)
+ goto fail2;
+ } else {
+ table->eft_encap_filter_count++;
+ }
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
static void
ef10_filter_remove_old(
__in efx_nic_t *enp)
}
table->eft_mulcst_filter_count = 0;
+ for (i = 0; i < table->eft_encap_filter_count; i++) {
+ (void) ef10_filter_delete_internal(enp,
+ table->eft_encap_filter_indexes[i]);
+ }
+ table->eft_encap_filter_count = 0;
+
return (0);
}
ef10_filter_set_entry_auto_old(table,
table->eft_mulcst_filter_indexes[i]);
}
+ for (i = 0; i < table->eft_encap_filter_count; i++) {
+ ef10_filter_set_entry_auto_old(table,
+ table->eft_encap_filter_indexes[i]);
+ }
/*
* Insert or renew unicast filters.
}
}
+ if (encp->enc_tunnel_encapsulations_supported != 0) {
+ /* Try to insert filters for encapsulated packets. */
+ (void) ef10_filter_insert_encap_filters(enp,
+ mulcst || all_mulcst || brdcst,
+ filter_flags);
+ }
+
/* Remove old filters which were not renewed */
ef10_filter_remove_old(enp);
#endif /* EFSYS_OPT_FILTER */
-#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
+#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */