[libvirt] [PATCH] Remove macvtap dependancy on domain configuration
by Daniel P. Berrange
Files under src/util must not depend on src/conf
Solve the macvtap problem by moving the definition
of macvtap modes from domain_conf.h into macvtap.h
* src/util/macvtap.c, src/util/macvtap.h: Add enum
for macvtap modes
* src/conf/domain_conf.c, src/conf/domain_conf.h: Remove
enum for macvtap modes
---
src/conf/domain_conf.c | 17 ++++++-----------
src/conf/domain_conf.h | 15 +--------------
src/util/macvtap.c | 40 +++++++++++++++++-----------------------
src/util/macvtap.h | 14 +++++++++++++-
4 files changed, 37 insertions(+), 49 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b5c0f83..c528960 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -447,12 +447,6 @@ VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
"dynamic",
"static")
-VIR_ENUM_IMPL(virDomainNetdevMacvtap, VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
- "vepa",
- "private",
- "bridge",
- "passthrough")
-
VIR_ENUM_IMPL(virVirtualPort, VIR_VIRTUALPORT_TYPE_LAST,
"none",
"802.1Qbg",
@@ -1156,7 +1150,7 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
}
if (caps->privateDataAllocFunc &&
- !(domain->privateData = (caps->privateDataAllocFunc)())) {
+ !(domain->privateData = (caps->privateDataAllocFunc)(caps->privateDataOpaque))) {
virReportOOMError();
VIR_FREE(domain);
return NULL;
@@ -2974,14 +2968,14 @@ virDomainNetDefParseXML(virCapsPtr caps,
if (mode != NULL) {
int m;
- if ((m = virDomainNetdevMacvtapTypeFromString(mode)) < 0) {
+ if ((m = virMacvtapModeTypeFromString(mode)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unkown mode has been specified"));
goto error;
}
def->data.direct.mode = m;
} else
- def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ def->data.direct.mode = VIR_MACVTAP_MODE_VEPA;
if (virtPortParsed)
def->data.direct.virtPortProfile = virtPort;
@@ -6737,12 +6731,13 @@ static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
char *str = virXMLPropString(nodes[i], "flag");
if (str) {
int flag = virDomainTaintTypeFromString(str);
- VIR_FREE(str);
if (flag < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown taint flag %s"), str);
+ VIR_FREE(str);
goto error;
}
+ VIR_FREE(str);
virDomainObjTaint(obj, flag);
}
}
@@ -8634,7 +8629,7 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferEscapeString(buf, " <source dev='%s'",
def->data.direct.linkdev);
virBufferAsprintf(buf, " mode='%s'",
- virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
+ virMacvtapModeTypeToString(def->data.direct.mode));
virBufferAddLit(buf, "/>\n");
virVirtualPortProfileFormat(buf, &def->data.direct.virtPortProfile,
" ");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 994ff91..aa25e36 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -348,17 +348,6 @@ enum virDomainNetVirtioTxModeType {
VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
};
-/* the mode type for macvtap devices */
-enum virDomainNetdevMacvtapType {
- VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA,
- VIR_DOMAIN_NETDEV_MACVTAP_MODE_PRIVATE,
- VIR_DOMAIN_NETDEV_MACVTAP_MODE_BRIDGE,
- VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU,
-
- VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
-};
-
-
/* Stores the virtual network interface configuration */
typedef struct _virDomainNetDef virDomainNetDef;
typedef virDomainNetDef *virDomainNetDefPtr;
@@ -396,7 +385,7 @@ struct _virDomainNetDef {
} internal;
struct {
char *linkdev;
- int mode;
+ int mode; /* enum virMacvtapMode from util/macvtap.h */
virVirtualPortProfileParams virtPortProfile;
} direct;
} data;
@@ -1615,8 +1604,6 @@ int virDomainStateReasonFromString(virDomainState state, const char *reason);
VIR_ENUM_DECL(virDomainSeclabel)
VIR_ENUM_DECL(virDomainClockOffset)
-VIR_ENUM_DECL(virDomainNetdevMacvtap)
-
VIR_ENUM_DECL(virDomainTimerName)
VIR_ENUM_DECL(virDomainTimerTrack)
VIR_ENUM_DECL(virDomainTimerTickpolicy)
diff --git a/src/util/macvtap.c b/src/util/macvtap.c
index 48c7b0e..4e4ed79 100644
--- a/src/util/macvtap.c
+++ b/src/util/macvtap.c
@@ -55,12 +55,17 @@
#include "util.h"
#include "macvtap.h"
+VIR_ENUM_IMPL(virMacvtapMode, VIR_MACVTAP_MODE_LAST,
+ "vepa",
+ "private",
+ "bridge",
+ "passthrough")
+
#if WITH_MACVTAP || WITH_VIRTUALPORT
# include "memory.h"
# include "logging.h"
# include "interface.h"
-# include "conf/domain_conf.h"
# include "virterror_internal.h"
# include "uuid.h"
# include "files.h"
@@ -468,26 +473,6 @@ int openTap(const char *ifname,
}
-static uint32_t
-macvtapModeFromInt(enum virDomainNetdevMacvtapType mode)
-{
- switch (mode) {
- case VIR_DOMAIN_NETDEV_MACVTAP_MODE_PRIVATE:
- return MACVLAN_MODE_PRIVATE;
-
- case VIR_DOMAIN_NETDEV_MACVTAP_MODE_BRIDGE:
- return MACVLAN_MODE_BRIDGE;
-
- case VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU:
- return MACVLAN_MODE_PASSTHRU;
-
- case VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA:
- default:
- return MACVLAN_MODE_VEPA;
- }
-}
-
-
/**
* configMacvtapTap:
* @tapfd: file descriptor of the macvtap tap
@@ -643,6 +628,13 @@ restoreMacAddress(const char *linkdev,
return 0;
}
+static const uint32_t modeMap[VIR_MACVTAP_MODE_LAST] = {
+ [VIR_MACVTAP_MODE_VEPA] = MACVLAN_MODE_VEPA,
+ [VIR_MACVTAP_MODE_PRIVATE] = MACVLAN_MODE_PRIVATE,
+ [VIR_MACVTAP_MODE_BRIDGE] = MACVLAN_MODE_BRIDGE,
+ [VIR_MACVTAP_MODE_PASSTHRU] = MACVLAN_MODE_PASSTHRU,
+};
+
/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
@@ -667,7 +659,7 @@ int
openMacvtapTap(const char *tgifname,
const unsigned char *macaddress,
const char *linkdev,
- int mode,
+ enum virMacvtapMode mode,
int vnet_hdr,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
@@ -679,10 +671,12 @@ openMacvtapTap(const char *tgifname,
int c, rc;
char ifname[IFNAMSIZ];
int retries, do_retry = 0;
- uint32_t macvtapMode = macvtapModeFromInt(mode);
+ uint32_t macvtapMode;
const char *cr_ifname;
int ifindex;
+ macvtapMode = modeMap[mode];
+
*res_ifname = NULL;
VIR_DEBUG("%s: VM OPERATION: %s", __FUNCTION__, virVMOperationTypeToString(vmOp));
diff --git a/src/util/macvtap.h b/src/util/macvtap.h
index 2843596..1b85989 100644
--- a/src/util/macvtap.h
+++ b/src/util/macvtap.h
@@ -34,6 +34,17 @@ enum virVirtualPortType {
VIR_VIRTUALPORT_TYPE_LAST,
};
+/* the mode type for macvtap devices */
+enum virMacvtapMode {
+ VIR_MACVTAP_MODE_VEPA,
+ VIR_MACVTAP_MODE_PRIVATE,
+ VIR_MACVTAP_MODE_BRIDGE,
+ VIR_MACVTAP_MODE_PASSTHRU,
+
+ VIR_MACVTAP_MODE_LAST,
+};
+
+
# ifdef IFLA_VF_PORT_PROFILE_MAX
# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX IFLA_VF_PORT_PROFILE_MAX
# else
@@ -78,7 +89,7 @@ enum virVMOperationType {
int openMacvtapTap(const char *ifname,
const unsigned char *macaddress,
const char *linkdev,
- int mode,
+ enum virMacvtapMode mode,
int vnet_hdr,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
@@ -110,5 +121,6 @@ int vpDisassociatePortProfileId(const char *macvtap_ifname,
VIR_ENUM_DECL(virVirtualPort)
VIR_ENUM_DECL(virVMOperation)
+VIR_ENUM_DECL(virMacvtapMode)
#endif /* __UTIL_MACVTAP_H__ */
--
1.7.4.4
13 years, 5 months
[libvirt] [PATCH]: set and get the MAC of an interface
by Gerhard Stenzel
The following patch renames the function to set the MAC of an interface
from ifSetInterfaceMac() to brSetInterfaceMac() and makes it available
to other components.
It also adds brGetInterfaceMac() to retrieve the MAC.
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
Index: libvirt/src/util/bridge.c
===================================================================
--- libvirt.orig/src/util/bridge.c
+++ libvirt/src/util/bridge.c
@@ -286,8 +286,41 @@ brDeleteInterface(brControl *ctl ATTRIBU
}
# endif
+
+/**
+ * brGetInterfaceMac:
+ * @ctl: bridge control pointer
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function gets the @macaddr for a given interface @ifname.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int brGetInterfaceMac(brControl *ctl, const char *ifname,
+ unsigned char *macaddr)
+{
+ struct ifreq ifr;
+
+ if (!ctl || !ifname)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ if(ioctl(ctl->fd, SIOCGIFHWADDR, (char *)&ifr) != 0){
+ return errno;
+ }
+
+ memcpy(macaddr, ifr.ifr_ifru.ifru_hwaddr.sa_data, VIR_MAC_BUFLEN);
+
+ return 0;
+}
+
+
/**
- * ifSetInterfaceMac:
+ * brSetInterfaceMac:
* @ctl: bridge control pointer
* @ifname: interface name to set MTU for
* @macaddr: MAC address (VIR_MAC_BUFLEN in size)
@@ -297,7 +330,7 @@ brDeleteInterface(brControl *ctl ATTRIBU
*
* Returns 0 in case of success or an errno code in case of failure.
*/
-static int ifSetInterfaceMac(brControl *ctl, const char *ifname,
+int brSetInterfaceMac(brControl *ctl, const char *ifname,
const unsigned char *macaddr)
{
struct ifreq ifr;
@@ -521,7 +554,7 @@ brAddTap(brControl *ctl,
* seeing the kernel allocate random MAC for the TAP
* device before we set our static MAC.
*/
- if ((errno = ifSetInterfaceMac(ctl, ifr.ifr_name, macaddr)))
+ if ((errno = brSetInterfaceMac(ctl, ifr.ifr_name, macaddr)))
goto error;
/* We need to set the interface MTU before adding it
* to the bridge, because the bridge will have its
Index: libvirt/src/util/bridge.h
===================================================================
--- libvirt.orig/src/util/bridge.h
+++ libvirt/src/util/bridge.h
@@ -106,6 +106,14 @@ int brGetEnableSTP (brContr
const char *bridge,
int *enable);
+int brSetInterfaceMac (brControl *ctl,
+ const char *ifname,
+ const unsigned char *macaddr);
+
+int brGetInterfaceMac (brControl *ctl,
+ const char *ifname,
+ unsigned char *macaddr);
+
# endif /* WITH_BRIDGE */
#endif /* __QEMUD_BRIDGE_H__ */
===================================================================
Best regards,
Gerhard Stenzel
-------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
13 years, 5 months
[libvirt] [RFC] Introduce virDomainBlockCopy API
by Jiri Denemark
This API starts asynchronous live copy of a block device (specified by
target element of the xml argument) into a new source (which must
already exist). The process can be controlled in the same way as
migration: monitored with virDomainJobInfo() and canceled using
virDomainAbortJob().
I don't particularly like the name (but I wasn't able to come up with a
better one) since it doesn't reflect the fact that once a block device
is switched to use the new source once copying finishes. In other words,
the goal of this API is to update the device to use new source (just
like virDomainUpdateDeviceFlags) but before doing so all data is copied
from the old source into the new one (unlike the UpdateDevice API).
---
include/libvirt/libvirt.h.in | 4 +++
src/driver.h | 6 ++++
src/libvirt.c | 54 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
4 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index cb9e8ca..41f6b2e 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2983,6 +2983,10 @@ typedef struct _virTypedParameter virMemoryParameter;
*/
typedef virMemoryParameter *virMemoryParameterPtr;
+int virDomainBlockCopy(virDomainPtr domain,
+ const char *xml,
+ unsigned int flags);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/driver.h b/src/driver.h
index 62bbc1d..8731d68 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -666,6 +666,11 @@ typedef int
virDomainBlockPullInfoPtr info,
unsigned int flags);
+typedef int
+ (*virDrvDomainBlockCopy)(virDomainPtr domain,
+ const char *xml,
+ unsigned int flags);
+
/**
* _virDriver:
*
@@ -809,6 +814,7 @@ struct _virDriver {
virDrvDomainBlockPullAll domainBlockPullAll;
virDrvDomainBlockPullAbort domainBlockPullAbort;
virDrvDomainGetBlockPullInfo domainGetBlockPullInfo;
+ virDrvDomainBlockCopy domainBlockCopy;
};
typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index c57e0c3..ad5da9b 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -15548,3 +15548,57 @@ error:
virDispatchError(dom->conn);
return -1;
}
+
+/**
+ * virDomainBlockCopy:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of the block device to copy
+ * @flags: currently unused, use 0
+ *
+ * Starts asynchronous live copy of a block device (specified by target element
+ * of the xml) into a new source (which must already exist). The process can be
+ * controlled in the same way as migration: monitored with virDomainJobInfo()
+ * and canceled using virDomainAbortJob().
+ *
+ * Returns -1 in case of failure, 0 when successful.
+ */
+int
+virDomainBlockCopy(virDomainPtr domain, const char *xml, unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%d", xml, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if (xml == NULL) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (domain->conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+ conn = domain->conn;
+
+ if (conn->driver->domainBlockCopy) {
+ int ret;
+ ret = conn->driver->domainBlockCopy(domain, xml, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(domain->conn);
+ return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index b2915f6..3028e15 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -452,6 +452,7 @@ LIBVIRT_0.9.2 {
LIBVIRT_0.9.3 {
global:
+ virDomainBlockCopy;
virDomainBlockPull;
virDomainBlockPullAbort;
virDomainBlockPullAll;
--
1.7.5.3
13 years, 5 months
[libvirt] qemu error: "fsdev is not supported by this qemu build."
by Richard W.M. Jones
When trying to add a 9p filesystem to a guest, I get the qemu error
"fsdev is not supported by this qemu build." (when starting the
guest).
I'm still looking at this. It seems to be something to do with the
machine type causing the -fsdev option not to be registered inside
qemu. I just wanted to record the problem here in case anyone else
has any ideas.
Full XML and qemu command line is below.
Occurs with:
libvirt-0.9.2-2.fc16.x86_64
2:qemu-system-x86-0.14.0-8.fc16.x86_64
Also occurs with the latest qemu & libvirt in Fedora 15, but
reportedly not with older versions of qemu.
Rich.
----------------------------------------------------------------------
<domain type='kvm'>
<name>F14x64</name>
<uuid>799ae7ca-23a2-f622-c691-48feebcddbe6</uuid>
<memory>1048576</memory>
<currentMemory>1048576</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64' machine='pc-0.14'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<cpu match='exact'>
<model>core2duo</model>
<vendor>Intel</vendor>
</cpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-kvm</emulator>
<disk type='block' device='disk'>
<driver name='qemu' type='raw'/>
<source dev='/dev/vg_pin/F14x64'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' unit='0'/>
</disk>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>
<filesystem type='mount' accessmode='passthrough'>
<source dir='/tmp'/>
<target dir='org.kernel.tmp'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</filesystem>
<interface type='network'>
<mac address='52:54:00:18:04:63'/>
<source network='default'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<channel type='unix'>
<source mode='bind' path='/tmp/f14socket'/>
<target type='virtio' name='org.libguestfs.channel.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' keymap='de'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<watchdog model='ib700' action='reset'/>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</memballoon>
</devices>
</domain>
----------------------------------------------------------------------
LC_ALL=C PATH=/sbin:/usr/sbin:/bin:/usr/bin QEMU_AUDIO_DRV=none /usr/bin/qemu-kvm -S -M pc-0.14 -cpu core2duo -enable-kvm -m 1024 -smp 1,sockets=1,cores=1,threads=1 -name F14x64 -uuid 799ae7ca-23a2-f622-c691-48feebcddbe6 -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/F14x64.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -boot c -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x5 -drive file=/dev/vg_pin/F14x64,if=none,id=drive-ide0-0-0,format=raw -device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/tmp -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=org.kernel.tmp,bus=pci.0,addr=0x6 -netdev tap,fd=23,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:18:04:63,bus=pci.0,addr=0x4 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -chardev socket,id=charchannel0,path=/tmp/f14socket,server,nowait -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.libguestfs.channel.0 -usb -vnc 127.0.0.1:0 -k de -vga cirrus -device ib700,id=watchdog0 -watchdog-action reset -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
qemu-kvm: -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/tmp: there is no option group "fsdev"
fsdev is not supported by this qemu build.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine. Supports Linux and Windows.
http://et.redhat.com/~rjones/virt-df/
13 years, 5 months
[libvirt] [PATCH] util: Correct the error prompt string
by Osier Yang
virCommandProcessIO: It's reading from stdout or stderr of child,
but not reading.
---
src/util/command.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/util/command.c b/src/util/command.c
index cb682fc..81a2345 100644
--- a/src/util/command.c
+++ b/src/util/command.c
@@ -1504,7 +1504,9 @@ virCommandProcessIO(virCommandPtr cmd)
if (errno != EINTR &&
errno != EAGAIN) {
virReportSystemError(errno, "%s",
- _("unable to write to child input"));
+ (fds[i].fd == outfd) ?
+ _("unable to read child stdout") :
+ _("unable to read child stderr"));
goto cleanup;
}
} else if (done == 0) {
--
1.7.4
13 years, 5 months
[libvirt] [PATCH] qemu: Fix one memory leak
by Osier Yang
* src/qemu/qemu_domain.c: (qemuDomainAppendLog)
Free "message" in "cleanup".
---
src/qemu/qemu_domain.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 5fe66ac..fab316f 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -947,5 +947,6 @@ cleanup:
if (fd != logFD)
VIR_FORCE_CLOSE(fd);
+ VIR_FREE(message);
return ret;
}
--
1.7.4
13 years, 5 months
[libvirt] [PATCH 1/2] cleanup: make nlComm commonly available
by Stefan Berger
In a first cleanup step, make nlComm from macvtap.c commonly available
for other code to use. Since nlComm uses Linux-specific structures as
parameters it's prototype is only visible on Linux.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/Makefile.am | 1
src/libvirt_private.syms | 4 +
src/util/macvtap.c | 98 ----------------------------------
src/util/netlink.c | 135
+++++++++++++++++++++++++++++++++++++++++++++++
src/util/netlink.h | 14 ++++
5 files changed, 155 insertions(+), 97 deletions(-)
Index: libvirt-acl/src/Makefile.am
===================================================================
--- libvirt-acl.orig/src/Makefile.am
+++ libvirt-acl/src/Makefile.am
@@ -63,6 +63,7 @@ UTIL_SOURCES = \
util/logging.c util/logging.h \
util/macvtap.c util/macvtap.h \
util/memory.c util/memory.h \
+ util/netlink.c util/netlink.h \
util/pci.c util/pci.h \
util/processinfo.c util/processinfo.h \
util/hostusb.c util/hostusb.h \
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -39,12 +39,8 @@
# include <sys/ioctl.h>
# include <linux/if.h>
-# include <linux/netlink.h>
-# include <linux/rtnetlink.h>
# include <linux/if_tun.h>
-# include <netlink/msg.h>
-
/* Older kernels lacked this enum value. */
# if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
# define MACVLAN_MODE_PASSTHRU 8
@@ -64,6 +60,7 @@
# include "virterror_internal.h"
# include "uuid.h"
# include "files.h"
+# include "netlink.h"
# define VIR_FROM_THIS VIR_FROM_NET
@@ -79,8 +76,6 @@
# define NLMSGBUF_SIZE 256
# define RATTBUF_SIZE 64
-# define NETLINK_ACK_TIMEOUT_S 2
-
# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC)
# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8)
@@ -96,97 +91,6 @@ enum virVirtualPortOp {
};
-/**
- * nlComm:
- * @nlmsg: pointer to netlink message
- * @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
- * buffer will be returned.
- */
-static
-int nlComm(struct nl_msg *nl_msg,
- unsigned char **respbuf, unsigned int *respbuflen,
- int nl_pid)
-{
- int rc = 0;
- struct sockaddr_nl nladdr = {
- .nl_family = AF_NETLINK,
- .nl_pid = nl_pid,
- .nl_groups = 0,
- };
- ssize_t nbytes;
- struct timeval tv = {
- .tv_sec = NETLINK_ACK_TIMEOUT_S,
- };
- fd_set readfds;
- int fd;
- int n;
- struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
- struct nl_handle *nlhandle = nl_handle_alloc();
-
- if (!nlhandle) {
- virReportSystemError(errno,
- "%s", _("cannot allocate nlhandle for
netlink"));
- return -1;
- }
-
- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
- virReportSystemError(errno,
- "%s", _("cannot connect to netlink socket"));
- rc = -1;
- goto err_exit;
- }
-
- nlmsg_set_dst(nl_msg, &nladdr);
-
- nlmsg->nlmsg_pid = getpid();
-
- nbytes = nl_send_auto_complete(nlhandle, nl_msg);
- if (nbytes < 0) {
- virReportSystemError(errno,
- "%s", _("cannot send to netlink socket"));
- rc = -1;
- goto err_exit;
- }
-
- fd = nl_socket_get_fd(nlhandle);
-
- 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;
- }
-
- *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
- if (*respbuflen <= 0) {
- virReportSystemError(errno,
- "%s", _("nl_recv failed"));
- rc = -1;
- }
-err_exit:
- if (rc == -1) {
- VIR_FREE(*respbuf);
- *respbuf = NULL;
- *respbuflen = 0;
- }
-
- nl_handle_destroy(nlhandle);
- return rc;
-}
# if WITH_MACVTAP
Index: libvirt-acl/src/util/netlink.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/util/netlink.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * Stefan Berger <stefanb(a)us.ibm.com>
+ *
+ * Notes:
+ * netlink: http://lovezutto.googlepages.com/netlink.pdf
+ * iproute2 package
+ *
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "netlink.h"
+#include "memory.h"
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_NET
+
+#define NETLINK_ACK_TIMEOUT_S 2
+
+/**
+ * nlComm:
+ * @nlmsg: pointer to netlink message
+ * @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
+ * buffer will be returned.
+ */
+#if __linux__
+int nlComm(struct nl_msg *nl_msg,
+ unsigned char **respbuf, unsigned int *respbuflen,
+ int nl_pid)
+{
+ int rc = 0;
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK,
+ .nl_pid = nl_pid,
+ .nl_groups = 0,
+ };
+ ssize_t nbytes;
+ struct timeval tv = {
+ .tv_sec = NETLINK_ACK_TIMEOUT_S,
+ };
+ fd_set readfds;
+ int fd;
+ int n;
+ struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
+ struct nl_handle *nlhandle = nl_handle_alloc();
+
+ if (!nlhandle) {
+ virReportSystemError(errno,
+ "%s", _("cannot allocate nlhandle for
netlink"));
+ return -1;
+ }
+
+ if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot connect to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ nlmsg_set_dst(nl_msg, &nladdr);
+
+ nlmsg->nlmsg_pid = getpid();
+
+ nbytes = nl_send_auto_complete(nlhandle, nl_msg);
+ if (nbytes < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot send to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ fd = nl_socket_get_fd(nlhandle);
+
+ 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;
+ }
+
+ *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
+ if (*respbuflen <= 0) {
+ virReportSystemError(errno,
+ "%s", _("nl_recv failed"));
+ rc = -1;
+ }
+err_exit:
+ if (rc == -1) {
+ VIR_FREE(*respbuf);
+ *respbuf = NULL;
+ *respbuflen = 0;
+ }
+
+ nl_handle_destroy(nlhandle);
+ return rc;
+}
+
+#endif /* __linux__ */
+
Index: libvirt-acl/src/util/netlink.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/util/netlink.h
@@ -0,0 +1,14 @@
+#ifndef __VIR_NETLINK_H__
+# define __VIR_NETLINK_H__
+
+# if __linux__
+
+# include <netlink/msg.h>
+
+int nlComm(struct nl_msg *nl_msg,
+ unsigned char **respbuf, unsigned int *respbuflen,
+ int nl_pid);
+
+#endif /* __linux__ */
+
+#endif /* __VIR_NETLINK_H__ */
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -668,6 +668,10 @@ virResizeN;
virShrinkN;
+#netlink.h
+nlComm;
+
+
# network.h
virSocketAddrBroadcast;
virSocketAddrBroadcastByPrefix;
13 years, 5 months
[libvirt] minor doc generation glitch
by Eric Blake
Looking at
http://libvirt.org/html/libvirt-libvirt.html#virDomainShutoffReason as
an example, I see several places where there are spurious "*" in the
generated documentation. It looks like anywhere we have:
typedef enum {
VALUE = 0; /* Multi-line
* comment */
} virName;
that the python generator is not stripping out the '^ *\*?' regex for
continued comment lines.
My python is a bit too weak to quickly determine a fix, so I'm throwing
this out for anyone else who wants an easy bug to fix.
--
Eric Blake eblake(a)redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
13 years, 5 months
[libvirt] [PATCH v2] qemu: domain I/O asynchronous handling
by Michal Privoznik
For virtio disks and interfaces, qemu allows users to enable or disable
ioeventfd feature. This means, qemu can execute domain code, while
another thread waits for I/O event. Basically, in some cases it is win,
in some loss. This feature is available via 'ioeventfd' attribute in disk
and interface <driver> element. It accepts 'on' and 'off'. Leaving this
attribute out defaults to hypervisor decision.
---
diff to v1:
-reverted to 'ioeventfd' attribute:
https://www.redhat.com/archives/libvir-list/2011-June/msg00712.html
docs/formatdomain.html.in | 34 +++++++++++++-
docs/schemas/domain.rng | 14 ++++++
src/conf/domain_conf.c | 49 +++++++++++++++++++-
src/conf/domain_conf.h | 11 ++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 13 +++++
tests/qemuhelptest.c | 3 +-
.../qemuxml2argv-disk-ioeventfd.args | 11 ++++
.../qemuxml2argv-disk-ioeventfd.xml | 50 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 4 ++
12 files changed, 191 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ab39417..39e1a85 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -785,7 +785,7 @@
</disk>
...
<disk type='network'>
- <driver name="qemu" type="raw" io="threads"/>
+ <driver name="qemu" type="raw" io="threads" ioeventfd="on"/>
<source protocol="sheepdog" name="image_name">
<host name="hostname" port="7000"/>
</source>
@@ -869,6 +869,20 @@
policies on I/O; qemu guests support "threads" and
"native". <span class="since">Since 0.8.8</span>
</li>
+ <li>
+ The optional <code>ioeventfd</code> attribute allows users to
+ set <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for disk device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span>
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </li>
</ul>
</dd>
<dt><code>boot</code></dt>
@@ -1649,7 +1663,7 @@ qemu-kvm -net nic,model=? /dev/null
<source network='default'/>
<target dev='vnet1'/>
<model type='virtio'/>
- <b><driver name='vhost' txmode='iothread'/></b>
+ <b><driver name='vhost' txmode='iothread' ioeventfd='on'/></b>
</interface>
</devices>
...</pre>
@@ -1700,6 +1714,22 @@ qemu-kvm -net nic,model=? /dev/null
<b>In general you should leave this option alone, unless you
are very certain you know what you are doing.</b>
</dd>
+ <dt><code>ioeventfd</code></dt>
+ <dd>
+ This optional attribute allows users to set
+ <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for interface device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span><br/><br/>
+
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </dd>
</dl>
<h5><a name="elementsNICSTargetOverride">Overriding the target element</a></h5>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 6de024e..891662d 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -778,6 +778,9 @@
<optional>
<ref name="driverIO"/>
</optional>
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
<empty/>
</element>
</define>
@@ -817,6 +820,14 @@
</choice>
</attribute>
</define>
+ <define name="ioeventfd">
+ <attribute name="ioeventfd">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ </define>
<define name="controller">
<element name="controller">
<choice>
@@ -1117,6 +1128,9 @@
</choice>
</attribute>
</optional>
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
<empty/>
</element>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5360863..2234857 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -163,6 +163,11 @@ VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
"default",
"native",
"threads")
+VIR_ENUM_IMPL(virDomainIoEventFd, VIR_DOMAIN_IO_EVENT_FD_LAST,
+ "default",
+ "on",
+ "off")
+
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
@@ -2013,6 +2018,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *cachetag = NULL;
char *error_policy = NULL;
char *iotag = NULL;
+ char *ioeventfd = NULL;
char *devaddr = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
@@ -2128,6 +2134,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
cachetag = virXMLPropString(cur, "cache");
error_policy = virXMLPropString(cur, "error_policy");
iotag = virXMLPropString(cur, "io");
+ ioeventfd = virXMLPropString(cur, "ioeventfd");
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -2264,6 +2271,24 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
}
+ if (ioeventfd) {
+ if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk ioeventfd mode supported "
+ "only for virtio bus"));
+ goto error;
+ }
+
+ int i;
+ if ((i = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown disk ioeventfd mode '%s'"),
+ ioeventfd);
+ goto error;
+ }
+ def->ioeventfd=i;
+ }
+
if (devaddr) {
if (virDomainParseLegacyDeviceAddress(devaddr,
&def->info.addr.pci) < 0) {
@@ -2326,6 +2351,7 @@ cleanup:
VIR_FREE(cachetag);
VIR_FREE(error_policy);
VIR_FREE(iotag);
+ VIR_FREE(ioeventfd);
VIR_FREE(devaddr);
VIR_FREE(serial);
virStorageEncryptionFree(encryption);
@@ -2713,6 +2739,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *model = NULL;
char *backend = NULL;
char *txmode = NULL;
+ char *ioeventfd = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
@@ -2802,6 +2829,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
backend = virXMLPropString(cur, "name");
txmode = virXMLPropString(cur, "txmode");
+ ioeventfd = virXMLPropString(cur, "ioeventfd");
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
filter = virXMLPropString(cur, "filter");
VIR_FREE(filterparams);
@@ -3018,6 +3046,16 @@ virDomainNetDefParseXML(virCapsPtr caps,
}
def->driver.virtio.txmode = m;
}
+ if (ioeventfd) {
+ int i;
+ if ((i = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown interface ioeventfd mode '%s'"),
+ ioeventfd);
+ goto error;
+ }
+ def->driver.virtio.ioeventfd = i;
+ }
}
if (filter != NULL) {
@@ -3057,6 +3095,7 @@ cleanup:
VIR_FREE(model);
VIR_FREE(backend);
VIR_FREE(txmode);
+ VIR_FREE(ioeventfd);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
@@ -8291,6 +8330,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
const char *iomode = virDomainDiskIoTypeToString(def->iomode);
+ const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -8322,7 +8362,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
" <disk type='%s' device='%s'>\n",
type, device);
- if (def->driverName || def->driverType || def->cachemode) {
+ if (def->driverName || def->driverType || def->cachemode ||
+ def->ioeventfd) {
virBufferAsprintf(buf, " <driver");
if (def->driverName)
virBufferAsprintf(buf, " name='%s'", def->driverName);
@@ -8334,6 +8375,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " error_policy='%s'", error_policy);
if (def->iomode)
virBufferAsprintf(buf, " io='%s'", iomode);
+ if (def->ioeventfd)
+ virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
virBufferAsprintf(buf, "/>\n");
}
@@ -8624,6 +8667,10 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " txmode='%s'",
virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
}
+ if (def->driver.virtio.ioeventfd) {
+ virBufferAsprintf(buf, " ioeventfd='%s'",
+ virDomainIoEventFdTypeToString(def->driver.virtio.ioeventfd));
+ }
virBufferAddLit(buf, "/>\n");
}
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ff5c28d..994ff91 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -206,6 +206,14 @@ enum virDomainDiskIo {
VIR_DOMAIN_DISK_IO_LAST
};
+enum virDomainIoEventFd {
+ VIR_DOMAIN_IO_EVENT_FD_DEFAULT = 0,
+ VIR_DOMAIN_IO_EVENT_FD_ON,
+ VIR_DOMAIN_IO_EVENT_FD_OFF,
+
+ VIR_DOMAIN_IO_EVENT_FD_LAST
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -225,6 +233,7 @@ struct _virDomainDiskDef {
int error_policy;
int bootIndex;
int iomode;
+ int ioeventfd;
unsigned int readonly : 1;
unsigned int shared : 1;
virDomainDeviceInfo info;
@@ -361,6 +370,7 @@ struct _virDomainNetDef {
struct {
enum virDomainNetBackendType name; /* which driver backend to use */
enum virDomainNetVirtioTxModeType txmode;
+ enum virDomainIoEventFd ioeventfd;
} virtio;
} driver;
union {
@@ -1554,6 +1564,7 @@ VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainDiskProtocol)
VIR_ENUM_DECL(virDomainDiskIo)
+VIR_ENUM_DECL(virDomainIoEventFd)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 03d2ddb..5c8d272 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -292,6 +292,8 @@ virDomainHostdevDefFree;
virDomainHostdevModeTypeToString;
virDomainHostdevSubsysTypeToString;
virDomainInputDefFree;
+virDomainIoEventFdTypeFromString;
+virDomainIoEventFdTypeToString;
virDomainLeaseIndex;
virDomainLeaseInsert;
virDomainLeaseInsertPreAlloc;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 28c89b5..ad62a07 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -121,6 +121,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"device-qxl-vga",
"pci-multifunction", /* 60 */
+ "virtio-blk-pci.ioeventfd",
);
struct qemu_feature_flags {
@@ -1207,6 +1208,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
qemuCapsSet(flags, QEMU_CAPS_VIRTIO_TX_ALG);
if (strstr(str, "name \"qxl-vga\""))
qemuCapsSet(flags, QEMU_CAPS_DEVICE_QXL_VGA);
+ if (strstr(str, "virtio-blk-pci.ioeventfd"))
+ qemuCapsSet(flags, QEMU_CAPS_VIRTIO_IOEVENTFD);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index e6d2fa3..0b9c8be 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -96,6 +96,7 @@ enum qemuCapsFlags {
QEMU_CAPS_VIRTIO_TX_ALG = 58, /* -device virtio-net-pci,tx=string */
QEMU_CAPS_DEVICE_QXL_VGA = 59, /* Is the primary and vga campatible qxl device named qxl-vga? */
QEMU_CAPS_PCI_MULTIFUNCTION = 60, /* -device multifunction=on|off */
+ QEMU_CAPS_VIRTIO_IOEVENTFD = 61, /* IOeventFD feature: virtio-{net|blk}-pci.ioeventfd=on/off */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6346243..f7c06f8 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1287,6 +1287,16 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
return 0;
}
+static int
+qemuBuildIoEventFdStr(virBufferPtr buf,
+ enum virDomainIoEventFd use,
+ virBitmapPtr qemuCaps)
+{
+ if (use && qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
+ virBufferAsprintf(buf, ",ioeventfd=%s",
+ virDomainIoEventFdTypeToString(use));
+ return 0;
+}
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
@@ -1554,6 +1564,7 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
virBufferAddLit(&opt, "virtio-blk-pci");
+ qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps);
break;
case VIR_DOMAIN_DISK_BUS_USB:
@@ -1777,6 +1788,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
goto error;
}
}
+ if (usingVirtio)
+ qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps);
if (vlan == -1)
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
else
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 327a0c7..119e771 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -475,7 +475,8 @@ mymain(void)
QEMU_CAPS_CCID_PASSTHRU,
QEMU_CAPS_CHARDEV_SPICEVMC,
QEMU_CAPS_DEVICE_QXL_VGA,
- QEMU_CAPS_VIRTIO_TX_ALG);
+ QEMU_CAPS_VIRTIO_TX_ALG,
+ QEMU_CAPS_VIRTIO_IOEVENTFD);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
new file mode 100644
index 0000000..c512f15
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
@@ -0,0 +1,11 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc-0.13 -m 1024 -smp 1 -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi \
+-boot dc -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
+-drive file=/var/lib/libvirt/images/f14.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,ioeventfd=on,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-device virtio-net-pci,tx=bh,ioeventfd=off,vlan=0,id=net0,mac=52:54:00:e5:48:58,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 -serial pty -usb -vnc 127.0.0.1:-809 -std-vga \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
new file mode 100644
index 0000000..c565c9f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
@@ -0,0 +1,50 @@
+<domain type='qemu'>
+ <name>test</name>
+ <memory>1048576</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-0.13'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2' ioeventfd='on'/>
+ <source file='/var/lib/libvirt/images/f14.img'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <interface type='user'>
+ <mac address='52:54:00:e5:48:58'/>
+ <model type='virtio'/>
+ <driver name='vhost' txmode='iothread' ioeventfd='off'/>
+ </interface>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </controller>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <graphics type='vnc' port='5091' autoport='no' listen='127.0.0.1'/>
+ <video>
+ <model type='vga' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index bd07efa..782664a 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -350,6 +350,10 @@ mymain(void)
DO_TEST("disk-aio", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_AIO,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT);
+ DO_TEST("disk-ioeventfd", false,
+ QEMU_CAPS_DRIVE, QEMU_CAPS_VIRTIO_IOEVENTFD,
+ QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE);
+
DO_TEST("graphics-vnc", false, NONE);
DO_TEST("graphics-vnc-socket", false, NONE);
--
1.7.5.rc3
13 years, 5 months
[libvirt] [PATCH v4]: set and restore MAC address of a NIC when using PASSTHROUGH mode
by Gerhard Stenzel
Next try ..
The following patch addresses the problem that when a PASSTHROUGH
mode DIRECT NIC connection is made the MAC address of the NIC is
not automatically set and reset to the configured VM MAC and
back again.
The attached patch fixes this problem by setting and resetting the MAC
while remembering the previous setting while the VM is running.
This also works if libvirtd is restarted while the VM is running.
the patch passes make syntax-check
Signed-off-by: Dirk Herrendoerfer <d.herrendoerfer at herrendoerfer.name>
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
---
Index: libvirt/src/qemu/qemu_command.c
===================================================================
--- libvirt.orig/src/qemu/qemu_command.c
+++ libvirt/src/qemu/qemu_command.c
@@ -128,7 +128,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def
rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
net->data.direct.mode, vnet_hdr, def->uuid,
&net->data.direct.virtPortProfile, &res_ifname,
- vmop);
+ vmop, driver->stateDir);
if (rc >= 0) {
qemuAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname);
@@ -149,7 +149,9 @@ qemuPhysIfaceConnect(virDomainDefPtr def
if (err) {
VIR_FORCE_CLOSE(rc);
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/qemu/qemu_process.c
===================================================================
--- libvirt.orig/src/qemu/qemu_process.c
+++ libvirt/src/qemu/qemu_process.c
@@ -2876,7 +2876,8 @@ void qemuProcessStop(struct qemud_driver
virDomainNetDefPtr net = def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile, driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/util/macvtap.c
===================================================================
--- libvirt.orig/src/util/macvtap.c
+++ libvirt/src/util/macvtap.c
@@ -545,6 +545,104 @@ configMacvtapTap(int tapfd, int vnet_hdr
return 0;
}
+/**
+ * replaceMacAdress:
+ * @macaddress: new MAC address for interface
+ * @linkdev: name of interface
+ * @stateDir: directory to store old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+static int
+replaceMacAdress(const unsigned char *macaddress,
+ const char *linkdev,
+ char *stateDir)
+{
+ unsigned char oldmac[6];
+ int rc;
+
+ rc = ifaceGetMacaddr(linkdev, oldmac);
+
+ if (rc) {
+ virReportSystemError(rc,
+ _("Getting MAC address from '%s' "
+ "to '%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ oldmac[0], oldmac[1], oldmac[2],
+ oldmac[3], oldmac[4], oldmac[5]);
+ } else {
+ char *path = NULL;
+ char macstr[VIR_MAC_STRING_BUFLEN];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return errno;
+ }
+ virFormatMacAddr(oldmac, macstr);
+ if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
+ virReportSystemError(errno, _("Unable to preserve mac for %s"),
+ linkdev);
+ return errno;
+ }
+ }
+
+ rc = ifaceSetMacaddr(linkdev, macaddress);
+ if (rc) {
+ virReportSystemError(errno,
+ _("Setting MAC address on '%s' to "
+ "'%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ macaddress[0], macaddress[1], macaddress[2],
+ macaddress[3], macaddress[4], macaddress[5]);
+ }
+ return rc;
+}
+
+/**
+ * restoreMacAddress:
+ * @linkdev: name of interface
+ * @stateDir: directory containing old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+static int
+restoreMacAddress(const char *linkdev,
+ char *stateDir)
+{
+ int ret;
+ char *oldmacname = NULL;
+ char *macstr = NULL;
+ char *path = NULL;
+ unsigned char oldmac[6];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) {
+ return errno;
+ }
+
+ if (virParseMacAddr(macstr, &oldmac[0]) != 0) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse MAC address from '%s'"),
+ oldmacname);
+ return -1;
+ }
+
+ /*reset mac and remove file-ignore results*/
+ ignore_value(ifaceSetMacaddr(linkdev, oldmac));
+ ignore_value(unlink(path));
+ VIR_FREE(macstr);
+ return 0;
+}
/**
* openMacvtapTap:
@@ -575,7 +673,8 @@ openMacvtapTap(const char *tgifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmOp)
+ enum virVMOperationType vmOp,
+ char *stateDir)
{
const char *type = "macvtap";
int c, rc;
@@ -589,6 +688,19 @@ openMacvtapTap(const char *tgifname,
VIR_DEBUG("%s: VM OPERATION: %s", __FUNCTION__, virVMOperationTypeToString(vmOp));
+ /** Note: When using PASSTHROUGH mode with MACVTAP devices the link
+ * device's MAC address must be set to the VMs MAC address. In
+ * order to not confuse the first switch or bridge in line this MAC
+ * address must be reset when the VM is shut down.
+ * This is especially important when using SRIOV capable cards that
+ * emulate their switch in firmware.
+ */
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) {
+ return -1;
+ }
+ }
+
if (tgifname) {
if(ifaceGetIndex(false, tgifname, &ifindex) == 0) {
if (STRPREFIX(tgifname,
@@ -684,8 +796,14 @@ void
delMacvtap(const char *ifname,
const unsigned char *macaddr,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile)
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir)
{
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ restoreMacAddress(linkdev, stateDir);
+ }
+
if (ifname) {
vpDisassociatePortProfileId(ifname, macaddr,
linkdev,
Index: libvirt/src/util/macvtap.h
===================================================================
--- libvirt.orig/src/util/macvtap.h
+++ libvirt/src/util/macvtap.h
@@ -83,12 +83,15 @@ int openMacvtapTap(const char *ifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmop);
+ enum virVMOperationType vmop,
+ char *stateDir);
void delMacvtap(const char *ifname,
const unsigned char *macaddress,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile);
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir);
int vpAssociatePortProfileId(const char *macvtap_ifname,
const unsigned char *macvtap_macaddr,
Index: libvirt/src/qemu/qemu_hotplug.c
===================================================================
--- libvirt.orig/src/qemu/qemu_hotplug.c
+++ libvirt/src/qemu/qemu_hotplug.c
@@ -1610,7 +1610,9 @@ int qemuDomainDetachNetDevice(struct qem
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
- &detach->data.direct.virtPortProfile);
+ detach->data.direct.mode,
+ &detach->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(detach->ifname);
}
#endif
Index: libvirt/src/util/interface.c
===================================================================
--- libvirt.orig/src/util/interface.c
+++ libvirt/src/util/interface.c
@@ -390,3 +390,99 @@ ifaceGetVlanID(const char *vlanifname AT
return ENOSYS;
}
#endif /* __linux__ */
+
+/**
+ * ifaceGetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function gets the @macaddr for a given interface @ifname.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceGetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ if (ioctl(fd, SIOCGIFHWADDR, (char *)&ifr) != 0)
+ return errno;
+
+ memcpy(macaddr, ifr.ifr_ifru.ifru_hwaddr.sa_data, VIR_MAC_BUFLEN);
+
+ return 0;
+}
+
+#else
+
+int
+ifaceGetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
+
+/**
+ * ifaceSetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function sets the @macaddr for a given interface @ifname. This
+ * gets rid of the kernel's automatically assigned random MAC.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceSetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ const unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ /* To fill ifr.ifr_hdaddr.sa_family field */
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
+ return errno;
+
+ memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
+
+ return ioctl(fd, SIOCSIFHWADDR, &ifr) == 0 ? 0 : errno;
+}
+
+#else
+
+int
+ifaceSetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ const unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
Index: libvirt/src/util/interface.h
===================================================================
--- libvirt.orig/src/util/interface.h
+++ libvirt/src/util/interface.h
@@ -32,4 +32,8 @@ int ifaceGetIndex(bool reportError, cons
int ifaceGetVlanID(const char *vlanifname, int *vlanid);
+int ifaceSetMacaddr(const char *ifname, const unsigned char *macaddr);
+
+int ifaceGetMacaddr(const char *ifname, unsigned char *macaddr);
+
#endif /* __VIR_INTERFACE_H__ */
Index: libvirt/src/libvirt_private.syms
===================================================================
--- libvirt.orig/src/libvirt_private.syms
+++ libvirt/src/libvirt_private.syms
@@ -507,7 +507,9 @@ ifaceCheck;
ifaceCtrl;
ifaceGetFlags;
ifaceGetIndex;
+ifaceGetMacaddr;
ifaceGetVlanID;
+ifaceSetMacaddr;
ifaceIsUp;
===================================================================
Best regards,
Gerhard Stenzel
-------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
13 years, 5 months