hub.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Hub net client
  3. *
  4. * Copyright IBM, Corp. 2012
  5. *
  6. * Authors:
  7. * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
  8. * Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
  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. #include "qemu/osdep.h"
  15. #include "monitor/monitor.h"
  16. #include "net/net.h"
  17. #include "clients.h"
  18. #include "hub.h"
  19. #include "qemu/iov.h"
  20. /*
  21. * A hub broadcasts incoming packets to all its ports except the source port.
  22. * Hubs can be used to provide independent network segments, also confusingly
  23. * named the QEMU 'vlan' feature.
  24. */
  25. typedef struct NetHub NetHub;
  26. typedef struct NetHubPort {
  27. NetClientState nc;
  28. QLIST_ENTRY(NetHubPort) next;
  29. NetHub *hub;
  30. int id;
  31. } NetHubPort;
  32. struct NetHub {
  33. int id;
  34. QLIST_ENTRY(NetHub) next;
  35. int num_ports;
  36. QLIST_HEAD(, NetHubPort) ports;
  37. };
  38. static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs);
  39. static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port,
  40. const uint8_t *buf, size_t len)
  41. {
  42. NetHubPort *port;
  43. QLIST_FOREACH(port, &hub->ports, next) {
  44. if (port == source_port) {
  45. continue;
  46. }
  47. qemu_send_packet(&port->nc, buf, len);
  48. }
  49. return len;
  50. }
  51. static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port,
  52. const struct iovec *iov, int iovcnt)
  53. {
  54. NetHubPort *port;
  55. ssize_t len = iov_size(iov, iovcnt);
  56. QLIST_FOREACH(port, &hub->ports, next) {
  57. if (port == source_port) {
  58. continue;
  59. }
  60. qemu_sendv_packet(&port->nc, iov, iovcnt);
  61. }
  62. return len;
  63. }
  64. static NetHub *net_hub_new(int id)
  65. {
  66. NetHub *hub;
  67. hub = g_malloc(sizeof(*hub));
  68. hub->id = id;
  69. hub->num_ports = 0;
  70. QLIST_INIT(&hub->ports);
  71. QLIST_INSERT_HEAD(&hubs, hub, next);
  72. return hub;
  73. }
  74. static int net_hub_port_can_receive(NetClientState *nc)
  75. {
  76. NetHubPort *port;
  77. NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
  78. NetHub *hub = src_port->hub;
  79. QLIST_FOREACH(port, &hub->ports, next) {
  80. if (port == src_port) {
  81. continue;
  82. }
  83. if (qemu_can_send_packet(&port->nc)) {
  84. return 1;
  85. }
  86. }
  87. return 0;
  88. }
  89. static ssize_t net_hub_port_receive(NetClientState *nc,
  90. const uint8_t *buf, size_t len)
  91. {
  92. NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
  93. return net_hub_receive(port->hub, port, buf, len);
  94. }
  95. static ssize_t net_hub_port_receive_iov(NetClientState *nc,
  96. const struct iovec *iov, int iovcnt)
  97. {
  98. NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
  99. return net_hub_receive_iov(port->hub, port, iov, iovcnt);
  100. }
  101. static void net_hub_port_cleanup(NetClientState *nc)
  102. {
  103. NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
  104. QLIST_REMOVE(port, next);
  105. }
  106. static NetClientInfo net_hub_port_info = {
  107. .type = NET_CLIENT_DRIVER_HUBPORT,
  108. .size = sizeof(NetHubPort),
  109. .can_receive = net_hub_port_can_receive,
  110. .receive = net_hub_port_receive,
  111. .receive_iov = net_hub_port_receive_iov,
  112. .cleanup = net_hub_port_cleanup,
  113. };
  114. static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
  115. {
  116. NetClientState *nc;
  117. NetHubPort *port;
  118. int id = hub->num_ports++;
  119. char default_name[128];
  120. if (!name) {
  121. snprintf(default_name, sizeof(default_name),
  122. "hub%dport%d", hub->id, id);
  123. name = default_name;
  124. }
  125. nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name);
  126. port = DO_UPCAST(NetHubPort, nc, nc);
  127. port->id = id;
  128. port->hub = hub;
  129. QLIST_INSERT_HEAD(&hub->ports, port, next);
  130. return port;
  131. }
  132. /**
  133. * Create a port on a given hub
  134. * @name: Net client name or NULL for default name.
  135. *
  136. * If there is no existing hub with the given id then a new hub is created.
  137. */
  138. NetClientState *net_hub_add_port(int hub_id, const char *name)
  139. {
  140. NetHub *hub;
  141. NetHubPort *port;
  142. QLIST_FOREACH(hub, &hubs, next) {
  143. if (hub->id == hub_id) {
  144. break;
  145. }
  146. }
  147. if (!hub) {
  148. hub = net_hub_new(hub_id);
  149. }
  150. port = net_hub_port_new(hub, name);
  151. return &port->nc;
  152. }
  153. /**
  154. * Find a specific client on a hub
  155. */
  156. NetClientState *net_hub_find_client_by_name(int hub_id, const char *name)
  157. {
  158. NetHub *hub;
  159. NetHubPort *port;
  160. NetClientState *peer;
  161. QLIST_FOREACH(hub, &hubs, next) {
  162. if (hub->id == hub_id) {
  163. QLIST_FOREACH(port, &hub->ports, next) {
  164. peer = port->nc.peer;
  165. if (peer && strcmp(peer->name, name) == 0) {
  166. return peer;
  167. }
  168. }
  169. }
  170. }
  171. return NULL;
  172. }
  173. /**
  174. * Find a available port on a hub; otherwise create one new port
  175. */
  176. NetClientState *net_hub_port_find(int hub_id)
  177. {
  178. NetHub *hub;
  179. NetHubPort *port;
  180. NetClientState *nc;
  181. QLIST_FOREACH(hub, &hubs, next) {
  182. if (hub->id == hub_id) {
  183. QLIST_FOREACH(port, &hub->ports, next) {
  184. nc = port->nc.peer;
  185. if (!nc) {
  186. return &(port->nc);
  187. }
  188. }
  189. break;
  190. }
  191. }
  192. nc = net_hub_add_port(hub_id, NULL);
  193. return nc;
  194. }
  195. /**
  196. * Print hub configuration
  197. */
  198. void net_hub_info(Monitor *mon)
  199. {
  200. NetHub *hub;
  201. NetHubPort *port;
  202. QLIST_FOREACH(hub, &hubs, next) {
  203. monitor_printf(mon, "hub %d\n", hub->id);
  204. QLIST_FOREACH(port, &hub->ports, next) {
  205. monitor_printf(mon, " \\ %s", port->nc.name);
  206. if (port->nc.peer) {
  207. monitor_printf(mon, ": ");
  208. print_net_client(mon, port->nc.peer);
  209. } else {
  210. monitor_printf(mon, "\n");
  211. }
  212. }
  213. }
  214. }
  215. /**
  216. * Get the hub id that a client is connected to
  217. *
  218. * @id: Pointer for hub id output, may be NULL
  219. */
  220. int net_hub_id_for_client(NetClientState *nc, int *id)
  221. {
  222. NetHubPort *port;
  223. if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
  224. port = DO_UPCAST(NetHubPort, nc, nc);
  225. } else if (nc->peer != NULL && nc->peer->info->type ==
  226. NET_CLIENT_DRIVER_HUBPORT) {
  227. port = DO_UPCAST(NetHubPort, nc, nc->peer);
  228. } else {
  229. return -ENOENT;
  230. }
  231. if (id) {
  232. *id = port->hub->id;
  233. }
  234. return 0;
  235. }
  236. int net_init_hubport(const Netdev *netdev, const char *name,
  237. NetClientState *peer, Error **errp)
  238. {
  239. const NetdevHubPortOptions *hubport;
  240. assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
  241. assert(!peer);
  242. hubport = &netdev->u.hubport;
  243. net_hub_add_port(hubport->hubid, name);
  244. return 0;
  245. }
  246. /**
  247. * Warn if hub configurations are likely wrong
  248. */
  249. void net_hub_check_clients(void)
  250. {
  251. NetHub *hub;
  252. NetHubPort *port;
  253. NetClientState *peer;
  254. QLIST_FOREACH(hub, &hubs, next) {
  255. int has_nic = 0, has_host_dev = 0;
  256. QLIST_FOREACH(port, &hub->ports, next) {
  257. peer = port->nc.peer;
  258. if (!peer) {
  259. fprintf(stderr, "Warning: hub port %s has no peer\n",
  260. port->nc.name);
  261. continue;
  262. }
  263. switch (peer->info->type) {
  264. case NET_CLIENT_DRIVER_NIC:
  265. has_nic = 1;
  266. break;
  267. case NET_CLIENT_DRIVER_USER:
  268. case NET_CLIENT_DRIVER_TAP:
  269. case NET_CLIENT_DRIVER_SOCKET:
  270. case NET_CLIENT_DRIVER_VDE:
  271. case NET_CLIENT_DRIVER_VHOST_USER:
  272. has_host_dev = 1;
  273. break;
  274. default:
  275. break;
  276. }
  277. }
  278. if (has_host_dev && !has_nic) {
  279. fprintf(stderr, "Warning: vlan %d with no nics\n", hub->id);
  280. }
  281. if (has_nic && !has_host_dev) {
  282. fprintf(stderr,
  283. "Warning: vlan %d is not connected to host network\n",
  284. hub->id);
  285. }
  286. }
  287. }
  288. bool net_hub_flush(NetClientState *nc)
  289. {
  290. NetHubPort *port;
  291. NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
  292. int ret = 0;
  293. QLIST_FOREACH(port, &source_port->hub->ports, next) {
  294. if (port != source_port) {
  295. ret += qemu_net_queue_flush(port->nc.incoming_queue);
  296. }
  297. }
  298. return ret ? true : false;
  299. }