[libvirt] [v4 PATCH] add 802.1Qbh handling for port-profiles based on Stefan's previous patches

Dave Allan dallan at redhat.com
Tue May 25 02:55:52 UTC 2010


On Mon, May 24, 2010 at 05:22:15PM -0700, Scott Feldman wrote:
> From: Scott Feldman <scofeldm at cisco.com>
> 
> This patch builds on the work recently posted by Stefan Berger.  It builds
> on top of Stefan's three posted patches:
> 
>         [PATCH v9] vepa: parsing for 802.1Qb{g|h} XML
>         [RFC][PATCH 1/3] vepa+vsi: Introduce dependency on libnl
>         [PATCH v3] Add host UUID (to libvirt capabilities)
> 
> Stefan's RFC patches 2/3 and 3/3 are incorporated into my patch.
> 
> Changes from v3 to v4:
>   - move from Stafan's 802.1Qb{g|h} XML v8 to v9
>   - move hostuuid and vf index calcs to inside doPortProfileOp8021Qbh

I don't have the latest if_link.h on my system, so I had to make the
changes in the attached patch to get v4 to build and pass make
syntax-check; nothing major.  The biggest thing is that getPhysfn is
only called when IFLA_VF_PORT_MAX is defined, so I moved the entire
function into that #ifdef and removed the internal #ifdef; otherwise
the compiler complains about the unused static function.

Dave


