2
0

hub.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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 "sysemu/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. * Find a available port on a hub; otherwise create one new port
  161. */
  162. NetClientState *net_hub_port_find(int hub_id)
  163. {
  164. NetHub *hub;
  165. NetHubPort *port;
  166. NetClientState *nc;
  167. QLIST_FOREACH(hub, &hubs, next) {
  168. if (hub->id == hub_id) {
  169. QLIST_FOREACH(port, &hub->ports, next) {
  170. nc = port->nc.peer;
  171. if (!nc) {
  172. return &(port->nc);
  173. }
  174. }
  175. break;
  176. }
  177. }
  178. nc = net_hub_add_port(hub_id, NULL, NULL);
  179. return nc;
  180. }
  181. /**
  182. * Print hub configuration
  183. */
  184. void net_hub_info(Monitor *mon)
  185. {
  186. NetHub *hub;
  187. NetHubPort *port;
  188. QLIST_FOREACH(hub, &hubs, next) {
  189. monitor_printf(mon, "hub %d\n", hub->id);
  190. QLIST_FOREACH(port, &hub->ports, next) {
  191. monitor_printf(mon, " \\ %s", port->nc.name);
  192. if (port->nc.peer) {
  193. monitor_printf(mon, ": ");
  194. print_net_client(mon, port->nc.peer);
  195. } else {
  196. monitor_printf(mon, "\n");
  197. }
  198. }
  199. }
  200. }
  201. /**
  202. * Get the hub id that a client is connected to
  203. *
  204. * @id: Pointer for hub id output, may be NULL
  205. */
  206. int net_hub_id_for_client(NetClientState *nc, int *id)
  207. {
  208. NetHubPort *port;
  209. if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
  210. port = DO_UPCAST(NetHubPort, nc, nc);
  211. } else if (nc->peer != NULL && nc->peer->info->type ==
  212. NET_CLIENT_DRIVER_HUBPORT) {
  213. port = DO_UPCAST(NetHubPort, nc, nc->peer);
  214. } else {
  215. return -ENOENT;
  216. }
  217. if (id) {
  218. *id = port->hub->id;
  219. }
  220. return 0;
  221. }
  222. int net_init_hubport(const Netdev *netdev, const char *name,
  223. NetClientState *peer, Error **errp)
  224. {
  225. const NetdevHubPortOptions *hubport;
  226. NetClientState *hubpeer = NULL;
  227. assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
  228. assert(!peer);
  229. hubport = &netdev->u.hubport;
  230. if (hubport->has_netdev) {
  231. hubpeer = qemu_find_netdev(hubport->netdev);
  232. if (!hubpeer) {
  233. error_setg(errp, "netdev '%s' not found", hubport->netdev);
  234. return -1;
  235. }
  236. }
  237. net_hub_add_port(hubport->hubid, name, hubpeer);
  238. return 0;
  239. }
  240. /**
  241. * Warn if hub configurations are likely wrong
  242. */
  243. void net_hub_check_clients(void)
  244. {
  245. NetHub *hub;
  246. NetHubPort *port;
  247. NetClientState *peer;
  248. QLIST_FOREACH(hub, &hubs, next) {
  249. int has_nic = 0, has_host_dev = 0;
  250. QLIST_FOREACH(port, &hub->ports, next) {
  251. peer = port->nc.peer;
  252. if (!peer) {
  253. warn_report("hub port %s has no peer", port->nc.name);
  254. continue;
  255. }
  256. switch (peer->info->type) {
  257. case NET_CLIENT_DRIVER_NIC:
  258. has_nic = 1;
  259. break;
  260. case NET_CLIENT_DRIVER_USER:
  261. case NET_CLIENT_DRIVER_TAP:
  262. case NET_CLIENT_DRIVER_SOCKET:
  263. case NET_CLIENT_DRIVER_VDE:
  264. case NET_CLIENT_DRIVER_VHOST_USER:
  265. has_host_dev = 1;
  266. break;
  267. default:
  268. break;
  269. }
  270. }
  271. if (has_host_dev && !has_nic) {
  272. warn_report("hub %d with no nics", hub->id);
  273. }
  274. if (has_nic && !has_host_dev && !qtest_enabled()) {
  275. warn_report("hub %d is not connected to host network", hub->id);
  276. }
  277. }
  278. }
  279. bool net_hub_flush(NetClientState *nc)
  280. {
  281. NetHubPort *port;
  282. NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
  283. int ret = 0;
  284. QLIST_FOREACH(port, &source_port->hub->ports, next) {
  285. if (port != source_port) {
  286. ret += qemu_net_queue_flush(port->nc.incoming_queue);
  287. }
  288. }
  289. return ret ? true : false;
  290. }