2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/buffer-view.h>
9 #include <common/dynamic-buffer.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/mi-lttng.h>
13 #include <common/payload-view.h>
14 #include <common/payload.h>
16 #include <lttng/action/rate-policy-internal.h>
17 #include <lttng/action/rate-policy.h>
19 #include <sys/types.h>
21 #define IS_EVERY_N_RATE_POLICY(policy) \
22 (lttng_rate_policy_get_type(policy) == LTTNG_RATE_POLICY_TYPE_EVERY_N)
24 #define IS_ONCE_AFTER_N_RATE_POLICY(policy) \
25 (lttng_rate_policy_get_type(policy) == \
26 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N)
28 typedef void (*rate_policy_destroy_cb
)(struct lttng_rate_policy
*rate_policy
);
29 typedef int (*rate_policy_serialize_cb
)(struct lttng_rate_policy
*rate_policy
,
30 struct lttng_payload
*payload
);
31 typedef bool (*rate_policy_equal_cb
)(const struct lttng_rate_policy
*a
,
32 const struct lttng_rate_policy
*b
);
33 typedef ssize_t (*rate_policy_create_from_payload_cb
)(
34 struct lttng_payload_view
*view
,
35 struct lttng_rate_policy
**rate_policy
);
36 typedef struct lttng_rate_policy
*(*rate_policy_copy_cb
)(
37 const struct lttng_rate_policy
*source
);
38 typedef enum lttng_error_code (*rate_policy_mi_serialize_cb
)(
39 const struct lttng_rate_policy
*rate_policy
,
40 struct mi_writer
*writer
);
42 struct lttng_rate_policy
{
43 enum lttng_rate_policy_type type
;
44 rate_policy_serialize_cb serialize
;
45 rate_policy_equal_cb equal
;
46 rate_policy_destroy_cb destroy
;
47 rate_policy_copy_cb copy
;
48 rate_policy_mi_serialize_cb mi_serialize
;
51 struct lttng_rate_policy_every_n
{
52 struct lttng_rate_policy parent
;
56 struct lttng_rate_policy_once_after_n
{
57 struct lttng_rate_policy parent
;
61 struct lttng_rate_policy_comm
{
62 /* enum lttng_rate_policy_type */
63 int8_t rate_policy_type
;
66 struct lttng_rate_policy_once_after_n_comm
{
70 struct lttng_rate_policy_every_n_comm
{
74 /* Forward declaration. */
75 static void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
76 enum lttng_rate_policy_type type
,
77 rate_policy_serialize_cb serialize
,
78 rate_policy_equal_cb equal
,
79 rate_policy_destroy_cb destroy
,
80 rate_policy_copy_cb copy
,
81 rate_policy_mi_serialize_cb mi
);
83 /* Forward declaration. Every n */
84 static bool lttng_rate_policy_every_n_should_execute(
85 const struct lttng_rate_policy
*policy
, uint64_t counter
);
87 /* Forward declaration. Once after N */
88 static bool lttng_rate_policy_once_after_n_should_execute(
89 const struct lttng_rate_policy
*policy
, uint64_t counter
);
92 const char *lttng_rate_policy_type_string(
93 enum lttng_rate_policy_type rate_policy_type
)
95 switch (rate_policy_type
) {
96 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
98 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
99 return "ONCE-AFTER-N";
105 enum lttng_rate_policy_type
lttng_rate_policy_get_type(
106 const struct lttng_rate_policy
*policy
)
108 return policy
? policy
->type
: LTTNG_RATE_POLICY_TYPE_UNKNOWN
;
112 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
113 enum lttng_rate_policy_type type
,
114 rate_policy_serialize_cb serialize
,
115 rate_policy_equal_cb equal
,
116 rate_policy_destroy_cb destroy
,
117 rate_policy_copy_cb copy
,
118 rate_policy_mi_serialize_cb mi
)
120 rate_policy
->type
= type
;
121 rate_policy
->serialize
= serialize
;
122 rate_policy
->equal
= equal
;
123 rate_policy
->destroy
= destroy
;
124 rate_policy
->copy
= copy
;
125 rate_policy
->mi_serialize
= mi
;
128 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
134 rate_policy
->destroy(rate_policy
);
138 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
139 struct lttng_payload
*payload
)
142 struct lttng_rate_policy_comm rate_policy_comm
= {
143 .rate_policy_type
= (int8_t) rate_policy
->type
,
146 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &rate_policy_comm
,
147 sizeof(rate_policy_comm
));
152 ret
= rate_policy
->serialize(rate_policy
, payload
);
160 static ssize_t
lttng_rate_policy_once_after_n_create_from_payload(
161 struct lttng_payload_view
*view
,
162 struct lttng_rate_policy
**rate_policy
)
164 ssize_t consumed_len
= -1;
165 struct lttng_rate_policy
*policy
= NULL
;
166 const struct lttng_rate_policy_once_after_n_comm
*comm
;
167 const struct lttng_payload_view comm_view
=
168 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
170 if (!view
|| !rate_policy
) {
175 if (!lttng_payload_view_is_valid(&comm_view
)) {
176 /* Payload not large enough to contain the header. */
181 comm
= (const struct lttng_rate_policy_once_after_n_comm
*)
182 comm_view
.buffer
.data
;
184 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
185 if (policy
== NULL
) {
190 *rate_policy
= policy
;
191 consumed_len
= sizeof(*comm
);
197 static ssize_t
lttng_rate_policy_every_n_create_from_payload(
198 struct lttng_payload_view
*view
,
199 struct lttng_rate_policy
**rate_policy
)
201 ssize_t consumed_len
= -1;
202 struct lttng_rate_policy
*policy
= NULL
;
203 const struct lttng_rate_policy_every_n_comm
*comm
;
204 const struct lttng_payload_view comm_view
=
205 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
207 if (!view
|| !rate_policy
) {
212 if (!lttng_payload_view_is_valid(&comm_view
)) {
213 /* Payload not large enough to contain the header. */
218 comm
= (const struct lttng_rate_policy_every_n_comm
*)
219 comm_view
.buffer
.data
;
221 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
222 if (policy
== NULL
) {
227 *rate_policy
= policy
;
228 consumed_len
= sizeof(*comm
);
235 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
236 struct lttng_rate_policy
**rate_policy
)
238 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
239 rate_policy_create_from_payload_cb create_from_payload_cb
;
240 const struct lttng_rate_policy_comm
*rate_policy_comm
;
241 const struct lttng_payload_view rate_policy_comm_view
=
242 lttng_payload_view_from_view(
243 view
, 0, sizeof(*rate_policy_comm
));
245 if (!view
|| !rate_policy
) {
250 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
251 /* Payload not large enough to contain the header. */
256 rate_policy_comm
= (const struct lttng_rate_policy_comm
*)
257 rate_policy_comm_view
.buffer
.data
;
259 DBG("Create rate_policy from payload: rate-policy-type=%s",
260 lttng_rate_policy_type_string(
261 rate_policy_comm
->rate_policy_type
));
263 switch (rate_policy_comm
->rate_policy_type
) {
264 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
265 create_from_payload_cb
=
266 lttng_rate_policy_every_n_create_from_payload
;
268 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
269 create_from_payload_cb
=
270 lttng_rate_policy_once_after_n_create_from_payload
;
273 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
274 rate_policy_comm
->rate_policy_type
,
275 lttng_rate_policy_type_string(
276 rate_policy_comm
->rate_policy_type
));
282 /* Create buffer view for the rate_policy-type-specific data.
284 struct lttng_payload_view specific_rate_policy_view
=
285 lttng_payload_view_from_view(view
,
286 sizeof(struct lttng_rate_policy_comm
),
289 specific_rate_policy_consumed_len
= create_from_payload_cb(
290 &specific_rate_policy_view
, rate_policy
);
292 if (specific_rate_policy_consumed_len
< 0) {
293 ERR("Failed to create specific rate_policy from buffer.");
298 LTTNG_ASSERT(*rate_policy
);
300 consumed_len
= sizeof(struct lttng_rate_policy_comm
) +
301 specific_rate_policy_consumed_len
;
308 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
309 const struct lttng_rate_policy
*b
)
311 bool is_equal
= false;
317 if (a
->type
!= b
->type
) {
326 LTTNG_ASSERT(a
->equal
);
327 is_equal
= a
->equal(a
, b
);
333 bool lttng_rate_policy_should_execute(
334 const struct lttng_rate_policy
*policy
, uint64_t counter
)
336 switch (policy
->type
) {
337 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
338 return lttng_rate_policy_every_n_should_execute(
340 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
341 return lttng_rate_policy_once_after_n_should_execute(
350 static struct lttng_rate_policy_every_n
*rate_policy_every_n_from_rate_policy(
351 struct lttng_rate_policy
*policy
)
353 LTTNG_ASSERT(policy
);
355 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
358 static const struct lttng_rate_policy_every_n
*
359 rate_policy_every_n_from_rate_policy_const(
360 const struct lttng_rate_policy
*policy
)
362 LTTNG_ASSERT(policy
);
364 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
367 static int lttng_rate_policy_every_n_serialize(
368 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
372 struct lttng_rate_policy_every_n
*every_n_policy
;
373 struct lttng_rate_policy_every_n_comm comm
= {};
375 LTTNG_ASSERT(policy
);
376 LTTNG_ASSERT(payload
);
378 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
379 comm
.interval
= every_n_policy
->interval
;
381 ret
= lttng_dynamic_buffer_append(
382 &payload
->buffer
, &comm
, sizeof(comm
));
386 static bool lttng_rate_policy_every_n_is_equal(
387 const struct lttng_rate_policy
*_a
,
388 const struct lttng_rate_policy
*_b
)
390 bool is_equal
= false;
391 const struct lttng_rate_policy_every_n
*a
, *b
;
393 a
= rate_policy_every_n_from_rate_policy_const(_a
);
394 b
= rate_policy_every_n_from_rate_policy_const(_b
);
396 if (a
->interval
!= b
->interval
) {
406 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
408 struct lttng_rate_policy_every_n
*every_n_policy
;
414 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
416 free(every_n_policy
);
422 static struct lttng_rate_policy
*lttng_rate_policy_every_n_copy(
423 const struct lttng_rate_policy
*source
)
425 struct lttng_rate_policy
*copy
= NULL
;
426 const struct lttng_rate_policy_every_n
*every_n_policy
;
432 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
433 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
439 static enum lttng_error_code
lttng_rate_policy_every_n_mi_serialize(
440 const struct lttng_rate_policy
*rate_policy
,
441 struct mi_writer
*writer
)
444 enum lttng_error_code ret_code
;
445 const struct lttng_rate_policy_every_n
*every_n_policy
= NULL
;
447 LTTNG_ASSERT(rate_policy
);
448 LTTNG_ASSERT(IS_EVERY_N_RATE_POLICY(rate_policy
));
449 LTTNG_ASSERT(writer
);
451 every_n_policy
= rate_policy_every_n_from_rate_policy_const(
454 /* Open rate_policy_every_n element. */
455 ret
= mi_lttng_writer_open_element(
456 writer
, mi_lttng_element_rate_policy_every_n
);
462 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
463 mi_lttng_element_rate_policy_every_n_interval
,
464 every_n_policy
->interval
);
469 /* Close rate_policy_every_n element. */
470 ret
= mi_lttng_writer_close_element(writer
);
479 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
484 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
486 struct lttng_rate_policy_every_n
*policy
= NULL
;
487 struct lttng_rate_policy
*_policy
= NULL
;
491 * An interval of 0 is invalid since it would never be fired.
496 policy
= zmalloc(sizeof(struct lttng_rate_policy_every_n
));
501 lttng_rate_policy_init(&policy
->parent
, LTTNG_RATE_POLICY_TYPE_EVERY_N
,
502 lttng_rate_policy_every_n_serialize
,
503 lttng_rate_policy_every_n_is_equal
,
504 lttng_rate_policy_every_n_destroy
,
505 lttng_rate_policy_every_n_copy
,
506 lttng_rate_policy_every_n_mi_serialize
);
508 policy
->interval
= interval
;
510 _policy
= &policy
->parent
;
518 enum lttng_rate_policy_status
lttng_rate_policy_every_n_get_interval(
519 const struct lttng_rate_policy
*policy
, uint64_t *interval
)
521 const struct lttng_rate_policy_every_n
*every_n_policy
;
522 enum lttng_rate_policy_status status
;
524 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
525 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
529 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
530 *interval
= every_n_policy
->interval
;
531 status
= LTTNG_RATE_POLICY_STATUS_OK
;
537 static bool lttng_rate_policy_every_n_should_execute(
538 const struct lttng_rate_policy
*policy
, uint64_t counter
)
540 const struct lttng_rate_policy_every_n
*every_n_policy
;
541 LTTNG_ASSERT(policy
);
542 bool execute
= false;
544 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
546 if (every_n_policy
->interval
== 0) {
550 execute
= (counter
% every_n_policy
->interval
) == 0;
552 DBG("Policy every N = %" PRIu64
553 ": execution %s. Execution count: %" PRIu64
,
554 every_n_policy
->interval
,
555 execute
? "accepted" : "denied", counter
);
562 static struct lttng_rate_policy_once_after_n
*
563 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
565 LTTNG_ASSERT(policy
);
568 policy
, struct lttng_rate_policy_once_after_n
, parent
);
571 static const struct lttng_rate_policy_once_after_n
*
572 rate_policy_once_after_n_from_rate_policy_const(
573 const struct lttng_rate_policy
*policy
)
575 LTTNG_ASSERT(policy
);
578 policy
, struct lttng_rate_policy_once_after_n
, parent
);
580 static int lttng_rate_policy_once_after_n_serialize(
581 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
585 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
586 struct lttng_rate_policy_once_after_n_comm comm
= {};
588 LTTNG_ASSERT(policy
);
589 LTTNG_ASSERT(payload
);
591 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
592 comm
.threshold
= once_after_n_policy
->threshold
;
594 ret
= lttng_dynamic_buffer_append(
595 &payload
->buffer
, &comm
, sizeof(comm
));
599 static bool lttng_rate_policy_once_after_n_is_equal(
600 const struct lttng_rate_policy
*_a
,
601 const struct lttng_rate_policy
*_b
)
603 bool is_equal
= false;
604 const struct lttng_rate_policy_once_after_n
*a
, *b
;
606 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
607 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
609 if (a
->threshold
!= b
->threshold
) {
619 static void lttng_rate_policy_once_after_n_destroy(
620 struct lttng_rate_policy
*policy
)
622 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
628 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
630 free(once_after_n_policy
);
636 static struct lttng_rate_policy
*lttng_rate_policy_once_after_n_copy(
637 const struct lttng_rate_policy
*source
)
639 struct lttng_rate_policy
*copy
= NULL
;
640 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
646 once_after_n_policy
=
647 rate_policy_once_after_n_from_rate_policy_const(source
);
648 copy
= lttng_rate_policy_once_after_n_create(
649 once_after_n_policy
->threshold
);
655 static enum lttng_error_code
lttng_rate_policy_once_after_n_mi_serialize(
656 const struct lttng_rate_policy
*rate_policy
,
657 struct mi_writer
*writer
)
660 enum lttng_error_code ret_code
;
661 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= NULL
;
663 LTTNG_ASSERT(rate_policy
);
664 LTTNG_ASSERT(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
665 LTTNG_ASSERT(writer
);
667 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(
670 /* Open rate_policy_once_after_n. */
671 ret
= mi_lttng_writer_open_element(
672 writer
, mi_lttng_element_rate_policy_once_after_n
);
678 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
679 mi_lttng_element_rate_policy_once_after_n_threshold
,
680 once_after_n_policy
->threshold
);
685 /* Close rate_policy_once_after_n element. */
686 ret
= mi_lttng_writer_close_element(writer
);
695 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
700 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(
703 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
704 struct lttng_rate_policy
*_policy
= NULL
;
706 if (threshold
== 0) {
707 /* threshold is expected to be > 0 */
711 policy
= zmalloc(sizeof(struct lttng_rate_policy_once_after_n
));
716 lttng_rate_policy_init(&policy
->parent
,
717 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
718 lttng_rate_policy_once_after_n_serialize
,
719 lttng_rate_policy_once_after_n_is_equal
,
720 lttng_rate_policy_once_after_n_destroy
,
721 lttng_rate_policy_once_after_n_copy
,
722 lttng_rate_policy_once_after_n_mi_serialize
);
724 policy
->threshold
= threshold
;
726 _policy
= &policy
->parent
;
734 enum lttng_rate_policy_status
lttng_rate_policy_once_after_n_get_threshold(
735 const struct lttng_rate_policy
*policy
, uint64_t *threshold
)
737 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
738 enum lttng_rate_policy_status status
;
740 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
741 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
745 once_after_n_policy
=
746 rate_policy_once_after_n_from_rate_policy_const(policy
);
747 *threshold
= once_after_n_policy
->threshold
;
748 status
= LTTNG_RATE_POLICY_STATUS_OK
;
755 struct lttng_rate_policy
*lttng_rate_policy_copy(
756 const struct lttng_rate_policy
*source
)
758 LTTNG_ASSERT(source
->copy
);
759 return source
->copy(source
);
762 static bool lttng_rate_policy_once_after_n_should_execute(
763 const struct lttng_rate_policy
*policy
, uint64_t counter
)
765 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
766 bool execute
= false;
767 LTTNG_ASSERT(policy
);
769 once_after_n_policy
=
770 rate_policy_once_after_n_from_rate_policy_const(policy
);
772 execute
= counter
== once_after_n_policy
->threshold
;
774 DBG("Policy once after N = %" PRIu64
775 ": execution %s. Execution count: %" PRIu64
,
776 once_after_n_policy
->threshold
,
777 execute
? "accepted" : "denied", counter
);
779 return counter
== once_after_n_policy
->threshold
;
783 enum lttng_error_code
lttng_rate_policy_mi_serialize(
784 const struct lttng_rate_policy
*rate_policy
,
785 struct mi_writer
*writer
)
788 enum lttng_error_code ret_code
;
790 LTTNG_ASSERT(rate_policy
);
791 LTTNG_ASSERT(writer
);
792 LTTNG_ASSERT(rate_policy
->mi_serialize
);
794 /* Open rate policy element. */
795 ret
= mi_lttng_writer_open_element(
796 writer
, mi_lttng_element_rate_policy
);
801 /* Serialize underlying rate policy. */
802 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
803 if (ret_code
!= LTTNG_OK
) {
807 /* Close rate policy element. */
808 ret
= mi_lttng_writer_close_element(writer
);
817 ret_code
= LTTNG_ERR_MI_IO_FAIL
;