> Changes from v2 to v3:
>   - remove debug fprintfs
>   - use virGetHostUUID (thanks Stefan!)
>   - fix compile issue when latest if_link.h isn't available
>   - change poll timeout to 10s, at 1/8 intervals
>      - if polling times out, log msg and return -ETIMEDOUT
> 
> Changes from v1 to v2:
>   - Add Stefan's code for getPortProfileStatus
>   - Poll for up to 2 secs for port-profile status, at 1/8 sec intervals:
>      - if status indicates error, abort openMacvtapTap
>      - if status indicates success, exit polling
>      - if status is "in-progress" after 2 secs of polling, exit
>        polling loop silently, without error
> 
> My patch finishes out the 802.1Qbh parts, which Stefan had mostly complete.
> I've tested using the recent kernel updates for VF_PORT netlink msgs and
> enic for Cisco's 10G Ethernet NIC.  I tested many VMs, each with several
> direct interfaces, each configured with a port-profile per the XML.  VM-to-VM,
> and VM-to-external work as expected.  VM-to-VM on same host (using same NIC)
> works same as VM-to-VM where VMs are on diff hosts.  I'm able to change
> settings on the port-profile while the VM is running to change the virtual
> port behaviour.  For example, adjusting a QoS setting like rate limit.  All
> VMs with interfaces using that port-profile immediatly see the effect of the
> change to the port-profile.
> 
> I don't have a SR-IOV device to test so source dev is a non-SR-IOV device,
> but most of the code paths include support for specifing the source dev and
> VF index.  We'll need to complete this by discovering the PF given the VF
> linkdev.  Once we have the PF, we'll also have the VF index.  All this info-
> mation is available from sysfs.
> 
> Signed-off-by: Scott Feldman <scofeldm at cisco.com>
> ---
>  configure.ac           |   16 +
>  src/qemu/qemu_conf.c   |    2 
>  src/qemu/qemu_driver.c |    4 
>  src/util/macvtap.c     |  778 +++++++++++++++++++++++++++++++++++++++++++++++-
>  src/util/macvtap.h     |    1 
>  5 files changed, 785 insertions(+), 16 deletions(-)
> 
> 
> diff --git a/configure.ac b/configure.ac
> index 36ba703..885b0ae 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2005,13 +2005,26 @@ if test "$with_macvtap" != "no" ; then
>  fi
>  AM_CONDITIONAL([WITH_MACVTAP], [test "$with_macvtap" = "yes"])
>  
> +AC_TRY_COMPILE([ #include <sys/socket.h>
> +                 #include <linux/rtnetlink.h> ],
> +                 [ int x = IFLA_PORT_MAX; ],
> +                 [ with_virtualport=yes ],
> +                 [ with_virtualport=no ])
> +if test "$with_virtualport" = "yes"; then
> +    val=1
> +else
> +    val=0
> +fi
> +AC_DEFINE_UNQUOTED([WITH_VIRTUALPORT], $val, [whether vsi vepa support is enabled])
> +AM_CONDITIONAL([WITH_VIRTUALPORT], [test "$with_virtualport" = "yes"])
> +
>  
>  dnl netlink library
>  
>  LIBNL_CFLAGS=""
>  LIBNL_LIBS=""
>  
> -if test "$with_macvtap" = "yes"; then
> +if test "$with_macvtap" = "yes" || "$with_virtualport" = "yes"; then
>      PKG_CHECK_MODULES([LIBNL], [libnl-1 >= $LIBNL_REQUIRED], [
>      ], [
>          AC_MSG_ERROR([libnl >= $LIBNL_REQUIRED is required for macvtap support])
> @@ -2084,6 +2097,7 @@ AC_MSG_NOTICE([ Network: $with_network])
>  AC_MSG_NOTICE([Libvirtd: $with_libvirtd])
>  AC_MSG_NOTICE([   netcf: $with_netcf])
>  AC_MSG_NOTICE([ macvtap: $with_macvtap])
> +AC_MSG_NOTICE([virtport: $with_virtualport])
>  AC_MSG_NOTICE([])
>  AC_MSG_NOTICE([Storage Drivers])
>  AC_MSG_NOTICE([])
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index 111fa6e..95d4c1a 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -1505,7 +1505,7 @@ qemudPhysIfaceConnect(virConnectPtr conn,
>              if (err) {
>                  close(rc);
>                  rc = -1;
> -                delMacvtap(net->ifname,
> +                delMacvtap(net->ifname, net->data.direct.linkdev,
>                             &net->data.direct.virtPortProfile);
>              }
>          }
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index f02bf3b..f1a0d0e 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -3679,7 +3679,7 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
>      for (i = 0; i < def->nnets; i++) {
>          virDomainNetDefPtr net = def->nets[i];
>          if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
> -            delMacvtap(net->ifname,
> +            delMacvtap(net->ifname, net->data.direct.linkdev,
>                         &net->data.direct.virtPortProfile);
>      }
>  #endif
> @@ -8369,7 +8369,7 @@ qemudDomainDetachNetDevice(struct qemud_driver *driver,
>  
>  #if WITH_MACVTAP
>      if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
> -        delMacvtap(detach->ifname,
> +        delMacvtap(detach->ifname, detach->data.direct.linkdev,
>                     &detach->data.direct.virtPortProfile);
>  #endif
>  
> diff --git a/src/util/macvtap.c b/src/util/macvtap.c
> index 5cbd02b..d5a08d9 100644
> --- a/src/util/macvtap.c
> +++ b/src/util/macvtap.c
> @@ -27,7 +27,7 @@
>  
>  #include <config.h>
>  
> -#if WITH_MACVTAP
> +#if WITH_MACVTAP || WITH_VIRTUALPORT
>  
>  # include <stdio.h>
>  # include <errno.h>
> @@ -41,6 +41,8 @@
>  # include <linux/rtnetlink.h>
>  # include <linux/if_tun.h>
>  
> +# include <netlink/msg.h>
> +
>  # include "util.h"
>  # include "memory.h"
>  # include "logging.h"
> @@ -48,6 +50,7 @@
>  # include "interface.h"
>  # include "conf/domain_conf.h"
>  # include "virterror_internal.h"
> +# include "uuid.h"
>  
>  # define VIR_FROM_THIS VIR_FROM_NET
>  
> @@ -58,15 +61,23 @@
>  # define MACVTAP_NAME_PREFIX	"macvtap"
>  # define MACVTAP_NAME_PATTERN	"macvtap%d"
>  
> +# define MICROSEC_PER_SEC       (1000 * 1000)
> +
>  
>  static int associatePortProfileId(const char *macvtap_ifname,
> +                                  const char *linkdev,
>                                    const virVirtualPortProfileDefPtr virtPort,
> -                                  int vf,
>                                    const unsigned char *vmuuid);
>  
>  static int disassociatePortProfileId(const char *macvtap_ifname,
> +                                     const char *linkdev,
>                                       const virVirtualPortProfileDefPtr virtPort);
>  
> +enum virVirtualPortOp {
> +    ASSOCIATE = 0x1,
> +    DISASSOCIATE = 0x2,
> +};
> +
>  
>  static int nlOpen(void)
>  {
> @@ -159,6 +170,156 @@ err_exit:
>  }
>  
>  
> +# ifdef IFLA_VF_PORT_MAX
> +
> +/**
> + * nlCommWaitSuccess:
> + *
> + * @nlmsg: pointer to netlink message
> + * @nl_grousp: the netlink multicast groups to send to
> + * @respbuf: pointer to pointer where response buffer will be allocated
> + * @respbuflen: pointer to integer holding the size of the response buffer
> + *      on return of the function.
> + * @to_usecs: timeout in microseconds to wait for a success message
> + *            to be returned
> + *
> + * Send the given message to the netlink multicast group and receive
> + * responses. Skip responses indicating an error and keep on receiving
> + * responses until a success response is returned.
> + * Returns 0 on success, -1 on error. In case of error, no response
> + * buffer will be returned.
> + */
> +static int
> +nlCommWaitSuccess(struct nlmsghdr *nlmsg, int nl_groups,
> +                  char **respbuf, int *respbuflen, long to_usecs)
> +{
> +    int rc = 0;
> +    struct sockaddr_nl nladdr = {
> +            .nl_family = AF_NETLINK,
> +            .nl_pid    = getpid(),
> +            .nl_groups = nl_groups,
> +    };
> +    int rcvChunkSize = 1024; // expecting less than that
> +    int rcvoffset = 0;
> +    ssize_t nbytes;
> +    int n;
> +    struct timeval tv = {
> +        .tv_sec  = to_usecs / MICROSEC_PER_SEC,
> +        .tv_usec = to_usecs % MICROSEC_PER_SEC,
> +    };
> +    fd_set rfds;
> +    bool gotvalid = false;
> +    int fd = nlOpen();
> +    static uint32_t seq = 0x1234;
> +    uint32_t myseq = seq++;
> +    uint32_t mypid = getpid();
> +
> +    if (fd < 0)
> +        return -1;
> +
> +    nlmsg->nlmsg_pid = mypid;
> +    nlmsg->nlmsg_seq = myseq;
> +    nlmsg->nlmsg_flags |= NLM_F_ACK;
> +
> +    nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0,
> +                    (struct sockaddr *)&nladdr, sizeof(nladdr));
> +    if (nbytes < 0) {
> +        virReportSystemError(errno,
> +                             "%s", _("cannot send to netlink socket"));
> +        rc = -1;
> +        goto err_exit;
> +    }
> +
> +    while (!gotvalid) {
> +        rcvoffset = 0;
> +        while (1) {
> +            socklen_t addrlen = sizeof(nladdr);
> +
> +            if (VIR_REALLOC_N(*respbuf, rcvoffset+rcvChunkSize) < 0) {
> +                virReportOOMError();
> +                rc = -1;
> +                goto err_exit;
> +            }
> +
> +            FD_ZERO(&rfds);
> +            FD_SET(fd, &rfds);
> +
> +            n = select(fd + 1, &rfds, NULL, NULL, &tv);
> +            if (n == 0) {
> +                rc = -1;
> +                goto err_exit;
> +            }
> +
> +            nbytes = recvfrom(fd, &((*respbuf)[rcvoffset]), rcvChunkSize, 0,
> +                              (struct sockaddr *)&nladdr, &addrlen);
> +            if (nbytes < 0) {
> +                if (errno == EAGAIN || errno == EINTR)
> +                    continue;
> +                virReportSystemError(errno, "%s",
> +                                     _("error receiving from netlink socket"));
> +                rc = -1;
> +                goto err_exit;
> +            }
> +            rcvoffset += nbytes;
> +            break;
> +        }
> +        *respbuflen = rcvoffset;
> +
> +        /* check message for error */
> +        if (*respbuflen > NLMSG_LENGTH(0) && *respbuf != NULL) {
> +            struct nlmsghdr *resp = (struct nlmsghdr *)*respbuf;
> +            struct nlmsgerr *err;
> +
> +            if (resp->nlmsg_pid != mypid ||
> +                resp->nlmsg_seq != myseq)
> +                continue;
> +
> +            /* skip reflected message */
> +            if (resp->nlmsg_type & 0x10)
> +                continue;
> +
> +            switch (resp->nlmsg_type) {
> +               case NLMSG_ERROR:
> +                  err = (struct nlmsgerr *)NLMSG_DATA(resp);
> +                  if (resp->nlmsg_len >= NLMSG_LENGTH(sizeof(*err))) {
> +                      if (-err->error != EOPNOTSUPP) {
> +                          /* assuming error msg from daemon */
> +                          gotvalid = true;
> +                          break;
> +                      }
> +                  }
> +                  /* whatever this is, skip it */
> +                  VIR_FREE(*respbuf);
> +                  *respbuf = NULL;
> +                  *respbuflen = 0;
> +                  break;
> +
> +               case NLMSG_DONE:
> +                  gotvalid = true;
> +                  break;
> +
> +               default:
> +                  VIR_FREE(*respbuf);
> +                  *respbuf = NULL;
> +                  *respbuflen = 0;
> +                  break;
> +            }
> +        }
> +    }
> +
> +err_exit:
> +    if (rc == -1) {
> +        VIR_FREE(*respbuf);
> +        *respbuf = NULL;
> +        *respbuflen = 0;
> +    }
> +
> +    nlClose(fd);
> +    return rc;
> +}
> +
> +#endif
> +
>  static struct rtattr *
>  rtattrCreate(char *buffer, int bufsize, int type,
>               const void *data, int datalen)
> @@ -204,6 +365,8 @@ nlAppend(struct nlmsghdr *nlm, int totlen, const void *data, int datalen)
>  }
>  
>  
> +# if WITH_MACVTAP
> +
>  static int
>  link_add(const char *type,
>           const unsigned char *macaddress, int macaddrsize,
> @@ -655,8 +818,8 @@ create_name:
>      }
>  
>      if (associatePortProfileId(cr_ifname,
> +                               linkdev,
>                                 virtPortProfile,
> -                               -1,
>                                 vmuuid) != 0) {
>          rc = -1;
>          goto link_del_exit;
> @@ -689,6 +852,7 @@ create_name:
>  
>  disassociate_exit:
>      disassociatePortProfileId(cr_ifname,
> +                              linkdev,
>                                virtPortProfile);
>  
>  link_del_exit:
> @@ -701,6 +865,7 @@ link_del_exit:
>  /**
>   * delMacvtap:
>   * @ifname : The name of the macvtap interface
> + * @linkdev: The interface name of the NIC to connect to the external bridge
>   * @virtPortProfile: pointer to object holding the virtual port profile data
>   *
>   * Delete an interface given its name. Disassociate
> @@ -709,24 +874,603 @@ link_del_exit:
>   */
>  void
>  delMacvtap(const char *ifname,
> +           const char *linkdev,
>             virVirtualPortProfileDefPtr virtPortProfile)
>  {
>      if (ifname) {
>          disassociatePortProfileId(ifname,
> +                                  linkdev,
>                                    virtPortProfile);
>          link_del(ifname);
>      }
>  }
>  
> -#endif
> +# endif
> +
> +
> +# ifdef IFLA_PORT_MAX
> +
> +static struct nla_policy ifla_policy[IFLA_MAX + 1] =
> +{
> +  [IFLA_VF_PORTS] = { .type = NLA_NESTED },
> +};
> +
> +static struct nla_policy ifla_vf_ports_policy[IFLA_VF_PORT_MAX + 1] =
> +{
> +  [IFLA_VF_PORT] = { .type = NLA_NESTED },
> +};
> +
> +static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
> +{
> +  [IFLA_PORT_RESPONSE]      = { .type = NLA_U16 },
> +};
> +
> +
> +static int
> +link_dump(int ifindex, struct nlattr **tb, char **recvbuf)
> +{
> +    int rc = 0;
> +    char nlmsgbuf[256] = { 0, };
> +    struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
> +    struct nlmsgerr *err;
> +    struct ifinfomsg i = {
> +        .ifi_family = AF_UNSPEC,
> +        .ifi_index  = ifindex
> +    };
> +    int recvbuflen;
> +
> +    *recvbuf = NULL;
> +
> +    nlInit(nlm, NLM_F_REQUEST, RTM_GETLINK);
> +
> +    if (!nlAppend(nlm, sizeof(nlmsgbuf), &i, sizeof(i)))
> +        goto buffer_too_small;
> +
> +    if (nlComm(nlm, recvbuf, &recvbuflen) < 0)
> +        return -1;
> +
> +    if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL)
> +        goto malformed_resp;
>  
> +    resp = (struct nlmsghdr *)*recvbuf;
> +
> +    switch (resp->nlmsg_type) {
> +    case NLMSG_ERROR:
> +        err = (struct nlmsgerr *)NLMSG_DATA(resp);
> +        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
> +            goto malformed_resp;
> +
> +        switch (-err->error) {
> +        case 0:
> +        break;
> +
> +        default:
> +            virReportSystemError(-err->error,
> +                                 _("error dumping %d interface"),
> +                                 ifindex);
> +            rc = -1;
> +        }
> +    break;
> +
> +    case GENL_ID_CTRL:
> +    case NLMSG_DONE:
> +        if (nlmsg_parse(resp, sizeof(struct ifinfomsg),
> +                        tb, IFLA_MAX, ifla_policy)) {
> +            goto malformed_resp;
> +        }
> +    break;
> +
> +    default:
> +        goto malformed_resp;
> +    }
> +
> +    if (rc != 0)
> +        VIR_FREE(*recvbuf);
> +
> +    return rc;
> +
> +malformed_resp:
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("malformed netlink response message"));
> +    VIR_FREE(*recvbuf);
> +    return -1;
> +
> +buffer_too_small:
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("internal buffer is too small"));
> +    return -1;
> +}
> +
> +
> +static int
> +getPortProfileStatus(struct nlattr **tb, int32_t vf, uint16_t *status)
> +{
> +    int rc = 1;
> +    const char *msg = NULL;
> +    struct nlattr *tb2[IFLA_VF_PORT_MAX + 1],
> +                  *tb3[IFLA_PORT_MAX+1];
> +
> +    if (vf == PORT_SELF_VF) {
> +        if (tb[IFLA_PORT_SELF]) {
> +            if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb[IFLA_PORT_SELF],
> +                                 ifla_port_policy)) {
> +                msg = _("error parsing nested IFLA_VF_PORT part");
> +                goto err_exit;
> +            }
> +        }
> +    } else {
> +        if (tb[IFLA_VF_PORTS]) {
> +            if (nla_parse_nested(tb2, IFLA_VF_PORT_MAX, tb[IFLA_VF_PORTS],
> +                                 ifla_vf_ports_policy)) {
> +                msg = _("error parsing nested IFLA_VF_PORTS part");
> +                goto err_exit;
> +            }
> +            if (tb2[IFLA_VF_PORT]) {
> +                if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb2[IFLA_VF_PORT],
> +                                     ifla_port_policy)) {
> +                    msg = _("error parsing nested IFLA_VF_PORT part");
> +                    goto err_exit;
> +                }
> +            }
> +        }
> +    }
> +
> +    if (tb3[IFLA_PORT_RESPONSE]) {
> +        *status = *(uint16_t *)RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
> +         rc = 0;
> +    } else {
> +         msg = _("no IFLA_PORT_RESPONSE found in netlink message");
> +         goto err_exit;
> +    }
> +
> +err_exit:
> +    if (msg)
> +        macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
> +
> +    return rc;
> +}
> +
> +
> +static int
> +doPortProfileOpSetLink(bool multicast,
> +                       int ifindex,
> +                       const char *profileId,
> +                       struct ifla_port_vsi *portVsi,
> +                       const unsigned char *instanceId,
> +                       const unsigned char *hostUUID,
> +                       int32_t vf,
> +                       uint8_t op)
> +{
> +    int rc = 0;
> +    char nlmsgbuf[256];
> +    struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
> +    struct nlmsgerr *err;
> +    char rtattbuf[64];
> +    struct rtattr *rta, *vfports, *vfport;
> +    struct ifinfomsg ifinfo = {
> +        .ifi_family = AF_UNSPEC,
> +        .ifi_index  = ifindex,
> +    };
> +    char *recvbuf = NULL;
> +    int recvbuflen = 0;
> +
> +    memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));
> +
> +    nlInit(nlm, NLM_F_REQUEST, RTM_SETLINK);
> +
> +    if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
> +        goto buffer_too_small;
> +
> +    if (vf == PORT_SELF_VF) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_SELF, NULL, 0);
> +    } else {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORTS, NULL, 0);
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!(vfports = nlAppend(nlm, sizeof(nlmsgbuf),
> +                                 rtattbuf, rta->rta_len)))
> +            goto buffer_too_small;
> +
> +        /* beging nesting vfports */
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORT, NULL, 0);
> +    }
> +
> +    if (!rta)
> +        goto buffer_too_small;
> +
> +    if (!(vfport = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
> +        goto buffer_too_small;
> +
> +    if (profileId) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_PROFILE,
> +                           profileId, strlen(profileId) + 1);
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +            goto buffer_too_small;
> +    }
> +
> +    if (portVsi) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VSI_TYPE,
> +                           portVsi, sizeof(*portVsi));
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +            goto buffer_too_small;
> +    }
> +
> +    if (instanceId) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_INSTANCE_UUID,
> +                           instanceId, VIR_UUID_BUFLEN);
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +            goto buffer_too_small;
> +    }
> +
> +    if (hostUUID) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_HOST_UUID,
> +                           hostUUID, VIR_UUID_BUFLEN);
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +            goto buffer_too_small;
> +    }
> +
> +    if (vf != PORT_SELF_VF) {
> +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VF,
> +                           &vf, sizeof(vf));
> +        if (!rta)
> +            goto buffer_too_small;
> +
> +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +            goto buffer_too_small;
> +    }
> +
> +    rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_REQUEST,
> +                       &op, sizeof(op));
> +    if (!rta)
> +        goto buffer_too_small;
> +
> +    if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> +        goto buffer_too_small;
> +
> +    /* end nesting of vport */
> +    vfport->rta_len  = (char *)nlm + nlm->nlmsg_len - (char *)vfport;
> +
> +    if (vf != PORT_SELF_VF) {
> +        /* end nesting of vfports */
> +        vfports->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfports;
> +    }
> +
> +    if (!multicast) {
> +        if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
> +            return -1;
> +    } else {
> +        if (nlCommWaitSuccess(nlm, RTMGRP_LINK, &recvbuf, &recvbuflen,
> +                              5 * MICROSEC_PER_SEC) < 0)
> +            return -1;
> +    }
> +
> +    if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
> +        goto malformed_resp;
> +
> +    resp = (struct nlmsghdr *)recvbuf;
> +
> +    switch (resp->nlmsg_type) {
> +    case NLMSG_ERROR:
> +        err = (struct nlmsgerr *)NLMSG_DATA(resp);
> +        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
> +            goto malformed_resp;
> +
> +        switch (-err->error) {
> +        case 0:
> +        break;
> +
> +        default:
> +            virReportSystemError(-err->error,
> +                _("error during virtual port configuration of ifindex %d"),
> +                ifindex);
> +            rc = -1;
> +        }
> +    break;
> +
> +    case NLMSG_DONE:
> +    break;
> +
> +    default:
> +        goto malformed_resp;
> +    }
> +
> +    VIR_FREE(recvbuf);
> +
> +    return rc;
> +
> +malformed_resp:
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("malformed netlink response message"));
> +    VIR_FREE(recvbuf);
> +    return -1;
> +
> +buffer_too_small:
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("internal buffer is too small"));
> +    return -1;
> +}
> +
> +
> +static int
> +doPortProfileOpCommon(bool multicast,
> +                      int ifindex,
> +                      const char *profileId,
> +                      struct ifla_port_vsi *portVsi,
> +                      const unsigned char *instanceId,
> +                      const unsigned char *hostUUID,
> +                      int32_t vf,
> +                      uint8_t op)
> +{
> +    int rc;
> +    char *recvbuf = NULL;
> +    struct nlattr *tb[IFLA_MAX + 1];
> +    int repeats = 80;
> +    uint16_t status = 0;
> +
> +    rc = doPortProfileOpSetLink(multicast,
> +                                ifindex,
> +                                profileId,
> +                                portVsi,
> +                                instanceId,
> +                                hostUUID,
> +                                vf,
> +                                op);
> +
> +    if (rc != 0) {
> +        macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                     _("sending of PortProfileRequest failed.\n"));
> +        return rc;
> +    }
> +
> +    if (!multicast) {
> +        while (--repeats) {
> +            rc = link_dump(ifindex, tb, &recvbuf);
> +            if (rc)
> +                goto err_exit;
> +            rc = getPortProfileStatus(tb, vf, &status);
> +            if (rc == 0) {
> +                if (status == PORT_PROFILE_RESPONSE_SUCCESS ||
> +                    status == PORT_VDP_RESPONSE_SUCCESS) {
> +                    break;
> +                } else if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
> +                    // keep trying...
> +                } else {
> +                    virReportSystemError(EINVAL,
> +                        _("error %d during port-profile setlink on ifindex %d"),
> +                        status, ifindex);
> +                    rc = 1;
> +                    break;
> +                }
> +            }
> +            usleep(125000);
> +
> +            VIR_FREE(recvbuf);
> +        }
> +    }
> +
> +    if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
> +        macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                     _("port-profile setlink timed out"));
> +        rc = -ETIMEDOUT;
> +    }
> +
> +err_exit:
> +    VIR_FREE(recvbuf);
> +
> +    return rc;
> +}
> +
> +# endif /* IFLA_PORT_MAX */
> +
> +static int
> +doPortProfileOp8021Qbg(const char *ifname,
> +                       const virVirtualPortProfileDefPtr virtPort,
> +                       enum virVirtualPortOp virtPortOp)
> +{
> +    int rc;
> +
> +# ifndef IFLA_VF_PORT_MAX
> +
> +    (void)ifname;
> +    (void)virtPort;
> +    (void)vf;
> +    (void)virtPortOp;
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("Kernel VF Port support was missing at compile time."));
> +    rc = 1;
> +
> +# else /* IFLA_VF_PORT_MAX */
> +
> +    int op = PORT_REQUEST_ASSOCIATE;
> +    struct ifla_port_vsi portVsi = {
> +        .vsi_mgr_id       = virtPort->u.virtPort8021Qbg.managerID,
> +        .vsi_type_version = virtPort->u.virtPort8021Qbg.typeIDVersion,
> +    };
> +    bool multicast = true;
> +    int ifindex;
> +
> +    if (ifaceGetIndex(true, ifname, &ifindex) != 0) {
> +        rc = 1;
> +        goto err_exit;
> +    }
> +
> +    portVsi.vsi_type_id[2] = virtPort->u.virtPort8021Qbg.typeID >> 16;
> +    portVsi.vsi_type_id[1] = virtPort->u.virtPort8021Qbg.typeID >> 8;
> +    portVsi.vsi_type_id[0] = virtPort->u.virtPort8021Qbg.typeID;
> +
> +    switch (virtPortOp) {
> +    case ASSOCIATE:
> +        op = PORT_REQUEST_ASSOCIATE;
> +        break;
> +    case DISASSOCIATE:
> +        op = PORT_REQUEST_DISASSOCIATE;
> +        break;
> +    default:
> +        macvtapError(VIR_ERR_INTERNAL_ERROR,
> +                     _("operation type %d not supported"), op);
> +        rc = 1;
> +        goto err_exit;
> +    }
> +
> +    rc = doPortProfileOpCommon(multicast, ifindex,
> +                               NULL,
> +                               &portVsi,
> +                               virtPort->u.virtPort8021Qbg.instanceID,
> +                               NULL,
> +                               PORT_SELF_VF,
> +                               op);
> +
> +err_exit:
> +
> +# endif /* IFLA_VF_PORT_MAX */
> +
> +    return rc;
> +}
> +
> +
> +static int
> +getPhysfn(const char *linkdev,
> +          int32_t *vf,
> +          char **physfndev)
> +{
> +    int rc = 0;
> +
> +# ifndef IFLA_VF_PORT_MAX
> +
> +    (void)linkdev;
> +    (void)vf;
> +    (void)physfndev;
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("Kernel VF Port support was missing at compile time."));
> +    rc = 1;
> +
> +# else /* IFLA_VF_PORT_MAX */
> +
> +    bool virtfn = false;
> +
> +    if (virtfn) {
> +
> +        // XXX: if linkdev is SR-IOV VF, then set vf = VF index
> +        // XXX: and set linkdev = PF device
> +        // XXX: need to use get_physical_function_linux() or
> +        // XXX: something like that to get PF
> +        // XXX: device and figure out VF index
> +
> +        rc = 1;
> +
> +    } else {
> +
> +        /* Not SR-IOV VF: physfndev is linkdev and VF index
> +         * refers to linkdev self
> +         */
> +
> +        *vf = PORT_SELF_VF;
> +        *physfndev = (char *)linkdev;
> +    }
> +
> +# endif /* IFLA_VF_PORT_MAX */
> +
> +    return rc;
> +}
> +
> +
> +static int
> +doPortProfileOp8021Qbh(const char *ifname,
> +                       const virVirtualPortProfileDefPtr virtPort,
> +                       const unsigned char *vm_uuid,
> +                       enum virVirtualPortOp virtPortOp)
> +{
> +    int rc;
> +
> +# ifndef IFLA_VF_PORT_MAX
> +
> +    (void)ifname;
> +    (void)virtPort;
> +    (void)vm_uuid;
> +    (void)virtPortOp;
> +    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                 _("Kernel VF Port support was missing at compile time."));
> +    rc = 1;
> +
> +# else /* IFLA_VF_PORT_MAX */
> +
> +    char *physfndev;
> +    unsigned char hostuuid[VIR_UUID_BUFLEN];
> +    int32_t vf;
> +    int op = PORT_REQUEST_ASSOCIATE;
> +    bool multicast = false;
> +    int ifindex;
> +
> +    rc = virGetHostUUID(hostuuid);
> +    if (rc)
> +        goto err_exit;
> +
> +    rc = getPhysfn(ifname, &vf, &physfndev);
> +    if (rc)
> +        goto err_exit;
> +
> +    if (ifaceGetIndex(true, physfndev, &ifindex) != 0) {
> +        rc = 1;
> +        goto err_exit;
> +    }
> +
> +    switch (virtPortOp) {
> +    case ASSOCIATE:
> +        op = PORT_REQUEST_ASSOCIATE;
> +        break;
> +    case DISASSOCIATE:
> +        op = PORT_REQUEST_DISASSOCIATE;
> +        break;
> +    default:
> +        macvtapError(VIR_ERR_INTERNAL_ERROR,
> +                     _("operation type %d not supported"), op);
> +        rc = 1;
> +        goto err_exit;
> +    }
> +
> +    rc = doPortProfileOpCommon(multicast, ifindex,
> +                               virtPort->u.virtPort8021Qbh.profileID,
> +                               NULL,
> +                               vm_uuid,
> +                               hostuuid,
> +                               vf,
> +                               op);
> +
> +    switch (virtPortOp) {
> +    case ASSOCIATE:
> +        ifaceUp(ifname);
> +        break;
> +    case DISASSOCIATE:
> +        ifaceDown(ifname);
> +        break;
> +    }
> +
> +err_exit:
> +
> +# endif /* IFLA_VF_PORT_MAX */
> +
> +    return rc;
> +}
>  
>  /**
>   * associatePortProfile
>   *
>   * @macvtap_ifname: The name of the macvtap device
> + * @linkdev: The link device in case of macvtap
>   * @virtPort: pointer to the object holding port profile parameters
> - * @vf: virtual function number, -1 if to be ignored
>   * @vmuuid : the UUID of the virtual machine
>   *
>   * Associate a port on a swtich with a profile. This function
> @@ -740,15 +1484,14 @@ delMacvtap(const char *ifname,
>   */
>  static int
>  associatePortProfileId(const char *macvtap_ifname,
> +                       const char *linkdev,
>                         const virVirtualPortProfileDefPtr virtPort,
> -                       int vf,
>                         const unsigned char *vmuuid)
>  {
>      int rc = 0;
> +
>      VIR_DEBUG("Associating port profile '%p' on link device '%s'",
>                virtPort, macvtap_ifname);
> -    (void)vf;
> -    (void)vmuuid;
>  
>      switch (virtPort->virtPortType) {
>      case VIR_VIRTUALPORT_NONE:
> @@ -756,11 +1499,14 @@ associatePortProfileId(const char *macvtap_ifname,
>          break;
>  
>      case VIR_VIRTUALPORT_8021QBG:
> -
> +        rc = doPortProfileOp8021Qbg(macvtap_ifname, virtPort,
> +                                    ASSOCIATE);
>          break;
>  
>      case VIR_VIRTUALPORT_8021QBH:
> -
> +        rc = doPortProfileOp8021Qbh(linkdev, virtPort,
> +                                    vmuuid,
> +                                    ASSOCIATE);
>          break;
>      }
>  
> @@ -772,6 +1518,7 @@ associatePortProfileId(const char *macvtap_ifname,
>   * disassociatePortProfile
>   *
>   * @macvtap_ifname: The name of the macvtap device
> + * @linkdev: The link device in case of macvtap
>   * @virtPort: point to object holding port profile parameters
>   *
>   * Returns 0 in case of success, != 0 otherwise with error
> @@ -779,9 +1526,11 @@ associatePortProfileId(const char *macvtap_ifname,
>   */
>  static int
>  disassociatePortProfileId(const char *macvtap_ifname,
> +                          const char *linkdev,
>                            const virVirtualPortProfileDefPtr virtPort)
>  {
>      int rc = 0;
> +
>      VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ",
>                virtPort, macvtap_ifname);
>  
> @@ -791,13 +1540,18 @@ disassociatePortProfileId(const char *macvtap_ifname,
>          break;
>  
>      case VIR_VIRTUALPORT_8021QBG:
> -
> +        rc = doPortProfileOp8021Qbg(macvtap_ifname, virtPort,
> +                                    DISASSOCIATE);
>          break;
>  
>      case VIR_VIRTUALPORT_8021QBH:
> -
> +        rc = doPortProfileOp8021Qbh(linkdev, virtPort,
> +                                    NULL,
> +                                    DISASSOCIATE);
>          break;
>      }
>  
>      return rc;
>  }
> +
> +#endif
> diff --git a/src/util/macvtap.h b/src/util/macvtap.h
> index ae11c5c..35db31c 100644
> --- a/src/util/macvtap.h
> +++ b/src/util/macvtap.h
> @@ -72,6 +72,7 @@ int openMacvtapTap(const char *ifname,
>                     char **res_ifname);
>  
>  void delMacvtap(const char *ifname,
> +                const char *linkdev,
>                  virVirtualPortProfileDefPtr virtPortProfile);
>  
>  # endif /* WITH_MACVTAP */
> 
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
-------------- next part --------------
>From 7b0c513288ad3b0740ac05d9bf47d4320e385639 Mon Sep 17 00:00:00 2001
From: David Allan <dallan at redhat.com>
Date: Mon, 24 May 2010 22:43:54 -0400
Subject: [PATCH 1/1] Minor fixes to compile ifndef IFLA_VF_PORT_MAX

* Make getPhysfn entirely within #ifdef IFLA_VF_PORT_MAX as it's only
  called when IFLA_VF_PORT_MAX is defined

* Fix a few nits found by make syntax check (newline in error message
  and preprocessor indentation)
---
 src/util/macvtap.c |   22 ++++------------------
 1 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/src/util/macvtap.c b/src/util/macvtap.c
index d5a08d9..8e4bea3 100644
--- a/src/util/macvtap.c
+++ b/src/util/macvtap.c
@@ -318,7 +318,7 @@ err_exit:
     return rc;
 }

-#endif
+# endif

 static struct rtattr *
 rtattrCreate(char *buffer, int bufsize, int type,
@@ -1231,7 +1231,7 @@ doPortProfileOpCommon(bool multicast,

     if (rc != 0) {
         macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
-                     _("sending of PortProfileRequest failed.\n"));
+                     _("sending of PortProfileRequest failed."));
         return rc;
     }

@@ -1286,7 +1286,6 @@ doPortProfileOp8021Qbg(const char *ifname,

     (void)ifname;
     (void)virtPort;
-    (void)vf;
     (void)virtPortOp;
     macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("Kernel VF Port support was missing at compile time."));
@@ -1341,24 +1340,13 @@ err_exit:
 }


+# ifdef IFLA_VF_PORT_MAX
 static int
 getPhysfn(const char *linkdev,
           int32_t *vf,
           char **physfndev)
 {
     int rc = 0;
-
-# ifndef IFLA_VF_PORT_MAX
-
-    (void)linkdev;
-    (void)vf;
-    (void)physfndev;
-    macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
-                 _("Kernel VF Port support was missing at compile time."));
-    rc = 1;
-
-# else /* IFLA_VF_PORT_MAX */
-
     bool virtfn = false;

     if (virtfn) {
@@ -1381,11 +1369,9 @@ getPhysfn(const char *linkdev,
         *physfndev = (char *)linkdev;
     }

-# endif /* IFLA_VF_PORT_MAX */
-
     return rc;
 }
-
+# endif /* IFLA_VF_PORT_MAX */

 static int
 doPortProfileOp8021Qbh(const char *ifname,
-- 
1.7.0.1



More information about the libvir-list mailing list