filter.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright (c) 2015 FUJITSU LIMITED
  3. * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
  4. *
  5. * This work is licensed under the terms of the GNU GPL, version 2 or
  6. * later. See the COPYING file in the top-level directory.
  7. */
  8. #include "qemu/osdep.h"
  9. #include "qapi/error.h"
  10. #include "qemu-common.h"
  11. #include "qapi/qmp/qerror.h"
  12. #include "qemu/error-report.h"
  13. #include "net/filter.h"
  14. #include "net/net.h"
  15. #include "net/vhost_net.h"
  16. #include "qom/object_interfaces.h"
  17. #include "qemu/iov.h"
  18. static inline bool qemu_can_skip_netfilter(NetFilterState *nf)
  19. {
  20. return !nf->on;
  21. }
  22. ssize_t qemu_netfilter_receive(NetFilterState *nf,
  23. NetFilterDirection direction,
  24. NetClientState *sender,
  25. unsigned flags,
  26. const struct iovec *iov,
  27. int iovcnt,
  28. NetPacketSent *sent_cb)
  29. {
  30. if (qemu_can_skip_netfilter(nf)) {
  31. return 0;
  32. }
  33. if (nf->direction == direction ||
  34. nf->direction == NET_FILTER_DIRECTION_ALL) {
  35. return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov(
  36. nf, sender, flags, iov, iovcnt, sent_cb);
  37. }
  38. return 0;
  39. }
  40. static NetFilterState *netfilter_next(NetFilterState *nf,
  41. NetFilterDirection dir)
  42. {
  43. NetFilterState *next;
  44. if (dir == NET_FILTER_DIRECTION_TX) {
  45. /* forward walk through filters */
  46. next = QTAILQ_NEXT(nf, next);
  47. } else {
  48. /* reverse order */
  49. next = QTAILQ_PREV(nf, NetFilterHead, next);
  50. }
  51. return next;
  52. }
  53. ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
  54. unsigned flags,
  55. const struct iovec *iov,
  56. int iovcnt,
  57. void *opaque)
  58. {
  59. int ret = 0;
  60. int direction;
  61. NetFilterState *nf = opaque;
  62. NetFilterState *next = NULL;
  63. if (!sender || !sender->peer) {
  64. /* no receiver, or sender been deleted, no need to pass it further */
  65. goto out;
  66. }
  67. if (nf->direction == NET_FILTER_DIRECTION_ALL) {
  68. if (sender == nf->netdev) {
  69. /* This packet is sent by netdev itself */
  70. direction = NET_FILTER_DIRECTION_TX;
  71. } else {
  72. direction = NET_FILTER_DIRECTION_RX;
  73. }
  74. } else {
  75. direction = nf->direction;
  76. }
  77. next = netfilter_next(nf, direction);
  78. while (next) {
  79. /*
  80. * if qemu_netfilter_pass_to_next been called, means that
  81. * the packet has been hold by filter and has already retured size
  82. * to the sender, so sent_cb shouldn't be called later, just
  83. * pass NULL to next.
  84. */
  85. ret = qemu_netfilter_receive(next, direction, sender, flags, iov,
  86. iovcnt, NULL);
  87. if (ret) {
  88. return ret;
  89. }
  90. next = netfilter_next(next, direction);
  91. }
  92. /*
  93. * We have gone through all filters, pass it to receiver.
  94. * Do the valid check again incase sender or receiver been
  95. * deleted while we go through filters.
  96. */
  97. if (sender && sender->peer) {
  98. qemu_net_queue_send_iov(sender->peer->incoming_queue,
  99. sender, flags, iov, iovcnt, NULL);
  100. }
  101. out:
  102. /* no receiver, or sender been deleted */
  103. return iov_size(iov, iovcnt);
  104. }
  105. static char *netfilter_get_netdev_id(Object *obj, Error **errp)
  106. {
  107. NetFilterState *nf = NETFILTER(obj);
  108. return g_strdup(nf->netdev_id);
  109. }
  110. static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp)
  111. {
  112. NetFilterState *nf = NETFILTER(obj);
  113. nf->netdev_id = g_strdup(str);
  114. }
  115. static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED)
  116. {
  117. NetFilterState *nf = NETFILTER(obj);
  118. return nf->direction;
  119. }
  120. static void netfilter_set_direction(Object *obj, int direction, Error **errp)
  121. {
  122. NetFilterState *nf = NETFILTER(obj);
  123. nf->direction = direction;
  124. }
  125. static char *netfilter_get_status(Object *obj, Error **errp)
  126. {
  127. NetFilterState *nf = NETFILTER(obj);
  128. return nf->on ? g_strdup("on") : g_strdup("off");
  129. }
  130. static void netfilter_set_status(Object *obj, const char *str, Error **errp)
  131. {
  132. NetFilterState *nf = NETFILTER(obj);
  133. NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
  134. if (strcmp(str, "on") && strcmp(str, "off")) {
  135. error_setg(errp, "Invalid value for netfilter status, "
  136. "should be 'on' or 'off'");
  137. return;
  138. }
  139. if (nf->on == !strcmp(str, "on")) {
  140. return;
  141. }
  142. nf->on = !nf->on;
  143. if (nf->netdev && nfc->status_changed) {
  144. nfc->status_changed(nf, errp);
  145. }
  146. }
  147. static void netfilter_init(Object *obj)
  148. {
  149. NetFilterState *nf = NETFILTER(obj);
  150. nf->on = true;
  151. object_property_add_str(obj, "netdev",
  152. netfilter_get_netdev_id, netfilter_set_netdev_id,
  153. NULL);
  154. object_property_add_enum(obj, "queue", "NetFilterDirection",
  155. NetFilterDirection_lookup,
  156. netfilter_get_direction, netfilter_set_direction,
  157. NULL);
  158. object_property_add_str(obj, "status",
  159. netfilter_get_status, netfilter_set_status,
  160. NULL);
  161. }
  162. static void netfilter_complete(UserCreatable *uc, Error **errp)
  163. {
  164. NetFilterState *nf = NETFILTER(uc);
  165. NetClientState *ncs[MAX_QUEUE_NUM];
  166. NetFilterClass *nfc = NETFILTER_GET_CLASS(uc);
  167. int queues;
  168. Error *local_err = NULL;
  169. if (!nf->netdev_id) {
  170. error_setg(errp, "Parameter 'netdev' is required");
  171. return;
  172. }
  173. queues = qemu_find_net_clients_except(nf->netdev_id, ncs,
  174. NET_CLIENT_DRIVER_NIC,
  175. MAX_QUEUE_NUM);
  176. if (queues < 1) {
  177. error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev",
  178. "a network backend id");
  179. return;
  180. } else if (queues > 1) {
  181. error_setg(errp, "multiqueue is not supported");
  182. return;
  183. }
  184. if (get_vhost_net(ncs[0])) {
  185. error_setg(errp, "Vhost is not supported");
  186. return;
  187. }
  188. nf->netdev = ncs[0];
  189. if (nfc->setup) {
  190. nfc->setup(nf, &local_err);
  191. if (local_err) {
  192. error_propagate(errp, local_err);
  193. return;
  194. }
  195. }
  196. QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
  197. }
  198. static void netfilter_finalize(Object *obj)
  199. {
  200. NetFilterState *nf = NETFILTER(obj);
  201. NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
  202. if (nfc->cleanup) {
  203. nfc->cleanup(nf);
  204. }
  205. if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) &&
  206. QTAILQ_IN_USE(nf, next)) {
  207. QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
  208. }
  209. g_free(nf->netdev_id);
  210. }
  211. static void netfilter_class_init(ObjectClass *oc, void *data)
  212. {
  213. UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
  214. ucc->complete = netfilter_complete;
  215. }
  216. static const TypeInfo netfilter_info = {
  217. .name = TYPE_NETFILTER,
  218. .parent = TYPE_OBJECT,
  219. .abstract = true,
  220. .class_size = sizeof(NetFilterClass),
  221. .class_init = netfilter_class_init,
  222. .instance_size = sizeof(NetFilterState),
  223. .instance_init = netfilter_init,
  224. .instance_finalize = netfilter_finalize,
  225. .interfaces = (InterfaceInfo[]) {
  226. { TYPE_USER_CREATABLE },
  227. { }
  228. }
  229. };
  230. static void register_types(void)
  231. {
  232. type_register_static(&netfilter_info);
  233. }
  234. type_init(register_types);