]> Git Repo - qemu.git/blob - net/hub.c
net: Use hubs for the vlan feature
[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     VLANClientState 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(VLANClientState *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(VLANClientState *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(VLANClientState *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     VLANClientState *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, 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 VLANClientState *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  * Print hub configuration
169  */
170 void net_hub_info(Monitor *mon)
171 {
172     NetHub *hub;
173     NetHubPort *port;
174
175     QLIST_FOREACH(hub, &hubs, next) {
176         monitor_printf(mon, "hub %d\n", hub->id);
177         QLIST_FOREACH(port, &hub->ports, next) {
178             monitor_printf(mon, "    port %d peer %s\n", port->id,
179                            port->nc.peer ? port->nc.peer->name : "<none>");
180         }
181     }
182 }
183
184 /**
185  * Get the hub id that a client is connected to
186  *
187  * @id              Pointer for hub id output, may be NULL
188  */
189 int net_hub_id_for_client(VLANClientState *nc, int *id)
190 {
191     NetHubPort *port;
192
193     if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
194         port = DO_UPCAST(NetHubPort, nc, nc);
195     } else if (nc->peer != NULL && nc->peer->info->type ==
196             NET_CLIENT_OPTIONS_KIND_HUBPORT) {
197         port = DO_UPCAST(NetHubPort, nc, nc->peer);
198     } else {
199         return -ENOENT;
200     }
201
202     if (id) {
203         *id = port->hub->id;
204     }
205     return 0;
206 }
207
208 int net_init_hubport(const NetClientOptions *opts, const char *name,
209                      VLANClientState *peer)
210 {
211     const NetdevHubPortOptions *hubport;
212
213     assert(opts->kind == NET_CLIENT_OPTIONS_KIND_HUBPORT);
214     hubport = opts->hubport;
215
216     /* Treat hub port like a backend, NIC must be the one to peer */
217     if (peer) {
218         return -EINVAL;
219     }
220
221     net_hub_add_port(hubport->hubid, name);
222     return 0;
223 }
This page took 0.036712 seconds and 4 git commands to generate.