2
0

filter-buffer.c 6.1 KB

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