mirror of https://gitee.com/openkylin/libvirt.git
conf: new "managed" attribute for target dev of <interface type='ethernet'>
Although <interface type='ethernet'> has always been able to use an existing tap device, this is just a coincidence due to the fact that the same ioctl is used to create a new tap device or get a handle to an existing device. Even then, once we have the handle to the device, we still insist on doing extra setup to it (setting the MAC address and IFF_UP). That *might* be okay if libvirtd is running as a privileged process, but if libvirtd is running as an unprivileged user, those attempted modifications to the tap device will fail (yes, even if the tap is set to be owned by the user running libvirtd). We could avoid this if we knew that the device already existed, but as stated above, an existing device and new device are both accessed in the same manner, and anyway, we need to preserve existing behavior for those who are already using pre-existing devices with privileged libvirtd (and allowing/expecting libvirt to configure the pre-existing device). In order to cleanly support the idea of using a pre-existing and pre-configured tap device, this patch introduces a new optional attribute "managed" for the interface <target> element. This attribute is only valid for <interface type='ethernet'> (since all other interface types have mandatory config that doesn't apply in the case where we expect the tap device to be setup before we get it). The syntax would look something like this: <interface type='ethernet'> <target dev='mytap0' managed='no'/> ... </interface> This patch just adds managed to the grammar and parser for <target>, but has no functionality behind it. (NB: when managed='no' (the default when not specified is 'yes'), the target dev is always a name explicitly provided, so we don't auto-remove it from the config just because it starts with "vnet" (VIR_NET_GENERATED_TAP_PREFIX); this makes it possible to use the same pattern of names that libvirt itself uses when it automatically creates the tap devices.) Signed-off-by: Laine Stump <laine@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
33d02dfca6
commit
77f72a8615
|
@ -5511,23 +5511,51 @@
|
||||||
<h5><a id="elementsNICSEthernet">Generic ethernet connection</a></h5>
|
<h5><a id="elementsNICSEthernet">Generic ethernet connection</a></h5>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Provides a means for the administrator to execute an arbitrary script
|
Provides a means to use a new or existing tap device (or veth
|
||||||
to connect the guest's network to the LAN. The guest will have a tun
|
device pair, depening on the needs of the hypervisor driver)
|
||||||
device created with a name of vnetN, which can also be overridden with the
|
that is partially or wholly setup external to libvirt (either
|
||||||
<target> element. After creating the tun device a shell script will
|
prior to the guest starting, or while the guest is being started
|
||||||
be run which is expected to do whatever host network integration is
|
via an optional script specified in the config).
|
||||||
required. By default this script is called /etc/qemu-ifup but can be
|
</p>
|
||||||
overridden.
|
<p>
|
||||||
|
The name of the tap device can optionally be specified with
|
||||||
|
the <code>dev</code> attribute of the
|
||||||
|
<code><target></code> element. If no target dev is
|
||||||
|
specified, libvirt will create a new standard tap device with a
|
||||||
|
name of the pattern "vnetN", where "N" is replaced with a
|
||||||
|
number. If a target dev is specified and that device doesn't
|
||||||
|
exist, then a new standard tap device will be created with the
|
||||||
|
exact dev name given. If the specified target dev does exist,
|
||||||
|
then that existing device will be used. Usually some basic setup
|
||||||
|
of the device is done by libvirt, including setting a MAC
|
||||||
|
address, and the IFF_UP flag, but if the <code>dev</code> is a
|
||||||
|
pre-existing device, and the <code>managed</code> attribute of
|
||||||
|
the <code>target</code> element is also set to "no" (the default
|
||||||
|
value is "yes"), even this basic setup will not be performed -
|
||||||
|
libvirt will simply pass the device on to the hypervisor with no
|
||||||
|
setup at all. <span class="since">Since 5.7.0</span> Using
|
||||||
|
managed='no' with a pre-created tap device is useful because
|
||||||
|
it permits a virtual machine managed by an unprivileged libvirtd
|
||||||
|
to have emulated network devices based on tap devices.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
After creating/opening the tap device, an optional shell script
|
||||||
|
(given in the <code>path</code> attribute of
|
||||||
|
the <code><script></code> element) will be run; this can
|
||||||
|
be used to do whatever extra host network integration is
|
||||||
|
required.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
<devices>
|
<devices>
|
||||||
<interface type='ethernet'/>
|
<interface type='ethernet'>
|
||||||
|
<script path='/etc/qemu-ifup-mynet'/>
|
||||||
|
</interface>
|
||||||
...
|
...
|
||||||
<interface type='ethernet'>
|
<interface type='ethernet'>
|
||||||
<target dev='vnet7'/>
|
<target dev='mytap1' managed='no'/>
|
||||||
<script path='/etc/qemu-ifup-mynet'/>
|
<model type='virtio'/>
|
||||||
</interface>
|
</interface>
|
||||||
</devices>
|
</devices>
|
||||||
...</pre>
|
...</pre>
|
||||||
|
|
|
@ -2885,6 +2885,11 @@
|
||||||
<attribute name="dev">
|
<attribute name="dev">
|
||||||
<ref name="deviceName"/>
|
<ref name="deviceName"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<optional>
|
||||||
|
<attribute name="managed">
|
||||||
|
<ref name="virYesNo"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
|
|
@ -6112,6 +6112,14 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
||||||
virDomainNetTypeToString(net->type));
|
virDomainNetTypeToString(net->type));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (net->managed_tap == VIR_TRISTATE_BOOL_NO &&
|
||||||
|
net->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("unmanaged target dev is not supported on "
|
||||||
|
"interfaces of type '%s'"),
|
||||||
|
virDomainNetTypeToString(net->type));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11421,6 +11429,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||||
VIR_AUTOFREE(char *) bridge = NULL;
|
VIR_AUTOFREE(char *) bridge = NULL;
|
||||||
VIR_AUTOFREE(char *) dev = NULL;
|
VIR_AUTOFREE(char *) dev = NULL;
|
||||||
VIR_AUTOFREE(char *) ifname = NULL;
|
VIR_AUTOFREE(char *) ifname = NULL;
|
||||||
|
VIR_AUTOFREE(char *) managed_tap = NULL;
|
||||||
VIR_AUTOFREE(char *) ifname_guest = NULL;
|
VIR_AUTOFREE(char *) ifname_guest = NULL;
|
||||||
VIR_AUTOFREE(char *) ifname_guest_actual = NULL;
|
VIR_AUTOFREE(char *) ifname_guest_actual = NULL;
|
||||||
VIR_AUTOFREE(char *) script = NULL;
|
VIR_AUTOFREE(char *) script = NULL;
|
||||||
|
@ -11583,13 +11592,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||||
} else if (!ifname &&
|
} else if (!ifname &&
|
||||||
virXMLNodeNameEqual(cur, "target")) {
|
virXMLNodeNameEqual(cur, "target")) {
|
||||||
ifname = virXMLPropString(cur, "dev");
|
ifname = virXMLPropString(cur, "dev");
|
||||||
if (ifname &&
|
managed_tap = virXMLPropString(cur, "managed");
|
||||||
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
|
||||||
(STRPREFIX(ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
|
||||||
(prefix && STRPREFIX(ifname, prefix)))) {
|
|
||||||
/* An auto-generated target name, blank it out */
|
|
||||||
VIR_FREE(ifname);
|
|
||||||
}
|
|
||||||
} else if ((!ifname_guest || !ifname_guest_actual) &&
|
} else if ((!ifname_guest || !ifname_guest_actual) &&
|
||||||
virXMLNodeNameEqual(cur, "guest")) {
|
virXMLNodeNameEqual(cur, "guest")) {
|
||||||
ifname_guest = virXMLPropString(cur, "dev");
|
ifname_guest = virXMLPropString(cur, "dev");
|
||||||
|
@ -11923,6 +11926,27 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||||
ctxt, &def->guestIP) < 0)
|
ctxt, &def->guestIP) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (managed_tap) {
|
||||||
|
if (STREQ(managed_tap, "no")) {
|
||||||
|
def->managed_tap = VIR_TRISTATE_BOOL_NO;
|
||||||
|
} else if (STREQ(managed_tap, "yes")) {
|
||||||
|
def->managed_tap = VIR_TRISTATE_BOOL_YES;
|
||||||
|
} else {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR,
|
||||||
|
_("invalid 'managed' value '%s'"),
|
||||||
|
managed_tap);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && ifname &&
|
||||||
|
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
||||||
|
(STRPREFIX(ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
||||||
|
(prefix && STRPREFIX(ifname, prefix)))) {
|
||||||
|
/* An auto-generated target name, blank it out */
|
||||||
|
VIR_FREE(ifname);
|
||||||
|
}
|
||||||
|
|
||||||
if (script != NULL)
|
if (script != NULL)
|
||||||
VIR_STEAL_PTR(def->script, script);
|
VIR_STEAL_PTR(def->script, script);
|
||||||
if (domain_name != NULL)
|
if (domain_name != NULL)
|
||||||
|
@ -25550,12 +25574,17 @@ virDomainNetDefFormat(virBufferPtr buf,
|
||||||
virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);
|
virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);
|
||||||
|
|
||||||
if (def->ifname &&
|
if (def->ifname &&
|
||||||
!((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
|
(def->managed_tap == VIR_TRISTATE_BOOL_NO ||
|
||||||
(STRPREFIX(def->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
!((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
|
||||||
(prefix && STRPREFIX(def->ifname, prefix))))) {
|
(STRPREFIX(def->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
||||||
|
(prefix && STRPREFIX(def->ifname, prefix)))))) {
|
||||||
/* Skip auto-generated target names for inactive config. */
|
/* Skip auto-generated target names for inactive config. */
|
||||||
virBufferEscapeString(&attrBuf, " dev='%s'", def->ifname);
|
virBufferEscapeString(&attrBuf, " dev='%s'", def->ifname);
|
||||||
}
|
}
|
||||||
|
if (def->managed_tap != VIR_TRISTATE_BOOL_ABSENT) {
|
||||||
|
virBufferAsprintf(&attrBuf, " managed='%s'",
|
||||||
|
virTristateBoolTypeToString(def->managed_tap));
|
||||||
|
}
|
||||||
|
|
||||||
if (virXMLFormatElement(buf, "target", &attrBuf, NULL) < 0)
|
if (virXMLFormatElement(buf, "target", &attrBuf, NULL) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1004,6 +1004,7 @@ struct _virDomainNetDef {
|
||||||
char *script;
|
char *script;
|
||||||
char *domain_name; /* backend domain name */
|
char *domain_name; /* backend domain name */
|
||||||
char *ifname; /* interface name on the host (<target dev='x'/>) */
|
char *ifname; /* interface name on the host (<target dev='x'/>) */
|
||||||
|
int managed_tap; /* enum virTristateBool - ABSENT == YES */
|
||||||
virNetDevIPInfo hostIP;
|
virNetDevIPInfo hostIP;
|
||||||
char *ifname_guest_actual;
|
char *ifname_guest_actual;
|
||||||
char *ifname_guest;
|
char *ifname_guest;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<domain type='qemu'>
|
||||||
|
<name>QEMUGuest1</name>
|
||||||
|
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||||
|
<memory unit='KiB'>219100</memory>
|
||||||
|
<currentMemory unit='KiB'>219100</currentMemory>
|
||||||
|
<vcpu placement='static'>1</vcpu>
|
||||||
|
<os>
|
||||||
|
<type arch='i686' machine='pc'>hvm</type>
|
||||||
|
<boot dev='hd'/>
|
||||||
|
</os>
|
||||||
|
<clock offset='utc'/>
|
||||||
|
<on_poweroff>destroy</on_poweroff>
|
||||||
|
<on_reboot>restart</on_reboot>
|
||||||
|
<on_crash>destroy</on_crash>
|
||||||
|
<devices>
|
||||||
|
<emulator>/usr/bin/qemu-system-i686</emulator>
|
||||||
|
<disk type='block' device='disk'>
|
||||||
|
<driver name='qemu' type='raw'/>
|
||||||
|
<source dev='/dev/HostVG/QEMUGuest1'/>
|
||||||
|
<target dev='hda' bus='ide'/>
|
||||||
|
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||||
|
</disk>
|
||||||
|
<controller type='usb' index='0'/>
|
||||||
|
<controller type='ide' index='0'/>
|
||||||
|
<controller type='pci' index='0' model='pci-root'/>
|
||||||
|
<interface type='ethernet'>
|
||||||
|
<mac address='fe:11:22:33:44:55'/>
|
||||||
|
<target dev='mytap0' managed='no'/>
|
||||||
|
<model type='virtio'/>
|
||||||
|
</interface>
|
||||||
|
<input type='mouse' bus='ps2'/>
|
||||||
|
<input type='keyboard' bus='ps2'/>
|
||||||
|
<memballoon model='none'/>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<domain type='qemu'>
|
||||||
|
<name>QEMUGuest1</name>
|
||||||
|
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||||
|
<memory unit='KiB'>219100</memory>
|
||||||
|
<currentMemory unit='KiB'>219100</currentMemory>
|
||||||
|
<vcpu placement='static'>1</vcpu>
|
||||||
|
<os>
|
||||||
|
<type arch='i686' machine='pc'>hvm</type>
|
||||||
|
<boot dev='hd'/>
|
||||||
|
</os>
|
||||||
|
<clock offset='utc'/>
|
||||||
|
<on_poweroff>destroy</on_poweroff>
|
||||||
|
<on_reboot>restart</on_reboot>
|
||||||
|
<on_crash>destroy</on_crash>
|
||||||
|
<devices>
|
||||||
|
<emulator>/usr/bin/qemu-system-i686</emulator>
|
||||||
|
<disk type='block' device='disk'>
|
||||||
|
<driver name='qemu' type='raw'/>
|
||||||
|
<source dev='/dev/HostVG/QEMUGuest1'/>
|
||||||
|
<target dev='hda' bus='ide'/>
|
||||||
|
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||||
|
</disk>
|
||||||
|
<controller type='usb' index='0'>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
|
||||||
|
</controller>
|
||||||
|
<controller type='ide' index='0'>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
|
||||||
|
</controller>
|
||||||
|
<controller type='pci' index='0' model='pci-root'/>
|
||||||
|
<interface type='ethernet'>
|
||||||
|
<mac address='fe:11:22:33:44:55'/>
|
||||||
|
<target dev='mytap0' managed='no'/>
|
||||||
|
<model type='virtio'/>
|
||||||
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
||||||
|
</interface>
|
||||||
|
<input type='mouse' bus='ps2'/>
|
||||||
|
<input type='keyboard' bus='ps2'/>
|
||||||
|
<memballoon model='none'/>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
|
@ -408,6 +408,7 @@ mymain(void)
|
||||||
DO_TEST("net-eth", NONE);
|
DO_TEST("net-eth", NONE);
|
||||||
DO_TEST("net-eth-ifname", NONE);
|
DO_TEST("net-eth-ifname", NONE);
|
||||||
DO_TEST("net-eth-hostip", NONE);
|
DO_TEST("net-eth-hostip", NONE);
|
||||||
|
DO_TEST("net-eth-unmanaged-tap", NONE);
|
||||||
DO_TEST("net-virtio-network-portgroup", NONE);
|
DO_TEST("net-virtio-network-portgroup", NONE);
|
||||||
DO_TEST("net-virtio-rxtxqueuesize", NONE);
|
DO_TEST("net-virtio-rxtxqueuesize", NONE);
|
||||||
DO_TEST("net-hostdev", NONE);
|
DO_TEST("net-hostdev", NONE);
|
||||||
|
|
Loading…
Reference in New Issue