On Thu, Aug 21, 2025 at 11:24 AM David Marchand <david.march...@redhat.com>
wrote:

> Protect concurrent access when calling netdev_get_features()
> or netdev_get_speed() for BSD netdevs.
>
> Signed-off-by: David Marchand <david.march...@redhat.com>
> ---
>  lib/netdev-bsd.c | 111 +++++++++++++++++++++++++++++------------------
>  1 file changed, 68 insertions(+), 43 deletions(-)
>
> diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
> index c7cd59376a..7718c30a04 100644
> --- a/lib/netdev-bsd.c
> +++ b/lib/netdev-bsd.c
> @@ -92,6 +92,11 @@ struct netdev_bsd {
>      struct eth_addr etheraddr;
>      int mtu;
>      int carrier;
> +    int get_features_error;
> +
> +    enum netdev_features current;
> +    enum netdev_features advertised;
> +    enum netdev_features supported;
>
>      int tap_fd;         /* TAP character device, if any, otherwise -1. */
>
> @@ -1099,28 +1104,22 @@ netdev_bsd_parse_media(int media)
>      return supported;
>  }
>
> -/*
> - * Stores the features supported by 'netdev' into each of '*current',
> - * '*advertised', '*supported', and '*peer' that are non-null.  Each
> value is a
> - * bitmap of "enum ofp_port_features" bits, in host byte order.  Returns
> 0 if
> - * successful, otherwise a positive errno value.  On failure, all of the
> - * passed-in values are set to 0.
> - */
> -static int
> -netdev_bsd_get_features(const struct netdev *netdev,
> -                        enum netdev_features *current, uint32_t
> *advertised,
> -                        enum netdev_features *supported, uint32_t *peer)
> +static void
> +netdev_bsd_read_features(struct netdev_bsd *netdev)
>  {
>      struct ifmediareq ifmr;
>      int *media_list;
> -    int i;
>      int error;
> -
> +    int i;
>
>      /* XXX Look into SIOCGIFCAP instead of SIOCGIFMEDIA */
>
>      memset(&ifmr, 0, sizeof(ifmr));
> -    ovs_strlcpy(ifmr.ifm_name, netdev_get_name(netdev), sizeof
> ifmr.ifm_name);
> +    ovs_strlcpy(ifmr.ifm_name, netdev_get_name(&netdev->up),
> +                sizeof ifmr.ifm_name);
> +
> +    media_list = xcalloc(ifmr.ifm_count, sizeof(int));
> +    ifmr.ifm_ulist = media_list;
>
>      /* We make two SIOCGIFMEDIA ioctl calls.  The first to determine the
>       * number of supported modes, and a second with a buffer to retrieve
> @@ -1128,16 +1127,13 @@ netdev_bsd_get_features(const struct netdev
> *netdev,
>      error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
>      if (error) {
>          VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
> -                    netdev_get_name(netdev), ovs_strerror(error));
> -        return error;
> +                    netdev_get_name(&netdev->up), ovs_strerror(error));
> +        goto cleanup;
>      }
>
> -    media_list = xcalloc(ifmr.ifm_count, sizeof(int));
> -    ifmr.ifm_ulist = media_list;
> -
>      if (IFM_TYPE(ifmr.ifm_current) != IFM_ETHER) {
>          VLOG_DBG_RL(&rl, "%s: doesn't appear to be ethernet",
> -                    netdev_get_name(netdev));
> +                    netdev_get_name(&netdev->up));
>          error = EINVAL;
>          goto cleanup;
>      }
> @@ -1145,53 +1141,82 @@ netdev_bsd_get_features(const struct netdev
> *netdev,
>      error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
>      if (error) {
>          VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
> -                    netdev_get_name(netdev), ovs_strerror(error));
> +                    netdev_get_name(&netdev->up), ovs_strerror(error));
>          goto cleanup;
>      }
>
>      /* Current settings. */
> -    *current = netdev_bsd_parse_media(ifmr.ifm_active);
> -    if (!*current) {
> -        *current = NETDEV_F_OTHER;
> +    netdev->current = netdev_bsd_parse_media(ifmr.ifm_active);
> +    if (!netdev->current) {
> +        netdev->current = NETDEV_F_OTHER;
>      }
>
>      /* Advertised features. */
> -    *advertised = netdev_bsd_parse_media(ifmr.ifm_current);
> +    netdev->advertised = netdev_bsd_parse_media(ifmr.ifm_current);
>
>      /* Supported features. */
> -    *supported = 0;
> +    netdev->supported = 0;
>      for (i = 0; i < ifmr.ifm_count; i++) {
> -        *supported |= netdev_bsd_parse_media(ifmr.ifm_ulist[i]);
> +        netdev->supported |= netdev_bsd_parse_media(ifmr.ifm_ulist[i]);
>      }
>
> -    /* Peer advertisements. */
> -    *peer = 0;                  /* XXX */
> -
>      error = 0;
> +
>  cleanup:
>      free(media_list);
> +    netdev->get_features_error = error;
>

Why not just return this value?



> +}
> +
> +/*
> + * Stores the features supported by 'netdev' into each of '*current',
> + * '*advertised', '*supported', and '*peer' that are non-null.  Each
> value is a
> + * bitmap of "enum ofp_port_features" bits, in host byte order.  Returns
> 0 if
> + * successful, otherwise a positive errno value.  On failure, all of the
> + * passed-in values are set to 0.
> + */
> +static int
> +netdev_bsd_get_features(const struct netdev *netdev_,
> +                        enum netdev_features *current, uint32_t
> *advertised,
> +                        enum netdev_features *supported, uint32_t *peer)
> +{
> +    struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
> +    int error;
> +
> +    ovs_mutex_lock(&netdev->mutex);
> +    netdev_bsd_read_features(netdev);
> +    if (!netdev->get_features_error) {
> +        *current = netdev->current;
> +        *advertised = netdev->advertised;
> +        *supported = netdev->supported;
> +        *peer = 0;
> +    }
> +    error = netdev->get_features_error;
> +    ovs_mutex_unlock(&netdev->mutex);
> +
>      return error;
>  }
>
>  static int
> -netdev_bsd_get_speed(const struct netdev *netdev, uint32_t *current,
> +netdev_bsd_get_speed(const struct netdev *netdev_, uint32_t *current,
>                       uint32_t *max)
>  {
> -    enum netdev_features f_current, f_supported, f_advertised, f_peer;
> +    struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
>      int error;
>
> -    error = netdev_bsd_get_features(netdev, &f_current, &f_advertised,
> -                                    &f_supported, &f_peer);
> -    if (error) {
> -        return error;
> -    }
> -
> -    *current = MIN(UINT32_MAX,
> -                   netdev_features_to_bps(f_current, 0) / 1000000ULL);
> -    *max = MIN(UINT32_MAX,
> -               netdev_features_to_bps(f_supported, 0) / 1000000ULL);
> +    ovs_mutex_lock(&netdev->mutex);
> +    netdev_bsd_read_features(netdev);
> +    if (!netdev->get_features_error) {
> +        *current = MIN(UINT32_MAX,
> +                       netdev_features_to_bps(netdev->current, 0)
> +                       / 1000000ULL);
> +        *max = MIN(UINT32_MAX,
> +                   netdev_features_to_bps(netdev->supported, 0)
> +                   / 1000000ULL);
> +    }
> +    error = netdev->get_features_error;
> +    ovs_mutex_unlock(&netdev->mutex);
>
> -    return 0;
> +    return error;
>  }
>
>  /*
> --
> 2.50.1
>
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to