While going through this code to clean up the white-space problems, I
found 3 issues that need to be addressed before I can push it. Sorry I
missed these before.
If you can base the new (and I hope final! :-) version on the version
where I've already corrected the whitespace, that would be very helpful
(otherwise I'll need to merge back with my updated version, a
mechanical, but time consuming process). Rather than post them to the
mailing list, I've pushed my updated versions of your patches to the
"lldpad2" branch of my staging repo on gitorious:
git://gitorious.org/~laine/libvirt/laine-staging.git
You should be able to get that branch into your local repo like this:
git remote add laine-staging \
git://gitorious.org/~laine/libvirt/laine-staging.git
git fetch laine-staging
git checkout laine-staging/llpad2
You can then cherry-pick those commits into your own branch, or create a
local branch based on it, then just squash in changes addressing the three problems I
point out below.
Once these are fixed, I will ACK and push it.
Thanks!
On 02/22/2012 08:17 AM, D. Herrendoerfer wrote:
From: "D. Herrendoerfer"
<d.herrendoerfer(a)herrendoerfer.name>
Add de-association handling for 802.1qbg (vepa) via lldpad
netlink messages. Also adds the possibility to perform an
association request without waiting for a confirmation.
Signed-off-by: D. Herrendoerfer <d.herrendoerfer(a)herrendoerfer.name>
---
src/qemu/qemu_migration.c | 2 +-
src/util/virnetdevmacvlan.c | 315 +++++++++++++++++++++++++++++++++++++-
src/util/virnetdevvportprofile.c | 33 +++--
src/util/virnetdevvportprofile.h | 3 +-
4 files changed, 339 insertions(+), 14 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 12cfbde..31428f8 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -2567,7 +2567,7 @@ qemuMigrationVPAssociatePortProfiles(virDomainDefPtr def) {
net->mac,
virDomainNetGetActualDirectDev(net),
def->uuid,
-
VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH) < 0)
+
VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH, false) < 0)
goto err_exit;
}
last_good_net = i;
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 25d0846..b3e3325 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -46,7 +46,6 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
"passthrough")
#if WITH_MACVTAP
-
# include <stdint.h>
# include <stdio.h>
# include <errno.h>
@@ -57,6 +56,8 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
# include <linux/if.h>
# include <linux/if_tun.h>
+# include <c-ctype.h>
+
/* Older kernels lacked this enum value. */
# if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
# define MACVLAN_MODE_PASSTHRU 8
@@ -68,6 +69,8 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
# include "virfile.h"
# include "virnetlink.h"
# include "virnetdev.h"
+# include "virpidfile.h"
+
# define MACVTAP_NAME_PREFIX "macvtap"
# define MACVTAP_NAME_PATTERN "macvtap%d"
@@ -75,6 +78,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
# define MACVLAN_NAME_PREFIX "macvlan"
# define MACVLAN_NAME_PATTERN "macvlan%d"
+
/**
* virNetDevMacVLanCreate:
*
@@ -445,6 +449,293 @@ static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = {
[VIR_NETDEV_MACVLAN_MODE_PASSTHRU] = MACVLAN_MODE_PASSTHRU,
};
+/* Struct to hold the state and configuration of a 802.1qbg port */
+struct virNetlinkCallbackData {
+ char cr_ifname[64];
Issue 1, part 1:
This should either be IFNAMSIZ bytes long, or be a char* (pointing to
separately allocated data) instead of a fixed size. This string is
copied into strings that are sent to the kernel for interface names, and
interface names have a maximum size of IFNAMSIZE (16); if you need
consistency of the name in all places (even in log messages), then you
should limit it at the source, but otherwise there's no sense in
checking string sizes both at this level and then again at the lower level.
My preference would be a char*, I think - leave it to the lower levels
to decide if it needs to be chopped.
+ virNetDevVPortProfilePtr virtPortProfile;
+ const unsigned char *macaddress;
+ const char *linkdev;
+ const unsigned char *vmuuid;
+ enum virNetDevVPortProfileOp vmOp;
+ unsigned int linkState;
+};
+
+typedef struct virNetlinkCallbackData *virNetlinkCallbackDataPtr;
+
+#define INSTANCE_STRLEN 36
+
+static int instance2str(const unsigned char *p, char *dst, size_t size)
+{
+ if (dst && size > INSTANCE_STRLEN) {
+ snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ p[0], p[1], p[2], p[3],
+ p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ return 0;
+ }
+ return -1;
+}
+
+# define LLDPAD_PID_FILE "/var/run/lldpad.pid"
+# define VIRIP_PID_FILE "/var/run/virip.pid"
+
+/**
+ * virNetDevMacVLanVPortProfileCallback:
+ *
+ * @msg: The buffer containing the received netlink message
+ * @length: The length of the received netlink message.
+ * @peer: The netling sockaddr containing the peer information
+ * @handeled: Contains information if the message has been replied to yet
+ * @opaque: Contains vital information regarding the associated vm an interface
+ *
+ * This function is called when a netlink message is received. The function
+ * reads the message and responds if it is pertinent to the running VMs
+ * network interface.
+ */
+
+static void
+virNetDevMacVLanVPortProfileCallback( unsigned char *msg,
+ int length,
+ struct sockaddr_nl *peer,
+ bool *handled,
+ void *opaque)
+{
+ struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = {
+ [IFLA_VF_MAC] = {.minlen = sizeof(struct ifla_vf_mac),
+ .maxlen = sizeof(struct ifla_vf_mac)},
+ [IFLA_VF_VLAN] = {.minlen = sizeof(struct ifla_vf_vlan),
+ .maxlen = sizeof(struct ifla_vf_vlan)},
+ };
+
+ struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = {
+ [IFLA_PORT_RESPONSE] = {.type = NLA_U16},
+ };
+
+ struct nlattr *tb[IFLA_MAX + 1],
+ *tb3[IFLA_PORT_MAX + 1],
+ *tb_vfinfo[IFLA_VF_MAX + 1], *tb_vfinfo_list;
+
+ struct ifinfomsg ifinfo;
+ struct nlmsghdr *hdr;
+ void *data;
+ int rem;
+ char *ifname;
+ bool indicate = false;
+ virNetlinkCallbackDataPtr calld = opaque;
+ pid_t lldpad_pid = 0;
+ pid_t virip_pid = 0;
+
+ hdr = (struct nlmsghdr *) msg;
+ data = nlmsg_data(hdr);
+
+ /* Quickly decide if we want this or not */
+
+ if (virPidFileReadPath(LLDPAD_PID_FILE, &lldpad_pid) < 0)
+ return;
+
+ ignore_value(virPidFileReadPath(VIRIP_PID_FILE, &virip_pid));
+
+ if (hdr->nlmsg_pid != lldpad_pid && hdr->nlmsg_pid != virip_pid)
+ return; // we only care for lldpad and virip messages
+ if (hdr->nlmsg_type != RTM_SETLINK)
+ return; // we only care for RTM_SETLINK
+ if (*handled)
+ return; // if it has been handeled - dont handle again
+
+ /* DEBUG start */
+ VIR_INFO("netlink message nl_sockaddr: %p len: %d", peer, length);
+ VIR_DEBUG("nlmsg_type = 0x%02x",hdr->nlmsg_type);
+ VIR_DEBUG("nlmsg_len = 0x%04x",hdr->nlmsg_len );
+ VIR_DEBUG("nlmsg_pid = %d",hdr->nlmsg_pid );
+ VIR_DEBUG("nlmsg_seq = 0x%08x",hdr->nlmsg_seq );
+ VIR_DEBUG("nlmsg_flags = 0x%04x",hdr->nlmsg_flags );
+
+ VIR_DEBUG("lldpad pid = %d",lldpad_pid);
+
+ switch (hdr->nlmsg_type) {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ case RTM_SETLINK:
+ case RTM_GETLINK:
+ VIR_DEBUG(" IFINFOMSG\n");
+ VIR_DEBUG(" ifi_family = 0x%02x\n",
+ ((struct ifinfomsg *)data)->ifi_family);
+ VIR_DEBUG(" ifi_type = 0x%x\n",
+ ((struct ifinfomsg *)data)->ifi_type);
+ VIR_DEBUG(" ifi_index = %i\n",
+ ((struct ifinfomsg *)data)->ifi_index);
+ VIR_DEBUG(" ifi_flags = 0x%04x\n",
+ ((struct ifinfomsg *)data)->ifi_flags);
+ VIR_DEBUG(" ifi_change = 0x%04x\n",
+ ((struct ifinfomsg *)data)->ifi_change);
+ }
+ /* DEBUG end */
+
+ /* Parse netlink message assume a setlink with vfports */
+ memcpy(&ifinfo, NLMSG_DATA(hdr), sizeof ifinfo);
+ VIR_DEBUG("family:%#x type:%#x index:%d flags:%#x change:%#x",
+ ifinfo.ifi_family, ifinfo.ifi_type, ifinfo.ifi_index,
+ ifinfo.ifi_flags, ifinfo.ifi_change);
+ if (nlmsg_parse(hdr, sizeof ifinfo,
+ (struct nlattr **)&tb, IFLA_MAX, NULL)) {
+ VIR_DEBUG("error parsing request...");
+ return;
+ }
+
+ if (tb[IFLA_VFINFO_LIST]) {
+ VIR_DEBUG("FOUND IFLA_VFINFO_LIST!");
+
+ nla_for_each_nested(tb_vfinfo_list, tb[IFLA_VFINFO_LIST], rem) {
+ if (nla_type(tb_vfinfo_list) != IFLA_VF_INFO) {
+ VIR_DEBUG("nested parsing of"
+ "IFLA_VFINFO_LIST failed.");
+ return;
+ }
+ if (nla_parse_nested(tb_vfinfo, IFLA_VF_MAX,
+ tb_vfinfo_list, ifla_vf_policy)) {
+ VIR_DEBUG("nested parsing of "
+ "IFLA_VF_INFO failed.");
+ return;
+ }
+ }
+
+ if (tb_vfinfo[IFLA_VF_MAC]) {
+ struct ifla_vf_mac *mac =
+ RTA_DATA(tb_vfinfo[IFLA_VF_MAC]);
+ unsigned char *m = mac->mac;
+
+ VIR_DEBUG("IFLA_VF_MAC=%2x:%2x:%2x:%2x:%2x:%2x",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ if (memcmp(calld->macaddress, m, VIR_MAC_BUFLEN))
+ {
+ /* Repeat the same check for a broadcast mac */
+ unsigned char broadcastmac[VIR_MAC_BUFLEN];
+ int i;
+
+ for (i=0;i<VIR_MAC_BUFLEN;i++)
+ broadcastmac[i]=0xFF;
+
+ if (memcmp(calld->macaddress, broadcastmac, VIR_MAC_BUFLEN)) {
+ VIR_DEBUG("MAC address match failed.");
+ return;
+ }
Issue 2:
Instead of using the loop to create a complete broadcast mac address,
then doing memcmp to compare to the current mac address, just change the
loop to this:
for (i = 0; i < VIR_MAC_BUFLEN; i++) {
if (calld->macaddress[i] != 0xff) {
VIR_DEBUG("MAC address match failed (wasn't
broadcast)");
return;
}
}
and get rid of the memcmp.
+ }
+ }
+
+ if (tb_vfinfo[IFLA_VF_VLAN]) {
+ struct ifla_vf_vlan *vlan =
+ RTA_DATA(tb_vfinfo[IFLA_VF_VLAN]);
+
+ VIR_DEBUG("IFLA_VF_VLAN=%d", vlan->vlan);
+ }
+ }
+
+ if (tb[IFLA_IFNAME]) {
+ ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+ VIR_DEBUG("IFLA_IFNAME=%s\n", ifname);
+ }
+
+ if (tb[IFLA_OPERSTATE]) {
+ rem = *(unsigned short *)RTA_DATA(tb[IFLA_OPERSTATE]);
+ VIR_DEBUG("IFLA_OPERSTATE=%d\n", rem);
+ }
+
+ if (tb[IFLA_VF_PORTS]) {
+ struct nlattr *tb_vf_ports;
+
+ VIR_DEBUG("found IFLA_VF_PORTS\n");
+ nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
+
+ VIR_DEBUG("iterating\n");
+ if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
+ VIR_DEBUG("not a IFLA_VF_PORT. skipping\n");
+ continue;
+ }
+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
+ ifla_port_policy)) {
+ VIR_DEBUG("nested parsing on level 2"
+ " failed.");
+ }
+ if (tb3[IFLA_PORT_VF]) {
+ VIR_DEBUG("IFLA_PORT_VF=%d",
+ *(uint32_t
+ *) (RTA_DATA(tb3[IFLA_PORT_VF])));
+ }
+ if (tb3[IFLA_PORT_PROFILE]) {
+ VIR_DEBUG("IFLA_PORT_PROFILE=%s", (char *)
+ RTA_DATA(tb3[IFLA_PORT_PROFILE]));
+ }
+
+ if (tb3[IFLA_PORT_VSI_TYPE]) {
+ struct ifla_port_vsi *pvsi;
+ int tid = 0;
+
+ pvsi = (struct ifla_port_vsi *)
+ RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
+ tid = pvsi->vsi_type_id[2] << 16 |
+ pvsi->vsi_type_id[1] << 8 |
+ pvsi->vsi_type_id[0];
+
+ VIR_DEBUG("mgr_id: %d", pvsi->vsi_mgr_id);
+ VIR_DEBUG("type_id: %d", tid);
+ VIR_DEBUG("type_version: %d",
+ pvsi->vsi_type_version);
+ }
+
+ if (tb3[IFLA_PORT_INSTANCE_UUID]) {
+ char instance[INSTANCE_STRLEN + 2];
+ unsigned char *uuid;
+
+ uuid = (unsigned char *)
+ RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
+ instance2str(uuid, instance, sizeof(instance));
+ VIR_DEBUG("IFLA_PORT_INSTANCE_UUID=%s\n",
+ instance);
+ }
+
+ if (tb3[IFLA_PORT_REQUEST]) {
+ uint8_t req = *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]);
+ VIR_DEBUG("IFLA_PORT_REQUEST=%d", req);
+
+ if ( req == PORT_REQUEST_DISASSOCIATE ) {
+ VIR_DEBUG("Set dissaccociated.");
+ indicate=true;
+ }
+ }
+
+ if (tb3[IFLA_PORT_RESPONSE]) {
+ VIR_DEBUG("IFLA_PORT_RESPONSE=%d\n", *(uint16_t *)
+ RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
+ }
+ }
+ }
+
+ if (!indicate) {
+ return;
+ }
+
+ VIR_INFO("Re-send 802.1qbg associate request:");
+ VIR_INFO(" if: %s",calld->cr_ifname );
+ VIR_INFO(" lf: %s",calld->linkdev );
+ VIR_INFO(" mac: %02x:%02x:%02x:%02x:%02x:%02x",calld->macaddress[0],
+ calld->macaddress[1],
+ calld->macaddress[2],
+ calld->macaddress[3],
+ calld->macaddress[4],
+ calld->macaddress[5] );
+
+ ignore_value(virNetDevVPortProfileAssociate(calld->cr_ifname,
+ calld->virtPortProfile,
+ calld->macaddress,
+ calld->linkdev,
+ calld->vmuuid, calld->vmOp, true));
+
+ *handled = true;
+ return;
+}
+
/**
* virNetDevMacVLanCreateWithVPortProfile:
* Create an instance of a macvtap device and open its tap character
@@ -547,7 +838,7 @@ create_name:
virtPortProfile,
macaddress,
linkdev,
- vmuuid, vmOp) < 0) {
+ vmuuid, vmOp, false) < 0) {
rc = -1;
goto link_del_exit;
}
@@ -589,6 +880,23 @@ create_name:
goto disassociate_exit;
}
+ if (virNetlinkEventServiceIsRunning()) {
+ virNetlinkCallbackDataPtr calld;
+
+ if (VIR_ALLOC(calld) < 0) {
+ virReportOOMError();
+ goto disassociate_exit;
+ }
+
+ strncpy(calld->cr_ifname,cr_ifname,64);
Issue 1, Part 2:
strncpy isn't allowed in libvirt code. Instead, you should either use
virStrncpy (which is safer, as it always makes sure the string is
null-terminated) or just change cr_ifname to be char* (as suggested
above), and fill it in with strdup() (which is allowed, but be sure to
check for failure!)
+ calld->virtPortProfile=virtPortProfile;
+ calld->macaddress=macaddress;
+ calld->linkdev=linkdev;
+ calld->vmuuid=vmuuid;
+ calld->vmOp=vmOp;
+
+ virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback, calld,
macaddress);
+ }
Issue 3, Part 1:
Note that at this point, "calld" is owned by the netlink event handler -
you haven't retained any other pointer to that memory. This will become
an issue when you later decide to remove the event...
return rc;
@@ -638,6 +946,9 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
if (virNetDevMacVLanDelete(ifname) < 0)
ret = -1;
}
+
+ virNetlinkEventRemoveClient(0,macaddr);
+
Issue 3, part 2:
... you've now removed the event, but the calld associated with it
hasn't been freed. Since the client code doesn't retain a pointer to it,
I think the netlink event code needs a new bit added to the API -
virNetlinkEventRemoveClient needs to accept a pointer to a destructor
function:
typedef void (*virNetlinkEventRemoveCallback)(int watch, const unsigned
char *macaddr, void *opaque);
int virNetlinkEventRemoveClient(int watch, const unsigned char *macaddr,
virNetlinkEventRemoveCallback cb);
If cb is non-NULL, it should be called with pointers to the appropriate
data. In the case of this particular client, the callback should look
like this:
static void
virNetDevMacVLanVPortProfileDestroyCallback(int watch ATTRIBUTE_UNUSED,
unsigned char *macaddr
ATTRIBUTE_UNUSED,
void *opaque)
{
virNetlinkCallbackDataPtr calld = opaque;
/* the part inside the if() assumes you changed cr_ifname to char * */
if (calld) {
VIR_FREE(calld->cr_ifname);
}
VIR_FREE(cr_ifname);
}
and when you remove the client:
virNetlinkEventRemoveClient, 0, macaddr,
virNetDevMacVLanVPortProfileDestroyCallback);
This will eliminate your memory leak (and get the ACK so we can push
both patches! :-)
return ret;
}
diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c
index faadc3a..554f128 100644
--- a/src/util/virnetdevvportprofile.c
+++ b/src/util/virnetdevvportprofile.c
@@ -650,7 +650,8 @@ virNetDevVPortProfileOpCommon(const char *ifname, int ifindex,
const unsigned char *instanceId,
const unsigned char *hostUUID,
int32_t vf,
- uint8_t op)
+ uint8_t op,
+ bool setlink_only)
{
int rc;
unsigned char *recvbuf = NULL;
@@ -675,6 +676,9 @@ virNetDevVPortProfileOpCommon(const char *ifname, int ifindex,
return rc;
}
+ if (setlink_only) /*for re-associations on existing links*/
+ return 0;
+
while (--repeats >= 0) {
rc = virNetDevVPortProfileLinkDump(NULL, ifindex, nltarget_kernel, tb,
&recvbuf,
virNetDevVPortProfileGetLldpadPid);
@@ -751,7 +755,8 @@ static int
virNetDevVPortProfileOp8021Qbg(const char *ifname,
const unsigned char *macaddr,
const virNetDevVPortProfilePtr virtPort,
- enum virNetDevVPortProfileLinkOp virtPortOp)
+ enum virNetDevVPortProfileLinkOp virtPortOp,
+ bool setlink_only)
{
int rc = 0;
int op = PORT_REQUEST_ASSOCIATE;
@@ -804,7 +809,8 @@ virNetDevVPortProfileOp8021Qbg(const char *ifname,
virtPort->u.virtPort8021Qbg.instanceID,
NULL,
vf,
- op);
+ op,
+ setlink_only);
err_exit:
@@ -892,7 +898,8 @@ virNetDevVPortProfileOp8021Qbh(const char *ifname,
(virtPortOp ==
VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR) ?
PORT_REQUEST_PREASSOCIATE_RR
- : PORT_REQUEST_ASSOCIATE);
+ : PORT_REQUEST_ASSOCIATE,
+ false);
if (rc == -2)
/* Association timed out, disassociate */
virNetDevVPortProfileOpCommon(NULL, ifindex,
@@ -904,7 +911,8 @@ virNetDevVPortProfileOp8021Qbh(const char *ifname,
NULL,
NULL,
vf,
- PORT_REQUEST_DISASSOCIATE);
+ PORT_REQUEST_DISASSOCIATE,
+ false);
break;
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE:
@@ -917,7 +925,8 @@ virNetDevVPortProfileOp8021Qbh(const char *ifname,
NULL,
NULL,
vf,
- PORT_REQUEST_DISASSOCIATE);
+ PORT_REQUEST_DISASSOCIATE,
+ false);
break;
default:
@@ -938,6 +947,7 @@ err_exit:
* @virtPort: pointer to the object holding port profile parameters
* @vmuuid : the UUID of the virtual machine
* @vmOp : The VM operation (i.e., create, no-op)
+ * @setlink_only : Only set the link - dont wait for the link to come up
*
* Associate a port on a swtich with a profile. This function
* may notify a kernel driver or an external daemon to run
@@ -954,7 +964,8 @@ virNetDevVPortProfileAssociate(const char *macvtap_ifname,
const unsigned char *macvtap_macaddr,
const char *linkdev,
const unsigned char *vmuuid,
- enum virNetDevVPortProfileOp vmOp)
+ enum virNetDevVPortProfileOp vmOp,
+ bool setlink_only)
{
int rc = 0;
@@ -976,7 +987,8 @@ virNetDevVPortProfileAssociate(const char *macvtap_ifname,
virtPort,
(vmOp ==
VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START)
?
VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE
- :
VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE);
+ :
VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE,
+ setlink_only);
break;
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
@@ -1033,7 +1045,7 @@ virNetDevVPortProfileDisassociate(const char *macvtap_ifname,
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
rc = virNetDevVPortProfileOp8021Qbg(macvtap_ifname, macvtap_macaddr,
virtPort,
-
VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE);
+
VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE, false);
break;
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
@@ -1056,7 +1068,8 @@ int virNetDevVPortProfileAssociate(const char *macvtap_ifname
ATTRIBUTE_UNUSED,
const unsigned char *macvtap_macaddr ATTRIBUTE_UNUSED,
const char *linkdev ATTRIBUTE_UNUSED,
const unsigned char *vmuuid ATTRIBUTE_UNUSED,
- enum virNetDevVPortProfileOp vmOp ATTRIBUTE_UNUSED)
+ enum virNetDevVPortProfileOp vmOp ATTRIBUTE_UNUSED,
+ bool setlink_only)
{
virReportSystemError(ENOSYS, "%s",
_("Virtual port profile association not supported on this
platform"));
diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h
index 7a8d81f..fe80086 100644
--- a/src/util/virnetdevvportprofile.h
+++ b/src/util/virnetdevvportprofile.h
@@ -81,7 +81,8 @@ int virNetDevVPortProfileAssociate(const char *ifname,
const unsigned char *macaddr,
const char *linkdev,
const unsigned char *vmuuid,
- enum virNetDevVPortProfileOp vmOp)
+ enum virNetDevVPortProfileOp vmOp,
+ bool setlink_only)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK;