[libvirt PATCH v5 1/3] Set VF MAC and VLAN ID in two different operations

Daniel P. Berrangé berrange at redhat.com
Thu Nov 18 16:22:33 UTC 2021


On Thu, Nov 18, 2021 at 11:43:24AM +0300, Dmitrii Shcherbakov wrote:
> This has a benefit of being able to handle error codes for those
> operations separately which is useful when drivers allow setting a MAC
> address but do not allow setting a VLAN (which is the case with some
> SmartNIC DPUs).
> 
> Signed-off-by: Dmitrii Shcherbakov <dmitrii.shcherbakov at canonical.com>
> ---
>  src/libvirt_private.syms |   7 ++
>  src/util/virnetdev.c     | 189 ++++++++++++++++++++-------------
>  src/util/virnetdevpriv.h |  44 ++++++++
>  tests/virnetdevtest.c    | 222 ++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 389 insertions(+), 73 deletions(-)
>  create mode 100644 src/util/virnetdevpriv.h
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index a7bc50a4d1..e681e69d77 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2849,6 +2849,13 @@ virNetDevOpenvswitchSetTimeout;
>  virNetDevOpenvswitchUpdateVlan;
>  
>  
> +#util/virnetdevpriv.h
> +virNetDevSendVfSetLinkRequest;
> +virNetDevSetVfConfig;
> +virNetDevSetVfMac;
> +virNetDevSetVfVlan;
> +
> +
>  # util/virnetdevtap.h
>  virNetDevTapAttachBridge;
>  virNetDevTapCreate;
> diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
> index 58f7360a0f..dfd4506c21 100644
> --- a/src/util/virnetdev.c
> +++ b/src/util/virnetdev.c
> @@ -19,7 +19,9 @@
>  #include <config.h>
>  #include <math.h>
>  
> -#include "virnetdev.h"
> +#define LIBVIRT_VIRNETDEVPRIV_H_ALLOW
> +
> +#include "virnetdevpriv.h"
>  #include "viralloc.h"
>  #include "virnetlink.h"
>  #include "virmacaddr.h"
> @@ -1527,16 +1529,12 @@ static struct nla_policy ifla_vfstats_policy[IFLA_VF_STATS_MAX+1] = {
>      [IFLA_VF_STATS_MULTICAST]   = { .type = NLA_U64 },
>  };
>  
> -
> -static int
> -virNetDevSetVfConfig(const char *ifname, int vf,
> -                     const virMacAddr *macaddr, int vlanid,
> -                     bool *allowRetry)
> +int
> +virNetDevSendVfSetLinkRequest(const char *ifname, int vfInfoType,
> +                              const void *payload, const size_t payloadLen)
>  {
> -    int rc = -1;
> -    char macstr[VIR_MAC_STRING_BUFLEN];
>      g_autofree struct nlmsghdr *resp = NULL;
> -    struct nlmsgerr *err;
> +    struct nlmsgerr *err = NULL;
>      unsigned int recvbuflen = 0;
>      struct nl_msg *nl_msg;
>      struct nlattr *vfinfolist, *vfinfo;
> @@ -1544,9 +1542,11 @@ virNetDevSetVfConfig(const char *ifname, int vf,
>          .ifi_family = AF_UNSPEC,
>          .ifi_index  = -1,
>      };
> +    int rc = 0;
>  
> -    if (!macaddr && vlanid < 0)
> +    if (payload == NULL || payloadLen == 0) {
>          return -1;
> +    }
>  
>      nl_msg = virNetlinkMsgNew(RTM_SETLINK, NLM_F_REQUEST);
>  
> @@ -1564,30 +1564,8 @@ virNetDevSetVfConfig(const char *ifname, int vf,
>      if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO)))
>          goto buffer_too_small;
>  
> -    if (macaddr) {
> -        struct ifla_vf_mac ifla_vf_mac = {
> -             .vf = vf,
> -             .mac = { 0, },
> -        };
> -
> -        virMacAddrGetRaw(macaddr, ifla_vf_mac.mac);
> -
> -        if (nla_put(nl_msg, IFLA_VF_MAC, sizeof(ifla_vf_mac),
> -                    &ifla_vf_mac) < 0)
> -            goto buffer_too_small;
> -    }
> -
> -    if (vlanid >= 0) {
> -        struct ifla_vf_vlan ifla_vf_vlan = {
> -             .vf = vf,
> -             .vlan = vlanid,
> -             .qos = 0,
> -        };
> -
> -        if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof(ifla_vf_vlan),
> -                    &ifla_vf_vlan) < 0)
> -            goto buffer_too_small;
> -    }
> +    if (nla_put(nl_msg, vfInfoType, payloadLen, payload) < 0)
> +        goto buffer_too_small;
>  
>      nla_nest_end(nl_msg, vfinfo);
>      nla_nest_end(nl_msg, vfinfolist);
> @@ -1600,48 +1578,20 @@ virNetDevSetVfConfig(const char *ifname, int vf,
>          goto malformed_resp;
>  
>      switch (resp->nlmsg_type) {
> -    case NLMSG_ERROR:
> -        err = (struct nlmsgerr *)NLMSG_DATA(resp);
> -        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
> +        case NLMSG_ERROR:
> +            err = (struct nlmsgerr *)NLMSG_DATA(resp);
> +            if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
> +                goto malformed_resp;
> +            rc = err->error;
> +            break;
> +        case NLMSG_DONE:
> +            rc = 0;
> +            break;
> +        default:
>              goto malformed_resp;
> -
> -        /* if allowRetry is true and the error was EINVAL, then
> -         * silently return a failure so the caller can retry with a
> -         * different MAC address
> -         */
> -        if (err->error == -EINVAL && *allowRetry &&
> -            macaddr && !virMacAddrCmp(macaddr, &zeroMAC)) {
> -            goto cleanup;
> -        } else if (err->error) {
> -            /* other errors are permanent */
> -            virReportSystemError(-err->error,
> -                                 _("Cannot set interface MAC/vlanid to %s/%d "
> -                                   "for ifname %s vf %d"),
> -                                 (macaddr
> -                                  ? virMacAddrFormat(macaddr, macstr)
> -                                  : "(unchanged)"),
> -                                 vlanid,
> -                                 ifname ? ifname : "(unspecified)",
> -                                 vf);
> -            *allowRetry = false; /* no use retrying */
> -            goto cleanup;
> -        }
> -        break;
> -
> -    case NLMSG_DONE:
> -        break;
> -
> -    default:
> -        goto malformed_resp;
>      }
>  
> -    rc = 0;
>   cleanup:
> -    VIR_DEBUG("RTM_SETLINK %s vf %d MAC=%s vlanid=%d - %s",
> -              ifname, vf,
> -              macaddr ? virMacAddrFormat(macaddr, macstr) : "(unchanged)",
> -              vlanid, rc < 0 ? "Fail" : "Success");
> -
>      nlmsg_free(nl_msg);
>      return rc;
>  
> @@ -1656,6 +1606,101 @@ virNetDevSetVfConfig(const char *ifname, int vf,
>      goto cleanup;
>  }
>  
> +int
> +virNetDevSetVfVlan(const char *ifname, int vf, int vlanid)
> +{
> +    int rc = 0;
> +    int requestError = 0;
> +
> +    struct ifla_vf_vlan ifla_vf_vlan = {
> +         .vf = vf,
> +         .vlan = vlanid,
> +         .qos = 0,
> +    };
> +
> +    /* VLAN ids 0 and 4095 are reserved per 802.1Q but are valid values. */
> +    if ((vlanid < 0 || vlanid > 4095)) {
> +        return -ERANGE;
> +    }
> +
> +    requestError = virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_VLAN,
> +                                                 &ifla_vf_vlan, sizeof(ifla_vf_vlan));
> +
> +    if (requestError) {
> +        virReportSystemError(-requestError,
> +                             _("Cannot set interface vlanid to %d "
> +                               "for ifname %s vf %d"),
> +                             vlanid, ifname ? ifname : "(unspecified)", vf);
> +        rc = requestError;
> +    }
> +    VIR_DEBUG("RTM_SETLINK %s vf %d vlanid=%d - %s",
> +              ifname, vf,
> +              vlanid, rc < 0 ? "Fail" : "Success");
> +    return rc;
> +}
> +
> +int
> +virNetDevSetVfMac(const char *ifname, int vf,
> +                  const virMacAddr *macaddr,
> +                  bool *allowRetry)
> +{
> +    int rc = 0;
> +    int requestError = 0;
> +    char macstr[VIR_MAC_STRING_BUFLEN];
> +
> +    struct ifla_vf_mac ifla_vf_mac = {
> +         .vf = vf,
> +         .mac = { 0, },
> +    };
> +
> +    if (macaddr == NULL || allowRetry == NULL)
> +        return -EINVAL;
> +
> +    virMacAddrGetRaw(macaddr, ifla_vf_mac.mac);
> +
> +    requestError = virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_MAC,
> +                                                 &ifla_vf_mac, sizeof(ifla_vf_mac));
> +    /* if allowRetry is true and the error was EINVAL, then
> +     * silently return a failure so the caller can retry with a
> +     * different MAC address. */
> +    if (requestError == -EINVAL && *allowRetry && !virMacAddrCmp(macaddr, &zeroMAC)) {
> +        rc = requestError;
> +    } else if (requestError) {
> +        /* other errors are permanent */
> +        virReportSystemError(-requestError,
> +                             _("Cannot set interface MAC to %s "
> +                               "for ifname %s vf %d"),
> +                             (macaddr
> +                              ? virMacAddrFormat(macaddr, macstr)
> +                              : "(unchanged)"),
> +                             ifname ? ifname : "(unspecified)",
> +                             vf);
> +        *allowRetry = false; /* no use retrying */
> +        rc = requestError;
> +    } else {
> +        rc = 0;
> +    }
> +    VIR_DEBUG("RTM_SETLINK %s vf %d MAC=%s - %s",
> +              ifname, vf,
> +              macaddr ? virMacAddrFormat(macaddr, macstr) : "(unchanged)",
> +              rc < 0 ? "Fail" : "Success");
> +    return rc;
> +}
> +
> +int
> +virNetDevSetVfConfig(const char *ifname, int vf,
> +                     const virMacAddr *macaddr, int vlanid,
> +                     bool *allowRetry)
> +{
> +    int rc = 0;
> +    if ((rc = virNetDevSetVfMac(ifname, vf, macaddr, allowRetry)) < 0) {
> +        return rc;
> +    } else if ((rc = virNetDevSetVfVlan(ifname, vf, vlanid)) < 0) {
> +        return rc;
> +    }

Minor point I would get rid of the 'else' here, to make it obvious that
in the "success" case, we're intending to be making both of these method
calls.

    if ((rc = virNetDevSetVfMac(ifname, vf, macaddr, allowRetry)) < 0)
        return rc;
    if ((rc = virNetDevSetVfVlan(ifname, vf, vlanid)) < 0)
        return rc;

Or alternatively compress them


    if ((rc = virNetDevSetVfMac(ifname, vf, macaddr, allowRetry)) < 0 ||
        (rc = virNetDevSetVfVlan(ifname, vf, vlanid)) < 0)
        return rc;



> +    return rc;
> +}
> +


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the libvir-list mailing list