filter-buffer.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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 "net/filter.h"
  10. #include "net/queue.h"
  11. #include "qapi/error.h"
  12. #include "qemu-common.h"
  13. #include "qemu/timer.h"
  14. #include "qemu/iov.h"
  15. #include "qapi/qmp/qerror.h"
  16. #include "qapi-visit.h"
  17. #include "qom/object.h"
  18. #define TYPE_FILTER_BUFFER "filter-buffer"
  19. #define FILTER_BUFFER(obj) \
  20. OBJECT_CHECK(FilterBufferState, (obj), TYPE_FILTER_BUFFER)
  21. typedef struct FilterBufferState {
  22. NetFilterState parent_obj;
  23. NetQueue *incoming_queue;
  24. uint32_t interval;
  25. QEMUTimer release_timer;
  26. } FilterBufferState;
  27. static void filter_buffer_flush(NetFilterState *nf)
  28. {
  29. FilterBufferState *s = FILTER_BUFFER(nf);
  30. if (!qemu_net_queue_flush(s->incoming_queue)) {
  31. /* Unable to empty the queue, purge remaining packets */
  32. qemu_net_queue_purge(s->incoming_queue, nf->netdev);
  33. }
  34. }
  35. static void filter_buffer_release_timer(void *opaque)
  36. {
  37. NetFilterState *nf = opaque;
  38. FilterBufferState *s = FILTER_BUFFER(nf);
  39. /*
  40. * Note: filter_buffer_flush() drops packets that can't be sent
  41. * TODO: We should leave them queued. But currently there's no way
  42. * for the next filter or receiver to notify us that it can receive
  43. * more packets.
  44. */
  45. filter_buffer_flush(nf);
  46. /* Timer rearmed to fire again in s->interval microseconds. */
  47. timer_mod(&s->release_timer,
  48. qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
  49. }
  50. /* filter APIs */
  51. static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
  52. NetClientState *sender,
  53. unsigned flags,
  54. const struct iovec *iov,
  55. int iovcnt,
  56. NetPacketSent *sent_cb)
  57. {
  58. FilterBufferState *s = FILTER_BUFFER(nf);
  59. /*
  60. * We return size when buffer a packet, the sender will take it as
  61. * a already sent packet, so sent_cb should not be called later.
  62. *
  63. * FIXME: Even if the guest can't receive packets for some reasons,
  64. * the filter can still accept packets until its internal queue is full.
  65. * For example:
  66. * For some reason, receiver could not receive more packets
  67. * (.can_receive() returns zero). Without a filter, at most one packet
  68. * will be queued in incoming queue and sender's poll will be disabled
  69. * unit its sent_cb() was called. With a filter, it will keep receiving
  70. * the packets without caring about the receiver. This is suboptimal.
  71. * May need more thoughts (e.g keeping sent_cb).
  72. */
  73. qemu_net_queue_append_iov(s->incoming_queue, sender, flags,
  74. iov, iovcnt, NULL);
  75. return iov_size(iov, iovcnt);
  76. }
  77. static void filter_buffer_cleanup(NetFilterState *nf)
  78. {
  79. FilterBufferState *s = FILTER_BUFFER(nf);
  80. if (s->interval) {
  81. timer_del(&s->release_timer);
  82. }
  83. /* flush packets */
  84. if (s->incoming_queue) {
  85. filter_buffer_flush(nf);
  86. g_free(s->incoming_queue);
  87. }
  88. }
  89. static void filter_buffer_setup_timer(NetFilterState *nf)
  90. {
  91. FilterBufferState *s = FILTER_BUFFER(nf);
  92. if (s->interval) {
  93. timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
  94. filter_buffer_release_timer, nf);
  95. /* Timer armed to fire in s->interval microseconds. */
  96. timer_mod(&s->release_timer,
  97. qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
  98. }
  99. }
  100. static void filter_buffer_setup(NetFilterState *nf, Error **errp)
  101. {
  102. FilterBufferState *s = FILTER_BUFFER(nf);
  103. /*
  104. * We may want to accept zero interval when VM FT solutions like MC
  105. * or COLO use this filter to release packets on demand.
  106. */
  107. if (!s->interval) {
  108. error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "interval",
  109. "a non-zero interval");
  110. return;
  111. }
  112. s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
  113. filter_buffer_setup_timer(nf);
  114. }
  115. static void filter_buffer_status_changed(NetFilterState *nf, Error **errp)
  116. {
  117. FilterBufferState *s = FILTER_BUFFER(nf);
  118. if (!nf->on) {
  119. if (s->interval) {
  120. timer_del(&s->release_timer);
  121. }
  122. filter_buffer_flush(nf);
  123. } else {
  124. filter_buffer_setup_timer(nf);
  125. }
  126. }
  127. static void filter_buffer_class_init(ObjectClass *oc, void *data)
  128. {
  129. NetFilterClass *nfc = NETFILTER_CLASS(oc);
  130. nfc->setup = filter_buffer_setup;
  131. nfc->cleanup = filter_buffer_cleanup;
  132. nfc->receive_iov = filter_buffer_receive_iov;
  133. nfc->status_changed = filter_buffer_status_changed;
  134. }
  135. static void filter_buffer_get_interval(Object *obj, Visitor *v,
  136. const char *name, void *opaque,
  137. Error **errp)
  138. {
  139. FilterBufferState *s = FILTER_BUFFER(obj);
  140. uint32_t value = s->interval;
  141. visit_type_uint32(v, name, &value, errp);
  142. }
  143. static void filter_buffer_set_interval(Object *obj, Visitor *v,
  144. const char *name, void *opaque,
  145. Error **errp)
  146. {
  147. FilterBufferState *s = FILTER_BUFFER(obj);
  148. Error *local_err = NULL;
  149. uint32_t value;
  150. visit_type_uint32(v, name, &value, &local_err);
  151. if (local_err) {
  152. goto out;
  153. }
  154. if (!value) {
  155. error_setg(&local_err, "Property '%s.%s' requires a positive value",
  156. object_get_typename(obj), name);
  157. goto out;
  158. }
  159. s->interval = value;
  160. out:
  161. error_propagate(errp, local_err);
  162. }
  163. static void filter_buffer_init(Object *obj)
  164. {
  165. object_property_add(obj, "interval", "int",
  166. filter_buffer_get_interval,
  167. filter_buffer_set_interval, NULL, NULL, NULL);
  168. }
  169. static const TypeInfo filter_buffer_info = {
  170. .name = TYPE_FILTER_BUFFER,
  171. .parent = TYPE_NETFILTER,
  172. .class_init = filter_buffer_class_init,
  173. .instance_init = filter_buffer_init,
  174. .instance_size = sizeof(FilterBufferState),
  175. };
  176. static void register_types(void)
  177. {
  178. type_register_static(&filter_buffer_info);
  179. }
  180. type_init(register_types);