4 * Copyright IBM, Corp. 2012
7 * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
8 * Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
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.
20 * A hub broadcasts incoming packets to all its ports except the source port.
21 * Hubs can be used to provide independent network segments, also confusingly
22 * named the QEMU 'vlan' feature.
25 typedef struct NetHub NetHub
;
27 typedef struct NetHubPort
{
29 QLIST_ENTRY(NetHubPort
) next
;
36 QLIST_ENTRY(NetHub
) next
;
38 QLIST_HEAD(, NetHubPort
) ports
;
41 static QLIST_HEAD(, NetHub
) hubs
= QLIST_HEAD_INITIALIZER(&hubs
);
43 static ssize_t
net_hub_receive(NetHub
*hub
, NetHubPort
*source_port
,
44 const uint8_t *buf
, size_t len
)
48 QLIST_FOREACH(port
, &hub
->ports
, next
) {
49 if (port
== source_port
) {
53 qemu_send_packet(&port
->nc
, buf
, len
);
58 static ssize_t
net_hub_receive_iov(NetHub
*hub
, NetHubPort
*source_port
,
59 const struct iovec
*iov
, int iovcnt
)
64 QLIST_FOREACH(port
, &hub
->ports
, next
) {
65 if (port
== source_port
) {
69 ret
= qemu_sendv_packet(&port
->nc
, iov
, iovcnt
);
74 static NetHub
*net_hub_new(int id
)
78 hub
= g_malloc(sizeof(*hub
));
81 QLIST_INIT(&hub
->ports
);
83 QLIST_INSERT_HEAD(&hubs
, hub
, next
);
88 static ssize_t
net_hub_port_receive(VLANClientState
*nc
,
89 const uint8_t *buf
, size_t len
)
91 NetHubPort
*port
= DO_UPCAST(NetHubPort
, nc
, nc
);
93 return net_hub_receive(port
->hub
, port
, buf
, len
);
96 static ssize_t
net_hub_port_receive_iov(VLANClientState
*nc
,
97 const struct iovec
*iov
, int iovcnt
)
99 NetHubPort
*port
= DO_UPCAST(NetHubPort
, nc
, nc
);
101 return net_hub_receive_iov(port
->hub
, port
, iov
, iovcnt
);
104 static void net_hub_port_cleanup(VLANClientState
*nc
)
106 NetHubPort
*port
= DO_UPCAST(NetHubPort
, nc
, nc
);
108 QLIST_REMOVE(port
, next
);
111 static NetClientInfo net_hub_port_info
= {
112 .type
= NET_CLIENT_OPTIONS_KIND_HUBPORT
,
113 .size
= sizeof(NetHubPort
),
114 .receive
= net_hub_port_receive
,
115 .receive_iov
= net_hub_port_receive_iov
,
116 .cleanup
= net_hub_port_cleanup
,
119 static NetHubPort
*net_hub_port_new(NetHub
*hub
, const char *name
)
123 int id
= hub
->num_ports
++;
124 char default_name
[128];
127 snprintf(default_name
, sizeof(default_name
),
128 "hub%dport%d", hub
->id
, id
);
132 nc
= qemu_new_net_client(&net_hub_port_info
, NULL
, NULL
, "hub", name
);
133 port
= DO_UPCAST(NetHubPort
, nc
, nc
);
137 QLIST_INSERT_HEAD(&hub
->ports
, port
, next
);
143 * Create a port on a given hub
144 * @name: Net client name or NULL for default name.
146 * If there is no existing hub with the given id then a new hub is created.
148 VLANClientState
*net_hub_add_port(int hub_id
, const char *name
)
153 QLIST_FOREACH(hub
, &hubs
, next
) {
154 if (hub
->id
== hub_id
) {
160 hub
= net_hub_new(hub_id
);
163 port
= net_hub_port_new(hub
, name
);
168 * Find a specific client on a hub
170 VLANClientState
*net_hub_find_client_by_name(int hub_id
, const char *name
)
174 VLANClientState
*peer
;
176 QLIST_FOREACH(hub
, &hubs
, next
) {
177 if (hub
->id
== hub_id
) {
178 QLIST_FOREACH(port
, &hub
->ports
, next
) {
179 peer
= port
->nc
.peer
;
181 if (peer
&& strcmp(peer
->name
, name
) == 0) {
191 * Print hub configuration
193 void net_hub_info(Monitor
*mon
)
198 QLIST_FOREACH(hub
, &hubs
, next
) {
199 monitor_printf(mon
, "hub %d\n", hub
->id
);
200 QLIST_FOREACH(port
, &hub
->ports
, next
) {
201 monitor_printf(mon
, " port %d peer %s\n", port
->id
,
202 port
->nc
.peer
? port
->nc
.peer
->name
: "<none>");
208 * Get the hub id that a client is connected to
210 * @id Pointer for hub id output, may be NULL
212 int net_hub_id_for_client(VLANClientState
*nc
, int *id
)
216 if (nc
->info
->type
== NET_CLIENT_OPTIONS_KIND_HUBPORT
) {
217 port
= DO_UPCAST(NetHubPort
, nc
, nc
);
218 } else if (nc
->peer
!= NULL
&& nc
->peer
->info
->type
==
219 NET_CLIENT_OPTIONS_KIND_HUBPORT
) {
220 port
= DO_UPCAST(NetHubPort
, nc
, nc
->peer
);
231 int net_init_hubport(const NetClientOptions
*opts
, const char *name
,
232 VLANClientState
*peer
)
234 const NetdevHubPortOptions
*hubport
;
236 assert(opts
->kind
== NET_CLIENT_OPTIONS_KIND_HUBPORT
);
237 hubport
= opts
->hubport
;
239 /* Treat hub port like a backend, NIC must be the one to peer */
244 net_hub_add_port(hubport
->hubid
, name
);