qemu: command: Generate -netdev command line via JSON->cmdline conversion
The 'netdev_add' command was recently formally described in qemu via the QMP schema. This means that it also requires the arguments to be properly formatted. Our current approach is to generate the command line and then use qemuMonitorJSONKeywordStringToJSON to get the JSON properties for the monitor. This will not work if we need to pass some fields as numbers or booleans. In this step we re-do internals of qemuBuildHostNetStr to format a JSON object which is converted back via virQEMUBuildNetdevCommandlineFromJSON to the equivalent command line. This will later allow fixing of the monitor code to use the JSON object directly rather than rely on the conversion. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
486bfba8b2
commit
b6738ffc9f
@ -3564,7 +3564,7 @@ qemuBuildNicDevStr(virDomainDefPtr def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *
|
virJSONValuePtr
|
||||||
qemuBuildHostNetStr(virDomainNetDefPtr net,
|
qemuBuildHostNetStr(virDomainNetDefPtr net,
|
||||||
char **tapfd,
|
char **tapfd,
|
||||||
size_t tapfdSize,
|
size_t tapfdSize,
|
||||||
@ -3573,10 +3573,11 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
const char *slirpfd)
|
const char *slirpfd)
|
||||||
{
|
{
|
||||||
bool is_tap = false;
|
bool is_tap = false;
|
||||||
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
|
||||||
virDomainNetType netType = virDomainNetGetActualType(net);
|
virDomainNetType netType = virDomainNetGetActualType(net);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
g_autoptr(virJSONValue) netprops = NULL;
|
||||||
|
|
||||||
if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("scripts are not supported on interfaces of type %s"),
|
_("scripts are not supported on interfaces of type %s"),
|
||||||
@ -3594,54 +3595,75 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
||||||
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
||||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
virBufferAddLit(&buf, "tap,");
|
if (virJSONValueObjectCreate(&netprops, "s:type", "tap", NULL) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* for one tapfd 'fd=' shall be used,
|
/* for one tapfd 'fd=' shall be used,
|
||||||
* for more than one 'fds=' is the right choice */
|
* for more than one 'fds=' is the right choice */
|
||||||
if (tapfdSize == 1) {
|
if (tapfdSize == 1) {
|
||||||
virBufferAsprintf(&buf, "fd=%s,", tapfd[0]);
|
if (virJSONValueObjectAdd(netprops, "s:fd", tapfd[0], NULL) < 0)
|
||||||
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
virBufferAddLit(&buf, "fds=");
|
g_auto(virBuffer) fdsbuf = VIR_BUFFER_INITIALIZER;
|
||||||
for (i = 0; i < tapfdSize; i++) {
|
|
||||||
if (i)
|
for (i = 0; i < tapfdSize; i++)
|
||||||
virBufferAddChar(&buf, ':');
|
virBufferAsprintf(&fdsbuf, "%s:", tapfd[i]);
|
||||||
virBufferAdd(&buf, tapfd[i], -1);
|
|
||||||
}
|
virBufferTrim(&fdsbuf, ":");
|
||||||
virBufferAddChar(&buf, ',');
|
|
||||||
|
if (virJSONValueObjectAdd(netprops,
|
||||||
|
"s:fds", virBufferCurrentContent(&fdsbuf),
|
||||||
|
NULL) < 0)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_tap = true;
|
is_tap = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
||||||
virBufferAsprintf(&buf, "socket,connect=%s:%d,",
|
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
|
||||||
net->data.socket.address,
|
virJSONValueObjectAppendStringPrintf(netprops, "connect", "%s:%d",
|
||||||
net->data.socket.port);
|
net->data.socket.address,
|
||||||
|
net->data.socket.port) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_SERVER:
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
||||||
virBufferAsprintf(&buf, "socket,listen=%s:%d,",
|
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
|
||||||
NULLSTR_EMPTY(net->data.socket.address),
|
virJSONValueObjectAppendStringPrintf(netprops, "listen", "%s:%d",
|
||||||
net->data.socket.port);
|
NULLSTR_EMPTY(net->data.socket.address),
|
||||||
|
net->data.socket.port) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_MCAST:
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
||||||
virBufferAsprintf(&buf, "socket,mcast=%s:%d,",
|
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
|
||||||
net->data.socket.address,
|
virJSONValueObjectAppendStringPrintf(netprops, "mcast", "%s:%d",
|
||||||
net->data.socket.port);
|
net->data.socket.address,
|
||||||
|
net->data.socket.port) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_UDP:
|
case VIR_DOMAIN_NET_TYPE_UDP:
|
||||||
virBufferAsprintf(&buf, "socket,udp=%s:%d,localaddr=%s:%d,",
|
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
|
||||||
net->data.socket.address,
|
virJSONValueObjectAppendStringPrintf(netprops, "udp", "%s:%d",
|
||||||
net->data.socket.port,
|
net->data.socket.address,
|
||||||
net->data.socket.localaddr,
|
net->data.socket.port) < 0 ||
|
||||||
net->data.socket.localport);
|
virJSONValueObjectAppendStringPrintf(netprops, "localaddr", "%s:%d",
|
||||||
|
net->data.socket.localaddr,
|
||||||
|
net->data.socket.localport) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_USER:
|
case VIR_DOMAIN_NET_TYPE_USER:
|
||||||
if (slirpfd) {
|
if (slirpfd) {
|
||||||
virBufferAsprintf(&buf, "socket,fd=%s,", slirpfd);
|
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
|
||||||
|
virJSONValueObjectAppendString(netprops, "fd", slirpfd) < 0)
|
||||||
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
virBufferAddLit(&buf, "user,");
|
if (virJSONValueObjectCreate(&netprops, "s:type", "user", NULL) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < net->guestIP.nips; i++) {
|
for (i = 0; i < net->guestIP.nips; i++) {
|
||||||
const virNetDevIPAddr *ip = net->guestIP.ips[i];
|
const virNetDevIPAddr *ip = net->guestIP.ips[i];
|
||||||
g_autofree char *addr = NULL;
|
g_autofree char *addr = NULL;
|
||||||
@ -3650,29 +3672,40 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) {
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) {
|
||||||
virBufferAsprintf(&buf, "net=%s", addr);
|
g_autofree char *ipv4netaddr = NULL;
|
||||||
|
|
||||||
if (ip->prefix)
|
if (ip->prefix)
|
||||||
virBufferAsprintf(&buf, "/%u", ip->prefix);
|
ipv4netaddr = g_strdup_printf("%s/%u", addr, ip->prefix);
|
||||||
virBufferAddChar(&buf, ',');
|
else
|
||||||
|
ipv4netaddr = g_strdup(addr);
|
||||||
|
|
||||||
|
if (virJSONValueObjectAppendString(netprops, "net", ipv4netaddr) < 0)
|
||||||
|
return NULL;
|
||||||
} else if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6)) {
|
} else if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET6)) {
|
||||||
virBufferAsprintf(&buf, "ipv6-prefix=%s,", addr);
|
if (virJSONValueObjectAppendString(netprops, "ipv6-prefix", addr) < 0)
|
||||||
if (ip->prefix)
|
return NULL;
|
||||||
virBufferAsprintf(&buf, "ipv6-prefixlen=%u,", ip->prefix);
|
if (ip->prefix &&
|
||||||
|
virJSONValueObjectAppendNumberUlong(netprops, "ipv6-prefixlen",
|
||||||
|
ip->prefix) < 0)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
||||||
virBufferAddLit(&buf, "user,");
|
if (virJSONValueObjectCreate(&netprops, "s:type", "user", NULL) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
||||||
virBufferAsprintf(&buf, "vhost-user,chardev=char%s,",
|
if (virJSONValueObjectCreate(&netprops, "s:type", "vhost-user", NULL) < 0 ||
|
||||||
net->info.alias);
|
virJSONValueObjectAppendStringPrintf(netprops, "chardev", "char%s", net->info.alias) < 0)
|
||||||
if (net->driver.virtio.queues > 1)
|
return NULL;
|
||||||
virBufferAsprintf(&buf, "queues=%u,",
|
|
||||||
net->driver.virtio.queues);
|
if (net->driver.virtio.queues > 1 &&
|
||||||
|
virJSONValueObjectAppendNumberUlong(netprops, "queues", net->driver.virtio.queues) < 0)
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
|
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
|
||||||
@ -3681,31 +3714,38 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
virBufferAsprintf(&buf, "id=host%s,", net->info.alias);
|
if (virJSONValueObjectAppendStringPrintf(netprops, "id", "host%s", net->info.alias) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (is_tap) {
|
if (is_tap) {
|
||||||
if (vhostfdSize) {
|
if (vhostfdSize) {
|
||||||
virBufferAddLit(&buf, "vhost=on,");
|
if (virJSONValueObjectAppendBoolean(netprops, "vhost", true) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (vhostfdSize == 1) {
|
if (vhostfdSize == 1) {
|
||||||
virBufferAsprintf(&buf, "vhostfd=%s,", vhostfd[0]);
|
if (virJSONValueObjectAdd(netprops, "s:vhostfd", vhostfd[0], NULL) < 0)
|
||||||
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
virBufferAddLit(&buf, "vhostfds=");
|
g_auto(virBuffer) fdsbuf = VIR_BUFFER_INITIALIZER;
|
||||||
for (i = 0; i < vhostfdSize; i++) {
|
|
||||||
if (i)
|
for (i = 0; i < vhostfdSize; i++)
|
||||||
virBufferAddChar(&buf, ':');
|
virBufferAsprintf(&fdsbuf, "%s:", vhostfd[i]);
|
||||||
virBufferAdd(&buf, vhostfd[i], -1);
|
|
||||||
}
|
virBufferTrim(&fdsbuf, ":");
|
||||||
virBufferAddChar(&buf, ',');
|
|
||||||
|
if (virJSONValueObjectAdd(netprops,
|
||||||
|
"s:vhostfds", virBufferCurrentContent(&fdsbuf),
|
||||||
|
NULL) < 0)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (net->tune.sndbuf_specified)
|
|
||||||
virBufferAsprintf(&buf, "sndbuf=%lu,", net->tune.sndbuf);
|
if (net->tune.sndbuf_specified &&
|
||||||
|
virJSONValueObjectAppendNumberUlong(netprops, "sndbuf", net->tune.sndbuf) < 0)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&netprops);
|
||||||
virBufferTrim(&buf, ",");
|
|
||||||
|
|
||||||
return virBufferContentAndReset(&buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -7680,6 +7720,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
|
|||||||
bool requireNicdev = false;
|
bool requireNicdev = false;
|
||||||
qemuSlirpPtr slirp;
|
qemuSlirpPtr slirp;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
g_autoptr(virJSONValue) hostnetprops = NULL;
|
||||||
|
|
||||||
|
|
||||||
if (!bootindex)
|
if (!bootindex)
|
||||||
@ -7883,11 +7924,15 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
|
|||||||
if (chardev)
|
if (chardev)
|
||||||
virCommandAddArgList(cmd, "-chardev", chardev, NULL);
|
virCommandAddArgList(cmd, "-chardev", chardev, NULL);
|
||||||
|
|
||||||
if (!(host = qemuBuildHostNetStr(net,
|
if (!(hostnetprops = qemuBuildHostNetStr(net,
|
||||||
tapfdName, tapfdSize,
|
tapfdName, tapfdSize,
|
||||||
vhostfdName, vhostfdSize,
|
vhostfdName, vhostfdSize,
|
||||||
slirpfdName)))
|
slirpfdName)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(host = virQEMUBuildNetdevCommandlineFromJSON(hostnetprops)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
virCommandAddArgList(cmd, "-netdev", host, NULL);
|
virCommandAddArgList(cmd, "-netdev", host, NULL);
|
||||||
|
|
||||||
/* Possible combinations:
|
/* Possible combinations:
|
||||||
|
@ -89,12 +89,12 @@ qemuBuildChrDeviceStr(char **deviceStr,
|
|||||||
char *
|
char *
|
||||||
qemuBuildChannelGuestfwdNetdevProps(virDomainChrDefPtr chr);
|
qemuBuildChannelGuestfwdNetdevProps(virDomainChrDefPtr chr);
|
||||||
|
|
||||||
char *qemuBuildHostNetStr(virDomainNetDefPtr net,
|
virJSONValuePtr qemuBuildHostNetStr(virDomainNetDefPtr net,
|
||||||
char **tapfd,
|
char **tapfd,
|
||||||
size_t tapfdSize,
|
size_t tapfdSize,
|
||||||
char **vhostfd,
|
char **vhostfd,
|
||||||
size_t vhostfdSize,
|
size_t vhostfdSize,
|
||||||
const char *slirpfd);
|
const char *slirpfd);
|
||||||
|
|
||||||
/* Current, best practice */
|
/* Current, best practice */
|
||||||
char *qemuBuildNicDevStr(virDomainDefPtr def,
|
char *qemuBuildNicDevStr(virDomainDefPtr def,
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "virstoragefile.h"
|
#include "virstoragefile.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
#include "virtime.h"
|
#include "virtime.h"
|
||||||
|
#include "virqemu.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
@ -1157,6 +1158,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|||||||
size_t vhostfdSize = 0;
|
size_t vhostfdSize = 0;
|
||||||
size_t queueSize = 0;
|
size_t queueSize = 0;
|
||||||
g_autofree char *nicstr = NULL;
|
g_autofree char *nicstr = NULL;
|
||||||
|
g_autoptr(virJSONValue) netprops = NULL;
|
||||||
g_autofree char *netstr = NULL;
|
g_autofree char *netstr = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool releaseaddr = false;
|
bool releaseaddr = false;
|
||||||
@ -1382,10 +1384,13 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|||||||
for (i = 0; i < vhostfdSize; i++)
|
for (i = 0; i < vhostfdSize; i++)
|
||||||
vhostfdName[i] = g_strdup_printf("vhostfd-%s%zu", net->info.alias, i);
|
vhostfdName[i] = g_strdup_printf("vhostfd-%s%zu", net->info.alias, i);
|
||||||
|
|
||||||
if (!(netstr = qemuBuildHostNetStr(net,
|
if (!(netprops = qemuBuildHostNetStr(net,
|
||||||
tapfdName, tapfdSize,
|
tapfdName, tapfdSize,
|
||||||
vhostfdName, vhostfdSize,
|
vhostfdName, vhostfdSize,
|
||||||
slirpfdName)))
|
slirpfdName)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(netstr = virQEMUBuildNetdevCommandlineFromJSON(netprops)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
qemuDomainObjEnterMonitor(driver, vm);
|
qemuDomainObjEnterMonitor(driver, vm);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user