2
0

filter-buffer.c 6.0 KB

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