On Wed, Jun 29, 2022 at 9:32 AM David Marchand <[email protected]>
wrote:

> As described in the bugzilla below, cpu_has_isa code may be compiled
> with some AVX512 instructions in it, because cpu.c is built as part of
> the libopenvswitchavx512.
> This is a problem when this function (supposed to probe for AVX512
> instructions availability) is invoked from generic OVS code, on older
> CPUs that don't support them.
>
> For the same reason, dpcls_subtable_avx512_gather_probe,
> dp_netdev_input_outer_avx512_probe, mfex_avx512_probe and
> mfex_avx512_vbmi_probe are potential runtime bombs and can't either be
> built as part of libopenvswitchavx512.
>
> Move cpu.c to be part of the "normal" libopenvswitch.
> And move other helpers in generic OVS code.
>
> Note:
> - dpcls_subtable_avx512_gather_probe is split in two, because it also
>   needs to do its own magic,
> - while moving those helpers, prefer direct calls to cpu_has_isa and
>   avoid cast to intermediate integer variables when a simple boolean
>   is enough,
>
> Fixes: 352b6c7116cd ("dpif-lookup: add avx512 gather implementation.")
> Fixes: abb807e27dd4 ("dpif-netdev: Add command to switch dpif
> implementation.")
> Fixes: 250ceddcc2d0 ("dpif-netdev/mfex: Add AVX512 based optimized
> miniflow extract")
> Fixes: b366fa2f4947 ("dpif-netdev: Call cpuid for x86 isa availability.")
> Reported-at: https://bugzilla.redhat.com/2100393
> Reported-by: Ales Musil <[email protected]>
> Co-authored-by: Ales Musil <[email protected]>
> Signed-off-by: Ales Musil <[email protected]>
> Signed-off-by: David Marchand <[email protected]>
> Acked-by: Sunil Pai G <[email protected]>
> ---
> Changes since v1:
> - restored Ales as co-author,
> - added more Fixes: lines: backports go back to 2.14 and are not that
> difficult
>   to do, but I can help if needed,
> - fixed one indent issue,
>
> ---
>  lib/automake.mk                        |  4 +--
>  lib/dpif-netdev-avx512.c               | 14 ---------
>  lib/dpif-netdev-extract-avx512.c       | 43 --------------------------
>  lib/dpif-netdev-lookup-avx512-gather.c | 12 ++-----
>  lib/dpif-netdev-lookup.c               | 16 ++++++++++
>  lib/dpif-netdev-lookup.h               |  3 +-
>  lib/dpif-netdev-private-dpif.c         | 14 +++++++++
>  lib/dpif-netdev-private-dpif.h         |  5 +--
>  lib/dpif-netdev-private-extract.c      | 41 ++++++++++++++++++++++++
>  lib/dpif-netdev-private-extract.h      |  4 +--
>  10 files changed, 79 insertions(+), 77 deletions(-)
>
> diff --git a/lib/automake.mk b/lib/automake.mk
> index cb50578eb7..3b9e775d4e 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -36,8 +36,6 @@ lib_libopenvswitchavx512_la_CFLAGS = \
>         -fPIC \
>         $(AM_CFLAGS)
>  lib_libopenvswitchavx512_la_SOURCES = \
> -       lib/cpu.c \
> -       lib/cpu.h \
>         lib/dpif-netdev-avx512.c
>  if HAVE_AVX512BW
>  lib_libopenvswitchavx512_la_CFLAGS += \
> @@ -92,6 +90,8 @@ lib_libopenvswitch_la_SOURCES = \
>         lib/conntrack.h \
>         lib/coverage.c \
>         lib/coverage.h \
> +       lib/cpu.c \
> +       lib/cpu.h \
>         lib/crc32c.c \
>         lib/crc32c.h \
>         lib/csum.c \
> diff --git a/lib/dpif-netdev-avx512.c b/lib/dpif-netdev-avx512.c
> index 11d9a00052..82a4138184 100644
> --- a/lib/dpif-netdev-avx512.c
> +++ b/lib/dpif-netdev-avx512.c
> @@ -20,7 +20,6 @@
>
>  #include <config.h>
>
> -#include "cpu.h"
>  #include "dpif-netdev.h"
>  #include "dpif-netdev-perf.h"
>  #include "dpif-netdev-private.h"
> @@ -59,19 +58,6 @@ struct dpif_userdata {
>          struct pkt_flow_meta pkt_meta[NETDEV_MAX_BURST];
>  };
>
> -int32_t
> -dp_netdev_input_outer_avx512_probe(void)
> -{
> -    bool avx512f_available = cpu_has_isa(OVS_CPU_ISA_X86_AVX512F);
> -    bool bmi2_available = cpu_has_isa(OVS_CPU_ISA_X86_BMI2);
> -
> -    if (!avx512f_available || !bmi2_available) {
> -        return -ENOTSUP;
> -    }
> -
> -    return 0;
> -}
> -
>  int32_t
>  dp_netdev_input_outer_avx512(struct dp_netdev_pmd_thread *pmd,
>                               struct dp_packet_batch *packets,
> diff --git a/lib/dpif-netdev-extract-avx512.c
> b/lib/dpif-netdev-extract-avx512.c
> index f1919befd1..5029730292 100644
> --- a/lib/dpif-netdev-extract-avx512.c
> +++ b/lib/dpif-netdev-extract-avx512.c
> @@ -42,7 +42,6 @@
>  #include <stdint.h>
>  #include <string.h>
>
> -#include "cpu.h"
>  #include "flow.h"
>
>  #include "dpif-netdev-private-dpcls.h"
> @@ -690,47 +689,5 @@ DECLARE_MFEX_FUNC(ip_udp, PROFILE_ETH_IPV4_UDP)
>  DECLARE_MFEX_FUNC(ip_tcp, PROFILE_ETH_IPV4_TCP)
>  DECLARE_MFEX_FUNC(dot1q_ip_udp, PROFILE_ETH_VLAN_IPV4_UDP)
>  DECLARE_MFEX_FUNC(dot1q_ip_tcp, PROFILE_ETH_VLAN_IPV4_TCP)
> -
> -
> -static int32_t
> -avx512_isa_probe(uint32_t needs_vbmi)
> -{
> -    static enum ovs_cpu_isa isa_required[] = {
> -        OVS_CPU_ISA_X86_AVX512F,
> -        OVS_CPU_ISA_X86_AVX512BW,
> -        OVS_CPU_ISA_X86_BMI2,
> -    };
> -
> -    int32_t ret = 0;
> -    for (uint32_t i = 0; i < ARRAY_SIZE(isa_required); i++) {
> -        if (!cpu_has_isa(isa_required[i])) {
> -            ret = -ENOTSUP;
> -        }
> -    }
> -
> -    if (needs_vbmi) {
> -        if (!cpu_has_isa(OVS_CPU_ISA_X86_AVX512VBMI)) {
> -            ret = -ENOTSUP;
> -        }
> -    }
> -
> -    return ret;
> -}
> -
> -/* Probe functions to check ISA requirements. */
> -int32_t
> -mfex_avx512_probe(void)
> -{
> -    const uint32_t needs_vbmi = 0;
> -    return avx512_isa_probe(needs_vbmi);
> -}
> -
> -int32_t
> -mfex_avx512_vbmi_probe(void)
> -{
> -    const uint32_t needs_vbmi = 1;
> -    return avx512_isa_probe(needs_vbmi);
> -}
> -
>  #endif /* __CHECKER__ */
>  #endif /* __x86_64__ */
> diff --git a/lib/dpif-netdev-lookup-avx512-gather.c
> b/lib/dpif-netdev-lookup-avx512-gather.c
> index 1e86be2072..7d3d81151f 100644
> --- a/lib/dpif-netdev-lookup-avx512-gather.c
> +++ b/lib/dpif-netdev-lookup-avx512-gather.c
> @@ -23,7 +23,6 @@
>  #include "dpif-netdev-lookup.h"
>
>  #include "cmap.h"
> -#include "cpu.h"
>  #include "flow.h"
>  #include "pvector.h"
>  #include "openvswitch/vlog.h"
> @@ -413,18 +412,11 @@ dpcls_avx512_gather_mf_any(struct dpcls_subtable
> *subtable, uint32_t keys_map,
>  }
>
>  dpcls_subtable_lookup_func
> -dpcls_subtable_avx512_gather_probe(uint32_t u0_bits, uint32_t u1_bits)
> +dpcls_subtable_avx512_gather_probe__(uint32_t u0_bits, uint32_t u1_bits,
> +                                     bool use_vpop)
>  {
>      dpcls_subtable_lookup_func f = NULL;
>
> -    int avx512f_available = cpu_has_isa(OVS_CPU_ISA_X86_AVX512F);
> -    int bmi2_available = cpu_has_isa(OVS_CPU_ISA_X86_BMI2);
> -    if (!avx512f_available || !bmi2_available) {
> -        return NULL;
> -    }
> -
> -    int use_vpop = cpu_has_isa(OVS_CPU_ISA_X86_VPOPCNTDQ);
> -
>      CHECK_LOOKUP_FUNCTION(9, 4, use_vpop);
>      CHECK_LOOKUP_FUNCTION(9, 1, use_vpop);
>      CHECK_LOOKUP_FUNCTION(5, 3, use_vpop);
> diff --git a/lib/dpif-netdev-lookup.c b/lib/dpif-netdev-lookup.c
> index 34ce12695f..6bcfb8ba81 100644
> --- a/lib/dpif-netdev-lookup.c
> +++ b/lib/dpif-netdev-lookup.c
> @@ -18,10 +18,26 @@
>  #include <errno.h>
>  #include "dpif-netdev-lookup.h"
>
> +#include "cpu.h"
>  #include "openvswitch/vlog.h"
>
>  VLOG_DEFINE_THIS_MODULE(dpif_netdev_lookup);
>
> +#if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && HAVE_AVX512BW \
> +     && __SSE4_2__)
> +static dpcls_subtable_lookup_func
> +dpcls_subtable_avx512_gather_probe(uint32_t u0_bits, uint32_t u1_bits)
> +{
> +    if (!cpu_has_isa(OVS_CPU_ISA_X86_AVX512F)
> +        || !cpu_has_isa(OVS_CPU_ISA_X86_BMI2)) {
> +        return NULL;
> +    }
> +
> +    return dpcls_subtable_avx512_gather_probe__(u0_bits, u1_bits,
> +        cpu_has_isa(OVS_CPU_ISA_X86_VPOPCNTDQ));
> +}
> +#endif
> +
>  /* Actual list of implementations goes here */
>  static struct dpcls_subtable_lookup_info_t subtable_lookups[] = {
>      /* The autovalidator implementation will not be used by default, it
> must
> diff --git a/lib/dpif-netdev-lookup.h b/lib/dpif-netdev-lookup.h
> index 7f124a46e9..ac6d973173 100644
> --- a/lib/dpif-netdev-lookup.h
> +++ b/lib/dpif-netdev-lookup.h
> @@ -45,7 +45,8 @@ dpcls_subtable_generic_probe(uint32_t u0_bit_count,
> uint32_t u1_bit_count);
>
>  /* Probe function for AVX-512 gather implementation */
>  dpcls_subtable_lookup_func
> -dpcls_subtable_avx512_gather_probe(uint32_t u0_bit_cnt, uint32_t
> u1_bit_cnt);
> +dpcls_subtable_avx512_gather_probe__(uint32_t u0_bit_cnt, uint32_t
> u1_bit_cnt,
> +                                     bool use_vpop);
>
>
>  /* Subtable registration and iteration helpers */
> diff --git a/lib/dpif-netdev-private-dpif.c
> b/lib/dpif-netdev-private-dpif.c
> index ffd6ff907a..9027129617 100644
> --- a/lib/dpif-netdev-private-dpif.c
> +++ b/lib/dpif-netdev-private-dpif.c
> @@ -22,6 +22,7 @@
>  #include <errno.h>
>  #include <string.h>
>
> +#include "cpu.h"
>  #include "openvswitch/dynamic-string.h"
>  #include "openvswitch/vlog.h"
>  #include "util.h"
> @@ -35,6 +36,19 @@ enum dpif_netdev_impl_info_idx {
>      DPIF_NETDEV_IMPL_AVX512
>  };
>
> +#if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && __SSE4_2__)
> +static int32_t
> +dp_netdev_input_outer_avx512_probe(void)
> +{
> +    if (!cpu_has_isa(OVS_CPU_ISA_X86_AVX512F)
> +        || !cpu_has_isa(OVS_CPU_ISA_X86_BMI2)) {
> +        return -ENOTSUP;
> +    }
> +
> +    return 0;
> +}
> +#endif
> +
>  /* Actual list of implementations goes here. */
>  static struct dpif_netdev_impl_info_t dpif_impls[] = {
>      /* The default scalar C code implementation. */
> diff --git a/lib/dpif-netdev-private-dpif.h
> b/lib/dpif-netdev-private-dpif.h
> index 0da639c55a..3e38630f53 100644
> --- a/lib/dpif-netdev-private-dpif.h
> +++ b/lib/dpif-netdev-private-dpif.h
> @@ -67,10 +67,7 @@ dp_netdev_input(struct dp_netdev_pmd_thread *pmd,
>                  struct dp_packet_batch *packets,
>                  odp_port_t in_port);
>
> -/* AVX512 enabled DPIF implementation and probe functions. */
> -int32_t
> -dp_netdev_input_outer_avx512_probe(void);
> -
> +/* AVX512 enabled DPIF implementation function. */
>  int32_t
>  dp_netdev_input_outer_avx512(struct dp_netdev_pmd_thread *pmd,
>                               struct dp_packet_batch *packets,
> diff --git a/lib/dpif-netdev-private-extract.c
> b/lib/dpif-netdev-private-extract.c
> index a70ab6a4d6..c0c14221b7 100644
> --- a/lib/dpif-netdev-private-extract.c
> +++ b/lib/dpif-netdev-private-extract.c
> @@ -19,6 +19,7 @@
>  #include <stdint.h>
>  #include <string.h>
>
> +#include "cpu.h"
>  #include "dp-packet.h"
>  #include "dpif-netdev-private-dpcls.h"
>  #include "dpif-netdev-private-extract.h"
> @@ -33,6 +34,46 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev_extract);
>  /* Variable to hold the default MFEX implementation. */
>  static ATOMIC(miniflow_extract_func) default_mfex_func;
>
> +#if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && HAVE_AVX512BW \
> +     && __SSE4_2__)
> +static int32_t
> +avx512_isa_probe(bool needs_vbmi)
> +{
> +    static enum ovs_cpu_isa isa_required[] = {
> +        OVS_CPU_ISA_X86_AVX512F,
> +        OVS_CPU_ISA_X86_AVX512BW,
> +        OVS_CPU_ISA_X86_BMI2,
> +    };
> +
> +    for (uint32_t i = 0; i < ARRAY_SIZE(isa_required); i++) {
> +        if (!cpu_has_isa(isa_required[i])) {
> +            return -ENOTSUP;
> +        }
> +    }
> +
> +    if (needs_vbmi && !cpu_has_isa(OVS_CPU_ISA_X86_AVX512VBMI)) {
> +        return -ENOTSUP;
> +    }
> +
> +    return 0;
> +}
> +
> +/* Probe functions to check ISA requirements. */
> +static int32_t
> +mfex_avx512_probe(void)
> +{
> +    return avx512_isa_probe(false);
> +}
> +
> +#if HAVE_AVX512VBMI
> +static int32_t
> +mfex_avx512_vbmi_probe(void)
> +{
> +    return avx512_isa_probe(true);
> +}
> +#endif
> +#endif
> +
>  /* Implementations of available extract options and
>   * the implementations are always in order of preference.
>   */
> diff --git a/lib/dpif-netdev-private-extract.h
> b/lib/dpif-netdev-private-extract.h
> index b2cd6779d7..2a3a91744e 100644
> --- a/lib/dpif-netdev-private-extract.h
> +++ b/lib/dpif-netdev-private-extract.h
> @@ -191,10 +191,8 @@ mfex_study_traffic(struct dp_packet_batch *packets,
>  int
>  mfex_set_study_pkt_cnt(uint32_t pkt_cmp_count, const char *name);
>
> -/* AVX512 MFEX Probe and Implementations functions. */
> +/* AVX512 MFEX Implementation functions. */
>  #ifdef __x86_64__
> -int32_t mfex_avx512_probe(void);
> -int32_t mfex_avx512_vbmi_probe(void);
>
>  #define DECLARE_AVX512_MFEX_PROTOTYPE(name)
>    \
>      uint32_t
>   \
> --
> 2.36.1
>
>
Thank you!

Acked-by: Ales Musil <[email protected] <[email protected]>>

-- 

Ales Musil

Senior Software Engineer - OVN Core

Red Hat EMEA <https://www.redhat.com>

[email protected]    IM: amusil
<https://red.ht/sig>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to