4 * Copyright IBM, Corp. 2012
10 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11 * See the COPYING.LIB file in the top-level directory.
15 #include "monitor/monitor.h"
22 * A hub broadcasts incoming packets to all its ports except the source port.
23 * Hubs can be used to provide independent network segments, also confusingly
24 * named the QEMU 'vlan' feature.
27 typedef struct NetHub NetHub;
29 typedef struct NetHubPort {
31 QLIST_ENTRY(NetHubPort) next;
38 QLIST_ENTRY(NetHub) next;
40 QLIST_HEAD(, NetHubPort) ports;
43 static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs);
45 static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port,
46 const uint8_t *buf, size_t len)
50 QLIST_FOREACH(port, &hub->ports, next) {
51 if (port == source_port) {
55 qemu_send_packet(&port->nc, buf, len);
60 static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port,
61 const struct iovec *iov, int iovcnt)
64 ssize_t len = iov_size(iov, iovcnt);
66 QLIST_FOREACH(port, &hub->ports, next) {
67 if (port == source_port) {
71 qemu_sendv_packet(&port->nc, iov, iovcnt);
76 static NetHub *net_hub_new(int id)
80 hub = g_malloc(sizeof(*hub));
83 QLIST_INIT(&hub->ports);
85 QLIST_INSERT_HEAD(&hubs, hub, next);
90 static int net_hub_port_can_receive(NetClientState *nc)
93 NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
94 NetHub *hub = src_port->hub;
96 QLIST_FOREACH(port, &hub->ports, next) {
97 if (port == src_port) {
101 if (qemu_can_send_packet(&port->nc)) {
109 static ssize_t net_hub_port_receive(NetClientState *nc,
110 const uint8_t *buf, size_t len)
112 NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
114 return net_hub_receive(port->hub, port, buf, len);
117 static ssize_t net_hub_port_receive_iov(NetClientState *nc,
118 const struct iovec *iov, int iovcnt)
120 NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
122 return net_hub_receive_iov(port->hub, port, iov, iovcnt);
125 static void net_hub_port_cleanup(NetClientState *nc)
127 NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
129 QLIST_REMOVE(port, next);
132 static NetClientInfo net_hub_port_info = {
133 .type = NET_CLIENT_OPTIONS_KIND_HUBPORT,
134 .size = sizeof(NetHubPort),
135 .can_receive = net_hub_port_can_receive,
136 .receive = net_hub_port_receive,
137 .receive_iov = net_hub_port_receive_iov,
138 .cleanup = net_hub_port_cleanup,
141 static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
145 int id = hub->num_ports++;
146 char default_name[128];
149 snprintf(default_name, sizeof(default_name),
150 "hub%dport%d", hub->id, id);
154 nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name);
155 port = DO_UPCAST(NetHubPort, nc, nc);
159 QLIST_INSERT_HEAD(&hub->ports, port, next);
165 * Create a port on a given hub
166 * @name: Net client name or NULL for default name.
168 * If there is no existing hub with the given id then a new hub is created.
170 NetClientState *net_hub_add_port(int hub_id, const char *name)
175 QLIST_FOREACH(hub, &hubs, next) {
176 if (hub->id == hub_id) {
182 hub = net_hub_new(hub_id);
185 port = net_hub_port_new(hub, name);
190 * Find a specific client on a hub
192 NetClientState *net_hub_find_client_by_name(int hub_id, const char *name)
196 NetClientState *peer;
198 QLIST_FOREACH(hub, &hubs, next) {
199 if (hub->id == hub_id) {
200 QLIST_FOREACH(port, &hub->ports, next) {
201 peer = port->nc.peer;
203 if (peer && strcmp(peer->name, name) == 0) {
213 * Find a available port on a hub; otherwise create one new port
215 NetClientState *net_hub_port_find(int hub_id)
221 QLIST_FOREACH(hub, &hubs, next) {
222 if (hub->id == hub_id) {
223 QLIST_FOREACH(port, &hub->ports, next) {
233 nc = net_hub_add_port(hub_id, NULL);
238 * Print hub configuration
240 void net_hub_info(Monitor *mon)
245 QLIST_FOREACH(hub, &hubs, next) {
246 monitor_printf(mon, "hub %d\n", hub->id);
247 QLIST_FOREACH(port, &hub->ports, next) {
248 monitor_printf(mon, " \\ %s", port->nc.name);
250 monitor_printf(mon, ": ");
251 print_net_client(mon, port->nc.peer);
253 monitor_printf(mon, "\n");
260 * Get the hub id that a client is connected to
262 * @id: Pointer for hub id output, may be NULL
264 int net_hub_id_for_client(NetClientState *nc, int *id)
268 if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
269 port = DO_UPCAST(NetHubPort, nc, nc);
270 } else if (nc->peer != NULL && nc->peer->info->type ==
271 NET_CLIENT_OPTIONS_KIND_HUBPORT) {
272 port = DO_UPCAST(NetHubPort, nc, nc->peer);
283 int net_init_hubport(const NetClientOptions *opts, const char *name,
284 NetClientState *peer, Error **errp)
286 const NetdevHubPortOptions *hubport;
288 assert(opts->kind == NET_CLIENT_OPTIONS_KIND_HUBPORT);
290 hubport = opts->hubport;
292 net_hub_add_port(hubport->hubid, name);
297 * Warn if hub configurations are likely wrong
299 void net_hub_check_clients(void)
303 NetClientState *peer;
305 QLIST_FOREACH(hub, &hubs, next) {
306 int has_nic = 0, has_host_dev = 0;
308 QLIST_FOREACH(port, &hub->ports, next) {
309 peer = port->nc.peer;
311 fprintf(stderr, "Warning: hub port %s has no peer\n",
316 switch (peer->info->type) {
317 case NET_CLIENT_OPTIONS_KIND_NIC:
320 case NET_CLIENT_OPTIONS_KIND_USER:
321 case NET_CLIENT_OPTIONS_KIND_TAP:
322 case NET_CLIENT_OPTIONS_KIND_SOCKET:
323 case NET_CLIENT_OPTIONS_KIND_VDE:
324 case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
331 if (has_host_dev && !has_nic) {
332 fprintf(stderr, "Warning: vlan %d with no nics\n", hub->id);
334 if (has_nic && !has_host_dev) {
336 "Warning: vlan %d is not connected to host network\n",
342 bool net_hub_flush(NetClientState *nc)
345 NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
348 QLIST_FOREACH(port, &source_port->hub->ports, next) {
349 if (port != source_port) {
350 ret += qemu_net_queue_flush(port->nc.incoming_queue);
353 return ret ? true : false;