]> Git Repo - qemu.git/blob - net/hub.c
net: Make "info network" output more readable info
[qemu.git] / net / hub.c
1 /*
2  * Hub net client
3  *
4  * Copyright IBM, Corp. 2012
5  *
6  * Authors:
7  *  Stefan Hajnoczi   <[email protected]>
8  *  Zhi Yong Wu       <[email protected]>
9  *
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.
12  *
13  */
14
15 #include "monitor.h"
16 #include "net.h"
17 #include "hub.h"
18
19 /*
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.
23  */
24
25 typedef struct NetHub NetHub;
26
27 typedef struct NetHubPort {
28     NetClientState nc;
29     QLIST_ENTRY(NetHubPort) next;
30     NetHub *hub;
31     int id;
32 } NetHubPort;
33
34 struct NetHub {
35     int id;
36     QLIST_ENTRY(NetHub) next;
37     int num_ports;
38     QLIST_HEAD(, NetHubPort) ports;
39 };
40
41 static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs);
42
43 static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port,
44                                const uint8_t *buf, size_t len)
45 {
46     NetHubPort *port;
47
48     QLIST_FOREACH(port, &hub->ports, next) {
49         if (port == source_port) {
50             continue;
51         }
52
53         qemu_send_packet(&port->nc, buf, len);
54     }
55     return len;
56 }
57
58 static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port,
59                                    const struct iovec *iov, int iovcnt)
60 {
61     NetHubPort *port;
62     ssize_t ret = 0;
63
64     QLIST_FOREACH(port, &hub->ports, next) {
65         if (port == source_port) {
66             continue;
67         }
68
69         ret = qemu_sendv_packet(&port->nc, iov, iovcnt);
70     }
71     return ret;
72 }
73
74 static NetHub *net_hub_new(int id)
75 {
76     NetHub *hub;
77
78     hub = g_malloc(sizeof(*hub));
79     hub->id = id;
80     hub->num_ports = 0;
81     QLIST_INIT(&hub->ports);
82
83     QLIST_INSERT_HEAD(&hubs, hub, next);
84
85     return hub;
86 }
87
88 static ssize_t net_hub_port_receive(NetClientState *nc,
89                                     const uint8_t *buf, size_t len)
90 {
91     NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
92
93     return net_hub_receive(port->hub, port, buf, len);
94 }
95
96 static ssize_t net_hub_port_receive_iov(NetClientState *nc,
97                                         const struct iovec *iov, int iovcnt)
98 {
99     NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
100
101     return net_hub_receive_iov(port->hub, port, iov, iovcnt);
102 }
103
104 static void net_hub_port_cleanup(NetClientState *nc)
105 {
106     NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
107
108     QLIST_REMOVE(port, next);
109 }
110
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,
117 };
118
119 static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
120 {
121     NetClientState *nc;
122     NetHubPort *port;
123     int id = hub->num_ports++;
124     char default_name[128];
125
126     if (!name) {
127         snprintf(default_name, sizeof(default_name),
128                  "hub%dport%d", hub->id, id);
129         name = default_name;
130     }
131
132     nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name);
133     port = DO_UPCAST(NetHubPort, nc, nc);
134     port->id = id;
135     port->hub = hub;
136
137     QLIST_INSERT_HEAD(&hub->ports, port, next);
138
139     return port;
140 }
141
142 /**
143  * Create a port on a given hub
144  * @name: Net client name or NULL for default name.
145  *
146  * If there is no existing hub with the given id then a new hub is created.
147  */
148 NetClientState *net_hub_add_port(int hub_id, const char *name)
149 {
150     NetHub *hub;
151     NetHubPort *port;
152
153     QLIST_FOREACH(hub, &hubs, next) {
154         if (hub->id == hub_id) {
155             break;
156         }
157     }
158
159     if (!hub) {
160         hub = net_hub_new(hub_id);
161     }
162
163     port = net_hub_port_new(hub, name);
164     return &port->nc;
165 }
166
167 /**
168  * Find a specific client on a hub
169  */
170 NetClientState *net_hub_find_client_by_name(int hub_id, const char *name)
171 {
172     NetHub *hub;
173     NetHubPort *port;
174     NetClientState *peer;
175
176     QLIST_FOREACH(hub, &hubs, next) {
177         if (hub->id == hub_id) {
178             QLIST_FOREACH(port, &hub->ports, next) {
179                 peer = port->nc.peer;
180
181                 if (peer && strcmp(peer->name, name) == 0) {
182                     return peer;
183                 }
184             }
185         }
186     }
187     return NULL;
188 }
189
190 /**
191  * Find a available port on a hub; otherwise create one new port
192  */
193 NetClientState *net_hub_port_find(int hub_id)
194 {
195     NetHub *hub;
196     NetHubPort *port;
197     NetClientState *nc;
198
199     QLIST_FOREACH(hub, &hubs, next) {
200         if (hub->id == hub_id) {
201             QLIST_FOREACH(port, &hub->ports, next) {
202                 nc = port->nc.peer;
203                 if (!nc) {
204                     return &(port->nc);
205                 }
206             }
207             break;
208         }
209     }
210
211     nc = net_hub_add_port(hub_id, NULL);
212     return nc;
213 }
214
215 /**
216  * Print hub configuration
217  */
218 void net_hub_info(Monitor *mon)
219 {
220     NetHub *hub;
221     NetHubPort *port;
222
223     QLIST_FOREACH(hub, &hubs, next) {
224         monitor_printf(mon, "hub %d\n", hub->id);
225         QLIST_FOREACH(port, &hub->ports, next) {
226             if (port->nc.peer) {
227                 monitor_printf(mon, " \\ ");
228                 print_net_client(mon, port->nc.peer);
229             }
230         }
231     }
232 }
233
234 /**
235  * Get the hub id that a client is connected to
236  *
237  * @id              Pointer for hub id output, may be NULL
238  */
239 int net_hub_id_for_client(NetClientState *nc, int *id)
240 {
241     NetHubPort *port;
242
243     if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
244         port = DO_UPCAST(NetHubPort, nc, nc);
245     } else if (nc->peer != NULL && nc->peer->info->type ==
246             NET_CLIENT_OPTIONS_KIND_HUBPORT) {
247         port = DO_UPCAST(NetHubPort, nc, nc->peer);
248     } else {
249         return -ENOENT;
250     }
251
252     if (id) {
253         *id = port->hub->id;
254     }
255     return 0;
256 }
257
258 int net_init_hubport(const NetClientOptions *opts, const char *name,
259                      NetClientState *peer)
260 {
261     const NetdevHubPortOptions *hubport;
262
263     assert(opts->kind == NET_CLIENT_OPTIONS_KIND_HUBPORT);
264     hubport = opts->hubport;
265
266     /* Treat hub port like a backend, NIC must be the one to peer */
267     if (peer) {
268         return -EINVAL;
269     }
270
271     net_hub_add_port(hubport->hubid, name);
272     return 0;
273 }
274
275 /**
276  * Warn if hub configurations are likely wrong
277  */
278 void net_hub_check_clients(void)
279 {
280     NetHub *hub;
281     NetHubPort *port;
282     NetClientState *peer;
283
284     QLIST_FOREACH(hub, &hubs, next) {
285         int has_nic = 0, has_host_dev = 0;
286
287         QLIST_FOREACH(port, &hub->ports, next) {
288             peer = port->nc.peer;
289             if (!peer) {
290                 fprintf(stderr, "Warning: hub port %s has no peer\n",
291                         port->nc.name);
292                 continue;
293             }
294
295             switch (peer->info->type) {
296             case NET_CLIENT_OPTIONS_KIND_NIC:
297                 has_nic = 1;
298                 break;
299             case NET_CLIENT_OPTIONS_KIND_USER:
300             case NET_CLIENT_OPTIONS_KIND_TAP:
301             case NET_CLIENT_OPTIONS_KIND_SOCKET:
302             case NET_CLIENT_OPTIONS_KIND_VDE:
303                 has_host_dev = 1;
304                 break;
305             default:
306                 break;
307             }
308         }
309         if (has_host_dev && !has_nic) {
310             fprintf(stderr, "Warning: vlan %d with no nics\n", hub->id);
311         }
312         if (has_nic && !has_host_dev) {
313             fprintf(stderr,
314                     "Warning: vlan %d is not connected to host network\n",
315                     hub->id);
316         }
317     }
318 }
This page took 0.039527 seconds and 4 git commands to generate.