Message ID | 20201108235952.107961-4-lekiravi@yandex-team.ru |
---|---|
State | New |
Headers | show |
Series | Introducing QMP query-netdev command | expand |
On 2020/11/9 上午7:59, Alexey Kirillov wrote: > +#ifdef CONFIG_SLIRP > + case NET_BACKEND_USER: { > + size_t len = strchr(ni->u.user.net, '/') - ni->u.user.net; > + char *net = g_strndup(ni->u.user.net, len); > + > + info_str = g_strdup_printf("net=%s,restrict=%s", > + net, > + ni->u.user.q_restrict ? "on" : "off"); > + g_free(net); > + break; > + } > +#endif /* CONFIG_SLIRP */ > + case NET_BACKEND_TAP: { > +#ifndef _WIN32 > + if (ni->u.tap.has_fds) { > + char **fds = g_strsplit(ni->u.tap.fds, ":", -1); > + > + info_str = g_strdup_printf("fd=%s", fds[nc->queue_index]); > + g_strfreev(fds); > + } else if (ni->u.tap.has_helper) { > + info_str = g_strdup_printf("helper=%s", ni->u.tap.helper); > + } else { > + info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", > + ni->u.tap.ifname, > + nc->queue_index == 0 ? ni->u.tap.script : "no", > + nc->queue_index == 0 ? ni->u.tap.downscript : "no"); > + } > +#else > + info_str = g_strdup_printf("tap: ifname=%s", ni->u.tap.ifname); > +#endif /* _WIN32 */ > + break; > + } > +#ifdef CONFIG_L2TPV3 > + case NET_BACKEND_L2TPV3: { > + info_str = g_strdup_printf("l2tpv3: connected"); > + break; > + } > +#endif /* CONFIG_L2TPV3 */ > + case NET_BACKEND_SOCKET: { > + if (ni->u.socket.has_listen) { > + if (ni->u.socket.has_fd) { > + info_str = g_strdup_printf("socket: connection from %s", > + ni->u.socket.listen); > + } else { > + info_str = g_strdup_printf("socket: wait from %s", > + ni->u.socket.listen); > + } > + } else if (ni->u.socket.has_connect && ni->u.socket.has_fd) { > + info_str = g_strdup_printf("socket: connect to %s", > + ni->u.socket.connect); > + } else if (ni->u.socket.has_mcast && ni->u.socket.has_fd) { > + info_str = g_strdup_printf("socket: mcast=%s", > + ni->u.socket.mcast); > + } else if (ni->u.socket.has_udp && ni->u.socket.has_fd) { > + info_str = g_strdup_printf("socket: udp=%s", ni->u.socket.udp); > + } else { > + g_assert(ni->u.socket.has_fd); > + int so_type = -1; > + int optlen = sizeof(so_type); > + int fd = atoi(ni->u.socket.fd); > + > + getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, > + (socklen_t *)&optlen); > + if (so_type == SOCK_STREAM) { > + info_str = g_strdup_printf("socket: fd=%s", > + ni->u.socket.fd); > + } else { > + if (ni->u.socket.has_mcast) { > + /* > + * This branch is unreachable, according to how it is in > + * net/socket.c at this moment > + */ > + info_str = g_strdup_printf("socket: fd=%s " > + "(cloned mcast=%s)", > + ni->u.socket.fd, > + ni->u.socket.mcast); > + } else { > + SocketAddress *sa = socket_local_address(fd, NULL); > + > + info_str = g_strdup_printf("socket: fd=%s %s", > + ni->u.socket.fd, > + SocketAddressType_str(sa->type)); > + qapi_free_SocketAddress(sa); > + } > + } > + } > + break; > + } > +#ifdef CONFIG_VDE > + case NET_BACKEND_VDE: { > + info_str = g_strdup_printf("sock=%s,fd=%d", > + ni->u.vde.sock, > + net_vde_get_fd(nc)); > + break; > + } > +#endif /* CONFIG_VDE */ > +#ifdef CONFIG_NET_BRIDGE > + case NET_BACKEND_BRIDGE: { > + info_str = g_strdup_printf("helper=%s,br=%s", > + ni->u.bridge.helper, > + ni->u.bridge.br); > + break; > + } > +#endif /* CONFIG_NET_BRIDGE */ > +#ifdef CONFIG_NETMAP > + case NET_BACKEND_NETMAP: { > + info_str = g_strdup_printf("netmap: ifname=%s", > + ni->u.netmap.ifname); > + break; > + } > +#endif /* CONFIG_NETMAP */ > +#ifdef CONFIG_VHOST_NET_USER > + case NET_BACKEND_VHOST_USER: { > + info_str = g_strdup_printf("vhost-user%d to %s", > + nc->queue_index, > + ni->u.vhost_user.chardev); > + break; > + } > +#endif /* CONFIG_VHOST_NET_USER */ > +#ifdef CONFIG_VHOST_NET_VDPA > + case NET_BACKEND_VHOST_VDPA: { > + info_str = g_strdup("vhost-vdpa"); > + break; > + } > +#endif /* CONFIG_VHOST_NET_VDPA */ This will introduce burdens for new netdevs or new attributes since people can easily forget to add the routine here. I think at least we need introduce callbacks for this. One more stupid question, instead of generating the string via hard codes, is there any method (dict?) to iterate all the key/values automatically? Thanks
Hi! 07.12.2020, 08:52, "Jason Wang" <jasowang@redhat.com>: > On 2020/11/9 上午7:59, Alexey Kirillov wrote: >> +#ifdef CONFIG_SLIRP >> + case NET_BACKEND_USER: { >> + size_t len = strchr(ni->u.user.net, '/') - ni->u.user.net; >> + char *net = g_strndup(ni->u.user.net, len); >> + >> + info_str = g_strdup_printf("net=%s,restrict=%s", >> + net, >> + ni->u.user.q_restrict ? "on" : "off"); >> + g_free(net); >> + break; >> + } >> +#endif /* CONFIG_SLIRP */ >> + case NET_BACKEND_TAP: { >> +#ifndef _WIN32 >> + if (ni->u.tap.has_fds) { >> + char **fds = g_strsplit(ni->u.tap.fds, ":", -1); >> + >> + info_str = g_strdup_printf("fd=%s", fds[nc->queue_index]); >> + g_strfreev(fds); >> + } else if (ni->u.tap.has_helper) { >> + info_str = g_strdup_printf("helper=%s", ni->u.tap.helper); >> + } else { >> + info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", >> + ni->u.tap.ifname, >> + nc->queue_index == 0 ? ni->u.tap.script : "no", >> + nc->queue_index == 0 ? ni->u.tap.downscript : "no"); >> + } >> +#else >> + info_str = g_strdup_printf("tap: ifname=%s", ni->u.tap.ifname); >> +#endif /* _WIN32 */ >> + break; >> + } >> +#ifdef CONFIG_L2TPV3 >> + case NET_BACKEND_L2TPV3: { >> + info_str = g_strdup_printf("l2tpv3: connected"); >> + break; >> + } >> +#endif /* CONFIG_L2TPV3 */ >> + case NET_BACKEND_SOCKET: { >> + if (ni->u.socket.has_listen) { >> + if (ni->u.socket.has_fd) { >> + info_str = g_strdup_printf("socket: connection from %s", >> + ni->u.socket.listen); >> + } else { >> + info_str = g_strdup_printf("socket: wait from %s", >> + ni->u.socket.listen); >> + } >> + } else if (ni->u.socket.has_connect && ni->u.socket.has_fd) { >> + info_str = g_strdup_printf("socket: connect to %s", >> + ni->u.socket.connect); >> + } else if (ni->u.socket.has_mcast && ni->u.socket.has_fd) { >> + info_str = g_strdup_printf("socket: mcast=%s", >> + ni->u.socket.mcast); >> + } else if (ni->u.socket.has_udp && ni->u.socket.has_fd) { >> + info_str = g_strdup_printf("socket: udp=%s", ni->u.socket.udp); >> + } else { >> + g_assert(ni->u.socket.has_fd); >> + int so_type = -1; >> + int optlen = sizeof(so_type); >> + int fd = atoi(ni->u.socket.fd); >> + >> + getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, >> + (socklen_t *)&optlen); >> + if (so_type == SOCK_STREAM) { >> + info_str = g_strdup_printf("socket: fd=%s", >> + ni->u.socket.fd); >> + } else { >> + if (ni->u.socket.has_mcast) { >> + /* >> + * This branch is unreachable, according to how it is in >> + * net/socket.c at this moment >> + */ >> + info_str = g_strdup_printf("socket: fd=%s " >> + "(cloned mcast=%s)", >> + ni->u.socket.fd, >> + ni->u.socket.mcast); >> + } else { >> + SocketAddress *sa = socket_local_address(fd, NULL); >> + >> + info_str = g_strdup_printf("socket: fd=%s %s", >> + ni->u.socket.fd, >> + SocketAddressType_str(sa->type)); >> + qapi_free_SocketAddress(sa); >> + } >> + } >> + } >> + break; >> + } >> +#ifdef CONFIG_VDE >> + case NET_BACKEND_VDE: { >> + info_str = g_strdup_printf("sock=%s,fd=%d", >> + ni->u.vde.sock, >> + net_vde_get_fd(nc)); >> + break; >> + } >> +#endif /* CONFIG_VDE */ >> +#ifdef CONFIG_NET_BRIDGE >> + case NET_BACKEND_BRIDGE: { >> + info_str = g_strdup_printf("helper=%s,br=%s", >> + ni->u.bridge.helper, >> + ni->u.bridge.br); >> + break; >> + } >> +#endif /* CONFIG_NET_BRIDGE */ >> +#ifdef CONFIG_NETMAP >> + case NET_BACKEND_NETMAP: { >> + info_str = g_strdup_printf("netmap: ifname=%s", >> + ni->u.netmap.ifname); >> + break; >> + } >> +#endif /* CONFIG_NETMAP */ >> +#ifdef CONFIG_VHOST_NET_USER >> + case NET_BACKEND_VHOST_USER: { >> + info_str = g_strdup_printf("vhost-user%d to %s", >> + nc->queue_index, >> + ni->u.vhost_user.chardev); >> + break; >> + } >> +#endif /* CONFIG_VHOST_NET_USER */ >> +#ifdef CONFIG_VHOST_NET_VDPA >> + case NET_BACKEND_VHOST_VDPA: { >> + info_str = g_strdup("vhost-vdpa"); >> + break; >> + } >> +#endif /* CONFIG_VHOST_NET_VDPA */ > > This will introduce burdens for new netdevs or new attributes since > people can easily forget to add the routine here. > > I think at least we need introduce callbacks for this. Thanks for pointing. I can't remember why exactly I chose to not do it. So it's definitely better to split this chunk to several callbacks. I'll do it in the next version of series. > One more stupid question, instead of generating the string via hard > codes, is there any method (dict?) to iterate all the key/values > automatically? > > Thanks Oh yes, that the point. Now there are no common format for info_str. This patch is aimed to keep old HMP command mostly untouched. But if we can drop old format, all this mess can be generalized as JSON lines replacing old info_str stuff. What do you think about that? Originally I wanted to completely drop old info_str and use QAPI to store and provide information about netdevs (and NICs too). Thanks! -- Alexey Kirillov Yandex.Cloud
----- Original Message ----- > Hi! > > 07.12.2020, 08:52, "Jason Wang" <jasowang@redhat.com>: > > On 2020/11/9 上午7:59, Alexey Kirillov wrote: > >> +#ifdef CONFIG_SLIRP > >> + case NET_BACKEND_USER: { > >> + size_t len = strchr(ni->u.user.net, '/') - ni->u.user.net; > >> + char *net = g_strndup(ni->u.user.net, len); > >> + > >> + info_str = g_strdup_printf("net=%s,restrict=%s", > >> + net, > >> + ni->u.user.q_restrict ? "on" : "off"); > >> + g_free(net); > >> + break; > >> + } > >> +#endif /* CONFIG_SLIRP */ > >> + case NET_BACKEND_TAP: { > >> +#ifndef _WIN32 > >> + if (ni->u.tap.has_fds) { > >> + char **fds = g_strsplit(ni->u.tap.fds, ":", -1); > >> + > >> + info_str = g_strdup_printf("fd=%s", fds[nc->queue_index]); > >> + g_strfreev(fds); > >> + } else if (ni->u.tap.has_helper) { > >> + info_str = g_strdup_printf("helper=%s", ni->u.tap.helper); > >> + } else { > >> + info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", > >> + ni->u.tap.ifname, > >> + nc->queue_index == 0 ? ni->u.tap.script : "no", > >> + nc->queue_index == 0 ? ni->u.tap.downscript : "no"); > >> + } > >> +#else > >> + info_str = g_strdup_printf("tap: ifname=%s", ni->u.tap.ifname); > >> +#endif /* _WIN32 */ > >> + break; > >> + } > >> +#ifdef CONFIG_L2TPV3 > >> + case NET_BACKEND_L2TPV3: { > >> + info_str = g_strdup_printf("l2tpv3: connected"); > >> + break; > >> + } > >> +#endif /* CONFIG_L2TPV3 */ > >> + case NET_BACKEND_SOCKET: { > >> + if (ni->u.socket.has_listen) { > >> + if (ni->u.socket.has_fd) { > >> + info_str = g_strdup_printf("socket: connection from %s", > >> + ni->u.socket.listen); > >> + } else { > >> + info_str = g_strdup_printf("socket: wait from %s", > >> + ni->u.socket.listen); > >> + } > >> + } else if (ni->u.socket.has_connect && ni->u.socket.has_fd) { > >> + info_str = g_strdup_printf("socket: connect to %s", > >> + ni->u.socket.connect); > >> + } else if (ni->u.socket.has_mcast && ni->u.socket.has_fd) { > >> + info_str = g_strdup_printf("socket: mcast=%s", > >> + ni->u.socket.mcast); > >> + } else if (ni->u.socket.has_udp && ni->u.socket.has_fd) { > >> + info_str = g_strdup_printf("socket: udp=%s", ni->u.socket.udp); > >> + } else { > >> + g_assert(ni->u.socket.has_fd); > >> + int so_type = -1; > >> + int optlen = sizeof(so_type); > >> + int fd = atoi(ni->u.socket.fd); > >> + > >> + getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, > >> + (socklen_t *)&optlen); > >> + if (so_type == SOCK_STREAM) { > >> + info_str = g_strdup_printf("socket: fd=%s", > >> + ni->u.socket.fd); > >> + } else { > >> + if (ni->u.socket.has_mcast) { > >> + /* > >> + * This branch is unreachable, according to how it is in > >> + * net/socket.c at this moment > >> + */ > >> + info_str = g_strdup_printf("socket: fd=%s " > >> + "(cloned mcast=%s)", > >> + ni->u.socket.fd, > >> + ni->u.socket.mcast); > >> + } else { > >> + SocketAddress *sa = socket_local_address(fd, NULL); > >> + > >> + info_str = g_strdup_printf("socket: fd=%s %s", > >> + ni->u.socket.fd, > >> + SocketAddressType_str(sa->type)); > >> + qapi_free_SocketAddress(sa); > >> + } > >> + } > >> + } > >> + break; > >> + } > >> +#ifdef CONFIG_VDE > >> + case NET_BACKEND_VDE: { > >> + info_str = g_strdup_printf("sock=%s,fd=%d", > >> + ni->u.vde.sock, > >> + net_vde_get_fd(nc)); > >> + break; > >> + } > >> +#endif /* CONFIG_VDE */ > >> +#ifdef CONFIG_NET_BRIDGE > >> + case NET_BACKEND_BRIDGE: { > >> + info_str = g_strdup_printf("helper=%s,br=%s", > >> + ni->u.bridge.helper, > >> + ni->u.bridge.br); > >> + break; > >> + } > >> +#endif /* CONFIG_NET_BRIDGE */ > >> +#ifdef CONFIG_NETMAP > >> + case NET_BACKEND_NETMAP: { > >> + info_str = g_strdup_printf("netmap: ifname=%s", > >> + ni->u.netmap.ifname); > >> + break; > >> + } > >> +#endif /* CONFIG_NETMAP */ > >> +#ifdef CONFIG_VHOST_NET_USER > >> + case NET_BACKEND_VHOST_USER: { > >> + info_str = g_strdup_printf("vhost-user%d to %s", > >> + nc->queue_index, > >> + ni->u.vhost_user.chardev); > >> + break; > >> + } > >> +#endif /* CONFIG_VHOST_NET_USER */ > >> +#ifdef CONFIG_VHOST_NET_VDPA > >> + case NET_BACKEND_VHOST_VDPA: { > >> + info_str = g_strdup("vhost-vdpa"); > >> + break; > >> + } > >> +#endif /* CONFIG_VHOST_NET_VDPA */ > > > > This will introduce burdens for new netdevs or new attributes since > > people can easily forget to add the routine here. > > > > I think at least we need introduce callbacks for this. > > Thanks for pointing. I can't remember why exactly I chose to not do it. > So it's definitely better to split this chunk to several callbacks. > I'll do it in the next version of series. > > > One more stupid question, instead of generating the string via hard > > codes, is there any method (dict?) to iterate all the key/values > > automatically? > > > > Thanks > > Oh yes, that the point. > Now there are no common format for info_str. > This patch is aimed to keep old HMP command mostly untouched. > But if we can drop old format, all this mess can be generalized as JSON > lines replacing old info_str stuff. > > What do you think about that? I think it works and there's no need for sticking to the old HMP format since it's not an ABI. And it would be better if you can generate more human readable format from JSON. Thanks > > Originally I wanted to completely drop old info_str and use > QAPI to store and provide information about netdevs (and NICs too). > > Thanks! > > -- > Alexey Kirillov > Yandex.Cloud > >
Jason Wang <jasowang@redhat.com> writes: [...] > One more stupid question, instead of generating the string via hard > codes, is there any method (dict?) to iterate all the key/values > automatically? QAPI visitors. The lazy way: use the QObject output visitor to convert the QAPI type (here: NetdevInfo) to QObject, then qobject_to_json() to convert to JSON text. If you don't want JSON, replace qobject_to_json(). Perhaps you can create something that's generally useful for HMP, not just "info network". I'd pick keyval_parse() syntax. The detour through QObject creates and destroys a rather fat temporary data structure. Tolerable when the amount of data is small. An output visitor that directly creates the string is more efficient. Takes a bit more code, though. I intend to post one for JSON, to reduce QMP's malloc gluttony.
----- Original Message ----- > Jason Wang <jasowang@redhat.com> writes: > > [...] > > One more stupid question, instead of generating the string via hard > > codes, is there any method (dict?) to iterate all the key/values > > automatically? > > QAPI visitors. > > The lazy way: use the QObject output visitor to convert the QAPI type > (here: NetdevInfo) to QObject, then qobject_to_json() to convert to > JSON text. > > If you don't want JSON, replace qobject_to_json(). Perhaps you can > create something that's generally useful for HMP, not just "info > network". I'd pick keyval_parse() syntax. > > The detour through QObject creates and destroys a rather fat temporary > data structure. Tolerable when the amount of data is small. An output > visitor that directly creates the string is more efficient. Takes a bit > more code, though. I intend to post one for JSON, to reduce QMP's > malloc gluttony. > Thanks a lot for the answer. Alexey, let's try what Markus suggested here.
16.12.2020, 08:58, "Jason Wang" <jasowang@redhat.com>: > ----- Original Message ----- >> Jason Wang <jasowang@redhat.com> writes: >> >> [...] >> > One more stupid question, instead of generating the string via hard >> > codes, is there any method (dict?) to iterate all the key/values >> > automatically? >> >> QAPI visitors. >> >> The lazy way: use the QObject output visitor to convert the QAPI type >> (here: NetdevInfo) to QObject, then qobject_to_json() to convert to >> JSON text. >> >> If you don't want JSON, replace qobject_to_json(). Perhaps you can >> create something that's generally useful for HMP, not just "info >> network". I'd pick keyval_parse() syntax. >> >> The detour through QObject creates and destroys a rather fat temporary >> data structure. Tolerable when the amount of data is small. An output >> visitor that directly creates the string is more efficient. Takes a bit >> more code, though. I intend to post one for JSON, to reduce QMP's >> malloc gluttony. > > Thanks a lot for the answer. > > Alexey, let's try what Markus suggested here. Thanks for information. I will do so and send a new version of the patchset. -- Alexey Kirillov Yandex.Cloud
diff --git a/include/net/net.h b/include/net/net.h index 16700f715e..ed77f444de 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -172,7 +172,8 @@ void qemu_check_nic_model(NICInfo *nd, const char *model); int qemu_find_nic_model(NICInfo *nd, const char * const *models, const char *default_model); -void print_net_client(Monitor *mon, NetClientState *nc); +void print_net_client(Monitor *mon, NetClientState *nc, + NetdevInfoList *ni_list); void hmp_info_network(Monitor *mon, const QDict *qdict); void net_socket_rs_init(SocketReadState *rs, SocketReadStateFinalize *finalize, diff --git a/net/clients.h b/net/clients.h index 92f9b59aed..fdf257f641 100644 --- a/net/clients.h +++ b/net/clients.h @@ -51,6 +51,7 @@ int net_init_l2tpv3(const Netdev *netdev, const char *name, #ifdef CONFIG_VDE int net_init_vde(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +int net_vde_get_fd(const NetClientState *nc); #endif #ifdef CONFIG_NETMAP diff --git a/net/hub.c b/net/hub.c index 1375738bf1..7815248650 100644 --- a/net/hub.c +++ b/net/hub.c @@ -221,7 +221,7 @@ NetClientState *net_hub_port_find(int hub_id) /** * Print hub configuration */ -void net_hub_info(Monitor *mon) +void net_hub_info(Monitor *mon, NetdevInfoList *ni_list) { NetHub *hub; NetHubPort *port; @@ -232,7 +232,7 @@ void net_hub_info(Monitor *mon) monitor_printf(mon, " \\ %s", port->nc.name); if (port->nc.peer) { monitor_printf(mon, ": "); - print_net_client(mon, port->nc.peer); + print_net_client(mon, port->nc.peer, ni_list); } else { monitor_printf(mon, "\n"); } diff --git a/net/hub.h b/net/hub.h index ce45f7b399..2c9a384077 100644 --- a/net/hub.h +++ b/net/hub.h @@ -17,7 +17,7 @@ NetClientState *net_hub_add_port(int hub_id, const char *name, NetClientState *hubpeer); -void net_hub_info(Monitor *mon); +void net_hub_info(Monitor *mon, NetdevInfoList *ninfo); void net_hub_check_clients(void); bool net_hub_flush(NetClientState *nc); diff --git a/net/net.c b/net/net.c index 551acadabc..4d3719434c 100644 --- a/net/net.c +++ b/net/net.c @@ -1178,14 +1178,182 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) monitor_printf(mon, "\n"); } -void print_net_client(Monitor *mon, NetClientState *nc) +static NetdevInfo *get_netdev_info(NetdevInfoList *ni_list, char *name) +{ + NetdevInfo *ni; + + while (ni_list) { + ni = ni_list->value; + if (g_str_equal(ni->id, name)) { + return ni; + } + ni_list = ni_list->next; + } + + return NULL; +} + +static char *generate_info_str(NetdevInfo *ni, NetClientState *nc) +{ + char *info_str; + + /* Use legacy field info_str for NIC and hubports */ + if ((nc->info->type == NET_CLIENT_DRIVER_NIC) || + (nc->info->type == NET_CLIENT_DRIVER_HUBPORT)) { + return g_strdup(nc->info_str); + } + + if (!ni) { + return g_malloc0(1); + } + + switch (ni->type) { +#ifdef CONFIG_SLIRP + case NET_BACKEND_USER: { + size_t len = strchr(ni->u.user.net, '/') - ni->u.user.net; + char *net = g_strndup(ni->u.user.net, len); + + info_str = g_strdup_printf("net=%s,restrict=%s", + net, + ni->u.user.q_restrict ? "on" : "off"); + g_free(net); + break; + } +#endif /* CONFIG_SLIRP */ + case NET_BACKEND_TAP: { +#ifndef _WIN32 + if (ni->u.tap.has_fds) { + char **fds = g_strsplit(ni->u.tap.fds, ":", -1); + + info_str = g_strdup_printf("fd=%s", fds[nc->queue_index]); + g_strfreev(fds); + } else if (ni->u.tap.has_helper) { + info_str = g_strdup_printf("helper=%s", ni->u.tap.helper); + } else { + info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", + ni->u.tap.ifname, + nc->queue_index == 0 ? ni->u.tap.script : "no", + nc->queue_index == 0 ? ni->u.tap.downscript : "no"); + } +#else + info_str = g_strdup_printf("tap: ifname=%s", ni->u.tap.ifname); +#endif /* _WIN32 */ + break; + } +#ifdef CONFIG_L2TPV3 + case NET_BACKEND_L2TPV3: { + info_str = g_strdup_printf("l2tpv3: connected"); + break; + } +#endif /* CONFIG_L2TPV3 */ + case NET_BACKEND_SOCKET: { + if (ni->u.socket.has_listen) { + if (ni->u.socket.has_fd) { + info_str = g_strdup_printf("socket: connection from %s", + ni->u.socket.listen); + } else { + info_str = g_strdup_printf("socket: wait from %s", + ni->u.socket.listen); + } + } else if (ni->u.socket.has_connect && ni->u.socket.has_fd) { + info_str = g_strdup_printf("socket: connect to %s", + ni->u.socket.connect); + } else if (ni->u.socket.has_mcast && ni->u.socket.has_fd) { + info_str = g_strdup_printf("socket: mcast=%s", + ni->u.socket.mcast); + } else if (ni->u.socket.has_udp && ni->u.socket.has_fd) { + info_str = g_strdup_printf("socket: udp=%s", ni->u.socket.udp); + } else { + g_assert(ni->u.socket.has_fd); + int so_type = -1; + int optlen = sizeof(so_type); + int fd = atoi(ni->u.socket.fd); + + getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, + (socklen_t *)&optlen); + if (so_type == SOCK_STREAM) { + info_str = g_strdup_printf("socket: fd=%s", + ni->u.socket.fd); + } else { + if (ni->u.socket.has_mcast) { + /* + * This branch is unreachable, according to how it is in + * net/socket.c at this moment + */ + info_str = g_strdup_printf("socket: fd=%s " + "(cloned mcast=%s)", + ni->u.socket.fd, + ni->u.socket.mcast); + } else { + SocketAddress *sa = socket_local_address(fd, NULL); + + info_str = g_strdup_printf("socket: fd=%s %s", + ni->u.socket.fd, + SocketAddressType_str(sa->type)); + qapi_free_SocketAddress(sa); + } + } + } + break; + } +#ifdef CONFIG_VDE + case NET_BACKEND_VDE: { + info_str = g_strdup_printf("sock=%s,fd=%d", + ni->u.vde.sock, + net_vde_get_fd(nc)); + break; + } +#endif /* CONFIG_VDE */ +#ifdef CONFIG_NET_BRIDGE + case NET_BACKEND_BRIDGE: { + info_str = g_strdup_printf("helper=%s,br=%s", + ni->u.bridge.helper, + ni->u.bridge.br); + break; + } +#endif /* CONFIG_NET_BRIDGE */ +#ifdef CONFIG_NETMAP + case NET_BACKEND_NETMAP: { + info_str = g_strdup_printf("netmap: ifname=%s", + ni->u.netmap.ifname); + break; + } +#endif /* CONFIG_NETMAP */ +#ifdef CONFIG_VHOST_NET_USER + case NET_BACKEND_VHOST_USER: { + info_str = g_strdup_printf("vhost-user%d to %s", + nc->queue_index, + ni->u.vhost_user.chardev); + break; + } +#endif /* CONFIG_VHOST_NET_USER */ +#ifdef CONFIG_VHOST_NET_VDPA + case NET_BACKEND_VHOST_VDPA: { + info_str = g_strdup("vhost-vdpa"); + break; + } +#endif /* CONFIG_VHOST_NET_VDPA */ + default: { + info_str = g_malloc0(1); + break; + } + } + + return info_str; +} + +void print_net_client(Monitor *mon, NetClientState *nc, NetdevInfoList *ni_list) { NetFilterState *nf; + NetdevInfo *ni = get_netdev_info(ni_list, nc->name); + char *info_str = generate_info_str(ni, nc); monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, nc->queue_index, NetClientDriver_str(nc->info->type), - nc->info_str); + info_str); + g_free(info_str); + if (!QTAILQ_EMPTY(&nc->filters)) { monitor_printf(mon, "filters:\n"); } @@ -1289,8 +1457,9 @@ void hmp_info_network(Monitor *mon, const QDict *qdict) { NetClientState *nc, *peer; NetClientDriver type; + NetdevInfoList *ni_list = qmp_query_netdev(NULL); - net_hub_info(mon); + net_hub_info(mon, ni_list); QTAILQ_FOREACH(nc, &net_clients, next) { peer = nc->peer; @@ -1302,13 +1471,15 @@ void hmp_info_network(Monitor *mon, const QDict *qdict) } if (!peer || type == NET_CLIENT_DRIVER_NIC) { - print_net_client(mon, nc); + print_net_client(mon, nc, ni_list); } /* else it's a netdev connected to a NIC, printed with the NIC */ if (peer && type == NET_CLIENT_DRIVER_NIC) { monitor_printf(mon, " \\ "); - print_net_client(mon, peer); + print_net_client(mon, peer, ni_list); } } + + qapi_free_NetdevInfoList(ni_list); } void colo_notify_filters_event(int event, Error **errp) diff --git a/net/vde.c b/net/vde.c index 1af9175060..041eadbcf9 100644 --- a/net/vde.c +++ b/net/vde.c @@ -153,3 +153,13 @@ int net_init_vde(const Netdev *netdev, const char *name, return 0; } + +int net_vde_get_fd(const NetClientState *nc) +{ + VDEState *s; + assert(nc->info->type == NET_CLIENT_DRIVER_VDE); + + s = DO_UPCAST(VDEState, nc, nc); + + return vde_datafd(s->vde); +}
Replace usage of legacy field info_str of NetClientState for backend network devices with result of QMP command query-netdev. NIC and hubports still use legacy info_str field. Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> --- include/net/net.h | 3 +- net/clients.h | 1 + net/hub.c | 4 +- net/hub.h | 2 +- net/net.c | 181 ++++++++++++++++++++++++++++++++++++++++++++-- net/vde.c | 10 +++ 6 files changed, 192 insertions(+), 9 deletions(-)