On Thu, 05/03 10:12, Daniel P. Berrangé wrote: > On Thu, May 03, 2018 at 09:25:45AM +0800, Fam Zheng wrote: > > HMP "info usernet" has been available but it isn't ideal for programmed > > use cases. This closes the gap in QMP by adding a counterpart > > "query-usernet" command. It is basically translated from > > the HMP slirp_connection_info() loop, which now calls the QMP > > implementation and prints the data, just like other HMP info_* commands. > > > > The TCPS_* macros are now defined as a QAPI enum. > > > > Signed-off-by: Fam Zheng <f...@redhat.com> > > > > diff --git a/qapi/net.json b/qapi/net.json > > index 9117c56972..83757d0ed0 100644 > > --- a/qapi/net.json > > +++ b/qapi/net.json > > @@ -689,3 +689,217 @@ > > ## > > { 'event': 'NIC_RX_FILTER_CHANGED', > > 'data': { '*name': 'str', 'path': 'str' } } > > + > > +## > > +# @TCPS: > > +# > > +# TCP States of a SLIRP connection. > > +# > > +# - States where connections are not established: none, closed, listen, > > syn-sent, > > +# syn-received > > +# > > +# - States where user has closed: fin-wait-1, closing, last-ack, > > fin-wait-2, > > +# time-wait > > +# > > +# - States awaiting ACK of FIN: fin-wait-1, closing, last-ack > > +# > > +# 'none' state is used only when host forwarding > > +# > > +# Since 2.13 > > +# > > +## > > +{ 'enum': 'TCPS', > > I'd suggest avoiding the abbreviation, IOW use TCPState as > the name. Yes that will require changnig the constants in > the SLIRP code, but that's worthwhile to get this QAPI > naming clearer IMHO. >
Yes, it feels cleaner to me. I wanted to keep this patch short-ish but that change can be split into a separate patch which introduces the QAPI enum and replaces the TCPS_ macros. I will do it in v6, thanks. Fam > I wonder if we should have a common prefix too eg UsernetTCPState > as this is a global QAPI namespace after all . > > > + 'data': > > + ['closed', > > + 'listen', > > + 'syn-sent', > > + 'syn-received', > > + 'established', > > + 'close-wait', > > + 'fin-wait-1', > > + 'closing', > > + 'last-ack', > > + 'fin-wait-2', > > + 'time-wait', > > + 'none' > > + ] } > > + > > +## > > +# @UsernetTCPConnection: > > +# > > +# SLIRP TCP information. > > +# > > +# @state: tcp connection state > > +# > > +# @hostfwd: whether this connection has host port forwarding > > +# > > +# @fd: the file descriptor of the connection > > +# > > +# @src-addr: source address of host port forwarding > > +# > > +# @src-port: source port of host port forwarding > > +# > > +# @dest-addr: destination address of host port forwarding > > +# > > +# @dest-port: destination port of host port forwarding > > +# > > +# @recv-buffered: number of bytes queued in the receive buffer > > +# > > +# @send-buffered: number of bytes queued in the send buffer > > +# > > +# Since: 2.13 > > +## > > +{ 'struct': 'UsernetTCPConnection', > > + 'data': { > > + 'state': 'TCPS', > > + 'hostfwd': 'bool', > > + 'fd': 'int', > > + 'src-addr': 'str', > > + 'src-port': 'int', > > + 'dest-addr': 'str', > > + 'dest-port': 'int', > > + 'recv-buffered': 'int', > > + 'send-buffered': 'int' > > + } } > > + > > +## > > +# @UsernetUDPConnection: > > +# > > +# SLIRP UDP information. > > +# > > +# @hostfwd: whether this connection has host port forwarding > > +# > > +# @expire-time-ms: time in microseconds after which this connection will > > expire > > +# > > +# @fd: the file descriptor of the connection > > +# > > +# @src-addr: source address of host port forwarding > > +# > > +# @src-port: source port of host port forwarding > > +# > > +# @dest-addr: destination address of host port forwarding > > +# > > +# @dest-port: destination port of host port forwarding > > +# > > +# @recv-buffered: number of bytes queued in the receive buffer > > +# > > +# @send-buffered: number of bytes queued in the send buffer > > +# > > +# Since: 2.13 > > +## > > +{ 'struct': 'UsernetUDPConnection', > > + 'data': { > > + 'hostfwd': 'bool', > > + 'expire-time-ms': 'int', > > + 'fd': 'int', > > + 'src-addr': 'str', > > + 'src-port': 'int', > > + 'dest-addr': 'str', > > + 'dest-port': 'int', > > + 'recv-buffered': 'int', > > + 'send-buffered': 'int' > > + } } > > + > > +## > > +# @UsernetICMPConnection: > > +# > > +# SLIRP ICMP information. > > +# > > +# @expire-time-ms: time in microseconds after which this connection will > > expire > > +# > > +# @fd: the file descriptor of the connection > > +# > > +# @src-addr: source address of host port forwarding > > +# > > +# @dest-addr: destination address of host port forwarding > > +# > > +# @recv-buffered: number of bytes queued in the receive buffer > > +# > > +# @send-buffered: number of bytes queued in the send buffer > > +# > > +# Since: 2.13 > > +## > > +{ 'struct': 'UsernetICMPConnection', > > + 'data': { > > + 'expire-time-ms': 'int', > > + 'fd': 'int', > > + 'src-addr': 'str', > > + 'dest-addr': 'str', > > + 'recv-buffered': 'int', > > + 'send-buffered': 'int' > > + } } > > + > > +## > > +# @UsernetType: > > +# > > +# Available netdev drivers. > > +# > > +# Since: 2.13 > > +## > > +{ 'enum': 'UsernetType', > > + 'data': [ 'tcp', 'udp', 'icmp' ] } > > + > > +## > > +# @UsernetConnection: > > +# > > +# SLIRP usernet connection information. > > +# > > +# Since: 2.13 > > +## > > +{ 'union': 'UsernetConnection', > > + 'discriminator': 'type', > > + 'base': { 'type': 'UsernetType' }, > > + 'data': { > > + 'tcp': 'UsernetTCPConnection', > > + 'udp': 'UsernetUDPConnection', > > + 'icmp': 'UsernetICMPConnection' > > + } } > > + > > +## > > +# @UsernetInfo: > > +# > > +# SLIRP usernet information. > > +# > > +# Since: 2.13 > > +## > > +{ 'struct': 'UsernetInfo', > > + 'data': { > > + 'id': 'str', > > + 'hub': 'int', > > + 'connections': ['UsernetConnection'] > > +} } > > + > > +## > > +# @query-usernet: > > +# > > +# Return SLIRP network information. > > +# > > +# Since: 2.13 > > +# > > +# Example: > > +# > > +# -> { "execute": "query-usernet", "arguments": { } } > > +# <- { "return": [ > > +# { > > +# "hub": -1, > > +# "connections": [ > > +# { > > +# "dest-addr": "10.0.2.15", > > +# "recv-buffered": 0, > > +# "src-port": 10022, > > +# "state": "closed", > > +# "fd": 16, > > +# "src-addr": "*", > > +# "send-buffered": 0, > > +# "dest-port": 22, > > +# "type": "tcp", > > +# "hostfwd": true > > +# } > > +# ], > > +# "id": "vnet" > > +# } > > +# ]} > > +# > > +## > > +{ 'command': 'query-usernet', > > + 'returns': ['UsernetInfo'] } > > diff --git a/slirp/libslirp.h b/slirp/libslirp.h > > index 540b3e5903..3ba361ea41 100644 > > --- a/slirp/libslirp.h > > +++ b/slirp/libslirp.h > > @@ -2,6 +2,7 @@ > > #define LIBSLIRP_H > > > > #include "qemu-common.h" > > +#include "qapi/qapi-commands-net.h" > > > > typedef struct Slirp Slirp; > > > > @@ -37,6 +38,7 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void > > *args, > > struct in_addr *guest_addr, int guest_port); > > > > void slirp_connection_info(Slirp *slirp, Monitor *mon); > > +void usernet_get_info(Slirp *slirp, UsernetInfo *info); > > > > void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, > > int guest_port, const uint8_t *buf, int size); > > diff --git a/slirp/misc.c b/slirp/misc.c > > index 260187b6b6..335b49aad8 100644 > > --- a/slirp/misc.c > > +++ b/slirp/misc.c > > @@ -205,39 +205,28 @@ fork_exec(struct socket *so, const char *ex, int > > do_pty) > > } > > #endif > > > > -void slirp_connection_info(Slirp *slirp, Monitor *mon) > > +void usernet_get_info(Slirp *slirp, UsernetInfo *info) > > { > > - const char * const tcpstates[] = { > > - [TCPS_CLOSED] = "CLOSED", > > - [TCPS_LISTEN] = "LISTEN", > > - [TCPS_SYN_SENT] = "SYN_SENT", > > - [TCPS_SYN_RECEIVED] = "SYN_RCVD", > > - [TCPS_ESTABLISHED] = "ESTABLISHED", > > - [TCPS_CLOSE_WAIT] = "CLOSE_WAIT", > > - [TCPS_FIN_WAIT_1] = "FIN_WAIT_1", > > - [TCPS_CLOSING] = "CLOSING", > > - [TCPS_LAST_ACK] = "LAST_ACK", > > - [TCPS_FIN_WAIT_2] = "FIN_WAIT_2", > > - [TCPS_TIME_WAIT] = "TIME_WAIT", > > - }; > > struct in_addr dst_addr; > > struct sockaddr_in src; > > socklen_t src_len; > > uint16_t dst_port; > > struct socket *so; > > - const char *state; > > - char buf[20]; > > - > > - monitor_printf(mon, " Protocol[State] FD Source Address Port " > > - "Dest. Address Port RecvQ SendQ\n"); > > + UsernetConnectionList **p_next = &info->connections; > > > > for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { > > + UsernetConnection *conn = g_new0(UsernetConnection, 1); > > + UsernetTCPConnection *tcp = &conn->u.tcp; > > + UsernetConnectionList *list = g_new0(UsernetConnectionList, 1); > > + > > + list->value = conn; > > if (so->so_state & SS_HOSTFWD) { > > - state = "HOST_FORWARD"; > > + tcp->hostfwd = true; > > + tcp->state = so->so_tcpcb->t_state; > > } else if (so->so_tcpcb) { > > - state = tcpstates[so->so_tcpcb->t_state]; > > + tcp->state = so->so_tcpcb->t_state; > > } else { > > - state = "NONE"; > > + tcp->state = TCPS_NONE; > > } > > if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) { > > src_len = sizeof(src); > > @@ -250,46 +239,125 @@ void slirp_connection_info(Slirp *slirp, Monitor > > *mon) > > dst_addr = so->so_faddr; > > dst_port = so->so_fport; > > } > > - snprintf(buf, sizeof(buf), " TCP[%s]", state); > > - monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s, > > - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", > > - ntohs(src.sin_port)); > > - monitor_printf(mon, "%15s %5d %5d %5d\n", > > - inet_ntoa(dst_addr), ntohs(dst_port), > > - so->so_rcv.sb_cc, so->so_snd.sb_cc); > > + tcp->fd = so->s; > > + tcp->src_addr = > > + g_strdup(src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*"); > > + tcp->src_port = ntohs(src.sin_port); > > + tcp->dest_addr = g_strdup(inet_ntoa(dst_addr)); > > + tcp->dest_port = ntohs(dst_port); > > + tcp->recv_buffered = so->so_rcv.sb_cc; > > + tcp->send_buffered = so->so_snd.sb_cc; > > + *p_next = list; > > + p_next = &list->next; > > } > > - > > for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) { > > + UsernetConnection *conn = g_new0(UsernetConnection, 1); > > + UsernetUDPConnection *udp = &conn->u.udp; > > + UsernetConnectionList *list = g_new0(UsernetConnectionList, 1); > > + > > + list->value = conn; > > if (so->so_state & SS_HOSTFWD) { > > - snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); > > + udp->hostfwd = true; > > src_len = sizeof(src); > > getsockname(so->s, (struct sockaddr *)&src, &src_len); > > dst_addr = so->so_laddr; > > dst_port = so->so_lport; > > } else { > > - snprintf(buf, sizeof(buf), " UDP[%d sec]", > > - (so->so_expire - curtime) / 1000); > > + udp->expire_time_ms = so->so_expire - curtime; > > src.sin_addr = so->so_laddr; > > src.sin_port = so->so_lport; > > dst_addr = so->so_faddr; > > dst_port = so->so_fport; > > } > > - monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s, > > - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", > > - ntohs(src.sin_port)); > > - monitor_printf(mon, "%15s %5d %5d %5d\n", > > - inet_ntoa(dst_addr), ntohs(dst_port), > > - so->so_rcv.sb_cc, so->so_snd.sb_cc); > > + udp->fd = so->s; > > + udp->src_addr = > > + g_strdup(src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*"); > > + udp->src_port = ntohs(src.sin_port); > > + udp->dest_addr = g_strdup(inet_ntoa(dst_addr)); > > + udp->dest_port = ntohs(dst_port); > > + udp->recv_buffered = so->so_rcv.sb_cc; > > + udp->send_buffered = so->so_snd.sb_cc; > > + *p_next = list; > > + p_next = &list->next; > > } > > > > for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) { > > - snprintf(buf, sizeof(buf), " ICMP[%d sec]", > > - (so->so_expire - curtime) / 1000); > > + UsernetConnection *conn = g_new0(UsernetConnection, 1); > > + UsernetICMPConnection *icmp = &conn->u.icmp; > > + UsernetConnectionList *list = g_new0(UsernetConnectionList, 1); > > + > > + icmp->expire_time_ms = so->so_expire - curtime; > > src.sin_addr = so->so_laddr; > > dst_addr = so->so_faddr; > > - monitor_printf(mon, "%-19s %3d %15s - ", buf, so->s, > > - src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : > > "*"); > > - monitor_printf(mon, "%15s - %5d %5d\n", inet_ntoa(dst_addr), > > - so->so_rcv.sb_cc, so->so_snd.sb_cc); > > + icmp->fd = so->s; > > + icmp->src_addr = > > + g_strdup(src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*"); > > + icmp->dest_addr = g_strdup(inet_ntoa(dst_addr)); > > + icmp->recv_buffered = so->so_rcv.sb_cc; > > + icmp->send_buffered = so->so_snd.sb_cc; > > + *p_next = list; > > + p_next = &list->next; > > } > > } > > + > > + > > +void slirp_connection_info(Slirp *slirp, Monitor *mon) > > +{ > > + const char *state; > > + char buf[64]; > > + UsernetInfo *info = g_new0(UsernetInfo, 1); > > + UsernetConnectionList *cl; > > + > > + monitor_printf(mon, " Protocol[State] FD Source Address Port " > > + "Dest. Address Port RecvQ SendQ\n"); > > + > > + usernet_get_info(slirp, info); > > + for (cl = info->connections; cl && cl->value; cl = cl->next) { > > + UsernetConnection *conn = cl->value; > > + > > + if (conn->type == USERNET_TYPE_TCP) { > > + UsernetTCPConnection *tcp = &conn->u.tcp; > > + > > + if (tcp->hostfwd) { > > + state = "HOST_FORWARD"; > > + } else { > > + state = TCPS_str(tcp->state); > > + } > > + snprintf(buf, sizeof(buf), " TCP[%s]", state); > > + monitor_printf(mon, "%-19s %3" PRId64 " %15s %5" PRId64 " ", > > + buf, tcp->fd, > > + tcp->src_addr, tcp->src_port); > > + monitor_printf(mon, "%15s %5" PRId64 " %5" PRId64 " %5" PRId64 > > "\n", > > + tcp->dest_addr, tcp->dest_port, > > + tcp->recv_buffered, tcp->send_buffered); > > + } else if (conn->type == USERNET_TYPE_UDP) { > > + UsernetUDPConnection *udp = &conn->u.udp; > > + > > + if (udp->hostfwd) { > > + snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); > > + } else { > > + snprintf(buf, sizeof(buf), " UDP[%" PRId64 " sec]", > > + udp->expire_time_ms / 1000); > > + } > > + monitor_printf(mon, "%-19s %3" PRId64 " %15s %5" PRId64 " ", > > + buf, udp->fd, > > + udp->src_addr, udp->src_port); > > + monitor_printf(mon, "%15s %5" PRId64 " %5" PRId64 " %5" PRId64 > > "\n", > > + udp->dest_addr, udp->dest_port, > > + udp->recv_buffered, udp->send_buffered); > > + } else { > > + UsernetICMPConnection *icmp = &conn->u.icmp; > > + > > + assert(conn->type == USERNET_TYPE_ICMP); > > + snprintf(buf, sizeof(buf), " ICMP[%" PRId64 " sec]", > > + icmp->expire_time_ms / 1000); > > + monitor_printf(mon, "%-19s %3" PRId64 " %15s - ", buf, > > icmp->fd, > > + icmp->src_addr); > > + monitor_printf(mon, "%15s - %5" PRId64 " %5" PRId64 "\n", > > + icmp->dest_addr, > > + icmp->recv_buffered, icmp->send_buffered); > > + } > > + } > > + > > + qapi_free_UsernetInfo(info); > > +} > > diff --git a/slirp/tcp.h b/slirp/tcp.h > > index 174d3d960c..155569f380 100644 > > --- a/slirp/tcp.h > > +++ b/slirp/tcp.h > > @@ -133,21 +133,6 @@ struct tcphdr { > > > > #define TCP_NSTATES 11 > > > > -#define TCPS_CLOSED 0 /* closed */ > > -#define TCPS_LISTEN 1 /* listening for connection */ > > -#define TCPS_SYN_SENT 2 /* active, have sent syn */ > > -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ > > -/* states < TCPS_ESTABLISHED are those where connections not established */ > > -#define TCPS_ESTABLISHED 4 /* established */ > > -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ > > -/* states > TCPS_CLOSE_WAIT are those where user has closed */ > > -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ > > -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK > > */ > > -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN > > ACK */ > > -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ > > -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ > > -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close > > */ > > - > > #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) > > #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) > > #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) > > -- > > 2.14.3 > > > > > > Regards, > Daniel > -- > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| > |: https://libvirt.org -o- https://fstop138.berrange.com :| > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|