rocker_fp.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * QEMU rocker switch emulation - front-panel ports
  3. *
  4. * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include "qemu/osdep.h"
  17. #include "qapi/qapi-types-rocker.h"
  18. #include "rocker.h"
  19. #include "rocker_hw.h"
  20. #include "rocker_fp.h"
  21. #include "rocker_world.h"
  22. enum duplex {
  23. DUPLEX_HALF = 0,
  24. DUPLEX_FULL
  25. };
  26. struct fp_port {
  27. Rocker *r;
  28. World *world;
  29. unsigned int index;
  30. char *name;
  31. uint32_t pport;
  32. bool enabled;
  33. uint32_t speed;
  34. uint8_t duplex;
  35. uint8_t autoneg;
  36. uint8_t learning;
  37. NICState *nic;
  38. NICConf conf;
  39. };
  40. char *fp_port_get_name(FpPort *port)
  41. {
  42. return port->name;
  43. }
  44. bool fp_port_get_link_up(FpPort *port)
  45. {
  46. return !qemu_get_queue(port->nic)->link_down;
  47. }
  48. RockerPort *fp_port_get_info(FpPort *port)
  49. {
  50. RockerPort *value = g_malloc0(sizeof(*value));
  51. value->name = g_strdup(port->name);
  52. value->enabled = port->enabled;
  53. value->link_up = fp_port_get_link_up(port);
  54. value->speed = port->speed;
  55. value->duplex = port->duplex;
  56. value->autoneg = port->autoneg;
  57. return value;
  58. }
  59. void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
  60. {
  61. memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
  62. }
  63. void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr)
  64. {
  65. /* XXX TODO implement and test setting mac addr
  66. * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
  67. */
  68. }
  69. uint8_t fp_port_get_learning(FpPort *port)
  70. {
  71. return port->learning;
  72. }
  73. void fp_port_set_learning(FpPort *port, uint8_t learning)
  74. {
  75. port->learning = learning;
  76. }
  77. int fp_port_get_settings(FpPort *port, uint32_t *speed,
  78. uint8_t *duplex, uint8_t *autoneg)
  79. {
  80. *speed = port->speed;
  81. *duplex = port->duplex;
  82. *autoneg = port->autoneg;
  83. return ROCKER_OK;
  84. }
  85. int fp_port_set_settings(FpPort *port, uint32_t speed,
  86. uint8_t duplex, uint8_t autoneg)
  87. {
  88. /* XXX validate inputs */
  89. port->speed = speed;
  90. port->duplex = duplex;
  91. port->autoneg = autoneg;
  92. return ROCKER_OK;
  93. }
  94. bool fp_port_from_pport(uint32_t pport, uint32_t *port)
  95. {
  96. if (pport < 1 || pport > ROCKER_FP_PORTS_MAX) {
  97. return false;
  98. }
  99. *port = pport - 1;
  100. return true;
  101. }
  102. int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt)
  103. {
  104. NetClientState *nc = qemu_get_queue(port->nic);
  105. if (port->enabled) {
  106. qemu_sendv_packet(nc, iov, iovcnt);
  107. }
  108. return ROCKER_OK;
  109. }
  110. static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
  111. int iovcnt)
  112. {
  113. FpPort *port = qemu_get_nic_opaque(nc);
  114. /* If the port is disabled, we want to drop this pkt
  115. * now rather than queueing it for later. We don't want
  116. * any stale pkts getting into the device when the port
  117. * transitions to enabled.
  118. */
  119. if (!port->enabled) {
  120. return -1;
  121. }
  122. return world_ingress(port->world, port->pport, iov, iovcnt);
  123. }
  124. static ssize_t fp_port_receive(NetClientState *nc, const uint8_t *buf,
  125. size_t size)
  126. {
  127. const struct iovec iov = {
  128. .iov_base = (uint8_t *)buf,
  129. .iov_len = size
  130. };
  131. return fp_port_receive_iov(nc, &iov, 1);
  132. }
  133. static void fp_port_cleanup(NetClientState *nc)
  134. {
  135. }
  136. static void fp_port_set_link_status(NetClientState *nc)
  137. {
  138. FpPort *port = qemu_get_nic_opaque(nc);
  139. rocker_event_link_changed(port->r, port->pport, !nc->link_down);
  140. }
  141. static NetClientInfo fp_port_info = {
  142. .type = NET_CLIENT_DRIVER_NIC,
  143. .size = sizeof(NICState),
  144. .receive = fp_port_receive,
  145. .receive_iov = fp_port_receive_iov,
  146. .cleanup = fp_port_cleanup,
  147. .link_status_changed = fp_port_set_link_status,
  148. };
  149. World *fp_port_get_world(FpPort *port)
  150. {
  151. return port->world;
  152. }
  153. void fp_port_set_world(FpPort *port, World *world)
  154. {
  155. DPRINTF("port %d setting world \"%s\"\n", port->index, world_name(world));
  156. port->world = world;
  157. }
  158. bool fp_port_check_world(FpPort *port, World *world)
  159. {
  160. return port->world == world;
  161. }
  162. bool fp_port_enabled(FpPort *port)
  163. {
  164. return port->enabled;
  165. }
  166. static void fp_port_set_link(FpPort *port, bool up)
  167. {
  168. NetClientState *nc = qemu_get_queue(port->nic);
  169. if (up == nc->link_down) {
  170. nc->link_down = !up;
  171. nc->info->link_status_changed(nc);
  172. }
  173. }
  174. void fp_port_enable(FpPort *port)
  175. {
  176. fp_port_set_link(port, true);
  177. port->enabled = true;
  178. DPRINTF("port %d enabled\n", port->index);
  179. }
  180. void fp_port_disable(FpPort *port)
  181. {
  182. port->enabled = false;
  183. fp_port_set_link(port, false);
  184. DPRINTF("port %d disabled\n", port->index);
  185. }
  186. FpPort *fp_port_alloc(Rocker *r, char *sw_name,
  187. MACAddr *start_mac, unsigned int index,
  188. NICPeers *peers)
  189. {
  190. FpPort *port = g_new0(FpPort, 1);
  191. port->r = r;
  192. port->index = index;
  193. port->pport = index + 1;
  194. /* front-panel switch port names are 1-based */
  195. port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
  196. memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
  197. port->conf.macaddr.a[5] += index;
  198. port->conf.bootindex = -1;
  199. port->conf.peers = *peers;
  200. port->nic = qemu_new_nic(&fp_port_info, &port->conf, sw_name, NULL,
  201. &DEVICE(r)->mem_reentrancy_guard, port);
  202. qemu_format_nic_info_str(qemu_get_queue(port->nic),
  203. port->conf.macaddr.a);
  204. fp_port_reset(port);
  205. return port;
  206. }
  207. void fp_port_free(FpPort *port)
  208. {
  209. qemu_del_nic(port->nic);
  210. g_free(port->name);
  211. g_free(port);
  212. }
  213. void fp_port_reset(FpPort *port)
  214. {
  215. fp_port_disable(port);
  216. port->speed = 10000; /* 10Gbps */
  217. port->duplex = DUPLEX_FULL;
  218. port->autoneg = 0;
  219. }