diff --git a/configure.ac b/configure.ac index 36ba703c07..691ef690b0 100644 --- a/configure.ac +++ b/configure.ac @@ -2005,13 +2005,27 @@ if test "$with_macvtap" != "no" ; then fi AM_CONDITIONAL([WITH_MACVTAP], [test "$with_macvtap" = "yes"]) +AC_TRY_COMPILE([ #include + #include ], + [ 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" || test "$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 +2098,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/libvirt_private.syms b/src/libvirt_private.syms index 6cb3d66f5c..4f44064928 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -695,6 +695,9 @@ virArgvToString; ifaceCtrl; ifaceCheck; ifaceGetIndex; +ifaceGetFlags; +ifaceIsUp; +ifaceGetVlanID; # usb.h usbGetDevice; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 16d2f44d74..08a2ba42c3 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1559,7 +1559,7 @@ qemudPhysIfaceConnect(virConnectPtr conn, if (err) { close(rc); rc = -1; - delMacvtap(net->ifname, + delMacvtap(net->ifname, net->mac, net->data.direct.linkdev, &net->data.direct.virtPortProfile); VIR_FREE(net->ifname); } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c8cd50ad60..6f77ea0bd3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3716,7 +3716,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->mac, net->data.direct.linkdev, &net->data.direct.virtPortProfile); VIR_FREE(net->ifname); } @@ -8555,7 +8555,7 @@ qemudDomainDetachNetDevice(struct qemud_driver *driver, #if WITH_MACVTAP if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) { - delMacvtap(detach->ifname, + delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev, &detach->data.direct.virtPortProfile); VIR_FREE(detach->ifname); } diff --git a/src/util/interface.c b/src/util/interface.c index 3929a92444..eec437a3a6 100644 --- a/src/util/interface.c +++ b/src/util/interface.c @@ -30,6 +30,8 @@ #ifdef __linux__ # include +# include +# include #endif #include "internal.h" @@ -42,6 +44,85 @@ virReportErrorHelper(NULL, VIR_FROM_NET, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +#if __linux__ +static int +getFlags(int fd, const char *ifname, struct ifreq *ifr) { + + memset(ifr, 0, sizeof(*ifr)); + + if (virStrncpy(ifr->ifr_name, + ifname, strlen(ifname), sizeof(ifr->ifr_name)) == NULL) + return ENODEV; + + if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0) + return errno; + + return 0; +} + + +/** + * ifaceGetFlags + * + * @ifname : name of the interface + * @flags : pointer to short holding the flags on success + * + * Get the flags of the interface. Returns 0 on success, error code on failure. + */ +int +ifaceGetFlags(const char *ifname, short *flags) { + struct ifreq ifr; + int rc; + int fd = socket(PF_PACKET, SOCK_DGRAM, 0); + + if (fd < 0) + return errno; + + rc = getFlags(fd, ifname, &ifr); + + *flags = ifr.ifr_flags; + + close(fd); + + return rc; +} + + +int +ifaceIsUp(const char *ifname, bool *up) { + short flags; + int rc = ifaceGetFlags(ifname, &flags); + + if (rc) + return rc; + + *up = ((flags & IFF_UP) == IFF_UP); + + return 0; +} +#else + +/* Note: Showstopper on cygwin is only missing PF_PACKET */ + +int +ifaceGetFlags(const char *ifname ATTRIBUTE_UNUSED, + short *flags ATTRIBUTE_UNUSED) { + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceGetFlags is not supported on non-linux platforms")); + return ENOSYS; +} + +int +ifaceIsUp(const char *ifname ATTRIBUTE_UNUSED, + bool *up ATTRIBUTE_UNUSED) { + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceIsUp is not supported on non-linux platforms")); + return ENOSYS; +} + +#endif /* __linux__ */ + /* * chgIfaceFlags: Change flags on an interface * @@ -59,23 +140,16 @@ static int chgIfaceFlags(const char *ifname, short flagclear, short flagset) { struct ifreq ifr; int rc = 0; - int flags; + short flags; short flagmask = (~0 ^ flagclear); int fd = socket(PF_PACKET, SOCK_DGRAM, 0); if (fd < 0) return errno; - if (virStrncpy(ifr.ifr_name, - ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { - rc = ENODEV; + rc = getFlags(fd, ifname, &ifr); + if (rc != 0) goto err_exit; - } - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { - rc = errno; - goto err_exit; - } flags = (ifr.ifr_flags & flagmask) | flagset; @@ -151,6 +225,8 @@ ifaceCheck(bool reportError, const char *ifname, if (fd < 0) return errno; + memset(&ifr, 0, sizeof(ifr)); + if (virStrncpy(ifr.ifr_name, ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { if (reportError) @@ -227,6 +303,8 @@ ifaceGetIndex(bool reportError, const char *ifname, int *ifindex) if (fd < 0) return errno; + memset(&ifreq, 0, sizeof(ifreq)); + if (virStrncpy(ifreq.ifr_name, ifname, strlen(ifname), sizeof(ifreq.ifr_name)) == NULL) { if (reportError) @@ -269,3 +347,46 @@ ifaceGetIndex(bool reportError, } #endif /* __linux__ */ + +#ifdef __linux__ +int +ifaceGetVlanID(const char *vlanifname, int *vlanid) { + struct vlan_ioctl_args vlanargs = { + .cmd = GET_VLAN_VID_CMD, + }; + int rc = 0; + int fd = socket(PF_PACKET, SOCK_DGRAM, 0); + + if (fd < 0) + return errno; + + if (virStrcpyStatic(vlanargs.device1, vlanifname) == NULL) { + rc = EINVAL; + goto err_exit; + } + + if (ioctl(fd, SIOCGIFVLAN, &vlanargs) != 0) { + rc = errno; + goto err_exit; + } + + *vlanid = vlanargs.u.VID; + + err_exit: + close(fd); + + return rc; +} + +#else + +int +ifaceGetVlanID(const char *vlanifname ATTRIBUTE_UNUSED, + int *vlanid ATTRIBUTE_UNUSED) { + + ifaceError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ifaceGetVlanID is not supported on non-linux platforms")); + + return ENOSYS; +} +#endif /* __linux__ */ diff --git a/src/util/interface.h b/src/util/interface.h index fc0ca1d3bc..6470492041 100644 --- a/src/util/interface.h +++ b/src/util/interface.h @@ -12,6 +12,9 @@ # include "datatypes.h" +int ifaceGetFlags(const char *name, short *flags); +int ifaceIsUp(const char *name, bool *up); + int ifaceCtrl(const char *name, bool up); static inline int ifaceUp(const char *name) { @@ -27,4 +30,6 @@ int ifaceCheck(bool reportError, const char *ifname, int ifaceGetIndex(bool reportError, const char *ifname, int *ifindex); +int ifaceGetVlanID(const char *vlanifname, int *vlanid); + #endif /* __VIR_INTERFACE_H__ */ diff --git a/src/util/macvtap.c b/src/util/macvtap.c index 8d6a79e0a3..fb333eb8bc 100644 --- a/src/util/macvtap.c +++ b/src/util/macvtap.c @@ -27,12 +27,13 @@ #include -#if WITH_MACVTAP +#if WITH_MACVTAP || WITH_VIRTUALPORT # include # include # include # include +# include # include # include @@ -41,6 +42,8 @@ # include # include +# include + # include "util.h" # include "memory.h" # include "logging.h" @@ -48,6 +51,7 @@ # include "interface.h" # include "conf/domain_conf.h" # include "virterror_internal.h" +# include "uuid.h" # define VIR_FROM_THIS VIR_FROM_NET @@ -58,14 +62,24 @@ # 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 virVirtualPortProfileParamsPtr virtPort, - int vf, - const unsigned char *vmuuid); +# define NLMSGBUF_SIZE 256 +# define RATTBUF_SIZE 64 -static int disassociatePortProfileId(const char *macvtap_ifname, - const virVirtualPortProfileParamsPtr virtPort); +# define NETLINK_ACK_TIMEOUT_S 2 + +# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC) +# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8) + + +# define LLDPAD_PID_FILE "/var/run/lldpad.pid" + + +enum virVirtualPortOp { + ASSOCIATE = 0x1, + DISASSOCIATE = 0x2, +}; static int nlOpen(void) @@ -90,6 +104,7 @@ static void nlClose(int fd) * @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. + * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response @@ -97,22 +112,29 @@ static void nlClose(int fd) */ static int nlComm(struct nlmsghdr *nlmsg, - char **respbuf, int *respbuflen) + char **respbuf, unsigned int *respbuflen, + int nl_pid) { int rc = 0; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, - .nl_pid = 0, + .nl_pid = nl_pid, .nl_groups = 0, }; int rcvChunkSize = 1024; // expecting less than that int rcvoffset = 0; ssize_t nbytes; + struct timeval tv = { + .tv_sec = NETLINK_ACK_TIMEOUT_S, + }; + fd_set readfds; int fd = nlOpen(); + int n; if (fd < 0) return -1; + nlmsg->nlmsg_pid = getpid(); nlmsg->nlmsg_flags |= NLM_F_ACK; nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0, @@ -124,6 +146,21 @@ int nlComm(struct nlmsghdr *nlmsg, goto err_exit; } + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + n = select(fd + 1, &readfds, NULL, NULL, &tv); + if (n <= 0) { + if (n < 0) + virReportSystemError(errno, "%s", + _("error in select call")); + if (n == 0) + virReportSystemError(ETIMEDOUT, "%s", + _("no valid netlink response was received")); + rc = -1; + goto err_exit; + } + while (1) { if (VIR_REALLOC_N(*respbuf, rcvoffset+rcvChunkSize) < 0) { virReportOOMError(); @@ -204,6 +241,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, @@ -213,15 +252,15 @@ link_add(const char *type, int *retry) { int rc = 0; - char nlmsgbuf[256]; + char nlmsgbuf[NLMSGBUF_SIZE]; struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp; struct nlmsgerr *err; - char rtattbuf[64]; + char rtattbuf[RATTBUF_SIZE]; struct rtattr *rta, *rta1, *li; - struct ifinfomsg i = { .ifi_family = AF_UNSPEC }; + struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; int ifindex; char *recvbuf = NULL; - int recvbuflen; + unsigned int recvbuflen; if (ifaceGetIndex(true, srcdev, &ifindex) != 0) return -1; @@ -232,65 +271,46 @@ link_add(const char *type, nlInit(nlm, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, RTM_NEWLINK); - if (!nlAppend(nlm, sizeof(nlmsgbuf), &i, sizeof(i))) + if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo))) goto buffer_too_small; rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINK, &ifindex, sizeof(ifindex)); - if (!rta) - goto buffer_too_small; - - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_ADDRESS, macaddress, macaddrsize); - if (!rta) - goto buffer_too_small; - - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; if (ifname) { rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME, ifname, strlen(ifname) + 1); - if (!rta) - goto buffer_too_small; - - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; } rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINKINFO, NULL, 0); - if (!rta) - goto buffer_too_small; - - if (!(li = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))) + if (!rta || + !(li = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))) goto buffer_too_small; rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_KIND, type, strlen(type)); - if (!rta) - goto buffer_too_small; - - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; if (macvlan_mode > 0) { rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_DATA, NULL, 0); - if (!rta) - goto buffer_too_small; - - if (!(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))) + if (!rta || + !(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))) goto buffer_too_small; rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_MACVLAN_MODE, &macvlan_mode, sizeof(macvlan_mode)); - if (!rta) - goto buffer_too_small; - - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; rta1->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)rta1; @@ -298,7 +318,7 @@ link_add(const char *type, li->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)li; - if (nlComm(nlm, &recvbuf, &recvbuflen) < 0) + if (nlComm(nlm, &recvbuf, &recvbuflen, 0) < 0) return -1; if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) @@ -312,15 +332,15 @@ link_add(const char *type, if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) goto malformed_resp; - switch (-err->error) { + switch (err->error) { case 0: - break; + break; - case EEXIST: + case -EEXIST: *retry = 1; rc = -1; - break; + break; default: virReportSystemError(-err->error, @@ -328,10 +348,10 @@ link_add(const char *type, type); rc = -1; } - break; + break; case NLMSG_DONE: - break; + break; default: goto malformed_resp; @@ -358,14 +378,14 @@ static int link_del(const char *name) { int rc = 0; - char nlmsgbuf[256]; + char nlmsgbuf[NLMSGBUF_SIZE]; struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp; struct nlmsgerr *err; - char rtattbuf[64]; + char rtattbuf[RATTBUF_SIZE]; struct rtattr *rta; struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; char *recvbuf = NULL; - int recvbuflen; + unsigned int recvbuflen; memset(&nlmsgbuf, 0, sizeof(nlmsgbuf)); @@ -376,13 +396,10 @@ link_del(const char *name) rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME, name, strlen(name)+1); - if (!rta) + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) goto buffer_too_small; - if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) - goto buffer_too_small; - - if (nlComm(nlm, &recvbuf, &recvbuflen) < 0) + if (nlComm(nlm, &recvbuf, &recvbuflen, 0) < 0) return -1; if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) @@ -396,20 +413,16 @@ link_del(const char *name) if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) goto malformed_resp; - switch (-err->error) { - case 0: - break; - - default: + if (err->error) { virReportSystemError(-err->error, _("error destroying %s interface"), name); rc = -1; } - break; + break; case NLMSG_DONE: - break; + break; default: goto malformed_resp; @@ -509,11 +522,9 @@ macvtapModeFromInt(enum virDomainNetdevMacvtapType mode) switch (mode) { case VIR_DOMAIN_NETDEV_MACVTAP_MODE_PRIVATE: return MACVLAN_MODE_PRIVATE; - break; case VIR_DOMAIN_NETDEV_MACVTAP_MODE_BRIDGE: return MACVLAN_MODE_BRIDGE; - break; case VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA: default: @@ -654,10 +665,11 @@ create_name: cr_ifname = ifname; } - if (associatePortProfileId(cr_ifname, - virtPortProfile, - -1, - vmuuid) != 0) { + if (vpAssociatePortProfileId(cr_ifname, + macaddress, + linkdev, + virtPortProfile, + vmuuid) != 0) { rc = -1; goto link_del_exit; } @@ -688,8 +700,10 @@ create_name: return rc; disassociate_exit: - disassociatePortProfileId(cr_ifname, - virtPortProfile); + vpDisassociatePortProfileId(cr_ifname, + macaddress, + linkdev, + virtPortProfile); link_del_exit: link_del(cr_ifname); @@ -701,6 +715,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,22 +724,837 @@ link_del_exit: */ void delMacvtap(const char *ifname, + const unsigned char *macaddr, + const char *linkdev, virVirtualPortProfileParamsPtr virtPortProfile) { if (ifname) { - disassociatePortProfileId(ifname, - virtPortProfile); + vpDisassociatePortProfileId(ifname, macaddr, + linkdev, + virtPortProfile); link_del(ifname); } } +# endif /* WITH_MACVTAP */ + +# ifdef IFLA_PORT_MAX + +static struct nla_policy ifla_policy[IFLA_MAX + 1] = +{ + [IFLA_VF_PORTS] = { .type = NLA_NESTED }, +}; + +static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = +{ + [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, +}; + + +static uint32_t +getLldpadPid(void) { + int fd; + uint32_t pid = 0; + + fd = open(LLDPAD_PID_FILE, O_RDONLY); + if (fd >= 0) { + char buffer[10]; + + if (saferead(fd, buffer, sizeof(buffer)) <= sizeof(buffer)) { + unsigned int res; + char *endptr; + + if (virStrToLong_ui(buffer, &endptr, 10, &res) == 0 + && (*endptr == '\0' || c_isspace(*endptr)) + && res != 0) { + pid = res; + } else { + macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", + _("error parsing pid of lldpad")); + } + } + } else { + virReportSystemError(errno, + _("Error opening file %s"), LLDPAD_PID_FILE); + } + + if (fd >= 0) + close(fd); + + return pid; +} + + +static int +link_dump(bool nltarget_kernel, const char *ifname, int ifindex, + struct nlattr **tb, char **recvbuf) +{ + int rc = 0; + char nlmsgbuf[NLMSGBUF_SIZE] = { 0, }; + struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp; + struct nlmsgerr *err; + char rtattbuf[RATTBUF_SIZE]; + struct rtattr *rta; + struct ifinfomsg ifinfo = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex + }; + unsigned int recvbuflen; + uint32_t pid = 0; + + *recvbuf = NULL; + + nlInit(nlm, NLM_F_REQUEST, RTM_GETLINK); + + if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo))) + goto buffer_too_small; + + if (ifindex < 0 && ifname) { + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME, + ifname, strlen(ifname) + 1); + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + goto buffer_too_small; + } + + if (!nltarget_kernel) { + pid = getLldpadPid(); + if (pid == 0) + return -1; + } + + if (nlComm(nlm, recvbuf, &recvbuflen, pid) < 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; + + if (err->error) { + virReportSystemError(-err->error, + _("error dumping %s (%d) interface"), + ifname, 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; +} + /** - * associatePortProfile + * ifaceGetNthParent + * + * @ifindex : the index of the interface or -1 if ifname is given + * @ifname : the name of the interface; ignored if ifindex is valid + * @nthParent : the nth parent interface to get + * @parent_ifindex : pointer to int + * @parent_ifname : pointer to buffer of size IFNAMSIZ + * @nth : the nth parent that is actually returned; if for example eth0.100 + * was given and the 100th parent is to be returned, then eth0 will + * most likely be returned with nth set to 1 since the chain does + * not have more interfaces + * + * Get the nth parent interface of the given interface. 0 is the interface + * itself. + * + * Return 0 on success, != 0 otherwise + */ +static int +ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent, + int *parent_ifindex, char *parent_ifname, + unsigned int *nth) +{ + int rc; + struct nlattr *tb[IFLA_MAX + 1] = { NULL, }; + char *recvbuf = NULL; + bool end = false; + unsigned int i = 0; + + *nth = 0; + + while (!end && i <= nthParent) { + rc = link_dump(true, ifname, ifindex, tb, &recvbuf); + if (rc) + break; + + if (tb[IFLA_IFNAME]) { + if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]), + IFNAMSIZ)) { + macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", + _("buffer for root interface name is too small")); + VIR_FREE(recvbuf); + return 1; + } + *parent_ifindex = ifindex; + } + + if (tb[IFLA_LINK]) { + ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]); + ifname = NULL; + } else + end = true; + + VIR_FREE(recvbuf); + + i++; + } + + if (nth) + *nth = i - 1; + + return rc; +} + +/** + * getPortProfileStatus + * + * tb: top level netlink response attributes + values + * vf: The virtual function used in the request + * instanceId: instanceId of the interface (vm uuid in case of 802.1Qbh) + * is8021Qbg: whether this function is call for 8021Qbg + * status: pointer to a uint16 where the status will be written into + * + * Get the status from the IFLA_PORT_RESPONSE field; Returns 0 in + * case of success, != 0 otherwise with error having been reported + */ +static int +getPortProfileStatus(struct nlattr **tb, int32_t vf, + const unsigned char *instanceId, + bool nltarget_kernel, + bool is8021Qbg, + uint16_t *status) +{ + int rc = 1; + const char *msg = NULL; + struct nlattr *tb_port[IFLA_PORT_MAX + 1] = { NULL, }; + + if (vf == PORT_SELF_VF && nltarget_kernel) { + if (tb[IFLA_PORT_SELF]) { + if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb[IFLA_PORT_SELF], + ifla_port_policy)) { + msg = _("error parsing IFLA_PORT_SELF part"); + goto err_exit; + } + } else { + msg = _("IFLA_PORT_SELF is missing"); + goto err_exit; + } + } else { + if (tb[IFLA_VF_PORTS]) { + int rem; + bool found = false; + struct nlattr *tb_vf_ports = { NULL, }; + + nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) { + + if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { + msg = _("error while iterating over IFLA_VF_PORTS part"); + goto err_exit; + } + + if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb_vf_ports, + ifla_port_policy)) { + msg = _("error parsing IFLA_VF_PORT part"); + goto err_exit; + } + + if (instanceId && + tb_port[IFLA_PORT_INSTANCE_UUID] && + !memcmp(instanceId, + (unsigned char *) + RTA_DATA(tb_port[IFLA_PORT_INSTANCE_UUID]), + VIR_UUID_BUFLEN) && + tb_port[IFLA_PORT_VF] && + vf == *(uint32_t *)RTA_DATA(tb_port[IFLA_PORT_VF])) { + found = true; + break; + } + } + + if (!found) { + msg = _("Could not find netlink response with " + "expected parameters"); + goto err_exit; + } + } else { + msg = _("IFLA_VF_PORTS is missing"); + goto err_exit; + } + } + + if (tb_port[IFLA_PORT_RESPONSE]) { + *status = *(uint16_t *)RTA_DATA(tb_port[IFLA_PORT_RESPONSE]); + rc = 0; + } else { + if (is8021Qbg) { + /* no in-progress here; may be missing */ + *status = PORT_PROFILE_RESPONSE_INPROGRESS; + } 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 nltarget_kernel, + const char *ifname, int ifindex, + const unsigned char *macaddr, + int vlanid, + 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[NLMSGBUF_SIZE]; + struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp; + struct nlmsgerr *err; + char rtattbuf[RATTBUF_SIZE]; + struct rtattr *rta, *vfports = NULL, *vfport; + struct ifinfomsg ifinfo = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + }; + char *recvbuf = NULL; + unsigned int recvbuflen = 0; + uint32_t pid = 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 (ifname) { + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME, + ifname, strlen(ifname) + 1); + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + goto buffer_too_small; + } + + if (macaddr && vlanid >= 0) { + struct rtattr *vfinfolist, *vfinfo; + struct ifla_vf_mac ifla_vf_mac = { + .vf = vf, + .mac = { 0, }, + }; + struct ifla_vf_vlan ifla_vf_vlan = { + .vf = vf, + .vlan = vlanid, + .qos = 0, + }; + + memcpy(ifla_vf_mac.mac, macaddr, 6); + + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VFINFO_LIST, + NULL, 0); + if (!rta || + !(vfinfolist = nlAppend(nlm, sizeof(nlmsgbuf), + rtattbuf, rta->rta_len))) + goto buffer_too_small; + + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_INFO, + NULL, 0); + if (!rta || + !(vfinfo = nlAppend(nlm, sizeof(nlmsgbuf), + rtattbuf, rta->rta_len))) + goto buffer_too_small; + + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_MAC, + &ifla_vf_mac, sizeof(ifla_vf_mac)); + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + goto buffer_too_small; + + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_VLAN, + &ifla_vf_vlan, sizeof(ifla_vf_vlan)); + + if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)) + goto buffer_too_small; + + vfinfo->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfinfo; + + vfinfolist->rta_len = (char *)nlm + nlm->nlmsg_len - + (char *)vfinfolist; + } + + if (vf == PORT_SELF_VF && nltarget_kernel) { + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_SELF, NULL, 0); + } else { + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORTS, NULL, 0); + if (!rta || + !(vfports = nlAppend(nlm, sizeof(nlmsgbuf), + rtattbuf, rta->rta_len))) + goto buffer_too_small; + + /* begin nesting vfports */ + rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORT, NULL, 0); + } + + if (!rta || + !(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 || !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 || !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 || !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 || !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 || !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 || !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 (vfports) { + /* end nesting of vfports */ + vfports->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfports; + } + + if (!nltarget_kernel) { + pid = getLldpadPid(); + if (pid == 0) + return -1; + } + + if (nlComm(nlm, &recvbuf, &recvbuflen, pid) < 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; + + if (err->error) { + 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 nltarget_kernel, + const char *ifname, int ifindex, + const unsigned char *macaddr, + int vlanid, + 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] = { NULL , }; + int repeats = STATUS_POLL_TIMEOUT_USEC / STATUS_POLL_INTERVL_USEC; + uint16_t status = 0; + bool is8021Qbg = (profileId == NULL); + + rc = doPortProfileOpSetLink(nltarget_kernel, + ifname, ifindex, + macaddr, + vlanid, + profileId, + portVsi, + instanceId, + hostUUID, + vf, + op); + + if (rc) { + macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", + _("sending of PortProfileRequest failed.")); + return rc; + } + + while (--repeats >= 0) { + rc = link_dump(nltarget_kernel, NULL, ifindex, tb, &recvbuf); + if (rc) + goto err_exit; + rc = getPortProfileStatus(tb, vf, instanceId, nltarget_kernel, + is8021Qbg, &status); + if (rc) + goto err_exit; + 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 " + "interface %s (%d)"), + status, ifname, ifindex); + rc = 1; + break; + } + + usleep(STATUS_POLL_INTERVL_USEC); + + 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 */ + + +# ifdef IFLA_VF_PORT_MAX + +static int +getPhysdevAndVlan(const char *ifname, int *root_ifindex, char *root_ifname, + int *vlanid) +{ + int ret; + unsigned int nth; + int ifindex = -1; + + *vlanid = -1; + while (1) { + if ((ret = ifaceGetNthParent(ifindex, ifname, 1, + root_ifindex, root_ifname, &nth))) + return ret; + if (nth == 0) + break; + if (*vlanid == -1) { + if (ifaceGetVlanID(root_ifname, vlanid)) + *vlanid = -1; + } + + ifindex = *root_ifindex; + ifname = NULL; + } + + return 0; +} + +# endif + +static int +doPortProfileOp8021Qbg(const char *ifname, + const unsigned char *macaddr, + const virVirtualPortProfileParamsPtr virtPort, + enum virVirtualPortOp virtPortOp) +{ + int rc; + +# ifndef IFLA_VF_PORT_MAX + + (void)ifname; + (void)macaddr; + (void)virtPort; + (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 nltarget_kernel = false; + int vlanid; + int physdev_ifindex = 0; + char physdev_ifname[IFNAMSIZ] = { 0, }; + int vf = PORT_SELF_VF; + + if (getPhysdevAndVlan(ifname, &physdev_ifindex, physdev_ifname, + &vlanid) != 0) { + rc = 1; + goto err_exit; + } + + if (vlanid < 0) + vlanid = 0; + + 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(nltarget_kernel, + physdev_ifname, physdev_ifindex, + macaddr, + vlanid, + NULL, + &portVsi, + virtPort->u.virtPort8021Qbg.instanceID, + NULL, + vf, + op); + +err_exit: + +# endif /* IFLA_VF_PORT_MAX */ + + return rc; +} + + +# ifdef IFLA_VF_PORT_MAX +static int +getPhysfn(const char *linkdev, + int32_t *vf, + char **physfndev) +{ + int rc = 0; + 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; + } + + return rc; +} +# endif /* IFLA_VF_PORT_MAX */ + +static int +doPortProfileOp8021Qbh(const char *ifname, + const virVirtualPortProfileParamsPtr 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; + bool nltarget_kernel = true; + int ifindex; + int vlanid = -1; + const unsigned char *macaddr = NULL; + + 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: + rc = virGetHostUUID(hostuuid); + if (rc) + goto err_exit; + + rc = doPortProfileOpCommon(nltarget_kernel, NULL, ifindex, + macaddr, + vlanid, + virtPort->u.virtPort8021Qbh.profileID, + NULL, + vm_uuid, + hostuuid, + vf, + PORT_REQUEST_ASSOCIATE); + if (rc == -ETIMEDOUT) + /* Association timed out, disassociate */ + doPortProfileOpCommon(nltarget_kernel, NULL, ifindex, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + vf, + PORT_REQUEST_DISASSOCIATE); + if (!rc) + ifaceUp(ifname); + break; + + case DISASSOCIATE: + rc = doPortProfileOpCommon(nltarget_kernel, NULL, ifindex, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + vf, + PORT_REQUEST_DISASSOCIATE); + ifaceDown(ifname); + break; + + default: + macvtapError(VIR_ERR_INTERNAL_ERROR, + _("operation type %d not supported"), virtPortOp); + rc = 1; + } + +err_exit: + +# endif /* IFLA_VF_PORT_MAX */ + + return rc; +} + +/** + * vpAssociatePortProfile * * @macvtap_ifname: The name of the macvtap device * @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 @@ -736,17 +1566,17 @@ delMacvtap(const char *ifname, * Returns 0 in case of success, != 0 otherwise with error * having been reported. */ -static int -associatePortProfileId(const char *macvtap_ifname, - const virVirtualPortProfileParamsPtr virtPort, - int vf, - const unsigned char *vmuuid) +int +vpAssociatePortProfileId(const char *macvtap_ifname, + const unsigned char *macvtap_macaddr, + const char *linkdev, + const virVirtualPortProfileParamsPtr virtPort, + 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: @@ -754,11 +1584,14 @@ associatePortProfileId(const char *macvtap_ifname, break; case VIR_VIRTUALPORT_8021QBG: - + rc = doPortProfileOp8021Qbg(macvtap_ifname, macvtap_macaddr, + virtPort, ASSOCIATE); break; case VIR_VIRTUALPORT_8021QBH: - + rc = doPortProfileOp8021Qbh(linkdev, virtPort, + vmuuid, + ASSOCIATE); break; } @@ -767,19 +1600,24 @@ associatePortProfileId(const char *macvtap_ifname, /** - * disassociatePortProfile + * vpDisassociatePortProfile * * @macvtap_ifname: The name of the macvtap device + * @macvtap_macaddr : The MAC address of the macvtap + * @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 * having been reported. */ -static int -disassociatePortProfileId(const char *macvtap_ifname, - const virVirtualPortProfileParamsPtr virtPort) +int +vpDisassociatePortProfileId(const char *macvtap_ifname, + const unsigned char *macvtap_macaddr, + const char *linkdev, + const virVirtualPortProfileParamsPtr virtPort) { int rc = 0; + VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ", virtPort, macvtap_ifname); @@ -789,15 +1627,18 @@ disassociatePortProfileId(const char *macvtap_ifname, break; case VIR_VIRTUALPORT_8021QBG: - + rc = doPortProfileOp8021Qbg(macvtap_ifname, macvtap_macaddr, + virtPort, DISASSOCIATE); break; case VIR_VIRTUALPORT_8021QBH: - + rc = doPortProfileOp8021Qbh(linkdev, virtPort, + NULL, + DISASSOCIATE); break; } return rc; } -#endif /* WITH_MACVTAP */ +#endif /* WITH_MACVTAP || WITH_VIRTUALPORT */ diff --git a/src/util/macvtap.h b/src/util/macvtap.h index 464562e4b5..167633a57d 100644 --- a/src/util/macvtap.h +++ b/src/util/macvtap.h @@ -72,6 +72,8 @@ int openMacvtapTap(const char *ifname, char **res_ifname); void delMacvtap(const char *ifname, + const unsigned char *macaddress, + const char *linkdev, virVirtualPortProfileParamsPtr virtPortProfile); # endif /* WITH_MACVTAP */ @@ -80,6 +82,16 @@ void delMacvtap(const char *ifname, # define MACVTAP_MODE_VEPA_STR "vepa" # define MACVTAP_MODE_BRIDGE_STR "bridge" +int vpAssociatePortProfileId(const char *macvtap_ifname, + const unsigned char *macvtap_macaddr, + const char *linkdev, + const virVirtualPortProfileParamsPtr virtPort, + const unsigned char *vmuuid); + +int vpDisassociatePortProfileId(const char *macvtap_ifname, + const unsigned char *macvtap_macaddr, + const char *linkdev, + const virVirtualPortProfileParamsPtr virtPort); VIR_ENUM_DECL(virVirtualPort)