From: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> The vlan feature can be implemented in terms of hubs. By introducing a hub net client it becomes possible to remove the special case vlan code from net.c and push the vlan feature out of generic networking code.
Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> Signed-off-by: Zhi Yong Wu <wu...@linux.vnet.ibm.com> --- Makefile.objs | 2 +- net.h | 1 + net/hub.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/hub.h | 23 +++++++ 4 files changed, 225 insertions(+), 1 deletions(-) create mode 100644 net/hub.c create mode 100644 net/hub.h diff --git a/Makefile.objs b/Makefile.objs index 70c5c79..a3a3a8a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -63,7 +63,7 @@ block-nested-$(CONFIG_RBD) += rbd.o block-obj-y += $(addprefix block/, $(block-nested-y)) net-obj-y = net.o -net-nested-y = queue.o checksum.o util.o +net-nested-y = queue.o checksum.o util.o hub.o net-nested-y += socket.o net-nested-y += dump.o net-nested-$(CONFIG_POSIX) += tap.o diff --git a/net.h b/net.h index 64993b4..50c55ad 100644 --- a/net.h +++ b/net.h @@ -38,6 +38,7 @@ typedef enum { NET_CLIENT_TYPE_VDE, NET_CLIENT_TYPE_DUMP, NET_CLIENT_TYPE_BRIDGE, + NET_CLIENT_TYPE_HUB, NET_CLIENT_TYPE_MAX } net_client_type; diff --git a/net/hub.c b/net/hub.c new file mode 100644 index 0000000..0d3df7f --- /dev/null +++ b/net/hub.c @@ -0,0 +1,200 @@ +/* + * Hub net client + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "monitor.h" +#include "net.h" +#include "hub.h" + +/* + * A hub broadcasts incoming packets to all its ports except the source port. + * Hubs can be used to provide independent network segments, also confusingly + * named the QEMU 'vlan' feature. + */ + +typedef struct NetHub NetHub; + +typedef struct NetHubPort { + VLANClientState nc; + QLIST_ENTRY(NetHubPort) next; + NetHub *hub; + unsigned int id; +} NetHubPort; + +struct NetHub { + unsigned int id; + QLIST_ENTRY(NetHub) next; + unsigned int num_ports; + QLIST_HEAD(, NetHubPort) ports; +}; + +static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs); + +static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port, + const uint8_t *buf, size_t len) +{ + NetHubPort *port; + + QLIST_FOREACH(port, &hub->ports, next) { + if (port == source_port) { + continue; + } + + qemu_send_packet(&port->nc, buf, len); + } + return len; +} + +static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port, + const struct iovec *iov, int iovcnt) +{ + NetHubPort *port; + ssize_t ret = 0; + + QLIST_FOREACH(port, &hub->ports, next) { + if (port == source_port) { + continue; + } + + ret = qemu_sendv_packet(&port->nc, iov, iovcnt); + } + return ret; +} + +static NetHub *net_hub_new(unsigned int id) +{ + NetHub *hub; + + hub = g_malloc(sizeof(*hub)); + hub->id = id; + hub->num_ports = 0; + QLIST_INIT(&hub->ports); + + QLIST_INSERT_HEAD(&hubs, hub, next); + + return hub; +} + +static ssize_t net_hub_port_receive(VLANClientState *nc, + const uint8_t *buf, size_t len) +{ + NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); + + return net_hub_receive(port->hub, port, buf, len); +} + +static ssize_t net_hub_port_receive_iov(VLANClientState *nc, + const struct iovec *iov, int iovcnt) +{ + NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); + + return net_hub_receive_iov(port->hub, port, iov, iovcnt); +} + +static void net_hub_port_cleanup(VLANClientState *nc) +{ + NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); + + QLIST_REMOVE(port, next); +} + +static NetClientInfo net_hub_port_info = { + .type = NET_CLIENT_TYPE_HUB, + .size = sizeof(NetHubPort), + .receive = net_hub_port_receive, + .receive_iov = net_hub_port_receive_iov, + .cleanup = net_hub_port_cleanup, +}; + +static NetHubPort *net_hub_port_new(NetHub *hub) +{ + VLANClientState *nc; + NetHubPort *port; + unsigned int id = hub->num_ports++; + char name[128]; + + snprintf(name, sizeof name, "hub%uport%u", hub->id, id); + + nc = qemu_new_net_client(&net_hub_port_info, NULL, NULL, "hub", name); + port = DO_UPCAST(NetHubPort, nc, nc); + port->id = id; + port->hub = hub; + + QLIST_INSERT_HEAD(&hub->ports, port, next); + + return port; +} + +/** + * Create a port on a given hub + * + * If there is no existing hub with the given id then a new hub is created. + */ +VLANClientState *net_hub_add_port(unsigned int hub_id) +{ + NetHub *hub; + NetHubPort *port; + + QLIST_FOREACH(hub, &hubs, next) { + if (hub->id == hub_id) { + break; + } + } + + if (!hub) { + hub = net_hub_new(hub_id); + } + + port = net_hub_port_new(hub); + return &port->nc; +} + +/** + * Print hub configuration + */ +void net_hub_info(Monitor *mon) +{ + NetHub *hub; + NetHubPort *port; + + QLIST_FOREACH(hub, &hubs, next) { + monitor_printf(mon, "hub %u\n", hub->id); + QLIST_FOREACH(port, &hub->ports, next) { + monitor_printf(mon, " port %u peer %s\n", port->id, + port->nc.peer ? port->nc.peer->name : "<none>"); + } + } +} + +/** + * Get the hub id that a client is connected to + * + * @id Pointer for hub id output, may be NULL + */ +int net_hub_id_for_client(VLANClientState *nc, unsigned int *id) +{ + NetHub *hub; + NetHubPort *port; + + QLIST_FOREACH(hub, &hubs, next) { + QLIST_FOREACH(port, &hub->ports, next) { + if (&port->nc == nc || + (port->nc.peer && port->nc.peer == nc)) { + if (id) { + *id = hub->id; + } + return 0; + } + } + } + return -ENOENT; +} diff --git a/net/hub.h b/net/hub.h new file mode 100644 index 0000000..3ca05dc --- /dev/null +++ b/net/hub.h @@ -0,0 +1,23 @@ +/* + * Hub net client + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef NET_HUB_H +#define NET_HUB_H + +#include "qemu-common.h" + +VLANClientState *net_hub_add_port(unsigned int hub_id); +void net_hub_info(Monitor *mon); +int net_hub_id_for_client(VLANClientState *nc, unsigned int *id); + +#endif /* NET_HUB_H */ -- 1.7.6