From 0bc12c4f7e8b5ff0f83908bdef0c247f1ca1a9d8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:12 +0800 Subject: [PATCH 01/16] stubs: Add qemu_set_fd_handler Some qemu_set_fd_handler2 stub callers will be converted to call qemu_set_fd_handler, add this stub for them before making the change. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-2-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- stubs/set-fd-handler.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c index fc874d33fe..25cca8c433 100644 --- a/stubs/set-fd-handler.c +++ b/stubs/set-fd-handler.c @@ -1,6 +1,14 @@ #include "qemu-common.h" #include "qemu/main-loop.h" +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) +{ + abort(); +} + int qemu_set_fd_handler2(int fd, IOCanReadHandler *fd_read_poll, IOHandler *fd_read, From 95b1416ae93106923f733941e52dfe55c4318643 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:14 +0800 Subject: [PATCH 02/16] l2tpv3: Drop l2tpv3_can_send This callback is called by main loop before polling s->fd, if it returns false, the fd will not be polled in this iteration. This is redundant with checks inside read callback. After this patch, the data will be copied from s->fd to s->msgvec when it arrives. If the device can't receive, it will be queued to incoming_queue, and when the device status changes, this queue will be flushed. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-4-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- net/l2tpv3.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/net/l2tpv3.c b/net/l2tpv3.c index ed395dc126..99d80b6bff 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -133,14 +133,12 @@ typedef struct NetL2TPV3State { } NetL2TPV3State; -static int l2tpv3_can_send(void *opaque); static void net_l2tpv3_send(void *opaque); static void l2tpv3_writable(void *opaque); static void l2tpv3_update_fd_handler(NetL2TPV3State *s) { - qemu_set_fd_handler2(s->fd, - s->read_poll ? l2tpv3_can_send : NULL, + qemu_set_fd_handler2(s->fd, NULL, s->read_poll ? net_l2tpv3_send : NULL, s->write_poll ? l2tpv3_writable : NULL, s); @@ -169,13 +167,6 @@ static void l2tpv3_writable(void *opaque) qemu_flush_queued_packets(&s->nc); } -static int l2tpv3_can_send(void *opaque) -{ - NetL2TPV3State *s = opaque; - - return qemu_can_send_packet(&s->nc); -} - static void l2tpv3_send_completed(NetClientState *nc, ssize_t len) { NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); From e8dd1d9c396104f0fac4b39a701143df49df2a74 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:15 +0800 Subject: [PATCH 03/16] netmap: Drop netmap_can_send This callback is called by main loop before polling s->fd, if it returns false, the fd will not be polled in this iteration. This is redundant with checks inside read callback. After this patch, the data will be copied from s->fd to s->iov when it arrives. If the device can't receive, it will be queued to incoming_queue, and when the device status changes, this queue will be flushed. Also remove the qemu_can_send_packet() check in netmap_send. If it's true, we are good; if it's false, the qemu_sendv_packet_async would return 0 and read poll will be disabled until netmap_send_completed is called. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-5-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- net/netmap.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/net/netmap.c b/net/netmap.c index 69300eb1ae..19d054287d 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -132,23 +132,13 @@ error: return -1; } -/* Tell the event-loop if the netmap backend can send packets - to the frontend. */ -static int netmap_can_send(void *opaque) -{ - NetmapState *s = opaque; - - return qemu_can_send_packet(&s->nc); -} - static void netmap_send(void *opaque); static void netmap_writable(void *opaque); /* Set the event-loop handlers for the netmap backend. */ static void netmap_update_fd_handler(NetmapState *s) { - qemu_set_fd_handler2(s->me.fd, - s->read_poll ? netmap_can_send : NULL, + qemu_set_fd_handler2(s->me.fd, NULL, s->read_poll ? netmap_send : NULL, s->write_poll ? netmap_writable : NULL, s); @@ -317,7 +307,7 @@ static void netmap_send(void *opaque) /* Keep sending while there are available packets into the netmap RX ring and the forwarding path towards the peer is open. */ - while (!nm_ring_empty(ring) && qemu_can_send_packet(&s->nc)) { + while (!nm_ring_empty(ring)) { uint32_t i; uint32_t idx; bool morefrag; From 6e99c631f116221d169ea53953d91b8aa74d297a Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:16 +0800 Subject: [PATCH 04/16] net/socket: Drop net_socket_can_send This callback is called by main loop before polling s->fd, if it returns false, the fd will not be polled in this iteration. This is redundant with checks inside read callback. After this patch, the data will be sent to peer when it arrives. If the device can't receive, it will be queued to incoming_queue, and when the device status changes, this queue will be flushed. If the peer is not ready, disable the read poll until send completes. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-6-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- net/socket.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/net/socket.c b/net/socket.c index 5a19aa1881..7055d1e9fa 100644 --- a/net/socket.c +++ b/net/socket.c @@ -51,18 +51,9 @@ typedef struct NetSocketState { static void net_socket_accept(void *opaque); static void net_socket_writable(void *opaque); -/* Only read packets from socket when peer can receive them */ -static int net_socket_can_send(void *opaque) -{ - NetSocketState *s = opaque; - - return qemu_can_send_packet(&s->nc); -} - static void net_socket_update_fd_handler(NetSocketState *s) { - qemu_set_fd_handler2(s->fd, - s->read_poll ? net_socket_can_send : NULL, + qemu_set_fd_handler2(s->fd, NULL, s->read_poll ? s->send_fn : NULL, s->write_poll ? net_socket_writable : NULL, s); @@ -142,6 +133,15 @@ static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, return ret; } +static void net_socket_send_completed(NetClientState *nc, ssize_t len) +{ + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); + + if (!s->read_poll) { + net_socket_read_poll(s, true); + } +} + static void net_socket_send(void *opaque) { NetSocketState *s = opaque; @@ -211,9 +211,13 @@ static void net_socket_send(void *opaque) buf += l; size -= l; if (s->index >= s->packet_len) { - qemu_send_packet(&s->nc, s->buf, s->packet_len); s->index = 0; s->state = 0; + if (qemu_send_packet_async(&s->nc, s->buf, size, + net_socket_send_completed) == 0) { + net_socket_read_poll(s, false); + break; + } } break; } @@ -234,7 +238,10 @@ static void net_socket_send_dgram(void *opaque) net_socket_write_poll(s, false); return; } - qemu_send_packet(&s->nc, s->buf, size); + if (qemu_send_packet_async(&s->nc, s->buf, size, + net_socket_send_completed) == 0) { + net_socket_read_poll(s, false); + } } static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr) From a90a7425cf592a3afeff3eaf32f543b83050ee5c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:17 +0800 Subject: [PATCH 05/16] tap: Drop tap_can_send This callback is called by main loop before polling s->fd, if it returns false, the fd will not be polled in this iteration. This is redundant with checks inside read callback. After this patch, the data will be sent to peer when it arrives. If the device can't receive, it will be queued to incoming_queue, and when the device status changes, this queue will be flushed. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-7-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- net/tap.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/net/tap.c b/net/tap.c index d1ca314dcf..0d184cfa01 100644 --- a/net/tap.c +++ b/net/tap.c @@ -62,14 +62,12 @@ typedef struct TAPState { static void launch_script(const char *setup_script, const char *ifname, int fd, Error **errp); -static int tap_can_send(void *opaque); static void tap_send(void *opaque); static void tap_writable(void *opaque); static void tap_update_fd_handler(TAPState *s) { - qemu_set_fd_handler2(s->fd, - s->read_poll && s->enabled ? tap_can_send : NULL, + qemu_set_fd_handler2(s->fd, NULL, s->read_poll && s->enabled ? tap_send : NULL, s->write_poll && s->enabled ? tap_writable : NULL, s); @@ -166,13 +164,6 @@ static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size) return tap_write_packet(s, iov, 1); } -static int tap_can_send(void *opaque) -{ - TAPState *s = opaque; - - return qemu_can_send_packet(&s->nc); -} - #ifndef __sun__ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) { @@ -192,7 +183,7 @@ static void tap_send(void *opaque) int size; int packets = 0; - while (qemu_can_send_packet(&s->nc)) { + while (true) { uint8_t *buf = s->buf; size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); From 82e1cc4bf91a2e1c3b62297b10b0ab1d93adfc45 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:18 +0800 Subject: [PATCH 06/16] Change qemu_set_fd_handler2(..., NULL, ...) to qemu_set_fd_handler Done with following Coccinelle semantic patch, plus manual cosmetic changes in net/*.c. @@ expression E1, E2, E3, E4; @@ - qemu_set_fd_handler2(E1, NULL, E2, E3, E4); + qemu_set_fd_handler(E1, E2, E3, E4); Signed-off-by: Fam Zheng Message-id: 1433400324-7358-8-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev-nbd.c | 4 ++-- main-loop.c | 3 +-- migration/exec.c | 6 +++--- migration/fd.c | 4 ++-- migration/rdma.c | 7 +++---- migration/tcp.c | 6 +++--- migration/unix.c | 6 +++--- net/l2tpv3.c | 8 ++++---- net/netmap.c | 8 ++++---- net/socket.c | 8 ++++---- net/tap.c | 8 ++++---- ui/vnc-auth-sasl.c | 2 +- ui/vnc-auth-vencrypt.c | 2 +- ui/vnc-ws.c | 6 +++--- ui/vnc.c | 27 ++++++++++++--------------- util/qemu-sockets.c | 8 +++----- 16 files changed, 53 insertions(+), 60 deletions(-) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 85cda4cfa7..0d9df47ce4 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -43,7 +43,7 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp) server_fd = socket_listen(addr, errp); if (server_fd != -1) { - qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL); + qemu_set_fd_handler(server_fd, nbd_accept, NULL, NULL); } } @@ -129,7 +129,7 @@ void qmp_nbd_server_stop(Error **errp) } if (server_fd != -1) { - qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(server_fd, NULL, NULL, NULL); close(server_fd); server_fd = -1; } diff --git a/main-loop.c b/main-loop.c index 981bcb5f8e..82875a4dfd 100644 --- a/main-loop.c +++ b/main-loop.c @@ -100,8 +100,7 @@ static int qemu_signal_init(void) fcntl_setfl(sigfd, O_NONBLOCK); - qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, - (void *)(intptr_t)sigfd); + qemu_set_fd_handler(sigfd, sigfd_handler, NULL, (void *)(intptr_t)sigfd); return 0; } diff --git a/migration/exec.c b/migration/exec.c index 479024752f..8406d2bbde 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -49,7 +49,7 @@ static void exec_accept_incoming_migration(void *opaque) { QEMUFile *f = opaque; - qemu_set_fd_handler2(qemu_get_fd(f), NULL, NULL, NULL, NULL); + qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL); process_incoming_migration(f); } @@ -64,6 +64,6 @@ void exec_start_incoming_migration(const char *command, Error **errp) return; } - qemu_set_fd_handler2(qemu_get_fd(f), NULL, - exec_accept_incoming_migration, NULL, f); + qemu_set_fd_handler(qemu_get_fd(f), exec_accept_incoming_migration, NULL, + f); } diff --git a/migration/fd.c b/migration/fd.c index 129da9910b..3e4bed0e06 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -62,7 +62,7 @@ static void fd_accept_incoming_migration(void *opaque) { QEMUFile *f = opaque; - qemu_set_fd_handler2(qemu_get_fd(f), NULL, NULL, NULL, NULL); + qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL); process_incoming_migration(f); } @@ -84,5 +84,5 @@ void fd_start_incoming_migration(const char *infd, Error **errp) return; } - qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f); + qemu_set_fd_handler(fd, fd_accept_incoming_migration, NULL, f); } diff --git a/migration/rdma.c b/migration/rdma.c index 77e34441dc..171c23fc3c 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2834,7 +2834,7 @@ static int qemu_rdma_accept(RDMAContext *rdma) } } - qemu_set_fd_handler2(rdma->channel->fd, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(rdma->channel->fd, NULL, NULL, NULL); ret = rdma_accept(rdma->cm_id, &conn_param); if (ret) { @@ -3331,9 +3331,8 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp) trace_rdma_start_incoming_migration_after_rdma_listen(); - qemu_set_fd_handler2(rdma->channel->fd, NULL, - rdma_accept_incoming_migration, NULL, - (void *)(intptr_t) rdma); + qemu_set_fd_handler(rdma->channel->fd, rdma_accept_incoming_migration, + NULL, (void *)(intptr_t)rdma); return; err: error_propagate(errp, local_err); diff --git a/migration/tcp.c b/migration/tcp.c index 91c9cf381e..ae891728ef 100644 --- a/migration/tcp.c +++ b/migration/tcp.c @@ -65,7 +65,7 @@ static void tcp_accept_incoming_migration(void *opaque) c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); err = socket_error(); } while (c < 0 && err == EINTR); - qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(s, NULL, NULL, NULL); closesocket(s); DPRINTF("accepted migration\n"); @@ -98,6 +98,6 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp) return; } - qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL, - (void *)(intptr_t)s); + qemu_set_fd_handler(s, tcp_accept_incoming_migration, NULL, + (void *)(intptr_t)s); } diff --git a/migration/unix.c b/migration/unix.c index 1cdadfbc83..b591813eb9 100644 --- a/migration/unix.c +++ b/migration/unix.c @@ -65,7 +65,7 @@ static void unix_accept_incoming_migration(void *opaque) c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen); err = errno; } while (c < 0 && err == EINTR); - qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(s, NULL, NULL, NULL); close(s); DPRINTF("accepted migration\n"); @@ -98,6 +98,6 @@ void unix_start_incoming_migration(const char *path, Error **errp) return; } - qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL, - (void *)(intptr_t)s); + qemu_set_fd_handler(s, unix_accept_incoming_migration, NULL, + (void *)(intptr_t)s); } diff --git a/net/l2tpv3.c b/net/l2tpv3.c index 99d80b6bff..356dae2b72 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -138,10 +138,10 @@ static void l2tpv3_writable(void *opaque); static void l2tpv3_update_fd_handler(NetL2TPV3State *s) { - qemu_set_fd_handler2(s->fd, NULL, - s->read_poll ? net_l2tpv3_send : NULL, - s->write_poll ? l2tpv3_writable : NULL, - s); + qemu_set_fd_handler(s->fd, + s->read_poll ? net_l2tpv3_send : NULL, + s->write_poll ? l2tpv3_writable : NULL, + s); } static void l2tpv3_read_poll(NetL2TPV3State *s, bool enable) diff --git a/net/netmap.c b/net/netmap.c index 19d054287d..508b82947d 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -138,10 +138,10 @@ static void netmap_writable(void *opaque); /* Set the event-loop handlers for the netmap backend. */ static void netmap_update_fd_handler(NetmapState *s) { - qemu_set_fd_handler2(s->me.fd, NULL, - s->read_poll ? netmap_send : NULL, - s->write_poll ? netmap_writable : NULL, - s); + qemu_set_fd_handler(s->me.fd, + s->read_poll ? netmap_send : NULL, + s->write_poll ? netmap_writable : NULL, + s); } /* Update the read handler. */ diff --git a/net/socket.c b/net/socket.c index 7055d1e9fa..c752696cbb 100644 --- a/net/socket.c +++ b/net/socket.c @@ -53,10 +53,10 @@ static void net_socket_writable(void *opaque); static void net_socket_update_fd_handler(NetSocketState *s) { - qemu_set_fd_handler2(s->fd, NULL, - s->read_poll ? s->send_fn : NULL, - s->write_poll ? net_socket_writable : NULL, - s); + qemu_set_fd_handler(s->fd, + s->read_poll ? s->send_fn : NULL, + s->write_poll ? net_socket_writable : NULL, + s); } static void net_socket_read_poll(NetSocketState *s, bool enable) diff --git a/net/tap.c b/net/tap.c index 0d184cfa01..aa8b3f5c8c 100644 --- a/net/tap.c +++ b/net/tap.c @@ -67,10 +67,10 @@ static void tap_writable(void *opaque); static void tap_update_fd_handler(TAPState *s) { - qemu_set_fd_handler2(s->fd, NULL, - s->read_poll && s->enabled ? tap_send : NULL, - s->write_poll && s->enabled ? tap_writable : NULL, - s); + qemu_set_fd_handler(s->fd, + s->read_poll && s->enabled ? tap_send : NULL, + s->write_poll && s->enabled ? tap_writable : NULL, + s); } static void tap_read_poll(TAPState *s, bool enable) diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index 2ddd2591f9..62a5fc4bf1 100644 --- a/ui/vnc-auth-sasl.c +++ b/ui/vnc-auth-sasl.c @@ -86,7 +86,7 @@ long vnc_client_write_sasl(VncState *vs) * SASL encoded output */ if (vs->output.offset == 0) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); } return ret; diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index 03ea48a69c..8fc965b4ad 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -94,7 +94,7 @@ static int vnc_start_vencrypt_handshake(VncState *vs) } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs); start_auth_vencrypt_subauth(vs); diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 38a1b8b646..8c18268054 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -56,7 +56,7 @@ static int vncws_start_tls_handshake(VncState *vs) } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); - qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs); return 0; } @@ -98,7 +98,7 @@ void vncws_handshake_read(void *opaque) handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer, vs->ws_input.offset, WS_HANDSHAKE_END); if (handshake_end) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + strlen(WS_HANDSHAKE_END)); @@ -176,7 +176,7 @@ long vnc_client_write_ws(VncState *vs) buffer_advance(&vs->ws_output, ret); if (vs->ws_output.offset == 0) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); } return ret; diff --git a/ui/vnc.c b/ui/vnc.c index 0c6b5e3553..69b605c709 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1213,7 +1213,7 @@ static void vnc_disconnect_start(VncState *vs) if (vs->csock == -1) return; vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); - qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(vs->csock, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; } @@ -1387,7 +1387,7 @@ static long vnc_client_write_plain(VncState *vs) buffer_advance(&vs->output, ret); if (vs->output.offset == 0) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); } return ret; @@ -1434,7 +1434,7 @@ void vnc_client_write(void *opaque) ) { vnc_client_write_locked(opaque); } else if (vs->csock != -1) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); } vnc_unlock_output(vs); } @@ -1581,7 +1581,7 @@ void vnc_write(VncState *vs, const void *data, size_t len) buffer_reserve(&vs->output, len); if (vs->csock != -1 && buffer_empty(&vs->output)) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs); } buffer_append(&vs->output, data, len); @@ -3022,18 +3022,16 @@ static void vnc_connect(VncDisplay *vd, int csock, vs->websocket = 1; #ifdef CONFIG_VNC_TLS if (vd->ws_tls) { - qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_io, - NULL, vs); + qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs); } else #endif /* CONFIG_VNC_TLS */ { - qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, - NULL, vs); + qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs); } } else #endif /* CONFIG_VNC_WS */ { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs); } vnc_client_cache_addr(vs); @@ -3182,14 +3180,14 @@ static void vnc_display_close(VncDisplay *vs) vs->enabled = false; vs->is_unix = false; if (vs->lsock != -1) { - qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(vs->lsock, NULL, NULL, NULL); close(vs->lsock); vs->lsock = -1; } #ifdef CONFIG_VNC_WS vs->ws_enabled = false; if (vs->lwebsock != -1) { - qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(vs->lwebsock, NULL, NULL, NULL); close(vs->lwebsock); vs->lwebsock = -1; } @@ -3707,12 +3705,11 @@ void vnc_display_open(const char *id, Error **errp) #endif /* CONFIG_VNC_WS */ } vs->enabled = true; - qemu_set_fd_handler2(vs->lsock, NULL, - vnc_listen_regular_read, NULL, vs); + qemu_set_fd_handler(vs->lsock, vnc_listen_regular_read, NULL, vs); #ifdef CONFIG_VNC_WS if (vs->ws_enabled) { - qemu_set_fd_handler2(vs->lwebsock, NULL, - vnc_listen_websocket_read, NULL, vs); + qemu_set_fd_handler(vs->lwebsock, vnc_listen_websocket_read, + NULL, vs); } #endif /* CONFIG_VNC_WS */ } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index f9ad34e40c..4026314435 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -244,7 +244,7 @@ static void wait_for_connect(void *opaque) bool in_progress; Error *err = NULL; - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); do { rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize); @@ -316,8 +316,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; - qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, - connect_state); + qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); *in_progress = true; } else if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); @@ -796,8 +795,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; - qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, - connect_state); + qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); return sock; } else if (rc >= 0) { /* non blocking socket immediate success, call callback */ From 6484e422479c93f28e3f8a68258b0eacd3b31e6d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:19 +0800 Subject: [PATCH 07/16] main-loop: Drop qemu_set_fd_handler2 All users are converted to qemu_set_fd_handler now, drop qemu_set_fd_handler2 and IOHandlerRecord.fd_read_poll. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-9-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- include/block/aio.h | 2 +- include/qemu/main-loop.h | 49 +--------------------------------------- iohandler.c | 26 ++++----------------- stubs/set-fd-handler.c | 9 -------- 4 files changed, 7 insertions(+), 79 deletions(-) diff --git a/include/block/aio.h b/include/block/aio.h index d2bb423de1..b46103ece7 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -241,7 +241,7 @@ bool aio_dispatch(AioContext *ctx); bool aio_poll(AioContext *ctx, bool blocking); /* Register a file descriptor and associated callbacks. Behaves very similarly - * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will + * to qemu_set_fd_handler. Unlike qemu_set_fd_handler, these callbacks will * be invoked when using aio_poll(). * * Code that invokes AIO completion functions should rely on this function diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 62c68c0f32..7da1d63fb0 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -96,8 +96,7 @@ AioContext *qemu_get_aio_context(void); * that the main loop waits for. * * Calling qemu_notify_event is rarely necessary, because main loop - * services (bottom halves and timers) call it themselves. One notable - * exception occurs when using qemu_set_fd_handler2 (see below). + * services (bottom halves and timers) call it themselves. */ void qemu_notify_event(void); @@ -171,52 +170,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); typedef int IOCanReadHandler(void *opaque); -/** - * qemu_set_fd_handler2: Register a file descriptor with the main loop - * - * This function tells the main loop to wake up whenever one of the - * following conditions is true: - * - * 1) if @fd_write is not %NULL, when the file descriptor is writable; - * - * 2) if @fd_read is not %NULL, when the file descriptor is readable. - * - * @fd_read_poll can be used to disable the @fd_read callback temporarily. - * This is useful to avoid calling qemu_set_fd_handler2 every time the - * client becomes interested in reading (or dually, stops being interested). - * A typical example is when @fd is a listening socket and you want to bound - * the number of active clients. Remember to call qemu_notify_event whenever - * the condition may change from %false to %true. - * - * The callbacks that are set up by qemu_set_fd_handler2 are level-triggered. - * If @fd_read does not read from @fd, or @fd_write does not write to @fd - * until its buffers are full, they will be called again on the next - * iteration. - * - * @fd: The file descriptor to be observed. Under Windows it must be - * a #SOCKET. - * - * @fd_read_poll: A function that returns 1 if the @fd_read callback - * should be fired. If the function returns 0, the main loop will not - * end its iteration even if @fd becomes readable. - * - * @fd_read: A level-triggered callback that is fired if @fd is readable - * at the beginning of a main loop iteration, or if it becomes readable - * during one. - * - * @fd_write: A level-triggered callback that is fired when @fd is writable - * at the beginning of a main loop iteration, or if it becomes writable - * during one. - * - * @opaque: A pointer-sized value that is passed to @fd_read_poll, - * @fd_read and @fd_write. - */ -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); - /** * qemu_set_fd_handler: Register a file descriptor with the main loop * diff --git a/iohandler.c b/iohandler.c index cca614f087..d361cf2c03 100644 --- a/iohandler.c +++ b/iohandler.c @@ -33,7 +33,6 @@ #endif typedef struct IOHandlerRecord { - IOCanReadHandler *fd_read_poll; IOHandler *fd_read; IOHandler *fd_write; void *opaque; @@ -46,14 +45,10 @@ typedef struct IOHandlerRecord { static QLIST_HEAD(, IOHandlerRecord) io_handlers = QLIST_HEAD_INITIALIZER(io_handlers); - -/* XXX: fd_read_poll should be suppressed, but an API change is - necessary in the character devices to suppress fd_can_read(). */ -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { IOHandlerRecord *ioh; @@ -75,7 +70,6 @@ int qemu_set_fd_handler2(int fd, QLIST_INSERT_HEAD(&io_handlers, ioh, next); found: ioh->fd = fd; - ioh->fd_read_poll = fd_read_poll; ioh->fd_read = fd_read; ioh->fd_write = fd_write; ioh->opaque = opaque; @@ -86,14 +80,6 @@ int qemu_set_fd_handler2(int fd, return 0; } -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); -} - void qemu_iohandler_fill(GArray *pollfds) { IOHandlerRecord *ioh; @@ -103,9 +89,7 @@ void qemu_iohandler_fill(GArray *pollfds) if (ioh->deleted) continue; - if (ioh->fd_read && - (!ioh->fd_read_poll || - ioh->fd_read_poll(ioh->opaque) != 0)) { + if (ioh->fd_read) { events |= G_IO_IN | G_IO_HUP | G_IO_ERR; } if (ioh->fd_write) { diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c index 25cca8c433..a895e623f8 100644 --- a/stubs/set-fd-handler.c +++ b/stubs/set-fd-handler.c @@ -8,12 +8,3 @@ int qemu_set_fd_handler(int fd, { abort(); } - -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - abort(); -} From be93f216278d84d283187c95cef16c0b60b711b8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:20 +0800 Subject: [PATCH 08/16] alsaaudio: Remove unused error handling of qemu_set_fd_handler The function cannot fail, so the check is superfluous. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-10-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- audio/alsaaudio.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 74ead97d87..ed7655de86 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -266,31 +266,19 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask) for (i = 0; i < count; ++i) { if (pfds[i].events & POLLIN) { - err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, - NULL, hlp); + qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp); } if (pfds[i].events & POLLOUT) { if (conf.verbose) { dolog ("POLLOUT %d %d\n", i, pfds[i].fd); } - err = qemu_set_fd_handler (pfds[i].fd, NULL, - alsa_poll_handler, hlp); + qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp); } if (conf.verbose) { dolog ("Set handler events=%#x index=%d fd=%d err=%d\n", pfds[i].events, i, pfds[i].fd, err); } - if (err) { - dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n", - pfds[i].events, i, pfds[i].fd, err); - - while (i--) { - qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL); - } - g_free (pfds); - return -1; - } } hlp->pfds = pfds; hlp->count = count; From b027a538c6790bcfc93ef7f4819fe3e581445959 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:21 +0800 Subject: [PATCH 09/16] oss: Remove unused error handling of qemu_set_fd_handler The function cannot fail, so the check is superfluous. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-11-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- audio/ossaudio.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 4db2ca65bf..b9c6b30ca1 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -138,18 +138,18 @@ static void oss_helper_poll_in (void *opaque) audio_run ("oss_poll_in"); } -static int oss_poll_out (HWVoiceOut *hw) +static void oss_poll_out (HWVoiceOut *hw) { OSSVoiceOut *oss = (OSSVoiceOut *) hw; - return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL); + qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL); } -static int oss_poll_in (HWVoiceIn *hw) +static void oss_poll_in (HWVoiceIn *hw) { OSSVoiceIn *oss = (OSSVoiceIn *) hw; - return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL); + qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL); } static int oss_write (SWVoiceOut *sw, void *buf, int len) @@ -634,7 +634,8 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) va_end (ap); ldebug ("enabling voice\n"); - if (poll_mode && oss_poll_out (hw)) { + if (poll_mode) { + oss_poll_out (hw); poll_mode = 0; } hw->poll_mode = poll_mode; @@ -828,7 +829,8 @@ static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) poll_mode = va_arg (ap, int); va_end (ap); - if (poll_mode && oss_poll_in (hw)) { + if (poll_mode) { + oss_poll_in (hw); poll_mode = 0; } hw->poll_mode = poll_mode; From 6b5166f8a82888638bb9aba9dc49aa7fa25f292f Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:22 +0800 Subject: [PATCH 10/16] xen_backend: Remove unused error handling of qemu_set_fd_handler The function cannot fail, so the check is superfluous. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-12-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/xen/xen_backend.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index b2cb22b99d..2510e2e4ff 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -714,9 +714,7 @@ int xen_be_init(void) return -1; } - if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) { - goto err; - } + qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL); if (xen_xc == XC_HANDLER_INITIAL_VALUE) { /* Check if xen_init() have been called */ From 1e354528bdaf9671ffc94e531e6967233abe7b8f Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:23 +0800 Subject: [PATCH 11/16] event-notifier: Always return 0 for posix implementation qemu_set_fd_handler cannot fail, let's always return 0. Signed-off-by: Fam Zheng Message-id: 1433400324-7358-13-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- util/event_notifier-posix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c index 8442c6e63c..ed4ca2b01e 100644 --- a/util/event_notifier-posix.c +++ b/util/event_notifier-posix.c @@ -85,7 +85,8 @@ int event_notifier_get_fd(EventNotifier *e) int event_notifier_set_handler(EventNotifier *e, EventNotifierHandler *handler) { - return qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e); + qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e); + return 0; } int event_notifier_set(EventNotifier *e) From f4d248bdc33167ab9e91b1470ef47a61dffd0b38 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 4 Jun 2015 14:45:24 +0800 Subject: [PATCH 12/16] iohandler: Change return type of qemu_set_fd_handler to "void" Signed-off-by: Fam Zheng Message-id: 1433400324-7358-14-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- include/qemu/main-loop.h | 8 ++++---- iohandler.c | 9 ++++----- stubs/set-fd-handler.c | 8 ++++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 7da1d63fb0..0f4a0fd4b2 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -198,10 +198,10 @@ typedef int IOCanReadHandler(void *opaque); * * @opaque: A pointer-sized value that is passed to @fd_read and @fd_write. */ -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); +void qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); #ifdef CONFIG_POSIX /** diff --git a/iohandler.c b/iohandler.c index d361cf2c03..826f713e9f 100644 --- a/iohandler.c +++ b/iohandler.c @@ -45,10 +45,10 @@ typedef struct IOHandlerRecord { static QLIST_HEAD(, IOHandlerRecord) io_handlers = QLIST_HEAD_INITIALIZER(io_handlers); -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) +void qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { IOHandlerRecord *ioh; @@ -77,7 +77,6 @@ int qemu_set_fd_handler(int fd, ioh->deleted = 0; qemu_notify_event(); } - return 0; } void qemu_iohandler_fill(GArray *pollfds) diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c index a895e623f8..a8481bc3c1 100644 --- a/stubs/set-fd-handler.c +++ b/stubs/set-fd-handler.c @@ -1,10 +1,10 @@ #include "qemu-common.h" #include "qemu/main-loop.h" -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) +void qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { abort(); } From 773495364ffbfc6a4d1e13e24e932f96409ba1d3 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 10 Jun 2015 18:21:18 -0700 Subject: [PATCH 13/16] rocker: Add support for phys name Add ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME to port settings. This attribute exports the port name to the guest OS allowing it to name interfaces with sensible defaults. Mostly done by Scott for phys_id support; adapted to phys_name by David. Signed-off-by: Scott Feldman Signed-off-by: David Ahern Message-id: 1433985681-56138-2-git-send-email-sfeldma@gmail.com Signed-off-by: Stefan Hajnoczi --- docs/specs/rocker.txt | 1 + hw/net/rocker/rocker.c | 23 ++++++++++++++++++++++- hw/net/rocker/rocker_fp.c | 7 ++++++- hw/net/rocker/rocker_fp.h | 1 + hw/net/rocker/rocker_hw.h | 1 + 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/specs/rocker.txt b/docs/specs/rocker.txt index 1e7e1e1859..0af5c61585 100644 --- a/docs/specs/rocker.txt +++ b/docs/specs/rocker.txt @@ -420,6 +420,7 @@ Other properties for front-panel ports are available via DMA CMD descriptors: LEARNING 1 MAC address learning on port 1 = enabled 0 = disabled + PHYS_NAME Physical port name (string) Set PORT_SETTINGS descriptor: diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 55b6c46157..e74c027922 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -238,6 +238,7 @@ static int cmd_get_port_settings(Rocker *r, uint8_t duplex; uint8_t autoneg; uint8_t learning; + char *phys_name; MACAddr macaddr; enum rocker_world_type mode; size_t tlv_size; @@ -265,6 +266,7 @@ static int cmd_get_port_settings(Rocker *r, fp_port_get_macaddr(fp_port, &macaddr); mode = world_type(fp_port_get_world(fp_port)); learning = fp_port_get_learning(fp_port); + phys_name = fp_port_get_name(fp_port); tlv_size = rocker_tlv_total_size(0) + /* nest */ rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */ @@ -273,7 +275,8 @@ static int cmd_get_port_settings(Rocker *r, rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */ rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */ rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */ - rocker_tlv_total_size(sizeof(uint8_t)); /* learning */ + rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */ + rocker_tlv_total_size(strlen(phys_name)); if (tlv_size > desc_buf_size(info)) { return -ROCKER_EMSGSIZE; @@ -290,6 +293,8 @@ static int cmd_get_port_settings(Rocker *r, rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode); rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, learning); + rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, + strlen(phys_name), phys_name); rocker_tlv_nest_end(buf, &pos, nest); return desc_set_buf(info, tlv_size); @@ -1277,6 +1282,22 @@ static int pci_rocker_init(PCIDevice *dev) goto err_duplicate; } + /* Rocker name is passed in port name requests to OS with the intention + * that the name is used in interface names. Limit the length of the + * rocker name to avoid naming problems in the OS. Also, adding the + * port number as p# and unganged breakout b#, where # is at most 2 + * digits, so leave room for it too (-1 for string terminator, -3 for + * p# and -3 for b#) + */ +#define ROCKER_IFNAMSIZ 16 +#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3) + if (strlen(r->name) > MAX_ROCKER_NAME_LEN) { + fprintf(stderr, + "rocker: name too long; please shorten to at most %d chars\n", + MAX_ROCKER_NAME_LEN); + return -EINVAL; + } + if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) { memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt)); r->fp_start_macaddr.a[4] += (sw_index++); diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index 2f1e3b348a..393e9e74f9 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -41,6 +41,11 @@ struct fp_port { NICConf conf; }; +char *fp_port_get_name(FpPort *port) +{ + return port->name; +} + bool fp_port_get_link_up(FpPort *port) { return !qemu_get_queue(port->nic)->link_down; @@ -201,7 +206,7 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name, /* front-panel switch port names are 1-based */ - port->name = g_strdup_printf("%s.%d", sw_name, port->pport); + port->name = g_strdup_printf("%sp%d", sw_name, port->pport); memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a)); port->conf.macaddr.a[5] += index; diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h index a5f28f120d..92a6861aec 100644 --- a/hw/net/rocker/rocker_fp.h +++ b/hw/net/rocker/rocker_fp.h @@ -26,6 +26,7 @@ typedef struct fp_port FpPort; int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt); +char *fp_port_get_name(FpPort *port); bool fp_port_get_link_up(FpPort *port); void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr); void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr); diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h index c9c85a75bd..fe639badd4 100644 --- a/hw/net/rocker/rocker_hw.h +++ b/hw/net/rocker/rocker_hw.h @@ -179,6 +179,7 @@ enum { ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */ ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */ + ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */ __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, From 73da0232098a69d06ce0d49ad8751b7c5e8b9448 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 10 Jun 2015 18:21:19 -0700 Subject: [PATCH 14/16] rocker: update tests using hw-derived interface names With previous patch to support phy name attribute for each port, the OS can name port interfaces using the hw-derived name. So update rocker tests to use the new hw-derived interface names. Signed-off-by: Scott Feldman Reviewed-by: Stefan Hajnoczi Message-id: 1433985681-56138-3-git-send-email-sfeldma@gmail.com Signed-off-by: Stefan Hajnoczi --- tests/rocker/bridge | 25 ++++++++++-------------- tests/rocker/bridge-stp | 25 ++++++++++-------------- tests/rocker/bridge-vlan | 37 ++++++++++++++++-------------------- tests/rocker/bridge-vlan-stp | 37 ++++++++++++++++-------------------- tests/rocker/port | 8 ++++---- 5 files changed, 56 insertions(+), 76 deletions(-) diff --git a/tests/rocker/bridge b/tests/rocker/bridge index 7a03f9a227..46abc6f4f6 100755 --- a/tests/rocker/bridge +++ b/tests/rocker/bridge @@ -9,8 +9,8 @@ while ! simp ssh tut h2 --cmd "ping -c 1 localhost >/dev/null"; do sleep 1; done # configure a 2-port bridge simp ssh tut sw1 --cmd "sudo /sbin/ip link add name br0 type bridge" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp1 master br0" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp2 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p1 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p2 master br0" # turn off vlan default_pvid on br0 @@ -18,28 +18,23 @@ simp ssh tut sw1 --cmd "echo 0 | sudo dd of=/sys/class/net/br0/bridge/default_pv # turn off learning and flooding in SW -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 flood off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 flood off" - -# turn on learning in HW - -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning on self" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning on self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 flood off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 flood off" # bring up bridge and ports simp ssh tut sw1 --cmd "sudo ifconfig br0 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp1 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp2 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p2 up" simp ssh tut sw1 --cmd "sudo ifconfig br0 11.0.0.3/24" # config IP on hosts -simp ssh tut h1 --cmd "sudo ifconfig swp1 11.0.0.1/24" -simp ssh tut h2 --cmd "sudo ifconfig swp1 11.0.0.2/24" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1 11.0.0.1/24" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1 11.0.0.2/24" # test... diff --git a/tests/rocker/bridge-stp b/tests/rocker/bridge-stp index 4a111a17d3..008568ad8a 100755 --- a/tests/rocker/bridge-stp +++ b/tests/rocker/bridge-stp @@ -10,8 +10,8 @@ while ! simp ssh tut h2 --cmd "ping -c 1 localhost >/dev/null"; do sleep 1; done simp ssh tut sw1 --cmd "sudo /sbin/ip link add name br0 type bridge" simp ssh tut sw1 --cmd "sudo brctl stp br0 on" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp1 master br0" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp2 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p1 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p2 master br0" # turn off vlan default_pvid on br0 @@ -19,27 +19,22 @@ simp ssh tut sw1 --cmd "echo 0 | sudo dd of=/sys/class/net/br0/bridge/default_pv # turn off learning and flooding in SW -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 flood off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 flood off" - -# turn on learning in HW - -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning on self" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning on self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 flood off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 flood off" # config IP on hosts -simp ssh tut h1 --cmd "sudo ifconfig swp1 11.0.0.1/24" -simp ssh tut h2 --cmd "sudo ifconfig swp1 11.0.0.2/24" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1 11.0.0.1/24" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1 11.0.0.2/24" # bring up bridge and ports simp ssh tut sw1 --cmd "sudo ifconfig br0 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp1 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp2 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p2 up" # test... diff --git a/tests/rocker/bridge-vlan b/tests/rocker/bridge-vlan index 9fa3431f66..ef9e5f53bb 100755 --- a/tests/rocker/bridge-vlan +++ b/tests/rocker/bridge-vlan @@ -9,8 +9,8 @@ while ! simp ssh tut h2 --cmd "ping -c 1 localhost >/dev/null"; do sleep 1; done # configure a 2-port bridge simp ssh tut sw1 --cmd "sudo /sbin/ip link add name br0 type bridge" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp1 master br0" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp2 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p1 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p2 master br0" # turn off vlan default_pvid on br0 # turn on vlan filtering on br0 @@ -20,37 +20,32 @@ simp ssh tut sw1 --cmd "echo 1 | sudo dd of=/sys/class/net/br0/bridge/vlan_filte # add both ports to VLAN 57 -simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev swp1 master" -simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev swp2 master" +simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev sw1p1 master self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev sw1p2 master self" # turn off learning and flooding in SW -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 flood off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 flood off" - -# turn on learning in HW - -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning on self" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning on self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 flood off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 flood off" # bring up bridge and ports simp ssh tut sw1 --cmd "sudo ifconfig br0 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp1 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp2 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p2 up" # config IP on host VLANs -simp ssh tut h1 --cmd "sudo vconfig add swp1 57 >/dev/null 2>&1" -simp ssh tut h1 --cmd "sudo ifconfig swp1 up" -simp ssh tut h1 --cmd "sudo ifconfig swp1.57 11.0.0.1/24" +simp ssh tut h1 --cmd "sudo vconfig add sw1p1 57 >/dev/null 2>&1" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1.57 11.0.0.1/24" -simp ssh tut h2 --cmd "sudo vconfig add swp1 57 >/dev/null 2>&1" -simp ssh tut h2 --cmd "sudo ifconfig swp1 up" -simp ssh tut h2 --cmd "sudo ifconfig swp1.57 11.0.0.2/24" +simp ssh tut h2 --cmd "sudo vconfig add sw1p1 57 >/dev/null 2>&1" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1.57 11.0.0.2/24" # test... diff --git a/tests/rocker/bridge-vlan-stp b/tests/rocker/bridge-vlan-stp index 77ab67efe2..c660312bc6 100755 --- a/tests/rocker/bridge-vlan-stp +++ b/tests/rocker/bridge-vlan-stp @@ -10,8 +10,8 @@ while ! simp ssh tut h2 --cmd "ping -c 1 localhost >/dev/null"; do sleep 1; done simp ssh tut sw1 --cmd "sudo /sbin/ip link add name br0 type bridge" simp ssh tut sw1 --cmd "sudo brctl stp br0 on" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp1 master br0" -simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev swp2 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p1 master br0" +simp ssh tut sw1 --cmd "sudo /sbin/ip link set dev sw1p2 master br0" # turn off vlan default_pvid on br0 # turn on vlan filtering on br0 @@ -21,37 +21,32 @@ simp ssh tut sw1 --cmd "echo 1 | sudo dd of=/sys/class/net/br0/bridge/vlan_filte # add both ports to VLAN 57 -simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev swp1 master" -simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev swp2 master" +simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev sw1p1 master self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge vlan add vid 57 dev sw1p2 master self" # turn off learning and flooding in SW -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 learning off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 learning off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 flood off" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 flood off" - -# turn on learning in HW - -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp1 learning on self" -simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev swp2 learning on self" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p1 flood off" +simp ssh tut sw1 --cmd "sudo /sbin/bridge link set dev sw1p2 flood off" # config IP on host VLANs -simp ssh tut h1 --cmd "sudo vconfig add swp1 57 >/dev/null 2>&1" -simp ssh tut h1 --cmd "sudo ifconfig swp1 up" -simp ssh tut h1 --cmd "sudo ifconfig swp1.57 11.0.0.1/24" +simp ssh tut h1 --cmd "sudo vconfig add sw1p1 57 >/dev/null 2>&1" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1.57 11.0.0.1/24" -simp ssh tut h2 --cmd "sudo vconfig add swp1 57 >/dev/null 2>&1" -simp ssh tut h2 --cmd "sudo ifconfig swp1 up" -simp ssh tut h2 --cmd "sudo ifconfig swp1.57 11.0.0.2/24" +simp ssh tut h2 --cmd "sudo vconfig add sw1p1 57 >/dev/null 2>&1" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1.57 11.0.0.2/24" # bring up bridge and ports simp ssh tut sw1 --cmd "sudo ifconfig br0 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp1 up" -simp ssh tut sw1 --cmd "sudo ifconfig swp2 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p1 up" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p2 up" # test... diff --git a/tests/rocker/port b/tests/rocker/port index 3437f7d7fe..5f2c248046 100755 --- a/tests/rocker/port +++ b/tests/rocker/port @@ -7,13 +7,13 @@ while ! simp ssh tut h2 --cmd "ping -c 1 localhost >/dev/null"; do sleep 1; done # bring up DUT ports -simp ssh tut sw1 --cmd "sudo ifconfig swp1 11.0.0.1/24" -simp ssh tut sw1 --cmd "sudo ifconfig swp2 12.0.0.1/24" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p1 11.0.0.1/24" +simp ssh tut sw1 --cmd "sudo ifconfig sw1p2 12.0.0.1/24" # config IP on hosts -simp ssh tut h1 --cmd "sudo ifconfig swp1 11.0.0.2/24" -simp ssh tut h2 --cmd "sudo ifconfig swp1 12.0.0.2/24" +simp ssh tut h1 --cmd "sudo ifconfig sw1p1 11.0.0.2/24" +simp ssh tut h2 --cmd "sudo ifconfig sw1p1 12.0.0.2/24" # test... From 5ff1547b756a820bc7b695fe393b25d82467d1fe Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 10 Jun 2015 18:21:20 -0700 Subject: [PATCH 15/16] rocker: bring link up/down on PHY enable/disable When the OS driver enables/disables the port, go ahead and set the port's link status to up/down in response to the change. This more closely emulates real hardware when the PHY for the port is brought up/down and the PHY negotiates carrier (link status) with link partner. In the case of qemu, the virtual rocker device can't really do link negotiation with the link partner as that requires signally over a physical medium (the wire), so just pretend the negotiation was successful and bring the link up when the port is enabled. Signed-off-by: Scott Feldman Reviewed-by: Stefan Hajnoczi Message-id: 1433985681-56138-4-git-send-email-sfeldma@gmail.com Signed-off-by: Stefan Hajnoczi --- hw/net/rocker/rocker_fp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index 393e9e74f9..29a2b681cd 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -178,8 +178,19 @@ bool fp_port_enabled(FpPort *port) return port->enabled; } +static void fp_port_set_link(FpPort *port, bool up) +{ + NetClientState *nc = qemu_get_queue(port->nic); + + if (up == nc->link_down) { + nc->link_down = !up; + nc->info->link_status_changed(nc); + } +} + void fp_port_enable(FpPort *port) { + fp_port_set_link(port, true); port->enabled = true; DPRINTF("port %d enabled\n", port->index); } @@ -187,6 +198,7 @@ void fp_port_enable(FpPort *port) void fp_port_disable(FpPort *port) { port->enabled = false; + fp_port_set_link(port, false); DPRINTF("port %d disabled\n", port->index); } From fafa4d508b42a70a59a6bd647a2c0cfad86246c3 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 10 Jun 2015 18:21:21 -0700 Subject: [PATCH 16/16] qmp/hmp: add rocker device support Add QMP/HMP support for rocker devices. This is mostly for debugging purposes to see inside the device's tables and port configurations. Some examples: (qemu) info rocker sw1 name: sw1 id: 0x0000013512005452 ports: 4 (qemu) info rocker-ports sw1 ena/ speed/ auto port link duplex neg? sw1.1 up 10G FD No sw1.2 up 10G FD No sw1.3 !ena 10G FD No sw1.4 !ena 10G FD No (qemu) info rocker-of-dpa-flows sw1 prio tbl hits key(mask) --> actions 2 60 pport 1 vlan 1 LLDP src 00:02:00:00:02:00 dst 01:80:c2:00:00:0e 2 60 pport 1 vlan 1 ARP src 00:02:00:00:02:00 dst 00:02:00:00:03:00 2 60 pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:00:02 proto 58 3 50 vlan 2 dst 33:33:ff:00:00:02 --> write group 0x32000001 goto tbl 60 2 60 pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:03:00 proto 58 3 50 1 vlan 2 dst 33:33:ff:00:03:00 --> write group 0x32000001 goto tbl 60 2 60 pport 2 vlan 2 ARP src 00:02:00:00:03:00 dst 00:02:00:00:02:00 3 50 2 vlan 2 dst 00:02:00:00:02:00 --> write group 0x02000001 goto tbl 60 2 60 1 pport 2 vlan 2 IP src 00:02:00:00:03:00 dst 00:02:00:00:02:00 proto 1 3 50 2 vlan 1 dst 00:02:00:00:03:00 --> write group 0x01000002 goto tbl 60 2 60 1 pport 1 vlan 1 IP src 00:02:00:00:02:00 dst 00:02:00:00:03:00 proto 1 2 60 pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:00:01 proto 58 3 50 vlan 1 dst 33:33:ff:00:00:01 --> write group 0x31000000 goto tbl 60 2 60 pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:02:00 proto 58 3 50 1 vlan 1 dst 33:33:ff:00:02:00 --> write group 0x31000000 goto tbl 60 1 60 173 pport 2 vlan 2 LLDP src dst 01:80:c2:00:00:0e --> write group 0x02000000 1 60 6 pport 2 vlan 2 IPv6 src dst --> write group 0x02000000 1 60 174 pport 1 vlan 1 LLDP src dst 01:80:c2:00:00:0e --> write group 0x01000000 1 60 174 pport 2 vlan 2 IP src dst --> write group 0x02000000 1 60 6 pport 1 vlan 1 IPv6 src dst --> write group 0x01000000 1 60 181 pport 2 vlan 2 ARP src dst --> write group 0x02000000 1 10 715 pport 2 --> apply new vlan 2 goto tbl 20 1 60 177 pport 1 vlan 1 ARP src dst --> write group 0x01000000 1 60 174 pport 1 vlan 1 IP src dst --> write group 0x01000000 1 10 717 pport 1 --> apply new vlan 1 goto tbl 20 1 0 1432 pport 0(0xffff) --> goto tbl 10 (qemu) info rocker-of-dpa-groups sw1 id (decode) --> buckets 0x32000001 (type L2 multicast vlan 2 index 1) --> groups [0x02000001,0x02000000] 0x02000001 (type L2 interface vlan 2 pport 1) --> pop vlan out pport 1 0x01000002 (type L2 interface vlan 1 pport 2) --> pop vlan out pport 2 0x02000000 (type L2 interface vlan 2 pport 0) --> pop vlan out pport 0 0x01000000 (type L2 interface vlan 1 pport 0) --> pop vlan out pport 0 0x31000000 (type L2 multicast vlan 1 index 0) --> groups [0x01000002,0x01000000] [Added "query-" prefixes to rocker.json commands as suggested by Eric Blake . --Stefan] Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Message-id: 1433985681-56138-5-git-send-email-sfeldma@gmail.com Signed-off-by: Stefan Hajnoczi --- hmp-commands.hx | 24 +++ hmp.c | 303 +++++++++++++++++++++++++++++++++ hmp.h | 4 + hw/net/Makefile.objs | 1 + hw/net/rocker/qmp-norocker.c | 50 ++++++ hw/net/rocker/rocker.c | 45 +++++ hw/net/rocker/rocker_fp.c | 10 ++ hw/net/rocker/rocker_fp.h | 1 + hw/net/rocker/rocker_of_dpa.c | 312 ++++++++++++++++++++++++++++++++++ monitor.c | 28 +++ qapi-schema.json | 3 + qapi/rocker.json | 286 +++++++++++++++++++++++++++++++ qmp-commands.hx | 103 +++++++++++ 13 files changed, 1170 insertions(+) create mode 100644 hw/net/rocker/qmp-norocker.c create mode 100644 qapi/rocker.json diff --git a/hmp-commands.hx b/hmp-commands.hx index 3d7dfccf7c..d3b7932ff6 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1798,6 +1798,30 @@ STEXI show available trace events and their state ETEXI +STEXI +@item rocker @var{name} +@findex rocker +Show Rocker(s) +ETEXI + +STEXI +@item rocker_ports @var{name} +@findex rocker_ports +Show Rocker ports +ETEXI + +STEXI +@item rocker_of_dpa_flows @var{name} [@var{tbl_id}] +@findex rocker_of_dpa_flows +Show Rocker OF-DPA flow tables +ETEXI + +STEXI +@item rocker_of_dpa_groups @var{name} [@var{type}] +@findex rocker_of_dpa_groups +Show Rocker OF-DPA groups +ETEXI + STEXI @end table ETEXI diff --git a/hmp.c b/hmp.c index 514f22fbfa..1e7cac02ac 100644 --- a/hmp.c +++ b/hmp.c @@ -15,6 +15,7 @@ #include "hmp.h" #include "net/net.h" +#include "net/eth.h" #include "sysemu/char.h" #include "sysemu/block-backend.h" #include "qemu/option.h" @@ -1999,3 +2000,305 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) } hmp_handle_error(mon, &err); } + +void hmp_rocker(Monitor *mon, const QDict *qdict) +{ + const char *name = qdict_get_str(qdict, "name"); + RockerSwitch *rocker; + Error *errp = NULL; + + rocker = qmp_query_rocker(name, &errp); + if (errp != NULL) { + hmp_handle_error(mon, &errp); + return; + } + + monitor_printf(mon, "name: %s\n", rocker->name); + monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id); + monitor_printf(mon, "ports: %d\n", rocker->ports); + + qapi_free_RockerSwitch(rocker); +} + +void hmp_rocker_ports(Monitor *mon, const QDict *qdict) +{ + RockerPortList *list, *port; + const char *name = qdict_get_str(qdict, "name"); + Error *errp = NULL; + + list = qmp_query_rocker_ports(name, &errp); + if (errp != NULL) { + hmp_handle_error(mon, &errp); + return; + } + + monitor_printf(mon, " ena/ speed/ auto\n"); + monitor_printf(mon, " port link duplex neg?\n"); + + for (port = list; port; port = port->next) { + monitor_printf(mon, "%10s %-4s %-3s %2s %-3s\n", + port->value->name, + port->value->enabled ? port->value->link_up ? + "up" : "down" : "!ena", + port->value->speed == 10000 ? "10G" : "??", + port->value->duplex ? "FD" : "HD", + port->value->autoneg ? "Yes" : "No"); + } + + qapi_free_RockerPortList(list); +} + +void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) +{ + RockerOfDpaFlowList *list, *info; + const char *name = qdict_get_str(qdict, "name"); + uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); + Error *errp = NULL; + + list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp); + if (errp != NULL) { + hmp_handle_error(mon, &errp); + return; + } + + monitor_printf(mon, "prio tbl hits key(mask) --> actions\n"); + + for (info = list; info; info = info->next) { + RockerOfDpaFlow *flow = info->value; + RockerOfDpaFlowKey *key = flow->key; + RockerOfDpaFlowMask *mask = flow->mask; + RockerOfDpaFlowAction *action = flow->action; + + if (flow->hits) { + monitor_printf(mon, "%-4d %-3d %-4" PRIu64, + key->priority, key->tbl_id, flow->hits); + } else { + monitor_printf(mon, "%-4d %-3d ", + key->priority, key->tbl_id); + } + + if (key->has_in_pport) { + monitor_printf(mon, " pport %d", key->in_pport); + if (mask->has_in_pport) { + monitor_printf(mon, "(0x%x)", mask->in_pport); + } + } + + if (key->has_vlan_id) { + monitor_printf(mon, " vlan %d", + key->vlan_id & VLAN_VID_MASK); + if (mask->has_vlan_id) { + monitor_printf(mon, "(0x%x)", mask->vlan_id); + } + } + + if (key->has_tunnel_id) { + monitor_printf(mon, " tunnel %d", key->tunnel_id); + if (mask->has_tunnel_id) { + monitor_printf(mon, "(0x%x)", mask->tunnel_id); + } + } + + if (key->has_eth_type) { + switch (key->eth_type) { + case 0x0806: + monitor_printf(mon, " ARP"); + break; + case 0x0800: + monitor_printf(mon, " IP"); + break; + case 0x86dd: + monitor_printf(mon, " IPv6"); + break; + case 0x8809: + monitor_printf(mon, " LACP"); + break; + case 0x88cc: + monitor_printf(mon, " LLDP"); + break; + default: + monitor_printf(mon, " eth type 0x%04x", key->eth_type); + break; + } + } + + if (key->has_eth_src) { + if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) && + (mask->has_eth_src) && + (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " src "); + } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) && + (mask->has_eth_src) && + (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " src "); + } else { + monitor_printf(mon, " src %s", key->eth_src); + if (mask->has_eth_src) { + monitor_printf(mon, "(%s)", mask->eth_src); + } + } + } + + if (key->has_eth_dst) { + if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) && + (mask->has_eth_dst) && + (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " dst "); + } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) && + (mask->has_eth_dst) && + (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " dst "); + } else { + monitor_printf(mon, " dst %s", key->eth_dst); + if (mask->has_eth_dst) { + monitor_printf(mon, "(%s)", mask->eth_dst); + } + } + } + + if (key->has_ip_proto) { + monitor_printf(mon, " proto %d", key->ip_proto); + if (mask->has_ip_proto) { + monitor_printf(mon, "(0x%x)", mask->ip_proto); + } + } + + if (key->has_ip_tos) { + monitor_printf(mon, " TOS %d", key->ip_tos); + if (mask->has_ip_tos) { + monitor_printf(mon, "(0x%x)", mask->ip_tos); + } + } + + if (key->has_ip_dst) { + monitor_printf(mon, " dst %s", key->ip_dst); + } + + if (action->has_goto_tbl || action->has_group_id || + action->has_new_vlan_id) { + monitor_printf(mon, " -->"); + } + + if (action->has_new_vlan_id) { + monitor_printf(mon, " apply new vlan %d", + ntohs(action->new_vlan_id)); + } + + if (action->has_group_id) { + monitor_printf(mon, " write group 0x%08x", action->group_id); + } + + if (action->has_goto_tbl) { + monitor_printf(mon, " goto tbl %d", action->goto_tbl); + } + + monitor_printf(mon, "\n"); + } + + qapi_free_RockerOfDpaFlowList(list); +} + +void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) +{ + RockerOfDpaGroupList *list, *g; + const char *name = qdict_get_str(qdict, "name"); + uint8_t type = qdict_get_try_int(qdict, "type", 9); + Error *errp = NULL; + bool set = false; + + list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp); + if (errp != NULL) { + hmp_handle_error(mon, &errp); + return; + } + + monitor_printf(mon, "id (decode) --> buckets\n"); + + for (g = list; g; g = g->next) { + RockerOfDpaGroup *group = g->value; + + monitor_printf(mon, "0x%08x", group->id); + + monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" : + group->type == 1 ? "L2 rewrite" : + group->type == 2 ? "L3 unicast" : + group->type == 3 ? "L2 multicast" : + group->type == 4 ? "L2 flood" : + group->type == 5 ? "L3 interface" : + group->type == 6 ? "L3 multicast" : + group->type == 7 ? "L3 ECMP" : + group->type == 8 ? "L2 overlay" : + "unknown"); + + if (group->has_vlan_id) { + monitor_printf(mon, " vlan %d", group->vlan_id); + } + + if (group->has_pport) { + monitor_printf(mon, " pport %d", group->pport); + } + + if (group->has_index) { + monitor_printf(mon, " index %d", group->index); + } + + monitor_printf(mon, ") -->"); + + if (group->has_set_vlan_id && group->set_vlan_id) { + set = true; + monitor_printf(mon, " set vlan %d", + group->set_vlan_id & VLAN_VID_MASK); + } + + if (group->has_set_eth_src) { + if (!set) { + set = true; + monitor_printf(mon, " set"); + } + monitor_printf(mon, " src %s", group->set_eth_src); + } + + if (group->has_set_eth_dst) { + if (!set) { + set = true; + monitor_printf(mon, " set"); + } + monitor_printf(mon, " dst %s", group->set_eth_dst); + } + + set = false; + + if (group->has_ttl_check && group->ttl_check) { + monitor_printf(mon, " check TTL"); + } + + if (group->has_group_id && group->group_id) { + monitor_printf(mon, " group id 0x%08x", group->group_id); + } + + if (group->has_pop_vlan && group->pop_vlan) { + monitor_printf(mon, " pop vlan"); + } + + if (group->has_out_pport) { + monitor_printf(mon, " out pport %d", group->out_pport); + } + + if (group->has_group_ids) { + struct uint32List *id; + + monitor_printf(mon, " groups ["); + for (id = group->group_ids; id; id = id->next) { + monitor_printf(mon, "0x%08x", id->value); + if (id->next) { + monitor_printf(mon, ","); + } + } + monitor_printf(mon, "]"); + } + + monitor_printf(mon, "\n"); + } + + qapi_free_RockerOfDpaGroupList(list); +} diff --git a/hmp.h b/hmp.h index a70ac4fd0f..0cf4f2a3d1 100644 --- a/hmp.h +++ b/hmp.h @@ -124,5 +124,9 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str); void delvm_completion(ReadLineState *rs, int nb_args, const char *str); void loadvm_completion(ReadLineState *rs, int nb_args, const char *str); +void hmp_rocker(Monitor *mon, const QDict *qdict); +void hmp_rocker_ports(Monitor *mon, const QDict *qdict); +void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict); +void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict); #endif diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index 7b91c4e51d..98801739ef 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -39,3 +39,4 @@ obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \ common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \ rocker/rocker_desc.o rocker/rocker_world.o \ rocker/rocker_of_dpa.o +obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o diff --git a/hw/net/rocker/qmp-norocker.c b/hw/net/rocker/qmp-norocker.c new file mode 100644 index 0000000000..f253747361 --- /dev/null +++ b/hw/net/rocker/qmp-norocker.c @@ -0,0 +1,50 @@ +/* + * QMP Target options - Commands handled based on a target config + * versus a host config + * + * Copyright (c) 2015 David Ahern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qemu-common.h" +#include "qmp-commands.h" +#include "qapi/qmp/qerror.h" + +RockerSwitch *qmp_query_rocker(const char *name, Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, + bool has_tbl_id, + uint32_t tbl_id, + Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; + +RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, + bool has_type, + uint8_t type, + Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "rocker"); + return NULL; +}; diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index e74c027922..4d25842509 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -94,6 +94,51 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type) return NULL; } +RockerSwitch *qmp_query_rocker(const char *name, Error **errp) +{ + RockerSwitch *rocker = g_malloc0(sizeof(*rocker)); + Rocker *r; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + rocker->name = g_strdup(r->name); + rocker->id = r->switch_id; + rocker->ports = r->fp_ports; + + return rocker; +} + +RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) +{ + RockerPortList *list = NULL; + Rocker *r; + int i; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + for (i = r->fp_ports - 1; i >= 0; i--) { + RockerPortList *info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + struct fp_port *port = r->fp_port[i]; + + fp_port_get_info(port, info); + info->next = list; + list = info; + } + + return list; +} + uint32_t rocker_fp_ports(Rocker *r) { return r->fp_ports; diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index 29a2b681cd..d8d934c396 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -51,6 +51,16 @@ bool fp_port_get_link_up(FpPort *port) return !qemu_get_queue(port->nic)->link_down; } +void fp_port_get_info(FpPort *port, RockerPortList *info) +{ + info->value->name = g_strdup(port->name); + info->value->enabled = port->enabled; + info->value->link_up = fp_port_get_link_up(port); + info->value->speed = port->speed; + info->value->duplex = port->duplex; + info->value->autoneg = port->autoneg; +} + void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr) { memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a)); diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h index 92a6861aec..ab80fd833c 100644 --- a/hw/net/rocker/rocker_fp.h +++ b/hw/net/rocker/rocker_fp.h @@ -28,6 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt); char *fp_port_get_name(FpPort *port); bool fp_port_get_link_up(FpPort *port); +void fp_port_get_info(FpPort *port, RockerPortList *info); void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr); void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr); uint8_t fp_port_get_learning(FpPort *port); diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 1bcb7af5ef..b25a17d6d7 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -2302,6 +2302,318 @@ static void of_dpa_uninit(World *world) g_hash_table_destroy(of_dpa->flow_tbl); } +struct of_dpa_flow_fill_context { + RockerOfDpaFlowList *list; + uint32_t tbl_id; +}; + +static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) +{ + struct of_dpa_flow *flow = value; + struct of_dpa_flow_key *key = &flow->key; + struct of_dpa_flow_key *mask = &flow->mask; + struct of_dpa_flow_fill_context *flow_context = user_data; + RockerOfDpaFlowList *new; + RockerOfDpaFlow *nflow; + RockerOfDpaFlowKey *nkey; + RockerOfDpaFlowMask *nmask; + RockerOfDpaFlowAction *naction; + + if (flow_context->tbl_id != -1 && + flow_context->tbl_id != key->tbl_id) { + return; + } + + new = g_malloc0(sizeof(*new)); + nflow = new->value = g_malloc0(sizeof(*nflow)); + nkey = nflow->key = g_malloc0(sizeof(*nkey)); + nmask = nflow->mask = g_malloc0(sizeof(*nmask)); + naction = nflow->action = g_malloc0(sizeof(*naction)); + + nflow->cookie = flow->cookie; + nflow->hits = flow->stats.hits; + nkey->priority = flow->priority; + nkey->tbl_id = key->tbl_id; + + if (key->in_pport || mask->in_pport) { + nkey->has_in_pport = true; + nkey->in_pport = key->in_pport; + } + + if (nkey->has_in_pport && mask->in_pport != 0xffffffff) { + nmask->has_in_pport = true; + nmask->in_pport = mask->in_pport; + } + + if (key->eth.vlan_id || mask->eth.vlan_id) { + nkey->has_vlan_id = true; + nkey->vlan_id = ntohs(key->eth.vlan_id); + } + + if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) { + nmask->has_vlan_id = true; + nmask->vlan_id = ntohs(mask->eth.vlan_id); + } + + if (key->tunnel_id || mask->tunnel_id) { + nkey->has_tunnel_id = true; + nkey->tunnel_id = key->tunnel_id; + } + + if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) { + nmask->has_tunnel_id = true; + nmask->tunnel_id = mask->tunnel_id; + } + + if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || + memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) { + nkey->has_eth_src = true; + nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a); + } + + if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { + nmask->has_eth_src = true; + nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a); + } + + if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || + memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) { + nkey->has_eth_dst = true; + nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a); + } + + if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { + nmask->has_eth_dst = true; + nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a); + } + + if (key->eth.type) { + + nkey->has_eth_type = true; + nkey->eth_type = ntohs(key->eth.type); + + switch (ntohs(key->eth.type)) { + case 0x0800: + case 0x86dd: + if (key->ip.proto || mask->ip.proto) { + nkey->has_ip_proto = true; + nkey->ip_proto = key->ip.proto; + } + if (nkey->has_ip_proto && mask->ip.proto != 0xff) { + nmask->has_ip_proto = true; + nmask->ip_proto = mask->ip.proto; + } + if (key->ip.tos || mask->ip.tos) { + nkey->has_ip_tos = true; + nkey->ip_tos = key->ip.tos; + } + if (nkey->has_ip_tos && mask->ip.tos != 0xff) { + nmask->has_ip_tos = true; + nmask->ip_tos = mask->ip.tos; + } + break; + } + + switch (ntohs(key->eth.type)) { + case 0x0800: + if (key->ipv4.addr.dst || mask->ipv4.addr.dst) { + char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst); + int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst); + nkey->has_ip_dst = true; + nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len); + } + break; + } + } + + if (flow->action.goto_tbl) { + naction->has_goto_tbl = true; + naction->goto_tbl = flow->action.goto_tbl; + } + + if (flow->action.write.group_id) { + naction->has_group_id = true; + naction->group_id = flow->action.write.group_id; + } + + if (flow->action.apply.new_vlan_id) { + naction->has_new_vlan_id = true; + naction->new_vlan_id = flow->action.apply.new_vlan_id; + } + + new->next = flow_context->list; + flow_context->list = new; +} + +RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, + bool has_tbl_id, + uint32_t tbl_id, + Error **errp) +{ + struct rocker *r; + struct world *w; + struct of_dpa *of_dpa; + struct of_dpa_flow_fill_context fill_context = { + .list = NULL, + .tbl_id = tbl_id, + }; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); + if (!w) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s doesn't have OF-DPA world", name); + return NULL; + } + + of_dpa = world_private(w); + + g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context); + + return fill_context.list; +} + +struct of_dpa_group_fill_context { + RockerOfDpaGroupList *list; + uint8_t type; +}; + +static void of_dpa_group_fill(void *key, void *value, void *user_data) +{ + struct of_dpa_group *group = value; + struct of_dpa_group_fill_context *flow_context = user_data; + RockerOfDpaGroupList *new; + RockerOfDpaGroup *ngroup; + struct uint32List *id; + int i; + + if (flow_context->type != 9 && + flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) { + return; + } + + new = g_malloc0(sizeof(*new)); + ngroup = new->value = g_malloc0(sizeof(*ngroup)); + + ngroup->id = group->id; + + ngroup->type = ROCKER_GROUP_TYPE_GET(group->id); + + switch (ngroup->type) { + case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: + ngroup->has_vlan_id = true; + ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); + ngroup->has_pport = true; + ngroup->pport = ROCKER_GROUP_PORT_GET(group->id); + ngroup->has_out_pport = true; + ngroup->out_pport = group->l2_interface.out_pport; + ngroup->has_pop_vlan = true; + ngroup->pop_vlan = group->l2_interface.pop_vlan; + break; + case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); + ngroup->has_group_id = true; + ngroup->group_id = group->l2_rewrite.group_id; + if (group->l2_rewrite.vlan_id) { + ngroup->has_set_vlan_id = true; + ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id); + } + break; + if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_src = true; + ngroup->set_eth_src = + qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a); + } + if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_dst = true; + ngroup->set_eth_dst = + qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a); + } + case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: + case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: + ngroup->has_vlan_id = true; + ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_GET(group->id); + for (i = 0; i < group->l2_flood.group_count; i++) { + ngroup->has_group_ids = true; + id = g_malloc0(sizeof(*id)); + id->value = group->l2_flood.group_ids[i]; + id->next = ngroup->group_ids; + ngroup->group_ids = id; + } + break; + case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: + ngroup->has_index = true; + ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); + ngroup->has_group_id = true; + ngroup->group_id = group->l3_unicast.group_id; + if (group->l3_unicast.vlan_id) { + ngroup->has_set_vlan_id = true; + ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id); + } + if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_src = true; + ngroup->set_eth_src = + qemu_mac_strdup_printf(group->l3_unicast.src_mac.a); + } + if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) { + ngroup->has_set_eth_dst = true; + ngroup->set_eth_dst = + qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a); + } + if (group->l3_unicast.ttl_check) { + ngroup->has_ttl_check = true; + ngroup->ttl_check = group->l3_unicast.ttl_check; + } + break; + } + + new->next = flow_context->list; + flow_context->list = new; +} + +RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, + bool has_type, + uint8_t type, + Error **errp) +{ + struct rocker *r; + struct world *w; + struct of_dpa *of_dpa; + struct of_dpa_group_fill_context fill_context = { + .list = NULL, + .type = type, + }; + + r = rocker_find(name); + if (!r) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s not found", name); + return NULL; + } + + w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); + if (!w) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "rocker %s doesn't have OF-DPA world", name); + return NULL; + } + + of_dpa = world_private(w); + + g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context); + + return fill_context.list; +} + static WorldOps of_dpa_ops = { .init = of_dpa_init, .uninit = of_dpa_uninit, diff --git a/monitor.c b/monitor.c index 9afee7b946..6a4642493a 100644 --- a/monitor.c +++ b/monitor.c @@ -2862,6 +2862,34 @@ static mon_cmd_t info_cmds[] = { .help = "show memory devices", .mhandler.cmd = hmp_info_memory_devices, }, + { + .name = "rocker", + .args_type = "name:s", + .params = "name", + .help = "Show rocker switch", + .mhandler.cmd = hmp_rocker, + }, + { + .name = "rocker-ports", + .args_type = "name:s", + .params = "name", + .help = "Show rocker ports", + .mhandler.cmd = hmp_rocker_ports, + }, + { + .name = "rocker-of-dpa-flows", + .args_type = "name:s,tbl_id:i?", + .params = "name [tbl_id]", + .help = "Show rocker OF-DPA flow tables", + .mhandler.cmd = hmp_rocker_of_dpa_flows, + }, + { + .name = "rocker-of-dpa-groups", + .args_type = "name:s,type:i?", + .params = "name [type]", + .help = "Show rocker OF-DPA groups", + .mhandler.cmd = hmp_rocker_of_dpa_groups, + }, { .name = NULL, }, diff --git a/qapi-schema.json b/qapi-schema.json index 6e17a5c36c..bcc604b813 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3788,3 +3788,6 @@ # Since: 2.1 ## { 'command': 'rtc-reset-reinjection' } + +# Rocker ethernet network switch +{ 'include': 'qapi/rocker.json' } diff --git a/qapi/rocker.json b/qapi/rocker.json new file mode 100644 index 0000000000..2fe7fdfa66 --- /dev/null +++ b/qapi/rocker.json @@ -0,0 +1,286 @@ +## +# @Rocker: +# +# Rocker switch information. +# +# @name: switch name +# +# @id: switch ID +# +# @ports: number of front-panel ports +# +# Since: 2.4 +## +{ 'struct': 'RockerSwitch', + 'data': { 'name': 'str', 'id': 'uint64', 'ports': 'uint32' } } + +## +# @query-rocker: +# +# Return rocker switch information. +# +# Returns: @Rocker information +# +# Since: 2.4 +## +{ 'command': 'query-rocker', + 'data': { 'name': 'str' }, + 'returns': 'RockerSwitch' } + +## +# @RockerPortDuplex: +# +# An eumeration of port duplex states. +# +# @half: half duplex +# +# @full: full duplex +# +# Since: 2.4 +## +{ 'enum': 'RockerPortDuplex', 'data': [ 'half', 'full' ] } + +## +# @RockerPortAutoneg: +# +# An eumeration of port autoneg states. +# +# @off: autoneg is off +# +# @on: autoneg is on +# +# Since: 2.4 +## +{ 'enum': 'RockerPortAutoneg', 'data': [ 'off', 'on' ] } + +## +# @RockerPort: +# +# Rocker switch port information. +# +# @name: port name +# +# @enabled: port is enabled for I/O +# +# @link-up: physical link is UP on port +# +# @speed: port link speed in Mbps +# +# @duplex: port link duplex +# +# @autoneg: port link autoneg +# +# Since: 2.4 +## +{ 'struct': 'RockerPort', + 'data': { 'name': 'str', 'enabled': 'bool', 'link-up': 'bool', + 'speed': 'uint32', 'duplex': 'RockerPortDuplex', + 'autoneg': 'RockerPortAutoneg' } } + +## +# @query-rocker-ports: +# +# Return rocker switch information. +# +# Returns: @Rocker information +# +# Since: 2.4 +## +{ 'command': 'query-rocker-ports', + 'data': { 'name': 'str' }, + 'returns': ['RockerPort'] } + +## +# @RockerOfDpaFlowKey: +# +# Rocker switch OF-DPA flow key +# +# @priority: key priority, 0 being lowest priority +# +# @tbl-id: flow table ID +# +# @in-pport: #optional physical input port +# +# @tunnel-id: #optional tunnel ID +# +# @vlan-id: #optional VLAN ID +# +# @eth-type: #optional Ethernet header type +# +# @eth-src: #optional Ethernet header source MAC address +# +# @eth-dst: #optional Ethernet header destination MAC address +# +# @ip-proto: #optional IP Header protocol field +# +# @ip-tos: #optional IP header TOS field +# +# @ip-dst: #optional IP header destination address +# +# Note: fields are marked #optional to indicate that they may or may not +# appear in the flow key depending if they're relevant to the flow key. +# +# Since: 2.4 +## +{ 'struct': 'RockerOfDpaFlowKey', + 'data' : { 'priority': 'uint32', 'tbl-id': 'uint32', '*in-pport': 'uint32', + '*tunnel-id': 'uint32', '*vlan-id': 'uint16', + '*eth-type': 'uint16', '*eth-src': 'str', '*eth-dst': 'str', + '*ip-proto': 'uint8', '*ip-tos': 'uint8', '*ip-dst': 'str' } } + +## +# @RockerOfDpaFlowMask: +# +# Rocker switch OF-DPA flow mask +# +# @in-pport: #optional physical input port +# +# @tunnel-id: #optional tunnel ID +# +# @vlan-id: #optional VLAN ID +# +# @eth-src: #optional Ethernet header source MAC address +# +# @eth-dst: #optional Ethernet header destination MAC address +# +# @ip-proto: #optional IP Header protocol field +# +# @ip-tos: #optional IP header TOS field +# +# Note: fields are marked #optional to indicate that they may or may not +# appear in the flow mask depending if they're relevant to the flow mask. +# +# Since: 2.4 +## +{ 'struct': 'RockerOfDpaFlowMask', + 'data' : { '*in-pport': 'uint32', '*tunnel-id': 'uint32', + '*vlan-id': 'uint16', '*eth-src': 'str', '*eth-dst': 'str', + '*ip-proto': 'uint8', '*ip-tos': 'uint8' } } + +## +# @RockerOfDpaFlowAction: +# +# Rocker switch OF-DPA flow action +# +# @goto-tbl: #optional next table ID +# +# @group-id: #optional group ID +# +# @tunnel-lport: #optional tunnel logical port ID +# +# @vlan-id: #optional VLAN ID +# +# @new-vlan-id: #optional new VLAN ID +# +# @out-pport: #optional physical output port +# +# Note: fields are marked #optional to indicate that they may or may not +# appear in the flow action depending if they're relevant to the flow action. +# +# Since: 2.4 +## +{ 'struct': 'RockerOfDpaFlowAction', + 'data' : { '*goto-tbl': 'uint32', '*group-id': 'uint32', + '*tunnel-lport': 'uint32', '*vlan-id': 'uint16', + '*new-vlan-id': 'uint16', '*out-pport': 'uint32' } } + +## +# @RockerOfDpaFlow: +# +# Rocker switch OF-DPA flow +# +# @cookie: flow unique cookie ID +# +# @hits: count of matches (hits) on flow +# +# @key: flow key +# +# @mask: flow mask +# +# @action: flow action +# +# Since: 2.4 +## +{ 'struct': 'RockerOfDpaFlow', + 'data': { 'cookie': 'uint64', 'hits': 'uint64', 'key': 'RockerOfDpaFlowKey', + 'mask': 'RockerOfDpaFlowMask', 'action': 'RockerOfDpaFlowAction' } } + +## +# @query-rocker-of-dpa-flows: +# +# Return rocker OF-DPA flow information. +# +# @name: switch name +# +# @tbl-id: #optional flow table ID. If tbl-id is not specified, returns +# flow information for all tables. +# +# Returns: @Rocker OF-DPA flow information +# +# Since: 2.4 +## +{ 'command': 'query-rocker-of-dpa-flows', + 'data': { 'name': 'str', '*tbl-id': 'uint32' }, + 'returns': ['RockerOfDpaFlow'] } + +## +# @RockerOfDpaGroup: +# +# Rocker switch OF-DPA group +# +# @id: group unique ID +# +# @type: group type +# +# @vlan-id: #optional VLAN ID +# +# @pport: #optional physical port number +# +# @index: #optional group index, unique with group type +# +# @out-pport: #optional output physical port number +# +# @group-id: #optional next group ID +# +# @set-vlan-id: #optional VLAN ID to set +# +# @pop-vlan: #optional pop VLAN headr from packet +# +# @group-ids: #optional list of next group IDs +# +# @set-eth-src: #optional set source MAC address in Ethernet header +# +# @set-eth-dst: #optional set destination MAC address in Ethernet header +# +# @ttl-check: #optional perform TTL check +# +# Note: fields are marked #optional to indicate that they may or may not +# appear in the group depending if they're relevant to the group type. +# +# Since: 2.4 +## +{ 'struct': 'RockerOfDpaGroup', + 'data': { 'id': 'uint32', 'type': 'uint8', '*vlan-id': 'uint16', + '*pport': 'uint32', '*index': 'uint32', '*out-pport': 'uint32', + '*group-id': 'uint32', '*set-vlan-id': 'uint16', + '*pop-vlan': 'uint8', '*group-ids': ['uint32'], + '*set-eth-src': 'str', '*set-eth-dst': 'str', + '*ttl-check': 'uint8' } } + +## +# @query-rocker-of-dpa-groups: +# +# Return rocker OF-DPA group information. +# +# @name: switch name +# +# @type: #optional group type. If type is not specified, returns +# group information for all group types. +# +# Returns: @Rocker OF-DPA group information +# +# Since: 2.4 +## +{ 'command': 'query-rocker-of-dpa-groups', + 'data': { 'name': 'str', '*type': 'uint8' }, + 'returns': ['RockerOfDpaGroup'] } diff --git a/qmp-commands.hx b/qmp-commands.hx index 867a21fab6..c97d0d7667 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -4165,3 +4165,106 @@ Example: <- { "return": {} } EQMP + + { + .name = "query-rocker", + .args_type = "name:s", + .mhandler.cmd_new = qmp_marshal_input_query_rocker, + }, + +SQMP +Show rocker switch +------------------ + +Arguments: + +- "name": switch name + +Example: + +-> { "execute": "query-rocker", "arguments": { "name": "sw1" } } +<- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}} + +EQMP + + { + .name = "query-rocker-ports", + .args_type = "name:s", + .mhandler.cmd_new = qmp_marshal_input_query_rocker_ports, + }, + +SQMP +Show rocker switch ports +------------------------ + +Arguments: + +- "name": switch name + +Example: + +-> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } } +<- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1", + "autoneg": "off", "link-up": true, "speed": 10000}, + {"duplex": "full", "enabled": true, "name": "sw1.2", + "autoneg": "off", "link-up": true, "speed": 10000} + ]} + +EQMP + + { + .name = "query-rocker-of-dpa-flows", + .args_type = "name:s,tbl-id:i?", + .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_flows, + }, + +SQMP +Show rocker switch OF-DPA flow tables +------------------------------------- + +Arguments: + +- "name": switch name +- "tbl-id": (optional) flow table ID + +Example: + +-> { "execute": "query-rocker-of-dpa-flows", "arguments": { "name": "sw1" } } +<- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0}, + "hits": 138, + "cookie": 0, + "action": {"goto-tbl": 10}, + "mask": {"in-pport": 4294901760} + }, + {...more...}, + ]} + +EQMP + + { + .name = "query-rocker-of-dpa-groups", + .args_type = "name:s,type:i?", + .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_groups, + }, + +SQMP +Show rocker OF-DPA group tables +------------------------------- + +Arguments: + +- "name": switch name +- "type": (optional) group type + +Example: + +-> { "execute": "query-rocker-of-dpa-groups", "arguments": { "name": "sw1" } } +<- { "return": [ {"type": 0, "out-pport": 2, "pport": 2, "vlan-id": 3841, + "pop-vlan": 1, "id": 251723778}, + {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3841, + "pop-vlan": 1, "id": 251723776}, + {"type": 0, "out-pport": 1, "pport": 1, "vlan-id": 3840, + "pop-vlan": 1, "id": 251658241}, + {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840, + "pop-vlan": 1, "id": 251658240} + ]}