hub.c 7.7 KB

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