rocker_fp.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. void fp_port_get_info(FpPort *port, RockerPortList *info)
  49. {
  50. info->value->name = g_strdup(port->name);
  51. info->value->enabled = port->enabled;
  52. info->value->link_up = fp_port_get_link_up(port);
  53. info->value->speed = port->speed;
  54. info->value->duplex = port->duplex;
  55. info->value->autoneg = port->autoneg;
  56. }
  57. void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
  58. {
  59. memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
  60. }
  61. void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr)
  62. {
  63. /* XXX TODO implement and test setting mac addr
  64. * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
  65. */
  66. }
  67. uint8_t fp_port_get_learning(FpPort *port)
  68. {
  69. return port->learning;
  70. }
  71. void fp_port_set_learning(FpPort *port, uint8_t learning)
  72. {
  73. port->learning = learning;
  74. }
  75. int fp_port_get_settings(FpPort *port, uint32_t *speed,
  76. uint8_t *duplex, uint8_t *autoneg)
  77. {
  78. *speed = port->speed;
  79. *duplex = port->duplex;
  80. *autoneg = port->autoneg;
  81. return ROCKER_OK;
  82. }
  83. int fp_port_set_settings(FpPort *port, uint32_t speed,
  84. uint8_t duplex, uint8_t autoneg)
  85. {
  86. /* XXX validate inputs */
  87. port->speed = speed;
  88. port->duplex = duplex;
  89. port->autoneg = autoneg;
  90. return ROCKER_OK;
  91. }
  92. bool fp_port_from_pport(uint32_t pport, uint32_t *port)
  93. {
  94. if (pport < 1 || pport > ROCKER_FP_PORTS_MAX) {
  95. return false;
  96. }
  97. *port = pport - 1;
  98. return true;
  99. }
  100. int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt)
  101. {
  102. NetClientState *nc = qemu_get_queue(port->nic);
  103. if (port->enabled) {
  104. qemu_sendv_packet(nc, iov, iovcnt);
  105. }
  106. return ROCKER_OK;
  107. }
  108. static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
  109. int iovcnt)
  110. {
  111. FpPort *port = qemu_get_nic_opaque(nc);
  112. /* If the port is disabled, we want to drop this pkt
  113. * now rather than queing it for later. We don't want
  114. * any stale pkts getting into the device when the port
  115. * transitions to enabled.
  116. */
  117. if (!port->enabled) {
  118. return -1;
  119. }
  120. return world_ingress(port->world, port->pport, iov, iovcnt);
  121. }
  122. static ssize_t fp_port_receive(NetClientState *nc, const uint8_t *buf,
  123. size_t size)
  124. {
  125. const struct iovec iov = {
  126. .iov_base = (uint8_t *)buf,
  127. .iov_len = size
  128. };
  129. return fp_port_receive_iov(nc, &iov, 1);
  130. }
  131. static void fp_port_cleanup(NetClientState *nc)
  132. {
  133. }
  134. static void fp_port_set_link_status(NetClientState *nc)
  135. {
  136. FpPort *port = qemu_get_nic_opaque(nc);
  137. rocker_event_link_changed(port->r, port->pport, !nc->link_down);
  138. }
  139. static NetClientInfo fp_port_info = {
  140. .type = NET_CLIENT_DRIVER_NIC,
  141. .size = sizeof(NICState),
  142. .receive = fp_port_receive,
  143. .receive_iov = fp_port_receive_iov,
  144. .cleanup = fp_port_cleanup,
  145. .link_status_changed = fp_port_set_link_status,
  146. };
  147. World *fp_port_get_world(FpPort *port)
  148. {
  149. return port->world;
  150. }
  151. void fp_port_set_world(FpPort *port, World *world)
  152. {
  153. DPRINTF("port %d setting world \"%s\"\n", port->index, world_name(world));
  154. port->world = world;
  155. }
  156. bool fp_port_check_world(FpPort *port, World *world)
  157. {
  158. return port->world == world;
  159. }
  160. bool fp_port_enabled(FpPort *port)
  161. {
  162. return port->enabled;
  163. }
  164. static void fp_port_set_link(FpPort *port, bool up)
  165. {
  166. NetClientState *nc = qemu_get_queue(port->nic);
  167. if (up == nc->link_down) {
  168. nc->link_down = !up;
  169. nc->info->link_status_changed(nc);
  170. }
  171. }
  172. void fp_port_enable(FpPort *port)
  173. {
  174. fp_port_set_link(port, true);
  175. port->enabled = true;
  176. DPRINTF("port %d enabled\n", port->index);
  177. }
  178. void fp_port_disable(FpPort *port)
  179. {
  180. port->enabled = false;
  181. fp_port_set_link(port, false);
  182. DPRINTF("port %d disabled\n", port->index);
  183. }
  184. FpPort *fp_port_alloc(Rocker *r, char *sw_name,
  185. MACAddr *start_mac, unsigned int index,
  186. NICPeers *peers)
  187. {
  188. FpPort *port = g_new0(FpPort, 1);
  189. port->r = r;
  190. port->index = index;
  191. port->pport = index + 1;
  192. /* front-panel switch port names are 1-based */
  193. port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
  194. memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
  195. port->conf.macaddr.a[5] += index;
  196. port->conf.bootindex = -1;
  197. port->conf.peers = *peers;
  198. port->nic = qemu_new_nic(&fp_port_info, &port->conf,
  199. sw_name, NULL, port);
  200. qemu_format_nic_info_str(qemu_get_queue(port->nic),
  201. port->conf.macaddr.a);
  202. fp_port_reset(port);
  203. return port;
  204. }
  205. void fp_port_free(FpPort *port)
  206. {
  207. qemu_del_nic(port->nic);
  208. g_free(port->name);
  209. g_free(port);
  210. }
  211. void fp_port_reset(FpPort *port)
  212. {
  213. fp_port_disable(port);
  214. port->speed = 10000; /* 10Gbps */
  215. port->duplex = DUPLEX_FULL;
  216. port->autoneg = 0;
  217. }