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
);
91 const char *lttng_rate_policy_type_string(
92 enum lttng_rate_policy_type rate_policy_type
)
94 switch (rate_policy_type
) {
95 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
97 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
98 return "ONCE-AFTER-N";
104 enum lttng_rate_policy_type
lttng_rate_policy_get_type(
105 const struct lttng_rate_policy
*policy
)
107 return policy
? policy
->type
: LTTNG_RATE_POLICY_TYPE_UNKNOWN
;
110 void lttng_rate_policy_init(struct lttng_rate_policy
*rate_policy
,
111 enum lttng_rate_policy_type type
,
112 rate_policy_serialize_cb serialize
,
113 rate_policy_equal_cb equal
,
114 rate_policy_destroy_cb destroy
,
115 rate_policy_copy_cb copy
,
116 rate_policy_mi_serialize_cb mi
)
118 rate_policy
->type
= type
;
119 rate_policy
->serialize
= serialize
;
120 rate_policy
->equal
= equal
;
121 rate_policy
->destroy
= destroy
;
122 rate_policy
->copy
= copy
;
123 rate_policy
->mi_serialize
= mi
;
126 void lttng_rate_policy_destroy(struct lttng_rate_policy
*rate_policy
)
132 rate_policy
->destroy(rate_policy
);
135 int lttng_rate_policy_serialize(struct lttng_rate_policy
*rate_policy
,
136 struct lttng_payload
*payload
)
139 struct lttng_rate_policy_comm rate_policy_comm
= {
140 .rate_policy_type
= (int8_t) rate_policy
->type
,
143 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &rate_policy_comm
,
144 sizeof(rate_policy_comm
));
149 ret
= rate_policy
->serialize(rate_policy
, payload
);
157 static ssize_t
lttng_rate_policy_once_after_n_create_from_payload(
158 struct lttng_payload_view
*view
,
159 struct lttng_rate_policy
**rate_policy
)
161 ssize_t consumed_len
= -1;
162 struct lttng_rate_policy
*policy
= NULL
;
163 const struct lttng_rate_policy_once_after_n_comm
*comm
;
164 const struct lttng_payload_view comm_view
=
165 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
167 if (!view
|| !rate_policy
) {
172 if (!lttng_payload_view_is_valid(&comm_view
)) {
173 /* Payload not large enough to contain the header. */
178 comm
= (const struct lttng_rate_policy_once_after_n_comm
*)
179 comm_view
.buffer
.data
;
181 policy
= lttng_rate_policy_once_after_n_create(comm
->threshold
);
182 if (policy
== NULL
) {
187 *rate_policy
= policy
;
188 consumed_len
= sizeof(*comm
);
194 static ssize_t
lttng_rate_policy_every_n_create_from_payload(
195 struct lttng_payload_view
*view
,
196 struct lttng_rate_policy
**rate_policy
)
198 ssize_t consumed_len
= -1;
199 struct lttng_rate_policy
*policy
= NULL
;
200 const struct lttng_rate_policy_every_n_comm
*comm
;
201 const struct lttng_payload_view comm_view
=
202 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
204 if (!view
|| !rate_policy
) {
209 if (!lttng_payload_view_is_valid(&comm_view
)) {
210 /* Payload not large enough to contain the header. */
215 comm
= (const struct lttng_rate_policy_every_n_comm
*)
216 comm_view
.buffer
.data
;
218 policy
= lttng_rate_policy_every_n_create(comm
->interval
);
219 if (policy
== NULL
) {
224 *rate_policy
= policy
;
225 consumed_len
= sizeof(*comm
);
231 ssize_t
lttng_rate_policy_create_from_payload(struct lttng_payload_view
*view
,
232 struct lttng_rate_policy
**rate_policy
)
234 ssize_t consumed_len
, specific_rate_policy_consumed_len
;
235 rate_policy_create_from_payload_cb create_from_payload_cb
;
236 const struct lttng_rate_policy_comm
*rate_policy_comm
;
237 const struct lttng_payload_view rate_policy_comm_view
=
238 lttng_payload_view_from_view(
239 view
, 0, sizeof(*rate_policy_comm
));
241 if (!view
|| !rate_policy
) {
246 if (!lttng_payload_view_is_valid(&rate_policy_comm_view
)) {
247 /* Payload not large enough to contain the header. */
252 rate_policy_comm
= (const struct lttng_rate_policy_comm
*)
253 rate_policy_comm_view
.buffer
.data
;
255 DBG("Create rate_policy from payload: rate-policy-type=%s",
256 lttng_rate_policy_type_string(
257 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
259 switch (rate_policy_comm
->rate_policy_type
) {
260 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
261 create_from_payload_cb
=
262 lttng_rate_policy_every_n_create_from_payload
;
264 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
265 create_from_payload_cb
=
266 lttng_rate_policy_once_after_n_create_from_payload
;
269 ERR("Failed to create rate-policy from payload, unhandled rate-policy type: rate-policy-type=%u (%s)",
270 rate_policy_comm
->rate_policy_type
,
271 lttng_rate_policy_type_string(
272 (lttng_rate_policy_type
) rate_policy_comm
->rate_policy_type
));
278 /* Create buffer view for the rate_policy-type-specific data.
280 struct lttng_payload_view specific_rate_policy_view
=
281 lttng_payload_view_from_view(view
,
282 sizeof(struct lttng_rate_policy_comm
),
285 specific_rate_policy_consumed_len
= create_from_payload_cb(
286 &specific_rate_policy_view
, rate_policy
);
288 if (specific_rate_policy_consumed_len
< 0) {
289 ERR("Failed to create specific rate_policy from buffer.");
294 LTTNG_ASSERT(*rate_policy
);
296 consumed_len
= sizeof(struct lttng_rate_policy_comm
) +
297 specific_rate_policy_consumed_len
;
303 bool lttng_rate_policy_is_equal(const struct lttng_rate_policy
*a
,
304 const struct lttng_rate_policy
*b
)
306 bool is_equal
= false;
312 if (a
->type
!= b
->type
) {
321 LTTNG_ASSERT(a
->equal
);
322 is_equal
= a
->equal(a
, b
);
327 bool lttng_rate_policy_should_execute(
328 const struct lttng_rate_policy
*policy
, uint64_t counter
)
330 switch (policy
->type
) {
331 case LTTNG_RATE_POLICY_TYPE_EVERY_N
:
332 return lttng_rate_policy_every_n_should_execute(
334 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
:
335 return lttng_rate_policy_once_after_n_should_execute(
344 static struct lttng_rate_policy_every_n
*rate_policy_every_n_from_rate_policy(
345 struct lttng_rate_policy
*policy
)
347 LTTNG_ASSERT(policy
);
349 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
352 static const struct lttng_rate_policy_every_n
*
353 rate_policy_every_n_from_rate_policy_const(
354 const struct lttng_rate_policy
*policy
)
356 LTTNG_ASSERT(policy
);
358 return container_of(policy
, struct lttng_rate_policy_every_n
, parent
);
361 static int lttng_rate_policy_every_n_serialize(
362 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
366 struct lttng_rate_policy_every_n
*every_n_policy
;
367 struct lttng_rate_policy_every_n_comm comm
= {};
369 LTTNG_ASSERT(policy
);
370 LTTNG_ASSERT(payload
);
372 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
373 comm
.interval
= every_n_policy
->interval
;
375 ret
= lttng_dynamic_buffer_append(
376 &payload
->buffer
, &comm
, sizeof(comm
));
380 static bool lttng_rate_policy_every_n_is_equal(
381 const struct lttng_rate_policy
*_a
,
382 const struct lttng_rate_policy
*_b
)
384 bool is_equal
= false;
385 const struct lttng_rate_policy_every_n
*a
, *b
;
387 a
= rate_policy_every_n_from_rate_policy_const(_a
);
388 b
= rate_policy_every_n_from_rate_policy_const(_b
);
390 if (a
->interval
!= b
->interval
) {
400 static void lttng_rate_policy_every_n_destroy(struct lttng_rate_policy
*policy
)
402 struct lttng_rate_policy_every_n
*every_n_policy
;
408 every_n_policy
= rate_policy_every_n_from_rate_policy(policy
);
410 free(every_n_policy
);
416 static struct lttng_rate_policy
*lttng_rate_policy_every_n_copy(
417 const struct lttng_rate_policy
*source
)
419 struct lttng_rate_policy
*copy
= NULL
;
420 const struct lttng_rate_policy_every_n
*every_n_policy
;
426 every_n_policy
= rate_policy_every_n_from_rate_policy_const(source
);
427 copy
= lttng_rate_policy_every_n_create(every_n_policy
->interval
);
433 static enum lttng_error_code
lttng_rate_policy_every_n_mi_serialize(
434 const struct lttng_rate_policy
*rate_policy
,
435 struct mi_writer
*writer
)
438 enum lttng_error_code ret_code
;
439 const struct lttng_rate_policy_every_n
*every_n_policy
= NULL
;
441 LTTNG_ASSERT(rate_policy
);
442 LTTNG_ASSERT(IS_EVERY_N_RATE_POLICY(rate_policy
));
443 LTTNG_ASSERT(writer
);
445 every_n_policy
= rate_policy_every_n_from_rate_policy_const(
448 /* Open rate_policy_every_n element. */
449 ret
= mi_lttng_writer_open_element(
450 writer
, mi_lttng_element_rate_policy_every_n
);
456 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
457 mi_lttng_element_rate_policy_every_n_interval
,
458 every_n_policy
->interval
);
463 /* Close rate_policy_every_n element. */
464 ret
= mi_lttng_writer_close_element(writer
);
473 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
478 struct lttng_rate_policy
*lttng_rate_policy_every_n_create(uint64_t interval
)
480 struct lttng_rate_policy_every_n
*policy
= NULL
;
481 struct lttng_rate_policy
*_policy
= NULL
;
485 * An interval of 0 is invalid since it would never be fired.
490 policy
= (lttng_rate_policy_every_n
*) zmalloc(sizeof(struct lttng_rate_policy_every_n
));
495 lttng_rate_policy_init(&policy
->parent
, LTTNG_RATE_POLICY_TYPE_EVERY_N
,
496 lttng_rate_policy_every_n_serialize
,
497 lttng_rate_policy_every_n_is_equal
,
498 lttng_rate_policy_every_n_destroy
,
499 lttng_rate_policy_every_n_copy
,
500 lttng_rate_policy_every_n_mi_serialize
);
502 policy
->interval
= interval
;
504 _policy
= &policy
->parent
;
512 enum lttng_rate_policy_status
lttng_rate_policy_every_n_get_interval(
513 const struct lttng_rate_policy
*policy
, uint64_t *interval
)
515 const struct lttng_rate_policy_every_n
*every_n_policy
;
516 enum lttng_rate_policy_status status
;
518 if (!policy
|| !IS_EVERY_N_RATE_POLICY(policy
) || !interval
) {
519 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
523 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
524 *interval
= every_n_policy
->interval
;
525 status
= LTTNG_RATE_POLICY_STATUS_OK
;
531 static bool lttng_rate_policy_every_n_should_execute(
532 const struct lttng_rate_policy
*policy
, uint64_t counter
)
534 const struct lttng_rate_policy_every_n
*every_n_policy
;
535 LTTNG_ASSERT(policy
);
536 bool execute
= false;
538 every_n_policy
= rate_policy_every_n_from_rate_policy_const(policy
);
540 if (every_n_policy
->interval
== 0) {
544 execute
= (counter
% every_n_policy
->interval
) == 0;
546 DBG("Policy every N = %" PRIu64
547 ": execution %s. Execution count: %" PRIu64
,
548 every_n_policy
->interval
,
549 execute
? "accepted" : "denied", counter
);
556 static struct lttng_rate_policy_once_after_n
*
557 rate_policy_once_after_n_from_rate_policy(struct lttng_rate_policy
*policy
)
559 LTTNG_ASSERT(policy
);
562 policy
, struct lttng_rate_policy_once_after_n
, parent
);
565 static const struct lttng_rate_policy_once_after_n
*
566 rate_policy_once_after_n_from_rate_policy_const(
567 const struct lttng_rate_policy
*policy
)
569 LTTNG_ASSERT(policy
);
572 policy
, struct lttng_rate_policy_once_after_n
, parent
);
574 static int lttng_rate_policy_once_after_n_serialize(
575 struct lttng_rate_policy
*policy
, struct lttng_payload
*payload
)
579 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
580 struct lttng_rate_policy_once_after_n_comm comm
= {};
582 LTTNG_ASSERT(policy
);
583 LTTNG_ASSERT(payload
);
585 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
586 comm
.threshold
= once_after_n_policy
->threshold
;
588 ret
= lttng_dynamic_buffer_append(
589 &payload
->buffer
, &comm
, sizeof(comm
));
593 static bool lttng_rate_policy_once_after_n_is_equal(
594 const struct lttng_rate_policy
*_a
,
595 const struct lttng_rate_policy
*_b
)
597 bool is_equal
= false;
598 const struct lttng_rate_policy_once_after_n
*a
, *b
;
600 a
= rate_policy_once_after_n_from_rate_policy_const(_a
);
601 b
= rate_policy_once_after_n_from_rate_policy_const(_b
);
603 if (a
->threshold
!= b
->threshold
) {
613 static void lttng_rate_policy_once_after_n_destroy(
614 struct lttng_rate_policy
*policy
)
616 struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
622 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy(policy
);
624 free(once_after_n_policy
);
630 static struct lttng_rate_policy
*lttng_rate_policy_once_after_n_copy(
631 const struct lttng_rate_policy
*source
)
633 struct lttng_rate_policy
*copy
= NULL
;
634 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
640 once_after_n_policy
=
641 rate_policy_once_after_n_from_rate_policy_const(source
);
642 copy
= lttng_rate_policy_once_after_n_create(
643 once_after_n_policy
->threshold
);
649 static enum lttng_error_code
lttng_rate_policy_once_after_n_mi_serialize(
650 const struct lttng_rate_policy
*rate_policy
,
651 struct mi_writer
*writer
)
654 enum lttng_error_code ret_code
;
655 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
= NULL
;
657 LTTNG_ASSERT(rate_policy
);
658 LTTNG_ASSERT(IS_ONCE_AFTER_N_RATE_POLICY(rate_policy
));
659 LTTNG_ASSERT(writer
);
661 once_after_n_policy
= rate_policy_once_after_n_from_rate_policy_const(
664 /* Open rate_policy_once_after_n. */
665 ret
= mi_lttng_writer_open_element(
666 writer
, mi_lttng_element_rate_policy_once_after_n
);
672 ret
= mi_lttng_writer_write_element_unsigned_int(writer
,
673 mi_lttng_element_rate_policy_once_after_n_threshold
,
674 once_after_n_policy
->threshold
);
679 /* Close rate_policy_once_after_n element. */
680 ret
= mi_lttng_writer_close_element(writer
);
689 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
694 struct lttng_rate_policy
*lttng_rate_policy_once_after_n_create(
697 struct lttng_rate_policy_once_after_n
*policy
= NULL
;
698 struct lttng_rate_policy
*_policy
= NULL
;
700 if (threshold
== 0) {
701 /* threshold is expected to be > 0 */
705 policy
= (lttng_rate_policy_once_after_n
*) zmalloc(sizeof(struct lttng_rate_policy_once_after_n
));
710 lttng_rate_policy_init(&policy
->parent
,
711 LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N
,
712 lttng_rate_policy_once_after_n_serialize
,
713 lttng_rate_policy_once_after_n_is_equal
,
714 lttng_rate_policy_once_after_n_destroy
,
715 lttng_rate_policy_once_after_n_copy
,
716 lttng_rate_policy_once_after_n_mi_serialize
);
718 policy
->threshold
= threshold
;
720 _policy
= &policy
->parent
;
728 enum lttng_rate_policy_status
lttng_rate_policy_once_after_n_get_threshold(
729 const struct lttng_rate_policy
*policy
, uint64_t *threshold
)
731 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
732 enum lttng_rate_policy_status status
;
734 if (!policy
|| !IS_ONCE_AFTER_N_RATE_POLICY(policy
) || !threshold
) {
735 status
= LTTNG_RATE_POLICY_STATUS_INVALID
;
739 once_after_n_policy
=
740 rate_policy_once_after_n_from_rate_policy_const(policy
);
741 *threshold
= once_after_n_policy
->threshold
;
742 status
= LTTNG_RATE_POLICY_STATUS_OK
;
748 struct lttng_rate_policy
*lttng_rate_policy_copy(
749 const struct lttng_rate_policy
*source
)
751 LTTNG_ASSERT(source
->copy
);
752 return source
->copy(source
);
755 static bool lttng_rate_policy_once_after_n_should_execute(
756 const struct lttng_rate_policy
*policy
, uint64_t counter
)
758 const struct lttng_rate_policy_once_after_n
*once_after_n_policy
;
759 bool execute
= false;
760 LTTNG_ASSERT(policy
);
762 once_after_n_policy
=
763 rate_policy_once_after_n_from_rate_policy_const(policy
);
765 execute
= counter
== once_after_n_policy
->threshold
;
767 DBG("Policy once after N = %" PRIu64
768 ": execution %s. Execution count: %" PRIu64
,
769 once_after_n_policy
->threshold
,
770 execute
? "accepted" : "denied", counter
);
772 return counter
== once_after_n_policy
->threshold
;
775 enum lttng_error_code
lttng_rate_policy_mi_serialize(
776 const struct lttng_rate_policy
*rate_policy
,
777 struct mi_writer
*writer
)
780 enum lttng_error_code ret_code
;
782 LTTNG_ASSERT(rate_policy
);
783 LTTNG_ASSERT(writer
);
784 LTTNG_ASSERT(rate_policy
->mi_serialize
);
786 /* Open rate policy element. */
787 ret
= mi_lttng_writer_open_element(
788 writer
, mi_lttng_element_rate_policy
);
793 /* Serialize underlying rate policy. */
794 ret_code
= rate_policy
->mi_serialize(rate_policy
, writer
);
795 if (ret_code
!= LTTNG_OK
) {
799 /* Close rate policy element. */
800 ret
= mi_lttng_writer_close_element(writer
);
809 ret_code
= LTTNG_ERR_MI_IO_FAIL
;