On 03/27/2014 07:17 PM, Michal Privoznik wrote: > We allow users to use SLIRP stack. However, there are some knobs > which are not exposed to users, such as host network address, DNS > server, smb, and others. > > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- > docs/formatdomain.html.in | 7 +- > docs/schemas/domaincommon.rng | 23 +++++- > src/conf/domain_conf.c | 88 ++++++++++++++++++++++ > src/conf/domain_conf.h | 6 ++ > src/qemu/qemu_command.c | 19 +++++ > .../qemuxml2argvdata/qemuxml2argv-net-user-ip.args | 7 ++ > .../qemuxml2argvdata/qemuxml2argv-net-user-ip.xml | 33 ++++++++ > tests/qemuxml2argvtest.c | 1 + > 8 files changed, 180 insertions(+), 4 deletions(-) > create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.args > create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.xml It is essential that this new <ip> element be rejected, preferably at parse time in the qemu-specific post-parse callback, for any interface type that doesn't support it. Since it is the most obvious way of specifying an IP address for a guest (and it is a way that has been requested in the past) we are otherwise certain to have a lot of support questions asking why the IP address setting isn't being used. Also, the attribute names seem confusing. The "address" attribute is the address of the *network*, not of the interface, and "dhcpstart" is the address of the interface. Even though qemu specifies the network address and interface address separately, the network address is really pointless, as it can/should be derived from the interface address. (I realize that "dhcpstart" isn't *exactly* the interface IP, since qemu allows for multiple IP leases to be acquired from it's internal dhcp server, but I think that usage is very rare, and unlikely to be possible for any other backend we might support). Beyond that, a question not with your patch, but with qemu's implemenation - does it always assume that the gateway address is $network.1 ? If that's the case, then I think definitely we should just have <ip address='x' prefix='y'/>. If there is support for specifying the gateway address, then it should be named "gateway", as is already done in the network xml for static routes. > > diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in > index 7f90455..0a353ca 100644 > --- a/docs/formatdomain.html.in > +++ b/docs/formatdomain.html.in > @@ -3225,7 +3225,11 @@ > starting from <code>10.0.2.15</code>. The default router will be > <code>10.0.2.2</code> and the DNS server will be <code>10.0.2.3</code>. > This networking is the only option for unprivileged users who need their > - VMs to have outgoing access. > + VMs to have outgoing access. <span class="since">Since 1.2.3</span> the > + user network can have the <ip/> element to override the default > + network of <code>10.0.2.0/24</code>. For example it can be set to > + <code>192.168.2.0/24</code>. The whole element and its attributes are > + optional. > </p> > > <pre> > @@ -3235,6 +3239,7 @@ > ... > <interface type='user'> > <mac address="00:11:22:33:44:55"/> > + <ip address="192.168.2.0" prefix="24" dns="192.168.2.3" dhcpstart="192.168.2.9"/> > </interface> > </devices> > ...</pre> > diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng > index bcd8142..5745ce7 100644 > --- a/docs/schemas/domaincommon.rng > +++ b/docs/schemas/domaincommon.rng > @@ -2152,9 +2152,26 @@ > </optional> > <optional> > <element name="ip"> > - <attribute name="address"> > - <ref name="ipv4Addr"/> > - </attribute> > + <optional> > + <attribute name="address"> > + <ref name="ipv4Addr"/> > + </attribute> > + </optional> > + <optional> > + <attribute name="prefix"> > + <data type="integer"/> > + </attribute> > + </optional> > + <optional> > + <attribute name="dns"> > + <ref name="ipv4Addr"/> > + </attribute> > + </optional> > + <optional> > + <attribute name="dhcpstart"> > + <ref name="ipv4Addr"/> > + </attribute> > + </optional> > <empty/> > </element> > </optional> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 6fb216e..aec14ed 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -1539,6 +1539,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def) > break; > > case VIR_DOMAIN_NET_TYPE_USER: > + VIR_FREE(def->data.user.ipaddr); > + VIR_FREE(def->data.user.dns); > + VIR_FREE(def->data.user.dhcpstart); > + break; > + > case VIR_DOMAIN_NET_TYPE_LAST: > break; > } > @@ -6669,6 +6674,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > char *mode = NULL; > char *linkstate = NULL; > char *addrtype = NULL; > + char *prefix = NULL; > + char *dns = NULL; > + char *dhcpstart = NULL; > virNWFilterHashTablePtr filterparams = NULL; > virDomainActualNetDefPtr actual = NULL; > xmlNodePtr oldnode = ctxt->node; > @@ -6750,6 +6758,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) && > xmlStrEqual(cur->name, BAD_CAST "ip")) { > address = virXMLPropString(cur, "address"); > + } else if (!address && > + def->type == VIR_DOMAIN_NET_TYPE_USER && > + xmlStrEqual(cur->name, BAD_CAST "ip")) { > + address = virXMLPropString(cur, "address"); > + prefix = virXMLPropString(cur, "prefix"); > + dns = virXMLPropString(cur, "dns"); > + dhcpstart = virXMLPropString(cur, "dhcpstart"); > } else if (!ifname && > xmlStrEqual(cur->name, BAD_CAST "target")) { > ifname = virXMLPropString(cur, "dev"); > @@ -6988,6 +7003,59 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > break; > > case VIR_DOMAIN_NET_TYPE_USER: > + if (prefix) { > + if (!address) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("can't use prefix without an address")); > + goto error; > + } > + > + if (virStrToLong_i(prefix, NULL, 10, &def->data.user.prefix) < 0 || > + def->data.user.prefix < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("Invalid prefix: '%s'"), prefix); > + goto error; > + } > + } else { > + def->data.user.prefix = -1; > + } > + > + if (address) { > + if (virSocketAddrParse(NULL, address, AF_UNSPEC) < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("Invalid address: '%s'"), address); > + goto error; > + } > + > + def->data.user.ipaddr = address; > + address = NULL; > + } > + > + if (dns) { > + if (virSocketAddrParse(NULL, dns, AF_UNSPEC) < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("Invalid dns address: '%s'"), dns); > + goto error; > + } > + > + def->data.user.dns = dns; > + dns = NULL; > + } > + > + if (dhcpstart) { > + if (virSocketAddrParse(NULL, dhcpstart, AF_UNSPEC) < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("Invalid dhcpstart address: '%s'"), > + dhcpstart); > + goto error; > + } > + > + def->data.user.dhcpstart = dhcpstart; > + dhcpstart = NULL; > + } > + > + break; > + > case VIR_DOMAIN_NET_TYPE_LAST: > break; > } > @@ -7134,6 +7202,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > VIR_FREE(mode); > VIR_FREE(linkstate); > VIR_FREE(addrtype); > + VIR_FREE(prefix); > + VIR_FREE(dns); > + VIR_FREE(dhcpstart); > virNWFilterHashTableFree(filterparams); > > return def; > @@ -15766,6 +15837,23 @@ virDomainNetDefFormat(virBufferPtr buf, > break; > > case VIR_DOMAIN_NET_TYPE_USER: > + if (def->data.user.ipaddr || > + def->data.user.dns || > + def->data.user.dhcpstart) { > + virBufferAddLit(buf, "<ip"); > + > + if (def->data.user.ipaddr) { > + virBufferAsprintf(buf, " address='%s'", def->data.user.ipaddr); > + if (def->data.user.prefix >= 0) > + virBufferAsprintf(buf, " prefix='%d'", def->data.user.prefix); > + } > + > + virBufferEscapeString(buf, " dns='%s'", def->data.user.dns); > + virBufferEscapeString(buf, " dhcpstart='%s'", def->data.user.dhcpstart); > + virBufferAddLit(buf, "/>\n"); > + } > + break; > + > case VIR_DOMAIN_NET_TYPE_LAST: > break; > } > diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h > index f3f24c4..b5d52e9 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -1046,6 +1046,12 @@ struct _virDomainNetDef { > struct { > virDomainHostdevDef def; > } hostdev; > + struct { > + char *ipaddr; > + int prefix; > + char *dns; > + char *dhcpstart; > + } user; > } data; > /* virtPortProfile is used by network/bridge/direct/hostdev */ > virNetDevVPortProfilePtr virtPortProfile; > diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > index 9a314bf..f17061e 100644 > --- a/src/qemu/qemu_command.c > +++ b/src/qemu/qemu_command.c > @@ -5156,6 +5156,25 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, > break; > > case VIR_DOMAIN_NET_TYPE_USER: > + virBufferAddLit(&buf, "user"); > + if (net->data.user.ipaddr) { > + virBufferAsprintf(&buf, "%cnet=%s", type_sep, > + net->data.user.ipaddr); > + type_sep = ','; > + if (net->data.user.prefix >= 0) > + virBufferAsprintf(&buf, "/%d", net->data.user.prefix); > + } > + if (net->data.user.dns) { > + virBufferAsprintf(&buf, "%cdns=%s", type_sep, net->data.user.dns); > + type_sep = ','; > + } > + if (net->data.user.dhcpstart) { > + virBufferAsprintf(&buf, "%cdhcpstart=%s", type_sep, > + net->data.user.dhcpstart); > + type_sep = ','; > + } > + break; > + > default: > virBufferAddLit(&buf, "user"); > break; > diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.args b/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.args > new file mode 100644 > index 0000000..3e355f3 > --- /dev/null > +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.args > @@ -0,0 +1,7 @@ > +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ > +/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic \ > +-monitor unix:/tmp/test-monitor,server,nowait \ > +-no-acpi -boot c -usb -hda /dev/HostVG/QEMUGuest1 \ > +-net nic,macaddr=00:11:22:33:44:55,vlan=0,model=rtl8139 \ > +-net user,net=192.168.2.0/24,dns=192.168.2.3,dhcpstart=192.168.2.9,vlan=0 \ > +-serial none -parallel none > diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.xml > new file mode 100644 > index 0000000..5c36c77 > --- /dev/null > +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user-ip.xml > @@ -0,0 +1,33 @@ > +<domain type='qemu'> > + <name>QEMUGuest1</name> > + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> > + <memory unit='KiB'>219136</memory> > + <currentMemory unit='KiB'>219136</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</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='user'> > + <ip address='192.168.2.0' prefix='24' dns='192.168.2.3' dhcpstart='192.168.2.9'/> > + <mac address='00:11:22:33:44:55'/> > + <model type='rtl8139'/> > + </interface> > + <memballoon model='virtio'/> > + </devices> > +</domain> > diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c > index 56854dc..02ed4ba 100644 > --- a/tests/qemuxml2argvtest.c > +++ b/tests/qemuxml2argvtest.c > @@ -923,6 +923,7 @@ mymain(void) > DO_TEST("misc-no-reboot", NONE); > DO_TEST("misc-uuid", QEMU_CAPS_NAME, QEMU_CAPS_UUID); > DO_TEST("net-user", NONE); > + DO_TEST("net-user-ip", NONE); > DO_TEST("net-virtio", NONE); > DO_TEST("net-virtio-device", > QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_TX_ALG); -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list